|
|
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.4 ! root 1719:
! 1720: static uae_u32 mmu030_get_ilong_atc(uaecptr addr, int l, uae_u32 fc) {
1.1.1.3 root 1721: uae_u32 page_index = addr & mmu030.translation.page.mask;
1722: uae_u32 addr_mask = mmu030.translation.page.imask;
1723:
1724: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1725: #if MMU030_ATC_DBG_MSG
1726: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
1727: physical_addr, page_index, phys_get_long(physical_addr + page_index));
1728: #endif
1729: physical_addr += page_index;
1.1 root 1730:
1.1.1.3 root 1731: if (mmu030.atc[l].physical.bus_error) {
1732: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
1733: return 0;
1734: }
1735:
1736: return x_phys_get_ilong(physical_addr);
1737: }
1738:
1739: uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc) {
1.1 root 1740: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.3 root 1741: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1742:
1743: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1744: #if MMU030_ATC_DBG_MSG
1.1.1.3 root 1745: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
1.1 root 1746: physical_addr, page_index, phys_get_word(physical_addr+page_index));
1747: #endif
1748: physical_addr += page_index;
1749:
1750: if (mmu030.atc[l].physical.bus_error) {
1.1.1.3 root 1751: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
1.1 root 1752: return 0;
1753: }
1754:
1755: return phys_get_word(physical_addr);
1756: }
1757:
1.1.1.4 ! root 1758: static uae_u16 mmu030_get_iword_atc(uaecptr addr, int l, uae_u32 fc) {
1.1.1.3 root 1759: uae_u32 page_index = addr & mmu030.translation.page.mask;
1760: uae_u32 addr_mask = mmu030.translation.page.imask;
1761:
1762: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1763: #if MMU030_ATC_DBG_MSG
1764: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
1765: physical_addr, page_index, phys_get_word(physical_addr + page_index));
1766: #endif
1767: physical_addr += page_index;
1768:
1769: if (mmu030.atc[l].physical.bus_error) {
1770: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
1771: return 0;
1772: }
1773:
1774: return x_phys_get_iword(physical_addr);
1775: }
1776:
1777: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc) {
1.1 root 1778: uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.3 root 1779: uae_u32 addr_mask = mmu030.translation.page.imask;
1.1 root 1780:
1781: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1782: #if MMU030_ATC_DBG_MSG
1.1.1.3 root 1783: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
1.1 root 1784: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1785: #endif
1786: physical_addr += page_index;
1787:
1788: if (mmu030.atc[l].physical.bus_error) {
1.1.1.3 root 1789: mmu030_page_fault(addr, true, MMU030_SSW_SIZE_B, fc);
1.1 root 1790: return 0;
1791: }
1792:
1793: return phys_get_byte(physical_addr);
1794: }
1795:
1.1.1.3 root 1796: /* Generic versions of above */
1797: void mmu030_put_atc_generic(uaecptr addr, uae_u32 val, int l, uae_u32 fc, int size, int flags) {
1798: uae_u32 page_index = addr & mmu030.translation.page.mask;
1799: uae_u32 addr_mask = mmu030.translation.page.imask;
1800:
1801: uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1802: #if MMU030_ATC_DBG_MSG
1803: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"),
1804: l, physical_addr, page_index, val);
1805: #endif
1806: physical_addr += page_index;
1807:
1808: if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
1809: mmu030_page_fault(addr, false, flags, fc);
1810: return;
1811: }
1812: if (size == sz_byte)
1813: phys_put_byte(physical_addr, val);
1814: else if (size == sz_word)
1815: phys_put_word(physical_addr, val);
1816: else
1817: phys_put_long(physical_addr, val);
1818:
1819: }
1.1.1.4 ! root 1820:
1.1.1.3 root 1821: uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite) {
1822: uae_u32 page_index = addr & mmu030.translation.page.mask;
1823: uae_u32 addr_mask = mmu030.translation.page.imask;
1824:
1825: uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1826: #if MMU030_ATC_DBG_MSG
1827: write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
1828: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1829: #endif
1830: physical_addr += page_index;
1831:
1832: if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
1833: mmu030_page_fault(addr, true, flags, fc);
1834: return 0;
1835: }
1836: if (size == sz_byte)
1837: return phys_get_byte(physical_addr);
1838: else if (size == sz_word)
1839: return phys_get_word(physical_addr);
1840: return phys_get_long(physical_addr);
1841: }
1842:
1.1 root 1843:
1844: /* This function checks if a certain logical address is in the ATC
1845: * by comparing the logical address and function code to the values
1846: * stored in the ATC entries. If a matching entry is found it sets
1847: * the history bit and returns the cache index of the entry. */
1848: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1849: uaecptr logical_addr = 0;
1.1.1.3 root 1850: uae_u32 addr_mask = mmu030.translation.page.imask;
1851: uae_u32 maddr = addr & addr_mask;
1852: int offset = (maddr >> mmu030.translation.page.size) & 0x1f;
1853:
1854: int i, index;
1855: index = atcindextable[offset];
1.1 root 1856: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1.1.1.3 root 1857: logical_addr = mmu030.atc[index].logical.addr;
1.1 root 1858: /* If actual address matches address in ATC */
1.1.1.3 root 1859: if (maddr==(logical_addr&addr_mask) &&
1860: (mmu030.atc[index].logical.fc==fc) &&
1861: mmu030.atc[index].logical.valid) {
1862: /* If access is valid write and M bit is not set, invalidate entry
1863: * else return index */
1864: if (!write || mmu030.atc[index].physical.modified ||
1865: mmu030.atc[index].physical.write_protect ||
1866: mmu030.atc[index].physical.bus_error) {
1.1 root 1867: /* Maintain history bit */
1.1.1.3 root 1868: mmu030_atc_handle_history_bit(index);
1869: atcindextable[offset] = index;
1870: return index;
1871: } else {
1872: mmu030.atc[index].logical.valid = false;
1873: }
1874: }
1875: index++;
1876: if (index >= ATC030_NUM_ENTRIES)
1877: index = 0;
1.1 root 1878: }
1.1.1.3 root 1879: return -1;
1.1 root 1880: }
1881:
1882: void mmu030_atc_handle_history_bit(int entry_num) {
1883: int j;
1884: mmu030.atc[entry_num].mru = 1;
1885: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1886: if (!mmu030.atc[j].mru)
1887: break;
1888: }
1889: /* If there are no more zero-bits, reset all */
1890: if (j==ATC030_NUM_ENTRIES) {
1891: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1892: mmu030.atc[j].mru = 0;
1893: }
1894: mmu030.atc[entry_num].mru = 1;
1895: #if MMU030_ATC_DBG_MSG
1.1.1.3 root 1896: write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
1.1 root 1897: #endif
1.1.1.3 root 1898: }
1.1 root 1899: }
1900:
1901:
1902: /* Memory access functions:
1903: * If the address matches one of the transparent translation registers
1904: * use it directly as physical address, else check ATC for the
1905: * logical address. If the logical address is not resident in the ATC
1906: * create a new ATC entry and then look up the physical address.
1907: */
1908:
1.1.1.3 root 1909: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) {
1.1 root 1910:
1911: // addr,super,write
1.1.1.3 root 1912: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
1.1 root 1913: phys_put_long(addr,val);
1914: return;
1915: }
1916:
1917: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1918:
1.1.1.3 root 1919: if (atc_line_num>=0) {
1920: mmu030_put_long_atc(addr, val, atc_line_num, fc);
1.1 root 1921: } else {
1922: mmu030_table_search(addr,fc,true,0);
1.1.1.3 root 1923: mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1924: }
1925: }
1926:
1.1.1.3 root 1927: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) {
1.1 root 1928:
1929: // addr,super,write
1.1.1.3 root 1930: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,true)) || (fc==7)) {
1.1 root 1931: phys_put_word(addr,val);
1932: return;
1933: }
1934:
1935: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1936:
1.1.1.3 root 1937: if (atc_line_num>=0) {
1938: mmu030_put_word_atc(addr, val, atc_line_num, fc);
1.1 root 1939: } else {
1940: mmu030_table_search(addr, fc, true, 0);
1.1.1.3 root 1941: mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1942: }
1943: }
1944:
1.1.1.3 root 1945: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) {
1.1 root 1946:
1947: // addr,super,write
1.1.1.3 root 1948: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
1.1 root 1949: phys_put_byte(addr,val);
1950: return;
1951: }
1952:
1953: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1954:
1.1.1.3 root 1955: if (atc_line_num>=0) {
1956: mmu030_put_byte_atc(addr, val, atc_line_num, fc);
1.1 root 1957: } else {
1958: mmu030_table_search(addr, fc, true, 0);
1.1.1.3 root 1959: mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
1.1 root 1960: }
1961: }
1962:
1.1.1.3 root 1963: uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
1964:
1965: // addr,super,write
1966: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
1967: return x_phys_get_ilong(addr);
1968: }
1969:
1970: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1971:
1972: if (atc_line_num >= 0) {
1973: return mmu030_get_ilong_atc(addr, atc_line_num, fc);
1974: }
1975: else {
1976: mmu030_table_search(addr, fc, false, 0);
1977: return mmu030_get_ilong_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
1978: }
1979: }
1980: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) {
1.1 root 1981:
1982: // addr,super,write
1.1.1.3 root 1983: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
1.1 root 1984: return phys_get_long(addr);
1985: }
1986:
1987: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1988:
1.1.1.3 root 1989: if (atc_line_num>=0) {
1990: return mmu030_get_long_atc(addr, atc_line_num, fc);
1.1 root 1991: } else {
1992: mmu030_table_search(addr, fc, false, 0);
1.1.1.3 root 1993: return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
1.1 root 1994: }
1995: }
1996:
1.1.1.3 root 1997: uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
1998:
1999: // addr,super,write
2000: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, false)) || (fc == 7)) {
2001: return x_phys_get_iword(addr);
2002: }
2003:
2004: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2005:
2006: if (atc_line_num >= 0) {
2007: return mmu030_get_iword_atc(addr, atc_line_num, fc);
2008: } else {
2009: mmu030_table_search(addr, fc, false, 0);
2010: return mmu030_get_iword_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
2011: }
2012: }
2013: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) {
1.1 root 2014:
2015: // addr,super,write
1.1.1.3 root 2016: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
1.1 root 2017: return phys_get_word(addr);
2018: }
2019:
2020: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2021:
1.1.1.3 root 2022: if (atc_line_num>=0) {
2023: return mmu030_get_word_atc(addr, atc_line_num, fc);
1.1 root 2024: } else {
2025: mmu030_table_search(addr, fc, false, 0);
1.1.1.3 root 2026: return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
1.1 root 2027: }
2028: }
2029:
1.1.1.3 root 2030: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) {
1.1 root 2031:
2032: // addr,super,write
1.1.1.3 root 2033: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
1.1 root 2034: return phys_get_byte(addr);
2035: }
2036:
2037: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2038:
1.1.1.3 root 2039: if (atc_line_num>=0) {
2040: return mmu030_get_byte_atc(addr, atc_line_num, fc);
2041: } else {
2042: mmu030_table_search(addr, fc, false, 0);
2043: return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
2044: }
2045: }
2046:
2047:
2048: /* Not commonly used access function */
2049: void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int accesssize, int flags) {
2050:
2051: // addr,super,write
2052: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr, fc, true)) || (fc==7)) {
2053: if (size == sz_byte)
2054: phys_put_byte(addr, val);
2055: else if (size == sz_word)
2056: phys_put_word(addr, val);
2057: else
2058: phys_put_long(addr, val);
2059: return;
2060: }
2061:
2062: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2063: if (atc_line_num>=0) {
2064: mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
2065: } else {
2066: mmu030_table_search(addr, fc, true, 0);
2067: atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2068: if (accesssize == sz_byte)
2069: flags |= MMU030_SSW_SIZE_B;
2070: else if (accesssize == sz_word)
2071: flags |= MMU030_SSW_SIZE_W;
2072: mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
2073: }
2074: }
2075: static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
2076:
2077: // addr,super,write
2078: if ((!mmu030.enabled) || (mmu030_match_lrmw_ttr_access(addr,fc)) || (fc==7)) {
2079: if (size == sz_byte)
2080: return phys_get_byte(addr);
2081: else if (size == sz_word)
2082: return phys_get_word(addr);
2083: return phys_get_long(addr);
2084: }
2085:
2086: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2087: if (atc_line_num>=0) {
2088: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
2089: } else {
2090: mmu030_table_search(addr, fc, true, 0);
2091: atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2092: if (accesssize == sz_byte)
2093: flags |= MMU030_SSW_SIZE_B;
2094: else if (accesssize == sz_word)
2095: flags |= MMU030_SSW_SIZE_W;
2096: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
2097: }
2098: }
2099: uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
2100: if (flags & MMU030_SSW_RM) {
2101: return mmu030_get_generic_lrmw(addr, fc, size, accesssize, flags);
2102: }
2103: // addr,super,write
2104: if ((!mmu030.enabled) || (mmu030_match_ttr_access(addr,fc,false)) || (fc==7)) {
2105: if (size == sz_byte)
2106: return phys_get_byte(addr);
2107: else if (size == sz_word)
2108: return phys_get_word(addr);
2109: return phys_get_long(addr);
2110: }
2111:
2112: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2113: if (atc_line_num>=0) {
2114: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
1.1 root 2115: } else {
2116: mmu030_table_search(addr, fc, false, 0);
1.1.1.3 root 2117: atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2118: if (accesssize == sz_byte)
2119: flags |= MMU030_SSW_SIZE_B;
2120: else if (accesssize == sz_word)
2121: flags |= MMU030_SSW_SIZE_W;
2122: return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
1.1 root 2123: }
2124: }
2125:
2126:
1.1.1.3 root 2127: /* Locked RMW is rarely used */
2128: uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
2129: {
2130: uae_u32 fc = (regs.s ? 4 : 0) | 1;
2131: if (size == sz_byte) {
2132: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2133: } else if (size == sz_word) {
2134: if (unlikely(is_unaligned(addr, 2)))
2135: return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM);
2136: else
2137: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2138: } else {
2139: if (unlikely(is_unaligned(addr, 4)))
2140: return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM);
2141: else
2142: return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
2143: }
2144: }
2145: void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
2146: {
2147: uae_u32 fc = (regs.s ? 4 : 0) | 1;
2148: if (size == sz_byte) {
2149: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2150: } else if (size == sz_word) {
2151: if (unlikely(is_unaligned(addr, 2)))
2152: mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM);
2153: else
2154: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2155: } else {
2156: if (unlikely(is_unaligned(addr, 4)))
2157: mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM);
2158: else
2159: mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
2160: }
2161: }
2162: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags)
1.1 root 2163: {
2164: uae_u16 res;
1.1.1.3 root 2165:
2166: res = (uae_u16)mmu030_get_generic(addr, fc, sz_byte, sz_word, flags) << 8;
1.1 root 2167: SAVE_EXCEPTION;
2168: TRY(prb) {
1.1.1.3 root 2169: res |= mmu030_get_generic(addr + 1, fc, sz_byte, sz_word, flags);
1.1 root 2170: RESTORE_EXCEPTION;
2171: }
2172: CATCH(prb) {
2173: RESTORE_EXCEPTION;
2174: THROW_AGAIN(prb);
2175: } ENDTRY
2176: return res;
2177: }
2178:
1.1.1.3 root 2179: uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
1.1 root 2180: {
2181: uae_u32 res;
2182:
1.1.1.3 root 2183: res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
2184: SAVE_EXCEPTION;
2185: TRY(prb) {
2186: res |= mmu030_get_iword(addr + 2, fc);
2187: RESTORE_EXCEPTION;
2188: }
2189: CATCH(prb) {
2190: RESTORE_EXCEPTION;
2191: THROW_AGAIN(prb);
2192: } ENDTRY
2193: return res;
2194: }
2195:
2196: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
2197: {
2198: uae_u32 res;
2199:
1.1 root 2200: if (likely(!(addr & 1))) {
1.1.1.3 root 2201: res = (uae_u32)mmu030_get_generic(addr, fc, sz_word, sz_long, flags) << 16;
1.1 root 2202: SAVE_EXCEPTION;
2203: TRY(prb) {
1.1.1.3 root 2204: res |= mmu030_get_generic(addr + 2, fc, sz_word, sz_long, flags);
1.1 root 2205: RESTORE_EXCEPTION;
2206: }
2207: CATCH(prb) {
2208: RESTORE_EXCEPTION;
2209: THROW_AGAIN(prb);
2210: } ENDTRY
2211: } else {
1.1.1.3 root 2212: res = (uae_u32)mmu030_get_generic(addr, fc, sz_byte, sz_long, flags) << 8;
1.1 root 2213: SAVE_EXCEPTION;
2214: TRY(prb) {
1.1.1.3 root 2215: res = (res | mmu030_get_generic(addr + 1, fc, sz_byte, sz_long, flags)) << 8;
2216: res = (res | mmu030_get_generic(addr + 2, fc, sz_byte, sz_long, flags)) << 8;
2217: res |= mmu030_get_generic(addr + 3, fc, sz_byte, sz_long, flags);
1.1 root 2218: RESTORE_EXCEPTION;
2219: }
2220: CATCH(prb) {
2221: RESTORE_EXCEPTION;
2222: THROW_AGAIN(prb);
2223: } ENDTRY
2224: }
2225: return res;
2226: }
2227:
2228:
1.1.1.3 root 2229: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags)
1.1 root 2230: {
2231: SAVE_EXCEPTION;
2232: TRY(prb) {
2233: if (likely(!(addr & 1))) {
1.1.1.3 root 2234: mmu030_put_generic(addr, val >> 16, fc, sz_word, sz_long, flags);
2235: mmu030_put_generic(addr + 2, val, fc, sz_word, sz_long, flags);
1.1 root 2236: } else {
1.1.1.3 root 2237: mmu030_put_generic(addr, val >> 24, fc, sz_byte, sz_long, flags);
2238: mmu030_put_generic(addr + 1, val >> 16, fc, sz_byte, sz_long, flags);
2239: mmu030_put_generic(addr + 2, val >> 8, fc, sz_byte, sz_long, flags);
2240: mmu030_put_generic(addr + 3, val, fc, sz_byte, sz_long, flags);
1.1 root 2241: }
2242: RESTORE_EXCEPTION;
2243: }
2244: CATCH(prb) {
2245: RESTORE_EXCEPTION;
2246: regs.wb3_data = val;
2247: THROW_AGAIN(prb);
2248: } ENDTRY
2249: }
2250:
1.1.1.3 root 2251: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags)
1.1 root 2252: {
2253: SAVE_EXCEPTION;
2254: TRY(prb) {
1.1.1.3 root 2255: mmu030_put_generic(addr, val >> 8, fc, sz_byte, sz_word, flags);
2256: mmu030_put_generic(addr + 1, val, fc, sz_byte, sz_word, flags);
1.1 root 2257: RESTORE_EXCEPTION;
2258: }
2259: CATCH(prb) {
2260: RESTORE_EXCEPTION;
2261: regs.wb3_data = val;
2262: THROW_AGAIN(prb);
2263: } ENDTRY
2264: }
2265:
2266:
1.1.1.3 root 2267: /* Used by debugger */
2268: static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write) {
2269: uae_u32 page_index = addr & mmu030.translation.page.mask;
2270: uae_u32 addr_mask = mmu030.translation.page.imask;
2271:
2272: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
2273: physical_addr += page_index;
2274:
2275: if (mmu030.atc[l].physical.bus_error || (write && mmu030.atc[l].physical.write_protect)) {
2276: mmu030_page_fault(addr, write == 0, MMU030_SSW_SIZE_B, fc);
2277: return 0;
2278: }
2279:
2280: return physical_addr;
2281: }
2282: uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
2283: {
2284: int fc = (super ? 4 : 0) | (data ? 1 : 2);
2285: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (fc==7)) {
2286: return addr;
2287: }
2288: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
2289:
2290: if (atc_line_num>=0) {
2291: return mmu030_get_addr_atc(addr, atc_line_num, fc, write);
2292: } else {
2293: mmu030_table_search(addr, fc, false, 0);
2294: return mmu030_get_addr_atc(addr, mmu030_logical_is_in_atc(addr,fc,write), fc, write);
2295: }
2296: }
2297:
2298: #ifndef WINUAE_FOR_HATARI
2299: static uae_u32 get_dcache_byte(uaecptr addr)
2300: {
2301: return read_dcache030(addr, 0);
2302: }
2303: static uae_u32 get_dcache_word(uaecptr addr)
2304: {
2305: return read_dcache030(addr, 1);
2306: }
2307: static uae_u32 get_dcache_long(uaecptr addr)
2308: {
2309: return read_dcache030(addr, 2);
2310: }
2311: static void put_dcache_byte(uaecptr addr, uae_u32 v)
2312: {
2313: write_dcache030(addr, v, 0);
2314: }
2315: static void put_dcache_word(uaecptr addr, uae_u32 v)
2316: {
2317: write_dcache030(addr, v, 1);
2318: }
2319: static void put_dcache_long(uaecptr addr, uae_u32 v)
2320: {
2321: write_dcache030(addr, v, 2);
2322: }
2323: #endif
2324:
1.1 root 2325: /* MMU Reset */
2326: void mmu030_reset(int hardreset)
2327: {
1.1.1.3 root 2328: /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
2329: mmu030.enabled = false;
2330: regs.mmu_page_size = 0;
1.1 root 2331: tc_030 &= ~TC_ENABLE_TRANSLATION;
2332: tt0_030 &= ~TT_ENABLE;
2333: tt1_030 &= ~TT_ENABLE;
2334: if (hardreset) {
2335: srp_030 = crp_030 = 0;
2336: tt0_030 = tt1_030 = tc_030 = 0;
1.1.1.3 root 2337: mmusr_030 = 0;
2338: mmu030_flush_atc_all();
2339: }
2340: mmu030_set_funcs();
2341: }
2342:
2343: void mmu030_set_funcs(void)
2344: {
2345: if (currprefs.mmu_model != 68030)
2346: return;
2347: if (currprefs.cpu_cycle_exact || currprefs.cpu_compatible) {
2348: x_phys_get_iword = get_word_icache030;
2349: x_phys_get_ilong = get_long_icache030;
2350: } else {
2351: x_phys_get_iword = phys_get_word;
2352: x_phys_get_ilong = phys_get_long;
1.1 root 2353: }
2354: }
2355:
2356:
2357: void m68k_do_rte_mmu030 (uaecptr a7)
2358: {
1.1.1.3 root 2359: // Restore access error exception state
2360:
2361: uae_u16 format = get_word_mmu030 (a7 + 6);
2362: uae_u16 frame = format >> 12;
2363: uae_u16 ssw = get_word_mmu030 (a7 + 10);
2364:
2365: // Fetch last word, real CPU does it to allow OS bus handler to map
2366: // the page if frame crosses pages and following page is not resident.
2367: if (frame == 0xb)
2368: get_word_mmu030(a7 + 92 - 2);
2369: else
2370: get_word_mmu030(a7 + 32 - 2);
2371:
2372: // Internal register, our opcode storage area
2373: mmu030_opcode = get_long_mmu030 (a7 + 0x14);
2374: // Misc state data
2375: mmu030_state[0] = get_word_mmu030 (a7 + 0x30);
2376: mmu030_state[1] = get_word_mmu030 (a7 + 0x32);
2377: mmu030_state[2] = get_word_mmu030 (a7 + 0x34);
2378: mmu030_disp_store[0] = get_long_mmu030 (a7 + 0x1c);
2379: mmu030_disp_store[1] = get_long_mmu030 (a7 + 0x1c + 4);
2380: if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
2381: mmu030_fmovem_store[0] = get_long_mmu030 (a7 + 0x5c - (7 + 1) * 4);
2382: mmu030_fmovem_store[1] = get_long_mmu030 (a7 + 0x5c - (8 + 1) * 4);
2383: }
2384: // Rerun "mmu030_opcode" using restored state.
2385: mmu030_retry = true;
2386:
2387: if (frame == 0xb) {
2388: uae_u16 idxsize = get_word_mmu030 (a7 + 0x36);
2389: int i;
2390: for (i = 0; i < idxsize + 1; i++) {
2391: mmu030_ad[i].done = i < idxsize;
2392: mmu030_ad[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4);
2393: }
2394: mmu030_ad[idxsize + 1].done = false;
2395: // did we have data fault but DF bit cleared?
2396: if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
2397: // DF not set: mark access as done
2398: if (ssw & MMU030_SSW_RM) {
2399: // Read-Modify-Write: whole instruction is considered done
2400: write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
2401: mmu030_retry = false;
2402: } else if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
2403: // if movem, skip next move
2404: mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
2405: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
2406: } else {
2407: mmu030_ad[idxsize].done = true;
2408: if (ssw & MMU030_SSW_RW) {
2409: // Read and no DF: use value in data input buffer
2410: mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
2411: mmu030_ad[idxsize].val = mmu030_data_buffer;
2412: }
2413: }
2414: }
2415: // did we have ins fault and RB bit cleared?
2416: if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
2417: uae_u16 stageb = get_word_mmu030 (a7 + 0x0e);
2418: if (mmu030_opcode == -1) {
2419: mmu030_opcode_stageb = stageb;
2420: write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb);
2421: } else {
2422: mmu030_ad[idxsize].done = true;
2423: mmu030_ad[idxsize].val = stageb;
2424: write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode, stageb);
2425: }
2426: }
2427: m68k_areg (regs, 7) += 92;
2428: } else {
2429: m68k_areg (regs, 7) += 32;
1.1 root 2430: }
2431: }
2432:
2433: void flush_mmu030 (uaecptr addr, int n)
2434: {
2435: }
2436:
2437: void m68k_do_rts_mmu030 (void)
2438: {
1.1.1.3 root 2439: m68k_setpc (get_long_mmu030_state (m68k_areg (regs, 7)));
1.1 root 2440: m68k_areg (regs, 7) += 4;
2441: }
2442:
2443: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
2444: {
1.1.1.3 root 2445: put_long_mmu030_state (m68k_areg (regs, 7) - 4, oldpc);
1.1 root 2446: m68k_areg (regs, 7) -= 4;
2447: m68k_incpci (offset);
2448: }
1.1.1.3 root 2449:
2450: uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx)
2451: {
2452: uae_u16 dp;
2453: int reg;
2454: uae_u32 v;
2455: int oldidx;
2456: int pcadd = 0;
2457:
2458: // we need to do this hack here because in worst case we don't have enough
2459: // stack frame space to store two very large 020 addressing mode access state
2460: // + whatever the instruction itself does.
2461:
2462: if (mmu030_state[1] & (1 << idx)) {
2463: m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
2464: return mmu030_disp_store[idx];
2465: }
2466:
2467: oldidx = mmu030_idx;
2468: dp = next_iword_mmu030_state ();
2469: pcadd += 1;
2470:
2471: reg = (dp >> 12) & 15;
2472: uae_s32 regd = regs.regs[reg];
2473: if ((dp & 0x800) == 0)
2474: regd = (uae_s32)(uae_s16)regd;
2475: regd <<= (dp >> 9) & 3;
2476: if (dp & 0x100) {
2477: uae_s32 outer = 0;
2478: if (dp & 0x80)
2479: base = 0;
2480: if (dp & 0x40)
2481: regd = 0;
2482:
2483: if ((dp & 0x30) == 0x20) {
2484: base += (uae_s32)(uae_s16) next_iword_mmu030_state ();
2485: pcadd += 1;
2486: }
2487: if ((dp & 0x30) == 0x30) {
2488: base += next_ilong_mmu030_state ();
2489: pcadd += 2;
2490: }
2491:
2492: if ((dp & 0x3) == 0x2) {
2493: outer = (uae_s32)(uae_s16) next_iword_mmu030_state ();
2494: pcadd += 1;
2495: }
2496: if ((dp & 0x3) == 0x3) {
2497: outer = next_ilong_mmu030_state ();
2498: pcadd += 2;
2499: }
2500:
2501: if ((dp & 0x4) == 0) {
2502: base += regd;
2503: }
2504: if (dp & 0x3) {
2505: base = get_long_mmu030_state (base);
2506: }
2507: if (dp & 0x4) {
2508: base += regd;
2509: }
2510: v = base + outer;
2511: } else {
2512: v = base + (uae_s32)((uae_s8)dp) + regd;
2513: }
2514:
2515: mmu030_state[1] |= 1 << idx;
2516: mmu030_state[2] |= pcadd << (idx * 4);
2517: mmu030_disp_store[idx] = v;
2518: mmu030_idx = oldidx;
2519: mmu030_ad[mmu030_idx].done = false;
2520:
2521: return v;
2522: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.