?? flatmem.c
字號:
/* top->p_ABus->bus_BusyUntil++; */
}
if ((address >= top->LowestPeripheralAddress) &&
(address <= top->HighestPeripheralAddress) &&
(rv = peripheral_access(handle,address,data,acc)) != -2)
{
return rv;
}
pageno=address>>PAGEBITS;
page=top->mem.page[pageno];
if (page==NULL) {
top->mem.page[pageno]=page=NewPage(top,address);
}
offset = address & OFFSETBITS_WORD;
ptr=(ARMword *)((char *)(page->memory)+offset);
if (acc==acc_LoadInstrS) {
*data=*ptr;
return 1;
} else if (acc_MREQ(acc)) {
if (acc_READ(acc)) {
switch (acc & WIDTH_MASK) {
case BITS_8: /* read byte */
if (HostEndian!=top->read_bigend) address^=3;
*data = ((unsigned8 *)ptr)[address & 3];
break;
case BITS_16: { /* read half-word */
/* extract half-word */
#ifndef HOST_HAS_NO_16BIT_TYPE
/*
* unsigned16 is always a 16-bit type, but if there is no native
* 16-bit type (e.g. ARM!) then we can do something a bit more
* cunning.
*/
if (HostEndian!=top->read_bigend) address^=2;
*data = *((unsigned16 *)(((char *)ptr)+(address & 2)));
#else
unsigned32 datum;
datum=*ptr;
if (HostEndian!=top->read_bigend) address^=2;
if (address & 2) datum<<=16;
*data = (datum>>16);
#endif
}
break;
case BITS_32: /* read word */
*data=*ptr;
break;
case BITS_64: /* read dword */
*data=*ptr;
if ((offset+4) & OFFSETBITS_WORD)
{
data[1]=ptr[1];
return 2;
}
break;
default:
return_PERIP_DABORT;
}
} else {
switch (acc & WIDTH_MASK) {
/* extract byte */
case BITS_8: /* write_byte */
if (HostEndian!=top->write_bigend) address^=3;
((unsigned8 *)ptr)[address & 3]=(unsigned8)(*data);
break;
case BITS_16: /* write half-word */
if (HostEndian!=top->write_bigend) address^=2;
*((unsigned16 *)(((char *)ptr)+(address & 2))) = (unsigned16)(*data);
break;
case BITS_32: /* write word */
*ptr=*data;
break;
case BITS_64: /* write dword */
*ptr=*data;
if ((offset+4) &OFFSETBITS_WORD)
{
ptr[1]=data[1];
return 2;
}
break;
default:
return_PERIP_DABORT;
}
} /* internal cycle */
}
return 1;
}
#ifdef PIPELINED
/*
* This function gets called before every memory access with the address and
* cycle type for the next cycle.
*/
static void NextCycle(void *handle,
ARMword address,
ARMul_acc acc)
{
/* armflat does not make use of pipelined addresses */
UNUSEDARG(handle); UNUSEDARG(address); UNUSEDARG(acc);
}
#endif /* PIPELINED */
#if 1
# define CHECKTOTAL
#else
/* ... This only works if we are called for every cycle ... */
# define CHECKTOTAL \
assert(top->p_ABus->bus_BusyUntil == \
(top->cycles.NumNcycles + top->cycles.NumScycles +\
top->cycles.NumIcycles+top->cycles.NumCcycles));
#endif
/*
* This is the most basic memory access function - an ARM610/ARM710 interface.
*
* Optimised for word loads and idle cycles
*/
static int MemAccessCached(void *handle,
ARMword address,
ARMword *data,
ARMul_acc acc)
{
toplevel *top=(toplevel *)handle;
unsigned int pageno;
mempage *page;
ARMword *ptr;
ARMword offset;
int rv;
if (acc_ACCOUNT(acc)) {
COUNTCYCLES(top->cycles,acc);
/* top->p_ABus->bus_BusyUntil++; */
CHECKTOTAL
}
if ((address >= top->LowestPeripheralAddress) &&
(address <= top->HighestPeripheralAddress) &&
(rv = peripheral_access(handle,address,data,acc)) != -2)
{
return rv;
}
if (ACCESS_IS_IDLE(acc))
return 1;
pageno=address>>PAGEBITS;
page=top->mem.page[pageno];
/* !TODO: if (page==dummyPage && ACCESS_IS_WRITE)... */
if (page==NULL)
{
top->mem.page[pageno]=page=NewPage(top,address);
}
offset = address & OFFSETBITS_WORD;
ptr=(ARMword *)((char *)(page->memory)+offset);
if (acc==acc_LoadWordS) {
*data=*ptr;
return 1;
} else if (acc_MREQ(acc)) {
if (acc_READ(acc)) {
switch (acc & WIDTH_MASK) {
case BITS_8: /* read byte */
if (HostEndian!=top->read_bigend) address^=3;
*data = ((unsigned8 *)ptr)[address & 3];
break;
case BITS_16: { /* read half-word */
/* extract half-word */
#ifndef HOST_HAS_NO_16BIT_TYPE
/*
* unsigned16 is always a 16-bit type, but if there is no native
* 16-bit type (e.g. ARM!) then we can do something a bit more
* cunning.
*/
if (HostEndian!=top->read_bigend) address^=2;
*data = *((unsigned16 *)(((char *)ptr)+(address & 2)));
#else
unsigned32 datum;
datum=*ptr;
if (HostEndian!=top->read_bigend) address^=2;
if (address & 2) datum<<=16;
*data = (datum>>16);
#endif
}
break;
case BITS_32: /* read word */
*data=*ptr;
break;
case BITS_64: /* read dword */
*data=*ptr;
if ((offset+4) & OFFSETBITS_WORD)
{
data[1]=ptr[1];
return 2;
}
break;
default:
return_PERIP_DABORT;
}
} else {
switch (acc & WIDTH_MASK) {
/* extract byte */
case BITS_8: /* write_byte */
if (HostEndian!=top->write_bigend) address^=3;
((unsigned8 *)ptr)[address & 3]=(unsigned8)(*data);
break;
case BITS_16: /* write half-word */
if (HostEndian!=top->write_bigend) address^=2;
*((unsigned16 *)(((char *)ptr)+(address & 2))) = (unsigned16)(*data);
break;
case BITS_32: /* write word */
*ptr=*data;
break;
case BITS_64: /* write dword */
*ptr=*data;
if ((offset+4) &OFFSETBITS_WORD)
{
ptr[1]=data[1];
return 2;
}
break;
default:
return_PERIP_DABORT;
}
} /* internal cycle */
}
return 1;
}
/*
* Same function, but optimised for Thumb accesses
*/
static int MemAccessThumb(void *handle,
ARMword address,
ARMword *data,
ARMul_acc acc)
{
toplevel *top=(toplevel *)handle;
unsigned int pageno;
mempage *page;
ARMword *ptr;
ARMword offset;
int rv;
if (acc_ACCOUNT(acc)) {
COUNTCYCLES(top->cycles,acc);
/* top->p_ABus->bus_BusyUntil++; */
CHECKTOTAL
}
if ((address >= top->LowestPeripheralAddress) &&
(address <= top->HighestPeripheralAddress) &&
(rv = peripheral_access(handle,address,data,acc)) != -2)
{
return rv;
}
pageno=address>>PAGEBITS;
page=top->mem.page[pageno];
if (page==NULL) {
top->mem.page[pageno]=page=NewPage(top,address);
}
offset = address & OFFSETBITS_WORD;
ptr=(ARMword *)((char *)(page->memory)+offset);
switch (acc & (ACCESS_SIZE_MASK | ACCESS_IDLE | ACCESS_WRITE) )
{
case BITS_8: /* read byte */
*data = ((unsigned8 *)ptr)[(address ^ top->byteAddrXor) & 3];
break;
case BITS_16: /* read half-word */
*data = *((unsigned16 *)(((char *)ptr)+
((address ^ top->hwordAddrXor) & 2)));
return 1;
case BITS_32: /* read word */
*data=*ptr;
return 1;
/* This case should not be needed for MemAccessThumb,
* but I intend to merge that with MemAccessCached. */
case BITS_64: /* read dword */
*data=*ptr;
if ((offset+4) & OFFSETBITS_WORD)
{
data[1]=ptr[1];
return 2;
}
break;
case BITS_8 | ACCESS_WRITE: /* write_byte */
if (HostEndian!=top->write_bigend) address^=3;
((unsigned8 *)ptr)[address & 3]=(unsigned8)(*data);
break;
case BITS_16 | ACCESS_WRITE: /* write half-word */
if (HostEndian!=top->write_bigend) address^=2;
*((unsigned16 *)(((char *)ptr)+(address & 2))) = (unsigned16)(*data);
break;
case BITS_32 | ACCESS_WRITE: /* write word */
*ptr=*data;
break;
case BITS_64 | ACCESS_WRITE: /* write dword */
*ptr=*data;
if ((offset+4) &OFFSETBITS_WORD)
{
ptr[1]=data[1];
return 2; /* PERIP_OK2 */
}
break;
case BITS_8 | ACCESS_IDLE:
case BITS_16 | ACCESS_IDLE:
case BITS_32 | ACCESS_IDLE:
case BITS_64 | ACCESS_IDLE:
case ACCESS_IDLE:
return 1;
default:
return_PERIP_DABORT;
}
return 1;
}
#ifdef MEM_ACCESS2_DISTINCT /* F */
/*
* This function is used by ARM8. Effectively we model a memory
* system which can return two words per cycle.
* The differences between this an a normal 64-bit bus (ARM10, XScale)
* are
* (1) 64-bit fetches need not be DWORD aligned.
* (2) A non-aligned fetch just below a 64k-boundary may return just one word!
*/
static int MemAccess2(void *handle,
ARMword address,
ARMword *data,ARMword *data2,
ARMul_acc acc)
{
toplevel *top=(toplevel *)handle;
unsigned int pageno;
mempage *page;
ARMword *ptr;
ARMword offset;
int words=1;
int rv;
if (acc_ACCOUNT(acc)) {
COUNTCYCLES(top->cycles,acc);
/* top->p_ABus->bus_BusyUntil++; */
CHECKTOTAL
}
if ((address >= top->LowestPeripheralAddress) &&
(address <= top->HighestPeripheralAddress) &&
(rv = peripheral_access(handle,address,data,acc)) != -2)
{
return rv;
}
pageno=address>>PAGEBITS;
page=top->mem.page[pageno];
if (page==NULL) {
top->mem.page[pageno]=page=NewPage(top,address);
}
offset = address & OFFSETBITS_WORD;
ptr=(ARMword *)((char *)(page->memory)+offset);
if (acc_MREQ(acc)) {
if (acc_READ(acc)) {
switch (acc & WIDTH_MASK) {
case BITS_8: /* read byte */
if (HostEndian!=top->read_bigend) address^=3;
*data = ((unsigned8 *)ptr)[address & 3];
break;
case BITS_16: { /* read half-word */
/* extract half-word */
if (HostEndian!=top->read_bigend) address^=2;
*data = *((unsigned16 *)(((char *)ptr)+(address & 2)));
}
break;
case BITS_32: /* read word */
*data=*ptr;
break;
case BITS_64: /* read two words */
*data=*ptr;
if ((offset+4) & OFFSETBITS_WORD) { *data2=ptr[1]; words=2; }
break;
default:
return_PERIP_DABORT;
}
} else {
switch (acc & WIDTH_MASK) {
/* extract byte */
case BITS_8: /* write_byte */
if (HostEndian!=top->write_bigend) address^=3;
((unsigned8 *)ptr)[address & 3]=(unsigned8)(*data);
break;
case BITS_16: /* write half-word */
if (HostEndian!=top->write_bigend) address^=2;
*((unsigned16 *)(((char *)ptr)+(address & 2)))=(unsigned16)(*data);
break;
case BITS_32: /* write word */
*ptr=*data;
break;
default:
return_PERIP_DABORT;
}
} /* internal cycle */
}
return words;
}
#endif
/*
* A memory model used by StrongARM. This only accounts
* for cycles on opcode boundaries - i.e. we allow both a data
* and an instruction fetch on one cycle.
*/
static int MemAccessSA(void *handle,
ARMword address,
ARMword *data,
ARMul_acc acc)
{
toplevel *top=(toplevel *)handle;
unsigned int pageno;
mempage *page;
ARMword *ptr;
ARMword offset;
int rv;
/*
* On StrongARM there are four types of cycle - we'll reuse
* the four cycle counters for these:
*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -