|
|
1.1.1.3 root 1: /*
2: * cpummu.cpp - MMU emulation
3: *
4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
5: *
6: * Inspired by UAE MMU patch
7: *
8: * This file is part of the ARAnyM project which builds a new and powerful
9: * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10: *
11: * ARAnyM is free software; you can redistribute it and/or modify
12: * it under the terms of the GNU General Public License as published by
13: * the Free Software Foundation; either version 2 of the License, or
14: * (at your option) any later version.
15: *
16: * ARAnyM is distributed in the hope that it will be useful,
17: * but WITHOUT ANY WARRANTY; without even the implied warranty of
18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: * GNU General Public License for more details.
20: *
21: * You should have received a copy of the GNU General Public License
22: * along with ARAnyM; if not, write to the Free Software
23: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: */
25:
26: #define DEBUG 0
27: #define USETAG 0
28:
29: #include "sysconfig.h"
30: #include "sysdeps.h"
31:
32: #include "options_cpu.h"
33: #include "memory.h"
34: #include "newcpu.h"
35: //#include "debug.h"
36: #include "main.h"
37: #include "cpummu.h"
38:
39: #define DBG_MMU_VERBOSE 1
40: #define DBG_MMU_SANITY 1
41: #define write_log printf
42:
43: #ifdef FULLMMU
44:
45: mmu_atc_l1_array atc_l1[2];
46: mmu_atc_l1_array *current_atc;
47: struct mmu_atc_line atc_l2[2][ATC_L2_SIZE];
48:
49: # ifdef ATC_STATS
50: static unsigned int mmu_atc_hits[ATC_L2_SIZE];
51: # endif
52:
53:
54: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
55: {
56: DUNUSED(label);
57: uae_u32 from_addr, to_addr;
58:
59: from_addr = ttr & MMU_TTR_LOGICAL_BASE;
60: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
61:
62: fprintf(stderr, "%s: [%08x] %08x - %08x enabled=%d supervisor=%d wp=%d cm=%02d\n",
63: label, ttr,
64: from_addr, to_addr,
65: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
66: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
67: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
68: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
69: );
70: }
71:
72: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
73: {
74: uae_u32 * ttr;
75: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0;
76: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1;
77:
78: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
79: ttr = ttr1;
80: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
81: ttr = ttr0;
82: else
83: return;
84:
85: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
86: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
87: *ttr |= MMU_TTR_BIT_ENABLED;
88:
89: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr);
90: }
91:
92: /* check if an address matches a ttr */
93: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
94: {
95: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
96: uae_u8 msb, mask;
97:
98: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
99: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
100:
101: if (!(msb & ~mask)) {
102:
103: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
104: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
105: return TTR_NO_MATCH;
106: }
107: }
108:
109: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
110: }
111: }
112: return TTR_NO_MATCH;
113: }
114:
115: static inline int mmu_match_ttr(uaecptr addr, bool super, bool data)
116: {
117: int res;
118:
119: if (data) {
120: res = mmu_do_match_ttr(regs.dtt0, addr, super);
121: if (res == TTR_NO_MATCH)
122: res = mmu_do_match_ttr(regs.dtt1, addr, super);
123: } else {
124: res = mmu_do_match_ttr(regs.itt0, addr, super);
125: if (res == TTR_NO_MATCH)
126: res = mmu_do_match_ttr(regs.itt1, addr, super);
127: }
128: return res;
129: }
130:
131: #if DEBUG
132: /* {{{ mmu_dump_table */
133: static void mmu_dump_table(const char * label, uaecptr root_ptr)
134: {
135: DUNUSED(label);
136: const int ROOT_TABLE_SIZE = 128,
137: PTR_TABLE_SIZE = 128,
138: PAGE_TABLE_SIZE = 64,
139: ROOT_INDEX_SHIFT = 25,
140: PTR_INDEX_SHIFT = 18;
141: // const int PAGE_INDEX_SHIFT = 12;
142: int root_idx, ptr_idx, page_idx;
143: uae_u32 root_des, ptr_des, page_des;
144: uaecptr ptr_des_addr, page_addr,
145: root_log, ptr_log, page_log;
146:
147: fprintf(stderr, "%s: root=%lx\n", label, root_ptr);
148:
149: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
150: root_des = phys_get_long(root_ptr + root_idx);
151:
152: if ((root_des & 2) == 0)
153: continue; /* invalid */
154:
155: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
156: root_des & 8 ? 1 : 0,
157: root_des & 4 ? 1 : 0,
158: root_des & 3
159: );
160:
161: root_log = root_idx << ROOT_INDEX_SHIFT;
162:
163: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
164:
165: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
166: struct {
167: uaecptr log, phys;
168: int start_idx, n_pages; /* number of pages covered by this entry */
169: uae_u32 match;
170: } page_info[PAGE_TABLE_SIZE];
171: int n_pages_used;
172:
173: ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
174: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
175:
176: if ((ptr_des & 2) == 0)
177: continue; /* invalid */
178:
179: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
180:
181: n_pages_used = -1;
182: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
183:
184: page_des = phys_get_long(page_addr + page_idx);
185: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT
186:
187: switch (page_des & 3) {
188: case 0: /* invalid */
189: continue;
190: case 1: case 3: /* resident */
191: case 2: /* indirect */
192: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
193: /* use the next entry */
194: n_pages_used++;
195:
196: page_info[n_pages_used].match = page_des;
197: page_info[n_pages_used].n_pages = 1;
198: page_info[n_pages_used].start_idx = page_idx;
199: page_info[n_pages_used].log = page_log;
200: } else {
201: page_info[n_pages_used].n_pages++;
202: }
203: break;
204: }
205: }
206:
207: if (n_pages_used == -1)
208: continue;
209:
210: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
211: ptr_des & 8 ? 1 : 0,
212: ptr_des & 4 ? 1 : 0,
213: ptr_des & 3
214: );
215:
216:
217: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
218: page_des = page_info[page_idx].match;
219:
220: if ((page_des & MMU_PDT_MASK) == 2) {
221: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
222: page_info[page_idx].start_idx,
223: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
224: page_info[page_idx].log,
225: page_des & MMU_PAGE_INDIRECT_MASK
226: );
227:
228: } else {
229: fprintf(stderr, " PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n",
230: page_info[page_idx].start_idx,
231: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
232: page_info[page_idx].log,
233: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
234: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
235: page_des & MMU_DES_GLOBAL ? 1 : 0,
236: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
237: page_des & MMU_DES_SUPER ? 1 : 0,
238: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
239: page_des & MMU_DES_MODIFIED ? 1 : 0,
240: page_des & MMU_DES_USED ? 1 : 0,
241: page_des & MMU_DES_WP ? 1 : 0
242: );
243: }
244: }
245: }
246:
247: }
248: }
249: /* }}} */
250: #endif
251:
252: /* {{{ mmu_dump_atc */
253: static void mmu_dump_atc(void)
254: {
255: int i, j;
256: for (i = 0; i < 2; i++) {
257: for (j = 0; j < ATC_L2_SIZE; j++) {
258: if (atc_l2[i][j].tag == 0x8000)
259: continue;
260: fprintf(stderr, "ATC[%02d] G=%d TT=%d M=%d WP=%d VD=%d VI=%d tag=%08x --> phys=%08x\n",
261: j, atc_l2[i][j].global, atc_l2[i][j].tt, atc_l2[i][j].modified,
262: atc_l2[i][j].write_protect, atc_l2[i][j].valid_data, atc_l2[i][j].valid_inst,
263: atc_l2[i][j].tag, atc_l2[i][j].phys);
264: }
265: }
266: }
267: /* }}} */
268:
269: /* {{{ mmu_dump_tables */
270: void mmu_dump_tables(void)
271: {
272: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr);
273: mmu_dump_ttr("DTT0", regs.dtt0);
274: mmu_dump_ttr("DTT1", regs.dtt1);
275: mmu_dump_ttr("ITT0", regs.itt0);
276: mmu_dump_ttr("ITT1", regs.itt1);
277: mmu_dump_atc();
278: #if DEBUG
279: mmu_dump_table("SRP", regs.srp);
280: #endif
281: }
282: /* }}} */
283:
284: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write);
285:
286: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
287: {
288: return (super ? 4 : 0) | (data ? 1 : 2);
289: }
290:
291: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size)
292: {
293: uae_u16 ssw = 0;
294:
295: ssw |= fc & MMU_SSW_TM; /* Copy TM */
296: switch (size) {
297: case sz_byte:
298: ssw |= MMU_SSW_SIZE_B;
299: break;
300: case sz_word:
301: ssw |= MMU_SSW_SIZE_W;
302: break;
303: case sz_long:
304: ssw |= MMU_SSW_SIZE_L;
305: break;
306: }
307:
308: regs.wb3_status = write ? 0x80 | ssw : 0;
309: if (!write)
310: ssw |= MMU_SSW_RW;
311:
312: regs.mmu_fault_addr = addr;
313: regs.mmu_ssw = ssw | MMU_SSW_ATC;
314:
315: fprintf(stderr, "BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc());
316:
317: //write_log(L"BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc());
318: //activate_debugger();
319:
320: THROW(2);
321: }
322:
323: /*
324: * Update the atc line for a given address by doing a mmu lookup.
325: */
326: static uaecptr mmu_fill_atc_l2(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l)
327: {
328: int res;
329: uae_u32 desc;
330:
331: l->tag = ATC_TAG(addr);
332: l->hw = l->bus_fault = 0;
333:
334: /* check ttr0 */
335: res = mmu_match_ttr(addr, super, data);
336: if (res != TTR_NO_MATCH) {
337: l->tt = 1;
338: if (data) {
339: l->valid_data = 1;
340: l->valid_inst = mmu_match_ttr(addr, super, 0) == res;
341: } else {
342: l->valid_inst = 1;
343: l->valid_data = mmu_match_ttr(addr, super, 1) == res;
344: }
345: l->global = 1;
346: l->modified = 1;
347: l->write_protect = (res == TTR_NO_WRITE);
348: l->phys = 0;
349:
350: return 0;
351: }
352:
353: l->tt = 0;
354: if (!regs.mmu_enabled) {
355: l->valid_data = l->valid_inst = 1;
356: l->global = 1;
357: l->modified = 1;
358: l->write_protect = 0;
359: l->phys = 0;
360: return 0;
361: }
362:
363: SAVE_EXCEPTION;
364: TRY(prb) {
365: desc = mmu_lookup_pagetable(addr, super, write);
366: #if DEBUG > 2
367: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc);
368: #endif
369: RESTORE_EXCEPTION;
370: }
371: CATCH(prb) {
372: RESTORE_EXCEPTION;
373: /* bus error during table search */
374: desc = 0;
375: //goto fail;
376: } ENDTRY
377:
378: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) {
379: fail:
380: l->valid_data = l->valid_inst = 0;
381: l->global = 0;
382: } else {
383: l->valid_data = l->valid_inst = 1;
384: if (regs.mmu_pagesize_8k)
385: l->phys = (desc & ~0x1fff) - (addr & ~0x1fff);
386: else
387: l->phys = (desc & ~0xfff) - (addr & ~0xfff);
388: l->global = (desc & MMU_MMUSR_G) != 0;
389: l->modified = (desc & MMU_MMUSR_M) != 0;
390: l->write_protect = (desc & MMU_MMUSR_W) != 0;
391: }
392:
393: return desc;
394: }
395:
396: static ALWAYS_INLINE bool mmu_fill_atc_l1(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1)
397: {
398: int idx = ATC_L2_INDEX(addr);
399: int tag = ATC_TAG(addr);
400: struct mmu_atc_line *l = &atc_l2[super ? 1 : 0][idx];
401:
402: if (l->tag != tag) {
403: restart:
404: mmu_fill_atc_l2(addr, super, data, write, l);
405: }
406: if (!(data ? l->valid_data : l->valid_inst)) {
407: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc);
408: goto fail;
409: }
410: if (write) {
411: if (l->write_protect) {
412: fprintf(stderr, "MMU: write protected (via %s) %x\n", l->tt ? "ttr" : "atc", addr);
413: goto fail;
414: }
415: if (!l->modified)
416: goto restart;
417: }
418: *l1 = *l;
419: #if 0
420: uaecptr phys_addr = addr + l1->phys;
421: if ((phys_addr & 0xfff00000) == 0x00f00000) {
422: l1->hw = 1;
423: goto fail;
424: }
425: if ((phys_addr & 0xfff00000) == 0xfff00000) {
426: l1->hw = 1;
427: l1->phys -= 0xff000000;
428: goto fail;
429: }
430:
431: if (!test_ram_boundary(phys_addr, 1, super, write)) {
432: l1->bus_fault = 1;
433: goto fail;
434: }
435: #endif
436: return true;
437:
438: fail:
439: l1->tag = ~l1->tag;
440: return false;
441: }
442:
443: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
444: {
445: struct mmu_atc_line *l;
446:
447: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
448: mmu_fill_atc_l2(addr, super, data, write, l);
449: if (!(data ? l->valid_data : l->valid_inst))
450: THROW(2);
451:
452: return addr + l->phys;
453: }
454:
455: /*
456: * Lookup the address by walking the page table and updating
457: * the page descriptors accordingly. Returns the found descriptor
458: * or produces a bus error.
459: */
460: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write)
461: {
462: uae_u32 desc, desc_addr, wp;
463: int i;
464:
465: wp = 0;
466: desc = super ? regs.srp : regs.urp;
467:
468: /* fetch root table descriptor */
469: i = (addr >> 23) & 0x1fc;
470: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
471: desc = phys_get_long(desc_addr);
472: if ((desc & 2) == 0) {
473: fprintf(stderr, "MMU: invalid root descriptor for %x desc at %x desc=%x %s at %d\n", addr,desc_addr,desc,__FILE__,__LINE__);
474: return 0;
475: }
476:
477: wp |= desc;
478: if ((desc & MMU_DES_USED) == 0)
479: phys_put_long(desc_addr, desc | MMU_DES_USED);
480:
481: /* fetch pointer table descriptor */
482: i = (addr >> 16) & 0x1fc;
483: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
484: desc = phys_get_long(desc_addr);
485: if ((desc & 2) == 0) {
486: fprintf(stderr, "MMU: invalid ptr descriptor for %x desc at %x desc=%x %s at %d\n", addr,desc_addr,desc,__FILE__,__LINE__);
487: return 0;
488: }
489: wp |= desc;
490: if ((desc & MMU_DES_USED) == 0)
491: phys_put_long(desc_addr, desc | MMU_DES_USED);
492:
493: /* fetch page table descriptor */
494: if (regs.mmu_pagesize_8k) {
495: i = (addr >> 11) & 0x7c;
496: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) | i;
497: } else {
498: i = (addr >> 10) & 0xfc;
499: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) | i;
500: }
501:
502: desc = phys_get_long(desc_addr);
503: if ((desc & 3) == 2) {
504: /* indirect */
505: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
506: desc = phys_get_long(desc_addr);
507: }
508: if ((desc & 1) == 0) {
509: fprintf(stderr, "MMU: invalid page descriptor log=%08x desc=%08x @%08x %s at %d\n", addr, desc, desc_addr,__FILE__,__LINE__);
510: return desc;
511: }
512:
513: desc |= wp & MMU_DES_WP;
514: if (write) {
515: if (desc & MMU_DES_WP) {
516: if ((desc & MMU_DES_USED) == 0) {
517: desc |= MMU_DES_USED;
518: phys_put_long(desc_addr, desc);
519: }
520: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
521: (MMU_DES_USED|MMU_DES_MODIFIED)) {
522: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
523: phys_put_long(desc_addr, desc);
524: }
525: } else {
526: if ((desc & MMU_DES_USED) == 0) {
527: desc |= MMU_DES_USED;
528: phys_put_long(desc_addr, desc);
529: }
530: }
531: return desc;
532: }
533:
534: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
535: {
536: uae_u16 res;
537:
538: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
539: SAVE_EXCEPTION;
540: TRY(prb) {
541: res |= mmu_get_byte(addr + 1, data, sz_word);
542: RESTORE_EXCEPTION;
543: }
544: CATCH(prb) {
545: RESTORE_EXCEPTION;
546: regs.mmu_fault_addr = addr;
547: regs.mmu_ssw |= MMU_SSW_MA;
548: THROW_AGAIN(prb);
549: } ENDTRY
550: return res;
551: }
552:
553: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
554: {
555: uae_u32 res;
556:
557: if (likely(!(addr & 1))) {
558: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
559: SAVE_EXCEPTION;
560: TRY(prb) {
561: res |= mmu_get_word(addr + 2, data, sz_long);
562: RESTORE_EXCEPTION;
563: }
564: CATCH(prb) {
565: RESTORE_EXCEPTION;
566: regs.mmu_fault_addr = addr;
567: regs.mmu_ssw |= MMU_SSW_MA;
568: THROW_AGAIN(prb);
569: } ENDTRY
570: } else {
571: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
572: SAVE_EXCEPTION;
573: TRY(prb) {
574: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
575: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
576: res |= mmu_get_byte(addr + 3, data, sz_long);
577: RESTORE_EXCEPTION;
578: }
579: CATCH(prb) {
580: RESTORE_EXCEPTION;
581: regs.mmu_fault_addr = addr;
582: regs.mmu_ssw |= MMU_SSW_MA;
583: THROW_AGAIN(prb);
584: } ENDTRY
585: }
586: return res;
587: }
588:
589: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
590: int size, struct mmu_atc_line *cl)
591: {
592: uae_u32 tag = ATC_TAG(addr);
593:
594: if (USETAG && cl->tag == (uae_u16)~tag) {
595: redo:
596: if (cl->hw)
597: return HWget_b(cl->phys + addr);
598: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
599: return 0;
600: }
601:
602: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
603: goto redo;
604:
605: return phys_get_byte(mmu_get_real_address(addr, cl));
606: }
607:
608: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
609: int size, struct mmu_atc_line *cl)
610: {
611: uae_u32 tag = ATC_TAG(addr);
612:
613: if (USETAG && cl->tag == (uae_u16)~tag) {
614: redo:
615: if (cl->hw)
616: return HWget_w(cl->phys + addr);
617: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
618: return 0;
619: }
620:
621: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
622: goto redo;
623:
624: return phys_get_word(mmu_get_real_address(addr, cl));
625: }
626:
627: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
628: int size, struct mmu_atc_line *cl)
629: {
630: uae_u32 tag = ATC_TAG(addr);
631:
632: if (USETAG && cl->tag == (uae_u16)~tag) {
633: redo:
634: if (cl->hw)
635: return HWget_l(cl->phys + addr);
636: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
637: return 0;
638: }
639:
640: if (!mmu_fill_atc_l1(addr, super, data, 0, cl))
641: goto redo;
642:
643: return phys_get_long(mmu_get_real_address(addr, cl));
644: }
645:
646: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
647: {
648: SAVE_EXCEPTION;
649: TRY(prb) {
650: if (likely(!(addr & 1))) {
651: mmu_put_word(addr, val >> 16, data, sz_long);
652: mmu_put_word(addr + 2, val, data, sz_long);
653: } else {
654: mmu_put_byte(addr, val >> 24, data, sz_long);
655: mmu_put_byte(addr + 1, val >> 16, data, sz_long);
656: mmu_put_byte(addr + 2, val >> 8, data, sz_long);
657: mmu_put_byte(addr + 3, val, data, sz_long);
658: }
659: RESTORE_EXCEPTION;
660: }
661: CATCH(prb) {
662: RESTORE_EXCEPTION;
663: regs.wb3_data = val;
664: if (regs.mmu_fault_addr != addr) {
665: regs.mmu_fault_addr = addr;
666: regs.mmu_ssw |= MMU_SSW_MA;
667: }
668: THROW_AGAIN(prb);
669: } ENDTRY
670: }
671:
672: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
673: {
674: SAVE_EXCEPTION;
675: TRY(prb) {
676: mmu_put_byte(addr, val >> 8, data, sz_word);
677: mmu_put_byte(addr + 1, val, data, sz_word);
678: RESTORE_EXCEPTION;
679: }
680: CATCH(prb) {
681: RESTORE_EXCEPTION;
682: regs.wb3_data = val;
683: if (regs.mmu_fault_addr != addr) {
684: regs.mmu_fault_addr = addr;
685: regs.mmu_ssw |= MMU_SSW_MA;
686: }
687: THROW_AGAIN(prb);
688: } ENDTRY
689: }
690:
691: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
692: int size, struct mmu_atc_line *cl)
693: {
694: uae_u32 tag = ATC_TAG(addr);
695:
696: if (USETAG && cl->tag == (uae_u16)~tag) {
697: redo:
698: if (cl->hw) {
699: HWput_b(cl->phys + addr, val);
700: return;
701: }
702: regs.wb3_data = val;
703: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
704: return;
705: }
706:
707: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
708: goto redo;
709:
710: phys_put_byte(mmu_get_real_address(addr, cl), val);
711: }
712:
713: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
714: int size, struct mmu_atc_line *cl)
715: {
716: uae_u32 tag = ATC_TAG(addr);
717:
718: if (USETAG && cl->tag == (uae_u16)~tag) {
719: redo:
720: if (cl->hw) {
721: HWput_w(cl->phys + addr, val);
722: return;
723: }
724: regs.wb3_data = val;
725: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
726: return;
727: }
728:
729: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
730: goto redo;
731:
732: phys_put_word(mmu_get_real_address(addr, cl), val);
733: }
734:
735: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
736: int size, struct mmu_atc_line *cl)
737: {
738: uae_u32 tag = ATC_TAG(addr);
739:
740: if (USETAG && cl->tag == (uae_u16)~tag) {
741: redo:
742: if (cl->hw) {
743: HWput_l(cl->phys + addr, val);
744: return;
745: }
746: regs.wb3_data = val;
747: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
748: return;
749: }
750:
751: if (!mmu_fill_atc_l1(addr, super, data, 1, cl))
752: goto redo;
753:
754: phys_put_long(mmu_get_real_address(addr, cl), val);
755: }
756:
757: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
758: {
759: bool super = (regs.sfc & 4) != 0;
760: bool data = (regs.sfc & 3) != 2;
761: uae_u32 res;
762:
763: if (likely(!is_unaligned(addr, 4)))
764: return mmu_get_user_long(addr, super, data, sz_long);
765:
766: if (likely(!(addr & 1))) {
767: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16;
768: SAVE_EXCEPTION;
769: TRY(prb) {
770: res |= mmu_get_user_word(addr + 2, super, data, sz_long);
771: RESTORE_EXCEPTION;
772: }
773: CATCH(prb) {
774: RESTORE_EXCEPTION;
775: regs.mmu_fault_addr = addr;
776: regs.mmu_ssw |= MMU_SSW_MA;
777: THROW_AGAIN(prb);
778: } ENDTRY
779: } else {
780: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8;
781: SAVE_EXCEPTION;
782: TRY(prb) {
783: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8;
784: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8;
785: res |= mmu_get_user_byte(addr + 3, super, data, sz_long);
786: RESTORE_EXCEPTION;
787: }
788: CATCH(prb) {
789: RESTORE_EXCEPTION;
790: regs.mmu_fault_addr = addr;
791: regs.mmu_ssw |= MMU_SSW_MA;
792: THROW_AGAIN(prb);
793: } ENDTRY
794: }
795: return res;
796: }
797:
798: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
799: {
800: bool super = (regs.sfc & 4) != 0;
801: bool data = (regs.sfc & 3) != 2;
802: uae_u16 res;
803:
804: if (likely(!is_unaligned(addr, 2)))
805: return mmu_get_user_word(addr, super, data, sz_word);
806:
807: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8;
808: SAVE_EXCEPTION;
809: TRY(prb) {
810: res |= mmu_get_user_byte(addr + 1, super, data, sz_word);
811: RESTORE_EXCEPTION;
812: }
813: CATCH(prb) {
814: RESTORE_EXCEPTION;
815: regs.mmu_fault_addr = addr;
816: regs.mmu_ssw |= MMU_SSW_MA;
817: THROW_AGAIN(prb);
818: } ENDTRY
819: return res;
820: }
821:
822: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
823: {
824: bool super = (regs.sfc & 4) != 0;
825: bool data = (regs.sfc & 3) != 2;
826:
827: return mmu_get_user_byte(addr, super, data, sz_byte);
828: }
829:
830: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
831: {
832: bool super = (regs.dfc & 4) != 0;
833: bool data = (regs.dfc & 3) != 2;
834:
835: SAVE_EXCEPTION;
836: TRY(prb) {
837: if (likely(!is_unaligned(addr, 4)))
838: mmu_put_user_long(addr, val, super, data, sz_long);
839: else if (likely(!(addr & 1))) {
840: mmu_put_user_word(addr, val >> 16, super, data, sz_long);
841: mmu_put_user_word(addr + 2, val, super, data, sz_long);
842: } else {
843: mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
844: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
845: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
846: mmu_put_user_byte(addr + 3, val, super, data, sz_long);
847: }
848: RESTORE_EXCEPTION;
849: }
850: CATCH(prb) {
851: RESTORE_EXCEPTION;
852: regs.wb3_data = val;
853: if (regs.mmu_fault_addr != addr) {
854: regs.mmu_fault_addr = addr;
855: regs.mmu_ssw |= MMU_SSW_MA;
856: }
857: THROW_AGAIN(prb);
858: } ENDTRY
859: }
860:
861: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
862: {
863: bool super = (regs.dfc & 4) != 0;
864: bool data = (regs.dfc & 3) != 2;
865:
866: SAVE_EXCEPTION;
867: TRY(prb) {
868: if (likely(!is_unaligned(addr, 2)))
869: mmu_put_user_word(addr, val, super, data, sz_word);
870: else {
871: mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
872: mmu_put_user_byte(addr + 1, val, super, data, sz_word);
873: }
874: RESTORE_EXCEPTION;
875: }
876: CATCH(prb) {
877: RESTORE_EXCEPTION;
878: regs.wb3_data = val;
879: if (regs.mmu_fault_addr != addr) {
880: regs.mmu_fault_addr = addr;
881: regs.mmu_ssw |= MMU_SSW_MA;
882: }
883: THROW_AGAIN(prb);
884: } ENDTRY
885: }
886:
887: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
888: {
889: bool super = (regs.dfc & 4) != 0;
890: bool data = (regs.dfc & 3) != 2;
891:
892: SAVE_EXCEPTION;
893: TRY(prb) {
894: mmu_put_user_byte(addr, val, super, data, sz_byte);
895: RESTORE_EXCEPTION;
896: }
897: CATCH(prb) {
898: RESTORE_EXCEPTION;
899: regs.wb3_data = val;
900: THROW_AGAIN(prb);
901: } ENDTRY
902: }
903:
904: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
905: {
906: bool super = (regs.dfc & 4) != 0;
907: DUNUSED(extra);
908: if ((opcode & 0xFE0) == 0x0500) {
909: bool glob;
910: int regno;
911: //D(didflush = 0);
912: uae_u32 addr;
913: /* PFLUSH */
914: regno = opcode & 7;
915: glob = (opcode & 8) != 0;
916:
917: if (opcode & 16) {
918: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc);
919: mmu_flush_atc_all(glob);
920: } else {
921: addr = m68k_areg(regs, regno);
922: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr);
923: mmu_flush_atc(addr, super, glob);
924: }
925: flush_internals();
926: #ifdef USE_JIT
927: flush_icache(0);
928: #endif
929: } else if ((opcode & 0x0FD8) == 0x548) {
930: bool write;
931: int regno;
932: uae_u32 addr;
933:
934: regno = opcode & 7;
935: write = (opcode & 32) == 0;
936: addr = m68k_areg(regs, regno);
937: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc);
938: mmu_flush_atc(addr, super, true);
939: SAVE_EXCEPTION;
940: TRY(prb) {
941: struct mmu_atc_line *l;
942: uae_u32 desc;
943: bool data = (regs.dfc & 3) != 2;
944:
945: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)];
946: desc = mmu_fill_atc_l2(addr, super, data, write, l);
947: if (!(data ? l->valid_data : l->valid_inst))
948: regs.mmusr = MMU_MMUSR_B;
949: else if (l->tt)
950: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
951: else {
952: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
953: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
954: regs.mmusr |= MMU_MMUSR_R;
955: }
956: }
957: CATCH(prb) {
958: regs.mmusr = MMU_MMUSR_B;
959: } ENDTRY
960: RESTORE_EXCEPTION;
961: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr);
962: } else
963: op_illg (opcode);
964: }
965:
966: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
967: {
968: struct mmu_atc_line *l;
969: int i, j;
970:
971: l = atc_l1[super ? 1 : 0][0][0];
972: i = ATC_L1_INDEX(addr);
973: for (j = 0; j < 4; j++) {
974: if (global || !l[i].global)
975: l[i].tag = 0x8000;
976: l += ATC_L1_SIZE;
977: }
978: if (regs.mmu_pagesize_8k) {
979: i = ATC_L1_INDEX(addr) ^ 1;
980: for (j = 0; j < 4; j++) {
981: if (global || !l[i].global)
982: l[i].tag = 0x8000;
983: l += ATC_L1_SIZE;
984: }
985: }
986: l = atc_l2[super ? 1 : 0];
987: i = ATC_L2_INDEX(addr);
988: if (global || !l[i].global)
989: l[i].tag = 0x8000;
990: if (regs.mmu_pagesize_8k) {
991: i ^= 1;
992: if (global || !l[i].global)
993: l[i].tag = 0x8000;
994: }
995: }
996:
997: void REGPARAM2 mmu_flush_atc_all(bool global)
998: {
999: struct mmu_atc_line *l;
1000: unsigned int i;
1001:
1002: l = atc_l1[0][0][0];
1003: for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) {
1004: if (global || !l->global)
1005: l->tag = 0x8000;
1006: }
1007:
1008: l = atc_l2[0];
1009: for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) {
1010: if (global || !l->global)
1011: l->tag = 0x8000;
1012: }
1013: }
1014:
1015: void REGPARAM2 mmu_reset(void)
1016: {
1017: mmu_flush_atc_all(true);
1018: #if 0
1019: regs.urp = regs.srp = 0;
1020: regs.itt0 = regs.itt0 = 0;
1021: regs.dtt0 = regs.dtt0 = 0;
1022: regs.mmusr = 0;
1023: #endif
1024: }
1025:
1026:
1027: void REGPARAM2 mmu_set_tc(uae_u16 tc)
1028: {
1029: #if 0
1030: if (regs.tcr == tc)
1031: return;
1032: regs.tcr = tc;
1033: #endif
1034: regs.mmu_enabled = tc & 0x8000 ? 1 : 0;
1035: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0;
1036: mmu_flush_atc_all(true);
1037:
1038: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k);
1039: }
1040:
1041: void REGPARAM2 mmu_set_super(bool super)
1042: {
1043: current_atc = &atc_l1[super ? 1 : 0];
1044: }
1045:
1046: jmp_buf __exbuf;
1047: int __exvalue;
1048: #define MAX_TRY_STACK 256
1049: static int s_try_stack_size=0;
1050: static jmp_buf s_try_stack[MAX_TRY_STACK];
1051: jmp_buf* __poptry(void) {
1052: if (s_try_stack_size>0) {
1053: s_try_stack_size--;
1.1.1.4 ! root 1054: if (s_try_stack_size == 0)
! 1055: return NULL;
! 1056: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
1.1.1.3 root 1057: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
1.1.1.4 ! root 1058: return &s_try_stack[s_try_stack_size-1];
1.1.1.3 root 1059: }
1060: else {
1061: fprintf(stderr,"try stack underflow...\n");
1062: exit(-1);
1063: }
1064: }
1065: void __pushtry(jmp_buf* j) {
1066: if (s_try_stack_size<MAX_TRY_STACK) {
1067: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
1068: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
1069: s_try_stack_size++;
1070: } else {
1071: fprintf(stderr,"try stack overflow...\n");
1072: exit(-1);
1073: }
1074: }
1075: int __is_catched(void) {return (s_try_stack_size>0); }
1076: #else
1077:
1078: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
1079: {
1080: if ((opcode & 0xFE0) == 0x0500) {
1081: /* PFLUSH instruction */
1082: flush_internals();
1083: } else if ((opcode & 0x0FD8) == 0x548) {
1084: /* PTEST instruction */
1085: } else
1086: op_illg(opcode);
1087: }
1088:
1089: #endif
1090:
1091: /*
1092: vim:ts=4:sw=4:
1093: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.