Line 49... |
Line 49... |
#include "dcache_model.h"
|
#include "dcache_model.h"
|
#include "icache_model.h"
|
#include "icache_model.h"
|
#include "debug.h"
|
#include "debug.h"
|
#include "stats.h"
|
#include "stats.h"
|
|
|
extern uorreg_t reg[];
|
|
extern char *disassembled;
|
extern char *disassembled;
|
|
|
/* This is an abstract+physical memory array rather than only physical
|
|
memory array */
|
|
static uint32_t *simmem32;
|
|
|
|
/* Pointer to memory area descriptions that are assigned to individual
|
/* Pointer to memory area descriptions that are assigned to individual
|
peripheral devices. */
|
peripheral devices. */
|
struct dev_memarea *dev_list;
|
struct dev_memarea *dev_list;
|
|
|
/* Temporary variable to increase speed. */
|
/* Temporary variable to increase speed. */
|
Line 86... |
Line 81... |
/* Register read and write function for a memory area.
|
/* Register read and write function for a memory area.
|
addr is inside the area, if addr & addr_mask == addr_compare
|
addr is inside the area, if addr & addr_mask == addr_compare
|
(used also by peripheral devices like 16450 UART etc.) */
|
(used also by peripheral devices like 16450 UART etc.) */
|
void register_memoryarea_mask(oraddr_t addr_mask, oraddr_t addr_compare,
|
void register_memoryarea_mask(oraddr_t addr_mask, oraddr_t addr_compare,
|
uint32_t size, unsigned granularity, unsigned mc_dev,
|
uint32_t size, unsigned granularity, unsigned mc_dev,
|
uint32_t (readfunc)(oraddr_t),
|
uint32_t (readfunc)(oraddr_t, void *),
|
void (writefunc)(oraddr_t, uint32_t))
|
void (writefunc)(oraddr_t, uint32_t, void *),
|
|
void *dat)
|
{
|
{
|
struct dev_memarea **pptmp;
|
struct dev_memarea **pptmp;
|
unsigned int size_mask = bit_mask (size);
|
unsigned int size_mask = bit_mask (size);
|
int found_error = 0;
|
int found_error = 0;
|
addr_compare &= addr_mask;
|
addr_compare &= addr_mask;
|
Line 134... |
Line 130... |
(*pptmp)->readfunc = readfunc;
|
(*pptmp)->readfunc = readfunc;
|
(*pptmp)->writefunc = writefunc;
|
(*pptmp)->writefunc = writefunc;
|
(*pptmp)->log = 0;
|
(*pptmp)->log = 0;
|
(*pptmp)->delayr = 2;
|
(*pptmp)->delayr = 2;
|
(*pptmp)->delayw = 2;
|
(*pptmp)->delayw = 2;
|
|
(*pptmp)->priv_dat = dat;
|
(*pptmp)->next = NULL;
|
(*pptmp)->next = NULL;
|
}
|
}
|
|
|
/* Register read and write function for a memory area.
|
/* Register read and write function for a memory area.
|
Memory areas should be aligned. Memory area is rounded up to
|
Memory areas should be aligned. Memory area is rounded up to
|
fit the nearest 2^n aligment.
|
fit the nearest 2^n aligment.
|
(used also by peripheral devices like 16450 UART etc.)
|
(used also by peripheral devices like 16450 UART etc.)
|
If mc_dev is 1, this means that this device will be checked first for match
|
If mc_dev is 1, this means that this device will be checked first for match
|
and will be accessed in case in overlaping memory spaces.
|
and will be accessed in case of overlaping memory spaces.
|
Only one device can have this set to 1 (used for memory controller) */
|
Only one device can have this set to 1 (used for memory controller) */
|
void register_memoryarea(oraddr_t addr, uint32_t size, unsigned granularity,
|
void register_memoryarea(oraddr_t addr, uint32_t size, unsigned granularity,
|
unsigned mc_dev,
|
unsigned mc_dev,
|
uint32_t (readfunc)(oraddr_t),
|
uint32_t (readfunc)(oraddr_t, void *),
|
void (writefunc)(oraddr_t, uint32_t))
|
void (writefunc)(oraddr_t, uint32_t, void *),
|
|
void *dat)
|
{
|
{
|
unsigned int size_mask = bit_mask (size);
|
unsigned int size_mask = bit_mask (size);
|
unsigned int addr_mask = ~size_mask;
|
unsigned int addr_mask = ~size_mask;
|
register_memoryarea_mask (addr_mask, addr & addr_mask,
|
register_memoryarea_mask (addr_mask, addr & addr_mask,
|
size_mask + 1, granularity, mc_dev,
|
size_mask + 1, granularity, mc_dev,
|
readfunc, writefunc);
|
readfunc, writefunc, dat);
|
}
|
}
|
|
|
|
|
/* Check if access is to registered area of memory. */
|
/* Check if access is to registered area of memory. */
|
inline struct dev_memarea *verify_memoryarea(oraddr_t addr)
|
inline struct dev_memarea *verify_memoryarea(oraddr_t addr)
|
Line 216... |
Line 214... |
uint32_t temp = 0;
|
uint32_t temp = 0;
|
|
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch(cur_area->granularity) {
|
switch(cur_area->granularity) {
|
case 4:
|
case 4:
|
temp = cur_area->readfunc(memaddr);
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat);
|
break;
|
break;
|
case 1:
|
case 1:
|
temp = cur_area->readfunc(memaddr) << 24;
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat) << 24;
|
temp |= cur_area->readfunc(memaddr + 1) << 16;
|
temp |= cur_area->readfunc(memaddr + 1, cur_area->priv_dat) << 16;
|
temp |= cur_area->readfunc(memaddr + 2) << 8;
|
temp |= cur_area->readfunc(memaddr + 2, cur_area->priv_dat) << 8;
|
temp |= cur_area->readfunc(memaddr + 3);
|
temp |= cur_area->readfunc(memaddr + 3, cur_area->priv_dat);
|
break;
|
break;
|
case 2:
|
case 2:
|
temp = cur_area->readfunc(memaddr) << 16;
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat) << 16;
|
temp |= cur_area->readfunc(memaddr + 2);
|
temp |= cur_area->readfunc(memaddr + 2, cur_area->priv_dat);
|
break;
|
break;
|
default:
|
default:
|
/* if you add new memory granularity be sure to check the formula
|
/* if you add new memory granularity be sure to check the formula
|
* below for the read delay and fix it if necessery
|
* below for the read delay and fix it if necessery
|
*/
|
*/
|
Line 260... |
Line 258... |
uint32_t temp = 0;
|
uint32_t temp = 0;
|
|
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch(cur_area->granularity) {
|
switch(cur_area->granularity) {
|
case 1:
|
case 1:
|
temp = cur_area->readfunc(memaddr) << 8;
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat) << 8;
|
temp |= cur_area->readfunc(memaddr + 1);
|
temp |= cur_area->readfunc(memaddr + 1, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayr * 2;
|
runtime.sim.mem_cycles += cur_area->delayr * 2;
|
break;
|
break;
|
case 2:
|
case 2:
|
temp = cur_area->readfunc(memaddr);
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayr;
|
runtime.sim.mem_cycles += cur_area->delayr;
|
break;
|
break;
|
case 4:
|
case 4:
|
temp = evalsim_mem32_atomic (memaddr & ~UINT32_C(3), cpu_access);
|
temp = evalsim_mem32_atomic (memaddr & ~UINT32_C(3), cpu_access);
|
Line 307... |
Line 305... |
uint32_t temp = 0;
|
uint32_t temp = 0;
|
|
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch(cur_area->granularity) {
|
switch(cur_area->granularity) {
|
case 1:
|
case 1:
|
temp = cur_area->readfunc(memaddr);
|
temp = cur_area->readfunc(memaddr, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayr;
|
runtime.sim.mem_cycles += cur_area->delayr;
|
break;
|
break;
|
case 2:
|
case 2:
|
temp = evalsim_mem16_atomic (memaddr & ~ADDR_C(1), cpu_access);
|
temp = evalsim_mem16_atomic (memaddr & ~ADDR_C(1), cpu_access);
|
Line 638... |
Line 636... |
void setsim_mem32_atomic(oraddr_t memaddr, uint32_t value, int cpu_access)
|
void setsim_mem32_atomic(oraddr_t memaddr, uint32_t value, int cpu_access)
|
{
|
{
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch(cur_area->granularity) {
|
switch(cur_area->granularity) {
|
case 4:
|
case 4:
|
cur_area->writefunc(memaddr, value);
|
cur_area->writefunc(memaddr, value, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw;
|
runtime.sim.mem_cycles += cur_area->delayw;
|
break;
|
break;
|
case 1:
|
case 1:
|
cur_area->writefunc(memaddr , (value >> 24) & 0xFF);
|
cur_area->writefunc(memaddr , (value >> 24) & 0xFF, cur_area->priv_dat);
|
cur_area->writefunc(memaddr + 1, (value >> 16) & 0xFF);
|
cur_area->writefunc(memaddr + 1, (value >> 16) & 0xFF, cur_area->priv_dat);
|
cur_area->writefunc(memaddr + 2, (value >> 8) & 0xFF);
|
cur_area->writefunc(memaddr + 2, (value >> 8) & 0xFF, cur_area->priv_dat);
|
cur_area->writefunc(memaddr + 3, (value ) & 0xFF);
|
cur_area->writefunc(memaddr + 3, (value ) & 0xFF, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw * 4;
|
runtime.sim.mem_cycles += cur_area->delayw * 4;
|
break;
|
break;
|
case 2:
|
case 2:
|
cur_area->writefunc(memaddr, (value >> 16) & 0xFFFF);
|
cur_area->writefunc(memaddr, (value >> 16) & 0xFFFF, cur_area->priv_dat);
|
cur_area->writefunc(memaddr + 2, value & 0xFFFF);
|
cur_area->writefunc(memaddr + 2, value & 0xFFFF, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw * 2;
|
runtime.sim.mem_cycles += cur_area->delayw * 2;
|
break;
|
break;
|
default:
|
default:
|
/* if you add new memory granularity be sure to check the formula
|
/* if you add new memory granularity be sure to check the formula
|
Line 688... |
Line 686... |
{
|
{
|
uint32_t temp;
|
uint32_t temp;
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch(cur_area->granularity) {
|
switch(cur_area->granularity) {
|
case 1:
|
case 1:
|
cur_area->writefunc(memaddr, (value >> 8) & 0xFF);
|
cur_area->writefunc(memaddr, (value >> 8) & 0xFF, cur_area->priv_dat);
|
cur_area->writefunc(memaddr + 1, value & 0xFF);
|
cur_area->writefunc(memaddr + 1, value & 0xFF, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw * 2;
|
runtime.sim.mem_cycles += cur_area->delayw * 2;
|
break;
|
break;
|
case 2:
|
case 2:
|
cur_area->writefunc(memaddr, value & 0xFFFF);
|
cur_area->writefunc(memaddr, value & 0xFFFF, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw;
|
runtime.sim.mem_cycles += cur_area->delayw;
|
break;
|
break;
|
case 4:
|
case 4:
|
temp = evalsim_mem32_void(memaddr & ~ADDR_C(3));
|
temp = evalsim_mem32_void(memaddr & ~ADDR_C(3));
|
Line 736... |
Line 734... |
{
|
{
|
uint32_t temp;
|
uint32_t temp;
|
if (verify_memoryarea(memaddr)) {
|
if (verify_memoryarea(memaddr)) {
|
switch (cur_area->granularity) {
|
switch (cur_area->granularity) {
|
case 1:
|
case 1:
|
cur_area->writefunc(memaddr, value);
|
cur_area->writefunc(memaddr, value, cur_area->priv_dat);
|
if (cpu_access)
|
if (cpu_access)
|
runtime.sim.mem_cycles += cur_area->delayw;
|
runtime.sim.mem_cycles += cur_area->delayw;
|
break;
|
break;
|
case 2:
|
case 2:
|
temp = evalsim_mem16_void (memaddr & ~ADDR_C(1));
|
temp = evalsim_mem16_void (memaddr & ~ADDR_C(1));
|
Line 990... |
Line 988... |
if (nl)
|
if (nl)
|
PRINTF ("\n");
|
PRINTF ("\n");
|
}
|
}
|
}
|
}
|
|
|
uint32_t simmem_read_word(oraddr_t addr) {
|
uint32_t simmem_read_word(oraddr_t addr, void *priv_dat) {
|
return simmem32[(cur_area->misc + (addr & cur_area->size_mask)) >> 2];
|
return *(uint32_t *)(priv_dat + (addr & cur_area->size_mask));
|
}
|
}
|
|
|
void simmem_write_word(oraddr_t addr, uint32_t value) {
|
void simmem_write_word(oraddr_t addr, uint32_t value, void *priv_dat) {
|
simmem32[(cur_area->misc + (addr & cur_area->size_mask)) >> 2] = value;
|
*(uint32_t *)(priv_dat + (addr & cur_area->size_mask)) = value;
|
}
|
}
|
|
|
uint32_t simmem_read_zero(oraddr_t addr) {
|
uint32_t simmem_read_zero(oraddr_t addr, void *dat) {
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
fprintf (stderr, "WARNING: memory read from non-read memory area 0x%"
|
fprintf (stderr, "WARNING: memory read from non-read memory area 0x%"
|
PRIxADDR".\n", addr);
|
PRIxADDR".\n", addr);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
void simmem_write_null(oraddr_t addr, uint32_t value) {
|
void simmem_write_null(oraddr_t addr, uint32_t value, void *dat) {
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
fprintf (stderr, "WARNING: memory write to 0x%"PRIxADDR", non-write memory area (value 0x%08"PRIx32").\n", addr, value);
|
fprintf (stderr, "WARNING: memory write to 0x%"PRIxADDR", non-write memory area (value 0x%08"PRIx32").\n", addr, value);
|
}
|
}
|
|
|
/* Initialize memory table from a config struct */
|
/* Initialize memory table from a config struct */
|
|
|
void init_memory_table ()
|
void init_memory_table ()
|
{
|
{
|
uint32_t memory_needed = 0;
|
|
|
|
/* If nothing was defined, use default memory block */
|
/* If nothing was defined, use default memory block */
|
if (config.memory.nmemories) {
|
if (config.memory.nmemories) {
|
int i;
|
int i;
|
for (i = 0; i < config.memory.nmemories; i++) {
|
for (i = 0; i < config.memory.nmemories; i++) {
|
oraddr_t start = config.memory.table[i].baseaddr;
|
oraddr_t start = config.memory.table[i].baseaddr;
|
uint32_t length = config.memory.table[i].size;
|
uint32_t length = config.memory.table[i].size;
|
char *type = config.memory.table[i].name;
|
char *type = config.memory.table[i].name;
|
int rd = config.memory.table[i].delayr;
|
int rd = config.memory.table[i].delayr;
|
int wd = config.memory.table[i].delayw;
|
int wd = config.memory.table[i].delayw;
|
int ce = config.memory.table[i].ce;
|
int ce = config.memory.table[i].ce;
|
|
void *mem = malloc (length);
|
|
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
debug (1, "%"PRIxADDR" %08"PRIx32" (%"PRIi32" KB): %s (activated by CE%i; read delay = %icyc, write delay = %icyc)\n",
|
debug (1, "%"PRIxADDR" %08"PRIx32" (%"PRIi32" KB): %s (activated by CE%i; read delay = %icyc, write delay = %icyc)\n",
|
start, length, length >> 10, type, ce, rd, wd);
|
start, length, length >> 10, type, ce, rd, wd);
|
|
|
|
if (!mem) {
|
|
fprintf (stderr, "Failed to allocate sim memory. Aborting\n");
|
|
exit (-1);
|
|
}
|
|
|
register_memoryarea(start, length, 4, 0, &simmem_read_word,
|
register_memoryarea(start, length, 4, 0, &simmem_read_word,
|
&simmem_write_word);
|
&simmem_write_word, mem);
|
cur_area->misc = memory_needed;
|
|
cur_area->chip_select = ce;
|
cur_area->chip_select = ce;
|
cur_area->valid = 1;
|
cur_area->valid = 1;
|
cur_area->delayw = wd;
|
cur_area->delayw = wd;
|
cur_area->delayr = rd;
|
cur_area->delayr = rd;
|
if (config.memory.table[i].log[0] != '\0') {
|
if (config.memory.table[i].log[0] != '\0') {
|
if ((cur_area->log = fopen (config.memory.table[i].log, "wt+")) == NULL)
|
if ((cur_area->log = fopen (config.memory.table[i].log, "wt+")) == NULL)
|
fprintf (stderr, "WARNING: Cannot open '%s'.\n",
|
fprintf (stderr, "WARNING: Cannot open '%s'.\n",
|
config.memory.table[i].log);
|
config.memory.table[i].log);
|
} else
|
} else
|
cur_area->log = NULL;
|
cur_area->log = NULL;
|
memory_needed += cur_area->size;
|
|
}
|
}
|
PRINTF ("\n");
|
PRINTF ("\n");
|
} else {
|
} else {
|
|
void *mem = malloc (DEFAULT_MEMORY_LEN);
|
if (config.sim.verbose)
|
if (config.sim.verbose)
|
fprintf (stderr, "WARNING: Memory not defined, assuming standard configuration.\n");
|
fprintf (stderr, "WARNING: Memory not defined, assuming standard configuration.\n");
|
|
|
|
if (!mem) {
|
|
fprintf (stderr, "Failed to allocate sim memory. Aborting\n");
|
|
exit (-1);
|
|
}
|
|
|
register_memoryarea(DEFAULT_MEMORY_START, DEFAULT_MEMORY_LEN, 4, 0,
|
register_memoryarea(DEFAULT_MEMORY_START, DEFAULT_MEMORY_LEN, 4, 0,
|
&simmem_read_word, &simmem_write_word);
|
&simmem_read_word, &simmem_write_word, mem);
|
cur_area->misc = memory_needed;
|
|
cur_area->chip_select = 0;
|
cur_area->chip_select = 0;
|
cur_area->valid = 1;
|
cur_area->valid = 1;
|
cur_area->delayw = 1;
|
cur_area->delayw = 1;
|
cur_area->delayr = 1;
|
cur_area->delayr = 1;
|
cur_area->log = NULL;
|
cur_area->log = NULL;
|
memory_needed += cur_area->size;
|
|
}
|
|
|
|
simmem32 = (uint32_t *) malloc (sizeof (uint32_t) * ((memory_needed + 3) / 4));
|
|
if (!simmem32) {
|
|
fprintf (stderr, "Failed to allocate sim memory. Aborting\n");
|
|
exit (-1);
|
|
}
|
}
|
}
|
}
|
|
|
/* Changes read/write memory in read/write only */
|
/* Changes read/write memory in read/write only */
|
|
|