Skip to content

Spartan programming C example

Ori Roth edited this page Apr 2, 2017 · 3 revisions

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 parentheses 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};
}
Clone this wiki locally