|
|
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:
1.1.1.2 ! root 490: /* TT comparison results */
1.1 root 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 ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1.1.1.2 ! root 965: * limit (only used with early termination page descriptor)
1.1 root 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:
1.1.1.2 ! root 1101: #if MMU030_REG_DBG_MSG
1.1 root 1102: write_log("Invalid descriptor!\n");
1.1.1.2 ! root 1103: #endif
1.1 root 1104: /* stop table walk */
1105: mmu030.status |= MMUSR_INVALID;
1106: goto stop_search;
1107: case DESCR_TYPE_EARLY_TERM:
1108: #if MMU030_REG_DBG_MSG
1109: write_log("Early termination page descriptor!\n");
1110: #endif
1111: early_termination = true;
1112: goto handle_page_descriptor;
1113: case DESCR_TYPE_VALID4:
1114: next_size = 4;
1115: break;
1116: case DESCR_TYPE_VALID8:
1117: next_size = 8;
1118: break;
1119: }
1120: }
1121:
1122:
1123: /* Upper level tables */
1124: do {
1125: if (descr_num) { /* if not root pointer */
1126: /* Set the updated bit */
1127: if (!level && !(descr[0]&DESCR_U) && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1128: descr[0] |= DESCR_U;
1129: phys_put_long(descr_addr[descr_num], descr[0]);
1130: }
1131: /* Update status bits */
1132: if (descr_size==8) {
1133: if (descr[0]&DESCR_S)
1134: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1135: }
1136: if (descr[0]&DESCR_WP) {
1137: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1138: write_protect = true;
1139: }
1140:
1141: /* Check if ptest level is reached */
1142: if (level && (level==descr_num)) {
1143: goto stop_search;
1144: }
1145: }
1146:
1147: addr_position = (descr_size==4) ? 0 : 1;
1148: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1149: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1150: #if MMU030_REG_DBG_MSG
1151: write_log("Table %c at %08X: index = %i, ",table_letter[t],table_addr,table_index);
1152: #endif // MMU030_REG_DBG_MSG
1153: t++; /* Proceed to the next table */
1154:
1155: /* Perform limit check */
1156: if (descr_size==8) {
1157: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1158: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1159: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1160: write_log("limit violation (lower limit %i)\n",limit);
1161: goto stop_search;
1162: }
1163: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1164: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1165: write_log("limit violation (upper limit %i)\n",limit);
1166: goto stop_search;
1167: }
1168: }
1169:
1170: /* Fetch next descriptor */
1171: descr_num++;
1172: descr_addr[descr_num] = table_addr+(table_index*next_size);
1173:
1174: if (next_size==4) {
1175: descr[0] = phys_get_long(descr_addr[descr_num]);
1176: #if MMU030_REG_DBG_MSG
1177: write_log("Next descriptor: %08X\n",descr[0]);
1178: #endif
1179: } else {
1180: descr[0] = phys_get_long(descr_addr[descr_num]);
1181: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1182: #if MMU030_REG_DBG_MSG
1183: write_log("Next descriptor: %08X%08X\n",descr[0],descr[1]);
1184: #endif
1185: }
1186:
1187: descr_size = next_size;
1188:
1189: /* Check descriptor type */
1190: descr_type = descr[0]&DESCR_TYPE_MASK;
1191: switch (descr_type) {
1192: case DESCR_TYPE_INVALID:
1.1.1.2 ! root 1193: #if MMU030_REG_DBG_MSG
1.1 root 1194: write_log("Invalid descriptor!\n");
1.1.1.2 ! root 1195: #endif
1.1 root 1196: /* stop table walk */
1197: mmu030.status |= MMUSR_INVALID;
1198: goto stop_search;
1199: case DESCR_TYPE_EARLY_TERM:
1200: /* go to last level table handling code */
1201: if (t<=mmu030.translation.last_table) {
1202: #if MMU030_REG_DBG_MSG
1203: write_log("Early termination page descriptor!\n");
1204: #endif
1205: early_termination = true;
1206: }
1207: goto handle_page_descriptor;
1208: case DESCR_TYPE_VALID4:
1209: next_size = 4;
1210: break;
1211: case DESCR_TYPE_VALID8:
1212: next_size = 8;
1213: break;
1214: }
1215: } while (t<=mmu030.translation.last_table);
1216:
1217:
1218: /* Handle indirect descriptor */
1219:
1220: /* Check if ptest level is reached */
1221: if (level && (level==descr_num)) {
1222: goto stop_search;
1223: }
1224:
1225: addr_position = (descr_size==4) ? 0 : 1;
1226: indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1227: write_log("Page indirect descriptor at %08X: ",indirect_addr);
1228:
1229: /* Fetch indirect descriptor */
1230: descr_num++;
1231: descr_addr[descr_num] = indirect_addr;
1232:
1233: if (next_size==4) {
1234: descr[0] = phys_get_long(descr_addr[descr_num]);
1235: write_log("descr = %08X\n",descr[0]);
1236: } else {
1237: descr[0] = phys_get_long(descr_addr[descr_num]);
1238: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1239: write_log("descr = %08X%08X",descr[0],descr[1]);
1240: }
1241:
1242: descr_size = next_size;
1243:
1244: /* Check descriptor type, only page descriptor is valid */
1245: descr_type = descr[0]&DESCR_TYPE_MASK;
1246: if (descr_type!=DESCR_TYPE_PAGE) {
1247: mmu030.status |= MMUSR_INVALID;
1248: goto stop_search;
1249: }
1250:
1251: handle_page_descriptor:
1252:
1253: if (descr_num) { /* if not root pointer */
1254: if (!level && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1255: /* set modified bit */
1256: if (!(descr[0]&DESCR_M) && write && !(mmu030.status&MMUSR_WRITE_PROTECTED)) {
1257: descr[0] |= DESCR_M;
1258: descr_modified = true;
1259: }
1260: /* set updated bit */
1261: if (!(descr[0]&DESCR_U)) {
1262: descr[0] |= DESCR_U;
1263: descr_modified = true;
1264: }
1.1.1.2 ! root 1265: /* write modified descriptor if necessary */
1.1 root 1266: if (descr_modified) {
1267: phys_put_long(descr_addr[descr_num], descr[0]);
1268: }
1269: }
1270:
1271: if ((descr_size==8) && (descr[0]&DESCR_S)) {
1272: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1273: }
1274:
1275: /* check if caching is inhibited */
1276: cache_inhibit = descr[0]&DESCR_CI ? true : false;
1277:
1278: /* check write protection */
1279: if (descr[0]&DESCR_WP) {
1280: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1281: write_protect = true;
1282: }
1283: /* TODO: check if this is handled at correct point (maybe before updating descr?) */
1284: mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
1285: }
1286:
1287: /* Check limit using next index field of logical address.
1288: * Limit is only checked on early termination. If we are
1289: * still at root pointer level, only check limit, if FCL
1290: * is disabled. */
1291: if (early_termination) {
1292: if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
1293: if (descr_size==8) {
1294: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1295: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1296: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1297: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1298: write_log("Limit violation (lower limit %i)\n",limit);
1299: goto stop_search;
1300: }
1301: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1302: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1303: write_log("Limit violation (upper limit %i)\n",limit);
1304: goto stop_search;
1305: }
1306: }
1307: }
1308: /* Get all unused bits of the logical address table index field.
1309: * they are added to the page address */
1310: /* TODO: They should be added via "signed addition". How to? */
1311: do {
1312: unused_fields_mask |= mmu030.translation.table[t].mask;
1313: t++;
1314: } while (t<=mmu030.translation.last_table);
1315: page_addr = addr&unused_fields_mask;
1316: #if MMU030_REG_DBG_MSG
1317: write_log("Logical address unused bits: %08X (mask = %08X)\n",
1318: page_addr,unused_fields_mask);
1319: #endif
1320: }
1321:
1322: /* Get page address */
1323: addr_position = (descr_size==4) ? 0 : 1;
1324: page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
1325: #if MMU030_REG_DBG_MSG
1326: write_log("Page at %08X\n",page_addr);
1327: #endif // MMU030_REG_DBG_MSG
1328:
1329: stop_search:
1330: ; /* Make compiler happy */
1331: } CATCH(prb) {
1.1.1.2 ! root 1332: /* We jump to this place, if a bus error occurred during table search.
1.1 root 1333: * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
1334: if (bBusErrorReadWrite) {
1335: descr_num--;
1336: }
1337: mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1338: write_log("MMU: Bus error while %s descriptor!\n",
1339: bBusErrorReadWrite?"reading":"writing");
1340: } ENDTRY
1341:
1342: regs.s = old_regs_s;
1343:
1344: /* check if we have to handle ptest */
1345: if (level) {
1346: if (mmu030.status&MMUSR_INVALID) {
1347: /* these bits are undefined, if the I bit is set: */
1348: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED|MMUSR_SUPER_VIOLATION);
1349: }
1350: mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
1351:
1352: /* If root pointer is page descriptor (descr_num 0), return 0 */
1353: return descr_num ? descr_addr[descr_num] : 0;
1354: }
1355:
1356: /* Find an ATC entry to replace */
1357: /* Search for invalid entry */
1358: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1359: if (!mmu030.atc[i].logical.valid) {
1360: break;
1361: }
1362: }
1363: /* If there are no invalid entries, replace first entry
1364: * with history bit not set */
1365: if (i == ATC030_NUM_ENTRIES) {
1366: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1367: if (!mmu030.atc[i].mru) {
1368: break;
1369: }
1370: }
1371: #if MMU030_ATC_DBG_MSG
1372: write_log("ATC is full. Replacing entry %i\n", i);
1373: #endif
1374: }
1375: mmu030_atc_handle_history_bit(i);
1376:
1377: /* Create ATC entry */
1378: mmu030.atc[i].logical.addr = addr & (~mmu030.translation.page.mask); /* delete page index bits */
1379: mmu030.atc[i].logical.fc = fc;
1380: mmu030.atc[i].logical.valid = true;
1381: mmu030.atc[i].physical.addr = page_addr & (~mmu030.translation.page.mask); /* delete page index bits */
1382: if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
1383: mmu030.atc[i].physical.bus_error = true;
1384: } else {
1385: mmu030.atc[i].physical.bus_error = false;
1386: }
1387: if (write && !(mmu030.status&MMUSR_SUPER_VIOLATION) && !(mmu030.status&MMUSR_LIMIT_VIOLATION)) {
1388: mmu030.atc[i].physical.modified = true;
1389: } else {
1390: mmu030.atc[i].physical.modified = false;
1391: }
1392: mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1393: mmu030.atc[i].physical.write_protect = write_protect;
1394:
1395: #if MMU030_ATC_DBG_MSG
1396: write_log("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n", i,
1397: mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
1398: mmu030.atc[i].logical.fc);
1399: write_log("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n", i,
1400: mmu030.atc[i].physical.bus_error?1:0,
1401: mmu030.atc[i].physical.cache_inhibit?1:0,
1402: mmu030.atc[i].physical.write_protect?1:0,
1403: mmu030.atc[i].physical.modified?1:0);
1404: #endif // MMU030_ATC_DBG_MSG
1405:
1406: return 0;
1407: }
1408:
1409: /* This function is used for PTEST level 0. */
1410: void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1411: int i;
1412: mmu030.status = 0;
1413:
1414: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1415: mmu030.status |= MMUSR_TRANSP_ACCESS;
1416: return;
1417: }
1418:
1419: for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
1420: if ((mmu030.atc[i].logical.fc == fc) &&
1421: (mmu030.atc[i].logical.addr == logical_addr) &&
1422: mmu030.atc[i].logical.valid) {
1423: break;
1424: }
1425: }
1426:
1427: if (i==ATC030_NUM_ENTRIES) {
1428: mmu030.status |= MMUSR_INVALID;
1429: return;
1430: }
1431:
1432: mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1433: mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
1434: mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
1435: if (mmu030.status&MMUSR_INVALID) {
1436: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED);
1437: }
1438: }
1439:
1440: /* This function is used for PTEST level 1 - 7. */
1441: uae_u32 mmu030_ptest_table_search(uaecptr logical_addr, uae_u32 fc, bool write, int level) {
1442: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1443: return 0;
1444: } else {
1445: return mmu030_table_search(logical_addr, fc, write, level);
1446: }
1447: }
1448:
1449:
1450: /* Address Translation Cache
1451: *
1452: * The ATC uses a pseudo-least-recently-used algorithm to keep track of
1453: * least recently used entries. They are replaced if the cache is full.
1454: * An internal history-bit (MRU-bit) is used to identify these entries.
1455: * If an entry is accessed, its history-bit is set to 1. If after that
1456: * there are no more entries with zero-bits, all other history-bits are
1457: * set to 0. When no more invalid entries are in the ATC, the first entry
1458: * with a zero-bit is replaced.
1459: *
1460: *
1461: * Logical Portion (28 bit):
1462: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1463: * logical address (most significant 24 bit)
1464: *
1465: * oooo -xxx ---- ---- ---- ---- ---- ----
1466: * function code
1467: *
1468: * oooo x--- ---- ---- ---- ---- ---- ----
1469: * valid
1470: *
1471: *
1472: * Physical Portion (28 bit):
1473: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1474: * physical address
1475: *
1476: * oooo ---x ---- ---- ---- ---- ---- ----
1477: * modified
1478: *
1479: * oooo --x- ---- ---- ---- ---- ---- ----
1480: * write protect
1481: *
1482: * oooo -x-- ---- ---- ---- ---- ---- ----
1483: * cache inhibit
1484: *
1485: * oooo x--- ---- ---- ---- ---- ---- ----
1486: * bus error
1487: *
1488: */
1489:
1490: #define ATC030_MASK 0x0FFFFFFF
1491: #define ATC030_ADDR_MASK 0x00FFFFFF /* after masking shift 8 (<< 8) */
1492:
1493: #define ATC030_LOG_FC 0x07000000
1494: #define ATC030_LOG_V 0x08000000
1495:
1496: #define ATC030_PHYS_M 0x01000000
1497: #define ATC030_PHYS_WP 0x02000000
1498: #define ATC030_PHYS_CI 0x04000000
1499: #define ATC030_PHYS_BE 0x08000000
1500:
1501: void mmu030_page_fault(uaecptr addr, bool read) {
1.1.1.2 ! root 1502: #if MMU030_ATC_DBG_MSG
1.1 root 1503: write_log("MMU: page fault (logical addr = %08X)\n", addr);
1.1.1.2 ! root 1504: #endif
1.1 root 1505: regs.mmu_fault_addr = addr;
1506: bBusErrorReadWrite = read;
1507: THROW(2);
1508: }
1509:
1510: void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l) {
1511: uae_u32 page_index = addr & mmu030.translation.page.mask;
1512: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1513:
1514: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1515: #if MMU030_ATC_DBG_MSG
1516: write_log("ATC match(%i): page addr = %08X, index = %08X (lput %08X)\n",
1517: l, physical_addr, page_index, val);
1518: #endif
1519: physical_addr += page_index;
1520:
1521: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1522: mmu030_page_fault(addr, 0);
1523: return;
1524: }
1525:
1526: phys_put_long(physical_addr, val);
1527: }
1528:
1529: void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l) {
1530: uae_u32 page_index = addr & mmu030.translation.page.mask;
1531: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1532:
1533: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1534: #if MMU030_ATC_DBG_MSG
1535: write_log("ATC match(%i): page addr = %08X, index = %08X (wput %04X)\n",
1536: l, physical_addr, page_index, val);
1537: #endif
1538: physical_addr += page_index;
1539:
1540: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1541: mmu030_page_fault(addr, 0);
1542: return;
1543: }
1544:
1545: phys_put_word(physical_addr, val);
1546: }
1547:
1548: void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l) {
1549: uae_u32 page_index = addr & mmu030.translation.page.mask;
1550: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1551:
1552: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1553: #if MMU030_ATC_DBG_MSG
1554: write_log("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n",
1555: l, physical_addr, page_index, val);
1556: #endif
1557: physical_addr += page_index;
1558:
1559: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1560: mmu030_page_fault(addr, 0);
1561: return;
1562: }
1563:
1564: phys_put_byte(physical_addr, val);
1565: }
1566:
1567: uae_u32 mmu030_get_long_atc(uaecptr addr, int l) {
1568: uae_u32 page_index = addr & mmu030.translation.page.mask;
1569: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1570:
1571: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1572: #if MMU030_ATC_DBG_MSG
1573: write_log("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n", l,
1574: physical_addr, page_index, phys_get_long(physical_addr+page_index));
1575: #endif
1576: physical_addr += page_index;
1577:
1578: if (mmu030.atc[l].physical.bus_error) {
1579: mmu030_page_fault(addr, 1);
1580: return 0;
1581: }
1582:
1583: return phys_get_long(physical_addr);
1584: }
1585:
1586: uae_u16 mmu030_get_word_atc(uaecptr addr, int l) {
1587: uae_u32 page_index = addr & mmu030.translation.page.mask;
1588: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1589:
1590: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1591: #if MMU030_ATC_DBG_MSG
1592: write_log("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n", l,
1593: physical_addr, page_index, phys_get_word(physical_addr+page_index));
1594: #endif
1595: physical_addr += page_index;
1596:
1597: if (mmu030.atc[l].physical.bus_error) {
1598: mmu030_page_fault(addr, 1);
1599: return 0;
1600: }
1601:
1602: return phys_get_word(physical_addr);
1603: }
1604:
1605: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l) {
1606: uae_u32 page_index = addr & mmu030.translation.page.mask;
1607: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1608:
1609: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1610: #if MMU030_ATC_DBG_MSG
1611: write_log("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n", l,
1612: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1613: #endif
1614: physical_addr += page_index;
1615:
1616: if (mmu030.atc[l].physical.bus_error) {
1617: mmu030_page_fault(addr, 1);
1618: return 0;
1619: }
1620:
1621: return phys_get_byte(physical_addr);
1622: }
1623:
1624:
1625: /* This function checks if a certain logical address is in the ATC
1626: * by comparing the logical address and function code to the values
1627: * stored in the ATC entries. If a matching entry is found it sets
1628: * the history bit and returns the cache index of the entry. */
1629: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1630: uaecptr physical_addr = 0;
1631: uaecptr logical_addr = 0;
1632: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1633: uae_u32 page_index = addr & mmu030.translation.page.mask;
1634:
1635: int i, j;
1636: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1637: logical_addr = mmu030.atc[i].logical.addr;
1638: /* If actual address matches address in ATC */
1639: if ((addr&addr_mask)==(logical_addr&addr_mask) &&
1640: (mmu030.atc[i].logical.fc==fc) &&
1641: mmu030.atc[i].logical.valid) {
1642: /* If M bit is set or access is read, return true
1643: * else invalidate entry */
1644: if (mmu030.atc[i].physical.modified || !write) {
1645: /* Maintain history bit */
1646: mmu030_atc_handle_history_bit(i);
1647: return i;
1648: } else {
1649: mmu030.atc[i].logical.valid = false;
1650: }
1651: }
1652: }
1653: return ATC030_NUM_ENTRIES;
1654: }
1655:
1656: void mmu030_atc_handle_history_bit(int entry_num) {
1657: int j;
1658: mmu030.atc[entry_num].mru = 1;
1659: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1660: if (!mmu030.atc[j].mru)
1661: break;
1662: }
1663: /* If there are no more zero-bits, reset all */
1664: if (j==ATC030_NUM_ENTRIES) {
1665: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1666: mmu030.atc[j].mru = 0;
1667: }
1668: mmu030.atc[entry_num].mru = 1;
1669: #if MMU030_ATC_DBG_MSG
1670: write_log("ATC: No more history zero-bits. Reset all.\n");
1671: #endif
1672: }
1673: }
1674:
1675:
1676: /* Memory access functions:
1677: * If the address matches one of the transparent translation registers
1678: * use it directly as physical address, else check ATC for the
1679: * logical address. If the logical address is not resident in the ATC
1680: * create a new ATC entry and then look up the physical address.
1681: */
1682:
1683: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc, int size) {
1684:
1685: // addr,super,write
1686: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1687: phys_put_long(addr,val);
1688: return;
1689: }
1690:
1691: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1692:
1693: if (atc_line_num<ATC030_NUM_ENTRIES) {
1694: mmu030_put_long_atc(addr, val, atc_line_num);
1695: } else {
1696: mmu030_table_search(addr,fc,true,0);
1697: mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1698: }
1699: }
1700:
1701: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc, int size) {
1702:
1703: // addr,super,write
1704: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1705: phys_put_word(addr,val);
1706: return;
1707: }
1708:
1709: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1710:
1711: if (atc_line_num<ATC030_NUM_ENTRIES) {
1712: mmu030_put_word_atc(addr, val, atc_line_num);
1713: } else {
1714: mmu030_table_search(addr, fc, true, 0);
1715: mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1716: }
1717: }
1718:
1719: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc, int size) {
1720:
1721: // addr,super,write
1722: if ((!mmu030.enabled) || (mmu030_match_ttr(addr, fc, true)&TT_OK_MATCH) || (fc==7)) {
1723: phys_put_byte(addr,val);
1724: return;
1725: }
1726:
1727: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1728:
1729: if (atc_line_num<ATC030_NUM_ENTRIES) {
1730: mmu030_put_byte_atc(addr, val, atc_line_num);
1731: } else {
1732: mmu030_table_search(addr, fc, true, 0);
1733: mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1734: }
1735: }
1736:
1737: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc, int size) {
1738:
1739: // addr,super,write
1740: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1741: return phys_get_long(addr);
1742: }
1743:
1744: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1745:
1746: if (atc_line_num<ATC030_NUM_ENTRIES) {
1747: return mmu030_get_long_atc(addr, atc_line_num);
1748: } else {
1749: mmu030_table_search(addr, fc, false, 0);
1750: return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1751: }
1752: }
1753:
1754: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc, int size) {
1755:
1756: // addr,super,write
1757: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1758: return phys_get_word(addr);
1759: }
1760:
1761: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1762:
1763: if (atc_line_num<ATC030_NUM_ENTRIES) {
1764: return mmu030_get_word_atc(addr, atc_line_num);
1765: } else {
1766: mmu030_table_search(addr, fc, false, 0);
1767: return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1768: }
1769: }
1770:
1771: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc, int size) {
1772:
1773: // addr,super,write
1774: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1775: return phys_get_byte(addr);
1776: }
1777:
1778: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1779:
1780: if (atc_line_num<ATC030_NUM_ENTRIES) {
1781: return mmu030_get_byte_atc(addr, atc_line_num);
1782: } else {
1783: mmu030_table_search(addr, fc, false, 0);
1784: return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1785: }
1786: }
1787:
1788:
1789: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc)
1790: {
1791: uae_u16 res;
1792:
1793: res = (uae_u16)mmu030_get_byte(addr, fc, sz_word) << 8;
1794: SAVE_EXCEPTION;
1795: TRY(prb) {
1796: res |= mmu030_get_byte(addr + 1, fc, sz_word);
1797: RESTORE_EXCEPTION;
1798: }
1799: CATCH(prb) {
1800: RESTORE_EXCEPTION;
1801: // regs.mmu_fault_addr = addr;
1802: regs.mmu_ssw |= MMU_SSW_MA;
1803: THROW_AGAIN(prb);
1804: } ENDTRY
1805: return res;
1806: }
1807:
1808: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc)
1809: {
1810: uae_u32 res;
1811:
1812: if (likely(!(addr & 1))) {
1813: res = (uae_u32)mmu030_get_word(addr, fc, sz_long) << 16;
1814: SAVE_EXCEPTION;
1815: TRY(prb) {
1816: res |= mmu030_get_word(addr + 2, fc, sz_long);
1817: RESTORE_EXCEPTION;
1818: }
1819: CATCH(prb) {
1820: RESTORE_EXCEPTION;
1821: // regs.mmu_fault_addr = addr;
1822: regs.mmu_ssw |= MMU_SSW_MA;
1823: THROW_AGAIN(prb);
1824: } ENDTRY
1825: } else {
1826: res = (uae_u32)mmu030_get_byte(addr, fc, sz_long) << 8;
1827: SAVE_EXCEPTION;
1828: TRY(prb) {
1829: res = (res | mmu030_get_byte(addr + 1, fc, sz_long)) << 8;
1830: res = (res | mmu030_get_byte(addr + 2, fc, sz_long)) << 8;
1831: res |= mmu030_get_byte(addr + 3, fc, sz_long);
1832: RESTORE_EXCEPTION;
1833: }
1834: CATCH(prb) {
1835: RESTORE_EXCEPTION;
1836: // regs.mmu_fault_addr = addr;
1837: regs.mmu_ssw |= MMU_SSW_MA;
1838: THROW_AGAIN(prb);
1839: } ENDTRY
1840: }
1841: return res;
1842: }
1843:
1844:
1845: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc)
1846: {
1847: SAVE_EXCEPTION;
1848: TRY(prb) {
1849: if (likely(!(addr & 1))) {
1850: mmu030_put_word(addr, val >> 16, fc, sz_long);
1851: mmu030_put_word(addr + 2, val, fc, sz_long);
1852: } else {
1853: mmu030_put_byte(addr, val >> 24, fc, sz_long);
1854: mmu030_put_byte(addr + 1, val >> 16, fc, sz_long);
1855: mmu030_put_byte(addr + 2, val >> 8, fc, sz_long);
1856: mmu030_put_byte(addr + 3, val, fc, sz_long);
1857: }
1858: RESTORE_EXCEPTION;
1859: }
1860: CATCH(prb) {
1861: RESTORE_EXCEPTION;
1862: regs.wb3_data = val;
1863: if (regs.mmu_fault_addr != addr) {
1864: // regs.mmu_fault_addr = addr;
1865: regs.mmu_ssw |= MMU_SSW_MA;
1866: }
1867: THROW_AGAIN(prb);
1868: } ENDTRY
1869: }
1870:
1871: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc)
1872: {
1873: SAVE_EXCEPTION;
1874: TRY(prb) {
1875: mmu030_put_byte(addr, val >> 8, fc, sz_word);
1876: mmu030_put_byte(addr + 1, val, fc, sz_word);
1877: RESTORE_EXCEPTION;
1878: }
1879: CATCH(prb) {
1880: RESTORE_EXCEPTION;
1881: regs.wb3_data = val;
1882: if (regs.mmu_fault_addr != addr) {
1883: // regs.mmu_fault_addr = addr;
1884: regs.mmu_ssw |= MMU_SSW_MA;
1885: }
1886: THROW_AGAIN(prb);
1887: } ENDTRY
1888: }
1889:
1890:
1891: /* MMU Reset */
1892: void mmu030_reset(int hardreset)
1893: {
1894: /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
1895: mmu030.enabled = false;
1896: tc_030 &= ~TC_ENABLE_TRANSLATION;
1897: tt0_030 &= ~TT_ENABLE;
1898: tt1_030 &= ~TT_ENABLE;
1899: if (hardreset) {
1900: srp_030 = crp_030 = 0;
1901: tt0_030 = tt1_030 = tc_030 = 0;
1902: mmusr_030 = 0;
1903: mmu030_flush_atc_all();
1904: }
1905: }
1906:
1907:
1908: void m68k_do_rte_mmu030 (uaecptr a7)
1909: {
1910: uae_u16 ssr = get_word_mmu030 (a7 + 8 + 4);
1911: if (ssr & MMU_SSW_CT) {
1912: uaecptr src_a7 = a7 + 8 - 8;
1913: uaecptr dst_a7 = a7 + 8 + 52;
1914: put_word_mmu030 (dst_a7 + 0, get_word_mmu030 (src_a7 + 0));
1915: put_long_mmu030 (dst_a7 + 2, get_long_mmu030 (src_a7 + 2));
1916: // skip this word
1917: put_long_mmu030 (dst_a7 + 8, get_long_mmu030 (src_a7 + 8));
1918: }
1919: }
1920:
1921: void flush_mmu030 (uaecptr addr, int n)
1922: {
1923: }
1924:
1925: void m68k_do_rts_mmu030 (void)
1926: {
1927: m68k_setpc (get_long_mmu030 (m68k_areg (regs, 7)));
1928: m68k_areg (regs, 7) += 4;
1929: }
1930:
1931: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
1932: {
1933: put_long_mmu030 (m68k_areg (regs, 7) - 4, oldpc);
1934: m68k_areg (regs, 7) -= 4;
1935: m68k_incpci (offset);
1936: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.