25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory_rw.c,v 1.82 2005/12/31 15:48:32 debug Exp $ |
* $Id: memory_rw.c,v 1.87 2006/06/22 11:43:03 debug Exp $ |
29 |
* |
* |
30 |
* Generic memory_rw(), with special hacks for specific CPU families. |
* Generic memory_rw(), with special hacks for specific CPU families. |
31 |
* |
* |
53 |
* If the address indicates access to a memory mapped device, that device' |
* If the address indicates access to a memory mapped device, that device' |
54 |
* read/write access function is called. |
* read/write access function is called. |
55 |
* |
* |
|
* If instruction latency/delay support is enabled, then |
|
|
* cpu->instruction_delay is increased by the number of instruction to |
|
|
* delay execution. |
|
|
* |
|
56 |
* This function should not be called with cpu == NULL. |
* This function should not be called with cpu == NULL. |
57 |
* |
* |
58 |
* Returns one of the following: |
* Returns one of the following: |
76 |
uint64_t paddr; |
uint64_t paddr; |
77 |
int cache, no_exceptions, offset; |
int cache, no_exceptions, offset; |
78 |
unsigned char *memblock; |
unsigned char *memblock; |
|
#ifdef MEM_MIPS |
|
|
int bintrans_cached = cpu->machine->bintrans_enable; |
|
|
#endif |
|
79 |
int dyntrans_device_danger = 0; |
int dyntrans_device_danger = 0; |
80 |
|
|
81 |
no_exceptions = misc_flags & NO_EXCEPTIONS; |
no_exceptions = misc_flags & NO_EXCEPTIONS; |
143 |
} |
} |
144 |
#endif /* X86 */ |
#endif /* X86 */ |
145 |
|
|
|
#ifdef MEM_MIPS |
|
|
if (bintrans_cached) { |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_bintrans_host_4kpage = NULL; |
|
|
cpu->cd.mips.pc_bintrans_paddr_valid = 0; |
|
|
} |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
146 |
|
|
147 |
#ifdef MEM_USERLAND |
#ifdef MEM_USERLAND |
148 |
#ifdef MEM_ALPHA |
#ifdef MEM_ALPHA |
150 |
#else |
#else |
151 |
paddr = vaddr & 0x7fffffff; |
paddr = vaddr & 0x7fffffff; |
152 |
#endif |
#endif |
153 |
goto have_paddr; |
#else /* !MEM_USERLAND */ |
|
#endif |
|
|
|
|
|
#ifndef MEM_USERLAND |
|
|
#ifdef MEM_MIPS |
|
|
/* |
|
|
* For instruction fetch, are we on the same page as the last |
|
|
* instruction we fetched? |
|
|
* |
|
|
* NOTE: There's no need to check this stuff here if this address |
|
|
* is known to be in host ram, as it's done at instruction fetch |
|
|
* time in cpu.c! Only check if _host_4k_page == NULL. |
|
|
*/ |
|
|
if (cache == CACHE_INSTRUCTION && |
|
|
cpu->cd.mips.pc_last_host_4k_page == NULL && |
|
|
(vaddr & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) { |
|
|
paddr = cpu->cd.mips.pc_last_physical_page | (vaddr & 0xfff); |
|
|
goto have_paddr; |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
|
|
|
154 |
if (misc_flags & PHYSICAL || cpu->translate_address == NULL) { |
if (misc_flags & PHYSICAL || cpu->translate_address == NULL) { |
155 |
paddr = vaddr; |
paddr = vaddr; |
|
#ifdef MEM_ALPHA |
|
|
/* paddr &= 0x1fffffff; For testalpha */ |
|
|
paddr &= 0x000003ffffffffffULL; |
|
|
#endif |
|
156 |
} else { |
} else { |
157 |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
158 |
(writeflag? FLAG_WRITEFLAG : 0) + |
(writeflag? FLAG_WRITEFLAG : 0) + |
187 |
#endif |
#endif |
188 |
} |
} |
189 |
#endif |
#endif |
190 |
|
#endif /* !MEM_USERLAND */ |
|
#ifdef MEM_MIPS |
|
|
/* |
|
|
* If correct cache emulation is enabled, and we need to simluate |
|
|
* cache misses even from the instruction cache, we can't run directly |
|
|
* from a host page. :-/ |
|
|
*/ |
|
|
#if defined(ENABLE_CACHE_EMULATION) && defined(ENABLE_INSTRUCTION_DELAYS) |
|
|
#else |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_last_virtual_page = vaddr & ~0xfff; |
|
|
cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff; |
|
|
cpu->cd.mips.pc_last_host_4k_page = NULL; |
|
|
|
|
|
/* _last_host_4k_page will be set to 1 further down, |
|
|
if the page is actually in host ram */ |
|
|
} |
|
|
#endif |
|
|
#endif /* MEM_MIPS */ |
|
|
#endif /* ifndef MEM_USERLAND */ |
|
|
|
|
|
|
|
|
#if defined(MEM_MIPS) || defined(MEM_USERLAND) |
|
|
have_paddr: |
|
|
#endif |
|
|
|
|
|
|
|
|
#ifdef MEM_MIPS |
|
|
/* TODO: How about bintrans vs cache emulation? */ |
|
|
if (bintrans_cached) { |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_bintrans_paddr_valid = 1; |
|
|
cpu->cd.mips.pc_bintrans_paddr = paddr; |
|
|
} |
|
|
} |
|
|
#endif /* MEM_MIPS */ |
|
|
|
|
191 |
|
|
192 |
|
|
193 |
#ifndef MEM_USERLAND |
#ifndef MEM_USERLAND |
301 |
data, len, writeflag, |
data, len, writeflag, |
302 |
mem->dev_extra[i]); |
mem->dev_extra[i]); |
303 |
|
|
|
#ifdef ENABLE_INSTRUCTION_DELAYS |
|
304 |
if (res == 0) |
if (res == 0) |
305 |
res = -1; |
res = -1; |
306 |
|
|
|
#ifdef MEM_MIPS |
|
|
cpu->cd.mips.instruction_delay += |
|
|
( (abs(res) - 1) * |
|
|
cpu->cd.mips.cpu_type.instrs_per_cycle ); |
|
|
#endif |
|
|
#endif |
|
|
|
|
307 |
#ifndef MEM_X86 |
#ifndef MEM_X86 |
308 |
/* |
/* |
309 |
* If accessing the memory mapped device |
* If accessing the memory mapped device |
372 |
#endif /* MIPS */ |
#endif /* MIPS */ |
373 |
{ |
{ |
374 |
if (paddr >= mem->physical_max) { |
if (paddr >= mem->physical_max) { |
375 |
|
uint64_t offset, old_pc = cpu->pc; |
376 |
char *symbol; |
char *symbol; |
|
uint64_t offset; |
|
|
#ifdef MEM_MIPS |
|
|
uint64_t old_pc = cpu->cd.mips.pc_last; |
|
|
#else |
|
|
uint64_t old_pc = cpu->pc; |
|
|
#endif |
|
377 |
|
|
378 |
/* This allows for example OS kernels to probe |
/* This allows for example OS kernels to probe |
379 |
memory a few KBs past the end of memory, |
memory a few KBs past the end of memory, |
420 |
fatal(" <%s> ]\n", |
fatal(" <%s> ]\n", |
421 |
symbol? symbol : " no symbol "); |
symbol? symbol : " no symbol "); |
422 |
} |
} |
|
|
|
|
if (cpu->machine->single_step_on_bad_addr) { |
|
|
fatal("[ unimplemented access to " |
|
|
"0x%llx, pc=0x",(long long)paddr); |
|
|
if (cpu->is_32bit) |
|
|
fatal("%08x ]\n", |
|
|
(int)old_pc); |
|
|
else |
|
|
fatal("%016llx ]\n", |
|
|
(long long)old_pc); |
|
|
single_step = 1; |
|
|
} |
|
423 |
} |
} |
424 |
|
|
425 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
522 |
*(uint8_t *)data = *(uint8_t *)(memblock + offset); |
*(uint8_t *)data = *(uint8_t *)(memblock + offset); |
523 |
else |
else |
524 |
memcpy(data, memblock + offset, len); |
memcpy(data, memblock + offset, len); |
|
|
|
|
#ifdef MEM_MIPS |
|
|
if (cache == CACHE_INSTRUCTION) { |
|
|
cpu->cd.mips.pc_last_host_4k_page = memblock |
|
|
+ (offset & ~offset_mask); |
|
|
if (bintrans_cached) { |
|
|
cpu->cd.mips.pc_bintrans_host_4kpage = |
|
|
cpu->cd.mips.pc_last_host_4k_page; |
|
|
} |
|
|
} |
|
|
#endif /* MIPS */ |
|
525 |
} |
} |
526 |
|
|
527 |
|
|