|
|
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: * - Check if read-modify-write operations are correctly detected for
21: * handling transparent access (see TT matching functions)
22: * - If possible, test mmu030_table_search with all kinds of translations
23: * (early termination, invalid descriptors, bus errors, indirect
24: * descriptors, PTEST in different levels, etc).
1.1.1.2 root 25: * - Check which bits of an ATC entry or the status register should be set
26: * and which should be un-set, if an invalid translation occurs.
1.1 root 27: * - Handle cache inhibit bit when accessing ATC entries
28: */
29:
30:
31: #include "sysconfig.h"
32: #include "sysdeps.h"
33:
1.1.1.3 ! root 34: #include "main.h"
! 35: #include "hatari-glue.h"
! 36: #include "host.h"
! 37:
1.1 root 38: #include "options_cpu.h"
39: #include "memory.h"
40: #include "newcpu.h"
41: #include "cpummu030.h"
42:
1.1.1.2 root 43: #define MMU030_OP_DBG_MSG 0
44: #define MMU030_ATC_DBG_MSG 0
45: #define MMU030_REG_DBG_MSG 0
1.1 root 46:
1.1.1.2 root 47: #define TT_FC_MASK 0x00000007
48: #define TT_FC_BASE 0x00000070
49: #define TT_RWM 0x00000100
50: #define TT_RW 0x00000200
51: #define TT_CI 0x00000400
52: #define TT_ENABLE 0x00008000
1.1 root 53:
1.1.1.2 root 54: #define TT_ADDR_MASK 0x00FF0000
55: #define TT_ADDR_BASE 0xFF000000
1.1 root 56:
1.1.1.2 root 57: static int bBusErrorReadWrite;
58: static int atcindextable[32];
59: static int tt_enabled;
60:
61: int mmu030_idx;
62:
63: uae_u32 mm030_stageb_address;
64: bool mmu030_retry;
65: int mmu030_opcode;
66: int mmu030_opcode_stageb;
1.1.1.3 ! root 67:
! 68: int mmu030_fake_prefetch;
! 69: uaecptr mmu030_fake_prefetch_addr;
! 70:
1.1.1.2 root 71: uae_u16 mmu030_state[3];
72: uae_u32 mmu030_data_buffer;
73: uae_u32 mmu030_disp_store[2];
74: uae_u32 mmu030_fmovem_store[2];
75: struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS];
76:
77: /* for debugging messages */
78: char table_letter[4] = {'A','B','C','D'};
79:
80: uae_u64 srp_030, crp_030;
81: uae_u32 tt0_030, tt1_030, tc_030;
82: uae_u16 mmusr_030;
1.1 root 83:
1.1.1.2 root 84: /* ATC struct */
1.1 root 85: #define ATC030_NUM_ENTRIES 22
86:
87: typedef struct {
88: struct {
89: uaecptr addr;
90: bool modified;
91: bool write_protect;
92: bool cache_inhibit;
93: bool bus_error;
94: } physical;
95:
96: struct {
97: uaecptr addr;
98: uae_u32 fc;
99: bool valid;
100: } logical;
101: /* history bit */
102: int mru;
103: } MMU030_ATC_LINE;
104:
105:
106: /* MMU struct for 68030 */
1.1.1.3 ! root 107: static struct {
1.1 root 108:
1.1.1.2 root 109: /* Translation tables */
1.1 root 110: struct {
111: struct {
112: uae_u32 mask;
113: uae_u8 shift;
114: } table[4];
115:
116: struct {
117: uae_u32 mask;
1.1.1.2 root 118: uae_u32 imask;
1.1 root 119: uae_u8 size;
120: } page;
121:
122: uae_u8 init_shift;
123: uae_u8 last_table;
124: } translation;
125:
126: /* Transparent translation */
127: struct {
128: TT_info tt0;
129: TT_info tt1;
130: } transparent;
131:
132: /* Address translation cache */
133: MMU030_ATC_LINE atc[ATC030_NUM_ENTRIES];
134:
1.1.1.2 root 135: /* Condition */
1.1 root 136: bool enabled;
137: uae_u16 status;
138: } mmu030;
139:
140:
141:
142: /* MMU Status Register
143: *
144: * ---x ---x x-xx x---
145: * reserved (all 0)
146: *
147: * x--- ---- ---- ----
148: * bus error
149: *
150: * -x-- ---- ---- ----
151: * limit violation
152: *
153: * --x- ---- ---- ----
154: * supervisor only
155: *
156: * ---- x--- ---- ----
157: * write protected
158: *
159: * ---- -x-- ---- ----
160: * invalid
161: *
162: * ---- --x- ---- ----
163: * modified
164: *
165: * ---- ---- -x-- ----
166: * transparent access
167: *
168: * ---- ---- ---- -xxx
169: * number of levels (number of tables accessed during search)
170: *
171: */
172:
173: #define MMUSR_BUS_ERROR 0x8000
174: #define MMUSR_LIMIT_VIOLATION 0x4000
175: #define MMUSR_SUPER_VIOLATION 0x2000
176: #define MMUSR_WRITE_PROTECTED 0x0800
177: #define MMUSR_INVALID 0x0400
178: #define MMUSR_MODIFIED 0x0200
179: #define MMUSR_TRANSP_ACCESS 0x0040
180: #define MMUSR_NUM_LEVELS_MASK 0x0007
181:
182:
183:
184: /* -- MMU instructions -- */
185:
1.1.1.3 ! root 186: static bool mmu_op30_invea(uae_u32 opcode)
! 187: {
! 188: int eamode = (opcode >> 3) & 7;
! 189: int rreg = opcode & 7;
! 190:
! 191: // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
! 192: if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || eamode == 6 || (eamode == 7 && rreg > 1))
! 193: return true;
! 194: return false;
! 195: }
! 196:
! 197: bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1 root 198: {
199: int preg = (next >> 10) & 31;
200: int rw = (next >> 9) & 1;
201: int fd = (next >> 8) & 1;
1.1.1.3 ! root 202: int unused = (next & 0xff);
! 203:
! 204: if (mmu_op30_invea(opcode))
! 205: return true;
! 206: // unused low 8 bits must be zeroed
! 207: if (unused)
! 208: return true;
! 209: // read and fd set?
! 210: if (rw && fd)
! 211: return true;
1.1.1.2 root 212:
213: #if MMU030_OP_DBG_MSG
214: switch (preg) {
215: case 0x10:
216: write_log(_T("PMOVE: %s TC %08X\n"), rw?"read":"write",
217: rw?tc_030:x_get_long(extra));
218: break;
219: case 0x12:
220: write_log(_T("PMOVE: %s SRP %08X%08X\n"), rw?"read":"write",
221: rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra),
222: rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4));
223: break;
224: case 0x13:
225: write_log(_T("PMOVE: %s CRP %08X%08X\n"), rw?"read":"write",
226: rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra),
227: rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4));
228: break;
229: case 0x18:
230: write_log(_T("PMOVE: %s MMUSR %04X\n"), rw?"read":"write",
231: rw?mmusr_030:x_get_word(extra));
232: break;
233: case 0x02:
234: write_log(_T("PMOVE: %s TT0 %08X\n"), rw?"read":"write",
235: rw?tt0_030:x_get_long(extra));
236: break;
237: case 0x03:
238: write_log(_T("PMOVE: %s TT1 %08X\n"), rw?"read":"write",
239: rw?tt1_030:x_get_long(extra));
240: break;
241: default:
242: break;
243: }
244: if (!fd && !rw && !(preg==0x18)) {
245: write_log(_T("PMOVE: flush ATC\n"));
246: }
247: #endif
248:
1.1 root 249: switch (preg)
250: {
251: case 0x10: // TC
1.1.1.2 root 252: if (rw)
1.1 root 253: x_put_long (extra, tc_030);
1.1.1.2 root 254: else {
1.1 root 255: tc_030 = x_get_long (extra);
1.1.1.3 ! root 256: if (mmu030_decode_tc(tc_030))
! 257: return true;
1.1 root 258: }
259: break;
260: case 0x12: // SRP
261: if (rw) {
262: x_put_long (extra, srp_030 >> 32);
263: x_put_long (extra + 4, srp_030);
264: } else {
265: srp_030 = (uae_u64)x_get_long (extra) << 32;
266: srp_030 |= x_get_long (extra + 4);
1.1.1.3 ! root 267: host_darkmatter(srp_030 == crp_030);
! 268: if (mmu030_decode_rp(srp_030))
! 269: return true;
1.1 root 270: }
271: break;
272: case 0x13: // CRP
273: if (rw) {
274: x_put_long (extra, crp_030 >> 32);
275: x_put_long (extra + 4, crp_030);
276: } else {
277: crp_030 = (uae_u64)x_get_long (extra) << 32;
278: crp_030 |= x_get_long (extra + 4);
1.1.1.3 ! root 279: if (mmu030_decode_rp(crp_030))
! 280: return true;
1.1 root 281: }
282: break;
283: case 0x18: // MMUSR
1.1.1.3 ! root 284: if (fd) {
! 285: // FD must be always zero when MMUSR read or write
! 286: return true;
! 287: }
1.1.1.2 root 288: if (rw)
1.1 root 289: x_put_word (extra, mmusr_030);
1.1.1.2 root 290: else
1.1 root 291: mmusr_030 = x_get_word (extra);
292: break;
293: case 0x02: // TT0
1.1.1.2 root 294: if (rw)
1.1 root 295: x_put_long (extra, tt0_030);
1.1.1.2 root 296: else {
1.1 root 297: tt0_030 = x_get_long (extra);
298: mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
299: }
300: break;
301: case 0x03: // TT1
1.1.1.2 root 302: if (rw)
1.1 root 303: x_put_long (extra, tt1_030);
1.1.1.2 root 304: else {
1.1 root 305: tt1_030 = x_get_long (extra);
306: mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
307: }
308: break;
309: default:
1.1.1.2 root 310: write_log (_T("Bad PMOVE at %08x\n"),m68k_getpc());
1.1.1.3 ! root 311: return true;
1.1.1.2 root 312: }
1.1 root 313:
1.1.1.3 ! root 314: if (!fd && !rw && preg != 0x18) {
1.1 root 315: mmu030_flush_atc_all();
316: }
1.1.1.2 root 317: tt_enabled = (tt0_030 & TT_ENABLE) || (tt1_030 & TT_ENABLE);
1.1.1.3 ! root 318: return false;
1.1 root 319: }
320:
1.1.1.3 ! root 321: bool mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1 root 322: {
323: mmu030.status = mmusr_030 = 0;
324:
325: int level = (next&0x1C00)>>10;
326: int rw = (next >> 9) & 1;
327: int a = (next >> 8) & 1;
328: int areg = (next&0xE0)>>5;
329: uae_u32 fc = mmu_op30_helper_get_fc(next);
330:
331: bool write = rw ? false : true;
332:
333: uae_u32 ret = 0;
334:
1.1.1.3 ! root 335: if (mmu_op30_invea(opcode))
! 336: return true;
! 337:
! 338: if (!level && a) {
1.1.1.2 root 339: write_log(_T("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n"));
1.1.1.3 ! root 340: return true;
1.1 root 341: }
342:
1.1.1.2 root 343: #if MMU030_OP_DBG_MSG
344: write_log(_T("PTEST%c: addr = %08X, fc = %i, level = %i, "),
1.1 root 345: rw?'R':'W', extra, fc, level);
346: if (a) {
1.1.1.2 root 347: write_log(_T("return descriptor to register A%i\n"), areg);
1.1 root 348: } else {
1.1.1.2 root 349: write_log(_T("do not return descriptor\n"));
1.1 root 350: }
1.1.1.2 root 351: #endif
1.1 root 352:
353: if (!level) {
354: mmu030_ptest_atc_search(extra, fc, write);
355: } else {
356: ret = mmu030_ptest_table_search(extra, fc, write, level);
357: if (a) {
358: m68k_areg (regs, areg) = ret;
359: }
360: }
361: mmusr_030 = mmu030.status;
362:
1.1.1.2 root 363: #if MMU030_OP_DBG_MSG
364: write_log(_T("PTEST status: %04X, B = %i, L = %i, S = %i, W = %i, I = %i, M = %i, T = %i, N = %i\n"),
1.1 root 365: mmusr_030, (mmusr_030&MMUSR_BUS_ERROR)?1:0, (mmusr_030&MMUSR_LIMIT_VIOLATION)?1:0,
366: (mmusr_030&MMUSR_SUPER_VIOLATION)?1:0, (mmusr_030&MMUSR_WRITE_PROTECTED)?1:0,
367: (mmusr_030&MMUSR_INVALID)?1:0, (mmusr_030&MMUSR_MODIFIED)?1:0,
368: (mmusr_030&MMUSR_TRANSP_ACCESS)?1:0, mmusr_030&MMUSR_NUM_LEVELS_MASK);
1.1.1.2 root 369: #endif
1.1.1.3 ! root 370: return false;
1.1 root 371: }
372:
1.1.1.3 ! root 373: bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1 root 374: {
375: int rw = (next >> 9) & 1;
1.1.1.3 ! root 376: int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
1.1 root 377: uae_u32 fc = mmu_op30_helper_get_fc(next);
378: bool write = rw ? false : true;
1.1.1.3 ! root 379:
! 380: if (mmu_op30_invea(opcode))
! 381: return true;
! 382: if (unused)
! 383: return true;
! 384:
1.1.1.2 root 385: #if 0
386: write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
387: #endif
1.1 root 388:
389: mmu030_flush_atc_page(extra);
390: mmu030_table_search(extra, fc, write, 0);
1.1.1.3 ! root 391: return false;
1.1 root 392: }
393:
1.1.1.3 ! root 394: bool mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1 root 395: {
1.1.1.3 ! root 396: uae_u16 mode = (next >> 10) & 0x7;
! 397: uae_u32 fc_mask = (next >> 5) & 0x7;
1.1 root 398: uae_u32 fc_base = mmu_op30_helper_get_fc(next);
1.1.1.3 ! root 399: uae_u32 fc_bits = next & 0x1f;
1.1.1.2 root 400:
401: #if 0
402: switch (mode) {
403: case 0x1:
404: write_log(_T("PFLUSH: Flush all entries\n"));
405: break;
406: case 0x4:
407: write_log(_T("PFLUSH: Flush by function code only\n"));
408: write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
409: break;
410: case 0x6:
411: write_log(_T("PFLUSH: Flush by function code and effective address\n"));
412: write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
413: write_log(_T("PFLUSH: effective address = %08X\n"), extra);
414: break;
415: default:
416: break;
417: }
418: #endif
419:
1.1 root 420: switch (mode) {
421: case 0x1:
1.1.1.3 ! root 422: if (fc_bits)
! 423: return true;
1.1 root 424: mmu030_flush_atc_all();
425: break;
426: case 0x4:
427: mmu030_flush_atc_fc(fc_base, fc_mask);
428: break;
429: case 0x6:
1.1.1.3 ! root 430: if (mmu_op30_invea(opcode))
! 431: return true;
1.1 root 432: mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
433: break;
434:
435: default:
1.1.1.2 root 436: write_log(_T("PFLUSH ERROR: bad mode! (%i)\n"),mode);
1.1.1.3 ! root 437: return true;
1.1 root 438: }
1.1.1.3 ! root 439: return false;
1.1 root 440: }
441:
442: /* -- Helper function for MMU instructions -- */
443: uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
444: switch (next&0x0018) {
445: case 0x0010:
446: return (next&0x7);
447: case 0x0008:
448: return (m68k_dreg(regs, next&0x7)&0x7);
449: case 0x0000:
450: if (next&1) {
1.1.1.2 root 451: return (regs.dfc);
1.1 root 452: } else {
1.1.1.2 root 453: return (regs.sfc);
1.1 root 454: }
455: default:
1.1.1.2 root 456: write_log(_T("MMU_OP30 ERROR: bad fc source! (%04X)\n"),next&0x0018);
1.1 root 457: return 0;
458: }
459: }
460:
461:
462: /* -- ATC flushing functions -- */
463:
464: /* This function flushes ATC entries depending on their function code */
465: void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
466: int i;
467: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
468: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
469: mmu030.atc[i].logical.valid) {
470: mmu030.atc[i].logical.valid = false;
1.1.1.2 root 471: #if MMU030_OP_DBG_MSG
472: write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
473: #endif
474: }
1.1 root 475: }
476: }
477:
478: /* This function flushes ATC entries depending on their logical address
479: * and their function code */
480: void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
481: int i;
1.1.1.2 root 482: logical_addr &= mmu030.translation.page.imask;
1.1 root 483: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
484: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
1.1.1.2 root 485: (mmu030.atc[i].logical.addr == logical_addr) &&
1.1 root 486: mmu030.atc[i].logical.valid) {
487: mmu030.atc[i].logical.valid = false;
1.1.1.2 root 488: #if MMU030_OP_DBG_MSG
489: write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
490: #endif
491: }
1.1 root 492: }
493: }
494:
495: /* This function flushes ATC entries depending on their logical address */
496: void mmu030_flush_atc_page(uaecptr logical_addr) {
497: int i;
1.1.1.2 root 498: logical_addr &= mmu030.translation.page.imask;
1.1 root 499: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1.1.1.2 root 500: if ((mmu030.atc[i].logical.addr == logical_addr) &&
1.1 root 501: mmu030.atc[i].logical.valid) {
502: mmu030.atc[i].logical.valid = false;
1.1.1.2 root 503: #if MMU030_OP_DBG_MSG
504: write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
505: #endif
506: }
1.1 root 507: }
508: }
509:
510: /* This function flushes all ATC entries */
511: void mmu030_flush_atc_all(void) {
1.1.1.2 root 512: #if MMU030_OP_DBG_MSG
513: write_log(_T("ATC: Flushing all entries\n"));
514: #endif
515: int i;
1.1 root 516: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
517: mmu030.atc[i].logical.valid = false;
518: }
519: }
520:
521:
522: /* Transparent Translation Registers (TT0 and TT1)
523: *
524: * ---- ---- ---- ---- -xxx x--- x--- x---
525: * reserved, must be 0
526: *
527: * ---- ---- ---- ---- ---- ---- ---- -xxx
528: * function code mask (FC bits to be ignored)
529: *
530: * ---- ---- ---- ---- ---- ---- -xxx ----
531: * function code base (FC value for transparent block)
532: *
533: * ---- ---- ---- ---- ---- ---x ---- ----
534: * 0 = r/w field used, 1 = read and write is transparently translated
535: *
536: * ---- ---- ---- ---- ---- --x- ---- ----
537: * r/w field: 0 = write ..., 1 = read access transparent
538: *
539: * ---- ---- ---- ---- ---- -x-- ---- ----
540: * cache inhibit: 0 = caching allowed, 1 = caching inhibited
541: *
542: * ---- ---- ---- ---- x--- ---- ---- ----
543: * 0 = transparent translation enabled disabled, 1 = enabled
544: *
545: * ---- ---- xxxx xxxx ---- ---- ---- ----
546: * logical address mask
547: *
548: * xxxx xxxx ---- ---- ---- ---- ---- ----
549: * logical address base
550: *
551: */
552:
553: /* TT comparision results */
554: #define TT_NO_MATCH 0x1
555: #define TT_OK_MATCH 0x2
556: #define TT_NO_READ 0x4
557: #define TT_NO_WRITE 0x8
558:
559: TT_info mmu030_decode_tt(uae_u32 TT) {
560:
561: TT_info ret;
562:
563: ret.fc_mask = ~((TT&TT_FC_MASK)|0xFFFFFFF8);
564: ret.fc_base = (TT&TT_FC_BASE)>>4;
565: ret.addr_base = TT & TT_ADDR_BASE;
566: ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
567:
1.1.1.2 root 568: #if 0
1.1 root 569: if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
1.1.1.2 root 570: write_log(_T("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n"));
1.1 root 571: }
1.1.1.2 root 572: #endif
573:
574: #if MMU030_REG_DBG_MSG /* enable or disable debugging messages */
575: write_log(_T("\n"));
576: write_log(_T("TRANSPARENT TRANSLATION: %08X\n"), TT);
577: write_log(_T("\n"));
1.1 root 578:
1.1.1.2 root 579: write_log(_T("TT: transparent translation "));
1.1 root 580: if (TT&TT_ENABLE) {
1.1.1.2 root 581: write_log(_T("enabled\n"));
1.1 root 582: } else {
1.1.1.2 root 583: write_log(_T("disabled\n"));
1.1 root 584: return ret;
585: }
586:
1.1.1.2 root 587: write_log(_T("TT: caching %s\n"), (TT&TT_CI) ? _T("inhibited") : _T("enabled"));
588: write_log(_T("TT: read-modify-write "));
1.1 root 589: if (TT&TT_RWM) {
1.1.1.2 root 590: write_log(_T("enabled\n"));
1.1 root 591: } else {
1.1.1.2 root 592: write_log(_T("disabled (%s only)\n"), (TT&TT_RW) ? _T("read") : _T("write"));
1.1 root 593: }
1.1.1.2 root 594: write_log(_T("\n"));
595: write_log(_T("TT: function code base: %08X\n"), ret.fc_base);
596: write_log(_T("TT: function code mask: %08X\n"), ret.fc_mask);
597: write_log(_T("\n"));
598: write_log(_T("TT: address base: %08X\n"), ret.addr_base);
599: write_log(_T("TT: address mask: %08X\n"), ret.addr_mask);
600: write_log(_T("\n"));
1.1 root 601: #endif
602:
603: return ret;
604: }
605:
606: /* This function compares the address with both transparent
607: * translation registers and returns the result */
608: int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
609: {
610: int tt0, tt1;
611:
612: bool cache_inhibit = false; /* TODO: pass to memory access function */
613:
614: tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
615: if (tt0&TT_OK_MATCH) {
616: cache_inhibit = (tt0_030&TT_CI) ? true : false;
617: }
618: tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
619: if (tt1&TT_OK_MATCH) {
620: if (!cache_inhibit) {
621: cache_inhibit = (tt1_030&TT_CI) ? true : false;
622: }
623: }
624:
625: return (tt0|tt1);
626: }
1.1.1.2 root 627: int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write)
628: {
629: int tt0, tt1;
630: if (!tt_enabled)
631: return 0;
632: tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
633: tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
634: return (tt0|tt1) & TT_OK_MATCH;
635: }
636:
637: /* Locked Read-Modify-Write */
638: int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
639: {
640: int tt0, tt1;
641:
642: if (!tt_enabled)
643: return 0;
644: tt0 = mmu030_do_match_lrmw_ttr(tt0_030, mmu030.transparent.tt0, addr, fc);
645: tt1 = mmu030_do_match_lrmw_ttr(tt1_030, mmu030.transparent.tt1, addr, fc);
646: return (tt0|tt1) & TT_OK_MATCH;
647: }
1.1 root 648:
649: /* This function checks if an address matches a transparent
650: * translation register */
651:
652: /* FIXME:
653: * If !(tt&TT_RMW) neither the read nor the write portion
654: * of a read-modify-write cycle is transparently translated! */
655:
656: int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
657: {
658: if (tt & TT_ENABLE) { /* transparent translation enabled */
659:
660: /* Compare actual function code with function code base using mask */
661: if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
662:
663: /* Compare actual address with address base using mask */
664: if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
665:
666: if (tt&TT_RWM) { /* r/w field disabled */
667: return TT_OK_MATCH;
668: } else {
669: if (tt&TT_RW) { /* read access transparent */
670: return write ? TT_NO_WRITE : TT_OK_MATCH;
671: } else { /* write access transparent */
672: return write ? TT_OK_MATCH : TT_NO_READ; /* TODO: check this! */
673: }
674: }
675: }
676: }
677: }
678: return TT_NO_MATCH;
679: }
680:
1.1.1.2 root 681: int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
682: {
1.1.1.3 ! root 683: if ((tt & TT_ENABLE) && (tt & TT_RWM)) { /* transparent translation enabled */
1.1.1.2 root 684:
685: /* Compare actual function code with function code base using mask */
686: if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
687:
688: /* Compare actual address with address base using mask */
689: if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
690:
1.1.1.3 ! root 691: return TT_OK_MATCH;
1.1.1.2 root 692: }
693: }
694: }
695: return TT_NO_MATCH;
696: }
697:
1.1 root 698:
699:
700: /* Translation Control Register:
701: *
702: * x--- ---- ---- ---- ---- ---- ---- ----
703: * translation: 1 = enable, 0 = disable
704: *
705: * ---- --x- ---- ---- ---- ---- ---- ----
706: * supervisor root: 1 = enable, 0 = disable
707: *
708: * ---- ---x ---- ---- ---- ---- ---- ----
709: * function code lookup: 1 = enable, 0 = disable
710: *
711: * ---- ---- xxxx ---- ---- ---- ---- ----
712: * page size:
713: * 1000 = 256 bytes
714: * 1001 = 512 bytes
715: * 1010 = 1 kB
716: * 1011 = 2 kB
717: * 1100 = 4 kB
718: * 1101 = 8 kB
719: * 1110 = 16 kB
720: * 1111 = 32 kB
721: *
722: * ---- ---- ---- xxxx ---- ---- ---- ----
723: * initial shift
724: *
725: * ---- ---- ---- ---- xxxx ---- ---- ----
726: * number of bits for table index A
727: *
728: * ---- ---- ---- ---- ---- xxxx ---- ----
729: * number of bits for table index B
730: *
731: * ---- ---- ---- ---- ---- ---- xxxx ----
732: * number of bits for table index C
733: *
1.1.1.2 root 734: * ---- ---- ---- ---- ---- ----- ---- xxxx
1.1 root 735: * number of bits for table index D
736: *
737: */
738:
739:
740: #define TC_ENABLE_TRANSLATION 0x80000000
741: #define TC_ENABLE_SUPERVISOR 0x02000000
742: #define TC_ENABLE_FCL 0x01000000
743:
744: #define TC_PS_MASK 0x00F00000
745: #define TC_IS_MASK 0x000F0000
746:
747: #define TC_TIA_MASK 0x0000F000
748: #define TC_TIB_MASK 0x00000F00
749: #define TC_TIC_MASK 0x000000F0
750: #define TC_TID_MASK 0x0000000F
751:
1.1.1.3 ! root 752: static void mmu030_do_fake_prefetch(void)
! 753: {
! 754: // fetch next opcode before MMU state switches.
! 755: // There are programs that do following:
! 756: // - enable MMU
! 757: // - JMP (An)
! 758: // "enable MMU" unmaps memory under us.
! 759: TRY (prb) {
! 760: uaecptr pc = m68k_getpci();
! 761: mmu030_fake_prefetch = -1;
! 762: mmu030_fake_prefetch_addr = mmu030_translate(pc, regs.s != 0, false, false);
! 763: mmu030_fake_prefetch = x_prefetch(0);
! 764: // A26x0 ROM code switches off rom
! 765: // NOP
! 766: // JMP (a0)
! 767: if (mmu030_fake_prefetch == 0x4e71)
! 768: mmu030_fake_prefetch = x_prefetch(2);
! 769: } CATCH (prb) {
! 770: // didn't work, oh well..
! 771: mmu030_fake_prefetch = -1;
! 772: } ENDTRY
! 773: }
1.1 root 774:
1.1.1.3 ! root 775: bool mmu030_decode_tc(uae_u32 TC)
! 776: {
1.1 root 777: /* Set MMU condition */
778: if (TC & TC_ENABLE_TRANSLATION) {
1.1.1.3 ! root 779: if (!mmu030.enabled)
! 780: mmu030_do_fake_prefetch();
1.1 root 781: mmu030.enabled = true;
782: } else {
1.1.1.3 ! root 783: if (mmu030.enabled) {
! 784: mmu030_do_fake_prefetch();
! 785: write_log(_T("MMU disabled PC=%08x\n"), M68K_GETPC);
! 786: }
1.1 root 787: mmu030.enabled = false;
1.1.1.3 ! root 788: return false;
1.1 root 789: }
790:
791: /* Note: 0 = Table A, 1 = Table B, 2 = Table C, 3 = Table D */
792: int i, j;
793: uae_u8 TI_bits[4] = {0,0,0,0};
794:
795: /* Reset variables before extracting new values from TC */
796: for (i = 0; i < 4; i++) {
797: mmu030.translation.table[i].mask = 0;
798: mmu030.translation.table[i].shift = 0;
799: }
800:
801:
802: /* Extract initial shift and page size values from TC register */
803: mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
804: mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
1.1.1.2 root 805: regs.mmu_page_size = 1 << mmu030.translation.page.size;
806:
1.1 root 807:
1.1.1.3 ! root 808: write_log(_T("68030 MMU enabled. Page size = %d PC=%08x\n"), regs.mmu_page_size, M68K_GETPC);
1.1.1.2 root 809:
810: if (mmu030.translation.page.size<8) {
811: write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad page size: %i byte)\n"),
1.1 root 812: 1<<mmu030.translation.page.size);
1.1.1.2 root 813: Exception(56); /* MMU Configuration Exception */
1.1.1.3 ! root 814: return true;
1.1 root 815: }
1.1.1.2 root 816: mmu030.translation.page.mask = regs.mmu_page_size - 1;
817: mmu030.translation.page.imask = ~mmu030.translation.page.mask;
1.1 root 818:
819: /* Calculate masks and shifts for later extracting table indices
820: * from logical addresses using: index = (addr&mask)>>shift */
821:
822: /* Get number of bits for each table index */
823: for (i = 0; i < 4; i++) {
824: j = (3-i)*4;
825: TI_bits[i] = (TC >> j) & 0xF;
826: }
827:
828: /* Calculate masks and shifts for each table */
829: mmu030.translation.last_table = 0;
830: uae_u8 shift = 32 - mmu030.translation.init_shift;
831: for (i = 0; (i < 4) && TI_bits[i]; i++) {
832: /* Get the shift */
833: shift -= TI_bits[i];
834: mmu030.translation.table[i].shift = shift;
835: /* Build the mask */
836: for (j = 0; j < TI_bits[i]; j++) {
837: mmu030.translation.table[i].mask |= (1<<(mmu030.translation.table[i].shift + j));
838: }
839: /* Update until reaching the last table */
840: mmu030.translation.last_table = i;
841: }
842:
1.1.1.2 root 843: #if MMU030_REG_DBG_MSG
1.1 root 844: /* At least one table has to be defined using at least
1.1.1.2 root 845: * 1 bit for the index. At least 2 bits are necessary
1.1 root 846: * if there is no second table. If these conditions are
847: * not met, it will automatically lead to a sum <32
1.1.1.2 root 848: * and cause an exception (see below). */
1.1 root 849: if (!TI_bits[0]) {
1.1.1.2 root 850: write_log(_T("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n"));
1.1 root 851: } else if ((TI_bits[0]<2) && !TI_bits[1]) {
1.1.1.2 root 852: write_log(_T("MMU Configuration Exception: Bad value in TC register! (no second table index defined and)\n"));
853: write_log(_T("MMU Configuration Exception: Bad value in TC register! (only 1 bit for first table index)\n"));
1.1 root 854: }
855: #endif
856:
1.1.1.2 root 857: /* TI fields are summed up until a zero field is reached (see above
858: * loop). The sum of all TI field values plus page size and initial
859: * shift has to be 32: IS + PS + TIA + TIB + TIC + TID = 32 */
860: if ((shift-mmu030.translation.page.size)!=0) {
861: write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad sum)\n"));
862: Exception(56); /* MMU Configuration Exception */
1.1.1.3 ! root 863: return true;
1.1.1.2 root 864: }
865:
866: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
867: write_log(_T("\n"));
868: write_log(_T("TRANSLATION CONTROL: %08X\n"), TC);
869: write_log(_T("\n"));
870: write_log(_T("TC: translation %s\n"), (TC&TC_ENABLE_TRANSLATION ? _T("enabled") : _T("disabled")));
871: write_log(_T("TC: supervisor root pointer %s\n"), (TC&TC_ENABLE_SUPERVISOR ? _T("enabled") : _T("disabled")));
872: write_log(_T("TC: function code lookup %s\n"), (TC&TC_ENABLE_FCL ? _T("enabled") : _T("disabled")));
873: write_log(_T("\n"));
874:
875: write_log(_T("TC: Initial Shift: %i\n"), mmu030.translation.init_shift);
876: write_log(_T("TC: Page Size: %i byte\n"), (1<<mmu030.translation.page.size));
877: write_log(_T("\n"));
1.1 root 878:
879: for (i = 0; i <= mmu030.translation.last_table; i++) {
1.1.1.2 root 880: write_log(_T("TC: Table %c: mask = %08X, shift = %i\n"), table_letter[i], mmu030.translation.table[i].mask, mmu030.translation.table[i].shift);
1.1 root 881: }
882:
1.1.1.2 root 883: write_log(_T("TC: Page: mask = %08X\n"), mmu030.translation.page.mask);
884: write_log(_T("\n"));
1.1 root 885:
1.1.1.2 root 886: write_log(_T("TC: Last Table: %c\n"), table_letter[mmu030.translation.last_table]);
887: write_log(_T("\n"));
1.1 root 888: #endif
1.1.1.3 ! root 889: return false;
1.1 root 890: }
891:
892:
893:
894: /* Root Pointer Registers (SRP and CRP)
895: *
896: * ---- ---- ---- ---- xxxx xxxx xxxx xx-- ---- ---- ---- ---- ---- ---- ---- xxxx
897: * reserved, must be 0
898: *
899: * ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
900: * table A address
901: *
902: * ---- ---- ---- ---- ---- ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- ----
903: * descriptor type
904: *
905: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
906: * limit
907: *
908: * x--- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
909: * 0 = upper limit, 1 = lower limit
910: *
911: */
912:
913:
914: #define RP_ADDR_MASK (UVAL64(0x00000000FFFFFFF0))
915: #define RP_DESCR_MASK (UVAL64(0x0000000300000000))
916: #define RP_LIMIT_MASK (UVAL64(0x7FFF000000000000))
917: #define RP_LOWER_MASK (UVAL64(0x8000000000000000))
1.1.1.2 root 918:
919: #define RP_ZERO_BITS 0x0000FFFC /* These bits in upper longword of RP must be 0 */
1.1 root 920:
1.1.1.3 ! root 921: bool mmu030_decode_rp(uae_u64 RP) {
1.1 root 922:
923: uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
924: if (!descriptor_type) { /* If descriptor type is invalid */
1.1.1.2 root 925: write_log(_T("MMU Configuration Exception: Root Pointer is invalid!\n"));
926: Exception(56); /* MMU Configuration Exception */
1.1.1.3 ! root 927: return true;
1.1 root 928: }
1.1.1.3 ! root 929: return false;
1.1 root 930:
1.1.1.2 root 931: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
1.1 root 932: uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
933: uae_u32 first_addr = (RP & RP_ADDR_MASK);
934:
1.1.1.2 root 935: write_log(_T("\n"));
936: write_log(_T("ROOT POINTER: %08X%08X\n"), (uae_u32)(RP>>32)&0xFFFFFFFF, (uae_u32)(RP&0xFFFFFFFF));
937: write_log(_T("\n"));
1.1 root 938:
1.1.1.2 root 939: write_log(_T("RP: descriptor type = %i "), descriptor_type);
1.1 root 940: switch (descriptor_type) {
941: case 0:
1.1.1.2 root 942: write_log(_T("(invalid descriptor)\n"));
1.1 root 943: break;
944: case 1:
1.1.1.2 root 945: write_log(_T("(early termination page descriptor)\n"));
1.1 root 946: break;
947: case 2:
1.1.1.2 root 948: write_log(_T("(valid 4 byte descriptor)\n"));
1.1 root 949: break;
950: case 3:
1.1.1.2 root 951: write_log(_T("(valid 8 byte descriptor)\n"));
1.1 root 952: break;
953: }
954:
1.1.1.2 root 955: write_log(_T("RP: %s limit = %i\n"), (RP&RP_LOWER_MASK) ? _T("lower") : _T("upper"), table_limit);
1.1 root 956:
1.1.1.2 root 957: write_log(_T("RP: first table address = %08X\n"), first_addr);
958: write_log(_T("\n"));
1.1 root 959: #endif
960: }
961:
962:
963:
964: /* Descriptors */
965:
966: #define DESCR_TYPE_MASK 0x00000003
967:
968: #define DESCR_TYPE_INVALID 0 /* all tables */
969:
970: #define DESCR_TYPE_EARLY_TERM 1 /* all but lowest level table */
971: #define DESCR_TYPE_PAGE 1 /* only lowest level table */
972: #define DESCR_TYPE_VALID4 2 /* all but lowest level table */
973: #define DESCR_TYPE_INDIRECT4 2 /* only lowest level table */
974: #define DESCR_TYPE_VALID8 3 /* all but lowest level table */
975: #define DESCR_TYPE_INDIRECT8 3 /* only lowest level table */
976:
977: #define DESCR_TYPE_VALID_MASK 0x2 /* all but lowest level table */
978: #define DESCR_TYPE_INDIRECT_MASK 0x2 /* only lowest level table */
979:
980:
981: /* Short format (4 byte):
982: *
983: * ---- ---- ---- ---- ---- ---- ---- --xx
984: * descriptor type:
985: * 0 = invalid
986: * 1 = page descriptor (early termination)
987: * 2 = valid (4 byte)
988: * 3 = valid (8 byte)
989: *
990: *
991: * table descriptor:
992: * ---- ---- ---- ---- ---- ---- ---- -x--
993: * write protect
994: *
995: * ---- ---- ---- ---- ---- ---- ---- x---
996: * update
997: *
998: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
999: * table address
1000: *
1001: *
1002: * (early termination) page descriptor:
1003: * ---- ---- ---- ---- ---- ---- ---- -x--
1004: * write protect
1005: *
1006: * ---- ---- ---- ---- ---- ---- ---- x---
1007: * update
1008: *
1009: * ---- ---- ---- ---- ---- ---- ---x ----
1010: * modified
1011: *
1012: * ---- ---- ---- ---- ---- ---- -x-- ----
1013: * cache inhibit
1014: *
1015: * ---- ---- ---- ---- ---- ---- x-x- ----
1016: * reserved (must be 0)
1017: *
1018: * xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
1019: * page address
1020: *
1021: *
1022: * indirect descriptor:
1023: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
1024: * descriptor address
1025: *
1026: */
1027:
1028: #define DESCR_WP 0x00000004
1029: #define DESCR_U 0x00000008
1030: #define DESCR_M 0x00000010 /* only last level table */
1031: #define DESCR_CI 0x00000040 /* only last level table */
1032:
1033: #define DESCR_TD_ADDR_MASK 0xFFFFFFF0
1034: #define DESCR_PD_ADDR_MASK 0xFFFFFF00
1035: #define DESCR_ID_ADDR_MASK 0xFFFFFFFC
1036:
1037:
1038: /* Long format (8 byte):
1039: *
1040: * ---- ---- ---- ---- ---- ---- ---- --xx | ---- ---- ---- ---- ---- ---- ---- ----
1041: * descriptor type:
1042: * 0 = invalid
1043: * 1 = page descriptor (early termination)
1044: * 2 = valid (4 byte)
1045: * 3 = valid (8 byte)
1046: *
1047: *
1048: * table desctriptor:
1049: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
1050: * write protect
1051: *
1052: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
1053: * update
1054: *
1055: * ---- ---- ---- ---- ---- ---- xxxx ---- | ---- ---- ---- ---- ---- ---- ---- ----
1056: * reserved (must be 0)
1057: *
1058: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1059: * supervisor
1060: *
1061: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1062: * reserved (must be 1111 110)
1063: *
1064: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1065: * limit
1066: *
1067: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1068: * 0 = upper limit, 1 = lower limit
1069: *
1070: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
1071: * table address
1072: *
1073: *
1074: * (early termination) page descriptor:
1075: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
1076: * write protect
1077: *
1078: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
1079: * update
1080: *
1081: * ---- ---- ---- ---- ---- ---- ---x ---- | ---- ---- ---- ---- ---- ---- ---- ----
1082: * modified
1083: *
1084: * ---- ---- ---- ---- ---- ---- -x-- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1085: * cache inhibit
1086: *
1087: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1088: * supervisor
1089: *
1090: * ---- ---- ---- ---- ---- ---- x-x- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1091: * reserved (must be 0)
1092: *
1093: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1094: * reserved (must be 1111 110)
1095: *
1096: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1097: * limit (only used with early termination page descriptor)
1098: *
1099: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1100: * 0 = upper limit, 1 = lower limit (only used with early termination page descriptor)
1101: *
1102: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
1103: * page address
1104: *
1105: *
1106: * indirect descriptor:
1107: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
1108: * descriptor address
1109: *
1110: */
1111:
1112: /* only for long descriptors */
1113: #define DESCR_S 0x00000100
1114:
1115: #define DESCR_LIMIT_MASK 0x7FFF0000
1116: #define DESCR_LOWER_MASK 0x80000000
1117:
1118:
1119:
1120: /* This functions searches through the translation tables. It can be used
1121: * for PTEST (levels 1 to 7). Using level 0 creates an ATC entry. */
1122:
1123: uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
1124: /* During table walk up to 7 different descriptors are used:
1125: * root pointer, descriptors fetched from function code lookup table,
1126: * tables A, B, C and D and one indirect descriptor */
1127: uae_u32 descr[2];
1128: uae_u32 descr_type;
1129: uaecptr descr_addr[7];
1130: uaecptr table_addr = 0;
1131: uaecptr page_addr = 0;
1132: uaecptr indirect_addr = 0;
1133: uae_u32 table_index = 0;
1134: uae_u32 limit = 0;
1135: uae_u32 unused_fields_mask = 0;
1136: bool super = (fc&4) ? true : false;
1.1.1.2 root 1137: bool super_violation = false;
1138: bool write_protected = false;
1.1 root 1139: bool cache_inhibit = false;
1140: bool descr_modified = false;
1141:
1142: mmu030.status = 0; /* Reset status */
1143:
1144: /* Initial values for condition variables.
1145: * Note: Root pointer is long descriptor. */
1146: int t = 0;
1147: int addr_position = 1;
1148: int next_size = 0;
1149: int descr_size = 8;
1150: int descr_num = 0;
1151: bool early_termination = false;
1152:
1153: int i;
1154:
1155: TRY(prb) {
1156: /* Use super user root pointer if enabled in TC register and access is in
1157: * super user mode, else use cpu root pointer. */
1158: if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
1159: descr[0] = (srp_030>>32)&0xFFFFFFFF;
1160: descr[1] = srp_030&0xFFFFFFFF;
1.1.1.2 root 1161: #if MMU030_REG_DBG_MSG
1162: write_log(_T("Supervisor Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1163: #endif // MMU030_REG_DBG_MSG
1.1 root 1164: } else {
1165: descr[0] = (crp_030>>32)&0xFFFFFFFF;
1166: descr[1] = crp_030&0xFFFFFFFF;
1.1.1.2 root 1167: #if MMU030_REG_DBG_MSG
1168: write_log(_T("CPU Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1169: #endif
1170: }
1171:
1172: if (descr[0]&RP_ZERO_BITS) {
1173: #if MMU030_REG_DBG_MSG
1174: write_log(_T("MMU Warning: Root pointer reserved bits are non-zero! %08X\n"), descr[0]);
1175: #endif
1176: descr[0] &= (~RP_ZERO_BITS);
1.1 root 1177: }
1178:
1179: /* Check descriptor type of root pointer */
1180: descr_type = descr[0]&DESCR_TYPE_MASK;
1181: switch (descr_type) {
1182: case DESCR_TYPE_INVALID:
1.1.1.2 root 1183: write_log(_T("Fatal error: Root pointer is invalid descriptor!\n"));
1.1 root 1184: mmu030.status |= MMUSR_INVALID;
1185: goto stop_search;
1186: case DESCR_TYPE_EARLY_TERM:
1.1.1.2 root 1187: write_log(_T("Root pointer is early termination page descriptor.\n"));
1.1 root 1188: early_termination = true;
1189: goto handle_page_descriptor;
1190: case DESCR_TYPE_VALID4:
1191: next_size = 4;
1192: break;
1193: case DESCR_TYPE_VALID8:
1194: next_size = 8;
1195: break;
1196: }
1197:
1198: /* If function code lookup is enabled in TC register use function code as
1199: * index for top level table, limit check not required */
1200:
1201: if (tc_030&TC_ENABLE_FCL) {
1.1.1.2 root 1202: write_log(_T("Function code lookup enabled, FC = %i\n"), fc);
1.1 root 1203:
1204: addr_position = (descr_size==4) ? 0 : 1;
1205: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1206: table_index = fc; /* table index is function code */
1.1.1.2 root 1207: write_log(_T("Table FCL at %08X: index = %i, "),table_addr,table_index);
1.1 root 1208:
1209: /* Fetch next descriptor */
1210: descr_num++;
1211: descr_addr[descr_num] = table_addr+(table_index*next_size);
1212:
1213: if (next_size==4) {
1214: descr[0] = phys_get_long(descr_addr[descr_num]);
1.1.1.2 root 1215: #if MMU030_REG_DBG_MSG
1216: write_log(_T("Next descriptor: %08X\n"),descr[0]);
1217: #endif
1.1 root 1218: } else {
1219: descr[0] = phys_get_long(descr_addr[descr_num]);
1220: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1.1.1.2 root 1221: #if MMU030_REG_DBG_MSG
1222: write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1223: #endif
1.1 root 1224: }
1225:
1226: descr_size = next_size;
1227:
1228: /* Check descriptor type */
1229: descr_type = descr[0]&DESCR_TYPE_MASK;
1230: switch (descr_type) {
1231: case DESCR_TYPE_INVALID:
1.1.1.2 root 1232: write_log(_T("Invalid descriptor!\n"));
1.1 root 1233: /* stop table walk */
1234: mmu030.status |= MMUSR_INVALID;
1235: goto stop_search;
1236: case DESCR_TYPE_EARLY_TERM:
1.1.1.2 root 1237: #if MMU030_REG_DBG_MSG
1238: write_log(_T("Early termination page descriptor!\n"));
1239: #endif
1240: early_termination = true;
1.1 root 1241: goto handle_page_descriptor;
1242: case DESCR_TYPE_VALID4:
1243: next_size = 4;
1244: break;
1245: case DESCR_TYPE_VALID8:
1246: next_size = 8;
1247: break;
1248: }
1249: }
1250:
1251:
1252: /* Upper level tables */
1253: do {
1254: if (descr_num) { /* if not root pointer */
1.1.1.2 root 1255: /* Check protection */
1256: if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
1257: super_violation = true;
1258: }
1259: if (descr[0]&DESCR_WP) {
1260: write_protected = true;
1261: }
1262:
1.1 root 1263: /* Set the updated bit */
1.1.1.2 root 1264: if (!level && !(descr[0]&DESCR_U) && !super_violation) {
1.1 root 1265: descr[0] |= DESCR_U;
1266: phys_put_long(descr_addr[descr_num], descr[0]);
1267: }
1.1.1.2 root 1268:
1.1 root 1269: /* Update status bits */
1.1.1.2 root 1270: mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
1.1.1.3 ! root 1271: mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
! 1272:
1.1 root 1273: /* Check if ptest level is reached */
1274: if (level && (level==descr_num)) {
1275: goto stop_search;
1276: }
1277: }
1278:
1279: addr_position = (descr_size==4) ? 0 : 1;
1280: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1281: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1.1.1.2 root 1282: #if MMU030_REG_DBG_MSG
1283: write_log(_T("Table %c at %08X: index = %i, "),table_letter[t],table_addr,table_index);
1284: #endif // MMU030_REG_DBG_MSG
1.1 root 1285: t++; /* Proceed to the next table */
1286:
1287: /* Perform limit check */
1288: if (descr_size==8) {
1289: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1290: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1291: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.2 root 1292: #if MMU030_REG_DBG_MSG
1293: write_log(_T("limit violation (lower limit %i)\n"),limit);
1294: #endif
1.1 root 1295: goto stop_search;
1296: }
1297: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1298: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.2 root 1299: #if MMU030_REG_DBG_MSG
1300: write_log(_T("limit violation (upper limit %i)\n"),limit);
1301: #endif
1.1 root 1302: goto stop_search;
1303: }
1304: }
1305:
1306: /* Fetch next descriptor */
1307: descr_num++;
1308: descr_addr[descr_num] = table_addr+(table_index*next_size);
1309:
1310: if (next_size==4) {
1311: descr[0] = phys_get_long(descr_addr[descr_num]);
1.1.1.2 root 1312: #if MMU030_REG_DBG_MSG
1313: write_log(_T("Next descriptor: %08X\n"),descr[0]);
1314: #endif
1.1 root 1315: } else {
1316: descr[0] = phys_get_long(descr_addr[descr_num]);
1317: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1.1.1.2 root 1318: #if MMU030_REG_DBG_MSG
1319: write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1320: #endif
1.1 root 1321: }
1322:
1323: descr_size = next_size;
1324:
1325: /* Check descriptor type */
1326: descr_type = descr[0]&DESCR_TYPE_MASK;
1327: switch (descr_type) {
1328: case DESCR_TYPE_INVALID:
1.1.1.2 root 1329: #if MMU030_REG_DBG_MSG
1330: write_log(_T("Invalid descriptor!\n"));
1331: #endif
1332: /* stop table walk */
1.1 root 1333: mmu030.status |= MMUSR_INVALID;
1334: goto stop_search;
1335: case DESCR_TYPE_EARLY_TERM:
1336: /* go to last level table handling code */
1337: if (t<=mmu030.translation.last_table) {
1.1.1.2 root 1338: #if MMU030_REG_DBG_MSG
1339: write_log(_T("Early termination page descriptor!\n"));
1340: #endif
1341: early_termination = true;
1.1 root 1342: }
1343: goto handle_page_descriptor;
1344: case DESCR_TYPE_VALID4:
1345: next_size = 4;
1346: break;
1347: case DESCR_TYPE_VALID8:
1348: next_size = 8;
1349: break;
1350: }
1351: } while (t<=mmu030.translation.last_table);
1352:
1353:
1354: /* Handle indirect descriptor */
1355:
1356: /* Check if ptest level is reached */
1357: if (level && (level==descr_num)) {
1358: goto stop_search;
1359: }
1360:
1361: addr_position = (descr_size==4) ? 0 : 1;
1362: indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1.1.1.2 root 1363: #if MMU030_REG_DBG_MSG
1364: write_log(_T("Page indirect descriptor at %08X: "),indirect_addr);
1365: #endif
1366:
1.1 root 1367: /* Fetch indirect descriptor */
1368: descr_num++;
1369: descr_addr[descr_num] = indirect_addr;
1370:
1371: if (next_size==4) {
1372: descr[0] = phys_get_long(descr_addr[descr_num]);
1.1.1.2 root 1373: #if MMU030_REG_DBG_MSG
1374: write_log(_T("descr = %08X\n"),descr[0]);
1375: #endif
1376: } else {
1.1 root 1377: descr[0] = phys_get_long(descr_addr[descr_num]);
1378: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1.1.1.2 root 1379: #if MMU030_REG_DBG_MSG
1380: write_log(_T("descr = %08X%08X"),descr[0],descr[1]);
1381: #endif
1382: }
1.1 root 1383:
1384: descr_size = next_size;
1385:
1386: /* Check descriptor type, only page descriptor is valid */
1387: descr_type = descr[0]&DESCR_TYPE_MASK;
1388: if (descr_type!=DESCR_TYPE_PAGE) {
1389: mmu030.status |= MMUSR_INVALID;
1390: goto stop_search;
1391: }
1392:
1393: handle_page_descriptor:
1394:
1395: if (descr_num) { /* if not root pointer */
1.1.1.2 root 1396: /* check protection */
1397: if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
1398: super_violation = true;
1399: }
1400: if (descr[0]&DESCR_WP) {
1401: write_protected = true;
1402: }
1403:
1404: if (!level && !super_violation) {
1.1 root 1405: /* set modified bit */
1.1.1.2 root 1406: if (!(descr[0]&DESCR_M) && write && !write_protected) {
1.1 root 1407: descr[0] |= DESCR_M;
1408: descr_modified = true;
1409: }
1410: /* set updated bit */
1411: if (!(descr[0]&DESCR_U)) {
1412: descr[0] |= DESCR_U;
1413: descr_modified = true;
1414: }
1415: /* write modified descriptor if neccessary */
1416: if (descr_modified) {
1417: phys_put_long(descr_addr[descr_num], descr[0]);
1418: }
1419: }
1420:
1.1.1.2 root 1421: /* update status bits */
1422: mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
1423: mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
1.1.1.3 ! root 1424:
1.1 root 1425: /* check if caching is inhibited */
1426: cache_inhibit = descr[0]&DESCR_CI ? true : false;
1427:
1.1.1.2 root 1428: /* check for the modified bit and set it in the status register */
1.1 root 1429: mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
1430: }
1431:
1432: /* Check limit using next index field of logical address.
1433: * Limit is only checked on early termination. If we are
1434: * still at root pointer level, only check limit, if FCL
1435: * is disabled. */
1436: if (early_termination) {
1437: if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
1438: if (descr_size==8) {
1439: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1440: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1441: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1442: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.2 root 1443: #if MMU030_REG_DBG_MSG
1444: write_log(_T("Limit violation (lower limit %i)\n"),limit);
1445: #endif
1.1 root 1446: goto stop_search;
1447: }
1448: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1449: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.2 root 1450: #if MMU030_REG_DBG_MSG
1451: write_log(_T("Limit violation (upper limit %i)\n"),limit);
1452: #endif
1.1 root 1453: goto stop_search;
1454: }
1455: }
1456: }
1457: /* Get all unused bits of the logical address table index field.
1458: * they are added to the page address */
1.1.1.2 root 1459: /* TODO: They should be added via "unsigned addition". How to? */
1.1 root 1460: do {
1461: unused_fields_mask |= mmu030.translation.table[t].mask;
1462: t++;
1463: } while (t<=mmu030.translation.last_table);
1464: page_addr = addr&unused_fields_mask;
1.1.1.2 root 1465: #if MMU030_REG_DBG_MSG
1466: write_log(_T("Logical address unused bits: %08X (mask = %08X)\n"),
1.1 root 1467: page_addr,unused_fields_mask);
1.1.1.2 root 1468: #endif
1469: }
1470:
1.1 root 1471: /* Get page address */
1472: addr_position = (descr_size==4) ? 0 : 1;
1473: page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
1.1.1.2 root 1474: #if MMU030_REG_DBG_MSG
1475: write_log(_T("Page at %08X\n"),page_addr);
1476: #endif // MMU030_REG_DBG_MSG
1.1 root 1477:
1478: stop_search:
1479: ; /* Make compiler happy */
1480: } CATCH(prb) {
1481: /* We jump to this place, if a bus error occured during table search.
1482: * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
1483: if (bBusErrorReadWrite) {
1484: descr_num--;
1485: }
1486: mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1.1.1.2 root 1487: write_log(_T("MMU: Bus error while %s descriptor!\n"),
1488: bBusErrorReadWrite?_T("reading"):_T("writing"));
1.1 root 1489: } ENDTRY
1.1.1.3 ! root 1490:
1.1 root 1491: /* check if we have to handle ptest */
1492: if (level) {
1.1.1.2 root 1493: /* Note: wp, m and sv bits are undefined if the invalid bit is set */
1.1 root 1494: mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
1495:
1496: /* If root pointer is page descriptor (descr_num 0), return 0 */
1497: return descr_num ? descr_addr[descr_num] : 0;
1498: }
1499:
1500: /* Find an ATC entry to replace */
1501: /* Search for invalid entry */
1502: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1503: if (!mmu030.atc[i].logical.valid) {
1504: break;
1505: }
1506: }
1507: /* If there are no invalid entries, replace first entry
1508: * with history bit not set */
1509: if (i == ATC030_NUM_ENTRIES) {
1510: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1511: if (!mmu030.atc[i].mru) {
1512: break;
1513: }
1514: }
1.1.1.2 root 1515: #if MMU030_REG_DBG_MSG
1516: write_log(_T("ATC is full. Replacing entry %i\n"), i);
1517: #endif
1518: }
1519: if (i >= ATC030_NUM_ENTRIES) {
1520: i = 0;
1521: write_log (_T("ATC entry not found!!!\n"));
1522: }
1523:
1.1 root 1524: mmu030_atc_handle_history_bit(i);
1525:
1526: /* Create ATC entry */
1.1.1.2 root 1527: mmu030.atc[i].logical.addr = addr & mmu030.translation.page.imask; /* delete page index bits */
1.1 root 1528: mmu030.atc[i].logical.fc = fc;
1529: mmu030.atc[i].logical.valid = true;
1.1.1.2 root 1530: mmu030.atc[i].physical.addr = page_addr & mmu030.translation.page.imask; /* delete page index bits */
1.1 root 1531: if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
1532: mmu030.atc[i].physical.bus_error = true;
1533: } else {
1534: mmu030.atc[i].physical.bus_error = false;
1535: }
1536: mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1.1.1.2 root 1537: mmu030.atc[i].physical.modified = (mmu030.status&MMUSR_MODIFIED) ? true : false;
1538: mmu030.atc[i].physical.write_protect = (mmu030.status&MMUSR_WRITE_PROTECTED) ? true : false;
1.1.1.3 ! root 1539:
1.1.1.2 root 1540: #if MMU030_ATC_DBG_MSG
1541: write_log(_T("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n"), i,
1.1 root 1542: mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
1543: mmu030.atc[i].logical.fc);
1.1.1.2 root 1544: write_log(_T("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n"), i,
1.1 root 1545: mmu030.atc[i].physical.bus_error?1:0,
1546: mmu030.atc[i].physical.cache_inhibit?1:0,
1547: mmu030.atc[i].physical.write_protect?1:0,
1548: mmu030.atc[i].physical.modified?1:0);
1.1.1.2 root 1549: #endif // MMU030_ATC_DBG_MSG
1.1 root 1550:
1551: return 0;
1552: }
1553:
1554: /* This function is used for PTEST level 0. */
1555: void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1556: int i;
1557: mmu030.status = 0;
1558:
1559: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1560: mmu030.status |= MMUSR_TRANSP_ACCESS;
1561: return;
1562: }
1563:
1564: for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
1565: if ((mmu030.atc[i].logical.fc == fc) &&
1566: (mmu030.atc[i].logical.addr == logical_addr) &&
1567: mmu030.atc[i].logical.valid) {
1568: break;
1569: }
1570: }
1571:
1572: if (i==ATC030_NUM_ENTRIES) {
1573: mmu030.status |= MMUSR_INVALID;
1574: return;
1575: }
1576:
1577: mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1.1.1.2 root 1578: /* Note: write protect and modified bits are undefined if the invalid bit is set */
1.1 root 1579: mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
1580: mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
1581: }
1582:
1583: /* This function is used for PTEST level 1 - 7. */
1584: uae_u32 mmu030_ptest_table_search(uaecptr logical_addr, uae_u32 fc, bool write, int level) {
1585: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1586: return 0;
1587: } else {
1588: return mmu030_table_search(logical_addr, fc, write, level);
1589: }
1590: }
1591:
1592:
1593: /* Address Translation Cache
1594: *
1595: * The ATC uses a pseudo-least-recently-used algorithm to keep track of
1.1.1.2 root 1596: * least recently used entries. They are replaced if the cache is full.
1.1 root 1597: * An internal history-bit (MRU-bit) is used to identify these entries.
1598: * If an entry is accessed, its history-bit is set to 1. If after that
1599: * there are no more entries with zero-bits, all other history-bits are
1600: * set to 0. When no more invalid entries are in the ATC, the first entry
1601: * with a zero-bit is replaced.
1602: *
1603: *
1604: * Logical Portion (28 bit):
1605: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1606: * logical address (most significant 24 bit)
1607: *
1608: * oooo -xxx ---- ---- ---- ---- ---- ----
1609: * function code
1610: *
1611: * oooo x--- ---- ---- ---- ---- ---- ----
1612: * valid
1613: *
1614: *
1615: * Physical Portion (28 bit):
1616: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1617: * physical address
1618: *
1619: * oooo ---x ---- ---- ---- ---- ---- ----
1620: * modified
1621: *
1622: * oooo --x- ---- ---- ---- ---- ---- ----
1623: * write protect
1624: *
1625: * oooo -x-- ---- ---- ---- ---- ---- ----
1626: * cache inhibit
1627: *
1628: * oooo x--- ---- ---- ---- ---- ---- ----
1629: * bus error
1630: *
1631: */
1632:
1633: #define ATC030_MASK 0x0FFFFFFF
1634: #define ATC030_ADDR_MASK 0x00FFFFFF /* after masking shift 8 (<< 8) */
1635:
1636: #define ATC030_LOG_FC 0x07000000
1637: #define ATC030_LOG_V 0x08000000
1638:
1639: #define ATC030_PHYS_M 0x01000000
1640: #define ATC030_PHYS_WP 0x02000000
1641: #define ATC030_PHYS_CI 0x04000000
1642: #define ATC030_PHYS_BE 0x08000000
1643:
1.1.1.2 root 1644: void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc) {
1645: regs.mmu_fault_addr = addr;
1646: regs.mmu_ssw = (fc & 1) ? MMU030_SSW_DF | (MMU030_SSW_DF << 1) : (MMU030_SSW_FB | MMU030_SSW_RB);
1647: regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
1648: regs.mmu_ssw |= flags;
1649: regs.mmu_ssw |= fc;
1650: bBusErrorReadWrite = read;
1651: mm030_stageb_address = addr;
1652: #if MMUDEBUG
1653: write_log(_T("MMU: page fault (logical addr=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x ins=%04X)\n"),
1654: addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc,
1655: regs.instruction_pc, (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val, mmu030_opcode & 0xffff);
1656: #endif
1657:
1658: // extern void activate_debugger(void);
1659: // activate_debugger ();
1660:
1661: THROW(2);
1.1 root 1662: }
1663:
1.1.1.2 root 1664: void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l, uae_u32 fc) {
1.1 root 1665: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1666: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1667:
1668: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1669: #if MMU030_ATC_DBG_MSG
1670: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lput %08X)\n"),
1.1 root 1671: l, physical_addr, page_index, val);
1672: #endif
1673: physical_addr += page_index;
1674:
1675: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1.1.1.2 root 1676: mmu030_page_fault(addr, false, MMU030_SSW_SIZE_L, fc);
1.1 root 1677: return;
1678: }
1679:
1680: phys_put_long(physical_addr, val);
1681: }
1682:
1.1.1.2 root 1683: void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l, uae_u32 fc) {
1.1 root 1684: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1685: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1686:
1687: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1688: #if MMU030_ATC_DBG_MSG
1689: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wput %04X)\n"),
1.1 root 1690: l, physical_addr, page_index, val);
1691: #endif
1692: physical_addr += page_index;
1693:
1694: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1.1.1.2 root 1695: mmu030_page_fault(addr, false, MMU030_SSW_SIZE_W, fc);
1.1 root 1696: return;
1697: }
1698:
1699: phys_put_word(physical_addr, val);
1700: }
1701:
1.1.1.2 root 1702: void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l, uae_u32 fc) {
1.1 root 1703: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1704: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1705:
1706: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1707: #if MMU030_ATC_DBG_MSG
1708: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"),
1.1 root 1709: l, physical_addr, page_index, val);
1710: #endif
1711: physical_addr += page_index;
1712:
1713: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1.1.1.2 root 1714: mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc);
1.1 root 1715: return;
1716: }
1717:
1718: phys_put_byte(physical_addr, val);
1719: }
1720:
1.1.1.2 root 1721: uae_u32 mmu030_get_long_atc(uaecptr addr, int l, uae_u32 fc) {
1.1 root 1722: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1723: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1724:
1725: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1726: #if MMU030_ATC_DBG_MSG
1727: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
1.1 root 1728: physical_addr, page_index, phys_get_long(physical_addr+page_index));
1729: #endif
1730: physical_addr += page_index;
1731:
1732: if (mmu030.atc[l].physical.bus_error) {
1.1.1.2 root 1733: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
1.1 root 1734: return 0;
1735: }
1736:
1737: return phys_get_long(physical_addr);
1738: }
1739:
1.1.1.3 ! root 1740: static uae_u32 mmu030_get_ilong_atc(uaecptr addr, int l, uae_u32 fc) {
! 1741: uae_u32 page_index = addr & mmu030.translation.page.mask;
! 1742: uae_u32 addr_mask = mmu030.translation.page.imask;
! 1743:
! 1744: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
! 1745: #if MMU030_ATC_DBG_MSG
! 1746: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
! 1747: physical_addr, page_index, phys_get_long(physical_addr + page_index));
! 1748: #endif
! 1749: physical_addr += page_index;
! 1750:
! 1751: if (mmu030.atc[l].physical.bus_error) {
! 1752: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
! 1753: return 0;
! 1754: }
! 1755:
! 1756: return phys_get_long(physical_addr);
! 1757: }
! 1758:
1.1.1.2 root 1759: uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc) {
1.1 root 1760: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1761: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1762:
1763: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1764: #if MMU030_ATC_DBG_MSG
1765: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
1.1 root 1766: physical_addr, page_index, phys_get_word(physical_addr+page_index));
1767: #endif
1768: physical_addr += page_index;
1769:
1770: if (mmu030.atc[l].physical.bus_error) {
1.1.1.2 root 1771: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
1.1 root 1772: return 0;
1773: }
1774:
1775: return phys_get_word(physical_addr);
1776: }
1777:
1.1.1.3 ! root 1778: static uae_u16 mmu030_get_iword_atc(uaecptr addr, int l, uae_u32 fc) {
! 1779: uae_u32 page_index = addr & mmu030.translation.page.mask;
! 1780: uae_u32 addr_mask = mmu030.translation.page.imask;
! 1781:
! 1782: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
! 1783: #if MMU030_ATC_DBG_MSG
! 1784: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
! 1785: physical_addr, page_index, phys_get_word(physical_addr + page_index));
! 1786: #endif
! 1787: physical_addr += page_index;
! 1788:
! 1789: if (mmu030.atc[l].physical.bus_error) {
! 1790: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
! 1791: return 0;
! 1792: }
! 1793:
! 1794: return phys_get_word(physical_addr);
! 1795: }
! 1796:
1.1.1.2 root 1797: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc) {
1.1 root 1798: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.2 root 1799: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1800:
1801: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.2 root 1802: #if MMU030_ATC_DBG_MSG
1803: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
1.1 root 1804: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1805: #endif
1806: physical_addr += page_index;
1807:
1808: if (mmu030.atc[l].physical.bus_error) {
1.1.1.2 root 1809: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_B, fc);
1.1 root 1810: return 0;
1811: }
1812:
1813: return phys_get_byte(physical_addr);
1814: }
1815:
1.1.1.2 root 1816: /* Generic versions of above */
1817: void mmu030_put_atc_generic(uaecptr addr, uae_u32 val, int l, uae_u32 fc, int size, int flags) {
1818: uae_u32 page_index = addr & mmu030.translation.page.mask;
1819: uae_u32 addr_mask = mmu030.translation.page.imask;
1820:
1821: uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1822: #if MMU030_ATC_DBG_MSG
1823: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"),
1824: l, physical_addr, page_index, val);
1825: #endif
1826: physical_addr += page_index;
1827:
1828: if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
1829: mmu030_page_fault(addr, false, flags, fc);
1830: return;
1831: }
1832: if (size == sz_byte)
1833: phys_put_byte(physical_addr, val);
1834: else if (size == sz_word)
1835: phys_put_word(physical_addr, val);
1836: else
1837: phys_put_long(physical_addr, val);
1838:
1839: }
1.1.1.3 ! root 1840:
1.1.1.2 root 1841: uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite) {
1842: uae_u32 page_index = addr & mmu030.translation.page.mask;
1843: uae_u32 addr_mask = mmu030.translation.page.imask;
1844:
1845: uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1846: #if MMU030_ATC_DBG_MSG
1847: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
1848: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1849: #endif
1850: physical_addr += page_index;
1851:
1852: if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
1853: mmu030_page_fault(addr, true, flags, fc);
1854: return 0;
1855: }
1856: if (size == sz_byte)
1857: return phys_get_byte(physical_addr);
1858: else if (size == sz_word)
1859: return phys_get_word(physical_addr);
1860: return phys_get_long(physical_addr);
1861: }
1862:
1.1 root 1863:
1864: /* This function checks if a certain logical address is in the ATC
1865: * by comparing the logical address and function code to the values
1866: * stored in the ATC entries. If a matching entry is found it sets
1867: * the history bit and returns the cache index of the entry. */
1868: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1869: uaecptr logical_addr = 0;
1.1.1.2 root 1870: uae_u32 addr_mask = mmu030.translation.page.imask;
1871: uae_u32 maddr = addr & addr_mask;
1872: int offset = (maddr >> mmu030.translation.page.size) & 0x1f;
1.1.1.3 ! root 1873:
1.1.1.2 root 1874: int i, index;
1875: index = atcindextable[offset];
1.1 root 1876: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1.1.1.2 root 1877: logical_addr = mmu030.atc[index].logical.addr;
1.1 root 1878: /* If actual address matches address in ATC */
1.1.1.2 root 1879: if (maddr==(logical_addr&addr_mask) &&
1880: (mmu030.atc[index].logical.fc==fc) &&
1881: mmu030.atc[index].logical.valid) {
1882: /* If access is valid write and M bit is not set, invalidate entry
1883: * else return index */
1884: if (!write || mmu030.atc[index].physical.modified ||
1885: mmu030.atc[index].physical.write_protect ||
1886: mmu030.atc[index].physical.bus_error) {
1.1 root 1887: /* Maintain history bit */
1.1.1.3 ! root 1888: mmu030_atc_handle_history_bit(index);
! 1889: atcindextable[offset] = index;
! 1890: return index;
! 1891: } else {
! 1892: mmu030.atc[index].logical.valid = false;
! 1893: }
1.1.1.2 root 1894: }
1895: index++;
1896: if (index >= ATC030_NUM_ENTRIES)
1897: index = 0;
1.1 root 1898: }
1.1.1.2 root 1899: return -1;
1.1 root 1900: }
1901:
1902: void mmu030_atc_handle_history_bit(int entry_num) {
1903: int j;
1904: mmu030.atc[entry_num].mru = 1;
1905: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1906: if (!mmu030.atc[j].mru)
1907: break;
1908: }
1909: /* If there are no more zero-bits, reset all */
1910: if (j==ATC030_NUM_ENTRIES) {
1911: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1912: mmu030.atc[j].mru = 0;
1913: }
1914: mmu030.atc[entry_num].mru = 1;
1.1.1.2 root 1915: #if MMU030_ATC_DBG_MSG
1916: write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
1917: #endif
1918: }
1.1 root 1919: }
1920:
1921:
1922: /* Memory access functions:
1923: * If the address matches one of the transparent translation registers
1924: * use it directly as physical address, else check ATC for the
1925: * logical address. If the logical address is not resident in the ATC
1926: * create a new ATC entry and then look up the physical address.
1927: */
1928:
1.1.1.2 root 1929: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) {
1.1 root 1930:
1.1.1.3 ! root 1931: // addr,fc,write
! 1932: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
! 1933: phys_put_long(addr,val);
! 1934: return;
1.1 root 1935: }
1936:
1937: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1938:
1.1.1.2 root 1939: if (atc_line_num>=0) {
1940: mmu030_put_long_atc(addr, val, atc_line_num, fc);
1.1 root 1941: } else {
1942: mmu030_table_search(addr,fc,true,0);
1.1.1.2 root 1943: mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1944: }
1945: }
1946:
1.1.1.2 root 1947: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) {
1.1 root 1948:
1.1.1.3 ! root 1949: // addr,fc,write
! 1950: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
! 1951: phys_put_word(addr,val);
! 1952: return;
1.1 root 1953: }
1954:
1955: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1956:
1.1.1.2 root 1957: if (atc_line_num>=0) {
1958: mmu030_put_word_atc(addr, val, atc_line_num, fc);
1.1 root 1959: } else {
1960: mmu030_table_search(addr, fc, true, 0);
1.1.1.2 root 1961: mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1962: }
1963: }
1964:
1.1.1.2 root 1965: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) {
1.1 root 1966:
1.1.1.3 ! root 1967: // addr,fc,write
! 1968: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
! 1969: phys_put_byte(addr,val);
! 1970: return;
1.1 root 1971: }
1972:
1973: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1974:
1.1.1.2 root 1975: if (atc_line_num>=0) {
1976: mmu030_put_byte_atc(addr, val, atc_line_num, fc);
1.1 root 1977: } else {
1978: mmu030_table_search(addr, fc, true, 0);
1.1.1.2 root 1979: mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1980: }
1981: }
1982:
1.1.1.3 ! root 1983: uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
! 1984:
! 1985: // addr,fc,write
! 1986: if ((fc == 7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 1987: return phys_get_long(addr);
! 1988: }
! 1989:
! 1990: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
! 1991:
! 1992: if (atc_line_num >= 0) {
! 1993: return mmu030_get_ilong_atc(addr, atc_line_num, fc);
! 1994: }
! 1995: else {
! 1996: mmu030_table_search(addr, fc, false, 0);
! 1997: return mmu030_get_ilong_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
! 1998: }
! 1999: }
1.1.1.2 root 2000: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) {
1.1 root 2001:
1.1.1.3 ! root 2002: // addr,fc,write
! 2003: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 2004: return phys_get_long(addr);
1.1 root 2005: }
2006:
2007: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2008:
1.1.1.2 root 2009: if (atc_line_num>=0) {
2010: return mmu030_get_long_atc(addr, atc_line_num, fc);
1.1 root 2011: } else {
2012: mmu030_table_search(addr, fc, false, 0);
1.1.1.2 root 2013: return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
1.1 root 2014: }
2015: }
2016:
1.1.1.3 ! root 2017: uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
! 2018:
! 2019: // addr,fc,write
! 2020: if ((fc == 7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 2021: return phys_get_word(addr);
! 2022: }
! 2023:
! 2024: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
! 2025:
! 2026: if (atc_line_num >= 0) {
! 2027: return mmu030_get_iword_atc(addr, atc_line_num, fc);
! 2028: } else {
! 2029: mmu030_table_search(addr, fc, false, 0);
! 2030: return mmu030_get_iword_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
! 2031: }
! 2032: }
1.1.1.2 root 2033: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) {
1.1 root 2034:
1.1.1.3 ! root 2035: // addr,fc,write
! 2036: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 2037: return phys_get_word(addr);
1.1 root 2038: }
2039:
2040: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2041:
1.1.1.2 root 2042: if (atc_line_num>=0) {
2043: return mmu030_get_word_atc(addr, atc_line_num, fc);
1.1 root 2044: } else {
2045: mmu030_table_search(addr, fc, false, 0);
1.1.1.2 root 2046: return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
1.1 root 2047: }
2048: }
2049:
1.1.1.2 root 2050: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) {
1.1 root 2051:
1.1.1.3 ! root 2052: // addr,fc,write
! 2053: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 2054: return phys_get_byte(addr);
1.1 root 2055: }
2056:
2057: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2058:
1.1.1.2 root 2059: if (atc_line_num>=0) {
2060: return mmu030_get_byte_atc(addr, atc_line_num, fc);
1.1 root 2061: } else {
2062: mmu030_table_search(addr, fc, false, 0);
1.1.1.2 root 2063: return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
1.1 root 2064: }
2065: }
2066:
2067:
1.1.1.2 root 2068: /* Not commonly used access function */
2069: void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int accesssize, int flags) {
2070:
1.1.1.3 ! root 2071: // addr,fc,write
! 2072: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
! 2073: if (size == sz_byte)
! 2074: phys_put_byte(addr, val);
! 2075: else if (size == sz_word)
! 2076: phys_put_word(addr, val);
! 2077: else
! 2078: phys_put_long(addr, val);
! 2079: return;
1.1.1.2 root 2080: }
2081:
2082: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2083: if (atc_line_num>=0) {
2084: mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
2085: } else {
2086: mmu030_table_search(addr, fc, true, 0);
2087: atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2088: if (accesssize == sz_byte)
2089: flags |= MMU030_SSW_SIZE_B;
2090: else if (accesssize == sz_word)
2091: flags |= MMU030_SSW_SIZE_W;
2092: mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
2093: }
2094: }
2095: static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
2096:
1.1.1.3 ! root 2097: // addr,fc,write
! 2098: if ((fc==7) || (mmu030_match_lrmw_ttr_access(addr,fc)) || (!mmu030.enabled)) {
! 2099: if (size == sz_byte)
! 2100: return phys_get_byte(addr);
! 2101: else if (size == sz_word)
! 2102: return phys_get_word(addr);
! 2103: return phys_get_long(addr);
1.1.1.2 root 2104: }
2105:
2106: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2107: if (atc_line_num>=0) {
2108: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
2109: } else {
2110: mmu030_table_search(addr, fc, true, 0);
2111: atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2112: if (accesssize == sz_byte)
2113: flags |= MMU030_SSW_SIZE_B;
2114: else if (accesssize == sz_word)
2115: flags |= MMU030_SSW_SIZE_W;
2116: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
2117: }
2118: }
2119: uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
1.1.1.3 ! root 2120: if (flags & MMU030_SSW_RM) {
! 2121: return mmu030_get_generic_lrmw(addr, fc, size, accesssize, flags);
! 2122: }
! 2123: // addr,fc,write
! 2124: if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
! 2125: if (size == sz_byte)
! 2126: return phys_get_byte(addr);
! 2127: else if (size == sz_word)
! 2128: return phys_get_word(addr);
! 2129: return phys_get_long(addr);
1.1.1.2 root 2130: }
2131:
2132: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2133: if (atc_line_num>=0) {
2134: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
2135: } else {
2136: mmu030_table_search(addr, fc, false, 0);
2137: atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2138: if (accesssize == sz_byte)
2139: flags |= MMU030_SSW_SIZE_B;
2140: else if (accesssize == sz_word)
2141: flags |= MMU030_SSW_SIZE_W;
2142: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
2143: }
2144: }
2145:
2146:
2147: /* Locked RMW is rarely used */
2148: uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
2149: {
2150: uae_u32 fc = (regs.s ? 4 : 0) | 1;
2151: if (size == sz_byte) {
2152: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2153: } else if (size == sz_word) {
2154: if (unlikely(is_unaligned(addr, 2)))
2155: return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM);
2156: else
2157: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2158: } else {
2159: if (unlikely(is_unaligned(addr, 4)))
2160: return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM);
2161: else
2162: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2163: }
2164: }
2165: void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
2166: {
2167: uae_u32 fc = (regs.s ? 4 : 0) | 1;
2168: if (size == sz_byte) {
2169: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2170: } else if (size == sz_word) {
2171: if (unlikely(is_unaligned(addr, 2)))
2172: mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM);
2173: else
2174: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2175: } else {
2176: if (unlikely(is_unaligned(addr, 4)))
2177: mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM);
2178: else
2179: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2180: }
2181: }
2182: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags)
1.1 root 2183: {
2184: uae_u16 res;
2185:
1.1.1.2 root 2186: res = (uae_u16)mmu030_get_generic(addr, fc, sz_byte, sz_word, flags) << 8;
1.1 root 2187: SAVE_EXCEPTION;
2188: TRY(prb) {
1.1.1.2 root 2189: res |= mmu030_get_generic(addr + 1, fc, sz_byte, sz_word, flags);
1.1 root 2190: RESTORE_EXCEPTION;
2191: }
2192: CATCH(prb) {
2193: RESTORE_EXCEPTION;
2194: THROW_AGAIN(prb);
2195: } ENDTRY
2196: return res;
2197: }
2198:
1.1.1.3 ! root 2199: uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
! 2200: {
! 2201: uae_u32 res;
! 2202:
! 2203: res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
! 2204: SAVE_EXCEPTION;
! 2205: TRY(prb) {
! 2206: res |= mmu030_get_iword(addr + 2, fc);
! 2207: RESTORE_EXCEPTION;
! 2208: }
! 2209: CATCH(prb) {
! 2210: RESTORE_EXCEPTION;
! 2211: THROW_AGAIN(prb);
! 2212: } ENDTRY
! 2213: return res;
! 2214: }
! 2215:
1.1.1.2 root 2216: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
1.1 root 2217: {
2218: uae_u32 res;
2219:
2220: if (likely(!(addr & 1))) {
1.1.1.2 root 2221: res = (uae_u32)mmu030_get_generic(addr, fc, sz_word, sz_long, flags) << 16;
1.1 root 2222: SAVE_EXCEPTION;
2223: TRY(prb) {
1.1.1.2 root 2224: res |= mmu030_get_generic(addr + 2, fc, sz_word, sz_long, flags);
1.1 root 2225: RESTORE_EXCEPTION;
2226: }
2227: CATCH(prb) {
2228: RESTORE_EXCEPTION;
2229: THROW_AGAIN(prb);
2230: } ENDTRY
2231: } else {
1.1.1.2 root 2232: res = (uae_u32)mmu030_get_generic(addr, fc, sz_byte, sz_long, flags) << 8;
1.1 root 2233: SAVE_EXCEPTION;
2234: TRY(prb) {
1.1.1.2 root 2235: res = (res | mmu030_get_generic(addr + 1, fc, sz_byte, sz_long, flags)) << 8;
2236: res = (res | mmu030_get_generic(addr + 2, fc, sz_byte, sz_long, flags)) << 8;
2237: res |= mmu030_get_generic(addr + 3, fc, sz_byte, sz_long, flags);
1.1 root 2238: RESTORE_EXCEPTION;
2239: }
2240: CATCH(prb) {
2241: RESTORE_EXCEPTION;
2242: THROW_AGAIN(prb);
2243: } ENDTRY
2244: }
2245: return res;
2246: }
2247:
2248:
1.1.1.2 root 2249: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags)
1.1 root 2250: {
2251: SAVE_EXCEPTION;
2252: TRY(prb) {
2253: if (likely(!(addr & 1))) {
1.1.1.2 root 2254: mmu030_put_generic(addr, val >> 16, fc, sz_word, sz_long, flags);
2255: mmu030_put_generic(addr + 2, val, fc, sz_word, sz_long, flags);
1.1 root 2256: } else {
1.1.1.2 root 2257: mmu030_put_generic(addr, val >> 24, fc, sz_byte, sz_long, flags);
2258: mmu030_put_generic(addr + 1, val >> 16, fc, sz_byte, sz_long, flags);
2259: mmu030_put_generic(addr + 2, val >> 8, fc, sz_byte, sz_long, flags);
2260: mmu030_put_generic(addr + 3, val, fc, sz_byte, sz_long, flags);
1.1 root 2261: }
2262: RESTORE_EXCEPTION;
2263: }
2264: CATCH(prb) {
2265: RESTORE_EXCEPTION;
2266: regs.wb3_data = val;
2267: THROW_AGAIN(prb);
2268: } ENDTRY
2269: }
2270:
1.1.1.2 root 2271: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags)
1.1 root 2272: {
2273: SAVE_EXCEPTION;
2274: TRY(prb) {
1.1.1.2 root 2275: mmu030_put_generic(addr, val >> 8, fc, sz_byte, sz_word, flags);
2276: mmu030_put_generic(addr + 1, val, fc, sz_byte, sz_word, flags);
1.1 root 2277: RESTORE_EXCEPTION;
2278: }
2279: CATCH(prb) {
2280: RESTORE_EXCEPTION;
2281: regs.wb3_data = val;
2282: THROW_AGAIN(prb);
2283: } ENDTRY
2284: }
2285:
2286:
1.1.1.2 root 2287: /* Used by debugger */
2288: static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write) {
2289: uae_u32 page_index = addr & mmu030.translation.page.mask;
2290: uae_u32 addr_mask = mmu030.translation.page.imask;
2291:
2292: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
2293: physical_addr += page_index;
2294:
2295: if (mmu030.atc[l].physical.bus_error || (write && mmu030.atc[l].physical.write_protect)) {
2296: mmu030_page_fault(addr, write == 0, MMU030_SSW_SIZE_B, fc);
2297: return 0;
2298: }
2299:
2300: return physical_addr;
2301: }
2302: uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
2303: {
1.1.1.3 ! root 2304: int fc = (super ? 4 : 0) | (data ? 1 : 2);
! 2305: if ((fc==7) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (!mmu030.enabled)) {
! 2306: return addr;
1.1.1.2 root 2307: }
2308: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
2309:
2310: if (atc_line_num>=0) {
2311: return mmu030_get_addr_atc(addr, atc_line_num, fc, write);
2312: } else {
2313: mmu030_table_search(addr, fc, false, 0);
2314: return mmu030_get_addr_atc(addr, mmu030_logical_is_in_atc(addr,fc,write), fc, write);
2315: }
2316: }
2317:
1.1 root 2318: /* MMU Reset */
2319: void mmu030_reset(int hardreset)
2320: {
2321: /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
2322: mmu030.enabled = false;
1.1.1.2 root 2323: regs.mmu_page_size = 0;
1.1 root 2324: tc_030 &= ~TC_ENABLE_TRANSLATION;
2325: tt0_030 &= ~TT_ENABLE;
2326: tt1_030 &= ~TT_ENABLE;
2327: if (hardreset) {
2328: srp_030 = crp_030 = 0;
2329: tt0_030 = tt1_030 = tc_030 = 0;
2330: mmusr_030 = 0;
2331: mmu030_flush_atc_all();
2332: }
1.1.1.3 ! root 2333: mmu030_set_funcs();
! 2334: }
! 2335:
! 2336: void mmu030_set_funcs(void)
! 2337: {
! 2338: if (currprefs.mmu_model != 68030)
! 2339: return;
1.1 root 2340: }
2341:
2342:
2343: void m68k_do_rte_mmu030 (uaecptr a7)
2344: {
1.1.1.2 root 2345: // Restore access error exception state
2346:
2347: uae_u16 format = get_word_mmu030 (a7 + 6);
2348: uae_u16 frame = format >> 12;
2349: uae_u16 ssw = get_word_mmu030 (a7 + 10);
1.1.1.3 ! root 2350:
! 2351: // Fetch last word, real CPU does it to allow OS bus handler to map
! 2352: // the page if frame crosses pages and following page is not resident.
! 2353: if (frame == 0xb)
! 2354: get_word_mmu030(a7 + 92 - 2);
! 2355: else
! 2356: get_word_mmu030(a7 + 32 - 2);
! 2357:
1.1.1.2 root 2358: // Internal register, our opcode storage area
2359: mmu030_opcode = get_long_mmu030 (a7 + 0x14);
2360: // Misc state data
2361: mmu030_state[0] = get_word_mmu030 (a7 + 0x30);
2362: mmu030_state[1] = get_word_mmu030 (a7 + 0x32);
2363: mmu030_state[2] = get_word_mmu030 (a7 + 0x34);
2364: mmu030_disp_store[0] = get_long_mmu030 (a7 + 0x1c);
2365: mmu030_disp_store[1] = get_long_mmu030 (a7 + 0x1c + 4);
1.1.1.3 ! root 2366: if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
! 2367: mmu030_fmovem_store[0] = get_long_mmu030 (a7 + 0x5c - (7 + 1) * 4);
! 2368: mmu030_fmovem_store[1] = get_long_mmu030 (a7 + 0x5c - (8 + 1) * 4);
! 2369: }
1.1.1.2 root 2370: // Rerun "mmu030_opcode" using restored state.
2371: mmu030_retry = true;
2372:
2373: if (frame == 0xb) {
2374: uae_u16 idxsize = get_word_mmu030 (a7 + 0x36);
1.1.1.3 ! root 2375: int i;
! 2376: for (i = 0; i < idxsize + 1; i++) {
1.1.1.2 root 2377: mmu030_ad[i].done = i < idxsize;
2378: mmu030_ad[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4);
2379: }
2380: mmu030_ad[idxsize + 1].done = false;
2381: // did we have data fault but DF bit cleared?
2382: if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
2383: // DF not set: mark access as done
2384: if (ssw & MMU030_SSW_RM) {
2385: // Read-Modify-Write: whole instruction is considered done
2386: write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
2387: mmu030_retry = false;
2388: } else if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
2389: // if movem, skip next move
2390: mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
2391: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
2392: } else {
2393: mmu030_ad[idxsize].done = true;
2394: if (ssw & MMU030_SSW_RW) {
2395: // Read and no DF: use value in data input buffer
2396: mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
2397: mmu030_ad[idxsize].val = mmu030_data_buffer;
2398: }
2399: }
2400: }
2401: // did we have ins fault and RB bit cleared?
2402: if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
2403: uae_u16 stageb = get_word_mmu030 (a7 + 0x0e);
2404: if (mmu030_opcode == -1) {
2405: mmu030_opcode_stageb = stageb;
2406: write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb);
2407: } else {
2408: mmu030_ad[idxsize].done = true;
2409: mmu030_ad[idxsize].val = stageb;
2410: write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode, stageb);
2411: }
2412: }
2413: m68k_areg (regs, 7) += 92;
2414: } else {
2415: m68k_areg (regs, 7) += 32;
1.1 root 2416: }
2417: }
2418:
2419: void flush_mmu030 (uaecptr addr, int n)
2420: {
2421: }
2422:
2423: void m68k_do_rts_mmu030 (void)
2424: {
1.1.1.2 root 2425: m68k_setpc (get_long_mmu030_state (m68k_areg (regs, 7)));
1.1 root 2426: m68k_areg (regs, 7) += 4;
2427: }
2428:
2429: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
2430: {
1.1.1.2 root 2431: put_long_mmu030_state (m68k_areg (regs, 7) - 4, oldpc);
1.1 root 2432: m68k_areg (regs, 7) -= 4;
2433: m68k_incpci (offset);
2434: }
1.1.1.2 root 2435:
2436: uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx)
2437: {
2438: uae_u16 dp;
2439: int reg;
2440: uae_u32 v;
2441: int oldidx;
2442: int pcadd = 0;
2443:
2444: // we need to do this hack here because in worst case we don't have enough
2445: // stack frame space to store two very large 020 addressing mode access state
2446: // + whatever the instruction itself does.
2447:
2448: if (mmu030_state[1] & (1 << idx)) {
2449: m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
2450: return mmu030_disp_store[idx];
2451: }
2452:
2453: oldidx = mmu030_idx;
2454: dp = next_iword_mmu030_state ();
2455: pcadd += 1;
2456:
2457: reg = (dp >> 12) & 15;
2458: uae_s32 regd = regs.regs[reg];
2459: if ((dp & 0x800) == 0)
2460: regd = (uae_s32)(uae_s16)regd;
2461: regd <<= (dp >> 9) & 3;
2462: if (dp & 0x100) {
2463: uae_s32 outer = 0;
2464: if (dp & 0x80)
2465: base = 0;
2466: if (dp & 0x40)
2467: regd = 0;
2468:
2469: if ((dp & 0x30) == 0x20) {
2470: base += (uae_s32)(uae_s16) next_iword_mmu030_state ();
2471: pcadd += 1;
2472: }
2473: if ((dp & 0x30) == 0x30) {
2474: base += next_ilong_mmu030_state ();
2475: pcadd += 2;
2476: }
2477:
2478: if ((dp & 0x3) == 0x2) {
2479: outer = (uae_s32)(uae_s16) next_iword_mmu030_state ();
2480: pcadd += 1;
2481: }
2482: if ((dp & 0x3) == 0x3) {
2483: outer = next_ilong_mmu030_state ();
2484: pcadd += 2;
2485: }
2486:
2487: if ((dp & 0x4) == 0) {
2488: base += regd;
2489: }
2490: if (dp & 0x3) {
2491: base = get_long_mmu030_state (base);
2492: }
2493: if (dp & 0x4) {
2494: base += regd;
2495: }
2496: v = base + outer;
2497: } else {
2498: v = base + (uae_s32)((uae_s8)dp) + regd;
2499: }
2500:
2501: mmu030_state[1] |= 1 << idx;
2502: mmu030_state[2] |= pcadd << (idx * 4);
2503: mmu030_disp_store[idx] = v;
2504: mmu030_idx = oldidx;
2505: mmu030_ad[mmu030_idx].done = false;
2506:
2507: return v;
2508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.