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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [peripheral/] [generic.c] - Diff between revs 1745 and 1748

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

Rev 1745 Rev 1748
Line 17... Line 17...
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
 
/* This program is commented throughout in a fashion suitable for processing
 
   with Doxygen. */
 
 
/* This is functional simulation of any external peripheral. It's job is to
/* This is functional simulation of any external peripheral. It's job is to
 * trap accesses in a specific range, so that the simulator can drive an
 * trap accesses in a specific range, so that the simulator can drive an
 * external device.
 * external device.
 */
 */
 
 
#include <stdlib.h>
/* Autoconf and/or portability configuration */
#include <stdio.h>
 
#include <string.h>
 
 
 
#include "config.h"
#include "config.h"
 
 
#ifdef HAVE_INTTYPES_H
/* System includes */
#include <inttypes.h>
#include <stdlib.h>
#endif
#include <stdio.h>
 
 
#include "or1ksim.h"
/* Package includes */
#include "port.h"
 
#include "arch.h"
#include "arch.h"
#include "abstract.h"
 
#include "sim-config.h"
#include "sim-config.h"
#include "pic.h"
#include "abstract.h"
#include "vapi.h"
#include "toplevel-support.h"
#include "sched.h"
#include "sim-cmd.h"
#include "channel.h"
 
#include "debug.h"
 
 
/*! State associated with the generic device. */
 
struct dev_generic
 
{
 
 
 
  /* Info about a particular transaction */
 
 
 
  enum
 
  {                             /* Direction of the access */
 
    GENERIC_READ,
 
    GENERIC_WRITE
 
  } trans_direction;
 
 
#include "generic.h"
  enum
 
  {                             /* Size of the access */
 
    GENERIC_BYTE,
 
    GENERIC_HW,
 
    GENERIC_WORD
 
  } trans_size;
 
 
 
  uint32_t value;               /* The value to read/write */
 
 
DEFAULT_DEBUG_CHANNEL( generic );
  /* Configuration */
 
 
 
  int enabled;                  /* Device enabled */
 
  int byte_enabled;             /* Byte R/W allowed */
 
  int hw_enabled;               /* Half word R/W allowed */
 
  int word_enabled;             /* Full word R/W allowed */
 
  char *name;                   /* Name of the device */
 
  oraddr_t baseaddr;            /* Base address of device */
 
  uint32_t size;                /* Address space size (bytes) */
 
 
 
};
 
 
 
 
/* Generic read and write upcall routines. Note the address here is absolute,
/* Generic read and write upcall routines. Note the address here is absolute,
   not relative to the device. */
   not relative to the device. */
 
 
static unsigned long int  ext_read( unsigned long int  addr,
static unsigned long int
                                    unsigned long int  mask )
ext_read (unsigned long int addr, unsigned long int mask)
{
{
  return config.ext.read_up( config.ext.class_ptr, addr, mask );
  return config.ext.read_up( config.ext.class_ptr, addr, mask );
 
 
}       /* ext_callback() */
}       /* ext_callback() */
 
 
 
 
/* Generic read and write upcall routines. Note the address here is absolute,
/* Generic read and write upcall routines. Note the address here is absolute,
   not relative to the device. */
   not relative to the device. */
 
 
static void  ext_write( unsigned long int  addr,
static void
                        unsigned long int  mask,
ext_write (unsigned long int addr,
                        unsigned long int  value )
           unsigned long int mask, unsigned long int value)
{
{
  config.ext.write_up( config.ext.class_ptr, addr, mask, value );
  config.ext.write_up( config.ext.class_ptr, addr, mask, value );
 
 
}       /* ext_callback() */
}       /* ext_callback() */
 
 
 
 
/* I/O routines. Note that address is relative to start of address space. */
/* I/O routines. Note that address is relative to start of address space. */
 
 
static uint8_t  generic_read_byte( oraddr_t  addr,
static uint8_t
                                   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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Byte read out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Byte read  out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
    return 0;
    return 0;
  }
  }
  else {
  else
 
    {
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
 
 
#ifdef WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
Line 109... Line 136...
#endif      
#endif      
  }
  }
}       /* generic_read_byte() */
}       /* generic_read_byte() */
 
 
 
 
static void  generic_write_byte( oraddr_t  addr,
static void
                                 uint8_t   value,
generic_write_byte (oraddr_t addr, uint8_t value, void *dat)
                                 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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Byte write out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Byte written out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
  }
  }
  else {
  else
 
    {
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
 
 
#ifdef WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
Line 140... Line 169...
    ext_write( wordaddr, mask, wordval );
    ext_write( wordaddr, mask, wordval );
  }
  }
}       /* generic_write_byte() */
}       /* generic_write_byte() */
 
 
 
 
static uint16_t  generic_read_hw( oraddr_t  addr,
static uint16_t
                                  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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Half word read out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Half-word read  out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
    return 0;
    return 0;
  }
  }
  else if( addr & 0x1 ) {
  else if (addr & 0x1)
    fprintf( stderr, "Unaligned half word read from 0x" PRIxADDR " ignored\n",
    {
 
      fprintf (stderr,
 
               "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  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
 
 
#ifdef WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
Line 179... Line 213...
#endif      
#endif      
  }
  }
}       /* generic_read_hw() */
}       /* generic_read_hw() */
 
 
 
 
static void  generic_write_hw( oraddr_t  addr,
static void
                               uint16_t  value,
generic_write_hw (oraddr_t addr, uint16_t value, void *dat)
                               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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Half word write out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Half-word written  out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
  }
  }
  else if( addr & 0x1 ) {
  else if (addr & 0x1)
    fprintf( stderr, "Unaligned half word write to 0x" PRIxADDR " ignored\n",
    {
             addr );
      fprintf (stderr,
 
               "Unaligned half word write to 0x%" PRIxADDR " ignored\n", addr);
  }
  }
  else{
  else
 
    {
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  fulladdr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  wordaddr = fulladdr & 0xfffffffc;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
    unsigned long  bitoff   = (fulladdr & 0x00000003) << 3;
 
 
#ifdef WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
Line 214... Line 251...
    ext_write( wordaddr, mask, wordval );
    ext_write( wordaddr, mask, wordval );
  }
  }
}       /* generic_write_hw() */
}       /* generic_write_hw() */
 
 
 
 
static uint32_t  generic_read_word( oraddr_t  addr,
static uint32_t
                                    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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Full word read out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Full word read  out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
    return 0;
    return 0;
  }
  }
  else if( 0 != (addr & 0x3) ) {
  else if (0 != (addr & 0x3))
    fprintf( stderr, "Unaligned full word read from 0x" PRIxADDR " ignored\n",
    {
 
      fprintf (stderr,
 
               "Unaligned full word read from 0x%" PRIxADDR " ignored\n",
             addr );
             addr );
    return 0;
    return 0;
  }
  }
  else {
  else
 
    {
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
 
 
    return (uint32_t) ext_read( wordaddr, 0xffffffff );
    return (uint32_t) ext_read( wordaddr, 0xffffffff );
  }
  }
}       /* generic_read_word() */
}       /* generic_read_word() */
 
 
 
 
static void  generic_write_word( oraddr_t  addr,
static void
                                 uint32_t   value,
generic_write_word (oraddr_t addr, uint32_t value, void *dat)
                                 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.class_ptr)
 
    {
    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)
    TRACE( "Generic device \"%s\": Full word write out of range (addr %"
    {
           PRIxADDR ")\n", dev->name, addr );
      fprintf (stderr, "Full word written  out of range for generic device %s "
 
               "(addr %" PRIxADDR ")\n", dev->name, addr);
  }
  }
  else if( 0 != (addr & 0x3) ) {
  else if (0 != (addr & 0x3))
    fprintf( stderr, "Unaligned full word write to 0x" PRIxADDR " ignored\n",
    {
             addr );
      fprintf (stderr,
 
               "Unaligned full word write to 0x%" PRIxADDR " ignored\n", addr);
  }
  }
  else{
  else
 
    {
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
    unsigned long  wordaddr = (unsigned long int)(addr + dev->baseaddr);
 
 
    ext_write( wordaddr, 0xffffffff, value );
    ext_write( wordaddr, 0xffffffff, value );
  }
  }
}       /* generic_write_word() */
}       /* generic_write_word() */
 
 
 
 
/* Reset is a null operation */
/* Reset is a null operation */
 
 
static void  generic_reset( void *dat )
static void
 
generic_reset (void *dat)
{
{
  return;
  return;
 
 
}       /* generic_reset() */
}       /* generic_reset() */
 
 
 
 
/* Status report can only advise of configuration. */
/* Status report can only advise of configuration. */
 
 
static void  generic_status( void *dat )
static void
 
generic_status (void *dat)
{
{
  struct dev_generic *dev = (struct dev_generic *)dat;
  struct dev_generic *dev = (struct dev_generic *)dat;
 
 
  PRINTF( "\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name,
  PRINTF( "\nGeneric device \"%s\" at 0x%" PRIxADDR ":\n", dev->name,
          dev->baseaddr );
          dev->baseaddr );
  PRINTF( "  Size 0x%" PRIx32 "\n", dev->size );
  PRINTF( "  Size 0x%" PRIx32 "\n", dev->size );
 
 
  if( dev->byte_enabled ) {
  if (dev->byte_enabled)
 
    {
    PRINTF( "  Byte R/W enabled\n" );
    PRINTF( "  Byte R/W enabled\n" );
  }
  }
 
 
  if( dev->hw_enabled ) {
  if (dev->hw_enabled)
 
    {
    PRINTF( "  Half word R/W enabled\n" );
    PRINTF( "  Half word R/W enabled\n" );
  }
  }
 
 
  if( dev->word_enabled ) {
  if (dev->word_enabled)
 
    {
    PRINTF( "  Full word R/W enabled\n" );
    PRINTF( "  Full word R/W enabled\n" );
  }
  }
 
 
  PRINTF( "\n" );
  PRINTF( "\n" );
 
 
}       /* generic_status() */
}       /* generic_status() */
 
 
 
 
/* Functions to set configuration */
/* Functions to set configuration */
 
 
static void  generic_enabled( union param_val  val,
static void
                              void            *dat )
generic_enabled (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->enabled = val.int_val;
  ((struct dev_generic *)dat)->enabled = val.int_val;
 
 
}       /* generic_enabled() */
}       /* generic_enabled() */
 
 
 
 
static void  generic_byte_enabled( union param_val  val,
static void
                                   void            *dat )
generic_byte_enabled (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->byte_enabled = val.int_val;
  ((struct dev_generic *)dat)->byte_enabled = val.int_val;
 
 
}       /* generic_byte_enabled() */
}       /* generic_byte_enabled() */
 
 
 
 
static void  generic_hw_enabled( union param_val  val,
static void
                                 void            *dat )
generic_hw_enabled (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->hw_enabled = val.int_val;
  ((struct dev_generic *)dat)->hw_enabled = val.int_val;
 
 
}       /* generic_hw_enabled() */
}       /* generic_hw_enabled() */
 
 
 
 
static void  generic_word_enabled( union param_val  val,
static void
                                   void            *dat )
generic_word_enabled (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->word_enabled = val.int_val;
  ((struct dev_generic *)dat)->word_enabled = val.int_val;
 
 
}       /* generic_word_enabled() */
}       /* generic_word_enabled() */
 
 
 
 
static void  generic_name( union param_val  val,
static void
                           void            *dat )
generic_name (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->name = strdup( val.str_val );
  ((struct dev_generic *)dat)->name = strdup( val.str_val );
 
 
  if( !((struct dev_generic *)dat)->name ) {
  if (!((struct dev_generic *) dat)->name)
 
    {
    fprintf(stderr, "Peripheral 16450: name \"%s\": Run out of memory\n",
    fprintf(stderr, "Peripheral 16450: name \"%s\": Run out of memory\n",
            val.str_val );
            val.str_val );
    exit(-1);
    exit(-1);
  }
  }
}       /* generic_name() */
}       /* generic_name() */
 
 
 
 
static void  generic_baseaddr( union param_val  val,
static void
                               void            *dat )
generic_baseaddr (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->baseaddr = val.addr_val;
  ((struct dev_generic *)dat)->baseaddr = val.addr_val;
 
 
}       /* generic_baseaddr() */
}       /* generic_baseaddr() */
 
 
 
 
static void  generic_size( union param_val  val,
static void
                              void            *dat )
generic_size (union param_val val, void *dat)
{
{
  ((struct dev_generic *)dat)->size = val.int_val;
  ((struct dev_generic *)dat)->size = val.int_val;
 
 
}       /* generic_size() */
}       /* generic_size() */
 
 
 
 
/* Start of new generic section */
/* Start of new generic section */
 
 
static void *generic_sec_start()
static void *
 
generic_sec_start ()
{
{
  struct dev_generic *new =
  struct dev_generic *new =
    (struct dev_generic *)malloc( sizeof( struct dev_generic ));
    (struct dev_generic *)malloc( sizeof( struct dev_generic ));
 
 
  if( 0 == new) {
  if (0 == new)
 
    {
    fprintf( stderr, "Generic peripheral: Run out of memory\n" );
    fprintf( stderr, "Generic peripheral: Run out of memory\n" );
    exit( -1 );
    exit( -1 );
  }
  }
 
 
  /* Default names */
  /* Default names */
Line 394... Line 447...
}       /* generic_sec_start() */
}       /* generic_sec_start() */
 
 
 
 
/* End of new generic section */
/* End of new generic section */
 
 
static void  generic_sec_end( void *dat)
static void
 
generic_sec_end (void *dat)
{
{
  struct dev_generic *generic = (struct dev_generic *)dat;
  struct dev_generic *generic = (struct dev_generic *)dat;
  struct mem_ops      ops;
  struct mem_ops      ops;
 
 
  /* Give up if not enabled, or if size is zero, or if no access size is
  /* Give up if not enabled, or if size is zero, or if no access size is
     enabled. */
     enabled. */
 
 
  if( !generic->enabled ) {
  if (!generic->enabled)
 
    {
    free( dat );
    free( dat );
    return;
    return;
  }
  }
 
 
  if( 0 == generic->size ) {
  if (0 == generic->size)
 
    {
    fprintf( stderr, "Generic peripheral \"%s\" has size 0: ignoring",
    fprintf( stderr, "Generic peripheral \"%s\" has size 0: ignoring",
             generic->name );
             generic->name );
    free( dat );
    free( dat );
    return;
    return;
  }
  }
 
 
  if( !generic->byte_enabled &&
  if( !generic->byte_enabled &&
      !generic->hw_enabled   &&
      !generic->hw_enabled && !generic->word_enabled)
      !generic->word_enabled ) {
    {
    fprintf( stderr, "Generic peripheral \"%s\" has no access: ignoring",
    fprintf( stderr, "Generic peripheral \"%s\" has no access: ignoring",
             generic->name );
             generic->name );
    free( dat );
    free( dat );
    return;
    return;
  }
  }
Line 429... Line 485...
   * come from the peripheral if desired.
   * come from the peripheral if desired.
   */
   */
 
 
  memset( &ops, 0, sizeof( struct mem_ops ));
  memset( &ops, 0, sizeof( struct mem_ops ));
 
 
  if( generic->byte_enabled ) {
  if (generic->byte_enabled)
 
    {
    ops.readfunc8 = generic_read_byte;
    ops.readfunc8 = generic_read_byte;
    ops.writefunc8 = generic_write_byte;
    ops.writefunc8 = generic_write_byte;
    ops.read_dat8 = dat;
    ops.read_dat8 = dat;
    ops.write_dat8 = dat;
    ops.write_dat8 = dat;
  }
  }
 
 
  if( generic->hw_enabled ) {
  if (generic->hw_enabled)
 
    {
    ops.readfunc16 = generic_read_hw;
    ops.readfunc16 = generic_read_hw;
    ops.writefunc16 = generic_write_hw;
    ops.writefunc16 = generic_write_hw;
    ops.read_dat16 = dat;
    ops.read_dat16 = dat;
    ops.write_dat16 = dat;
    ops.write_dat16 = dat;
  }
  }
 
 
  if( generic->word_enabled ) {
  if (generic->word_enabled)
 
    {
    ops.readfunc32 = generic_read_word;
    ops.readfunc32 = generic_read_word;
    ops.writefunc32 = generic_write_word;
    ops.writefunc32 = generic_write_word;
    ops.read_dat32 = dat;
    ops.read_dat32 = dat;
    ops.write_dat32 = dat;
    ops.write_dat32 = dat;
  }
  }
Line 462... Line 521...
}       /* generic_sec_end() */
}       /* generic_sec_end() */
 
 
 
 
/* Register a generic section. */
/* Register a generic section. */
 
 
void reg_generic_sec(void)
void
 
reg_generic_sec (void)
{
{
  struct config_section *sec = reg_config_sec( "generic",
  struct config_section *sec = reg_config_sec( "generic",
                                               generic_sec_start,
                                               generic_sec_start,
                                               generic_sec_end );
                                               generic_sec_end );
 
 

powered by: WebSVN 2.1.0

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