/[gxemul]/upstream/0.3.1/src/memory_rw.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.1/src/memory_rw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 13083 byte(s)
0.3.1
1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: memory_rw.c,v 1.10 2005/03/01 08:23:55 debug Exp $
29 *
30 * Generic memory_rw(), with special hacks for specific CPU families.
31 *
32 * Example for inclusion from memory_mips.c:
33 *
34 * MEMORY_RW should be mips_memory_rw
35 * MEM_MIPS should be defined
36 */
37
38
39 /*
40 * memory_rw():
41 *
42 * Read or write data from/to memory.
43 *
44 * cpu the cpu doing the read/write
45 * mem the memory object to use
46 * vaddr the virtual address
47 * data a pointer to the data to be written to memory, or
48 * a placeholder for data when reading from memory
49 * len the length of the 'data' buffer
50 * writeflag set to MEM_READ or MEM_WRITE
51 * cache_flags CACHE_{NONE,DATA,INSTRUCTION} | other flags
52 *
53 * If the address indicates access to a memory mapped device, that device'
54 * read/write access function is called.
55 *
56 * If instruction latency/delay support is enabled, then
57 * cpu->instruction_delay is increased by the number of instruction to
58 * delay execution.
59 *
60 * This function should not be called with cpu == NULL.
61 *
62 * Returns one of the following:
63 * MEMORY_ACCESS_FAILED
64 * MEMORY_ACCESS_OK
65 *
66 * (MEMORY_ACCESS_FAILED is 0.)
67 */
68 int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr,
69 unsigned char *data, size_t len, int writeflag, int cache_flags)
70 {
71 #ifndef MEM_USERLAND
72 int ok = 1;
73 #endif
74 uint64_t paddr;
75 int cache, no_exceptions, offset;
76 unsigned char *memblock;
77 #ifdef BINTRANS
78 int bintrans_cached = cpu->machine->bintrans_enable;
79 #endif
80 no_exceptions = cache_flags & NO_EXCEPTIONS;
81 cache = cache_flags & CACHE_FLAGS_MASK;
82
83 #ifdef MEM_PPC
84 if (cpu->cd.ppc.bits == 32)
85 vaddr &= 0xffffffff;
86 #endif
87
88 #ifdef MEM_URISC
89 {
90 uint64_t mask = (uint64_t) -1;
91 if (cpu->cd.urisc.wordlen < 64)
92 mask = ((int64_t)1 << cpu->cd.urisc.wordlen) - 1;
93 vaddr &= mask;
94 }
95 #endif
96
97 #ifdef MEM_MIPS
98 #ifdef BINTRANS
99 if (bintrans_cached) {
100 if (cache == CACHE_INSTRUCTION) {
101 cpu->cd.mips.pc_bintrans_host_4kpage = NULL;
102 cpu->cd.mips.pc_bintrans_paddr_valid = 0;
103 }
104 }
105 #endif
106 #endif /* MEM_MIPS */
107
108 #ifdef MEM_USERLAND
109 paddr = vaddr & 0x7fffffff;
110 goto have_paddr;
111 #endif
112
113 #ifndef MEM_USERLAND
114 #ifdef MEM_MIPS
115 /*
116 * For instruction fetch, are we on the same page as the last
117 * instruction we fetched?
118 *
119 * NOTE: There's no need to check this stuff here if this address
120 * is known to be in host ram, as it's done at instruction fetch
121 * time in cpu.c! Only check if _host_4k_page == NULL.
122 */
123 if (cache == CACHE_INSTRUCTION &&
124 cpu->cd.mips.pc_last_host_4k_page == NULL &&
125 (vaddr & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) {
126 paddr = cpu->cd.mips.pc_last_physical_page | (vaddr & 0xfff);
127 goto have_paddr;
128 }
129 #endif /* MEM_MIPS */
130
131 if (cache_flags & PHYSICAL || cpu->translate_address == NULL) {
132 paddr = vaddr;
133 } else {
134 ok = cpu->translate_address(cpu, vaddr, &paddr,
135 (writeflag? FLAG_WRITEFLAG : 0) +
136 (no_exceptions? FLAG_NOEXCEPTIONS : 0)
137 + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));
138 /* If the translation caused an exception, or was invalid in
139 some way, we simply return without doing the memory
140 access: */
141 if (!ok)
142 return MEMORY_ACCESS_FAILED;
143 }
144
145
146 #ifdef MEM_MIPS
147 /*
148 * If correct cache emulation is enabled, and we need to simluate
149 * cache misses even from the instruction cache, we can't run directly
150 * from a host page. :-/
151 */
152 #if defined(ENABLE_CACHE_EMULATION) && defined(ENABLE_INSTRUCTION_DELAYS)
153 #else
154 if (cache == CACHE_INSTRUCTION) {
155 cpu->cd.mips.pc_last_virtual_page = vaddr & ~0xfff;
156 cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;
157 cpu->cd.mips.pc_last_host_4k_page = NULL;
158
159 /* _last_host_4k_page will be set to 1 further down,
160 if the page is actually in host ram */
161 }
162 #endif
163 #endif /* MEM_MIPS */
164 #endif /* ifndef MEM_USERLAND */
165
166
167 have_paddr:
168
169
170 #ifdef MEM_MIPS
171 /* TODO: How about bintrans vs cache emulation? */
172 #ifdef BINTRANS
173 if (bintrans_cached) {
174 if (cache == CACHE_INSTRUCTION) {
175 cpu->cd.mips.pc_bintrans_paddr_valid = 1;
176 cpu->cd.mips.pc_bintrans_paddr = paddr;
177 }
178 }
179 #endif
180 #endif /* MEM_MIPS */
181
182
183 if (!(cache_flags & PHYSICAL))
184 if (no_exceptions)
185 goto no_exception_access;
186
187
188 #ifndef MEM_USERLAND
189 /*
190 * Memory mapped device?
191 *
192 * TODO: this is utterly slow.
193 * TODO2: if paddr<base, but len enough, then we should write
194 * to a device to
195 */
196 if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {
197 #ifdef BINTRANS
198 uint64_t orig_paddr = paddr;
199 #endif
200 int i, start, res;
201 i = start = mem->last_accessed_device;
202
203 /* Scan through all devices: */
204 do {
205 if (paddr >= mem->dev_baseaddr[i] &&
206 paddr < mem->dev_baseaddr[i] + mem->dev_length[i]) {
207 /* Found a device, let's access it: */
208 mem->last_accessed_device = i;
209
210 paddr -= mem->dev_baseaddr[i];
211 if (paddr + len > mem->dev_length[i])
212 len = mem->dev_length[i] - paddr;
213
214 #ifdef BINTRANS
215 if (bintrans_cached && mem->dev_flags[i] &
216 MEM_BINTRANS_OK) {
217 int wf = writeflag == MEM_WRITE? 1 : 0;
218
219 if (writeflag) {
220 if (paddr < mem->
221 dev_bintrans_write_low[i])
222 mem->
223 dev_bintrans_write_low
224 [i] =
225 paddr & ~0xfff;
226 if (paddr > mem->
227 dev_bintrans_write_high[i])
228 mem->
229 dev_bintrans_write_high
230 [i] = paddr | 0xfff;
231 }
232
233 if (!(mem->dev_flags[i] &
234 MEM_BINTRANS_WRITE_OK))
235 wf = 0;
236
237 update_translation_table(cpu,
238 vaddr & ~0xfff,
239 mem->dev_bintrans_data[i] +
240 (paddr & ~0xfff),
241 wf, orig_paddr & ~0xfff);
242 }
243 #endif
244
245 res = mem->dev_f[i](cpu, mem, paddr, data, len,
246 writeflag, mem->dev_extra[i]);
247
248 #ifdef ENABLE_INSTRUCTION_DELAYS
249 if (res == 0)
250 res = -1;
251
252 cpu->cd.mips.instruction_delay +=
253 ( (abs(res) - 1) *
254 cpu->cd.mips.cpu_type.instrs_per_cycle );
255 #endif
256 /*
257 * If accessing the memory mapped device
258 * failed, then return with a DBE exception.
259 */
260 if (res <= 0) {
261 debug("%s device '%s' addr %08lx "
262 "failed\n", writeflag?
263 "writing to" : "reading from",
264 mem->dev_name[i], (long)paddr);
265 #ifdef MEM_MIPS
266 mips_cpu_exception(cpu, EXCEPTION_DBE,
267 0, vaddr, 0, 0, 0, 0);
268 #endif
269 return MEMORY_ACCESS_FAILED;
270 }
271
272 goto do_return_ok;
273 }
274
275 i ++;
276 if (i == mem->n_mmapped_devices)
277 i = 0;
278 } while (i != start);
279 }
280
281
282 #ifdef MEM_MIPS
283 /*
284 * Data and instruction cache emulation:
285 */
286
287 switch (cpu->cd.mips.cpu_type.mmu_model) {
288 case MMU3K:
289 /* if not uncached addess (TODO: generalize this) */
290 if (!(cache_flags & PHYSICAL) && cache != CACHE_NONE &&
291 !((vaddr & 0xffffffffULL) >= 0xa0000000ULL &&
292 (vaddr & 0xffffffffULL) <= 0xbfffffffULL)) {
293 if (memory_cache_R3000(cpu, cache, paddr,
294 writeflag, len, data))
295 goto do_return_ok;
296 }
297 break;
298 #if 0
299 /* Remove this, it doesn't work anyway */
300 case MMU10K:
301 /* other cpus: */
302 /*
303 * SUPER-UGLY HACK for SGI-IP32 PROM, R10000:
304 * K0 bits == 0x3 means uncached...
305 *
306 * It seems that during bootup, the SGI-IP32 prom
307 * stores a return pointers a 0x80000f10, then tests
308 * memory by writing bit patterns to 0xa0000xxx, and
309 * then when it's done, reads back the return pointer
310 * from 0x80000f10.
311 *
312 * I need to find the correct way to disconnect the
313 * cache from the main memory for R10000. (TODO !!!)
314 */
315 /* if ((cpu->cd.mips.coproc[0]->reg[COP0_CONFIG] & 7) == 3) { */
316 /*
317 if (cache == CACHE_DATA &&
318 cpu->r10k_cache_disable_TODO) {
319 paddr &= ((512*1024)-1);
320 paddr += 512*1024;
321 }
322 */
323 break;
324 #endif
325 default:
326 /* R4000 etc */
327 /* TODO */
328 ;
329 }
330 #endif /* MEM_MIPS */
331
332
333 /* Outside of physical RAM? */
334 if (paddr >= mem->physical_max) {
335 if ((paddr & 0xffff000000ULL) == 0x1f000000) {
336 /* Ok, this is PROM stuff */
337 } else if ((paddr & 0xfffff00000ULL) == 0x1ff00000) {
338 /* Sprite reads from this area of memory... */
339 /* TODO: is this still correct? */
340 if (writeflag == MEM_READ)
341 memset(data, 0, len);
342 goto do_return_ok;
343 } else {
344 if (paddr >= mem->physical_max + 0 * 1024) {
345 char *symbol;
346 #ifdef MEM_MIPS
347 uint64_t offset;
348 #endif
349 if (!quiet_mode) {
350 fatal("[ memory_rw(): writeflag=%i ",
351 writeflag);
352 if (writeflag) {
353 unsigned int i;
354 debug("data={", writeflag);
355 if (len > 16) {
356 int start2 = len-16;
357 for (i=0; i<16; i++)
358 debug("%s%02x",
359 i?",":"",
360 data[i]);
361 debug(" .. ");
362 if (start2 < 16)
363 start2 = 16;
364 for (i=start2; i<len;
365 i++)
366 debug("%s%02x",
367 i?",":"",
368 data[i]);
369 } else
370 for (i=0; i<len; i++)
371 debug("%s%02x",
372 i?",":"",
373 data[i]);
374 debug("}");
375 }
376 #ifdef MEM_MIPS
377 symbol = get_symbol_name(
378 &cpu->machine->symbol_context,
379 cpu->cd.mips.pc_last, &offset);
380 #else
381 symbol = "(unimpl for non-MIPS)";
382 #endif
383
384 /* TODO: fix! not mips.pc_last for for example ppc */
385
386 fatal(" paddr=%llx >= physical_max pc="
387 "0x%08llx <%s> ]\n",
388 (long long)paddr,
389 (long long)cpu->cd.mips.pc_last,
390 symbol? symbol : "no symbol");
391 }
392
393 if (cpu->machine->single_step_on_bad_addr) {
394 fatal("[ unimplemented access to "
395 "0x%016llx, pc = 0x%016llx ]\n",
396 (long long)paddr,
397 (long long)cpu->pc);
398 single_step = 1;
399 }
400 }
401
402 if (writeflag == MEM_READ) {
403 /* Return all zeroes? (Or 0xff? TODO) */
404 memset(data, 0, len);
405
406 #ifdef MEM_MIPS
407 /*
408 * For real data/instruction accesses, cause
409 * an exceptions on an illegal read:
410 */
411 if (cache != CACHE_NONE && cpu->machine->
412 dbe_on_nonexistant_memaccess) {
413 if (paddr >= mem->physical_max &&
414 paddr < mem->physical_max+1048576)
415 mips_cpu_exception(cpu,
416 EXCEPTION_DBE, 0, vaddr, 0,
417 0, 0, 0);
418 }
419 #endif /* MEM_MIPS */
420 }
421
422 /* Hm? Shouldn't there be a DBE exception for
423 invalid writes as well? TODO */
424
425 goto do_return_ok;
426 }
427 }
428
429 #endif /* ifndef MEM_USERLAND */
430
431
432 no_exception_access:
433
434 /*
435 * Uncached access:
436 */
437 memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
438 if (memblock == NULL) {
439 if (writeflag == MEM_READ)
440 memset(data, 0, len);
441 goto do_return_ok;
442 }
443
444 offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);
445
446 #ifdef BINTRANS
447 if (bintrans_cached)
448 update_translation_table(cpu, vaddr & ~0xfff,
449 memblock + (offset & ~0xfff),
450 #if 0
451 cache == CACHE_INSTRUCTION?
452 (writeflag == MEM_WRITE? 1 : 0)
453 : ok - 1,
454 #else
455 writeflag == MEM_WRITE? 1 : 0,
456 #endif
457 paddr & ~0xfff);
458 #endif
459
460 if (writeflag == MEM_WRITE) {
461 if (len == sizeof(uint32_t) && (offset & 3)==0)
462 *(uint32_t *)(memblock + offset) = *(uint32_t *)data;
463 else if (len == sizeof(uint8_t))
464 *(uint8_t *)(memblock + offset) = *(uint8_t *)data;
465 else
466 memcpy(memblock + offset, data, len);
467 } else {
468 if (len == sizeof(uint32_t) && (offset & 3)==0)
469 *(uint32_t *)data = *(uint32_t *)(memblock + offset);
470 else if (len == sizeof(uint8_t))
471 *(uint8_t *)data = *(uint8_t *)(memblock + offset);
472 else
473 memcpy(data, memblock + offset, len);
474
475 if (cache == CACHE_INSTRUCTION) {
476 cpu->cd.mips.pc_last_host_4k_page = memblock
477 + (offset & ~0xfff);
478 #ifdef BINTRANS
479 if (bintrans_cached) {
480 cpu->cd.mips.pc_bintrans_host_4kpage =
481 cpu->cd.mips.pc_last_host_4k_page;
482 }
483 #endif
484 }
485 }
486
487
488 do_return_ok:
489 return MEMORY_ACCESS_OK;
490 }
491

  ViewVC Help
Powered by ViewVC 1.1.26