25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: memory_rw.c,v 1.16 2005/04/19 01:24:35 debug Exp $ |
* $Id: memory_rw.c,v 1.37 2005/06/02 12:31:39 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 |
* |
* |
86 |
vaddr &= 0xffffffff; |
vaddr &= 0xffffffff; |
87 |
#endif |
#endif |
88 |
|
|
89 |
|
#ifdef MEM_ARM |
90 |
|
vaddr &= 0x0fffffff; |
91 |
|
#endif |
92 |
|
|
93 |
#ifdef MEM_X86 |
#ifdef MEM_X86 |
94 |
if (cpu->cd.x86.bits == 32) { |
/* Real-mode wrap-around: */ |
95 |
if ((vaddr >> 32) == 0xffffffff) |
if (REAL_MODE && !(cache_flags & PHYSICAL)) { |
96 |
vaddr &= 0xffffffff; |
if ((vaddr & 0xffff) + len > 0x10000) { |
97 |
|
/* Do one byte at a time: */ |
98 |
/* TODO: Actual address translation */ |
int res = 0, i; |
99 |
if ((vaddr >> 32) == 0) { |
for (i=0; i<len; i++) |
100 |
vaddr &= 0x0fffffff; |
res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1, |
101 |
|
writeflag, cache_flags); |
102 |
if (cpu->cd.x86.mode == 16) { |
return res; |
103 |
vaddr = (cpu->cd.x86.cursegment<<4) + |
} |
104 |
(vaddr & 0xffff); |
} |
105 |
/* TODO: A20 stuff */ |
|
106 |
if ((vaddr & 0xffff) + len > 0x10000) { |
/* Crossing a page boundary? Then do one byte at a time: */ |
107 |
fatal("x86 memory access crossing" |
if ((vaddr & 0xfff) + len > 0x1000 && !(cache_flags & PHYSICAL) |
108 |
" segment boundary: TODO\n"); |
&& cpu->cd.x86.cr[0] & X86_CR0_PG) { |
109 |
cpu->running = 0; |
/* For WRITES: Read ALL BYTES FIRST and write them back!!! |
110 |
|
Then do a write of all the new bytes. This is to make sure |
111 |
|
than both pages around the boundary are writable so we don't |
112 |
|
do a partial write. */ |
113 |
|
int res = 0, i; |
114 |
|
if (writeflag == MEM_WRITE) { |
115 |
|
unsigned char tmp; |
116 |
|
for (i=0; i<len; i++) { |
117 |
|
res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1, |
118 |
|
MEM_READ, cache_flags); |
119 |
|
if (!res) |
120 |
|
return 0; |
121 |
|
res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1, |
122 |
|
MEM_WRITE, cache_flags); |
123 |
|
if (!res) |
124 |
|
return 0; |
125 |
|
} |
126 |
|
for (i=0; i<len; i++) { |
127 |
|
res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1, |
128 |
|
MEM_WRITE, cache_flags); |
129 |
|
if (!res) |
130 |
|
return 0; |
131 |
|
} |
132 |
|
} else { |
133 |
|
for (i=0; i<len; i++) { |
134 |
|
/* Do one byte at a time: */ |
135 |
|
res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1, |
136 |
|
writeflag, cache_flags); |
137 |
|
if (!res) { |
138 |
|
if (cache == CACHE_INSTRUCTION) { |
139 |
|
fatal("FAILED instruction " |
140 |
|
"fetch across page boundar" |
141 |
|
"y: todo. vaddr=0x%08x\n", |
142 |
|
(int)vaddr); |
143 |
|
cpu->running = 0; |
144 |
|
} |
145 |
return 0; |
return 0; |
146 |
} |
} |
147 |
} |
} |
148 |
} |
} |
149 |
|
return res; |
150 |
} |
} |
151 |
#endif |
#endif /* X86 */ |
152 |
|
|
153 |
#ifdef MEM_URISC |
#ifdef MEM_URISC |
154 |
{ |
{ |
199 |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
ok = cpu->translate_address(cpu, vaddr, &paddr, |
200 |
(writeflag? FLAG_WRITEFLAG : 0) + |
(writeflag? FLAG_WRITEFLAG : 0) + |
201 |
(no_exceptions? FLAG_NOEXCEPTIONS : 0) |
(no_exceptions? FLAG_NOEXCEPTIONS : 0) |
202 |
|
#ifdef MEM_X86 |
203 |
|
+ (cache_flags & NO_SEGMENTATION) |
204 |
|
#endif |
205 |
+ (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0)); |
+ (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0)); |
206 |
/* If the translation caused an exception, or was invalid in |
/* If the translation caused an exception, or was invalid in |
207 |
some way, we simply return without doing the memory |
some way, we simply return without doing the memory |
211 |
} |
} |
212 |
|
|
213 |
|
|
214 |
|
#ifdef MEM_X86 |
215 |
|
/* DOS debugging :-) */ |
216 |
|
if (!quiet_mode && !(cache_flags & PHYSICAL)) { |
217 |
|
if (paddr >= 0x400 && paddr <= 0x4ff) |
218 |
|
debug("{ PC BIOS DATA AREA: %s 0x%x }\n", writeflag == |
219 |
|
MEM_WRITE? "writing to" : "reading from", |
220 |
|
(int)paddr); |
221 |
|
#if 0 |
222 |
|
if (paddr >= 0xf0000 && paddr <= 0xfffff) |
223 |
|
debug("{ BIOS ACCESS: %s 0x%x }\n", |
224 |
|
writeflag == MEM_WRITE? "writing to" : |
225 |
|
"reading from", (int)paddr); |
226 |
|
#endif |
227 |
|
} |
228 |
|
#endif |
229 |
|
|
230 |
#ifdef MEM_MIPS |
#ifdef MEM_MIPS |
231 |
/* |
/* |
232 |
* If correct cache emulation is enabled, and we need to simluate |
* If correct cache emulation is enabled, and we need to simluate |
266 |
#endif /* MEM_MIPS */ |
#endif /* MEM_MIPS */ |
267 |
|
|
268 |
|
|
|
if (!(cache_flags & PHYSICAL)) |
|
|
if (no_exceptions) |
|
|
goto no_exception_access; |
|
|
|
|
269 |
|
|
270 |
#ifndef MEM_USERLAND |
#ifndef MEM_USERLAND |
271 |
/* |
/* |
355 |
} |
} |
356 |
#endif |
#endif |
357 |
|
|
358 |
res = mem->dev_f[i](cpu, mem, paddr, data, len, |
res = 0; |
359 |
writeflag, mem->dev_extra[i]); |
if (!no_exceptions || (mem->dev_flags[i] & |
360 |
|
MEM_READING_HAS_NO_SIDE_EFFECTS)) |
361 |
|
res = mem->dev_f[i](cpu, mem, paddr, |
362 |
|
data, len, writeflag, |
363 |
|
mem->dev_extra[i]); |
364 |
|
|
365 |
#ifdef ENABLE_INSTRUCTION_DELAYS |
#ifdef ENABLE_INSTRUCTION_DELAYS |
366 |
if (res == 0) |
if (res == 0) |
370 |
( (abs(res) - 1) * |
( (abs(res) - 1) * |
371 |
cpu->cd.mips.cpu_type.instrs_per_cycle ); |
cpu->cd.mips.cpu_type.instrs_per_cycle ); |
372 |
#endif |
#endif |
373 |
|
|
374 |
|
#ifndef MEM_X86 |
375 |
/* |
/* |
376 |
* If accessing the memory mapped device |
* If accessing the memory mapped device |
377 |
* failed, then return with a DBE exception. |
* failed, then return with a DBE exception. |
378 |
*/ |
*/ |
379 |
if (res <= 0) { |
if (res <= 0 && !no_exceptions) { |
380 |
debug("%s device '%s' addr %08lx " |
debug("%s device '%s' addr %08lx " |
381 |
"failed\n", writeflag? |
"failed\n", writeflag? |
382 |
"writing to" : "reading from", |
"writing to" : "reading from", |
387 |
#endif |
#endif |
388 |
return MEMORY_ACCESS_FAILED; |
return MEMORY_ACCESS_FAILED; |
389 |
} |
} |
390 |
|
#endif |
391 |
goto do_return_ok; |
goto do_return_ok; |
392 |
} |
} |
393 |
|
|
451 |
|
|
452 |
/* Outside of physical RAM? */ |
/* Outside of physical RAM? */ |
453 |
if (paddr >= mem->physical_max) { |
if (paddr >= mem->physical_max) { |
454 |
if ((paddr & 0xffff000000ULL) == 0x1f000000) { |
#ifdef MEM_MIPS |
455 |
|
if ((paddr & 0xffffc00000ULL) == 0x1fc00000) { |
456 |
/* Ok, this is PROM stuff */ |
/* Ok, this is PROM stuff */ |
457 |
} else if ((paddr & 0xfffff00000ULL) == 0x1ff00000) { |
} else if ((paddr & 0xfffff00000ULL) == 0x1ff00000) { |
458 |
/* Sprite reads from this area of memory... */ |
/* Sprite reads from this area of memory... */ |
460 |
if (writeflag == MEM_READ) |
if (writeflag == MEM_READ) |
461 |
memset(data, 0, len); |
memset(data, 0, len); |
462 |
goto do_return_ok; |
goto do_return_ok; |
463 |
} else { |
} else |
464 |
if (paddr >= mem->physical_max + 0 * 1024) { |
#endif /* MIPS */ |
465 |
|
{ |
466 |
|
if (paddr >= mem->physical_max) { |
467 |
char *symbol; |
char *symbol; |
468 |
#ifdef MEM_MIPS |
#ifdef MEM_MIPS |
469 |
uint64_t offset; |
uint64_t offset; |
470 |
#endif |
#endif |
471 |
if (!quiet_mode) { |
/* This allows for example OS kernels to probe |
472 |
|
memory a few KBs past the end of memory, |
473 |
|
without giving too many warnings. */ |
474 |
|
if (!quiet_mode && paddr >= |
475 |
|
mem->physical_max + 0x40000) { |
476 |
fatal("[ memory_rw(): writeflag=%i ", |
fatal("[ memory_rw(): writeflag=%i ", |
477 |
writeflag); |
writeflag); |
478 |
if (writeflag) { |
if (writeflag) { |
526 |
} |
} |
527 |
|
|
528 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
529 |
|
#ifdef MEM_X86 |
530 |
|
/* Reading non-existant memory on x86: */ |
531 |
|
memset(data, 0xff, len); |
532 |
|
#else |
533 |
/* Return all zeroes? (Or 0xff? TODO) */ |
/* Return all zeroes? (Or 0xff? TODO) */ |
534 |
memset(data, 0, len); |
memset(data, 0, len); |
535 |
|
#endif |
536 |
|
|
537 |
#ifdef MEM_MIPS |
#ifdef MEM_MIPS |
538 |
/* |
/* |
540 |
* an exceptions on an illegal read: |
* an exceptions on an illegal read: |
541 |
*/ |
*/ |
542 |
if (cache != CACHE_NONE && cpu->machine-> |
if (cache != CACHE_NONE && cpu->machine-> |
543 |
dbe_on_nonexistant_memaccess) { |
dbe_on_nonexistant_memaccess && |
544 |
|
!no_exceptions) { |
545 |
if (paddr >= mem->physical_max && |
if (paddr >= mem->physical_max && |
546 |
paddr < mem->physical_max+1048576) |
paddr < mem->physical_max+1048576) |
547 |
mips_cpu_exception(cpu, |
mips_cpu_exception(cpu, |
561 |
#endif /* ifndef MEM_USERLAND */ |
#endif /* ifndef MEM_USERLAND */ |
562 |
|
|
563 |
|
|
|
no_exception_access: |
|
|
|
|
564 |
/* |
/* |
565 |
* Uncached access: |
* Uncached access: |
566 |
*/ |
*/ |
602 |
else |
else |
603 |
memcpy(data, memblock + offset, len); |
memcpy(data, memblock + offset, len); |
604 |
|
|
605 |
|
#ifdef MEM_MIPS |
606 |
if (cache == CACHE_INSTRUCTION) { |
if (cache == CACHE_INSTRUCTION) { |
607 |
cpu->cd.mips.pc_last_host_4k_page = memblock |
cpu->cd.mips.pc_last_host_4k_page = memblock |
608 |
+ (offset & ~0xfff); |
+ (offset & ~0xfff); |
613 |
} |
} |
614 |
#endif |
#endif |
615 |
} |
} |
616 |
|
#endif /* MIPS */ |
617 |
} |
} |
618 |
|
|
619 |
|
|