Line 20... |
Line 20... |
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
|
/* This program is commented throughout in a fashion suitable for processing
|
with Doxygen. */
|
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.
|
|
*
|
|
* A note on endianess. All external communication is done using HOST
|
|
* endianess. A set of functions are provided to convert between host and
|
|
* model endianess (htoml, htoms, mtohl, mtohs).
|
*/
|
*/
|
|
|
/* Autoconf and/or portability configuration */
|
/* Autoconf and/or portability configuration */
|
#include "config.h"
|
#include "config.h"
|
|
|
Line 74... |
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
|
|
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
|
|
|
|
return *((unsigned long int *)model_array);
|
|
|
|
} /* 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
|
|
|
|
return *((unsigned short int *)model_array);
|
|
|
|
} /* htoms () */
|
|
|
|
|
|
/* Convert a 32-bit value from model to host endianess */
|
|
static unsigned long int
|
|
mtohl (unsigned long int model_val)
|
|
{
|
|
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;
|
|
|
|
} /* 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,
|
/* Generic read and write upcall routines. Note the address here is absolute,
|
not relative to the device. */
|
not relative to the device. The mask uses host endianess, not Or1ksim
|
|
endianess. */
|
|
|
static unsigned long int
|
static unsigned long int
|
ext_read (unsigned long int addr, 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. The mask and value use host endianess, not
|
|
Or1ksim endianess. */
|
|
|
static void
|
static void
|
ext_write (unsigned long int addr,
|
ext_write (unsigned long int addr,
|
unsigned long int mask, 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() */
|
|
|
Line 119... |
Line 214... |
}
|
}
|
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 bytenum = fulladdr & 0x00000003;
|
|
|
#ifdef OR32_BIG_ENDIAN
|
uint8_t mask_array[4];
|
unsigned long mask = 0x000000ff << (24 - bitoff);
|
unsigned long res;
|
unsigned long res = ext_read (wordaddr, mask);
|
uint8_t *res_array;
|
|
|
return (uint8_t) ((res >> (24 - bitoff)) & 0x000000ff);
|
/* This works whatever the host endianess */
|
#else
|
memset (mask_array, 0, 4);
|
unsigned long mask = 0x000000ff << bitoff;
|
mask_array[bytenum] = 0xff;
|
unsigned long res = ext_read (wordaddr, mask);
|
|
|
|
return (uint8_t) ((res >> bitoff) & 0x00000ff);
|
res = ext_read (wordaddr, *((unsigned int *)mask_array));
|
#endif
|
res_array = (uint8_t *)(&res);
|
|
|
|
return res_array[bytenum];
|
}
|
}
|
} /* generic_read_byte() */
|
} /* generic_read_byte() */
|
|
|
|
|
static void
|
static void
|
Line 154... |
Line 250... |
}
|
}
|
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;
|
|
|
|
#ifdef OR32_BIG_ENDIAN
|
unsigned long bytenum = fulladdr & 0x00000003;
|
unsigned long mask = 0x000000ff << (24 - bitoff);
|
uint8_t mask_array[4];
|
unsigned long wordval = ((unsigned long int) value) << (24 - bitoff);
|
uint8_t value_array[4];
|
#else
|
|
unsigned long mask = 0x000000ff << bitoff;
|
/* This works whatever the host endianess */
|
unsigned long wordval = ((unsigned long int) value) << bitoff;
|
memset (mask_array, 0, 4);
|
#endif
|
mask_array[bytenum] = 0xff;
|
|
memset (value_array, 0, 4);
|
|
value_array[bytenum] = value;
|
|
|
ext_write (wordaddr, mask, wordval);
|
ext_write (wordaddr, *((unsigned long int *)mask_array),
|
|
*((unsigned long int *)value_array));
|
}
|
}
|
} /* generic_write_byte() */
|
} /* generic_write_byte() */
|
|
|
|
|
|
/* Result is in model endianess */
|
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;
|
|
|
Line 196... |
Line 295... |
}
|
}
|
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 bytenum = fulladdr & 0x00000002;
|
|
|
#ifdef OR32_BIG_ENDIAN
|
uint8_t mask_array[4];
|
unsigned long mask = 0x0000ffff << (16 - bitoff);
|
unsigned long res;
|
unsigned long res = ext_read (wordaddr, mask);
|
uint8_t *res_array;
|
|
uint8_t hwres_array[2];
|
|
|
return (uint16_t) ((res >> (16 - bitoff)) & 0x0000ffff);
|
/* This works whatever the host endianess */
|
#else
|
memset (mask_array, 0, 4);
|
unsigned long mask = 0x0000ffff << bitoff;
|
mask_array[bytenum] = 0xff;
|
unsigned long res = ext_read (wordaddr, mask);
|
mask_array[bytenum + 1] = 0xff;
|
|
|
return (uint16_t) ((res >> bitoff) & 0x0000ffff);
|
res = ext_read (wordaddr, *((unsigned int *)mask_array));
|
#endif
|
res_array = (uint8_t *)(&res);
|
|
|
|
hwres_array[0] = res_array[bytenum];
|
|
hwres_array[1] = res_array[bytenum + 1];
|
|
|
|
return htoms (*((uint16_t *)hwres_array));
|
}
|
}
|
} /* generic_read_hw() */
|
} /* generic_read_hw() */
|
|
|
|
|
|
/* Value is in model endianness */
|
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;
|
|
|
Line 234... |
Line 340... |
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 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 bytenum = fulladdr & 0x00000002;
|
|
|
#ifdef OR32_BIG_ENDIAN
|
uint8_t mask_array[4];
|
unsigned long mask = 0x0000ffff << (16 - bitoff);
|
uint8_t value_array[4];
|
unsigned long wordval = ((unsigned long int) value) << (16 - bitoff);
|
uint8_t *hw_value_array;
|
#else
|
|
unsigned long mask = 0x0000ffff << bitoff;
|
/* This works whatever the host endianess */
|
unsigned long wordval = ((unsigned long int) value) << bitoff;
|
memset (mask_array, 0, 4);
|
#endif
|
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];
|
|
|
ext_write (wordaddr, mask, wordval);
|
ext_write (wordaddr, *((unsigned long int *)mask_array),
|
|
*((unsigned long int *)value_array));
|
}
|
}
|
} /* generic_write_hw() */
|
} /* generic_write_hw() */
|
|
|
|
|
static uint32_t
|
static uint32_t
|
Line 278... |
Line 393... |
}
|
}
|
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) htoml (ext_read (wordaddr, 0xffffffff));
|
}
|
}
|
} /* generic_read_word() */
|
} /* generic_read_word() */
|
|
|
|
|
static void
|
static void
|
Line 304... |
Line 419... |
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 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, host_value);
|
}
|
}
|
} /* generic_write_word() */
|
} /* generic_write_word() */
|
|
|
|
|
/* Reset is a null operation */
|
/* Reset is a null operation */
|