|
|
1.1.1.2 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 1
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:
46: bool mmu_is_super;
47: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
48:
49: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
50: {
51: DUNUSED(label);
52: uae_u32 from_addr, to_addr;
53:
54: from_addr = ttr & MMU_TTR_LOGICAL_BASE;
55: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
56:
57:
58: fprintf(stderr, "%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n",
59: label, ttr,
60: from_addr, to_addr,
61: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
62: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
63: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
64: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
65: );
66: }
67:
68: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
69: {
70: uae_u32 * ttr;
71: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0;
72: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1;
73:
74: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
75: ttr = ttr1;
76: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
77: ttr = ttr0;
78: else
79: return;
80:
81: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
82: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
83: *ttr |= MMU_TTR_BIT_ENABLED;
84:
85: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr);
86: }
87:
88:
89:
90: #if 0
91: /* {{{ mmu_dump_table */
92: static void mmu_dump_table(const char * label, uaecptr root_ptr)
93: {
94: DUNUSED(label);
95: const int ROOT_TABLE_SIZE = 128,
96: PTR_TABLE_SIZE = 128,
97: PAGE_TABLE_SIZE = 64,
98: ROOT_INDEX_SHIFT = 25,
99: PTR_INDEX_SHIFT = 18;
100: // const int PAGE_INDEX_SHIFT = 12;
101: int root_idx, ptr_idx, page_idx;
102: uae_u32 root_des, ptr_des, page_des;
103: uaecptr ptr_des_addr, page_addr,
104: root_log, ptr_log, page_log;
105:
106: fprintf(stderr, "%s: root=%lx\n", label, root_ptr);
107:
108: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
109: root_des = phys_get_long(root_ptr + root_idx);
110:
111: if ((root_des & 2) == 0)
112: continue; /* invalid */
113:
114: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
115: root_des & 8 ? 1 : 0,
116: root_des & 4 ? 1 : 0,
117: root_des & 3
118: );
119:
120: root_log = root_idx << ROOT_INDEX_SHIFT;
121:
122: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
123:
124: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
125: struct {
126: uaecptr log, phys;
127: int start_idx, n_pages; /* number of pages covered by this entry */
128: uae_u32 match;
129: } page_info[PAGE_TABLE_SIZE];
130: int n_pages_used;
131:
132: ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
133: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
134:
135: if ((ptr_des & 2) == 0)
136: continue; /* invalid */
137:
138: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
139:
140: n_pages_used = -1;
141: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
142:
143: page_des = phys_get_long(page_addr + page_idx);
144: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT
145:
146: switch (page_des & 3) {
147: case 0: /* invalid */
148: continue;
149: case 1: case 3: /* resident */
150: case 2: /* indirect */
151: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
152: /* use the next entry */
153: n_pages_used++;
154:
155: page_info[n_pages_used].match = page_des;
156: page_info[n_pages_used].n_pages = 1;
157: page_info[n_pages_used].start_idx = page_idx;
158: page_info[n_pages_used].log = page_log;
159: } else {
160: page_info[n_pages_used].n_pages++;
161: }
162: break;
163: }
164: }
165:
166: if (n_pages_used == -1)
167: continue;
168:
169: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
170: ptr_des & 8 ? 1 : 0,
171: ptr_des & 4 ? 1 : 0,
172: ptr_des & 3
173: );
174:
175:
176: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
177: page_des = page_info[page_idx].match;
178:
179: if ((page_des & MMU_PDT_MASK) == 2) {
180: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
181: page_info[page_idx].start_idx,
182: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
183: page_info[page_idx].log,
184: page_des & MMU_PAGE_INDIRECT_MASK
185: );
186:
187: } else {
188: 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",
189: page_info[page_idx].start_idx,
190: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
191: page_info[page_idx].log,
192: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
193: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
194: page_des & MMU_DES_GLOBAL ? 1 : 0,
195: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
196: page_des & MMU_DES_SUPER ? 1 : 0,
197: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
198: page_des & MMU_DES_MODIFIED ? 1 : 0,
199: page_des & MMU_DES_USED ? 1 : 0,
200: page_des & MMU_DES_WP ? 1 : 0
201: );
202: }
203: }
204: }
205:
206: }
207: }
208: /* }}} */
209: #endif
210:
211: /* {{{ mmu_dump_atc */
212: void mmu_dump_atc(void)
213: {
214:
215: }
216: /* }}} */
217:
218: /* {{{ mmu_dump_tables */
219: void mmu_dump_tables(void)
220: {
221: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr);
222: mmu_dump_ttr(L"DTT0", regs.dtt0);
223: mmu_dump_ttr(L"DTT1", regs.dtt1);
224: mmu_dump_ttr(L"ITT0", regs.itt0);
225: mmu_dump_ttr(L"ITT1", regs.itt1);
226: mmu_dump_atc();
227: #if DEBUG
228: // mmu_dump_table("SRP", regs.srp);
229: #endif
230: }
231: /* }}} */
232:
233: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write);
234:
235: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
236: {
237: return (super ? 4 : 0) | (data ? 1 : 2);
238: }
239:
240: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size)
241: {
242: uae_u16 ssw = 0;
243:
244: ssw |= fc & MMU_SSW_TM; /* Copy TM */
245: switch (size) {
246: case sz_byte:
247: ssw |= MMU_SSW_SIZE_B;
248: break;
249: case sz_word:
250: ssw |= MMU_SSW_SIZE_W;
251: break;
252: case sz_long:
253: ssw |= MMU_SSW_SIZE_L;
254: break;
255: }
256:
257: regs.wb3_status = write ? 0x80 | ssw : 0;
258: if (!write)
259: ssw |= MMU_SSW_RW;
260:
261: regs.mmu_fault_addr = addr;
262: regs.mmu_ssw = ssw | MMU_SSW_ATC;
263:
264: fprintf(stderr, "BUS ERROR: fc=%d w=%d logical=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc());
265:
266: THROW(2);
267: }
268:
269: /*
270: * Update the atc line for a given address by doing a mmu lookup.
271: */
272: static uaecptr mmu_fill_atc(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l)
273: {
274: int res;
275: uae_u32 desc;
276:
277: SAVE_EXCEPTION;
278: TRY(prb) {
279: desc = mmu_lookup_pagetable(addr, super, write);
280: #if DEBUG > 2
281: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc);
282: #endif
283: RESTORE_EXCEPTION;
284: }
285: CATCH(prb) {
286: RESTORE_EXCEPTION;
287: /* bus error during table search */
288: desc = 0;
289: // goto fail;
290: } ENDTRY
291:
292: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) {
293: fail:
294: l->valid = 0;
295: l->global = 0;
296: } else {
297: l->valid = 1;
298: if (regs.mmu_pagesize_8k)
299: l->phys = (desc & ~0x1fff);
300: else
301: l->phys = (desc & ~0xfff);
302: l->global = (desc & MMU_MMUSR_G) != 0;
303: l->modified = (desc & MMU_MMUSR_M) != 0;
304: l->write_protect = (desc & MMU_MMUSR_W) != 0;
305: }
306:
307: return desc;
308: }
309:
310: static ALWAYS_INLINE bool mmu_fill_atc_try(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1)
311: {
312: mmu_fill_atc(addr,super,data,write,l1);
313: if (!(l1->valid)) {
314: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc);
315: goto fail;
316: }
317: if (write) {
318: if (l1->write_protect) {
319: fprintf(stderr, "MMU: write protected %lx by atc \n", addr);
320: mmu_dump_atc();
321: goto fail;
322: }
323:
324: }
325: return true;
326:
327: fail:
328: return false;
329: }
330:
331: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
332: {
333: struct mmu_atc_line *l;
334:
335: // this should return a miss but choose a valid line
336: mmu_user_lookup(addr, super, data, write, &l);
337:
338: mmu_fill_atc(addr, super, data, write, l);
339: if (!l->valid) {
340: fprintf(stderr, "[MMU] mmu_translate error");
341: THROW(2);
342: }
343:
344: return l->phys | (addr & (regs.mmu_pagesize_8k?0x00001fff:0x00000fff));
345:
346: }
347:
348: /*
349: * Lookup the address by walking the page table and updating
350: * the page descriptors accordingly. Returns the found descriptor
351: * or produces a bus error.
352: */
353: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write)
354: {
355: uae_u32 desc, desc_addr, wp;
356: int i;
357:
358: wp = 0;
359: desc = super ? regs.srp : regs.urp;
360:
361: /* fetch root table descriptor */
362: i = (addr >> 23) & 0x1fc;
363: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
364: desc = phys_get_long(desc_addr);
365: if ((desc & 2) == 0) {
366: fprintf(stderr, "MMU: invalid root descriptor %s for %lx desc at %lx desc=%lx %s at %d\n", super ? "srp":"urp",
367: addr,desc_addr,desc,__FILE__,__LINE__);
368: return 0;
369: }
370:
371: wp |= desc;
372: if ((desc & MMU_DES_USED) == 0)
373: phys_put_long(desc_addr, desc | MMU_DES_USED);
374:
375: /* fetch pointer table descriptor */
376: i = (addr >> 16) & 0x1fc;
377: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
378: desc = phys_get_long(desc_addr);
379: if ((desc & 2) == 0) {
380: fprintf(stderr, "MMU: invalid ptr descriptor %s for %lx desc at %lx desc=%lx %s at %d\n", super ? "srp":"urp",
381: addr,desc_addr,desc,__FILE__,__LINE__);
382: return 0;
383: }
384: wp |= desc;
385: if ((desc & MMU_DES_USED) == 0)
386: phys_put_long(desc_addr, desc | MMU_DES_USED);
387:
388: /* fetch page table descriptor */
389: if (regs.mmu_pagesize_8k) {
390: i = (addr >> 11) & 0x7c;
391: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
392: } else {
393: i = (addr >> 10) & 0xfc;
394: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
395: }
396:
397: desc = phys_get_long(desc_addr);
398: if ((desc & 3) == 2) {
399: /* indirect */
400: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
401: desc = phys_get_long(desc_addr);
402: }
403: if ((desc & 1) == 0) {
404: fprintf(stderr, "MMU: invalid page descriptor log=%08lx desc=%08lx @%08lx %s at %d\n", addr, desc, desc_addr,__FILE__,__LINE__);
405: return desc;
406: }
407:
408: desc |= wp & MMU_DES_WP;
409: if (write) {
410: if (desc & MMU_DES_WP) {
411: if ((desc & MMU_DES_USED) == 0) {
412: desc |= MMU_DES_USED;
413: phys_put_long(desc_addr, desc);
414: }
415: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
416: (MMU_DES_USED|MMU_DES_MODIFIED)) {
417: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
418: phys_put_long(desc_addr, desc);
419: }
420: } else {
421: if ((desc & MMU_DES_USED) == 0) {
422: desc |= MMU_DES_USED;
423: phys_put_long(desc_addr, desc);
424: }
425: }
426: return desc;
427: }
428:
429: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
430: {
431: uae_u16 res;
432:
433: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
434: SAVE_EXCEPTION;
435: TRY(prb) {
436: res |= mmu_get_byte(addr + 1, data, sz_word);
437: RESTORE_EXCEPTION;
438: }
439: CATCH(prb) {
440: RESTORE_EXCEPTION;
441: regs.mmu_fault_addr = addr;
442: regs.mmu_ssw |= MMU_SSW_MA;
443: THROW_AGAIN(prb);
444: } ENDTRY
445: return res;
446: }
447:
448: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
449: {
450: uae_u32 res;
451:
452: if (likely(!(addr & 1))) {
453: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
454: SAVE_EXCEPTION;
455: TRY(prb) {
456: res |= mmu_get_word(addr + 2, data, sz_long);
457: RESTORE_EXCEPTION;
458: }
459: CATCH(prb) {
460: RESTORE_EXCEPTION;
461: regs.mmu_fault_addr = addr;
462: regs.mmu_ssw |= MMU_SSW_MA;
463: THROW_AGAIN(prb);
464: } ENDTRY
465: } else {
466: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
467: SAVE_EXCEPTION;
468: TRY(prb) {
469: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
470: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
471: res |= mmu_get_byte(addr + 3, data, sz_long);
472: RESTORE_EXCEPTION;
473: }
474: CATCH(prb) {
475: RESTORE_EXCEPTION;
476: regs.mmu_fault_addr = addr;
477: regs.mmu_ssw |= MMU_SSW_MA;
478: THROW_AGAIN(prb);
479: } ENDTRY
480: }
481: return res;
482: }
483:
484: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
485: int size, struct mmu_atc_line *cl)
486: {
487: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) {
488: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
489: return 0;
490: }
491: return phys_get_byte(mmu_get_real_address(addr, cl));
492: }
493:
494: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
495: int size, struct mmu_atc_line *cl)
496: {
497: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) {
498: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
499: return 0;
500: }
501: return phys_get_word(mmu_get_real_address(addr, cl));
502: }
503:
504: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
505: int size, struct mmu_atc_line *cl)
506: {
507: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) {
508: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size);
509: return 0;
510: }
511: return phys_get_long(mmu_get_real_address(addr, cl));
512: }
513:
514: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
515: {
516: SAVE_EXCEPTION;
517: TRY(prb) {
518: if (likely(!(addr & 1))) {
519: mmu_put_word(addr, val >> 16, data, sz_long);
520: mmu_put_word(addr + 2, val, data, sz_long);
521: } else {
522: mmu_put_byte(addr, val >> 24, data, sz_long);
523: mmu_put_byte(addr + 1, val >> 16, data, sz_long);
524: mmu_put_byte(addr + 2, val >> 8, data, sz_long);
525: mmu_put_byte(addr + 3, val, data, sz_long);
526: }
527: RESTORE_EXCEPTION;
528: }
529: CATCH(prb) {
530: RESTORE_EXCEPTION;
531: regs.wb3_data = val;
532: if (regs.mmu_fault_addr != addr) {
533: regs.mmu_fault_addr = addr;
534: regs.mmu_ssw |= MMU_SSW_MA;
535: }
536: THROW_AGAIN(prb);
537: } ENDTRY
538: }
539:
540: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
541: {
542: SAVE_EXCEPTION;
543: TRY(prb) {
544: mmu_put_byte(addr, val >> 8, data, sz_word);
545: mmu_put_byte(addr + 1, val, data, sz_word);
546: RESTORE_EXCEPTION;
547: }
548: CATCH(prb) {
549: RESTORE_EXCEPTION;
550: regs.wb3_data = val;
551: if (regs.mmu_fault_addr != addr) {
552: regs.mmu_fault_addr = addr;
553: regs.mmu_ssw |= MMU_SSW_MA;
554: }
555: THROW_AGAIN(prb);
556: } ENDTRY
557: }
558:
559: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
560: int size, struct mmu_atc_line *cl)
561: {
562: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) {
563: regs.wb3_data = val;
564: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
565: return;
566: }
567: phys_put_byte(mmu_get_real_address(addr, cl), val);
568: }
569:
570: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
571: int size, struct mmu_atc_line *cl)
572: {
573: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) {
574: regs.wb3_data = val;
575: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
576: return;
577: }
578: phys_put_word(mmu_get_real_address(addr, cl), val);
579: }
580:
581: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
582: int size, struct mmu_atc_line *cl)
583: {
584: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) {
585: regs.wb3_data = val;
586: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size);
587: return;
588: }
589: phys_put_long(mmu_get_real_address(addr, cl), val);
590: }
591:
592: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
593: {
594: bool super = (regs.sfc & 4) != 0;
595: bool data = (regs.sfc & 3) != 2;
596: uae_u32 res;
597:
598: if (likely(!is_unaligned(addr, 4)))
599: return mmu_get_user_long(addr, super, data, sz_long);
600:
601: if (likely(!(addr & 1))) {
602: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16;
603: SAVE_EXCEPTION;
604: TRY(prb) {
605: res |= mmu_get_user_word(addr + 2, super, data, sz_long);
606: RESTORE_EXCEPTION;
607: }
608: CATCH(prb) {
609: RESTORE_EXCEPTION;
610: regs.mmu_fault_addr = addr;
611: regs.mmu_ssw |= MMU_SSW_MA;
612: THROW_AGAIN(prb);
613: } ENDTRY
614: } else {
615: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8;
616: SAVE_EXCEPTION;
617: TRY(prb) {
618: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8;
619: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8;
620: res |= mmu_get_user_byte(addr + 3, super, data, sz_long);
621: RESTORE_EXCEPTION;
622: }
623: CATCH(prb) {
624: RESTORE_EXCEPTION;
625: regs.mmu_fault_addr = addr;
626: regs.mmu_ssw |= MMU_SSW_MA;
627: THROW_AGAIN(prb);
628: } ENDTRY
629: }
630: return res;
631: }
632:
633: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
634: {
635: bool super = (regs.sfc & 4) != 0;
636: bool data = (regs.sfc & 3) != 2;
637: uae_u16 res;
638:
639: if (likely(!is_unaligned(addr, 2)))
640: return mmu_get_user_word(addr, super, data, sz_word);
641:
642: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8;
643: SAVE_EXCEPTION;
644: TRY(prb) {
645: res |= mmu_get_user_byte(addr + 1, super, data, sz_word);
646: RESTORE_EXCEPTION;
647: }
648: CATCH(prb) {
649: RESTORE_EXCEPTION;
650: regs.mmu_fault_addr = addr;
651: regs.mmu_ssw |= MMU_SSW_MA;
652: THROW_AGAIN(prb);
653: } ENDTRY
654: return res;
655: }
656:
657: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
658: {
659: bool super = (regs.sfc & 4) != 0;
660: bool data = (regs.sfc & 3) != 2;
661:
662: return mmu_get_user_byte(addr, super, data, sz_byte);
663: }
664:
665: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
666: {
667: bool super = (regs.dfc & 4) != 0;
668: bool data = (regs.dfc & 3) != 2;
669:
670: SAVE_EXCEPTION;
671: TRY(prb) {
672: if (likely(!is_unaligned(addr, 4)))
673: mmu_put_user_long(addr, val, super, data, sz_long);
674: else if (likely(!(addr & 1))) {
675: mmu_put_user_word(addr, val >> 16, super, data, sz_long);
676: mmu_put_user_word(addr + 2, val, super, data, sz_long);
677: } else {
678: mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
679: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
680: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
681: mmu_put_user_byte(addr + 3, val, super, data, sz_long);
682: }
683: RESTORE_EXCEPTION;
684: }
685: CATCH(prb) {
686: RESTORE_EXCEPTION;
687: regs.wb3_data = val;
688: if (regs.mmu_fault_addr != addr) {
689: regs.mmu_fault_addr = addr;
690: regs.mmu_ssw |= MMU_SSW_MA;
691: }
692: THROW_AGAIN(prb);
693: } ENDTRY
694: }
695:
696: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
697: {
698: bool super = (regs.dfc & 4) != 0;
699: bool data = (regs.dfc & 3) != 2;
700:
701: SAVE_EXCEPTION;
702: TRY(prb) {
703: if (likely(!is_unaligned(addr, 2)))
704: mmu_put_user_word(addr, val, super, data, sz_word);
705: else {
706: mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
707: mmu_put_user_byte(addr + 1, val, super, data, sz_word);
708: }
709: RESTORE_EXCEPTION;
710: }
711: CATCH(prb) {
712: RESTORE_EXCEPTION;
713: regs.wb3_data = val;
714: if (regs.mmu_fault_addr != addr) {
715: regs.mmu_fault_addr = addr;
716: regs.mmu_ssw |= MMU_SSW_MA;
717: }
718: THROW_AGAIN(prb);
719: } ENDTRY
720: }
721:
722: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
723: {
724: bool super = (regs.dfc & 4) != 0;
725: bool data = (regs.dfc & 3) != 2;
726:
727: SAVE_EXCEPTION;
728: TRY(prb) {
729: mmu_put_user_byte(addr, val, super, data, sz_byte);
730: RESTORE_EXCEPTION;
731: }
732: CATCH(prb) {
733: RESTORE_EXCEPTION;
734: regs.wb3_data = val;
735: THROW_AGAIN(prb);
736: } ENDTRY
737: }
738:
739: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
740: {
741: bool super = (regs.dfc & 4) != 0;
742: DUNUSED(extra);
743: if ((opcode & 0xFE0) == 0x0500) {
744: bool glob;
745: int regno;
746: //D(didflush = 0);
747: uae_u32 addr;
748: /* PFLUSH */
749: regno = opcode & 7;
750: glob = (opcode & 8) != 0;
751:
752: if (opcode & 16) {
753: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc);
754: mmu_flush_atc_all(glob);
755: } else {
756: addr = m68k_areg(regs, regno);
757: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr);
758: mmu_flush_atc(addr, super, glob);
759: }
760: flush_internals();
761: #ifdef USE_JIT
762: flush_icache(0);
763: #endif
764: } else if ((opcode & 0x0FD8) == 0x548) {
765: bool write;
766: int regno;
767: uae_u32 addr;
768:
769: regno = opcode & 7;
770: write = (opcode & 32) == 0;
771: addr = m68k_areg(regs, regno);
772: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc);
773: mmu_flush_atc(addr, super, true);
774: SAVE_EXCEPTION;
775: TRY(prb) {
776: struct mmu_atc_line *l;
777: uae_u32 desc;
778: bool data = (regs.dfc & 3) != 2;
779:
780: if (mmu_match_ttr(addr,super,data)!=TTR_NO_MATCH)
781: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
782: else {
783: mmu_user_lookup(addr, super, data, write, &l);
784: desc = mmu_fill_atc(addr, super, data, write, l);
785: if (!(l->valid))
786: regs.mmusr = MMU_MMUSR_B;
787: else {
788: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
789: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
790: regs.mmusr |= MMU_MMUSR_R;
791: }
792: }
793: }
794: CATCH(prb) {
795: regs.mmusr = MMU_MMUSR_B;
796: } ENDTRY
797: RESTORE_EXCEPTION;
798: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr);
799: } else
800: op_illg (opcode);
801: }
802:
803: // fixme : global parameter?
804: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
805: {
806: int way,type,index;
807:
808: addr = ((mmu_is_super?0x80000000:0x00000000)|(addr >> 1)) & (regs.mmu_pagesize_8k?0xFFFE0000:0xFFFF0000);
809: if (regs.mmu_pagesize_8k)
810: index=(addr & 0x0001E000)>>13;
811: else
812: index=(addr & 0x0000F000)>>12;
813: for (type=0;type<ATC_TYPE;type++)
814: for (way=0;way<ATC_WAYS;way++) {
815: if (!global && mmu_atc_array[type][way][index].global)
816: continue;
817: // if we have this
818: if ((addr == mmu_atc_array[type][way][index].tag) && (mmu_atc_array[type][way][index].valid)) {
819: mmu_atc_array[type][way][index].valid=false;
820: }
821: }
822: }
823:
824: void REGPARAM2 mmu_flush_atc_all(bool global)
825: {
826: unsigned int way,slot,type;
827: for (type=0;type<ATC_TYPE;type++)
828: for (way=0;way<ATC_WAYS;way++)
829: for (slot=0;slot<ATC_SLOTS;slot++) {
830: if (!global && mmu_atc_array[type][way][slot].global)
831: continue;
832: mmu_atc_array[type][way][slot].valid=false;
833: }
834: }
835:
836: void REGPARAM2 mmu_reset(void)
837: {
838: mmu_flush_atc_all(true);
839: }
840:
841:
842: void REGPARAM2 mmu_set_tc(uae_u16 tc)
843: {
844: regs.mmu_enabled = tc & 0x8000 ? 1 : 0;
845: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0;
846: mmu_flush_atc_all(true);
847:
848: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k);
849: }
850:
851: void REGPARAM2 mmu_set_super(bool super)
852: {
853: mmu_is_super=super;
854: }
855:
856: jmp_buf __exbuf;
857: int __exvalue;
858: #define MAX_TRY_STACK 256
859: static int s_try_stack_size=0;
860: static jmp_buf s_try_stack[MAX_TRY_STACK];
861: jmp_buf* __poptry(void) {
862: if (s_try_stack_size>0) {
1.1.1.3 ! root 863: s_try_stack_size--;
! 864: if (s_try_stack_size == 0)
! 865: return NULL;
! 866: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
! 867: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
! 868: return &s_try_stack[s_try_stack_size-1];
! 869: }
1.1.1.2 root 870: else {
871: fprintf(stderr,"try stack underflow...\n");
872: // return (NULL);
873: abort();
874: }
875: }
1.1.1.3 ! root 876: void __pushtry(jmp_buf* j) {
1.1.1.2 root 877: if (s_try_stack_size<MAX_TRY_STACK) {
878: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
879: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
880: s_try_stack_size++;
881: } else {
882: fprintf(stderr,"try stack overflow...\n");
883: abort();
884: }
885: }
886: int __is_catched(void) {return (s_try_stack_size>0); }
887: #else
888:
889: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
890: {
891: if ((opcode & 0xFE0) == 0x0500) {
892: /* PFLUSH instruction */
893: flush_internals();
894: } else if ((opcode & 0x0FD8) == 0x548) {
895: /* PTEST instruction */
896: } else
897: op_illg(opcode);
898: }
899:
900: #endif
901:
902: /*
903: vim:ts=4:sw=4:
904: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.