|
|
1.1 root 1: /* Emulation of MC68030 MMU
2: * This code has been written for Previous - a NeXT Computer emulator
3: *
4: * This file is distributed under the GNU General Public License, version 2
5: * or at your option any later version. Read the file gpl.txt for details.
6: *
7: *
8: * Written by Andreas Grabher
9: *
10: * Many thanks go to Thomas Huth and the Hatari community for helping
11: * to test and debug this code!
12: *
13: *
14: * Release notes:
15: * 01-09-2012: First release
16: * 29-09-2012: Improved function code handling
17: * 16-11-2012: Improved exception handling
18: *
19: *
20: * Known Problems:
21: * - Special Status Word (SSW) is not handled correctly
22: *
23: *
24: * TODO list:
25: * - Correctly handle Special Status Word. Now we use 68040 values.
26: * This also needs to be done in m68000.c, M68000_BusError!
27: * - Check if read-modify-write operations are correctly detected for
28: * handling transparent access (see TT matching functions)
29: * - If possible, test mmu030_table_search with all kinds of translations
30: * (early termination, invalid descriptors, bus errors, indirect
31: * descriptors, PTEST in different levels, etc).
32: * - Check which bits of an ATC entry should be set and which should be
33: * un-set, if an invalid translation occurs.
34: * - Handle cache inhibit bit when accessing ATC entries
35: */
36:
37:
38: #include "sysconfig.h"
39: #include "sysdeps.h"
40:
41: #include "options_cpu.h"
42: #include "memory.h"
43: #include "newcpu.h"
44: #include "main.h"
45: #include "m68000.h"
46: #include "hatari-glue.h"
47: #include "cpummu030.h"
48:
49:
50:
51: /* Definitions for debugging */
52: #define MMU030_DEBUG 1 /* enable(1) or disable(0) MMU general debugging messages */
53: #define MMU030_DEBUG_ERROR 1 /* enable(1) or disable(0) MMU error debugging messages */
54: #define MMU030_LOG_MEM_ACCESS 0 /* enable(1) or disable(0) ATC memory access logging */
55:
56:
57: #if MMU030_DEBUG
58: #define debug_msg write_log
59: #else
60: #define debug_msg(...)
61: #endif
62:
63: #if MMU030_DEBUG_ERROR
64: #define error_msg write_log
65: #else
66: #define error_msg(...)
67: #endif
68:
69: char table_letter[4] = {'A','B','C','D'}; /* only used for debugging messages */
70:
71:
72: /* Structs that hold all informations needed for address translation */
73:
74: /* ATC struct for 68030 */
75: #define ATC030_NUM_ENTRIES 22
76:
77: typedef struct {
78: struct {
79: uaecptr addr;
80: bool modified;
81: bool write_protect;
82: bool cache_inhibit;
83: bool bus_error;
84: } physical;
85:
86: struct {
87: uaecptr addr;
88: uae_u32 fc;
89: bool valid;
90: } logical;
91: /* history bit */
92: int mru;
93: } MMU030_ATC_LINE;
94:
95:
96: /* MMU struct for 68030 */
97: struct {
98:
99: /* Translation tables and page */
100: struct {
101: struct {
102: uae_u32 mask;
103: uae_u8 shift;
104: } table[4];
105:
106: struct {
107: uae_u32 mask;
108: uae_u8 size;
109: } page;
110:
111: uae_u8 init_shift;
112: uae_u8 last_table;
113: } translation;
114:
115: /* Transparent translation */
116: struct {
117: TT_info tt0;
118: TT_info tt1;
119: } transparent;
120:
121: /* Address translation cache */
122: MMU030_ATC_LINE atc[ATC030_NUM_ENTRIES];
123:
124: /* MMU condition */
125: bool enabled;
126: uae_u16 status;
127: } mmu030;
128:
129:
130:
131: /* MMU Status Register
132: *
133: * ---x ---x x-xx x---
134: * reserved (all 0)
135: *
136: * x--- ---- ---- ----
137: * bus error
138: *
139: * -x-- ---- ---- ----
140: * limit violation
141: *
142: * --x- ---- ---- ----
143: * supervisor only
144: *
145: * ---- x--- ---- ----
146: * write protected
147: *
148: * ---- -x-- ---- ----
149: * invalid
150: *
151: * ---- --x- ---- ----
152: * modified
153: *
154: * ---- ---- -x-- ----
155: * transparent access
156: *
157: * ---- ---- ---- -xxx
158: * number of levels (number of tables accessed during search)
159: *
160: */
161:
162: #define MMUSR_BUS_ERROR 0x8000
163: #define MMUSR_LIMIT_VIOLATION 0x4000
164: #define MMUSR_SUPER_VIOLATION 0x2000
165: #define MMUSR_WRITE_PROTECTED 0x0800
166: #define MMUSR_INVALID 0x0400
167: #define MMUSR_MODIFIED 0x0200
168: #define MMUSR_TRANSP_ACCESS 0x0040
169: #define MMUSR_NUM_LEVELS_MASK 0x0007
170:
171:
172:
173: /* -- MMU instructions -- */
174:
175: void mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
176: {
177: int preg = (next >> 10) & 31;
178: int rw = (next >> 9) & 1;
179: int fd = (next >> 8) & 1;
180:
181: switch (preg)
182: {
183: case 0x10: // TC
184: if (rw) {
185: debug_msg("PMOVE: read TC %08X\n", tc_030);
186: x_put_long (extra, tc_030);
187: } else {
188: tc_030 = x_get_long (extra);
189: debug_msg("PMOVE: write TC %08X\n", tc_030);
190: mmu030_decode_tc(tc_030);
191: }
192: break;
193: case 0x12: // SRP
194: if (rw) {
195: debug_msg("PMOVE: read SRP %08X%08X\n", srp_030>>32, srp_030);
196: x_put_long (extra, srp_030 >> 32);
197: x_put_long (extra + 4, srp_030);
198: } else {
199: srp_030 = (uae_u64)x_get_long (extra) << 32;
200: srp_030 |= x_get_long (extra + 4);
201: debug_msg("PMOVE: write SRP %08X%08X\n", srp_030>>32, srp_030);
202: mmu030_decode_rp(srp_030);
203: }
204: break;
205: case 0x13: // CRP
206: if (rw) {
207: debug_msg("PMOVE: read CRP %08X%08X\n", crp_030>>32, crp_030);
208: x_put_long (extra, crp_030 >> 32);
209: x_put_long (extra + 4, crp_030);
210: } else {
211: crp_030 = (uae_u64)x_get_long (extra) << 32;
212: crp_030 |= x_get_long (extra + 4);
213: debug_msg("PMOVE: write CRP %08X%08X\n", crp_030>>32, crp_030);
214: mmu030_decode_rp(crp_030);
215: }
216: break;
217: case 0x18: // MMUSR
218: if (rw) {
219: debug_msg("PMOVE: read MMUSR %04X\n", mmusr_030);
220: x_put_word (extra, mmusr_030);
221: } else {
222: mmusr_030 = x_get_word (extra);
223: debug_msg("PMOVE: write MMUSR %04X\n", mmusr_030);
224: }
225: break;
226: case 0x02: // TT0
227: if (rw) {
228: debug_msg("PMOVE: read TT0 %08X\n", tt0_030);
229: x_put_long (extra, tt0_030);
230: } else {
231: tt0_030 = x_get_long (extra);
232: debug_msg("PMOVE: write TT0 %08X\n", tt0_030);
233: mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
234: }
235: break;
236: case 0x03: // TT1
237: if (rw) {
238: debug_msg("PMOVE: read TT1 %08X\n", tt1_030);
239: x_put_long (extra, tt1_030);
240: } else {
241: tt1_030 = x_get_long (extra);
242: debug_msg("PMOVE: write TT1 %08X\n", tt1_030);
243: mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
244: }
245: break;
246: default:
247: error_msg("Bad PMOVE at %08x\n",m68k_getpc());
248: op_illg (opcode);
249: return;
250: }
251:
252: if (!fd && !rw && !(preg==0x18)) {
253: debug_msg("PMOVE: flush ATC\n");
254: mmu030_flush_atc_all();
255: }
256: }
257:
258: void mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
259: {
260: mmu030.status = mmusr_030 = 0;
261:
262: int level = (next&0x1C00)>>10;
263: int rw = (next >> 9) & 1;
264: int a = (next >> 8) & 1;
265: int areg = (next&0xE0)>>5;
266: uae_u32 fc = mmu_op30_helper_get_fc(next);
267:
268: bool write = rw ? false : true;
269:
270: uae_u32 ret = 0;
271:
272: /* Check this - datasheet says:
273: * "When the instruction specifies an address translation cache search
274: * with an address register operand, the MC68030 takes an F-line
275: * unimplemented instruction exception."
276: */
277: if (!level && a) {
278: error_msg("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n");
279: Exception(11, m68k_getpc(), M68000_EXC_SRC_CPU); /* F-line unimplemented instruction exception */
280: return;
281: }
282:
283: debug_msg("PTEST%c: addr = %08X, fc = %i, level = %i, ",
284: rw?'R':'W', extra, fc, level);
285: if (a) {
286: debug_msg("return descriptor to register A%i\n", areg);
287: } else {
288: debug_msg("do not return descriptor\n");
289: }
290:
291: if (!level) {
292: mmu030_ptest_atc_search(extra, fc, write);
293: } else {
294: ret = mmu030_ptest_table_search(extra, fc, write, level);
295: if (a) {
296: m68k_areg (regs, areg) = ret;
297: }
298: }
299: mmusr_030 = mmu030.status;
300:
301: debug_msg("PTEST status: %04X, B = %i, L = %i, S = %i, W = %i, I = %i, M = %i, T = %i, N = %i\n",
302: mmusr_030, (mmusr_030&MMUSR_BUS_ERROR)?1:0, (mmusr_030&MMUSR_LIMIT_VIOLATION)?1:0,
303: (mmusr_030&MMUSR_SUPER_VIOLATION)?1:0, (mmusr_030&MMUSR_WRITE_PROTECTED)?1:0,
304: (mmusr_030&MMUSR_INVALID)?1:0, (mmusr_030&MMUSR_MODIFIED)?1:0,
305: (mmusr_030&MMUSR_TRANSP_ACCESS)?1:0, mmusr_030&MMUSR_NUM_LEVELS_MASK);
306: }
307:
308: void mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
309: {
310: int rw = (next >> 9) & 1;
311: uae_u32 fc = mmu_op30_helper_get_fc(next);
312:
313: bool write = rw ? false : true;
314:
315: debug_msg("PLOAD%c: Create ATC entry for %08X, FC = %i\n", write?'W':'R', extra, fc);
316:
317: mmu030_flush_atc_page(extra);
318: mmu030_table_search(extra, fc, write, 0);
319: }
320:
321: void mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
322: {
323: uae_u16 mode = (next&0x1C00)>>10;
324: uae_u32 fc_mask = (uae_u32)(next&0x00E0)>>5;
325: uae_u32 fc_base = mmu_op30_helper_get_fc(next);
326:
327: switch (mode) {
328: case 0x1:
329: debug_msg("PFLUSH: Flush all entries\n");
330: mmu030_flush_atc_all();
331: break;
332: case 0x4:
333: debug_msg("PFLUSH: Flush by function code only\n");
334: debug_msg("PFLUSH: function code: base = %08X, mask = %08X\n", fc_base, fc_mask);
335: mmu030_flush_atc_fc(fc_base, fc_mask);
336: break;
337: case 0x6:
338: debug_msg("PFLUSH: Flush by function code and effective address\n");
339: debug_msg("PFLUSH: function code: base = %08X, mask = %08X\n", fc_base, fc_mask);
340: debug_msg("PFLUSH: effective address = %08X\n", extra);
341: mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
342: break;
343:
344: default:
345: error_msg("PFLUSH ERROR: bad mode! (%i)\n",mode);
346: break;
347: }
348: }
349:
350: /* -- Helper function for MMU instructions -- */
351: uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
352: switch (next&0x0018) {
353: case 0x0010:
354: return (next&0x7);
355: case 0x0008:
356: return (m68k_dreg(regs, next&0x7)&0x7);
357: case 0x0000:
358: if (next&1) {
359: return (regs.dfc&0x7);
360: } else {
361: return (regs.sfc&0x7);
362: }
363: default:
364: error_msg("MMU_OP30 ERROR: bad fc source! (%04X)\n",next&0x0018);
365: return 0;
366: }
367: }
368:
369:
370: /* -- ATC flushing functions -- */
371:
372: /* This function flushes ATC entries depending on their function code */
373: void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
374: int i;
375: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
376: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
377: mmu030.atc[i].logical.valid) {
378: mmu030.atc[i].logical.valid = false;
379: debug_msg("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
380: }
381: }
382: }
383:
384: /* This function flushes ATC entries depending on their logical address
385: * and their function code */
386: void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
387: int i;
388: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
389: if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
390: (mmu030.atc[i].logical.addr == (logical_addr&(~mmu030.translation.page.mask))) &&
391: mmu030.atc[i].logical.valid) {
392: mmu030.atc[i].logical.valid = false;
393: debug_msg("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
394: }
395: }
396: }
397:
398: /* This function flushes ATC entries depending on their logical address */
399: void mmu030_flush_atc_page(uaecptr logical_addr) {
400: int i;
401: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
402: if ((mmu030.atc[i].logical.addr == (logical_addr&(~mmu030.translation.page.mask))) &&
403: mmu030.atc[i].logical.valid) {
404: mmu030.atc[i].logical.valid = false;
405: debug_msg("ATC: Flushing %08X\n", mmu030.atc[i].physical.addr);
406: }
407: }
408: }
409:
410: /* This function flushes all ATC entries */
411: void mmu030_flush_atc_all(void) {
412: debug_msg("ATC: Flushing all entries\n");
413: int i;
414: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
415: mmu030.atc[i].logical.valid = false;
416: }
417: }
418:
419:
420: /* Transparent Translation Registers (TT0 and TT1)
421: *
422: * ---- ---- ---- ---- -xxx x--- x--- x---
423: * reserved, must be 0
424: *
425: * ---- ---- ---- ---- ---- ---- ---- -xxx
426: * function code mask (FC bits to be ignored)
427: *
428: * ---- ---- ---- ---- ---- ---- -xxx ----
429: * function code base (FC value for transparent block)
430: *
431: * ---- ---- ---- ---- ---- ---x ---- ----
432: * 0 = r/w field used, 1 = read and write is transparently translated
433: *
434: * ---- ---- ---- ---- ---- --x- ---- ----
435: * r/w field: 0 = write ..., 1 = read access transparent
436: *
437: * ---- ---- ---- ---- ---- -x-- ---- ----
438: * cache inhibit: 0 = caching allowed, 1 = caching inhibited
439: *
440: * ---- ---- ---- ---- x--- ---- ---- ----
441: * 0 = transparent translation enabled disabled, 1 = enabled
442: *
443: * ---- ---- xxxx xxxx ---- ---- ---- ----
444: * logical address mask
445: *
446: * xxxx xxxx ---- ---- ---- ---- ---- ----
447: * logical address base
448: *
449: */
450:
451:
452: #define TT_FC_MASK 0x00000007
453: #define TT_FC_BASE 0x00000070
454: #define TT_RWM 0x00000100
455: #define TT_RW 0x00000200
456: #define TT_CI 0x00000400
457: #define TT_ENABLE 0x00008000
458:
459: #define TT_ADDR_MASK 0x00FF0000
460: #define TT_ADDR_BASE 0xFF000000
461:
462: /* TT comparision results */
463: #define TT_NO_MATCH 0x1
464: #define TT_OK_MATCH 0x2
465: #define TT_NO_READ 0x4
466: #define TT_NO_WRITE 0x8
467:
468: TT_info mmu030_decode_tt(uae_u32 TT) {
469:
470: TT_info ret;
471:
472: ret.fc_mask = ~((TT&TT_FC_MASK)|0xFFFFFFF8);
473: ret.fc_base = (TT&TT_FC_BASE)>>4;
474: ret.addr_base = TT & TT_ADDR_BASE;
475: ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
476:
477: if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
478: write_log("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n");
479: }
480:
481: #if MMU030_DEBUG
482: write_log("\n");
483: write_log("TRANSPARENT TRANSLATION: %08X\n", TT);
484: write_log("\n");
485:
486: write_log("TT: transparent translation ");
487: if (TT&TT_ENABLE) {
488: write_log("enabled\n");
489: } else {
490: write_log("disabled\n");
491: return ret;
492: }
493:
494: write_log("TT: caching %s\n", (TT&TT_CI) ? "inhibited" : "enabled");
495: write_log("TT: read-modify-write ");
496: if (TT&TT_RWM) {
497: write_log("enabled\n");
498: } else {
499: write_log("disabled (%s only)\n", (TT&TT_RW) ? "read" : "write");
500: }
501: write_log("\n");
502: write_log("TT: function code base: %08X\n", ret.fc_base);
503: write_log("TT: function code mask: %08X\n", ret.fc_mask);
504: write_log("\n");
505: write_log("TT: address base: %08X\n", ret.addr_base);
506: write_log("TT: address mask: %08X\n", ret.addr_mask);
507: write_log("\n");
508: #endif
509:
510: return ret;
511: }
512:
513: /* This function compares the address with both transparent
514: * translation registers and returns the result */
515: int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
516: {
517: int tt0, tt1;
518:
519: bool cache_inhibit = false; /* TODO: pass to memory access function */
520:
521: tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
522: if (tt0&TT_OK_MATCH) {
523: cache_inhibit = (tt0_030&TT_CI) ? true : false;
524: }
525: tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
526: if (tt1&TT_OK_MATCH) {
527: if (!cache_inhibit) {
528: cache_inhibit = (tt1_030&TT_CI) ? true : false;
529: }
530: }
531:
532: return (tt0|tt1);
533: }
534:
535: /* This function checks if an address matches a transparent
536: * translation register */
537:
538: /* FIXME:
539: * If !(tt&TT_RMW) neither the read nor the write portion
540: * of a read-modify-write cycle is transparently translated! */
541:
542: int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
543: {
544: if (tt & TT_ENABLE) { /* transparent translation enabled */
545:
546: /* Compare actual function code with function code base using mask */
547: if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
548:
549: /* Compare actual address with address base using mask */
550: if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
551:
552: if (tt&TT_RWM) { /* r/w field disabled */
553: return TT_OK_MATCH;
554: } else {
555: if (tt&TT_RW) { /* read access transparent */
556: return write ? TT_NO_WRITE : TT_OK_MATCH;
557: } else { /* write access transparent */
558: return write ? TT_OK_MATCH : TT_NO_READ; /* TODO: check this! */
559: }
560: }
561: }
562: }
563: }
564: return TT_NO_MATCH;
565: }
566:
567:
568:
569: /* Translation Control Register:
570: *
571: * x--- ---- ---- ---- ---- ---- ---- ----
572: * translation: 1 = enable, 0 = disable
573: *
574: * ---- --x- ---- ---- ---- ---- ---- ----
575: * supervisor root: 1 = enable, 0 = disable
576: *
577: * ---- ---x ---- ---- ---- ---- ---- ----
578: * function code lookup: 1 = enable, 0 = disable
579: *
580: * ---- ---- xxxx ---- ---- ---- ---- ----
581: * page size:
582: * 1000 = 256 bytes
583: * 1001 = 512 bytes
584: * 1010 = 1 kB
585: * 1011 = 2 kB
586: * 1100 = 4 kB
587: * 1101 = 8 kB
588: * 1110 = 16 kB
589: * 1111 = 32 kB
590: *
591: * ---- ---- ---- xxxx ---- ---- ---- ----
592: * initial shift
593: *
594: * ---- ---- ---- ---- xxxx ---- ---- ----
595: * number of bits for table index A
596: *
597: * ---- ---- ---- ---- ---- xxxx ---- ----
598: * number of bits for table index B
599: *
600: * ---- ---- ---- ---- ---- ---- xxxx ----
601: * number of bits for table index C
602: *
603: * ---- ---- ---- ---- ---- ---- ---- xxxx
604: * number of bits for table index D
605: *
606: */
607:
608:
609: #define TC_ENABLE_TRANSLATION 0x80000000
610: #define TC_ENABLE_SUPERVISOR 0x02000000
611: #define TC_ENABLE_FCL 0x01000000
612:
613: #define TC_PS_MASK 0x00F00000
614: #define TC_IS_MASK 0x000F0000
615:
616: #define TC_TIA_MASK 0x0000F000
617: #define TC_TIB_MASK 0x00000F00
618: #define TC_TIC_MASK 0x000000F0
619: #define TC_TID_MASK 0x0000000F
620:
621:
622: void mmu030_decode_tc(uae_u32 TC) {
623:
624: /* Set MMU condition */
625: if (TC & TC_ENABLE_TRANSLATION) {
626: mmu030.enabled = true;
627: write_log("MMU enabled\n");
628: } else {
629: mmu030.enabled = false;
630: write_log("MMU disabled\n");
631: return;
632: }
633:
634: /* Note: 0 = Table A, 1 = Table B, 2 = Table C, 3 = Table D */
635: int i, j;
636: uae_u8 TI_bits[4] = {0,0,0,0};
637:
638: /* Reset variables before extracting new values from TC */
639: for (i = 0; i < 4; i++) {
640: mmu030.translation.table[i].mask = 0;
641: mmu030.translation.table[i].shift = 0;
642: }
643: mmu030.translation.page.mask = 0;
644:
645:
646: /* Extract initial shift and page size values from TC register */
647: mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
648: mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
649:
650: if (mmu030.translation.page.size<8) {
651: error_msg("MMU Configuration Exception: Bad value in TC register! (bad page size: %i byte)\n",
652: 1<<mmu030.translation.page.size);
653: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
654: return;
655: }
656: /* Build the page mask */
657: for (i = 0; i < mmu030.translation.page.size; i++) {
658: mmu030.translation.page.mask |= (1<<i);
659: }
660:
661:
662: /* Calculate masks and shifts for later extracting table indices
663: * from logical addresses using: index = (addr&mask)>>shift */
664:
665: /* Get number of bits for each table index */
666: for (i = 0; i < 4; i++) {
667: j = (3-i)*4;
668: TI_bits[i] = (TC >> j) & 0xF;
669: }
670:
671: /* Calculate masks and shifts for each table */
672: mmu030.translation.last_table = 0;
673: uae_u8 shift = 32 - mmu030.translation.init_shift;
674: for (i = 0; (i < 4) && TI_bits[i]; i++) {
675: /* Get the shift */
676: shift -= TI_bits[i];
677: mmu030.translation.table[i].shift = shift;
678: /* Build the mask */
679: for (j = 0; j < TI_bits[i]; j++) {
680: mmu030.translation.table[i].mask |= (1<<(mmu030.translation.table[i].shift + j));
681: }
682: /* Update until reaching the last table */
683: mmu030.translation.last_table = i;
684: }
685:
686:
687: /* TI fields are summed up until a zero field is reached (see above
688: * loop). The sum of all TI field values plus page size and initial
689: * shift has to be 32: IS + PS + TIA + TIB + TIC + TID = 32 */
690: if ((shift-mmu030.translation.page.size)!=0) {
691: error_msg("MMU Configuration Exception: Bad value in TC register! (bad sum)\n");
692: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
693: return;
694: }
695:
696: #if MMU030_DEBUG_ERROR
697: /* At least one table has to be defined using at least
698: * 1 bit for the index. At least 2 bits are necessary
699: * if there is no second table. If these conditions are
700: * not met, it will automatically lead to a sum <32
701: * and cause an exception (see above). */
702: if (!TI_bits[0]) {
703: write_log("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n");
704: } else if ((TI_bits[0]<2) && !TI_bits[1]) {
705: write_log("MMU Configuration Exception: Bad value in TC register! (no second table index defined and)\n");
706: write_log("MMU Configuration Exception: Bad value in TC register! (only 1 bit for first table index)\n");
707: }
708: #endif
709:
710: #if MMU030_DEBUG
711: write_log("\n");
712: write_log("TRANSLATION CONTROL: %08X\n", TC);
713: write_log("\n");
714: write_log("TC: translation %s\n", (TC&TC_ENABLE_TRANSLATION ? "enabled" : "disabled"));
715: write_log("TC: supervisor root pointer %s\n", (TC&TC_ENABLE_SUPERVISOR ? "enabled" : "disabled"));
716: write_log("TC: function code lookup %s\n", (TC&TC_ENABLE_FCL ? "enabled" : "disabled"));
717: write_log("\n");
718:
719: write_log("TC: Initial Shift: %i\n", mmu030.translation.init_shift);
720: write_log("TC: Page Size: %i byte\n", (1<<mmu030.translation.page.size));
721: write_log("\n");
722:
723: for (i = 0; i <= mmu030.translation.last_table; i++) {
724: write_log("TC: Table %c: mask = %08X, shift = %i\n", table_letter[i], mmu030.translation.table[i].mask, mmu030.translation.table[i].shift);
725: }
726:
727: write_log("TC: Page: mask = %08X\n", mmu030.translation.page.mask);
728: write_log("\n");
729:
730: write_log("TC: Last Table: %c\n", table_letter[mmu030.translation.last_table]);
731: write_log("\n");
732: #endif
733: }
734:
735:
736:
737: /* Root Pointer Registers (SRP and CRP)
738: *
739: * ---- ---- ---- ---- xxxx xxxx xxxx xx-- ---- ---- ---- ---- ---- ---- ---- xxxx
740: * reserved, must be 0
741: *
742: * ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
743: * table A address
744: *
745: * ---- ---- ---- ---- ---- ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- ----
746: * descriptor type
747: *
748: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
749: * limit
750: *
751: * x--- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
752: * 0 = upper limit, 1 = lower limit
753: *
754: */
755:
756:
757: #define RP_ADDR_MASK (UVAL64(0x00000000FFFFFFF0))
758: #define RP_DESCR_MASK (UVAL64(0x0000000300000000))
759: #define RP_LIMIT_MASK (UVAL64(0x7FFF000000000000))
760: #define RP_LOWER_MASK (UVAL64(0x8000000000000000))
761: #define RP_ZERO_BITS (UVAL64(0x0000FFFC00000000))
762:
763: void mmu030_decode_rp(uae_u64 RP) {
764:
765: uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
766: if (!descriptor_type) { /* If descriptor type is invalid */
767: error_msg("MMU Configuration Exception: Root Pointer is invalid!\n");
768: Exception(56, m68k_getpc(), M68000_EXC_SRC_CPU); /* MMU Configuration Exception */
769: }
770:
771: #if MMU030_DEBUG_ERROR
772: if (RP&RP_ZERO_BITS) {
773: write_log("MMU Warning: Root pointer reserved bits are non-zero!\n");
774: }
775: #endif
776:
777: #if MMU030_DEBUG
778: uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
779: uae_u32 first_addr = (RP & RP_ADDR_MASK);
780:
781: write_log("\n");
782: write_log("ROOT POINTER: %08X%08X\n", (uae_u32)(RP>>32)&0xFFFFFFFF, (uae_u32)(RP&0xFFFFFFFF));
783: write_log("\n");
784:
785: write_log("RP: descriptor type = %i ", descriptor_type);
786: switch (descriptor_type) {
787: case 0:
788: write_log("(invalid descriptor)\n");
789: break;
790: case 1:
791: write_log("(early termination page descriptor)\n");
792: break;
793: case 2:
794: write_log("(valid 4 byte descriptor)\n");
795: break;
796: case 3:
797: write_log("(valid 8 byte descriptor)\n");
798: break;
799: }
800:
801: write_log("RP: %s limit = %i\n", (RP&RP_LOWER_MASK) ? "lower" : "upper", table_limit);
802:
803: write_log("RP: first table address = %08X\n", first_addr);
804: write_log("\n");
805: #endif
806: }
807:
808:
809:
810: /* Descriptors */
811:
812: #define DESCR_TYPE_MASK 0x00000003
813:
814: #define DESCR_TYPE_INVALID 0 /* all tables */
815:
816: #define DESCR_TYPE_EARLY_TERM 1 /* all but lowest level table */
817: #define DESCR_TYPE_PAGE 1 /* only lowest level table */
818: #define DESCR_TYPE_VALID4 2 /* all but lowest level table */
819: #define DESCR_TYPE_INDIRECT4 2 /* only lowest level table */
820: #define DESCR_TYPE_VALID8 3 /* all but lowest level table */
821: #define DESCR_TYPE_INDIRECT8 3 /* only lowest level table */
822:
823: #define DESCR_TYPE_VALID_MASK 0x2 /* all but lowest level table */
824: #define DESCR_TYPE_INDIRECT_MASK 0x2 /* only lowest level table */
825:
826:
827: /* Short format (4 byte):
828: *
829: * ---- ---- ---- ---- ---- ---- ---- --xx
830: * descriptor type:
831: * 0 = invalid
832: * 1 = page descriptor (early termination)
833: * 2 = valid (4 byte)
834: * 3 = valid (8 byte)
835: *
836: *
837: * table descriptor:
838: * ---- ---- ---- ---- ---- ---- ---- -x--
839: * write protect
840: *
841: * ---- ---- ---- ---- ---- ---- ---- x---
842: * update
843: *
844: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
845: * table address
846: *
847: *
848: * (early termination) page descriptor:
849: * ---- ---- ---- ---- ---- ---- ---- -x--
850: * write protect
851: *
852: * ---- ---- ---- ---- ---- ---- ---- x---
853: * update
854: *
855: * ---- ---- ---- ---- ---- ---- ---x ----
856: * modified
857: *
858: * ---- ---- ---- ---- ---- ---- -x-- ----
859: * cache inhibit
860: *
861: * ---- ---- ---- ---- ---- ---- x-x- ----
862: * reserved (must be 0)
863: *
864: * xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
865: * page address
866: *
867: *
868: * indirect descriptor:
869: * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
870: * descriptor address
871: *
872: */
873:
874: #define DESCR_WP 0x00000004
875: #define DESCR_U 0x00000008
876: #define DESCR_M 0x00000010 /* only last level table */
877: #define DESCR_CI 0x00000040 /* only last level table */
878:
879: #define DESCR_TD_ADDR_MASK 0xFFFFFFF0
880: #define DESCR_PD_ADDR_MASK 0xFFFFFF00
881: #define DESCR_ID_ADDR_MASK 0xFFFFFFFC
882:
883:
884: /* Long format (8 byte):
885: *
886: * ---- ---- ---- ---- ---- ---- ---- --xx | ---- ---- ---- ---- ---- ---- ---- ----
887: * descriptor type:
888: * 0 = invalid
889: * 1 = page descriptor (early termination)
890: * 2 = valid (4 byte)
891: * 3 = valid (8 byte)
892: *
893: *
894: * table desctriptor:
895: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
896: * write protect
897: *
898: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
899: * update
900: *
901: * ---- ---- ---- ---- ---- ---- xxxx ---- | ---- ---- ---- ---- ---- ---- ---- ----
902: * reserved (must be 0)
903: *
904: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
905: * supervisor
906: *
907: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
908: * reserved (must be 1111 110)
909: *
910: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
911: * limit
912: *
913: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
914: * 0 = upper limit, 1 = lower limit
915: *
916: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
917: * table address
918: *
919: *
920: * (early termination) page descriptor:
921: * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
922: * write protect
923: *
924: * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
925: * update
926: *
927: * ---- ---- ---- ---- ---- ---- ---x ---- | ---- ---- ---- ---- ---- ---- ---- ----
928: * modified
929: *
930: * ---- ---- ---- ---- ---- ---- -x-- ---- | ---- ---- ---- ---- ---- ---- ---- ----
931: * cache inhibit
932: *
933: * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
934: * supervisor
935: *
936: * ---- ---- ---- ---- ---- ---- x-x- ---- | ---- ---- ---- ---- ---- ---- ---- ----
937: * reserved (must be 0)
938: *
939: * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
940: * reserved (must be 1111 110)
941: *
942: * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
943: * limit (only used with early termination page descriptor)
944: *
945: * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
946: * 0 = upper limit, 1 = lower limit (only used with early termination page descriptor)
947: *
948: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
949: * page address
950: *
951: *
952: * indirect descriptor:
953: * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
954: * descriptor address
955: *
956: */
957:
958: /* only for long descriptors */
959: #define DESCR_S 0x00000100
960:
961: #define DESCR_LIMIT_MASK 0x7FFF0000
962: #define DESCR_LOWER_MASK 0x80000000
963:
964:
965:
966: /* This functions searches through the translation tables. It can be used
967: * for PTEST (levels 1 to 7). Using level 0 creates an ATC entry. */
968:
969: uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
970: /* During table walk up to 7 different descriptors are used:
971: * root pointer, descriptors fetched from function code lookup table,
972: * tables A, B, C and D and one indirect descriptor */
973: uae_u32 descr[2];
974: uae_u32 descr_type;
975: uaecptr descr_addr[7];
976: uaecptr table_addr = 0;
977: uaecptr page_addr = 0;
978: uaecptr indirect_addr = 0;
979: uae_u32 table_index = 0;
980: uae_u32 limit = 0;
981: uae_u32 unused_fields_mask = 0;
982: bool super = (fc&4) ? true : false;
983: bool write_protect = false;
984: bool cache_inhibit = false;
985: bool descr_modified = false;
986:
987: mmu030.status = 0; /* Reset status */
988:
989: /* Initial values for condition variables.
990: * Note: Root pointer is long descriptor. */
991: int t = 0;
992: int addr_position = 1;
993: int next_size = 0;
994: int descr_size = 8;
995: int descr_num = 0;
996: bool early_termination = false;
997:
998: int i;
999:
1000: TRY(prb) {
1001: /* Use super user root pointer if enabled in TC register and access is in
1002: * super user mode, else use cpu root pointer. */
1003: if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
1004: descr[0] = (srp_030>>32)&0xFFFFFFFF;
1005: descr[1] = srp_030&0xFFFFFFFF;
1006: debug_msg("Supervisor Root Pointer: %08X%08X\n",descr[0],descr[1]);
1007: } else {
1008: descr[0] = (crp_030>>32)&0xFFFFFFFF;
1009: descr[1] = crp_030&0xFFFFFFFF;
1010: debug_msg("CPU Root Pointer: %08X%08X\n",descr[0],descr[1]);
1011: }
1012:
1013: /* Check descriptor type of root pointer */
1014: descr_type = descr[0]&DESCR_TYPE_MASK;
1015: switch (descr_type) {
1016: case DESCR_TYPE_INVALID:
1017: error_msg("Fatal error: Root pointer is invalid descriptor!\n");
1018: mmu030.status |= MMUSR_INVALID;
1019: goto stop_search;
1020: case DESCR_TYPE_EARLY_TERM:
1021: debug_msg("Root pointer is early termination page descriptor.\n");
1022: early_termination = true;
1023: goto handle_page_descriptor;
1024: case DESCR_TYPE_VALID4:
1025: next_size = 4;
1026: break;
1027: case DESCR_TYPE_VALID8:
1028: next_size = 8;
1029: break;
1030: }
1031:
1032: /* If function code lookup is enabled in TC register use function code as
1033: * index for top level table, limit check not required */
1034:
1035: if (tc_030&TC_ENABLE_FCL) {
1036: debug_msg("Function code lookup enabled, FC = %i\n", fc);
1037:
1038: addr_position = (descr_size==4) ? 0 : 1;
1039: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1040: table_index = fc; /* table index is function code */
1041: debug_msg("Table FCL at %08X: index = %i, ",table_addr,table_index);
1042:
1043: /* Fetch next descriptor */
1044: descr_num++;
1045: descr_addr[descr_num] = table_addr+(table_index*next_size);
1046:
1047: if (next_size==4) {
1048: descr[0] = phys_get_long(descr_addr[descr_num]);
1049: debug_msg("Next descriptor: %08X\n",descr[0]);
1050: } else {
1051: descr[0] = phys_get_long(descr_addr[descr_num]);
1052: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1053: debug_msg("Next descriptor: %08X%08X\n",descr[0],descr[1]);
1054: }
1055:
1056: descr_size = next_size;
1057:
1058: /* Check descriptor type */
1059: descr_type = descr[0]&DESCR_TYPE_MASK;
1060: switch (descr_type) {
1061: case DESCR_TYPE_INVALID:
1062: debug_msg("Invalid descriptor!\n");
1063: /* stop table walk */
1064: mmu030.status |= MMUSR_INVALID;
1065: goto stop_search;
1066: case DESCR_TYPE_EARLY_TERM:
1067: debug_msg("Early termination page descriptor!\n");
1068: early_termination = true;
1069: goto handle_page_descriptor;
1070: case DESCR_TYPE_VALID4:
1071: next_size = 4;
1072: break;
1073: case DESCR_TYPE_VALID8:
1074: next_size = 8;
1075: break;
1076: }
1077: }
1078:
1079:
1080: /* Upper level tables */
1081: do {
1082: if (descr_num) { /* if not root pointer */
1083: /* Set the updated bit */
1084: if (!level && !(descr[0]&DESCR_U) && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1085: descr[0] |= DESCR_U;
1086: phys_put_long(descr_addr[descr_num], descr[0]);
1087: }
1088: /* Update status bits */
1089: if (descr_size==8) {
1090: if (descr[0]&DESCR_S)
1091: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1092: }
1093: if (descr[0]&DESCR_WP) {
1094: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1095: write_protect = true;
1096: }
1097:
1098: /* Check if ptest level is reached */
1099: if (level && (level==descr_num)) {
1100: goto stop_search;
1101: }
1102: }
1103:
1104: addr_position = (descr_size==4) ? 0 : 1;
1105: table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1106: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1107: debug_msg("Table %c at %08X: index = %i, ",table_letter[t],table_addr,table_index);
1108: t++; /* Proceed to the next table */
1109:
1110: /* Perform limit check */
1111: if (descr_size==8) {
1112: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1113: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1114: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1115: debug_msg("limit violation (lower limit %i)\n",limit);
1116: goto stop_search;
1117: }
1118: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1119: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1120: debug_msg("limit violation (upper limit %i)\n",limit);
1121: goto stop_search;
1122: }
1123: }
1124:
1125: /* Fetch next descriptor */
1126: descr_num++;
1127: descr_addr[descr_num] = table_addr+(table_index*next_size);
1128:
1129: if (next_size==4) {
1130: descr[0] = phys_get_long(descr_addr[descr_num]);
1131: debug_msg("Next descriptor: %08X\n",descr[0]);
1132: } else {
1133: descr[0] = phys_get_long(descr_addr[descr_num]);
1134: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1135: debug_msg("Next descriptor: %08X%08X\n",descr[0],descr[1]);
1136: }
1137:
1138: descr_size = next_size;
1139:
1140: /* Check descriptor type */
1141: descr_type = descr[0]&DESCR_TYPE_MASK;
1142: switch (descr_type) {
1143: case DESCR_TYPE_INVALID:
1144: debug_msg("Invalid descriptor!\n");
1145: /* stop table walk */
1146: mmu030.status |= MMUSR_INVALID;
1147: goto stop_search;
1148: case DESCR_TYPE_EARLY_TERM:
1149: /* go to last level table handling code */
1150: if (t<=mmu030.translation.last_table) {
1151: debug_msg("Early termination page descriptor!\n");
1152: early_termination = true;
1153: }
1154: goto handle_page_descriptor;
1155: case DESCR_TYPE_VALID4:
1156: next_size = 4;
1157: break;
1158: case DESCR_TYPE_VALID8:
1159: next_size = 8;
1160: break;
1161: }
1162: } while (t<=mmu030.translation.last_table);
1163:
1164:
1165: /* Handle indirect descriptor */
1166:
1167: /* Check if ptest level is reached */
1168: if (level && (level==descr_num)) {
1169: goto stop_search;
1170: }
1171:
1172: addr_position = (descr_size==4) ? 0 : 1;
1173: indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1174: debug_msg("Page indirect descriptor at %08X: ",indirect_addr);
1175:
1176: /* Fetch indirect descriptor */
1177: descr_num++;
1178: descr_addr[descr_num] = indirect_addr;
1179:
1180: if (next_size==4) {
1181: descr[0] = phys_get_long(descr_addr[descr_num]);
1182: debug_msg("descr = %08X\n",descr[0]);
1183: } else {
1184: descr[0] = phys_get_long(descr_addr[descr_num]);
1185: descr[1] = phys_get_long(descr_addr[descr_num]+4);
1186: debug_msg("descr = %08X%08X",descr[0],descr[1]);
1187: }
1188:
1189: descr_size = next_size;
1190:
1191: /* Check descriptor type, only page descriptor is valid */
1192: descr_type = descr[0]&DESCR_TYPE_MASK;
1193: if (descr_type!=DESCR_TYPE_PAGE) {
1194: mmu030.status |= MMUSR_INVALID;
1195: goto stop_search;
1196: }
1197:
1198: handle_page_descriptor:
1199:
1200: if (descr_num) { /* if not root pointer */
1201: if (!level && !(mmu030.status&MMUSR_SUPER_VIOLATION)) {
1202: /* set modified bit */
1203: if (!(descr[0]&DESCR_M) && write && !(mmu030.status&MMUSR_WRITE_PROTECTED)) {
1204: descr[0] |= DESCR_M;
1205: descr_modified = true;
1206: }
1207: /* set updated bit */
1208: if (!(descr[0]&DESCR_U)) {
1209: descr[0] |= DESCR_U;
1210: descr_modified = true;
1211: }
1212: /* write modified descriptor if neccessary */
1213: if (descr_modified) {
1214: phys_put_long(descr_addr[descr_num], descr[0]);
1215: }
1216: }
1217:
1218: if ((descr_size==8) && (descr[0]&DESCR_S)) {
1219: mmu030.status |= super ? 0 : MMUSR_SUPER_VIOLATION;
1220: }
1221:
1222: /* check if caching is inhibited */
1223: cache_inhibit = descr[0]&DESCR_CI ? true : false;
1224:
1225: /* check write protection */
1226: if (descr[0]&DESCR_WP) {
1227: mmu030.status |= (descr[0]&DESCR_WP) ? MMUSR_WRITE_PROTECTED : 0;
1228: write_protect = true;
1229: }
1230: /* TODO: check if this is handled at correct point (maybe before updating descr?) */
1231: mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
1232: }
1233:
1234: /* Check limit using next index field of logical address.
1235: * Limit is only checked on early termination. If we are
1236: * still at root pointer level, only check limit, if FCL
1237: * is disabled. */
1238: if (early_termination) {
1239: if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
1240: if (descr_size==8) {
1241: table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1242: limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1243: if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1244: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1245: debug_msg("Limit violation (lower limit %i)\n",limit);
1246: goto stop_search;
1247: }
1248: if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1249: mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1250: debug_msg("Limit violation (upper limit %i)\n",limit);
1251: goto stop_search;
1252: }
1253: }
1254: }
1255: /* Get all unused bits of the logical address table index field.
1256: * they are added to the page address */
1257: /* TODO: They should be added via "signed addition". How to? */
1258: do {
1259: unused_fields_mask |= mmu030.translation.table[t].mask;
1260: t++;
1261: } while (t<=mmu030.translation.last_table);
1262: page_addr = addr&unused_fields_mask;
1263: debug_msg("Logical address unused bits: %08X (mask = %08X)\n",
1264: page_addr,unused_fields_mask);
1265: }
1266:
1267: /* Get page address */
1268: addr_position = (descr_size==4) ? 0 : 1;
1269: page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
1270: debug_msg("Page at %08X\n",page_addr);
1271:
1272: stop_search:
1273: ; /* Make compiler happy */
1274: } CATCH(prb) {
1275: /* We jump to this place, if a bus error occured during table search.
1276: * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
1277: if (bBusErrorReadWrite) {
1278: descr_num--;
1279: }
1280: mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1281: debug_msg("MMU: Bus error while %s descriptor!\n",
1282: bBusErrorReadWrite?"reading":"writing");
1283: } ENDTRY
1284:
1285: /* check if we have to handle ptest */
1286: if (level) {
1287: if (mmu030.status&MMUSR_INVALID) {
1288: /* these bits are undefined, if the I bit is set: */
1289: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED|MMUSR_SUPER_VIOLATION);
1290: }
1291: mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
1292:
1293: /* If root pointer is page descriptor (descr_num 0), return 0 */
1294: return descr_num ? descr_addr[descr_num] : 0;
1295: }
1296:
1297: /* Find an ATC entry to replace */
1298: /* Search for invalid entry */
1299: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1300: if (!mmu030.atc[i].logical.valid) {
1301: break;
1302: }
1303: }
1304: /* If there are no invalid entries, replace first entry
1305: * with history bit not set */
1306: if (i == ATC030_NUM_ENTRIES) {
1307: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1308: if (!mmu030.atc[i].mru) {
1309: break;
1310: }
1311: }
1312: debug_msg("ATC is full. Replacing entry %i\n", i);
1313: }
1314: mmu030_atc_handle_history_bit(i);
1315:
1316: /* Create ATC entry */
1317: mmu030.atc[i].logical.addr = addr & (~mmu030.translation.page.mask); /* delete page index bits */
1318: mmu030.atc[i].logical.fc = fc;
1319: mmu030.atc[i].logical.valid = true;
1320: mmu030.atc[i].physical.addr = page_addr & (~mmu030.translation.page.mask); /* delete page index bits */
1321: if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
1322: mmu030.atc[i].physical.bus_error = true;
1323: } else {
1324: mmu030.atc[i].physical.bus_error = false;
1325: }
1326: if (write && !(mmu030.status&MMUSR_SUPER_VIOLATION) && !(mmu030.status&MMUSR_LIMIT_VIOLATION)) {
1327: mmu030.atc[i].physical.modified = true;
1328: } else {
1329: mmu030.atc[i].physical.modified = false;
1330: }
1331: mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1332: mmu030.atc[i].physical.write_protect = write_protect;
1333:
1334: debug_msg("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n", i,
1335: mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
1336: mmu030.atc[i].logical.fc);
1337: debug_msg("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n", i,
1338: mmu030.atc[i].physical.bus_error?1:0,
1339: mmu030.atc[i].physical.cache_inhibit?1:0,
1340: mmu030.atc[i].physical.write_protect?1:0,
1341: mmu030.atc[i].physical.modified?1:0);
1342:
1343: return 0;
1344: }
1345:
1346: /* This function is used for PTEST level 0. */
1347: void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1348: int i;
1349: mmu030.status = 0;
1350:
1351: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1352: mmu030.status |= MMUSR_TRANSP_ACCESS;
1353: return;
1354: }
1355:
1356: for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
1357: if ((mmu030.atc[i].logical.fc == fc) &&
1358: (mmu030.atc[i].logical.addr == logical_addr) &&
1359: mmu030.atc[i].logical.valid) {
1360: break;
1361: }
1362: }
1363:
1364: if (i==ATC030_NUM_ENTRIES) {
1365: mmu030.status |= MMUSR_INVALID;
1366: return;
1367: }
1368:
1369: mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1370: mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
1371: mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
1372: if (mmu030.status&MMUSR_INVALID) {
1373: mmu030.status &= ~(MMUSR_WRITE_PROTECTED|MMUSR_MODIFIED);
1374: }
1375: }
1376:
1377: /* This function is used for PTEST level 1 - 7. */
1378: uae_u32 mmu030_ptest_table_search(uaecptr logical_addr, uae_u32 fc, bool write, int level) {
1379: if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1380: return 0;
1381: } else {
1382: return mmu030_table_search(logical_addr, fc, write, level);
1383: }
1384: }
1385:
1386:
1387: /* Address Translation Cache
1388: *
1389: * The ATC uses a pseudo-least-recently-used algorithm to keep track of
1390: * least recently used entries. Entries are replaced if the cache is full.
1391: * An internal history-bit (MRU-bit) is used to identify these entries.
1392: * If an entry is accessed, its history-bit is set to 1. If after that
1393: * there are no more entries with zero-bits, all other history-bits are
1394: * set to 0. When no more invalid entries are in the ATC, the first entry
1395: * with a zero-bit is replaced.
1396: *
1397: *
1398: * Logical Portion (28 bit):
1399: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1400: * logical address (most significant 24 bit)
1401: *
1402: * oooo -xxx ---- ---- ---- ---- ---- ----
1403: * function code
1404: *
1405: * oooo x--- ---- ---- ---- ---- ---- ----
1406: * valid
1407: *
1408: *
1409: * Physical Portion (28 bit):
1410: * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1411: * physical address
1412: *
1413: * oooo ---x ---- ---- ---- ---- ---- ----
1414: * modified
1415: *
1416: * oooo --x- ---- ---- ---- ---- ---- ----
1417: * write protect
1418: *
1419: * oooo -x-- ---- ---- ---- ---- ---- ----
1420: * cache inhibit
1421: *
1422: * oooo x--- ---- ---- ---- ---- ---- ----
1423: * bus error
1424: *
1425: */
1426:
1427: #define ATC030_MASK 0x0FFFFFFF
1428: #define ATC030_ADDR_MASK 0x00FFFFFF /* after masking shift 8 (<< 8) */
1429:
1430: #define ATC030_LOG_FC 0x07000000
1431: #define ATC030_LOG_V 0x08000000
1432:
1433: #define ATC030_PHYS_M 0x01000000
1434: #define ATC030_PHYS_WP 0x02000000
1435: #define ATC030_PHYS_CI 0x04000000
1436: #define ATC030_PHYS_BE 0x08000000
1437:
1438: void mmu030_page_fault(uaecptr addr, bool read) {
1439: write_log("MMU: page fault (logical addr = %08X)\n", addr);
1440: regs.mmu_fault_addr = addr;
1441: bBusErrorReadWrite = read;
1442: THROW(2);
1443: }
1444:
1445: void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l) {
1446: uae_u32 page_index = addr & mmu030.translation.page.mask;
1447: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1448:
1449: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1450: #if MMU030_LOG_MEM_ACCESS
1451: write_log("ATC match(%i): page addr = %08X, index = %08X (lput %08X)\n",
1452: l, physical_addr, page_index, val);
1453: #endif
1454: physical_addr += page_index;
1455:
1456: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1457: mmu030_page_fault(addr, 0);
1458: return;
1459: }
1460:
1461: phys_put_long(physical_addr, val);
1462: }
1463:
1464: void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l) {
1465: uae_u32 page_index = addr & mmu030.translation.page.mask;
1466: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1467:
1468: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1469: #if MMU030_LOG_MEM_ACCESS
1470: write_log("ATC match(%i): page addr = %08X, index = %08X (wput %04X)\n",
1471: l, physical_addr, page_index, val);
1472: #endif
1473: physical_addr += page_index;
1474:
1475: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1476: mmu030_page_fault(addr, 0);
1477: return;
1478: }
1479:
1480: phys_put_word(physical_addr, val);
1481: }
1482:
1483: void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l) {
1484: uae_u32 page_index = addr & mmu030.translation.page.mask;
1485: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1486:
1487: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1488: #if MMU030_LOG_MEM_ACCESS
1489: write_log("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n",
1490: l, physical_addr, page_index, val);
1491: #endif
1492: physical_addr += page_index;
1493:
1494: if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1495: mmu030_page_fault(addr, 0);
1496: return;
1497: }
1498:
1499: phys_put_byte(physical_addr, val);
1500: }
1501:
1502: uae_u32 mmu030_get_long_atc(uaecptr addr, int l) {
1503: uae_u32 page_index = addr & mmu030.translation.page.mask;
1504: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1505:
1506: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1507: #if MMU030_LOG_MEM_ACCESS
1508: write_log("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n", l,
1509: physical_addr, page_index, phys_get_long(physical_addr+page_index));
1510: #endif
1511: physical_addr += page_index;
1512:
1513: if (mmu030.atc[l].physical.bus_error) {
1514: mmu030_page_fault(addr, 1);
1515: return 0;
1516: }
1517:
1518: return phys_get_long(physical_addr);
1519: }
1520:
1521: uae_u16 mmu030_get_word_atc(uaecptr addr, int l) {
1522: uae_u32 page_index = addr & mmu030.translation.page.mask;
1523: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1524:
1525: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1526: #if MMU030_LOG_MEM_ACCESS
1527: write_log("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n", l,
1528: physical_addr, page_index, phys_get_word(physical_addr+page_index));
1529: #endif
1530: physical_addr += page_index;
1531:
1532: if (mmu030.atc[l].physical.bus_error) {
1533: mmu030_page_fault(addr, 1);
1534: return 0;
1535: }
1536:
1537: return phys_get_word(physical_addr);
1538: }
1539:
1540: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l) {
1541: uae_u32 page_index = addr & mmu030.translation.page.mask;
1542: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1543:
1544: uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1545: #if MMU030_LOG_MEM_ACCESS
1546: write_log("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n", l,
1547: physical_addr, page_index, phys_get_byte(physical_addr+page_index));
1548: #endif
1549: physical_addr += page_index;
1550:
1551: if (mmu030.atc[l].physical.bus_error) {
1552: mmu030_page_fault(addr, 1);
1553: return 0;
1554: }
1555:
1556: return phys_get_byte(physical_addr);
1557: }
1558:
1559:
1560: /* This function checks if a certain logical address is in the ATC
1561: * by comparing the logical address and function code to the values
1562: * stored in the ATC entries. If a matching entry is found it sets
1563: * the history bit and returns the cache index of the entry. */
1564: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1565: uaecptr physical_addr = 0;
1566: uaecptr logical_addr = 0;
1567: uae_u32 addr_mask = ~mmu030.translation.page.mask;
1568: uae_u32 page_index = addr & mmu030.translation.page.mask;
1569:
1570: int i;
1571: for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1572: logical_addr = mmu030.atc[i].logical.addr;
1573: /* If actual address matches address in ATC */
1574: if ((addr&addr_mask)==(logical_addr&addr_mask) &&
1575: (mmu030.atc[i].logical.fc==fc) &&
1576: mmu030.atc[i].logical.valid) {
1577: /* If M bit is set or access is read, return true
1578: * else invalidate entry */
1579: if (mmu030.atc[i].physical.modified || !write) {
1580: /* Maintain history bit */
1581: mmu030_atc_handle_history_bit(i);
1582: return i;
1583: } else {
1584: mmu030.atc[i].logical.valid = false;
1585: }
1586: }
1587: }
1588: return ATC030_NUM_ENTRIES;
1589: }
1590:
1591: void mmu030_atc_handle_history_bit(int entry_num) {
1592: int j;
1593: mmu030.atc[entry_num].mru = 1;
1594: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1595: if (!mmu030.atc[j].mru)
1596: break;
1597: }
1598: /* If there are no more zero-bits, reset all */
1599: if (j==ATC030_NUM_ENTRIES) {
1600: for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1601: mmu030.atc[j].mru = 0;
1602: }
1603: mmu030.atc[entry_num].mru = 1;
1604: debug_msg("ATC: No more history zero-bits. Reset all.\n");
1605: }
1606: }
1607:
1608:
1609: /* Memory access functions:
1610: * If the address matches one of the transparent translation registers
1611: * use it directly as physical address, else check ATC for the
1612: * logical address. If the logical address is not resident in the ATC
1613: * create a new ATC entry and then look up the physical address.
1614: */
1615:
1616: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc, int size) {
1617:
1618: // addr,super,write
1619: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1620: phys_put_long(addr,val);
1621: return;
1622: }
1623:
1624: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1625:
1626: if (atc_line_num<ATC030_NUM_ENTRIES) {
1627: mmu030_put_long_atc(addr, val, atc_line_num);
1628: } else {
1629: mmu030_table_search(addr,fc,true,0);
1630: mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1631: }
1632: }
1633:
1634: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc, int size) {
1635:
1636: // addr,super,write
1637: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,true)&TT_OK_MATCH) || (fc==7)) {
1638: phys_put_word(addr,val);
1639: return;
1640: }
1641:
1642: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1643:
1644: if (atc_line_num<ATC030_NUM_ENTRIES) {
1645: mmu030_put_word_atc(addr, val, atc_line_num);
1646: } else {
1647: mmu030_table_search(addr, fc, true, 0);
1648: mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1649: }
1650: }
1651:
1652: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc, int size) {
1653:
1654: // addr,super,write
1655: if ((!mmu030.enabled) || (mmu030_match_ttr(addr, fc, true)&TT_OK_MATCH) || (fc==7)) {
1656: phys_put_byte(addr,val);
1657: return;
1658: }
1659:
1660: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
1661:
1662: if (atc_line_num<ATC030_NUM_ENTRIES) {
1663: mmu030_put_byte_atc(addr, val, atc_line_num);
1664: } else {
1665: mmu030_table_search(addr, fc, true, 0);
1666: mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true));
1667: }
1668: }
1669:
1670: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc, int size) {
1671:
1672: // addr,super,write
1673: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1674: return phys_get_long(addr);
1675: }
1676:
1677: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1678:
1679: if (atc_line_num<ATC030_NUM_ENTRIES) {
1680: return mmu030_get_long_atc(addr, atc_line_num);
1681: } else {
1682: mmu030_table_search(addr, fc, false, 0);
1683: return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1684: }
1685: }
1686:
1687: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc, int size) {
1688:
1689: // addr,super,write
1690: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1691: return phys_get_word(addr);
1692: }
1693:
1694: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1695:
1696: if (atc_line_num<ATC030_NUM_ENTRIES) {
1697: return mmu030_get_word_atc(addr, atc_line_num);
1698: } else {
1699: mmu030_table_search(addr, fc, false, 0);
1700: return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1701: }
1702: }
1703:
1704: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc, int size) {
1705:
1706: // addr,super,write
1707: if ((!mmu030.enabled) || (mmu030_match_ttr(addr,fc,false)&TT_OK_MATCH) || (fc==7)) {
1708: return phys_get_byte(addr);
1709: }
1710:
1711: int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
1712:
1713: if (atc_line_num<ATC030_NUM_ENTRIES) {
1714: return mmu030_get_byte_atc(addr, atc_line_num);
1715: } else {
1716: mmu030_table_search(addr, fc, false, 0);
1717: return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false));
1718: }
1719: }
1720:
1721:
1722: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc)
1723: {
1724: uae_u16 res;
1725:
1726: res = (uae_u16)mmu030_get_byte(addr, fc, sz_word) << 8;
1727: SAVE_EXCEPTION;
1728: TRY(prb) {
1729: res |= mmu030_get_byte(addr + 1, fc, sz_word);
1730: RESTORE_EXCEPTION;
1731: }
1732: CATCH(prb) {
1733: RESTORE_EXCEPTION;
1734: // regs.mmu_fault_addr = addr;
1735: regs.mmu_ssw |= MMU_SSW_MA;
1736: THROW_AGAIN(prb);
1737: } ENDTRY
1738: return res;
1739: }
1740:
1741: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc)
1742: {
1743: uae_u32 res;
1744:
1745: if (likely(!(addr & 1))) {
1746: res = (uae_u32)mmu030_get_word(addr, fc, sz_long) << 16;
1747: SAVE_EXCEPTION;
1748: TRY(prb) {
1749: res |= mmu030_get_word(addr + 2, fc, sz_long);
1750: RESTORE_EXCEPTION;
1751: }
1752: CATCH(prb) {
1753: RESTORE_EXCEPTION;
1754: // regs.mmu_fault_addr = addr;
1755: regs.mmu_ssw |= MMU_SSW_MA;
1756: THROW_AGAIN(prb);
1757: } ENDTRY
1758: } else {
1759: res = (uae_u32)mmu030_get_byte(addr, fc, sz_long) << 8;
1760: SAVE_EXCEPTION;
1761: TRY(prb) {
1762: res = (res | mmu030_get_byte(addr + 1, fc, sz_long)) << 8;
1763: res = (res | mmu030_get_byte(addr + 2, fc, sz_long)) << 8;
1764: res |= mmu030_get_byte(addr + 3, fc, sz_long);
1765: RESTORE_EXCEPTION;
1766: }
1767: CATCH(prb) {
1768: RESTORE_EXCEPTION;
1769: // regs.mmu_fault_addr = addr;
1770: regs.mmu_ssw |= MMU_SSW_MA;
1771: THROW_AGAIN(prb);
1772: } ENDTRY
1773: }
1774: return res;
1775: }
1776:
1777:
1778: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc)
1779: {
1780: SAVE_EXCEPTION;
1781: TRY(prb) {
1782: if (likely(!(addr & 1))) {
1783: mmu030_put_word(addr, val >> 16, fc, sz_long);
1784: mmu030_put_word(addr + 2, val, fc, sz_long);
1785: } else {
1786: mmu030_put_byte(addr, val >> 24, fc, sz_long);
1787: mmu030_put_byte(addr + 1, val >> 16, fc, sz_long);
1788: mmu030_put_byte(addr + 2, val >> 8, fc, sz_long);
1789: mmu030_put_byte(addr + 3, val, fc, sz_long);
1790: }
1791: RESTORE_EXCEPTION;
1792: }
1793: CATCH(prb) {
1794: RESTORE_EXCEPTION;
1795: regs.wb3_data = val;
1796: if (regs.mmu_fault_addr != addr) {
1797: // regs.mmu_fault_addr = addr;
1798: regs.mmu_ssw |= MMU_SSW_MA;
1799: }
1800: THROW_AGAIN(prb);
1801: } ENDTRY
1802: }
1803:
1804: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc)
1805: {
1806: SAVE_EXCEPTION;
1807: TRY(prb) {
1808: mmu030_put_byte(addr, val >> 8, fc, sz_word);
1809: mmu030_put_byte(addr + 1, val, fc, sz_word);
1810: RESTORE_EXCEPTION;
1811: }
1812: CATCH(prb) {
1813: RESTORE_EXCEPTION;
1814: regs.wb3_data = val;
1815: if (regs.mmu_fault_addr != addr) {
1816: // regs.mmu_fault_addr = addr;
1817: regs.mmu_ssw |= MMU_SSW_MA;
1818: }
1819: THROW_AGAIN(prb);
1820: } ENDTRY
1821: }
1822:
1823:
1824: /* MMU Reset */
1825: void mmu030_reset(int hardreset)
1826: {
1827: /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
1828: mmu030.enabled = false;
1829: tc_030 &= ~TC_ENABLE_TRANSLATION;
1830: tt0_030 &= ~TT_ENABLE;
1831: tt1_030 &= ~TT_ENABLE;
1832: if (hardreset) {
1833: srp_030 = crp_030 = 0;
1834: tt0_030 = tt1_030 = tc_030 = 0;
1835: mmusr_030 = 0;
1836: mmu030_flush_atc_all();
1837: }
1838: }
1839:
1840:
1841: void m68k_do_rte_mmu030 (uaecptr a7)
1842: {
1843: uae_u16 ssr = get_word_mmu030 (a7 + 8 + 4);
1844: if (ssr & MMU_SSW_CT) {
1845: uaecptr src_a7 = a7 + 8 - 8;
1846: uaecptr dst_a7 = a7 + 8 + 52;
1847: put_word_mmu030 (dst_a7 + 0, get_word_mmu030 (src_a7 + 0));
1848: put_long_mmu030 (dst_a7 + 2, get_long_mmu030 (src_a7 + 2));
1849: // skip this word
1850: put_long_mmu030 (dst_a7 + 8, get_long_mmu030 (src_a7 + 8));
1851: }
1852: }
1853:
1854: void flush_mmu030 (uaecptr addr, int n)
1855: {
1856: }
1857:
1858: void m68k_do_rts_mmu030 (void)
1859: {
1860: m68k_setpc (get_long_mmu030 (m68k_areg (regs, 7)));
1861: m68k_areg (regs, 7) += 4;
1862: }
1863:
1864: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
1865: {
1866: put_long_mmu030 (m68k_areg (regs, 7) - 4, oldpc);
1867: m68k_areg (regs, 7) -= 4;
1868: m68k_incpci (offset);
1869: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.