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