OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [generic.c] - Diff between revs 82 and 93

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 82 Rev 93
Line 79... Line 79...
  uint32_t size;                /* Address space size (bytes) */
  uint32_t size;                /* Address space size (bytes) */
 
 
};
};
 
 
 
 
/* Convert a 32-bit value from host to model endianess */
/* --------------------------------------------------------------------------*/
static unsigned long int
/*!Read a byte from an external device
htoml (unsigned long int  host_val)
 
{
 
  unsigned char  model_array[4];
 
 
 
#ifdef OR32_BIG_ENDIAN
 
  model_array[0] = (host_val >> 24) & 0xff;
 
  model_array[1] = (host_val >> 16) & 0xff;
 
  model_array[2] = (host_val >>  8) & 0xff;
 
  model_array[3] = (host_val      ) & 0xff;
 
#else
 
  model_array[0] = (host_val      ) & 0xff;
 
  model_array[1] = (host_val >>  8) & 0xff;
 
  model_array[2] = (host_val >> 16) & 0xff;
 
  model_array[3] = (host_val >> 24) & 0xff;
 
#endif
 
 
 
  unsigned long int *res = (unsigned long int *) model_array;
 
  return *res;
 
 
 
}       /* htoml () */
 
 
 
 
 
/* Convert a 16-bit value from host to model endianess */
 
static unsigned short int
 
htoms (unsigned short int  host_val)
 
{
 
  unsigned char  model_array[2];
 
 
 
#ifdef OR32_BIG_ENDIAN
 
  model_array[0] = (host_val >>  8) & 0xff;
 
  model_array[1] = (host_val      ) & 0xff;
 
#else
 
  model_array[0] = (host_val      ) & 0xff;
 
  model_array[1] = (host_val >>  8) & 0xff;
 
#endif
 
 
 
  unsigned short int *res = (unsigned short int *) model_array;
 
  return *res;
 
 
 
}       /* htoms () */
   To model Wishbone accurately, we always do this as a 4-byte access, with a
 
   mask for the bytes we don't want.
 
 
 
   Since this is only a byte, the endianess of the result is irrelevant.
 
 
/* Convert a 32-bit value from model to host endianess */
   @note We are passed the device address, but we must convert it to a full
static unsigned long int
         address for external use, to allow the single upcall handler to
mtohl (unsigned long int  model_val)
         decode multiple generic devices.
{
 
  unsigned char     *model_array = (unsigned char *)(&model_val);
 
  unsigned long int  host_val;
 
 
 
#ifdef OR32_BIG_ENDIAN
 
  host_val =                   model_array[0];
 
  host_val = (host_val << 8) | model_array[1];
 
  host_val = (host_val << 8) | model_array[2];
 
  host_val = (host_val << 8) | model_array[3];
 
#else
 
  host_val =                   model_array[3];
 
  host_val = (host_val << 8) | model_array[2];
 
  host_val = (host_val << 8) | model_array[1];
 
  host_val = (host_val << 8) | model_array[0];
 
#endif
 
 
 
  return  host_val;
   @param[in] addr  The device address to read from (host endian).
 
   @param[in] dat   The device data structure
}       /* mtohl () */
 
 
 
 
 
/* Convert a 32-bit value from model to host endianess */
 
static unsigned short int
 
mtohs (unsigned short int  model_val)
 
{
 
  unsigned char      *model_array = (unsigned char *)(&model_val);
 
  unsigned short int  host_val;
 
 
 
#ifdef OR32_BIG_ENDIAN
 
  host_val =                   model_array[0];
 
  host_val = (host_val << 8) | model_array[1];
 
#else
 
  host_val =                   model_array[1];
 
  host_val = (host_val << 8) | model_array[0];
 
#endif
 
 
 
  return  host_val;
 
 
 
}       /* mtohs () */
 
 
 
 
 
/* Generic read and write upcall routines. Note the address here is absolute,
 
   not relative to the device. The mask uses host endianess, not Or1ksim
 
   endianess. */
 
 
 
static unsigned long int
 
ext_read (unsigned long int  addr,
 
          unsigned long int  mask)
 
{
 
  return config.ext.read_up (config.ext.class_ptr, addr, mask);
 
 
 
}                               /* ext_callback() */
 
 
 
 
 
/* Generic read and write upcall routines. Note the address here is absolute,
 
   not relative to the device. The mask and value use host endianess, not
 
   Or1ksim endianess. */
 
 
 
static void
 
ext_write (unsigned long int  addr,
 
           unsigned long int  mask,
 
           unsigned long int  value)
 
{
 
  config.ext.write_up (config.ext.class_ptr, addr, mask, value);
 
 
 
}                               /* ext_callback() */
 
 
 
 
 
/* I/O routines. Note that address is relative to start of address space. */
 
 
 
 
   @return  The byte read.                                                   */
 
/* --------------------------------------------------------------------------*/
static uint8_t
static uint8_t
generic_read_byte (oraddr_t addr, void *dat)
generic_read_byte (oraddr_t  addr,
 
                   void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.read_up)
    {
    {
      fprintf (stderr, "Byte read from disabled generic device\n");
      fprintf (stderr, "Byte read from disabled generic device\n");
      return 0;
      return 0;
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
Line 214... Line 115...
               "(addr %" PRIxADDR ")\n", dev->name, addr);
               "(addr %" PRIxADDR ")\n", dev->name, addr);
      return 0;
      return 0;
    }
    }
  else
  else
    {
    {
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long int  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
      unsigned long int  wordaddr = fulladdr & 0xfffffffc;
      unsigned long  bytenum  = fulladdr & 0x00000003;
      int                bytenum  = fulladdr & 0x00000003;
 
 
      uint8_t        mask_array[4];
      unsigned char      mask[4];
      unsigned long  res;
      unsigned char      res[4];
      uint8_t       *res_array;
 
 
      /* Set the mask, read and get the result */
      /* This works whatever the host endianess */
      memset (mask, 0, sizeof (mask));
      memset (mask_array, 0, 4);
      mask[bytenum] = 0xff;
      mask_array[bytenum] = 0xff;
 
 
      if (0 != config.ext.read_up (NULL, wordaddr, mask, res, 4))
      unsigned int *arg_ptr = (unsigned int *) mask_array;
        {
      res       = ext_read (wordaddr, *arg_ptr);
          fprintf (stderr, "Warning: external byte read failed.\n");
      res_array = (uint8_t *)(&res);
          return  0;
 
        }
 
 
      return  res_array[bytenum];
      return  res[bytenum];
    }
    }
}                               /* generic_read_byte() */
}                               /* generic_read_byte() */
 
 
 
 
 
/* --------------------------------------------------------------------------*/
 
/*!Write a byte to an external device
 
 
 
   To model Wishbone accurately, we always do this as a 4-byte access, with a
 
   mask for the bytes we don't want.
 
 
 
   Since this is only a byte, the endianess of the value is irrelevant.
 
 
 
   @note We are passed the device address, but we must convert it to a full
 
         address for external use, to allow the single upcall handler to
 
         decode multiple generic devices.
 
 
 
   @param[in] addr  The device address to write to (host endian)
 
   @param[in] value The byte value to write
 
   @param[in] dat   The device data structure                                */
 
/* --------------------------------------------------------------------------*/
static void
static void
generic_write_byte (oraddr_t addr, uint8_t value, void *dat)
generic_write_byte (oraddr_t  addr,
 
                    uint8_t   value,
 
                    void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.write_up)
    {
    {
      fprintf (stderr, "Byte write to disabled generic device\n");
      fprintf (stderr, "Byte write to disabled generic device\n");
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
    {
    {
      fprintf (stderr, "Byte written out of range for generic device %s "
      fprintf (stderr, "Byte written out of range for generic device %s "
               "(addr %" PRIxADDR ")\n", dev->name, addr);
               "(addr %" PRIxADDR ")\n", dev->name, addr);
    }
    }
  else
  else
    {
    {
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long int  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
      unsigned long int  wordaddr = fulladdr & 0xfffffffc;
 
      int                bytenum  = fulladdr & 0x00000003;
 
 
 
      unsigned char      mask[4];
 
      unsigned char      val[4];
 
 
      unsigned long  bytenum  = fulladdr & 0x00000003;
      /* Set the mask and write data do the write. */
      uint8_t        mask_array[4];
      memset (mask, 0, sizeof (mask));
      uint8_t        value_array[4];
      mask[bytenum] = 0xff;
 
      val[bytenum]  = value;
      /* This works whatever the host endianess */
 
      memset (mask_array, 0, 4);
      if (0 != config.ext.write_up (NULL, wordaddr, mask, val, 4))
      mask_array[bytenum] = 0xff;
        {
      memset (value_array, 0, 4);
          fprintf (stderr, "Warning: external byte write failed.\n");
      value_array[bytenum] = value;
        }
 
 
      unsigned long int *arg1_ptr = (unsigned long int *)mask_array;
 
      unsigned long int *arg2_ptr = (unsigned long int *)value_array;
 
      ext_write (wordaddr, *arg1_ptr, *arg2_ptr);
 
    }
    }
}                               /* generic_write_byte() */
}                               /* generic_write_byte() */
 
 
 
 
/* Result is in model endianess */
/* --------------------------------------------------------------------------*/
 
/*!Read a half word from an external device
 
 
 
   To model Wishbone accurately, we always do this as a 4-byte access, with a
 
   mask for the bytes we don't want.
 
 
 
   Since this is a half word, the result must be converted to host endianess.
 
 
 
   @note We are passed the device address, but we must convert it to a full
 
         address for external use, to allow the single upcall handler to
 
         decode multiple generic devices.
 
 
 
   @param[in] addr  The device address to read from (host endian).
 
   @param[in] dat   The device data structure.
 
 
 
   @return  The half word read (host endian).                                */
 
/* --------------------------------------------------------------------------*/
static uint16_t
static uint16_t
generic_read_hw (oraddr_t addr, void *dat)
generic_read_hw (oraddr_t  addr,
 
                 void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.read_up)
    {
    {
      fprintf (stderr, "Half word read from disabled generic device\n");
      fprintf (stderr, "Half word read from disabled generic device\n");
      return 0;
      return 0;
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
Line 290... Line 227...
               "(addr %" PRIxADDR ")\n", dev->name, addr);
               "(addr %" PRIxADDR ")\n", dev->name, addr);
      return 0;
      return 0;
    }
    }
  else if (addr & 0x1)
  else if (addr & 0x1)
    {
    {
 
      /* This should be trapped elsewhere - here for safety. */
      fprintf (stderr,
      fprintf (stderr,
               "Unaligned half word read from 0x%" PRIxADDR " ignored\n",
               "Unaligned half word read from 0x%" PRIxADDR " ignored\n",
               addr);
               addr);
      return 0;
      return 0;
    }
    }
  else
  else
    {
    {
      unsigned long   fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long int  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long   wordaddr = fulladdr & 0xfffffffc;
      unsigned long int  wordaddr = fulladdr & 0xfffffffc;
      unsigned long   bytenum  = fulladdr & 0x00000002;
      int                hwnum    = fulladdr & 0x00000002;
 
 
      uint8_t         mask_array[4];
 
      unsigned long   res;
 
      uint8_t        *res_array;
 
      uint8_t         hwres_array[2];
 
 
 
      /* This works whatever the host endianess */
 
      memset (mask_array, 0, 4);
 
      mask_array[bytenum]     = 0xff;
 
      mask_array[bytenum + 1] = 0xff;
 
 
 
      unsigned int *arg_ptr = (unsigned int *) mask_array;
 
      res       = ext_read (wordaddr, *arg_ptr);
 
      res_array = (uint8_t *)(&res);
 
 
 
      hwres_array[0] = res_array[bytenum];
      unsigned char      mask[4];
      hwres_array[1] = res_array[bytenum + 1];
      unsigned char      res[4];
 
 
      uint16_t *hwres_ptr = (uint16_t *) hwres_array;
      /* Set the mask, read and get the result */
      return htoms (*hwres_ptr);
      memset (mask, 0, sizeof (mask));
 
      mask[hwnum    ] = 0xff;
 
      mask[hwnum + 1] = 0xff;
 
 
 
      if (0 != config.ext.read_up (NULL, wordaddr, mask, res, 4))
 
        {
 
          fprintf (stderr, "Warning: external half word read failed.\n");
 
          return  0;
 
        }
 
 
 
      /* Result converted according to endianess */
 
#ifdef OR32_BIG_ENDIAN
 
      return  (unsigned short int) res[hwnum    ] << 8 |
 
              (unsigned short int) res[hwnum + 1];
 
#else
 
      return  (unsigned short int) res[hwnum + 1] << 8 |
 
              (unsigned short int) res[hwnum    ];
 
#endif
    }
    }
}                               /* generic_read_hw() */
}                               /* generic_read_hw() */
 
 
 
 
/* Value is in model endianness */
/* --------------------------------------------------------------------------*/
 
/*!Write a half word to an external device
 
 
 
   To model Wishbone accurately, we always do this as a 4-byte access, with a
 
   mask for the bytes we don't want.
 
 
 
   Since this is a half word, the value must be converted from host endianess.
 
 
 
   @note We are passed the device address, but we must convert it to a full
 
         address for external use, to allow the single upcall handler to
 
         decode multiple generic devices.
 
 
 
   @param[in] addr  The device address to write to (host endian).
 
   @param[in] value The half word value to write (model endian).
 
   @param[in] dat   The device data structure.                               */
 
/* --------------------------------------------------------------------------*/
static void
static void
generic_write_hw (oraddr_t addr, uint16_t value, void *dat)
generic_write_hw (oraddr_t  addr,
 
                  uint16_t  value,
 
                  void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.write_up)
    {
    {
      fprintf (stderr, "Half word write to disabled generic device\n");
      fprintf (stderr, "Half word write to disabled generic device\n");
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
    {
    {
Line 346... Line 304...
      fprintf (stderr,
      fprintf (stderr,
               "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr);
               "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr);
    }
    }
  else
  else
    {
    {
      uint16_t       host_value = mtohs (value);
      unsigned long int  fulladdr = (unsigned long int) (addr + dev->baseaddr);
 
      unsigned long int  wordaddr = fulladdr & 0xfffffffc;
 
      int                hwnum    = fulladdr & 0x00000002;
 
 
 
      unsigned char      mask[4];
 
      unsigned char      val[4];
 
 
 
      /* Set the mask and write data do the write. */
 
      memset (mask, 0, sizeof (mask));
 
      mask[hwnum    ] = 0xff;
 
      mask[hwnum + 1] = 0xff;
 
 
 
      /* Value converted according to endianess */
 
#ifdef OR32_BIG_ENDIAN
 
      val[hwnum    ] = (unsigned char) (value >> 8);
 
      val[hwnum + 1] = (unsigned char) (value     );
 
#else
 
      val[hwnum + 1] = (unsigned char) (value >> 8);
 
      val[hwnum    ] = (unsigned char) (value     );
 
#endif
 
 
      unsigned long  fulladdr = (unsigned long int) (addr + dev->baseaddr);
      if (0 != config.ext.write_up (NULL, wordaddr, mask, val, 4))
      unsigned long  wordaddr = fulladdr & 0xfffffffc;
        {
      unsigned long  bytenum  = fulladdr & 0x00000002;
          fprintf (stderr, "Warning: external half word write failed.\n");
 
        }
      uint8_t        mask_array[4];
 
      uint8_t        value_array[4];
 
      uint8_t       *hw_value_array;
 
 
 
      /* This works whatever the host endianess */
 
      memset (mask_array, 0, 4);
 
      mask_array[bytenum]     = 0xff;
 
      mask_array[bytenum + 1] = 0xff;
 
 
 
      memset (value_array, 0, 4);
 
      hw_value_array           = (uint8_t *)(&host_value);
 
      value_array[bytenum]     = hw_value_array[0];
 
      value_array[bytenum + 1] = hw_value_array[1];
 
 
 
      unsigned long int *arg1_ptr = (unsigned long int *)mask_array;
 
      unsigned long int *arg2_ptr = (unsigned long int *)value_array;
 
      ext_write (wordaddr, *arg1_ptr, *arg2_ptr);
 
    }
    }
}                               /* generic_write_hw() */
}                               /* generic_write_hw() */
 
 
 
 
 
/* --------------------------------------------------------------------------*/
 
/*!Read a full word from an external device
 
 
 
   Since this is a full word, the result must be converted to host endianess.
 
 
 
   @note We are passed the device address, but we must convert it to a full
 
         address for external use, to allow the single upcall handler to
 
         decode multiple generic devices.
 
 
 
   @param[in] addr  The device address to read from (host endian).
 
   @param[in] dat   The device data structure.
 
 
 
   @return  The full word read (host endian).                                */
 
/* --------------------------------------------------------------------------*/
static uint32_t
static uint32_t
generic_read_word (oraddr_t addr, void *dat)
generic_read_word (oraddr_t  addr,
 
                   void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.read_up)
    {
    {
      fprintf (stderr, "Full word read from disabled generic device\n");
      fprintf (stderr, "Full word read from disabled generic device\n");
      return 0;
      return 0;
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
Line 398... Line 373...
               addr);
               addr);
      return 0;
      return 0;
    }
    }
  else
  else
    {
    {
      unsigned long wordaddr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long int  wordaddr = (unsigned long int) (addr + dev->baseaddr);
 
 
 
      unsigned char      mask[4];
 
      unsigned char      res[4];
 
 
      return (uint32_t) htoml (ext_read (wordaddr, 0xffffffff));
      /* Set the mask, read and get the result */
 
      memset (mask, 0xff, sizeof (mask));
 
 
 
      if (0 != config.ext.read_up (NULL, wordaddr, mask, res, 4))
 
        {
 
          fprintf (stderr, "Warning: external full word read failed.\n");
 
          return  0;
 
        }
 
 
 
      /* Result converted according to endianess */
 
#ifdef OR32_BIG_ENDIAN
 
      return  (unsigned long int) res[0] << 24 |
 
              (unsigned long int) res[1] << 16 |
 
              (unsigned long int) res[2] <<  8 |
 
              (unsigned long int) res[3];
 
#else
 
      return  (unsigned long int) res[3] << 24 |
 
              (unsigned long int) res[2] << 16 |
 
              (unsigned long int) res[1] <<  8 |
 
              (unsigned long int) res[0];
 
#endif
    }
    }
}                               /* generic_read_word() */
}                               /* generic_read_word() */
 
 
 
 
 
/* --------------------------------------------------------------------------*/
 
/*!Write a full word to an external device
 
 
 
   Since this is a half word, the value must be converted from host endianess.
 
 
 
   @note We are passed the device address, but we must convert it to a full
 
         address for external use, to allow the single upcall handler to
 
         decode multiple generic devices.
 
 
 
   @param[in] addr  The device address to write to (host endian).
 
   @param[in] value The full word value to write (host endian).
 
   @param[in] dat   The device data structure.                               */
 
/* --------------------------------------------------------------------------*/
static void
static void
generic_write_word (oraddr_t addr, uint32_t value, void *dat)
generic_write_word (oraddr_t  addr,
 
                    uint32_t  value,
 
                    void     *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *) dat;
  struct dev_generic *dev = (struct dev_generic *) dat;
 
 
  if (!config.ext.class_ptr)
  if (!config.ext.write_up)
    {
    {
      fprintf (stderr, "Full word write to disabled generic device\n");
      fprintf (stderr, "Full word write to disabled generic device\n");
    }
    }
  else if (addr >= dev->size)
  else if (addr >= dev->size)
    {
    {
Line 426... Line 439...
      fprintf (stderr,
      fprintf (stderr,
               "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr);
               "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr);
    }
    }
  else
  else
    {
    {
      unsigned long host_value = mtohl (value);
      unsigned long int  wordaddr = (unsigned long int) (addr + dev->baseaddr);
      unsigned long wordaddr   = (unsigned long int) (addr + dev->baseaddr);
 
 
      unsigned char      mask[4];
 
      unsigned char      val[4];
 
 
 
      /* Set the mask and write data do the write. */
 
      memset (mask, 0xff, sizeof (mask));
 
 
      ext_write (wordaddr, 0xffffffff, host_value);
      /* Value converted according to endianess */
 
#ifdef OR32_BIG_ENDIAN
 
      val[0] = (unsigned char) (value >> 24);
 
      val[1] = (unsigned char) (value >> 16);
 
      val[2] = (unsigned char) (value >>  8);
 
      val[3] = (unsigned char) (value      );
 
#else
 
      val[3] = (unsigned char) (value >> 24);
 
      val[2] = (unsigned char) (value >> 16);
 
      val[1] = (unsigned char) (value >>  8);
 
      val[0] = (unsigned char) (value      );
 
#endif
 
 
 
      if (0 != config.ext.write_up (NULL, wordaddr, mask, val, 4))
 
        {
 
          fprintf (stderr, "Warning: external full word write failed.\n");
 
        }
    }
    }
}                               /* generic_write_word() */
}                               /* generic_write_word() */
 
 
 
 
/* Reset is a null operation */
/* Reset is a null operation */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.