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