Spartan programming C example
From Ssdlpedia
Initial code:
#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) #define REG_OFFSET(addr) (0x00000000000000FF & (addr)) #define SAL_SET_VECTORS 0x01000000 #define SAL_GET_STATE_INFO 0x01000001 #define SAL_GET_STATE_INFO_SIZE 0x01000002 #define SAL_CLEAR_STATE_INFO 0x01000003 #define SAL_MC_RENDEZ 0x01000004 #define SAL_MC_SET_PARAMS 0x01000005 #define SAL_REGISTER_PHYSICAL_ADDR 0x01000006 #define SAL_CACHE_FLUSH 0x01000008 #define SAL_CACHE_INIT 0x01000009 #define SAL_PCI_CONFIG_READ 0x01000010 #define SAL_PCI_CONFIG_WRITE 0x01000011 #define SAL_FREQ_BASE 0x01000012 #define SAL_PHYSICAL_ID_INFO 0x01000013 #define SAL_UPDATE_PAL 0x01000020 enum { SAL_FREQ_BASE_PLATFORM = 0, SAL_FREQ_BASE_INTERVAL_TIMER = 1, SAL_FREQ_BASE_REALTIME_CLOCK = 2 }; static struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7) { long r9 = 0; long r10 = 0; long r11 = 0; long status; status = 0; if (index == SAL_FREQ_BASE) { switch (in1) { case SAL_FREQ_BASE_PLATFORM: r9 = 200000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: /* * Is this supposed to be the cr.itc frequency * or something platform specific? The SAL * doc ain't exactly clear on this... */ r9 = 700000000; break; case SAL_FREQ_BASE_REALTIME_CLOCK: r9 = 1; break; default: status = -1; break; } } else if (index == SAL_SET_VECTORS) { ; } else if (index == SAL_GET_STATE_INFO) { ; } else if (index == SAL_GET_STATE_INFO_SIZE) { ; } else if (index == SAL_CLEAR_STATE_INFO) { ; } else if (index == SAL_MC_RENDEZ) { ; } else if (index == SAL_MC_SET_PARAMS) { ; } else if (index == SAL_CACHE_FLUSH) { ; } else if (index == SAL_CACHE_INIT) { ; } else if (index == SAL_PCI_CONFIG_READ) { /* * in1 contains the PCI configuration address and in2 * the size of the read. The value that is read is * returned via the general register r9. */ outl(BUILD_CMD(in1), 0xCF8); if (in2 == 1) /* Reading byte */ r9 = inb(0xCFC + ((REG_OFFSET(in1) & 3))); else if (in2 == 2) /* Reading word */ r9 = inw(0xCFC + ((REG_OFFSET(in1) & 2))); else /* Reading dword */ r9 = inl(0xCFC); status = PCIBIOS_SUCCESSFUL; } else if (index == SAL_PCI_CONFIG_WRITE) { /* * in1 contains the PCI configuration address, in2 the * size of the write, and in3 the actual value to be * written out. */ outl(BUILD_CMD(in1), 0xCF8); if (in2 == 1) /* Writing byte */ outb(in3, 0xCFC + ((REG_OFFSET(in1) & 3))); else if (in2 == 2) /* Writing word */ outw(in3, 0xCFC + ((REG_OFFSET(in1) & 2))); else /* Writing dword */ outl(in3, 0xCFC); status = PCIBIOS_SUCCESSFUL; } else if (index == SAL_UPDATE_PAL) { ; } else { status = -1; } return ((struct sal_ret_values) {status, r9, r10, r11}); }
Changes:
- enumeration is created
- nested 'if' turned to switch
- variable 'status' initialization is added
- return statement parenthesis are deleted
- all cases with no performed action moved to the beginning of switch
- SAL_PCI_CONFIG_READ and SAL_PCI_CONFIG_WRITE cases union
- structure for functions and parameter that called for specified 'in2' is defined
- array of characteristics (in/out function and paramater) for different 'in2' is defined
- new structure for input to the function is defined
- two new functions for cases treatment are defined
- variables r10, r11 are deleted
Simplified code:
#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) #define REG_OFFSET(addr) (0x00000000000000FF & (addr)) enum sal_cmd_event { SAL_SET_VECTORS = 0x01000000, SAL_GET_STATE_INFO, SAL_GET_STATE_INFO_SIZE, SAL_CLEAR_STATE_INFO, SAL_MC_RENDEZ, SAL_MC_SET_PARAMS, SAL_REGISTER_PHYSICAL_ADDR, SAL_CACHE_FLUSH = 0x01000008, SAL_CACHE_INIT, SAL_PCI_CONFIG_READ, SAL_PCI_CONFIG_WRITE, SAL_FREQ_BASE, SAL_PHYSICAL_ID_INFO, SAL_UPDATE_PAL = 0x01000020, }; enum { SAL_FREQ_BASE_PLATFORM = 0, SAL_FREQ_BASE_INTERVAL_TIMER = 1, SAL_FREQ_BASE_REALTIME_CLOCK = 2 }; typedef long (*ptInFunction)(long); typedef void (*ptOutFunction)(unsigned long, long); typedef struct sal_rw_params_struct { ptInFunction inFunction; ptOutFunction outFunction; int andParameter; } sal_rw_params; typedef struct sal_rec_vals_struct { long index; unsigned long in1; unsigned long in2; unsigned long in3; unsigned long in4; unsigned long in5; unsigned long in6; unsigned long in7 } sal_rec_vals; static long sal_freq_base_treat(unsigned long in1, long* r9) { switch (in1) { case SAL_FREQ_BASE_PLATFORM: *r9 = 200000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: /* * Is this supposed to be the cr.itc frequency * or something platform specific? The SAL * doc ain't exactly clear on this... */ *r9 = 700000000; break; case SAL_FREQ_BASE_REALTIME_CLOCK: *r9 = 1; break; default: return -1; } return 0; } static long sal_config_rw_treat(sal_rec_vals input, long* r9) { long param; int rw_index = 0; static sal_rw_params sal_rw[] = {{&inl, &outl, 0}, {&inb, &outb, REG_OFFSET(in1) & 3}, {&inw, &outw, REG_OFFSET(in1) & 2}}; outl(BUILD_CMD(input.in1), 0xCF8); if ((input.in2 == 1) || (input.in2 == 2)) rw_index = input.in2; param = 0xCFC + REG_OFFSET(input.in1) & (sal_rw[rw_index].offset); if (input.index == SAL_PCI_CONFIG_READ) /* * in1 contains the PCI configuration address and in2 * the size of the read. The value that is read is * returned via the general register r9. */ *r9 = (*sal_rw[rw_index].inFunction)(param); else /* * in1 contains the PCI configuration address, in2 the * size of the write, and in3 the actual value to be * written out. */ (*sal_rw[rw_index].outFunction)(input.in3, param); return PCIBIOS_SUCCESSFUL; } static struct sal_ret_values sal_emulator (sal_rec_vals input) { long r9 = 0; long status = 0; switch(input.index) { case SAL_SET_VECTORS: case SAL_GET_STATE_INFO: case SAL_GET_STATE_INFO_SIZE: case SAL_CLEAR_STATE_INFO: case SAL_MC_RENDEZ: case SAL_MC_SET_PARAMS: case SAL_CACHE_FLUSH: case SAL_CACHE_INIT: case SAL_UPDATE_PAL: break; case SAL_FREQ_BASE: status = sal_freq_base_treat(input.in1, &r9); break; case SAL_PCI_CONFIG_READ: case SAL_PCI_CONFIG_WRITE: status = sal_config_rw_treat(input, &r9); break; default: status = -1; break; } return (struct sal_ret_values) {status, r9, 0L, 0L}; }