|
|
1.1 root 1: /* Emulation of MC68030 MMU
2: * This code has been written for Previous - a NeXT Computer emulator
3: *
4: * This file is distributed under the GNU General Public License, version 2
5: * or at your option any later version. Read the file gpl.txt for details.
6: *
7: *
8: * Written by Andreas Grabher
9: *
10: * Many thanks go to Thomas Huth and the Hatari community for helping
11: * to test and debug this code!
12: *
13: *
14: * Release notes:
15: * 01-09-2012: First release
16: * 29-09-2012: Improved function code handling
17: * 16-11-2012: Improved exception handling
18: *
19: *
20: * Known Problems:
21: * - Special Status Word (SSW) is not handled correctly
22: *
23: *
24: * TODO list:
25: * - Correctly handle Special Status Word. Now we use 68040 values.
26: * This also needs to be done in m68000.c, M68000_BusError!
27: * - Check if read-modify-write operations are correctly detected for
28: * handling transparent access (see TT matching functions)
29: * - If possible, test mmu030_table_search with all kinds of translations
30: * (early termination, invalid descriptors, bus errors, indirect
31: * descriptors, PTEST in different levels, etc).
32: * - Check which bits of an ATC entry should be set and which should be
33: * un-set, if an invalid translation occurs.
34: * - Handle cache inhibit bit when accessing ATC entries
35: */
36:
37:
38: #include "sysconfig.h"
39: #include "sysdeps.h"
40:
41: #include "options_cpu.h"
42: #include "memory.h"
43: #include "newcpu.h"
44: #include "main.h"
45: #include "m68000.h"
46: #include "hatari-glue.h"
47: #include "cpummu030.h"
48:
49:
50: #define MMU030_OP_DBG_MSG 0
51: #define MMU030_ATC_DBG_MSG 0
52: #define MMU030_REG_DBG_MSG 0
53:
54:
55: /* for debugging messages */
56: char table_letter[4] = {'A','B','C','D'};
57:
58:
59: /* ATC struct */
60: #define ATC030_NUM_ENTRIES 22
61:
62: typedef struct {
63: struct {
64: uaecptr addr;
65: bool modified;
66: bool write_protect;
67: bool cache_inhibit;
68: bool bus_error;
69: } physical;
70:
71: struct {
72: uaecptr addr;
73: uae_u32 fc;
74: bool valid;
75: } logical;
76: /* history bit */
77: int mru;
78: } MMU030_ATC_LINE;
79:
80:
81: /* MMU struct for 68030 */
82: struct {
83:
84: /* Translation tables */
85: struct {
86: struct {
87: uae_u32 mask;
88: uae_u8 shift;
89: } table[4];
90:
91: struct {
92: uae_u32 mask;
93: uae_u8 size;
94: } page;
95:
96: uae_u8 init_shift;
97: uae_u8 last_table;
98: } translation;
99:
100: /* Transparent translation */
101: struct {
102: TT_info tt0;
103: TT_info tt1;
104: } transparent;
105:
106: /* Address translation cache */
107: MMU030_ATC_LINE atc[ATC030_NUM_ENTRIES];
108:
109: /* Condition */
110: bool enabled;
111: uae_u16 status;
112: } mmu030;
113:
114:
115:
116: /* MMU Status Register
117: *
118: * ---x ---x x-xx x---
119: * reserved (all 0)
120: *
121: * x--- ---- ---- ----
122: * bus error
123: *
124: * -x-- ---- ---- ----
125: * limit violation
126: *
127: * --x- ---- ---- ----
128: * supervisor only
129: *
130: * ---- x--- ---- ----
131: * write protected
132: *
133: * ---- -x-- ---- ----
134: * invalid
135: *
136: * ---- --x- ---- ----
137: * modified
138: *
139: * ---- ---- -x-- ----
140: * transparent access
141: *
142: * ---- ---- ---- -xxx
143: * number of levels (number of tables accessed during search)
144: *
145: */
146:
147: #define MMUSR_BUS_ERROR 0x8000
148: #define MMUSR_LIMIT_VIOLATION 0x4000
149: #define MMUSR_SUPER_VIOLATION 0x2000
150: #define MMUSR_WRITE_PROTECTED 0x0800
151: #define MMUSR_INVALID 0x0400
152: #define MMUSR_MODIFIED 0x0200
153: #define MMUSR_TRANSP_ACCESS 0x0040
154: #define MMUSR_NUM_LEVELS_MASK 0x0007
155:
156:
157:
158: /* -- MMU instructions -- */
159:
160: void mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
161: {
162: int preg = (next >> 10) & 31;
163: int rw = (next >> 9) & 1;
164: int fd = (next >> 8) & 1;
165:
166: #if MMU030_OP_DBG_MSG
167: switch (preg) {
168: case 0x10:
169: write_log("PMOVE: %s TC %08X\n", rw?"read":"write",
170: rw?tc_030:x_get_long(extra));
171: break;
172: case 0x12:
173: write_log("PMOVE: %s SRP %08X%08X\n", rw?"read":"write",
174: rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra),
175: rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4));
176: break;
177: case 0x13:
178: write_log("PMOVE: %s CRP %08X%08X\n", rw?"read":"write",
179: rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra),
180: rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4));
181: break;
182: case 0x18:
183: write_log("PMOVE: %s MMUSR %04X\n", rw?"read":"write",
184: rw?mmusr_030:x_get_word(extra));
185: break;
186: case 0x02:
187: write_log("PMOVE: %s TT0 %08X\n", rw?"read":"write",
188: rw?tt0_030:x_get_long(extra));
189: break;
190: case 0x03:
191: write_log("PMOVE: %s TT1 %08X\n", rw?"read":"write",
192: rw?tt1_030:x_get_long(extra));
193: break;
194: default:
195: break;
196: }
197: if (!fd && !rw && !(preg==0x18)) {
198: write_log("PMOVE: flush ATC\n");
199: }
200: #endif
201:
202: switch (preg)
203: {
204: case 0x10: // TC
205: if (rw)
206: x_put_long (extra, tc_030);
207: else {
208: tc_030 = x_get_long (extra);
209: mmu030_decode_tc(tc_030);
210: }
211: break;
212: case 0x12: // SRP
213: if (rw) {
214: x_put_long (extra, srp_030 >> 32);
215: x_put_long (extra + 4, srp_030);
216: } else {
217: srp_030 = (uae_u64)x_get_long (extra) << 32;
218: srp_030 |= x_get_long (extra + 4);
219: mmu030_decode_rp(srp_030);
220: }
221: break;
222: case 0x13: // CRP
223: if (rw) {
224: x_put_long (extra, crp_030 >> 32);
225: x_put_long (extra + 4, crp_030);
226: } else {
227: crp_030 = (uae_u64)x_get_long (extra) << 32;
228: crp_030 |= x_get_long (extra + 4);
229: mmu030_decode_rp(crp_030);
230: }
231: break;
232: case 0x18: // MMUSR
233: if (rw)
234: x_put_word (extra, mmusr_030);
235: else
236: mmusr_030 = x_get_word (extra);
237: break;
238: case 0x02: // TT0
239: if (rw)
240: x_put_long (extra, tt0_030);
241: else {
242: tt0_030 = x_get_long (extra);
243: mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
244: }
245: break;
246: case 0x03: // TT1
247: if (rw)
248: x_put_long (extra, tt1_030);
249: else {
250: tt1_030 = x_get_long (extra);
251: mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
252: }
253: break;
254: default:
255: write_log ("Bad PMOVE at %08x\n",m68k_getpc());
256: op_illg (opcode);
257: return;
258: }
259:
260: if (!fd && !rw && !(preg==0x18)) {
261: mmu030_flush_atc_all();
262: }
263: }
264:
265: void mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
266: {
267: mmu030.status = mmusr_030 = 0;
268:
269: int level = (next&0x1C00)>>10;
270: int rw = (next >> 9) & 1;
271: int a = (next >> 8) & 1;
272: int areg = (next&0xE0)>>5;
273: uae_u32 fc = mmu_op30_helper_get_fc(next);
274:
275: bool write = rw ? false : true;
276:
277: uae_u32 ret = 0;
278:
279: /* Check this - datasheet says:
280: * "When the instruction specifies an address translation cache search
281: * with an address register operand, the MC68030 takes an F-line
282: * unimplemented instruction exception."
283: */
284: if (!level && a) { /* correct ? */
285: write_log("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n");
286: Exception(11, m68k_getpc(), M68000_EXC_SRC_CPU); /* F-line unimplemented instruction exception */
287: return;
288: }
289:
290: #if MMU030_OP_DBG_MSG
291: write_log("PTEST%c: addr = %08X, fc = %i, level = %i, ",
292: rw?'R':'W', extra, fc, level);
293: if (a) {
294: write_log("return descriptor to register A%i\n", areg);
295: } else {
296: write_log("do not return descriptor\n");
297: }
298: #endif
299:
300: if (!level) {
301: mmu030_ptest_atc_search(extra, fc, write);
302: } else {
303: ret = mmu030_ptest_table_search(extra, fc, write, level);
304: if (a) {
305: m68k_areg (regs, areg) = ret;
306: }
307: }
308: mmusr_030 = mmu030.status;
309:
310: #if MMU030_OP_DBG_MSG
311: write_log("PTEST status: %04X, B = %i, L = %i, S = %i, W = %i, I = %i, M = %i, T = %i, N = %i\n",
312: mmusr_030, (mmusr_030&MMUSR_BUS_ERROR)?1:0, (mmusr_030&MMUSR_LIMIT_VIOLATION)?1:0,
313: (mmusr_030&MMUSR_SUPER_VIOLATION)?1:0, (mmusr_030&MMUSR_WRITE_PROTECTED)?1:0,
314: (mmusr_030&MMUSR_INVALID)?1:0, (mmusr_030&MMUSR_MODIFIED)?1:0,
315: (mmusr_030&MMUSR_TRANSP_ACCESS)?1:0, mmusr_030&MMUSR_NUM_LEVELS_MASK);
316: #endif
317: }
318:
319: void mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
320: {
321: int rw = (next >> 9) & 1;
322: uae_u32 fc = mmu_op30_helper_get_fc(next);
323:
324: bool write = rw ? false : true;
325:
326: #if MMU030_OP_DBG_MSG
327: write_log ("PLOAD%c: Create ATC entry for %08X, FC = %i\n", write?'W':'R', extra, fc);
328: #endif
329:
330: mmu030_flush_atc_page(extra);
331: mmu030_table_search(extra, fc, write, 0);
332: }
333:
334: void mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
335: {
336: uae_u16 mode = (next&0x1C00)>>10;
337: uae_u32 fc_mask = (uae_u32)(next&0x00E0)>>5;
338: uae_u32 fc_base = mmu_op30_helper_get_fc(next);
339:
340: #if MMU030_OP_DBG_MSG
341: switch (mode) {
342: case 0x1:
343: write_log("PFLUSH: Flush all entries\n");
344: break;
345: case 0x4:
346: write_log("PFLUSH: Flush by function code only\n");
347: write_log("PFLUSH: function code: base = %08X, mask = %08X\n", fc_base, fc_mask);
348: break;
349: case 0x6:
350: write_log("PFLUSH: Flush by function code and effective address\n");
351: write_log("PFLUSH: function code: base = %08X, mask = %08X\n", fc_base, fc_mask);
352: write_log("PFLUSH: effective address = %08X\n", extra);
353: break;
354: default:
355: break;
356: }
357: #endif
358:
359: switch (mode) {
360: case 0x1:
361: mmu030_flush_atc_all();
362: break;
363: case 0x4:
364: mmu030_flush_atc_fc(fc_base, fc_mask);
365: break;
366: case 0x6:
367: mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
368: break;
369:
370: default:
371: write_log("PFLUSH ERROR: bad mode! (%i)\n",mode);
372: break;
373: }
374: }
375:
376: /* -- Helper function for MMU instructions -- */
377: uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
378: switch (next&0x0018) {
379: case 0x0010:
380: return (next&0x7);
381: case 0x0008:
382: return (m68k_dreg(regs, next&0x7)&0x7);
383: case 0x0000:
384: if (next&1) {
385: return (regs.dfc&0x7);
386: } else {
387: return (regs.sfc&0x7);
388: }
389: default:
390: write_log("MMU_OP30 ERROR: bad fc source! (%04X)\n",next&0x0018);
391: return 0;
392: }
393: }
394:
395:
396: /* -- ATC flushing functions -- */
397:
398: /* This function flushes ATC entries depending on their function code */
399: void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
400: int i;
401: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
402: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
403: mmu030.atc[i].logical.valid) {
404: mmu030.atc[i].logical.valid = false;
405: write_log("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
406: }
407: }
408: }
409:
410: /* This function flushes ATC entries depending on their logical address
411: * and their function code */
412: void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
413: int i;
414: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
415: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
416: (mmu030.atc[i].logical.addr == logical_addr) &&
417: mmu030.atc[i].logical.valid) {
418: mmu030.atc[i].logical.valid = false;
419: write_log("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
420: }
421: }
422: }
423:
424: /* This function flushes ATC entries depending on their logical address */
425: void mmu030_flush_atc_page(uaecptr logical_addr) {
426: int i;
427: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
428: if ((mmu030.atc[i].logical.addr == logical_addr) &&
429: mmu030.atc[i].logical.valid) {
430: mmu030.atc[i].logical.valid = false;
431: write_log("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
432: }
433: }
434: }
435:
436: /* This function flushes all ATC entries */
437: void mmu030_flush_atc_all(void) {
438: #if MMU030_ATC_DBG_MSG
439: write_log("ATC: Flushing all entries\n");
440: #endif
441: int i;
442: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
443: mmu030.atc[i].logical.valid = false;
444: }
445: }
446:
447:
448: /* Transparent Translation Registers (TT0 and TT1)
449: *
450: * ---- ---- ---- ---- -xxx x--- x--- x---
451: * reserved, must be 0
452: *
453: * ---- ---- ---- ---- ---- ---- ---- -xxx
454: * function code mask (FC bits to be ignored)
455: *
456: * ---- ---- ---- ---- ---- ---- -xxx ----
457: * function code base (FC value for transparent block)
458: *
459: * ---- ---- ---- ---- ---- ---x ---- ----
460: * 0 = r/w field used, 1 = read and write is transparently translated
461: *
462: * ---- ---- ---- ---- ---- --x- ---- ----
463: * r/w field: 0 = write ..., 1 = read access transparent
464: *
465: * ---- ---- ---- ---- ---- -x-- ---- ----
466: * cache inhibit: 0 = caching allowed, 1 = caching inhibited
467: *
468: * ---- ---- ---- ---- x--- ---- ---- ----
469: * 0 = transparent translation enabled disabled, 1 = enabled
470: *
471: * ---- ---- xxxx xxxx ---- ---- ---- ----
472: * logical address mask
473: *
474: * xxxx xxxx ---- ---- ---- ---- ---- ----
475: * logical address base
476: *
477: */
478:
479:
480: #define TT_FC_MASK 0x00000007
481: #define TT_FC_BASE 0x00000070
482: #define TT_RWM 0x00000100
483: #define TT_RW 0x00000200
484: #define TT_CI 0x00000400
485: #define TT_ENABLE 0x00008000
486:
487: #define TT_ADDR_MASK 0x00FF0000
488: #define TT_ADDR_BASE 0xFF000000
489:
490: /* TT comparision results */
491: #define TT_NO_MATCH 0x1
492: #define TT_OK_MATCH 0x2
493: #define TT_NO_READ 0x4
494: #define TT_NO_WRITE 0x8
495:
496: TT_info mmu030_decode_tt(uae_u32 TT) {
497:
498: TT_info ret;
499:
500: ret.fc_mask = ~((TT&TT_FC_MASK)|0xFFFFFFF8);
501: ret.fc_base = (TT&TT_FC_BASE)>>4;
502: ret.addr_base = TT & TT_ADDR_BASE;
503: ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
504:
505: if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
506: write_log("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n");
507: }
508:
509: #if MMU030_REG_DBG_MSG /* enable or disable debugging messages */
510: write_log("\n");
511: write_log("TRANSPARENT TRANSLATION: %08X\n", TT);
512: write_log("\n");
513:
514: write_log("TT: transparent translation ");
515: if (TT&TT_ENABLE) {
516: write_log("enabled\n");
517: } else {
518: write_log("disabled\n");
519: return ret;
520: }
521:
522: write_log("TT: caching %s\n", (TT&TT_CI) ? "inhibited" : "enabled");
523: write_log("TT: read-modify-write ");
524: if (TT&TT_RWM) {
525: write_log("enabled\n");
526: } else {
527: write_log("disabled (%s only)\n", (TT&TT_RW) ? "read" : "write");
528: }
529: write_log("\n");
530: write_log("TT: function code base: %08X\n", ret.fc_base);
531: write_log("TT: function code mask: %08X\n", ret.fc_mask);
532: write_log("\n");
533: write_log("TT: address base: %08X\n", ret.addr_base);
534: write_log("TT: address mask: %08X\n", ret.addr_mask);
535: write_log("\n");
536: #endif
537:
538: return ret;
539: }
540:
541: /* This function compares the address with both transparent
542: * translation registers and returns the result */
543: int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
544: {
545: int tt0, tt1;
546:
547: bool cache_inhibit = false; /* TODO: pass to memory access function */
548:
549: tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
550: if (tt0&TT_OK_MATCH) {
551: cache_inhibit = (tt0_030&TT_CI) ? true : false;
552: }
553: tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
554: if (tt1&TT_OK_MATCH) {
555: if (!cache_inhibit) {
556: cache_inhibit = (tt1_030&TT_CI) ? true : false;
557: }
558: }
559:
560: return (tt0|tt1);
561: }
562:
563: /* This function checks if an address matches a transparent
564: * translation register */
565:
566: /* FIXME:
567: * If !(tt&TT_RMW) neither the read nor the write portion
568: * of a read-modify-write cycle is transparently translated! */
569:
570: int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
571: {
572: if (tt & TT_ENABLE) { /* transparent translation enabled */
573:
574: /* Compare actual function code with function code base using mask */
575: if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
576:
577: /* Compare actual address with address base using mask */
578: if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
579:
580: if (tt&TT_RWM) { /* r/w field disabled */
581: return TT_OK_MATCH;
582: } else {
583: if (tt&TT_RW) { /* read access transparent */
584: return write ? TT_NO_WRITE : TT_OK_MATCH;
585: } else { /* write access transparent */
586: return write ? TT_OK_MATCH : TT_NO_READ; /* TODO: check this! */
587: }
588: }
589: }
590: }
591: }
592: return TT_NO_MATCH;
593: }
594:
595:
596:
597: /* Translation Control Register:
598: *
599: * x--- ---- ---- ---- ---- ---- ---- ----
600: * translation: 1 = enable, 0 = disable
601: *
602: * ---- --x- ---- ---- ---- ---- ---- ----
603: * supervisor root: 1 = enable, 0 = disable
604: *
605: * ---- ---x ---- ---- ---- ---- ---- ----
606: * function code lookup: 1 = enable, 0 = disable
607: *
608: * ---- ---- xxxx ---- ---- ---- ---- ----
609: * page size:
610: * 1000 = 256 bytes
611: * 1001 = 512 bytes
612: * 1010 = 1 kB
613: * 1011 = 2 kB
614: * 1100 = 4 kB
615: * 1101 = 8 kB
616: * 1110 = 16 kB
617: * 1111 = 32 kB
618: *
619: * ---- ---- ---- xxxx ---- ---- ---- ----
620: * initial shift
621: *
622: * ---- ---- ---- ---- xxxx ---- ---- ----
623: * number of bits for table index A
624: *
625: * ---- ---- ---- ---- ---- xxxx ---- ----
626: * number of bits for table index B
627: *
628: * ---- ---- ---- ---- ---- ---- xxxx ----
629: * number of bits for table index C
630: *
631: * ---- ---- ---- ---- ---- ----- ---- xxxx
632: * number of bits for table index D
633: *
634: */
635:
636:
637: #define TC_ENABLE_TRANSLATION 0x80000000
638: #define TC_ENABLE_SUPERVISOR 0x02000000
639: #define TC_ENABLE_FCL 0x01000000
640:
641: #define TC_PS_MASK 0x00F00000
642: #define TC_IS_MASK 0x000F0000
643:
644: #define TC_TIA_MASK 0x0000F000
645: #define TC_TIB_MASK 0x00000F00
646: #define TC_TIC_MASK 0x000000F0
647: #define TC_TID_MASK 0x0000000F
648:
649:
650: void mmu030_decode_tc(uae_u32 TC) {
651:
652: /* Set MMU condition */
653: if (TC & TC_ENABLE_TRANSLATION) {
654: mmu030.enabled = true;
655: write_log("MMU enabled\n");
656: } else {
657: mmu030.enabled = false;
658: write_log("MMU disabled\n");
659: return;
660: }
661:
662: /* Note: 0 = Table A, 1 = Table B, 2 = Table C, 3 = Table D */
663: int i, j;
664: uae_u8 TI_bits[4] = {0,0,0,0};
665:
666: /* Reset variables before extracting new values from TC */
667: for (i = 0; i < 4; i++) {
668: mmu030.translation.table[i].mask = 0;
669: mmu030.translation.table[i].shift = 0;
670: }
671: mmu030.translation.page.mask = 0;
672:
673:
674: /* Extract initial shift and page size values from TC register */
675: mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
676: mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
677:
678: if (mmu030.translation.page.size<8) {
679: write_log("MMU Configuration Exception: Bad value in TC register! (bad page size: %i byte)\n",
680: 1<<mmu030.translation.page.size);
681: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
682: return;
683: }
684: /* Build the page mask */
685: for (i = 0; i < mmu030.translation.page.size; i++) {
686: mmu030.translation.page.mask |= (1<<i);
687: }
688:
689:
690: /* Calculate masks and shifts for later extracting table indices
691: * from logical addresses using: index = (addr&mask)>>shift */
692:
693: /* Get number of bits for each table index */
694: for (i = 0; i < 4; i++) {
695: j = (3-i)*4;
696: TI_bits[i] = (TC >> j) & 0xF;
697: }
698:
699: /* Calculate masks and shifts for each table */
700: mmu030.translation.last_table = 0;
701: uae_u8 shift = 32 - mmu030.translation.init_shift;
702: for (i = 0; (i < 4) && TI_bits[i]; i++) {
703: /* Get the shift */
704: shift -= TI_bits[i];
705: mmu030.translation.table[i].shift = shift;
706: /* Build the mask */
707: for (j = 0; j < TI_bits[i]; j++) {
708: mmu030.translation.table[i].mask |= (1<<(mmu030.translation.table[i].shift + j));
709: }
710: /* Update until reaching the last table */
711: mmu030.translation.last_table = i;
712: }
713:
714: #if MMU030_REG_DBG_MSG
715: /* At least one table has to be defined using at least
716: * 1 bit for the index. At least 2 bits are necessary
717: * if there is no second table. If these conditions are
718: * not met, it will automatically lead to a sum <32
719: * and cause an exception (see below). */
720: if (!TI_bits[0]) {
721: write_log("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n");
722: } else if ((TI_bits[0]<2) && !TI_bits[1]) {
723: write_log("MMU Configuration Exception: Bad value in TC register! (no second table index defined and)\n");
724: write_log("MMU Configuration Exception: Bad value in TC register! (only 1 bit for first table index)\n");
725: }
726: #endif
727:
728: /* TI fields are summed up until a zero field is reached (see above
729: * loop). The sum of all TI field values plus page size and initial
730: * shift has to be 32: IS + PS + TIA + TIB + TIC + TID = 32 */
731: if ((shift-mmu030.translation.page.size)!=0) {
732: write_log("MMU Configuration Exception: Bad value in TC register! (bad sum)\n");
733: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
734: return;
735: }
736:
737: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
738: write_log("\n");
739: write_log("TRANSLATION CONTROL: %08X\n", TC);
740: write_log("\n");
741: write_log("TC: translation %s\n", (TC&TC_ENABLE_TRANSLATION ? "enabled" : "disabled"));
742: write_log("TC: supervisor root pointer %s\n", (TC&TC_ENABLE_SUPERVISOR ? "enabled" : "disabled"));
743: write_log("TC: function code lookup %s\n", (TC&TC_ENABLE_FCL ? "enabled" : "disabled"));
744: write_log("\n");
745:
746: write_log("TC: Initial Shift: %i\n", mmu030.translation.init_shift);
747: write_log("TC: Page Size: %i byte\n", (1<<mmu030.translation.page.size));
748: write_log("\n");
749:
750: for (i = 0; i <= mmu030.translation.last_table; i++) {
751: write_log("TC: Table %c: mask = %08X, shift = %i\n", table_letter[i], mmu030.translation.table[i].mask, mmu030.translation.table[i].shift);
752: }
753:
754: write_log("TC: Page: mask = %08X\n", mmu030.translation.page.mask);
755: write_log("\n");
756:
757: write_log("TC: Last Table: %c\n", table_letter[mmu030.translation.last_table]);
758: write_log("\n");
759: #endif
760: }
761:
762:
763:
764: /* Root Pointer Registers (SRP and CRP)
765: *
766: * ---- ---- ---- ---- xxxx xxxx xxxx xx-- ---- ---- ---- ---- ---- ---- ---- xxxx
767: * reserved, must be 0
768: *
769: * ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
770: * table A address
771: *
772: * ---- ---- ---- ---- ---- ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- ----
773: * descriptor type
774: *
775: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
776: * limit
777: *
778: * x--- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
779: * 0 = upper limit, 1 = lower limit
780: *
781: */
782:
783:
784: #define RP_ADDR_MASK (UVAL64(0x00000000FFFFFFF0))
785: #define RP_DESCR_MASK (UVAL64(0x0000000300000000))
786: #define RP_LIMIT_MASK (UVAL64(0x7FFF000000000000))
787: #define RP_LOWER_MASK (UVAL64(0x8000000000000000))
788:
789: #define RP_ZERO_BITS 0x0000FFFC /* These bits in upper longword of RP must be 0 */
790:
791: void mmu030_decode_rp(uae_u64 RP) {
792:
793: uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
794: if (!descriptor_type) { /* If descriptor type is invalid */
795: write_log("MMU Configuration Exception: Root Pointer is invalid!\n");
796: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
797: }
798:
799: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
800: uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
801: uae_u32 first_addr = (RP & RP_ADDR_MASK);
802:
803: write_log("\n");
804: write_log("ROOT POINTER: %08X%08X\n", (uae_u32)(RP>>32)&0xFFFFFFFF, (uae_u32)(RP&0xFFFFFFFF));
805: write_log("\n");
806:
807: write_log("RP: descriptor type = %i ", descriptor_type);
808: switch (descriptor_type) {
809: case 0:
810: write_log("(invalid descriptor)\n");
811: break;
812: case 1:
813: write_log("(early termination page descriptor)\n");
814: break;
815: case 2:
816: write_log("(valid 4 byte descriptor)\n");
817: break;
818: case 3:
819: write_log("(valid 8 byte descriptor)\n");
820: break;
821: }
822:
823: write_log("RP: %s limit = %i\n", (RP&RP_LOWER_MASK) ? "lower" : "upper", table_limit);
824:
825: write_log("RP: first table address = %08X\n", first_addr);
826: write_log("\n");
827: #endif
828: }
829:
830:
831:
832: /* Descriptors */
833:
834: #define DESCR_TYPE_MASK 0x00000003
835:
836: #define DESCR_TYPE_INVALID 0 /* all tables */
837:
838: #define DESCR_TYPE_EARLY_TERM 1 /* all but lowest level table */
839: #define DESCR_TYPE_PAGE 1 /* only lowest level table */
840: #define DESCR_TYPE_VALID4 2 /* all but lowest level table */
841: #define DESCR_TYPE_INDIRECT4 2 /* only lowest level table */
842: #define DESCR_TYPE_VALID8 3 /* all but lowest level table */
843: #define DESCR_TYPE_INDIRECT8 3 /* only lowest level table */
844:
845: #define DESCR_TYPE_VALID_MASK 0x2 /* all but lowest level table */
846: #define DESCR_TYPE_INDIRECT_MASK 0x2 /* only lowest level table */
847:
848:
849: /* Short format (4 byte):
850: *
851: * ---- ---- ---- ---- ---- ---- ---- --xx
852: * descriptor type:
853: * 0 = invalid
854: * 1 = page descriptor (early termination)
855: * 2 = valid (4 byte)
856: * 3 = valid (8 byte)
857: *
858: *
859: * table descriptor:
860: * ---- ---- ---- ---- ---- ---- ---- -x--
861: * write protect
862: *
863: * ---- ---- ---- ---- ---- ---- ---- x---
864: * update
865: *
866: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
867: * table address
868: *
869: *
870: * (early termination) page descriptor:
871: * ---- ---- ---- ---- ---- ---- ---- -x--
872: * write protect
873: *
874: * ---- ---- ---- ---- ---- ---- ---- x---
875: * update
876: *
877: * ---- ---- ---- ---- ---- ---- ---x ----
878: * modified
879: *
880: * ---- ---- ---- ---- ---- ---- -x-- ----
881: * cache inhibit
882: *
883: * ---- ---- ---- ---- ---- ---- x-x- ----
884: * reserved (must be 0)
885: *
886: * xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
887: * page address
888: *
889: *
890: * indirect descriptor:
891: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
892: * descriptor address
893: *
894: */
895:
896: #define DESCR_WP 0x00000004
897: #define DESCR_U 0x00000008
898: #define DESCR_M 0x00000010 /* only last level table */
899: #define DESCR_CI 0x00000040 /* only last level table */
900:
901: #define DESCR_TD_ADDR_MASK 0xFFFFFFF0
902: #define DESCR_PD_ADDR_MASK 0xFFFFFF00
903: #define DESCR_ID_ADDR_MASK 0xFFFFFFFC
904:
905:
906: /* Long format (8 byte):
907: *
908: * ---- ---- ---- ---- ---- ---- ---- --xx | ---- ---- ---- ---- ---- ---- ---- ----
909: * descriptor type:
910: * 0 = invalid
911: * 1 = page descriptor (early termination)
912: * 2 = valid (4 byte)
913: * 3 = valid (8 byte)
914: *
915: *
916: * table desctriptor:
917: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
918: * write protect
919: *
920: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
921: * update
922: *
923: * ---- ---- ---- ---- ---- ---- xxxx ---- | ---- ---- ---- ---- ---- ---- ---- ----
924: * reserved (must be 0)
925: *
926: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
927: * supervisor
928: *
929: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
930: * reserved (must be 1111 110)
931: *
932: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
933: * limit
934: *
935: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
936: * 0 = upper limit, 1 = lower limit
937: *
938: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
939: * table address
940: *
941: *
942: * (early termination) page descriptor:
943: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
944: * write protect
945: *
946: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
947: * update
948: *
949: * ---- ---- ---- ---- ---- ---- ---x ---- | ---- ---- ---- ---- ---- ---- ---- ----
950: * modified
951: *
952: * ---- ---- ---- ---- ---- ---- -x-- ---- | ---- ---- ---- ---- ---- ---- ---- ----
953: * cache inhibit
954: *
955: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
956: * supervisor
957: *
958: * ---- ---- ---- ---- ---- ---- x-x- ---- | ---- ---- ---- ---- ---- ---- ---- ----
959: * reserved (must be 0)
960: *
961: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
962: * reserved (must be 1111 110)
963: *
964: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
965: * limit (only used with early termination page decriptor)
966: *
967: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
968: * 0 = upper limit, 1 = lower limit (only used with early termination page descriptor)
969: *
970: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
971: * page address
972: *
973: *
974: * indirect descriptor:
975: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
976: * descriptor address
977: *
978: */
979:
980: /* only for long descriptors */
981: #define DESCR_S 0x00000100
982:
983: #define DESCR_LIMIT_MASK 0x7FFF0000
984: #define DESCR_LOWER_MASK 0x80000000
985:
986:
987:
988: /* This functions searches through the translation tables. It can be used
989: * for PTEST (levels 1 to 7). Using level 0 creates an ATC entry. */
990:
991: uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
992: /* During table walk up to 7 different descriptors are used:
993: * root pointer, descriptors fetched from function code lookup table,
994: * tables A, B, C and D and one indirect descriptor */
995: uae_u32 descr[2];
996: uae_u32 descr_type;
997: uaecptr descr_addr[7];
998: uaecptr table_addr = 0;
999: uaecptr page_addr = 0;
1000: uaecptr indirect_addr = 0;
1001: uae_u32 table_index = 0;
1002: uae_u32 limit = 0;
1003: uae_u32 unused_fields_mask = 0;
1004: bool super = (fc&4) ? true : false;
1005: bool write_protect = false;
1006: bool cache_inhibit = false;
1007: bool descr_modified = false;
1008:
1009: mmu030.status = 0; /* Reset status */
1010:
1011: /* Initial values for condition variables.
1012: * Note: Root pointer is long descriptor. */
1013: int t = 0;
1014: int addr_position = 1;
1015: int next_size = 0;
1016: int descr_size = 8;
1017: int descr_num = 0;
1018: bool early_termination = false;
1019:
1020: int i;
1021: int old_regs_s; /* Supervisor status when this function has been called */
1022:
1023: old_regs_s = regs.s;
1024: regs.s = 1; /* FIXME: Always enable supervisor (needed for SysMem) */
1025:
1026: TRY(prb) {
1027: /* Use super user root pointer if enabled in TC register and access is in
1028: * super user mode, else use cpu root pointer. */
1029: if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
1030: descr[0] = (srp_030>>32)&0xFFFFFFFF;
1031: descr[1] = srp_030&0xFFFFFFFF;
1032: #if MMU030_REG_DBG_MSG
1033: write_log("Supervisor Root Pointer: %08X%08X\n",descr[0],descr[1]);
1034: #endif // MMU030_REG_DBG_MSG
1035: } else {
1036: descr[0] = (crp_030>>32)&0xFFFFFFFF;
1037: descr[1] = crp_030&0xFFFFFFFF;
1038: #if MMU030_REG_DBG_MSG
1039: write_log("CPU Root Pointer: %08X%08X\n",descr[0],descr[1]);
1040: #endif
1041: }
1042:
1043: if (descr[0]&RP_ZERO_BITS) {
1044: write_log("MMU Warning: Root pointer reserved bits are non-zero!\n");
1045: descr[0] &= (~RP_ZERO_BITS);
1046: }
1047:
1048: /* Check descriptor type of root pointer */
1049: descr_type = descr[0]&DESCR_TYPE_MASK;
1050: switch (descr_type) {
1051: case DESCR_TYPE_INVALID:
1052: write_log("Fatal error: Root pointer is invalid descriptor!\n");
1053: mmu030.status |= MMUSR_INVALID;
1054: goto stop_search;
1055: case DESCR_TYPE_EARLY_TERM:
1056: write_log("Root pointer is early termination page descriptor.\n");
1057: early_termination = true;
1058: goto handle_page_descriptor;
1059: case DESCR_TYPE_VALID4:
1060: next_size = 4;
1061: break;
1062: case DESCR_TYPE_VALID8:
1063: next_size = 8;
1064: break;
1065: }
1066:
1067: /* If function code lookup is enabled in TC register use function code as
1068: * index for top level table, limit check not required */
1069:
1070: if (tc_030&TC_ENABLE_FCL) {
1071: write_log("Function code lookup enabled, FC = %i\n", fc);
1072:
1073: addr_position = (descr_size==4) ? 0 : 1;
1074: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1075: table_index = fc; /* table index is function code */
1076: write_log("Table FCL at %08X: index = %i, ",table_addr,table_index);
1077:
1078: /* Fetch next descriptor */
1079: descr_num++;
1080: descr_addr[descr_num] = table_addr+(table_index*next_size);
1081:
1082: if (next_size==4) {
1083: descr[0] = phys_get_long(descr_addr[descr_num]);
1084: #if MMU030_REG_DBG_MSG
1085: write_log("Next descriptor: %08X\n",descr[0]);
1086: #endif
1087: } else {
1088: descr[0] = phys_get_long(descr_addr[descr_num]);
1089: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1090: #if MMU030_REG_DBG_MSG
1091: write_log("Next descriptor: %08X%08X\n",descr[0],descr[1]);
1092: #endif
1093: }
1094:
1095: descr_size = next_size;
1096:
1097: /* Check descriptor type */
1098: descr_type = descr[0]&DESCR_TYPE_MASK;
1099: switch (descr_type) {
1100: case DESCR_TYPE_INVALID:
1101: write_log("Invalid descriptor!\n");
1102: /* stop table walk */
1103: mmu030.status |= MMUSR_INVALID;
1104: goto stop_search;
1105: case DESCR_TYPE_EARLY_TERM:
1106: #if MMU030_REG_DBG_MSG
1107: write_log("Early termination page descriptor!\n");
1108: #endif
1109: early_termination = true;
1110: goto handle_page_descriptor;
1111: case DESCR_TYPE_VALID4:
1112: next_size = 4;
1113: break;
1114: case DESCR_TYPE_VALID8:
1115: next_size = 8;
1116: break;
1117: }
1118: }
1119:
1120:
1121: /* Upper level tables */
1122: do {
1123: if (descr_num) { /* if not root pointer */
1124: /* Set the updated bit */
1125: if (!level && !(descr[0]&DESCR_U) && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1126: descr[0] |= DESCR_U;
1127: phys_put_long(descr_addr[descr_num], descr[0]);
1128: }
1129: /* Update status bits */
1130: if (descr_size==8) {
1131: if (descr[0]&DESCR_S)
1132: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1133: }
1134: if (descr[0]&DESCR_WP) {
1135: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1136: write_protect = true;
1137: }
1138:
1139: /* Check if ptest level is reached */
1140: if (level && (level==descr_num)) {
1141: goto stop_search;
1142: }
1143: }
1144:
1145: addr_position = (descr_size==4) ? 0 : 1;
1146: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1147: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1148: #if MMU030_REG_DBG_MSG
1149: write_log("Table %c at %08X: index = %i, ",table_letter[t],table_addr,table_index);
1150: #endif // MMU030_REG_DBG_MSG
1151: t++; /* Proceed to the next table */
1152:
1153: /* Perform limit check */
1154: if (descr_size==8) {
1155: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1156: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1157: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1158: write_log("limit violation (lower limit %i)\n",limit);
1159: goto stop_search;
1160: }
1161: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1162: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1163: write_log("limit violation (upper limit %i)\n",limit);
1164: goto stop_search;
1165: }
1166: }
1167:
1168: /* Fetch next descriptor */
1169: descr_num++;
1170: descr_addr[descr_num] = table_addr+(table_index*next_size);
1171:
1172: if (next_size==4) {
1173: descr[0] = phys_get_long(descr_addr[descr_num]);
1174: #if MMU030_REG_DBG_MSG
1175: write_log("Next descriptor: %08X\n",descr[0]);
1176: #endif
1177: } else {
1178: descr[0] = phys_get_long(descr_addr[descr_num]);
1179: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1180: #if MMU030_REG_DBG_MSG
1181: write_log("Next descriptor: %08X%08X\n",descr[0],descr[1]);
1182: #endif
1183: }
1184:
1185: descr_size = next_size;
1186:
1187: /* Check descriptor type */
1188: descr_type = descr[0]&DESCR_TYPE_MASK;
1189: switch (descr_type) {
1190: case DESCR_TYPE_INVALID:
1191: write_log("Invalid descriptor!\n");
1192: /* stop table walk */
1193: mmu030.status |= MMUSR_INVALID;
1194: goto stop_search;
1195: case DESCR_TYPE_EARLY_TERM:
1196: /* go to last level table handling code */
1197: if (t<=mmu030.translation.last_table) {
1198: #if MMU030_REG_DBG_MSG
1199: write_log("Early termination page descriptor!\n");
1200: #endif
1201: early_termination = true;
1202: }
1203: goto handle_page_descriptor;
1204: case DESCR_TYPE_VALID4:
1205: next_size = 4;
1206: break;
1207: case DESCR_TYPE_VALID8:
1208: next_size = 8;
1209: break;
1210: }
1211: } while (t<=mmu030.translation.last_table);
1212:
1213:
1214: /* Handle indirect descriptor */
1215:
1216: /* Check if ptest level is reached */
1217: if (level && (level==descr_num)) {
1218: goto stop_search;
1219: }
1220:
1221: addr_position = (descr_size==4) ? 0 : 1;
1222: indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1223: write_log("Page indirect descriptor at %08X: ",indirect_addr);
1224:
1225: /* Fetch indirect descriptor */
1226: descr_num++;
1227: descr_addr[descr_num] = indirect_addr;
1228:
1229: if (next_size==4) {
1230: descr[0] = phys_get_long(descr_addr[descr_num]);
1231: write_log("descr = %08X\n",descr[0]);
1232: } else {
1233: descr[0] = phys_get_long(descr_addr[descr_num]);
1234: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1235: write_log("descr = %08X%08X",descr[0],descr[1]);
1236: }
1237:
1238: descr_size = next_size;
1239:
1240: /* Check descriptor type, only page descriptor is valid */
1241: descr_type = descr[0]&DESCR_TYPE_MASK;
1242: if (descr_type!=DESCR_TYPE_PAGE) {
1243: mmu030.status |= MMUSR_INVALID;
1244: goto stop_search;
1245: }
1246:
1247: handle_page_descriptor:
1248:
1249: if (descr_num) { /* if not root pointer */
1250: if (!level && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1251: /* set modified bit */
1252: if (!(descr[0]&DESCR_M) && write && !(mmu030.status&MMUSR_WRITE_PROTECTED)) {
1253: descr[0] |= DESCR_M;
1254: descr_modified = true;
1255: }
1256: /* set updated bit */
1257: if (!(descr[0]&DESCR_U)) {
1258: descr[0] |= DESCR_U;
1259: descr_modified = true;
1260: }
1261: /* write modified descriptor if neccessary */
1262: if (descr_modified) {
1263: phys_put_long(descr_addr[descr_num], descr[0]);
1264: }
1265: }
1266:
1267: if ((descr_size==8) && (descr[0]&DESCR_S)) {
1268: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1269: }
1270:
1271: /* check if caching is inhibited */
1272: cache_inhibit = descr[0]&DESCR_CI ? true : false;
1273:
1274: /* check write protection */
1275: if (descr[0]&DESCR_WP) {
1276: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1277: write_protect = true;
1278: }
1279: /* TODO: check if this is handled at correct point (maybe before updating descr?) */
1280: mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
1281: }
1282:
1283: /* Check limit using next index field of logical address.
1284: * Limit is only checked on early termination. If we are
1285: * still at root pointer level, only check limit, if FCL
1286: * is disabled. */
1287: if (early_termination) {
1288: if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
1289: if (descr_size==8) {
1290: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1291: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1292: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1293: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1294: write_log("Limit violation (lower limit %i)\n",limit);
1295: goto stop_search;
1296: }
1297: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1298: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1299: write_log("Limit violation (upper limit %i)\n",limit);
1300: goto stop_search;
1301: }
1302: }
1303: }
1304: /* Get all unused bits of the logical address table index field.
1305: * they are added to the page address */
1306: /* TODO: They should be added via "signed addition". How to? */
1307: do {
1308: unused_fields_mask |= mmu030.translation.table[t].mask;
1309: t++;
1310: } while (t<=mmu030.translation.last_table);
1311: page_addr = addr&unused_fields_mask;
1312: #if MMU030_REG_DBG_MSG
1313: write_log("Logical address unused bits: %08X (mask = %08X)\n",
1314: page_addr,unused_fields_mask);
1315: #endif
1316: }
1317:
1318: /* Get page address */
1319: addr_position = (descr_size==4) ? 0 : 1;
1320: page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
1321: #if MMU030_REG_DBG_MSG
1322: write_log("Page at %08X\n",page_addr);
1323: #endif // MMU030_REG_DBG_MSG
1324:
1325: stop_search:
1326: ; /* Make compiler happy */
1327: } CATCH(prb) {
1328: /* We jump to this place, if a bus error occured during table search.
1329: * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
1330: if (bBusErrorReadWrite) {
1331: descr_num--;
1332: }
1333: mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1334: write_log("MMU: Bus error while %s descriptor!\n",
1335: bBusErrorReadWrite?"reading":"writing");
1336: } ENDTRY
1337:
1338: regs.s = old_regs_s;
1339:
1340: /* check if we have to handle ptest */
1341: if (level) {
1342: if (mmu030.status&MMUSR_INVALID) {
1343: /* these bits are undefined, if the I bit is set: */
1344: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED|MMUSR_SUPER_VIOLATION);
1345: }
1346: mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
1347:
1348: /* If root pointer is page descriptor (descr_num 0), return 0 */
1349: return descr_num ? descr_addr[descr_num] : 0;
1350: }
1351:
1352: /* Find an ATC entry to replace */
1353: /* Search for invalid entry */
1354: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1355: if (!mmu030.atc[i].logical.valid) {
1356: break;
1357: }
1358: }
1359: /* If there are no invalid entries, replace first entry
1360: * with history bit not set */
1361: if (i == ATC030_NUM_ENTRIES) {
1362: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1363: if (!mmu030.atc[i].mru) {
1364: break;
1365: }
1366: }
1367: #if MMU030_ATC_DBG_MSG
1368: write_log("ATC is full. Replacing entry %i\n", i);
1369: #endif
1370: }
1371: mmu030_atc_handle_history_bit(i);
1372:
1373: /* Create ATC entry */
1374: mmu030.atc[i].logical.addr = addr & (~mmu030.translation.page.mask); /* delete page index bits */
1375: mmu030.atc[i].logical.fc = fc;
1376: mmu030.atc[i].logical.valid = true;
1377: mmu030.atc[i].physical.addr = page_addr & (~mmu030.translation.page.mask); /* delete page index bits */
1378: if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
1379: mmu030.atc[i].physical.bus_error = true;
1380: } else {
1381: mmu030.atc[i].physical.bus_error = false;
1382: }
1383: if (write && !(mmu030.status&MMUSR_SUPER_VIOLATION) && !(mmu030.status&MMUSR_LIMIT_VIOLATION)) {
1384: mmu030.atc[i].physical.modified = true;
1385: } else {
1386: mmu030.atc[i].physical.modified = false;
1387: }
1388: mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1389: mmu030.atc[i].physical.write_protect = write_protect;
1390:
1391: #if MMU030_ATC_DBG_MSG
1392: write_log("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n", i,
1393: mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
1394: mmu030.atc[i].logical.fc);
1395: write_log("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n", i,
1396: mmu030.atc[i].physical.bus_error?1:0,
1397: mmu030.atc[i].physical.cache_inhibit?1:0,
1398: mmu030.atc[i].physical.write_protect?1:0,
1399: mmu030.atc[i].physical.modified?1:0);
1400: #endif // MMU030_ATC_DBG_MSG
1401:
1402: return 0;
1403: }
1404:
1405: /* This function is used for PTEST level 0. */
1406: void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1407: int i;
1408: mmu030.status = 0;
1409:
1410: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1411: mmu030.status |= MMUSR_TRANSP_ACCESS;
1412: return;
1413: }
1414:
1415: for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
1416: if ((mmu030.atc[i].logical.fc == fc) &&
1417: (mmu030.atc[i].logical.addr == logical_addr) &&
1418: mmu030.atc[i].logical.valid) {
1419: break;
1420: }
1421: }
1422:
1423: if (i==ATC030_NUM_ENTRIES) {
1424: mmu030.status |= MMUSR_INVALID;
1425: return;
1426: }
1427:
1428: mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1429: mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
1430: mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
1431: if (mmu030.status&MMUSR_INVALID) {
1432: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED);
1433: }
1434: }
1435:
1436: /* This function is used for PTEST level 1 - 7. */
1437: uae_u32 mmu030_ptest_table_search(uaecptr logical_addr, uae_u32 fc, bool write, int level) {
1438: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1439: return 0;
1440: } else {
1441: return mmu030_table_search(logical_addr, fc, write, level);
1442: }
1443: }
1444:
1445:
1446: /* Address Translation Cache
1447: *
1448: * The ATC uses a pseudo-least-recently-used algorithm to keep track of
1449: * least recently used entries. They are replaced if the cache is full.
1450: * An internal history-bit (MRU-bit) is used to identify these entries.
1451: * If an entry is accessed, its history-bit is set to 1. If after that
1452: * there are no more entries with zero-bits, all other history-bits are
1453: * set to 0. When no more invalid entries are in the ATC, the first entry
1454: * with a zero-bit is replaced.
1455: *
1456: *
1457: * Logical Portion (28 bit):
1458: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1459: * logical address (most significant 24 bit)
1460: *
1461: * oooo -xxx ---- ---- ---- ---- ---- ----
1462: * function code
1463: *
1464: * oooo x--- ---- ---- ---- ---- ---- ----
1465: * valid
1466: *
1467: *
1468: * Physical Portion (28 bit):
1469: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1470: * physical address
1471: *
1472: * oooo ---x ---- ---- ---- ---- ---- ----
1473: * modified
1474: *
1475: * oooo --x- ---- ---- ---- ---- ---- ----
1476: * write protect
1477: *
1478: * oooo -x-- ---- ---- ---- ---- ---- ----
1479: * cache inhibit
1480: *
1481: * oooo x--- ---- ---- ---- ---- ---- ----
1482: * bus error
1483: *
1484: */
1485:
1486: #define ATC030_MASK 0x0FFFFFFF
1487: #define ATC030_ADDR_MASK 0x00FFFFFF /* after masking shift 8 (<< 8) */
1488:
1489: #define ATC030_LOG_FC 0x07000000
1490: #define ATC030_LOG_V 0x08000000
1491:
1492: #define ATC030_PHYS_M 0x01000000
1493: #define ATC030_PHYS_WP 0x02000000
1494: #define ATC030_PHYS_CI 0x04000000
1495: #define ATC030_PHYS_BE 0x08000000
1496:
1497: void mmu030_page_fault(uaecptr addr, bool read) {
1498: write_log("MMU: page fault (logical addr = %08X)\n", addr);
1499: regs.mmu_fault_addr = addr;
1500: bBusErrorReadWrite = read;
1501: THROW(2);
1502: }
1503:
1504: void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l) {
1505: uae_u32 page_index = addr & mmu030.translation.page.mask;
1506: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1507:
1508: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1509: #if MMU030_ATC_DBG_MSG
1510: write_log("ATC match(%i): page addr = %08X, index = %08X (lput %08X)\n",
1511: l, physical_addr, page_index, val);
1512: #endif
1513: physical_addr += page_index;
1514:
1515: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1516: mmu030_page_fault(addr, 0);
1517: return;
1518: }
1519:
1520: phys_put_long(physical_addr, val);
1521: }
1522:
1523: void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l) {
1524: uae_u32 page_index = addr & mmu030.translation.page.mask;
1525: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1526:
1527: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1528: #if MMU030_ATC_DBG_MSG
1529: write_log("ATC match(%i): page addr = %08X, index = %08X (wput %04X)\n",
1530: l, physical_addr, page_index, val);
1531: #endif
1532: physical_addr += page_index;
1533:
1534: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1535: mmu030_page_fault(addr, 0);
1536: return;
1537: }
1538:
1539: phys_put_word(physical_addr, val);
1540: }
1541:
1542: void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l) {
1543: uae_u32 page_index = addr & mmu030.translation.page.mask;
1544: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1545:
1546: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1547: #if MMU030_ATC_DBG_MSG
1548: write_log("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n",
1549: l, physical_addr, page_index, val);
1550: #endif
1551: physical_addr += page_index;
1552:
1553: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1554: mmu030_page_fault(addr, 0);
1555: return;
1556: }
1557:
1558: phys_put_byte(physical_addr, val);
1559: }
1560:
1561: uae_u32 mmu030_get_long_atc(uaecptr addr, int l) {
1562: uae_u32 page_index = addr & mmu030.translation.page.mask;
1563: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1564:
1565: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1566: #if MMU030_ATC_DBG_MSG
1567: write_log("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n", l,
1568: physical_addr, page_index, phys_get_long(physical_addr+page_index));
1569: #endif
1570: physical_addr += page_index;
1571:
1572: if (mmu030.atc[l].physical.bus_error) {
1573: mmu030_page_fault(addr, 1);
1574: return 0;
1575: }
1576:
1577: return phys_get_long(physical_addr);
1578: }
1579:
1580: uae_u16 mmu030_get_word_atc(uaecptr addr, int l) {
1581: uae_u32 page_index = addr & mmu030.translation.page.mask;
1582: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1583:
1584: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1585: #if MMU030_ATC_DBG_MSG
1586: write_log("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n", l,
1587: physical_addr, page_index, phys_get_word(physical_addr+page_index));
1588: #endif
1589: physical_addr += page_index;
1590:
1591: if (mmu030.atc[l].physical.bus_error) {
1592: mmu030_page_fault(addr, 1);
1593: return 0;
1594: }
1595:
1596: return phys_get_word(physical_addr);
1597: }
1598:
1599: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l) {
1600: uae_u32 page_index = addr & mmu030.translation.page.mask;
1601: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1602:
1603: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1604: #if MMU030_ATC_DBG_MSG
1605: write_log("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n", l,
1606: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1607: #endif
1608: physical_addr += page_index;
1609:
1610: if (mmu030.atc[l].physical.bus_error) {
1611: mmu030_page_fault(addr, 1);
1612: return 0;
1613: }
1614:
1615: return phys_get_byte(physical_addr);
1616: }
1617:
1618:
1619: /* This function checks if a certain logical address is in the ATC
1620: * by comparing the logical address and function code to the values
1621: * stored in the ATC entries. If a matching entry is found it sets
1622: * the history bit and returns the cache index of the entry. */
1623: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1624: uaecptr physical_addr = 0;
1625: uaecptr logical_addr = 0;
1626: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1627: uae_u32 page_index = addr & mmu030.translation.page.mask;
1628:
1629: int i, j;
1630: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1631: logical_addr = mmu030.atc[i].logical.addr;
1632: /* If actual address matches address in ATC */
1633: if ((addr&addr_mask)==(logical_addr&addr_mask) &&
1634: (mmu030.atc[i].logical.fc==fc) &&
1635: mmu030.atc[i].logical.valid) {
1636: /* If M bit is set or access is read, return true
1637: * else invalidate entry */
1638: if (mmu030.atc[i].physical.modified || !write) {
1639: /* Maintain history bit */
1640: mmu030_atc_handle_history_bit(i);
1641: return i;
1642: } else {
1643: mmu030.atc[i].logical.valid = false;
1644: }
1645: }
1646: }
1647: return ATC030_NUM_ENTRIES;
1648: }
1649:
1650: void mmu030_atc_handle_history_bit(int entry_num) {
1651: int j;
1652: mmu030.atc[entry_num].mru = 1;
1653: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1654: if (!mmu030.atc[j].mru)
1655: break;
1656: }
1657: /* If there are no more zero-bits, reset all */
1658: if (j==ATC030_NUM_ENTRIES) {
1659: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1660: mmu030.atc[j].mru = 0;
1661: }
1662: mmu030.atc[entry_num].mru = 1;
1663: #if MMU030_ATC_DBG_MSG
1664: write_log("ATC: No more history zero-bits. Reset all.\n");
1665: #endif
1666: }
1667: }
1668:
1669:
1670: /* Memory access functions:
1671: * If the address matches one of the transparent translation registers
1672: * use it directly as physical address, else check ATC for the
1673: * logical address. If the logical address is not resident in the ATC
1674: * create a new ATC entry and then look up the physical address.
1675: */
1676:
1677: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc, int size) {
1678:
1679: // addr,super,write
1680: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1681: phys_put_long(addr,val);
1682: return;
1683: }
1684:
1685: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1686:
1687: if (atc_line_num<ATC030_NUM_ENTRIES) {
1688: mmu030_put_long_atc(addr, val, atc_line_num);
1689: } else {
1690: mmu030_table_search(addr,fc,true,0);
1691: mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1692: }
1693: }
1694:
1695: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc, int size) {
1696:
1697: // addr,super,write
1698: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1699: phys_put_word(addr,val);
1700: return;
1701: }
1702:
1703: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1704:
1705: if (atc_line_num<ATC030_NUM_ENTRIES) {
1706: mmu030_put_word_atc(addr, val, atc_line_num);
1707: } else {
1708: mmu030_table_search(addr, fc, true, 0);
1709: mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1710: }
1711: }
1712:
1713: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc, int size) {
1714:
1715: // addr,super,write
1716: if ((!mmu030.enabled) || (mmu030_match_ttr(addr, fc, true)&TT_OK_MATCH) || (fc==7)) {
1717: phys_put_byte(addr,val);
1718: return;
1719: }
1720:
1721: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1722:
1723: if (atc_line_num<ATC030_NUM_ENTRIES) {
1724: mmu030_put_byte_atc(addr, val, atc_line_num);
1725: } else {
1726: mmu030_table_search(addr, fc, true, 0);
1727: mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1728: }
1729: }
1730:
1731: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc, int size) {
1732:
1733: // addr,super,write
1734: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1735: return phys_get_long(addr);
1736: }
1737:
1738: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1739:
1740: if (atc_line_num<ATC030_NUM_ENTRIES) {
1741: return mmu030_get_long_atc(addr, atc_line_num);
1742: } else {
1743: mmu030_table_search(addr, fc, false, 0);
1744: return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1745: }
1746: }
1747:
1748: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc, int size) {
1749:
1750: // addr,super,write
1751: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1752: return phys_get_word(addr);
1753: }
1754:
1755: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1756:
1757: if (atc_line_num<ATC030_NUM_ENTRIES) {
1758: return mmu030_get_word_atc(addr, atc_line_num);
1759: } else {
1760: mmu030_table_search(addr, fc, false, 0);
1761: return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1762: }
1763: }
1764:
1765: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc, int size) {
1766:
1767: // addr,super,write
1768: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1769: return phys_get_byte(addr);
1770: }
1771:
1772: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1773:
1774: if (atc_line_num<ATC030_NUM_ENTRIES) {
1775: return mmu030_get_byte_atc(addr, atc_line_num);
1776: } else {
1777: mmu030_table_search(addr, fc, false, 0);
1778: return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1779: }
1780: }
1781:
1782:
1783: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc)
1784: {
1785: uae_u16 res;
1786:
1787: res = (uae_u16)mmu030_get_byte(addr, fc, sz_word) << 8;
1788: SAVE_EXCEPTION;
1789: TRY(prb) {
1790: res |= mmu030_get_byte(addr + 1, fc, sz_word);
1791: RESTORE_EXCEPTION;
1792: }
1793: CATCH(prb) {
1794: RESTORE_EXCEPTION;
1795: // regs.mmu_fault_addr = addr;
1796: regs.mmu_ssw |= MMU_SSW_MA;
1797: THROW_AGAIN(prb);
1798: } ENDTRY
1799: return res;
1800: }
1801:
1802: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc)
1803: {
1804: uae_u32 res;
1805:
1806: if (likely(!(addr & 1))) {
1807: res = (uae_u32)mmu030_get_word(addr, fc, sz_long) << 16;
1808: SAVE_EXCEPTION;
1809: TRY(prb) {
1810: res |= mmu030_get_word(addr + 2, fc, sz_long);
1811: RESTORE_EXCEPTION;
1812: }
1813: CATCH(prb) {
1814: RESTORE_EXCEPTION;
1815: // regs.mmu_fault_addr = addr;
1816: regs.mmu_ssw |= MMU_SSW_MA;
1817: THROW_AGAIN(prb);
1818: } ENDTRY
1819: } else {
1820: res = (uae_u32)mmu030_get_byte(addr, fc, sz_long) << 8;
1821: SAVE_EXCEPTION;
1822: TRY(prb) {
1823: res = (res | mmu030_get_byte(addr + 1, fc, sz_long)) << 8;
1824: res = (res | mmu030_get_byte(addr + 2, fc, sz_long)) << 8;
1825: res |= mmu030_get_byte(addr + 3, fc, sz_long);
1826: RESTORE_EXCEPTION;
1827: }
1828: CATCH(prb) {
1829: RESTORE_EXCEPTION;
1830: // regs.mmu_fault_addr = addr;
1831: regs.mmu_ssw |= MMU_SSW_MA;
1832: THROW_AGAIN(prb);
1833: } ENDTRY
1834: }
1835: return res;
1836: }
1837:
1838:
1839: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc)
1840: {
1841: SAVE_EXCEPTION;
1842: TRY(prb) {
1843: if (likely(!(addr & 1))) {
1844: mmu030_put_word(addr, val >> 16, fc, sz_long);
1845: mmu030_put_word(addr + 2, val, fc, sz_long);
1846: } else {
1847: mmu030_put_byte(addr, val >> 24, fc, sz_long);
1848: mmu030_put_byte(addr + 1, val >> 16, fc, sz_long);
1849: mmu030_put_byte(addr + 2, val >> 8, fc, sz_long);
1850: mmu030_put_byte(addr + 3, val, fc, sz_long);
1851: }
1852: RESTORE_EXCEPTION;
1853: }
1854: CATCH(prb) {
1855: RESTORE_EXCEPTION;
1856: regs.wb3_data = val;
1857: if (regs.mmu_fault_addr != addr) {
1858: // regs.mmu_fault_addr = addr;
1859: regs.mmu_ssw |= MMU_SSW_MA;
1860: }
1861: THROW_AGAIN(prb);
1862: } ENDTRY
1863: }
1864:
1865: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc)
1866: {
1867: SAVE_EXCEPTION;
1868: TRY(prb) {
1869: mmu030_put_byte(addr, val >> 8, fc, sz_word);
1870: mmu030_put_byte(addr + 1, val, fc, sz_word);
1871: RESTORE_EXCEPTION;
1872: }
1873: CATCH(prb) {
1874: RESTORE_EXCEPTION;
1875: regs.wb3_data = val;
1876: if (regs.mmu_fault_addr != addr) {
1877: // regs.mmu_fault_addr = addr;
1878: regs.mmu_ssw |= MMU_SSW_MA;
1879: }
1880: THROW_AGAIN(prb);
1881: } ENDTRY
1882: }
1883:
1884:
1885: /* MMU Reset */
1886: void mmu030_reset(int hardreset)
1887: {
1888: /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
1889: mmu030.enabled = false;
1890: tc_030 &= ~TC_ENABLE_TRANSLATION;
1891: tt0_030 &= ~TT_ENABLE;
1892: tt1_030 &= ~TT_ENABLE;
1893: if (hardreset) {
1894: srp_030 = crp_030 = 0;
1895: tt0_030 = tt1_030 = tc_030 = 0;
1896: mmusr_030 = 0;
1897: mmu030_flush_atc_all();
1898: }
1899: }
1900:
1901:
1902: void m68k_do_rte_mmu030 (uaecptr a7)
1903: {
1904: uae_u16 ssr = get_word_mmu030 (a7 + 8 + 4);
1905: if (ssr & MMU_SSW_CT) {
1906: uaecptr src_a7 = a7 + 8 - 8;
1907: uaecptr dst_a7 = a7 + 8 + 52;
1908: put_word_mmu030 (dst_a7 + 0, get_word_mmu030 (src_a7 + 0));
1909: put_long_mmu030 (dst_a7 + 2, get_long_mmu030 (src_a7 + 2));
1910: // skip this word
1911: put_long_mmu030 (dst_a7 + 8, get_long_mmu030 (src_a7 + 8));
1912: }
1913: }
1914:
1915: void flush_mmu030 (uaecptr addr, int n)
1916: {
1917: }
1918:
1919: void m68k_do_rts_mmu030 (void)
1920: {
1921: m68k_setpc (get_long_mmu030 (m68k_areg (regs, 7)));
1922: m68k_areg (regs, 7) += 4;
1923: }
1924:
1925: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
1926: {
1927: put_long_mmu030 (m68k_areg (regs, 7) - 4, oldpc);
1928: m68k_areg (regs, 7) -= 4;
1929: m68k_incpci (offset);
1930: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.