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).
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.
27  * - Handle cache inhibit bit when accessing ATC entries
28  */
29 
30 
31 #include "sysconfig.h"
32 #include "sysdeps.h"
33 
34 #ifdef WINUAE_FOR_HATARI
35 #include "main.h"
36 #include "hatari-glue.h"
37 #include "log.h"
38 #endif
39 
40 #include "options_cpu.h"
41 #include "memory.h"
42 #include "newcpu.h"
43 #include "debug.h"
44 #include "cpummu030.h"
45 
46 #define MMU030_OP_DBG_MSG 0
47 #define MMU030_ATC_DBG_MSG 0
48 #define MMU030_REG_DBG_MSG 0
49 
50 #define TT_FC_MASK      0x00000007
51 #define TT_FC_BASE      0x00000070
52 #define TT_RWM          0x00000100
53 #define TT_RW           0x00000200
54 #define TT_CI           0x00000400
55 #define TT_ENABLE       0x00008000
56 
57 #define TT_ADDR_MASK    0x00FF0000
58 #define TT_ADDR_BASE    0xFF000000
59 
60 static int bBusErrorReadWrite;
61 static int atcindextable[32];
62 static int tt_enabled;
63 
64 int mmu030_idx;
65 
66 uae_u32 mm030_stageb_address;
67 bool mmu030_retry;
68 int mmu030_opcode;
69 int mmu030_opcode_stageb;
70 
71 int mmu030_fake_prefetch;
72 uaecptr mmu030_fake_prefetch_addr;
73 
74 uae_u16 mmu030_state[3];
75 uae_u32 mmu030_data_buffer_out;
76 uae_u32 mmu030_disp_store[2];
77 uae_u32 mmu030_fmovem_store[2];
78 uae_u8 mmu030_cache_state;
79 struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1];
80 
81 static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write);
82 static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level);
83 static TT_info mmu030_decode_tt(uae_u32 TT);
84 
85 #if MMU_DPAGECACHE030
86 #define MMUFASTCACHE_ENTRIES030 256
87 struct mmufastcache030
88 {
89 	uae_u32 log;
90 	uae_u32 phys;
91 	uae_u8 cs;
92 };
93 static struct mmufastcache030 atc_data_cache_read[MMUFASTCACHE_ENTRIES030];
94 static struct mmufastcache030 atc_data_cache_write[MMUFASTCACHE_ENTRIES030];
95 #endif
96 
97 /* for debugging messages */
98 char table_letter[4] = {'A','B','C','D'};
99 
100 static const uae_u32 mmu030_size[3] = { MMU030_SSW_SIZE_B, MMU030_SSW_SIZE_W, MMU030_SSW_SIZE_L };
101 
102 uae_u64 srp_030, crp_030;
103 uae_u32 tt0_030, tt1_030, tc_030;
104 uae_u16 mmusr_030;
105 
106 /* ATC struct */
107 #define ATC030_NUM_ENTRIES  22
108 
109 typedef struct {
110     struct {
111         uaecptr addr;
112         bool modified;
113         bool write_protect;
114         uae_u8 cache_inhibit;
115         bool bus_error;
116     } physical;
117 
118     struct {
119         uaecptr addr;
120         uae_u32 fc;
121         bool valid;
122     } logical;
123     /* history bit */
124     int mru;
125 } MMU030_ATC_LINE;
126 
127 
128 /* MMU struct for 68030 */
129 static struct {
130 
131     /* Translation tables */
132     struct {
133         struct {
134             uae_u32 mask;
135             uae_u8 shift;
136         } table[4];
137 
138         struct {
139             uae_u32 mask;
140 			uae_u32 imask;
141             uae_u32 size;
142 			uae_u32 size3m;
143         } page;
144 
145         uae_u8 init_shift;
146         uae_u8 last_table;
147     } translation;
148 
149     /* Transparent translation */
150     struct {
151         TT_info tt0;
152         TT_info tt1;
153     } transparent;
154 
155     /* Address translation cache */
156     MMU030_ATC_LINE atc[ATC030_NUM_ENTRIES];
157 
158     /* Condition */
159     bool enabled;
160     uae_u16 status;
161 
162 #if MMU_IPAGECACHE030
163 	uae_u8 mmu030_cache_state;
164 #if MMU_DIRECT_ACCESS
165 	uae_u8 *mmu030_last_physical_address_real;
166 #else
167 	uae_u32 mmu030_last_physical_address;
168 #endif
169 	uae_u32 mmu030_last_logical_address;
170 #endif
171 
172 } mmu030;
173 
174 /* MMU Status Register
175  *
176  * ---x ---x x-xx x---
177  * reserved (all 0)
178  *
179  * x--- ---- ---- ----
180  * bus error
181  *
182  * -x-- ---- ---- ----
183  * limit violation
184  *
185  * --x- ---- ---- ----
186  * supervisor only
187  *
188  * ---- x--- ---- ----
189  * write protected
190  *
191  * ---- -x-- ---- ----
192  * invalid
193  *
194  * ---- --x- ---- ----
195  * modified
196  *
197  * ---- ---- -x-- ----
198  * transparent access
199  *
200  * ---- ---- ---- -xxx
201  * number of levels (number of tables accessed during search)
202  *
203  */
204 
205 #define MMUSR_BUS_ERROR         0x8000
206 #define MMUSR_LIMIT_VIOLATION   0x4000
207 #define MMUSR_SUPER_VIOLATION   0x2000
208 #define MMUSR_WRITE_PROTECTED   0x0800
209 #define MMUSR_INVALID           0x0400
210 #define MMUSR_MODIFIED          0x0200
211 #define MMUSR_TRANSP_ACCESS     0x0040
212 #define MMUSR_NUM_LEVELS_MASK   0x0007
213 
214 /* -- ATC flushing functions -- */
215 
mmu030_flush_cache(uaecptr addr)216 static void mmu030_flush_cache(uaecptr addr)
217 {
218 #if MMU_IPAGECACHE030
219 	mmu030.mmu030_last_logical_address = 0xffffffff;
220 #endif
221 #if MMU_DPAGECACHE030
222 	if (addr == 0xffffffff) {
223 		memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
224 		memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
225 	} else {
226 		uae_u32 idx = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | 7;
227 		for (int i = 0; i < MMUFASTCACHE_ENTRIES030; i++) {
228 			if ((atc_data_cache_read[i].log | 7) == idx)
229 				atc_data_cache_read[i].log = 0xffffffff;
230 			if ((atc_data_cache_write[i].log | 7) == idx)
231 				atc_data_cache_write[i].log = 0xffffffff;
232 		}
233 	}
234 #endif
235 }
236 
237 /* This function flushes ATC entries depending on their function code */
mmu030_flush_atc_fc(uae_u32 fc_base,uae_u32 fc_mask)238 static void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
239     int i;
240     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
241         if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
242             mmu030.atc[i].logical.valid) {
243             mmu030.atc[i].logical.valid = false;
244 #if MMU030_OP_DBG_MSG
245             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
246 #endif
247 		}
248     }
249 	mmu030_flush_cache(0xffffffff);
250 }
251 
252 /* This function flushes ATC entries depending on their logical address
253  * and their function code */
mmu030_flush_atc_page_fc(uaecptr logical_addr,uae_u32 fc_base,uae_u32 fc_mask)254 static void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
255     int i;
256 	logical_addr &= mmu030.translation.page.imask;
257     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
258         if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
259             (mmu030.atc[i].logical.addr == logical_addr) &&
260             mmu030.atc[i].logical.valid) {
261             mmu030.atc[i].logical.valid = false;
262 #if MMU030_OP_DBG_MSG
263             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
264 #endif
265 		}
266     }
267 	mmu030_flush_cache(logical_addr);
268 }
269 
270 /* This function flushes ATC entries depending on their logical address */
mmu030_flush_atc_page(uaecptr logical_addr)271 static void mmu030_flush_atc_page(uaecptr logical_addr) {
272     int i;
273 	logical_addr &= mmu030.translation.page.imask;
274     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
275         if ((mmu030.atc[i].logical.addr == logical_addr) &&
276             mmu030.atc[i].logical.valid) {
277             mmu030.atc[i].logical.valid = false;
278 #if MMU030_OP_DBG_MSG
279             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
280 #endif
281 		}
282     }
283 	mmu030_flush_cache(logical_addr);
284 }
285 
286 /* This function flushes all ATC entries */
mmu030_flush_atc_all(void)287 void mmu030_flush_atc_all(void) {
288 #if MMU030_OP_DBG_MSG
289 	write_log(_T("ATC: Flushing all entries\n"));
290 #endif
291 	int i;
292     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
293         mmu030.atc[i].logical.valid = false;
294     }
295 	mmu030_flush_cache(0xffffffff);
296 }
297 
298 /* -- Helper function for MMU instructions -- */
mmu_op30_helper_get_fc(uae_u16 next)299 static uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
300 	switch (next & 0x0018) {
301 	case 0x0010:
302 	return (next & 0x7);
303 	case 0x0008:
304 	return (m68k_dreg(regs, next & 0x7) & 0x7);
305 	case 0x0000:
306 	if (next & 1) {
307 		return (regs.dfc);
308 	} else {
309 		return (regs.sfc);
310 	}
311 	default:
312 	write_log(_T("MMU_OP30 ERROR: bad fc source! (%04X)\n"), next & 0x0018);
313 	return 0;
314 	}
315 }
316 
317 /* -- MMU instructions -- */
318 
mmu_op30_invea(uae_u32 opcode)319 static bool mmu_op30_invea(uae_u32 opcode)
320 {
321 	int eamode = (opcode >> 3) & 7;
322 	int rreg = opcode & 7;
323 
324 	// Dn, An, (An)+, -(An), immediate and PC-relative not allowed
325 	if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || (eamode == 7 && rreg > 1))
326 		return true;
327 	return false;
328 }
329 
mmu_op30_pmove(uaecptr pc,uae_u32 opcode,uae_u16 next,uaecptr extra)330 bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
331 {
332 	int preg = (next >> 10) & 31;
333 	int rw = (next >> 9) & 1;
334 	int fd = (next >> 8) & 1;
335  	int unused = (next & 0xff);
336 
337 	if (mmu_op30_invea(opcode))
338 		return true;
339 	// unused low 8 bits must be zeroed
340 	if (unused)
341 		return true;
342 	// read and fd set?
343 	if (rw && fd)
344 		return true;
345 
346 #if MMU030_OP_DBG_MSG
347     switch (preg) {
348         case 0x10:
349             write_log(_T("PMOVE: %s TC %08X PC=%08x\n"), rw ? _T("read"):  _T("write"),
350                       rw ? tc_030 : x_get_long(extra), m68k_getpc());
351             break;
352         case 0x12:
353             write_log(_T("PMOVE: %s SRP %08X%08X PC=%08x\n"), rw ? _T("read") : _T("write"),
354                       rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra),
355                       rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4), m68k_getpc());
356             break;
357         case 0x13:
358             write_log(_T("PMOVE: %s CRP %08X%08X PC=%08x\n"), rw ? _T("read") : _T("write"),
359                       rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra),
360                       rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4), m68k_getpc());
361             break;
362         case 0x18:
363             write_log(_T("PMOVE: %s MMUSR %04X PC=%08x\n"), rw ? _T("read") : _T("write"),
364                       rw?mmusr_030:x_get_word(extra), m68k_getpc());
365             break;
366         case 0x02:
367             write_log(_T("PMOVE: %s TT0 %08X PC=%08x\n"), rw ? _T("read") : _T("write"),
368                       rw?tt0_030:x_get_long(extra), m68k_getpc());
369             break;
370         case 0x03:
371             write_log(_T("PMOVE: %s TT1 %08X PC=%08x\n"), rw ? _T("read") : _T("write"),
372                       rw?tt1_030:x_get_long(extra), m68k_getpc());
373             break;
374         default:
375             break;
376     }
377     if (!fd && !rw && !(preg==0x18)) {
378         write_log(_T("PMOVE: flush ATC\n"));
379     }
380 #endif
381 
382 	switch (preg)
383 	{
384         case 0x10: // TC
385             if (rw)
386                 x_put_long (extra, tc_030);
387             else {
388                 tc_030 = x_get_long (extra);
389                 if (mmu030_decode_tc(tc_030, true))
390 					return true;
391             }
392             break;
393         case 0x12: // SRP
394             if (rw) {
395                 x_put_long (extra, srp_030 >> 32);
396                 x_put_long (extra + 4, srp_030);
397             } else {
398                 srp_030 = (uae_u64)x_get_long (extra) << 32;
399                 srp_030 |= x_get_long (extra + 4);
400                 if (mmu030_decode_rp(srp_030))
401 					return true;
402             }
403             break;
404         case 0x13: // CRP
405             if (rw) {
406                 x_put_long (extra, crp_030 >> 32);
407                 x_put_long (extra + 4, crp_030);
408             } else {
409                 crp_030 = (uae_u64)x_get_long (extra) << 32;
410                 crp_030 |= x_get_long (extra + 4);
411                 if (mmu030_decode_rp(crp_030))
412 					return true;
413             }
414             break;
415         case 0x18: // MMUSR
416 			if (fd) {
417 				// FD must be always zero when MMUSR read or write
418 				return true;
419 			}
420             if (rw)
421                 x_put_word (extra, mmusr_030);
422             else
423                 mmusr_030 = x_get_word (extra);
424             break;
425         case 0x02: // TT0
426             if (rw)
427                 x_put_long (extra, tt0_030);
428             else {
429                 tt0_030 = x_get_long (extra);
430                 mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
431             }
432             break;
433         case 0x03: // TT1
434             if (rw)
435                 x_put_long (extra, tt1_030);
436             else {
437                 tt1_030 = x_get_long (extra);
438                 mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
439             }
440             break;
441         default:
442             write_log (_T("Bad PMOVE at %08x\n"),m68k_getpc());
443             return true;
444 	}
445 
446     if (!fd && !rw && preg != 0x18) {
447         mmu030_flush_atc_all();
448     }
449 	tt_enabled = (tt0_030 & TT_ENABLE) || (tt1_030 & TT_ENABLE);
450 	return false;
451 }
452 
mmu_op30_ptest(uaecptr pc,uae_u32 opcode,uae_u16 next,uaecptr extra)453 bool mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
454 {
455     mmu030.status = mmusr_030 = 0;
456 
457     int level = (next&0x1C00)>>10;
458     int rw = (next >> 9) & 1;
459     int a = (next >> 8) & 1;
460     int areg = (next&0xE0)>>5;
461     uae_u32 fc = mmu_op30_helper_get_fc(next);
462     bool write = rw ? false : true;
463     uae_u32 ret = 0;
464 
465 	if (mmu_op30_invea(opcode))
466 		return true;
467     if (!level && a) {
468         write_log(_T("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n"));
469         return true;
470     }
471 
472 #if MMU030_OP_DBG_MSG
473     write_log(_T("PTEST%c: addr = %08X, fc = %i, level = %i, PC=%08x, "),
474               rw?'R':'W', extra, fc, level, m68k_getpc());
475     if (a) {
476         write_log(_T("return descriptor to register A%i\n"), areg);
477     } else {
478         write_log(_T("do not return descriptor\n"));
479     }
480 #endif
481 
482     if (!level) {
483         mmu030_ptest_atc_search(extra, fc, write);
484     } else {
485         ret = mmu030_table_search(extra, fc, write, level);
486         if (a) {
487             m68k_areg (regs, areg) = ret;
488         }
489     }
490     mmusr_030 = mmu030.status;
491 
492 #if MMU030_OP_DBG_MSG
493     write_log(_T("PTEST status: %04X, B = %i, L = %i, S = %i, W = %i, I = %i, M = %i, T = %i, N = %i\n"),
494               mmusr_030, (mmusr_030&MMUSR_BUS_ERROR)?1:0, (mmusr_030&MMUSR_LIMIT_VIOLATION)?1:0,
495               (mmusr_030&MMUSR_SUPER_VIOLATION)?1:0, (mmusr_030&MMUSR_WRITE_PROTECTED)?1:0,
496               (mmusr_030&MMUSR_INVALID)?1:0, (mmusr_030&MMUSR_MODIFIED)?1:0,
497               (mmusr_030&MMUSR_TRANSP_ACCESS)?1:0, mmusr_030&MMUSR_NUM_LEVELS_MASK);
498 #endif
499 	return false;
500 }
501 
mmu_op30_pload(uaecptr pc,uae_u32 opcode,uae_u16 next,uaecptr extra)502 static bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
503 {
504     int rw = (next >> 9) & 1;
505   	int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
506 	uae_u32 fc = mmu_op30_helper_get_fc(next);
507     bool write = rw ? false : true;
508 
509 	if (mmu_op30_invea(opcode))
510 		return true;
511 	if (unused)
512 		return true;
513 
514 #if 0
515     write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
516 #endif
517 
518     mmu030_flush_atc_page(extra);
519     mmu030_table_search(extra, fc, write, 0);
520 	return false;
521 }
522 
mmu_op30_pflush(uaecptr pc,uae_u32 opcode,uae_u16 next,uaecptr extra)523 bool mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
524 {
525 	uae_u16 mode = (next >> 8) & 31;
526     uae_u32 fc_mask = (uae_u32)(next & 0x00E0) >> 5;
527     uae_u32 fc_base = mmu_op30_helper_get_fc(next);
528 	uae_u32 fc_bits = next & 0x7f;
529 
530 #if 0
531     switch (mode) {
532         case 0x1:
533             write_log(_T("PFLUSH: Flush all entries\n"));
534             break;
535         case 0x4:
536             write_log(_T("PFLUSH: Flush by function code only\n"));
537             write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
538             break;
539         case 0x6:
540             write_log(_T("PFLUSH: Flush by function code and effective address\n"));
541             write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
542             write_log(_T("PFLUSH: effective address = %08X\n"), extra);
543             break;
544         default:
545             break;
546     }
547 #endif
548 
549     switch (mode) {
550 		case 0x00: // PLOAD W
551 		case 0x02: // PLOAD R
552 			return mmu_op30_pload(pc, opcode, next, extra);
553         case 0x04:
554 			if (fc_bits)
555 				return true;
556             mmu030_flush_atc_all();
557             break;
558         case 0x10:
559             mmu030_flush_atc_fc(fc_base, fc_mask);
560             break;
561         case 0x18:
562 			if (mmu_op30_invea(opcode))
563 				return true;
564             mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
565             break;
566         default:
567             write_log(_T("PFLUSH %04x-%04x ERROR: bad mode! (%i)\n"), opcode, next, mode);
568 			return true;
569     }
570 	return false;
571 }
572 
573 
574 /* Transparent Translation Registers (TT0 and TT1)
575  *
576  * ---- ---- ---- ---- -xxx x--- x--- x---
577  * reserved, must be 0
578  *
579  * ---- ---- ---- ---- ---- ---- ---- -xxx
580  * function code mask (FC bits to be ignored)
581  *
582  * ---- ---- ---- ---- ---- ---- -xxx ----
583  * function code base (FC value for transparent block)
584  *
585  * ---- ---- ---- ---- ---- ---x ---- ----
586  * 0 = r/w field used, 1 = read and write is transparently translated
587  *
588  * ---- ---- ---- ---- ---- --x- ---- ----
589  * r/w field: 0 = write ..., 1 = read access transparent
590  *
591  * ---- ---- ---- ---- ---- -x-- ---- ----
592  * cache inhibit: 0 = caching allowed, 1 = caching inhibited
593  *
594  * ---- ---- ---- ---- x--- ---- ---- ----
595  * 0 = transparent translation enabled disabled, 1 = enabled
596  *
597  * ---- ---- xxxx xxxx ---- ---- ---- ----
598  * logical address mask
599  *
600  * xxxx xxxx ---- ---- ---- ---- ---- ----
601  * logical address base
602  *
603  */
604 
605 /* TT comparison results */
606 #define TT_NO_MATCH	0x1
607 #define TT_OK_MATCH	0x2
608 #define TT_NO_READ  0x4
609 #define TT_NO_WRITE	0x8
610 
mmu030_decode_tt(uae_u32 TT)611 TT_info mmu030_decode_tt(uae_u32 TT) {
612 
613     TT_info ret;
614 
615     ret.fc_mask = ~((TT&TT_FC_MASK)|0xFFFFFFF8);
616     ret.fc_base = (TT&TT_FC_BASE)>>4;
617     ret.addr_base = TT & TT_ADDR_BASE;
618     ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
619 
620 #if 0
621     if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
622         write_log(_T("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n"));
623     }
624 #endif
625 
626 #if MMU030_REG_DBG_MSG /* enable or disable debugging messages */
627     write_log(_T("\n"));
628     write_log(_T("TRANSPARENT TRANSLATION: %08X\n"), TT);
629     write_log(_T("\n"));
630 
631     write_log(_T("TT: transparent translation "));
632     if (TT&TT_ENABLE) {
633         write_log(_T("enabled\n"));
634     } else {
635         write_log(_T("disabled\n"));
636         return ret;
637     }
638 
639     write_log(_T("TT: caching %s\n"), (TT&TT_CI) ? _T("inhibited") : _T("enabled"));
640     write_log(_T("TT: read-modify-write "));
641     if (TT&TT_RWM) {
642         write_log(_T("enabled\n"));
643     } else {
644         write_log(_T("disabled (%s only)\n"), (TT&TT_RW) ? _T("read") : _T("write"));
645     }
646     write_log(_T("\n"));
647     write_log(_T("TT: function code base: %08X\n"), ret.fc_base);
648     write_log(_T("TT: function code mask: %08X\n"), ret.fc_mask);
649     write_log(_T("\n"));
650     write_log(_T("TT: address base: %08X\n"), ret.addr_base);
651     write_log(_T("TT: address mask: %08X\n"), ret.addr_mask);
652     write_log(_T("\n"));
653 #endif
654 
655     return ret;
656 }
657 
658 /* This function checks if an address matches a transparent
659  * translation register */
660 
661 /* FIXME:
662  * If !(tt&TT_RMW) neither the read nor the write portion
663  * of a read-modify-write cycle is transparently translated! */
664 
mmu030_do_match_ttr(uae_u32 tt,TT_info comp,uaecptr addr,uae_u32 fc,bool write)665 static int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
666 {
667 	if (tt & TT_ENABLE)	{	/* transparent translation enabled */
668 
669         /* Compare actual function code with function code base using mask */
670         if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
671 
672             /* Compare actual address with address base using mask */
673             if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
674                 if (tt&TT_RWM) {  /* r/w field disabled */
675                     return TT_OK_MATCH;
676                 } else {
677                     if (tt&TT_RW) { /* read access transparent */
678                         return write ? TT_NO_WRITE : TT_OK_MATCH;
679                     } else {        /* write access transparent */
680                         return write ? TT_OK_MATCH : TT_NO_READ; /* TODO: check this! */
681                     }
682                 }
683             }
684 		}
685 	}
686 	return TT_NO_MATCH;
687 }
688 
mmu030_do_match_lrmw_ttr(uae_u32 tt,TT_info comp,uaecptr addr,uae_u32 fc)689 static int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
690 {
691 	if ((tt & TT_ENABLE) && (tt & TT_RWM))	{	/* transparent translation enabled */
692 
693         /* Compare actual function code with function code base using mask */
694         if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
695 
696             /* Compare actual address with address base using mask */
697             if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
698 				return TT_OK_MATCH;
699             }
700 		}
701 	}
702 	return TT_NO_MATCH;
703 }
704 
705 /* This function compares the address with both transparent
706  * translation registers and returns the result */
707 
mmu030_match_ttr(uaecptr addr,uae_u32 fc,bool write)708 static int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
709 {
710     int tt0, tt1;
711 
712     tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
713     if (tt0&TT_OK_MATCH) {
714 		if (tt0_030&TT_CI)
715 	        mmu030_cache_state = CACHE_DISABLE_MMU;
716 	}
717     tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
718     if (tt1&TT_OK_MATCH) {
719 		if (tt0_030&TT_CI)
720 	        mmu030_cache_state = CACHE_DISABLE_MMU;
721     }
722 
723     return (tt0|tt1);
724 }
725 
mmu030_match_ttr_access(uaecptr addr,uae_u32 fc,bool write)726 static int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write)
727 {
728     int tt0, tt1;
729 	if (!tt_enabled)
730 		return 0;
731     tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
732     tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
733     return (tt0|tt1) & TT_OK_MATCH;
734 }
735 
736 /* Locked Read-Modify-Write */
mmu030_match_lrmw_ttr_access(uaecptr addr,uae_u32 fc)737 static int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
738 {
739     int tt0, tt1;
740 
741  	if (!tt_enabled)
742 		return 0;
743     tt0 = mmu030_do_match_lrmw_ttr(tt0_030, mmu030.transparent.tt0, addr, fc);
744     tt1 = mmu030_do_match_lrmw_ttr(tt1_030, mmu030.transparent.tt1, addr, fc);
745     return (tt0|tt1) & TT_OK_MATCH;
746 }
747 
748 /* Translation Control Register:
749  *
750  * x--- ---- ---- ---- ---- ---- ---- ----
751  * translation: 1 = enable, 0 = disable
752  *
753  * ---- --x- ---- ---- ---- ---- ---- ----
754  * supervisor root: 1 = enable, 0 = disable
755  *
756  * ---- ---x ---- ---- ---- ---- ---- ----
757  * function code lookup: 1 = enable, 0 = disable
758  *
759  * ---- ---- xxxx ---- ---- ---- ---- ----
760  * page size:
761  * 1000 = 256 bytes
762  * 1001 = 512 bytes
763  * 1010 =  1 kB
764  * 1011 =  2 kB
765  * 1100 =  4 kB
766  * 1101 =  8 kB
767  * 1110 = 16 kB
768  * 1111 = 32 kB
769  *
770  * ---- ---- ---- xxxx ---- ---- ---- ----
771  * initial shift
772  *
773  * ---- ---- ---- ---- xxxx ---- ---- ----
774  * number of bits for table index A
775  *
776  * ---- ---- ---- ---- ---- xxxx ---- ----
777  * number of bits for table index B
778  *
779  * ---- ---- ---- ---- ---- ---- xxxx ----
780  * number of bits for table index C
781  *
782  * ---- ---- ---- ---- ---- ----- ---- xxxx
783  * number of bits for table index D
784  *
785  */
786 
787 
788 #define TC_ENABLE_TRANSLATION   0x80000000
789 #define TC_ENABLE_SUPERVISOR    0x02000000
790 #define TC_ENABLE_FCL           0x01000000
791 
792 #define TC_PS_MASK              0x00F00000
793 #define TC_IS_MASK              0x000F0000
794 
795 #define TC_TIA_MASK             0x0000F000
796 #define TC_TIB_MASK             0x00000F00
797 #define TC_TIC_MASK             0x000000F0
798 #define TC_TID_MASK             0x0000000F
799 
mmu030_do_fake_prefetch(void)800 static void mmu030_do_fake_prefetch(void)
801 {
802 	if (currprefs.cpu_compatible)
803 		return;
804 	// fetch next opcode before MMU state switches.
805 	// There are programs that do following:
806 	// - enable MMU
807 	// - JMP (An)
808 	// "enable MMU" unmaps memory under us.
809 	TRY (prb) {
810 		uaecptr pc = m68k_getpci();
811 		mmu030_fake_prefetch = -1;
812 		mmu030_fake_prefetch_addr = mmu030_translate(pc, regs.s != 0, false, false);
813 		mmu030_fake_prefetch = x_prefetch(0);
814 		// A26x0 ROM code switches off rom
815 		// NOP
816 		// JMP (a0)
817 		if (mmu030_fake_prefetch == 0x4e71)
818 			mmu030_fake_prefetch = x_prefetch(2);
819 	} CATCH (prb) {
820 		// didn't work, oh well..
821 		mmu030_fake_prefetch = -1;
822 	} ENDTRY
823 }
824 
mmu030_decode_tc(uae_u32 TC,bool check)825 bool mmu030_decode_tc(uae_u32 TC, bool check)
826 {
827 #if MMU_IPAGECACHE030
828 	mmu030.mmu030_last_logical_address = 0xffffffff;
829 #endif
830 
831 	if (currprefs.mmu_ec)
832 		TC &= ~TC_ENABLE_TRANSLATION;
833     /* Set MMU condition */
834     if (TC & TC_ENABLE_TRANSLATION) {
835 		if (!mmu030.enabled && check)
836 			mmu030_do_fake_prefetch();
837         mmu030.enabled = true;
838     } else {
839 		if (mmu030.enabled) {
840 			mmu030_do_fake_prefetch();
841 			write_log(_T("MMU disabled PC=%08x\n"), M68K_GETPC);
842 		}
843         mmu030.enabled = false;
844         return false;
845     }
846 
847     /* Note: 0 = Table A, 1 = Table B, 2 = Table C, 3 = Table D */
848     int i, j;
849     uae_u8 TI_bits[4] = {0,0,0,0};
850 
851     /* Reset variables before extracting new values from TC */
852     for (i = 0; i < 4; i++) {
853         mmu030.translation.table[i].mask = 0;
854         mmu030.translation.table[i].shift = 0;
855     }
856 
857 
858     /* Extract initial shift and page size values from TC register */
859     mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
860     mmu030.translation.page.size3m =  mmu030.translation.page.size - 3;
861     mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
862 	regs.mmu_page_size = 1 << mmu030.translation.page.size;
863 
864 	write_log(_T("68030 MMU enabled. Page size = %d PC=%08x\n"), regs.mmu_page_size, M68K_GETPC);
865 
866 	if (mmu030.translation.page.size<8) {
867         write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad page size: %i byte)\n"),
868                   1<<mmu030.translation.page.size);
869         Exception(56); /* MMU Configuration Exception */
870         return true;
871     }
872 	mmu030.translation.page.mask = regs.mmu_page_size - 1;
873 	mmu030.translation.page.imask = ~mmu030.translation.page.mask;
874 
875     /* Calculate masks and shifts for later extracting table indices
876      * from logical addresses using: index = (addr&mask)>>shift */
877 
878     /* Get number of bits for each table index */
879     for (i = 0; i < 4; i++) {
880         j = (3-i)*4;
881         TI_bits[i] = (TC >> j) & 0xF;
882     }
883 
884     /* Calculate masks and shifts for each table */
885     mmu030.translation.last_table = 0;
886     uae_u8 shift = 32 - mmu030.translation.init_shift;
887     for (i = 0; (i < 4) && TI_bits[i]; i++) {
888         /* Get the shift */
889         shift -= TI_bits[i];
890         mmu030.translation.table[i].shift = shift;
891         /* Build the mask */
892         for (j = 0; j < TI_bits[i]; j++) {
893             mmu030.translation.table[i].mask |= (1<<(mmu030.translation.table[i].shift + j));
894         }
895         /* Update until reaching the last table */
896         mmu030.translation.last_table = i;
897     }
898 
899 #if MMU030_REG_DBG_MSG
900     /* At least one table has to be defined using at least
901      * 1 bit for the index. At least 2 bits are necessary
902      * if there is no second table. If these conditions are
903      * not met, it will automatically lead to a sum <32
904      * and cause an exception (see below). */
905     if (!TI_bits[0]) {
906         write_log(_T("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n"));
907     } else if ((TI_bits[0]<2) && !TI_bits[1]) {
908         write_log(_T("MMU Configuration Exception: Bad value in TC register! (no second table index defined and)\n"));
909         write_log(_T("MMU Configuration Exception: Bad value in TC register! (only 1 bit for first table index)\n"));
910     }
911 #endif
912 
913     /* TI fields are summed up until a zero field is reached (see above
914      * loop). The sum of all TI field values plus page size and initial
915      * shift has to be 32: IS + PS + TIA + TIB + TIC + TID = 32 */
916     if ((shift-mmu030.translation.page.size)!=0) {
917         write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad sum)\n"));
918         Exception(56); /* MMU Configuration Exception */
919         return true;
920     }
921 
922 #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
923     write_log(_T("\n"));
924     write_log(_T("TRANSLATION CONTROL: %08X\n"), TC);
925     write_log(_T("\n"));
926     write_log(_T("TC: translation %s\n"), (TC&TC_ENABLE_TRANSLATION ? _T("enabled") : _T("disabled")));
927     write_log(_T("TC: supervisor root pointer %s\n"), (TC&TC_ENABLE_SUPERVISOR ? _T("enabled") : _T("disabled")));
928     write_log(_T("TC: function code lookup %s\n"), (TC&TC_ENABLE_FCL ? _T("enabled") : _T("disabled")));
929     write_log(_T("\n"));
930 
931     write_log(_T("TC: Initial Shift: %i\n"), mmu030.translation.init_shift);
932     write_log(_T("TC: Page Size: %i byte\n"), (1<<mmu030.translation.page.size));
933     write_log(_T("\n"));
934 
935     for (i = 0; i <= mmu030.translation.last_table; i++) {
936         write_log(_T("TC: Table %c: mask = %08X, shift = %i\n"), table_letter[i], mmu030.translation.table[i].mask, mmu030.translation.table[i].shift);
937     }
938 
939     write_log(_T("TC: Page:    mask = %08X\n"), mmu030.translation.page.mask);
940     write_log(_T("\n"));
941 
942     write_log(_T("TC: Last Table: %c\n"), table_letter[mmu030.translation.last_table]);
943     write_log(_T("\n"));
944 #endif
945 	return false;
946 }
947 
948 
949 
950 /* Root Pointer Registers (SRP and CRP)
951  *
952  * ---- ---- ---- ---- xxxx xxxx xxxx xx-- ---- ---- ---- ---- ---- ---- ---- xxxx
953  * reserved, must be 0
954  *
955  * ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
956  * table A address
957  *
958  * ---- ---- ---- ---- ---- ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- ----
959  * descriptor type
960  *
961  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
962  * limit
963  *
964  * x--- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
965  * 0 = upper limit, 1 = lower limit
966  *
967  */
968 
969 
970 #define RP_ADDR_MASK    (UVAL64(0x00000000FFFFFFF0))
971 #define RP_DESCR_MASK   (UVAL64(0x0000000300000000))
972 #define RP_LIMIT_MASK   (UVAL64(0x7FFF000000000000))
973 #define RP_LOWER_MASK   (UVAL64(0x8000000000000000))
974 
975 #define RP_ZERO_BITS 0x0000FFFC /* These bits in upper longword of RP must be 0 */
976 
mmu030_decode_rp(uae_u64 RP)977 bool mmu030_decode_rp(uae_u64 RP) {
978 
979     uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
980     if (!descriptor_type) { /* If descriptor type is invalid */
981         write_log(_T("MMU Configuration Exception: Root Pointer is invalid!\n"));
982         Exception(56); /* MMU Configuration Exception */
983 		return true;
984     }
985 	return false;
986 
987 #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
988     uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
989     uae_u32 first_addr = (RP & RP_ADDR_MASK);
990 
991     write_log(_T("\n"));
992     write_log(_T("ROOT POINTER: %08X%08X\n"), (uae_u32)(RP>>32)&0xFFFFFFFF, (uae_u32)(RP&0xFFFFFFFF));
993     write_log(_T("\n"));
994 
995     write_log(_T("RP: descriptor type = %i "), descriptor_type);
996     switch (descriptor_type) {
997         case 0:
998             write_log(_T("(invalid descriptor)\n"));
999             break;
1000         case 1:
1001             write_log(_T("(early termination page descriptor)\n"));
1002             break;
1003         case 2:
1004             write_log(_T("(valid 4 byte descriptor)\n"));
1005             break;
1006         case 3:
1007             write_log(_T("(valid 8 byte descriptor)\n"));
1008             break;
1009     }
1010 
1011     write_log(_T("RP: %s limit = %i\n"), (RP&RP_LOWER_MASK) ? _T("lower") : _T("upper"), table_limit);
1012 
1013     write_log(_T("RP: first table address = %08X\n"), first_addr);
1014     write_log(_T("\n"));
1015 #endif
1016 }
1017 
mmu030_atc_handle_history_bit(int entry_num)1018 static void mmu030_atc_handle_history_bit(int entry_num) {
1019     int j;
1020     mmu030.atc[entry_num].mru = 1;
1021     for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1022         if (!mmu030.atc[j].mru)
1023             break;
1024     }
1025     /* If there are no more zero-bits, reset all */
1026     if (j==ATC030_NUM_ENTRIES) {
1027         for (j=0; j<ATC030_NUM_ENTRIES; j++) {
1028             mmu030.atc[j].mru = 0;
1029         }
1030         mmu030.atc[entry_num].mru = 1;
1031 #if MMU030_ATC_DBG_MSG
1032         write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
1033 #endif
1034 	}
1035 }
1036 
desc_put_long(uaecptr addr,uae_u32 v)1037 static void desc_put_long(uaecptr addr, uae_u32 v)
1038 {
1039 	x_phys_put_long(addr, v);
1040 }
desc_get_long(uaecptr addr)1041 static uae_u32 desc_get_long(uaecptr addr)
1042 {
1043 	return x_phys_get_long(addr);
1044 }
desc_get_quad(uaecptr addr,uae_u32 * descr)1045 static void desc_get_quad(uaecptr addr, uae_u32 *descr)
1046 {
1047 	descr[0] = x_phys_get_long(addr);
1048 	descr[1] = x_phys_get_long(addr + 4);
1049 }
1050 
1051 /* Descriptors */
1052 
1053 #define DESCR_TYPE_MASK         0x00000003
1054 
1055 #define DESCR_TYPE_INVALID      0 /* all tables */
1056 
1057 #define DESCR_TYPE_EARLY_TERM   1 /* all but lowest level table */
1058 #define DESCR_TYPE_PAGE         1 /* only lowest level table */
1059 #define DESCR_TYPE_VALID4       2 /* all but lowest level table */
1060 #define DESCR_TYPE_INDIRECT4    2 /* only lowest level table */
1061 #define DESCR_TYPE_VALID8       3 /* all but lowest level table */
1062 #define DESCR_TYPE_INDIRECT8    3 /* only lowest level table */
1063 
1064 #define DESCR_TYPE_VALID_MASK       0x2 /* all but lowest level table */
1065 #define DESCR_TYPE_INDIRECT_MASK    0x2 /* only lowest level table */
1066 
1067 
1068 /* Short format (4 byte):
1069  *
1070  * ---- ---- ---- ---- ---- ---- ---- --xx
1071  * descriptor type:
1072  * 0 = invalid
1073  * 1 = page descriptor (early termination)
1074  * 2 = valid (4 byte)
1075  * 3 = valid (8 byte)
1076  *
1077  *
1078  * table descriptor:
1079  * ---- ---- ---- ---- ---- ---- ---- -x--
1080  * write protect
1081  *
1082  * ---- ---- ---- ---- ---- ---- ---- x---
1083  * update
1084  *
1085  * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
1086  * table address
1087  *
1088  *
1089  * (early termination) page descriptor:
1090  * ---- ---- ---- ---- ---- ---- ---- -x--
1091  * write protect
1092  *
1093  * ---- ---- ---- ---- ---- ---- ---- x---
1094  * update
1095  *
1096  * ---- ---- ---- ---- ---- ---- ---x ----
1097  * modified
1098  *
1099  * ---- ---- ---- ---- ---- ---- -x-- ----
1100  * cache inhibit
1101  *
1102  * ---- ---- ---- ---- ---- ---- x-x- ----
1103  * reserved (must be 0)
1104  *
1105  * xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
1106  * page address
1107  *
1108  *
1109  * indirect descriptor:
1110  * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
1111  * descriptor address
1112  *
1113  */
1114 
1115 #define DESCR_WP       0x00000004
1116 #define DESCR_U        0x00000008
1117 #define DESCR_M        0x00000010 /* only last level table */
1118 #define DESCR_CI       0x00000040 /* only last level table */
1119 
1120 #define DESCR_TD_ADDR_MASK 0xFFFFFFF0
1121 #define DESCR_PD_ADDR_MASK 0xFFFFFF00
1122 #define DESCR_ID_ADDR_MASK 0xFFFFFFFC
1123 
1124 
1125 /* Long format (8 byte):
1126  *
1127  * ---- ---- ---- ---- ---- ---- ---- --xx | ---- ---- ---- ---- ---- ---- ---- ----
1128  * descriptor type:
1129  * 0 = invalid
1130  * 1 = page descriptor (early termination)
1131  * 2 = valid (4 byte)
1132  * 3 = valid (8 byte)
1133  *
1134  *
1135  * table desctriptor:
1136  * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
1137  * write protect
1138  *
1139  * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
1140  * update
1141  *
1142  * ---- ---- ---- ---- ---- ---- xxxx ---- | ---- ---- ---- ---- ---- ---- ---- ----
1143  * reserved (must be 0)
1144  *
1145  * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1146  * supervisor
1147  *
1148  * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1149  * reserved (must be 1111 110)
1150  *
1151  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1152  * limit
1153  *
1154  * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1155  * 0 = upper limit, 1 = lower limit
1156  *
1157  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
1158  * table address
1159  *
1160  *
1161  * (early termination) page descriptor:
1162  * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
1163  * write protect
1164  *
1165  * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
1166  * update
1167  *
1168  * ---- ---- ---- ---- ---- ---- ---x ---- | ---- ---- ---- ---- ---- ---- ---- ----
1169  * modified
1170  *
1171  * ---- ---- ---- ---- ---- ---- -x-- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1172  * cache inhibit
1173  *
1174  * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1175  * supervisor
1176  *
1177  * ---- ---- ---- ---- ---- ---- x-x- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1178  * reserved (must be 0)
1179  *
1180  * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1181  * reserved (must be 1111 110)
1182  *
1183  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1184  * limit (only used with early termination page descriptor)
1185  *
1186  * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1187  * 0 = upper limit, 1 = lower limit (only used with early termination page descriptor)
1188  *
1189  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
1190  * page address
1191  *
1192  *
1193  * indirect descriptor:
1194  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
1195  * descriptor address
1196  *
1197  */
1198 
1199 /* only for long descriptors */
1200 #define DESCR_S        0x00000100
1201 
1202 #define DESCR_LIMIT_MASK   0x7FFF0000
1203 #define DESCR_LOWER_MASK   0x80000000
1204 
1205 
1206 
1207 /* This functions searches through the translation tables. It can be used
1208  * for PTEST (levels 1 to 7). Using level 0 creates an ATC entry. */
1209 
mmu030_table_search(uaecptr addr,uae_u32 fc,bool write,int level)1210 static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
1211     /* During table walk up to 7 different descriptors are used:
1212      * root pointer, descriptors fetched from function code lookup table,
1213      * tables A, B, C and D and one indirect descriptor */
1214     uae_u32 descr[2];
1215     uae_u32 descr_type;
1216     uaecptr descr_addr[7];
1217     uaecptr table_addr = 0;
1218     uaecptr page_addr = 0;
1219     uaecptr indirect_addr = 0;
1220     uae_u32 table_index = 0;
1221     uae_u32 limit = 0;
1222     uae_u32 unused_fields_mask = 0;
1223     bool super = (fc&4) ? true : false;
1224     bool super_violation = false;
1225     bool write_protected = false;
1226     uae_u8 cache_inhibit = CACHE_ENABLE_ALL;
1227     bool descr_modified = false;
1228 
1229     mmu030.status = 0; /* Reset status */
1230 
1231     /* Initial values for condition variables.
1232      * Note: Root pointer is long descriptor. */
1233     int t = 0;
1234     int addr_position = 1;
1235     int next_size = 0;
1236     int descr_size = 8;
1237     int descr_num = 0;
1238     bool early_termination = false;
1239     int old_s;
1240     int i;
1241 
1242 	// Always use supervisor mode to access descriptors
1243     old_s = regs.s;
1244     regs.s = 1;
1245 
1246 	TRY(prb) {
1247         /* Use super user root pointer if enabled in TC register and access is in
1248          * super user mode, else use cpu root pointer. */
1249         if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
1250             descr[0] = (srp_030>>32)&0xFFFFFFFF;
1251             descr[1] = srp_030&0xFFFFFFFF;
1252 #if MMU030_REG_DBG_MSG
1253             write_log(_T("Supervisor Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1254 #endif // MMU030_REG_DBG_MSG
1255         } else {
1256             descr[0] = (crp_030>>32)&0xFFFFFFFF;
1257             descr[1] = crp_030&0xFFFFFFFF;
1258 #if MMU030_REG_DBG_MSG
1259             write_log(_T("CPU Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1260 #endif
1261 		}
1262 
1263         if (descr[0]&RP_ZERO_BITS) {
1264 #if MMU030_REG_DBG_MSG
1265 			write_log(_T("MMU Warning: Root pointer reserved bits are non-zero! %08X\n"), descr[0]);
1266 #endif
1267 			descr[0] &= (~RP_ZERO_BITS);
1268         }
1269 
1270         /* Check descriptor type of root pointer */
1271         descr_type = descr[0]&DESCR_TYPE_MASK;
1272         switch (descr_type) {
1273             case DESCR_TYPE_INVALID:
1274                 write_log(_T("Fatal error: Root pointer is invalid descriptor!\n"));
1275                 mmu030.status |= MMUSR_INVALID;
1276                 goto stop_search;
1277             case DESCR_TYPE_EARLY_TERM:
1278                 write_log(_T("Root pointer is early termination page descriptor.\n"));
1279                 early_termination = true;
1280                 goto handle_page_descriptor;
1281             case DESCR_TYPE_VALID4:
1282                 next_size = 4;
1283                 break;
1284             case DESCR_TYPE_VALID8:
1285                 next_size = 8;
1286                 break;
1287         }
1288 
1289         /* If function code lookup is enabled in TC register use function code as
1290          * index for top level table, limit check not required */
1291 
1292         if (tc_030&TC_ENABLE_FCL) {
1293             write_log(_T("Function code lookup enabled, FC = %i\n"), fc);
1294 
1295             addr_position = (descr_size==4) ? 0 : 1;
1296             table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1297             table_index = fc; /* table index is function code */
1298             write_log(_T("Table FCL at %08X: index = %i, "),table_addr,table_index);
1299 
1300             /* Fetch next descriptor */
1301             descr_num++;
1302             descr_addr[descr_num] = table_addr+(table_index*next_size);
1303 
1304             if (next_size==4) {
1305                 descr[0] = desc_get_long(descr_addr[descr_num]);
1306 #if MMU030_REG_DBG_MSG
1307                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
1308 #endif
1309             } else {
1310 				desc_get_quad(descr_addr[descr_num], descr);
1311 #if MMU030_REG_DBG_MSG
1312                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1313 #endif
1314             }
1315 
1316             descr_size = next_size;
1317 
1318             /* Check descriptor type */
1319             descr_type = descr[0]&DESCR_TYPE_MASK;
1320             switch (descr_type) {
1321                 case DESCR_TYPE_INVALID:
1322                     write_log(_T("Invalid descriptor!\n"));
1323                     /* stop table walk */
1324                     mmu030.status |= MMUSR_INVALID;
1325                     goto stop_search;
1326                 case DESCR_TYPE_EARLY_TERM:
1327 #if MMU030_REG_DBG_MSG
1328                     write_log(_T("Early termination page descriptor!\n"));
1329 #endif
1330 					early_termination = true;
1331                     goto handle_page_descriptor;
1332                 case DESCR_TYPE_VALID4:
1333                     next_size = 4;
1334                     break;
1335                 case DESCR_TYPE_VALID8:
1336                     next_size = 8;
1337                     break;
1338             }
1339         }
1340 
1341 
1342         /* Upper level tables */
1343         do {
1344             if (descr_num) { /* if not root pointer */
1345                 /* Check protection */
1346                 if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
1347                     super_violation = true;
1348                 }
1349                 if (descr[0]&DESCR_WP) {
1350                     write_protected = true;
1351                 }
1352 
1353                 /* Set the updated bit */
1354                 if (!level && !(descr[0]&DESCR_U) && !super_violation) {
1355                     descr[0] |= DESCR_U;
1356                     desc_put_long(descr_addr[descr_num], descr[0]);
1357                 }
1358 
1359                 /* Update status bits */
1360                 mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
1361                 mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
1362 
1363                 /* Check if ptest level is reached */
1364                 if (level && (level==descr_num)) {
1365                     goto stop_search;
1366                 }
1367             }
1368 
1369             addr_position = (descr_size==4) ? 0 : 1;
1370             table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
1371             table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1372 #if MMU030_REG_DBG_MSG
1373             write_log(_T("Table %c at %08X: index = %i, "),table_letter[t],table_addr,table_index);
1374 #endif // MMU030_REG_DBG_MSG
1375             t++; /* Proceed to the next table */
1376 
1377             /* Perform limit check */
1378             if (descr_size==8) {
1379                 limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1380                 if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1381                     mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1382 #if MMU030_REG_DBG_MSG
1383                     write_log(_T("limit violation (lower limit %i)\n"),limit);
1384 #endif
1385                     goto stop_search;
1386                 }
1387                 if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1388                     mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1389 #if MMU030_REG_DBG_MSG
1390                     write_log(_T("limit violation (upper limit %i)\n"),limit);
1391 #endif
1392                     goto stop_search;
1393                 }
1394             }
1395 
1396             /* Fetch next descriptor */
1397             descr_num++;
1398             descr_addr[descr_num] = table_addr+(table_index*next_size);
1399 
1400             if (next_size==4) {
1401                 descr[0] = desc_get_long(descr_addr[descr_num]);
1402 #if MMU030_REG_DBG_MSG
1403                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
1404 #endif
1405             } else {
1406 				desc_get_quad(descr_addr[descr_num], descr);
1407 #if MMU030_REG_DBG_MSG
1408                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1409 #endif
1410             }
1411 
1412             descr_size = next_size;
1413 
1414             /* Check descriptor type */
1415             descr_type = descr[0]&DESCR_TYPE_MASK;
1416             switch (descr_type) {
1417                 case DESCR_TYPE_INVALID:
1418 #if MMU030_REG_DBG_MSG
1419                     write_log(_T("Invalid descriptor!\n"));
1420 #endif
1421 					/* stop table walk */
1422                     mmu030.status |= MMUSR_INVALID;
1423                     goto stop_search;
1424                 case DESCR_TYPE_EARLY_TERM:
1425                     /* go to last level table handling code */
1426                     if (t<=mmu030.translation.last_table) {
1427 #if MMU030_REG_DBG_MSG
1428                         write_log(_T("Early termination page descriptor!\n"));
1429 #endif
1430 						early_termination = true;
1431                     }
1432                     goto handle_page_descriptor;
1433                 case DESCR_TYPE_VALID4:
1434                     next_size = 4;
1435                     break;
1436                 case DESCR_TYPE_VALID8:
1437                     next_size = 8;
1438                     break;
1439             }
1440         } while (t<=mmu030.translation.last_table);
1441 
1442 
1443         /* Handle indirect descriptor */
1444 
1445         /* Check if ptest level is reached */
1446         if (level && (level==descr_num)) {
1447             goto stop_search;
1448         }
1449 
1450         addr_position = (descr_size==4) ? 0 : 1;
1451         indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1452 #if MMU030_REG_DBG_MSG
1453         write_log(_T("Page indirect descriptor at %08X: "),indirect_addr);
1454 #endif
1455 
1456         /* Fetch indirect descriptor */
1457         descr_num++;
1458         descr_addr[descr_num] = indirect_addr;
1459 
1460         if (next_size==4) {
1461             descr[0] = desc_get_long(descr_addr[descr_num]);
1462 #if MMU030_REG_DBG_MSG
1463             write_log(_T("descr = %08X\n"),descr[0]);
1464 #endif
1465 		} else {
1466 			desc_get_quad(descr_addr[descr_num], descr);
1467 #if MMU030_REG_DBG_MSG
1468             write_log(_T("descr = %08X%08X"),descr[0],descr[1]);
1469 #endif
1470 		}
1471 
1472         descr_size = next_size;
1473 
1474         /* Check descriptor type, only page descriptor is valid */
1475         descr_type = descr[0]&DESCR_TYPE_MASK;
1476         if (descr_type!=DESCR_TYPE_PAGE) {
1477             mmu030.status |= MMUSR_INVALID;
1478             goto stop_search;
1479         }
1480 
1481     handle_page_descriptor:
1482 
1483         if (descr_num) { /* if not root pointer */
1484             /* check protection */
1485             if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
1486                 super_violation = true;
1487             }
1488             if (descr[0]&DESCR_WP) {
1489                 write_protected = true;
1490             }
1491 
1492             if (!level && !super_violation) {
1493                 /* set modified bit */
1494                 if (!(descr[0]&DESCR_M) && write && !write_protected) {
1495                     descr[0] |= DESCR_M;
1496                     descr_modified = true;
1497                 }
1498                 /* set updated bit */
1499                 if (!(descr[0]&DESCR_U)) {
1500                     descr[0] |= DESCR_U;
1501                     descr_modified = true;
1502                 }
1503                 /* write modified descriptor if necessary */
1504                 if (descr_modified) {
1505                     desc_put_long(descr_addr[descr_num], descr[0]);
1506                 }
1507             }
1508 
1509             /* update status bits */
1510             mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
1511             mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
1512 
1513             /* check if caching is inhibited */
1514             cache_inhibit = (descr[0]&DESCR_CI) ? CACHE_DISABLE_MMU : CACHE_ENABLE_ALL;
1515 
1516             /* check for the modified bit and set it in the status register */
1517             mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
1518         }
1519 
1520         /* Check limit using next index field of logical address.
1521          * Limit is only checked on early termination. If we are
1522          * still at root pointer level, only check limit, if FCL
1523          * is disabled. */
1524         if (early_termination) {
1525             if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
1526                 if (descr_size==8) {
1527                     table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
1528                     limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
1529                     if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
1530                         mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1531 #if MMU030_REG_DBG_MSG
1532                         write_log(_T("Limit violation (lower limit %i)\n"),limit);
1533 #endif
1534                         goto stop_search;
1535                     }
1536                     if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
1537                         mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1538 #if MMU030_REG_DBG_MSG
1539                         write_log(_T("Limit violation (upper limit %i)\n"),limit);
1540 #endif
1541                         goto stop_search;
1542                     }
1543                 }
1544             }
1545             /* Get all unused bits of the logical address table index field.
1546              * they are added to the page address */
1547             /* TODO: They should be added via "unsigned addition". How to? */
1548             do {
1549                 unused_fields_mask |= mmu030.translation.table[t].mask;
1550                 t++;
1551             } while (t<=mmu030.translation.last_table);
1552             page_addr = addr&unused_fields_mask;
1553 #if MMU030_REG_DBG_MSG
1554             write_log(_T("Logical address unused bits: %08X (mask = %08X)\n"),
1555                       page_addr,unused_fields_mask);
1556 #endif
1557 		}
1558 
1559         /* Get page address */
1560         addr_position = (descr_size==4) ? 0 : 1;
1561         page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
1562 #if MMU030_REG_DBG_MSG
1563         write_log(_T("Page at %08X\n"),page_addr);
1564 #endif // MMU030_REG_DBG_MSG
1565 
1566     stop_search:
1567         ; /* Make compiler happy */
1568     } CATCH(prb) {
1569         /* We jump to this place, if a bus error occurred during table search.
1570          * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
1571         if (bBusErrorReadWrite) {
1572             descr_num--;
1573         }
1574         mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1575         write_log(_T("MMU: Bus error while %s descriptor!\n"),
1576                   bBusErrorReadWrite?_T("reading"):_T("writing"));
1577     } ENDTRY;
1578 
1579     // Restore original supervisor state
1580     regs.s = old_s;
1581 
1582     /* check if we have to handle ptest */
1583     if (level) {
1584         /* Note: wp, m and sv bits are undefined if the invalid bit is set */
1585         mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
1586 
1587         /* If root pointer is page descriptor (descr_num 0), return 0 */
1588         return descr_num ? descr_addr[descr_num] : 0;
1589     }
1590 
1591     /* Find an ATC entry to replace */
1592     /* Search for invalid entry */
1593     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1594         if (!mmu030.atc[i].logical.valid) {
1595             break;
1596         }
1597     }
1598     /* If there are no invalid entries, replace first entry
1599      * with history bit not set */
1600     if (i == ATC030_NUM_ENTRIES) {
1601         for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1602             if (!mmu030.atc[i].mru) {
1603                 break;
1604             }
1605         }
1606 #if MMU030_REG_DBG_MSG
1607         write_log(_T("ATC is full. Replacing entry %i\n"), i);
1608 #endif
1609 	}
1610 	if (i >= ATC030_NUM_ENTRIES) {
1611 		i = 0;
1612 		write_log (_T("ATC entry not found!!!\n"));
1613 	}
1614 
1615     mmu030_atc_handle_history_bit(i);
1616 
1617     /* Create ATC entry */
1618     mmu030.atc[i].logical.addr = addr & mmu030.translation.page.imask; /* delete page index bits */
1619     mmu030.atc[i].logical.fc = fc;
1620     mmu030.atc[i].logical.valid = true;
1621     mmu030.atc[i].physical.addr = page_addr & mmu030.translation.page.imask; /* delete page index bits */
1622     if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
1623         mmu030.atc[i].physical.bus_error = true;
1624     } else {
1625         mmu030.atc[i].physical.bus_error = false;
1626     }
1627     mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1628     mmu030.atc[i].physical.modified = (mmu030.status&MMUSR_MODIFIED) ? true : false;
1629     mmu030.atc[i].physical.write_protect = (mmu030.status&MMUSR_WRITE_PROTECTED) ? true : false;
1630 
1631 	mmu030_flush_cache(mmu030.atc[i].logical.addr);
1632 
1633 #if MMU030_ATC_DBG_MSG
1634     write_log(_T("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n"), i,
1635               mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
1636               mmu030.atc[i].logical.fc);
1637     write_log(_T("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n"), i,
1638               mmu030.atc[i].physical.bus_error?1:0,
1639               mmu030.atc[i].physical.cache_inhibit?1:0,
1640               mmu030.atc[i].physical.write_protect?1:0,
1641               mmu030.atc[i].physical.modified?1:0);
1642 #endif // MMU030_ATC_DBG_MSG
1643 
1644     return 0;
1645 }
1646 
1647 /* This function is used for PTEST level 0. */
mmu030_ptest_atc_search(uaecptr logical_addr,uae_u32 fc,bool write)1648 static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1649     int i;
1650     mmu030.status = 0;
1651 
1652     if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
1653         mmu030.status |= MMUSR_TRANSP_ACCESS;
1654         return;
1655     }
1656 
1657     for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
1658         if ((mmu030.atc[i].logical.fc == fc) &&
1659             (mmu030.atc[i].logical.addr == logical_addr) &&
1660             mmu030.atc[i].logical.valid) {
1661             break;
1662         }
1663     }
1664 
1665     if (i==ATC030_NUM_ENTRIES) {
1666         mmu030.status |= MMUSR_INVALID;
1667         return;
1668     }
1669 
1670     mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1671     /* Note: write protect and modified bits are undefined if the invalid bit is set */
1672     mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
1673     mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
1674 }
1675 
1676 /* Address Translation Cache
1677  *
1678  * The ATC uses a pseudo-least-recently-used algorithm to keep track of
1679  * least recently used entries. They are replaced if the cache is full.
1680  * An internal history-bit (MRU-bit) is used to identify these entries.
1681  * If an entry is accessed, its history-bit is set to 1. If after that
1682  * there are no more entries with zero-bits, all other history-bits are
1683  * set to 0. When no more invalid entries are in the ATC, the first entry
1684  * with a zero-bit is replaced.
1685  *
1686  *
1687  * Logical Portion (28 bit):
1688  * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1689  * logical address (most significant 24 bit)
1690  *
1691  * oooo -xxx ---- ---- ---- ---- ---- ----
1692  * function code
1693  *
1694  * oooo x--- ---- ---- ---- ---- ---- ----
1695  * valid
1696  *
1697  *
1698  * Physical Portion (28 bit):
1699  * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
1700  * physical address
1701  *
1702  * oooo ---x ---- ---- ---- ---- ---- ----
1703  * modified
1704  *
1705  * oooo --x- ---- ---- ---- ---- ---- ----
1706  * write protect
1707  *
1708  * oooo -x-- ---- ---- ---- ---- ---- ----
1709  * cache inhibit
1710  *
1711  * oooo x--- ---- ---- ---- ---- ---- ----
1712  * bus error
1713  *
1714  */
1715 
1716 #define ATC030_MASK         0x0FFFFFFF
1717 #define ATC030_ADDR_MASK    0x00FFFFFF /* after masking shift 8 (<< 8) */
1718 
1719 #define ATC030_LOG_FC   0x07000000
1720 #define ATC030_LOG_V    0x08000000
1721 
1722 #define ATC030_PHYS_M   0x01000000
1723 #define ATC030_PHYS_WP  0x02000000
1724 #define ATC030_PHYS_CI  0x04000000
1725 #define ATC030_PHYS_BE  0x08000000
1726 
1727 #if MMUDEBUG
dump_opcode(uae_u16 opcode)1728 static void dump_opcode(uae_u16 opcode)
1729 {
1730 	struct mnemolookup *lookup;
1731 	struct instr *dp;
1732 	char size = '_';
1733 
1734 	dp = table68k + opcode;
1735 	if (dp->mnemo == i_ILLG) {
1736 		dp = table68k + 0x4AFC;
1737 	}
1738 	for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++);
1739 
1740 	if (!dp->unsized) {
1741 		switch (dp->size)
1742 		{
1743 		case sz_byte:
1744 		size = 'B';
1745 		break;
1746 		case sz_word:
1747 		size = 'W';
1748 		break;
1749 		case sz_long:
1750 		size = 'L';
1751 		break;
1752 		}
1753 	}
1754 	write_log(_T("%04x %s.%c"), opcode, lookup->name, size);
1755 }
1756 #endif
1757 
mmu030_page_fault(uaecptr addr,bool read,int flags,uae_u32 fc)1758 void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
1759 {
1760 	if (flags < 0) {
1761 		read = (regs.mmu_ssw & MMU030_SSW_RW) ? 1 : 0;
1762 		fc = regs.mmu_ssw & MMU030_SSW_FC_MASK;
1763 		flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7);
1764 	}
1765 	regs.mmu_fault_addr = addr;
1766 	if (fc & 1) {
1767 		regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1);
1768 	} else {
1769 		if (currprefs.cpu_compatible) {
1770 			if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
1771 				regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
1772 			} else if (regs.prefetch020_valid[2] != 1) {
1773 				regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
1774 			} else {
1775 				// This happens when CPU prefetches from page
1776 				// end - 4 and both pages are originally invalid.
1777 				regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
1778 			}
1779 		} else {
1780 			regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
1781 		}
1782 	}
1783 	regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
1784 	regs.mmu_ssw |= flags;
1785 	regs.mmu_ssw |= fc;
1786 	// temporary store in 68040+ variables because stack frame creation may modify them.
1787 	regs.wb3_data = mmu030_data_buffer_out;
1788 	regs.wb2_address = mmu030_state[1];
1789     bBusErrorReadWrite = read;
1790 	mm030_stageb_address = addr;
1791 
1792 #if MMUDEBUG
1793 	write_log(_T("MMU: la=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x "),
1794 		addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc,
1795 		regs.instruction_pc, mmu030_data_buffer_out, mmu030_opcode & 0xffff);
1796 	dump_opcode(mmu030_opcode & 0xffff);
1797 	write_log(_T("\n"));
1798 #endif
1799 
1800 #if 0
1801 	if (addr == 0xBFE201)
1802 		write_log("!");
1803 	if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0)
1804 		write_log("!");
1805 	if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1)
1806 		write_log("!");
1807 #endif
1808 
1809 	THROW(2);
1810 }
1811 
mmu030_add_data_read_cache(uaecptr addr,uaecptr phys,uae_u32 fc)1812 static void mmu030_add_data_read_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
1813 {
1814 #if MMU_DPAGECACHE030
1815 	uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size3m) | fc;
1816 	uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
1817 	if (idx2 < MMUFASTCACHE_ENTRIES030 - 1) {
1818 		atc_data_cache_read[idx2].log = idx1;
1819 		atc_data_cache_read[idx2].phys = phys;
1820 		atc_data_cache_read[idx2].cs = mmu030_cache_state;
1821 	}
1822 #endif
1823 }
1824 
mmu030_add_data_write_cache(uaecptr addr,uaecptr phys,uae_u32 fc)1825 static void mmu030_add_data_write_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
1826 {
1827 #if MMU_DPAGECACHE030
1828 	uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size3m) | fc;
1829 	uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
1830 	if (idx2 < MMUFASTCACHE_ENTRIES030 - 1) {
1831 		atc_data_cache_write[idx2].log = idx1;
1832 		atc_data_cache_write[idx2].phys = phys;
1833 		atc_data_cache_write[idx2].cs = mmu030_cache_state;
1834 	}
1835 #endif
1836 }
1837 
mmu030_put_atc(uaecptr addr,int l,uae_u32 fc,uae_u32 size)1838 static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1839     uae_u32 page_index = addr & mmu030.translation.page.mask;
1840     uae_u32 addr_mask = mmu030.translation.page.imask;
1841     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1842 
1843 #if MMU030_ATC_DBG_MSG
1844     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
1845               l, physical_addr, page_index);
1846 #endif
1847 
1848 	if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1849         mmu030_page_fault(addr, false, size, fc);
1850         return 0;
1851     }
1852 
1853 	mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1854 
1855 	mmu030_add_data_write_cache(addr, physical_addr, fc);
1856 
1857 	return physical_addr + page_index;
1858 }
1859 
mmu030_get_atc(uaecptr addr,int l,uae_u32 fc,uae_u32 size)1860 static uaecptr mmu030_get_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1861     uae_u32 page_index = addr & mmu030.translation.page.mask;
1862     uae_u32 addr_mask = mmu030.translation.page.imask;
1863     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1864 
1865 #if MMU030_ATC_DBG_MSG
1866     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
1867               physical_addr, page_index);
1868 #endif
1869 
1870 	if (mmu030.atc[l].physical.bus_error) {
1871         mmu030_page_fault(addr, true, size, fc);
1872         return 0;
1873     }
1874 
1875 	mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1876 
1877 	mmu030_add_data_read_cache(addr, physical_addr, fc);
1878 
1879 	return physical_addr + page_index;
1880 }
1881 
mmu030_get_i_atc(uaecptr addr,int l,uae_u32 fc,uae_u32 size)1882 static uaecptr mmu030_get_i_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1883 	uae_u32 page_index = addr & mmu030.translation.page.mask;
1884 	uae_u32 addr_mask = mmu030.translation.page.imask;
1885 	uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1886 
1887 #if MMU030_ATC_DBG_MSG
1888 	write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
1889 		physical_addr, page_index);
1890 #endif
1891 
1892 	if (mmu030.atc[l].physical.bus_error) {
1893 		mmu030_page_fault(addr, true, size, fc);
1894 		return 0;
1895 	}
1896 
1897 #if MMU_IPAGECACHE030
1898 	mmu030.mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1899 #if MMU_DIRECT_ACCESS
1900 	mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr);
1901 #else
1902 	mmu030.mmu030_last_physical_address = physical_addr;
1903 #endif
1904 	mmu030.mmu030_last_logical_address = (addr & mmu030.translation.page.imask) | fc;
1905 #endif
1906 
1907 	mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1908 
1909 	return physical_addr + page_index;
1910 }
1911 
1912 /* Generic versions of above */
mmu030_put_atc_generic(uaecptr addr,int l,uae_u32 fc,int flags)1913 static uaecptr mmu030_put_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags) {
1914     uae_u32 page_index = addr & mmu030.translation.page.mask;
1915     uae_u32 addr_mask = mmu030.translation.page.imask;
1916     uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1917 
1918 #if MMU030_ATC_DBG_MSG
1919     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
1920               l, physical_addr, page_index);
1921 #endif
1922 
1923     if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
1924 		mmu030_page_fault(addr, false, flags, fc);
1925         return 0;
1926     }
1927 
1928 	mmu030_add_data_write_cache(addr, physical_addr, fc);
1929 
1930 	return physical_addr + page_index;
1931 }
1932 
mmu030_get_atc_generic(uaecptr addr,int l,uae_u32 fc,int flags,bool checkwrite)1933 static uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags, bool checkwrite) {
1934     uae_u32 page_index = addr & mmu030.translation.page.mask;
1935     uae_u32 addr_mask = mmu030.translation.page.imask;
1936     uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1937 
1938 #if MMU030_ATC_DBG_MSG
1939     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
1940               physical_addr, page_index);
1941 #endif
1942 
1943 	if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
1944         mmu030_page_fault(addr, true, flags, fc);
1945         return 0;
1946     }
1947 
1948 	mmu030_add_data_read_cache(addr, physical_addr, fc);
1949 
1950 	return physical_addr + page_index;
1951 }
1952 
1953 
1954 /* This function checks if a certain logical address is in the ATC
1955  * by comparing the logical address and function code to the values
1956  * stored in the ATC entries. If a matching entry is found it sets
1957  * the history bit and returns the cache index of the entry. */
mmu030_logical_is_in_atc(uaecptr addr,uae_u32 fc,bool write)1958 static int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1959     uaecptr logical_addr = 0;
1960     uae_u32 addr_mask = mmu030.translation.page.imask;
1961 	uae_u32 maddr = addr & addr_mask;
1962     int offset = (maddr >> mmu030.translation.page.size) & 0x1f;
1963 
1964     int i, index;
1965 	index = atcindextable[offset];
1966     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1967         logical_addr = mmu030.atc[index].logical.addr;
1968         /* If actual address matches address in ATC */
1969         if (maddr==(logical_addr&addr_mask) &&
1970             (mmu030.atc[index].logical.fc==fc) &&
1971             mmu030.atc[index].logical.valid) {
1972             /* If access is valid write and M bit is not set, invalidate entry
1973              * else return index */
1974             if (!write || mmu030.atc[index].physical.modified ||
1975                 mmu030.atc[index].physical.write_protect ||
1976                 mmu030.atc[index].physical.bus_error) {
1977                 /* Maintain history bit */
1978 					mmu030_atc_handle_history_bit(index);
1979 					atcindextable[offset] = index;
1980 					return index;
1981 				} else {
1982 					mmu030.atc[index].logical.valid = false;
1983 				}
1984 		}
1985 		index++;
1986 		if (index >= ATC030_NUM_ENTRIES)
1987 			index = 0;
1988     }
1989     return -1;
1990 }
1991 
1992 /* Memory access functions:
1993  * If the address matches one of the transparent translation registers
1994  * use it directly as physical address, else check ATC for the
1995  * logical address. If the logical address is not resident in the ATC
1996  * create a new ATC entry and then look up the physical address.
1997  */
1998 
cacheablecheck(uaecptr addr)1999 STATIC_INLINE void cacheablecheck(uaecptr addr)
2000 {
2001 	if (mmu030_cache_state == CACHE_ENABLE_ALL) {
2002 		// MMU didn't inhibit caches, use hardware cache state
2003 		mmu030_cache_state = ce_cachable[addr >> 16];
2004 	}
2005 }
2006 
mmu030_put_long(uaecptr addr,uae_u32 val,uae_u32 fc)2007 void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc)
2008 {
2009  	mmu030_cache_state = CACHE_ENABLE_ALL;
2010 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
2011 #if MMU_DPAGECACHE030
2012 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2013 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2014 		if (atc_data_cache_write[idx2].log == idx1) {
2015 			addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
2016 			mmu030_cache_state = atc_data_cache_write[idx2].cs;
2017 		} else
2018 #endif
2019 		{
2020 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2021 			if (atc_line_num>=0) {
2022 				addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
2023 			} else {
2024 				mmu030_table_search(addr,fc,true,0);
2025 				addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_L);
2026 			}
2027 		}
2028 	}
2029 	cacheablecheck(addr);
2030 	x_phys_put_long(addr,val);
2031 }
2032 
mmu030_put_word(uaecptr addr,uae_u16 val,uae_u32 fc)2033 void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc)
2034 {
2035  	mmu030_cache_state = CACHE_ENABLE_ALL;
2036 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
2037 #if MMU_DPAGECACHE030
2038 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2039 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2040 		if (atc_data_cache_write[idx2].log == idx1) {
2041 			addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
2042 			mmu030_cache_state = atc_data_cache_write[idx2].cs;
2043 		} else
2044 #endif
2045 		{
2046 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2047 			if (atc_line_num>=0) {
2048 				addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
2049 			} else {
2050 				mmu030_table_search(addr, fc, true, 0);
2051 				addr = mmu030_put_atc(addr,  mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_W);
2052 			}
2053 		}
2054 	}
2055 	cacheablecheck(addr);
2056 	x_phys_put_word(addr,val);
2057 }
2058 
mmu030_put_byte(uaecptr addr,uae_u8 val,uae_u32 fc)2059 void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc)
2060 {
2061  	mmu030_cache_state = CACHE_ENABLE_ALL;
2062 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
2063 #if MMU_DPAGECACHE030
2064 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2065 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2066 		if (atc_data_cache_write[idx2].log == idx1) {
2067 			addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
2068 			mmu030_cache_state = atc_data_cache_write[idx2].cs;
2069 		} else
2070 #endif
2071 		{
2072 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2073 			if (atc_line_num>=0) {
2074 				addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
2075 			} else {
2076 				mmu030_table_search(addr, fc, true, 0);
2077 				addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_B);
2078 			}
2079 		}
2080 	}
2081 	cacheablecheck(addr);
2082 	x_phys_put_byte(addr,val);
2083 }
2084 
2085 
mmu030_get_long(uaecptr addr,uae_u32 fc)2086 uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc)
2087 {
2088  	mmu030_cache_state = CACHE_ENABLE_ALL;
2089 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2090 #if MMU_DPAGECACHE030
2091 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2092 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2093 		if (atc_data_cache_read[idx2].log == idx1) {
2094 			addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
2095 			mmu030_cache_state = atc_data_cache_read[idx2].cs;
2096 		} else
2097 #endif
2098 		{
2099 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2100 			if (atc_line_num>=0) {
2101 				addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
2102 			} else {
2103 				mmu030_table_search(addr, fc, false, 0);
2104 				addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_L);
2105 			}
2106 		}
2107 	}
2108 	cacheablecheck(addr);
2109 	return x_phys_get_long(addr);
2110 }
2111 
mmu030_get_word(uaecptr addr,uae_u32 fc)2112 uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc)
2113 {
2114  	mmu030_cache_state = CACHE_ENABLE_ALL;
2115 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2116 #if MMU_DPAGECACHE030
2117 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2118 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2119 		if (atc_data_cache_read[idx2].log == idx1) {
2120 			addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
2121 			mmu030_cache_state = atc_data_cache_read[idx2].cs;
2122 		} else
2123 #endif
2124 		{
2125 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2126 		    if (atc_line_num>=0) {
2127 				addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
2128 			} else {
2129 				mmu030_table_search(addr, fc, false, 0);
2130 				addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_W);
2131 			}
2132 		}
2133 	}
2134 	cacheablecheck(addr);
2135 	return x_phys_get_word(addr);
2136 }
2137 
mmu030_get_byte(uaecptr addr,uae_u32 fc)2138 uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc)
2139 {
2140  	mmu030_cache_state = CACHE_ENABLE_ALL;
2141 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2142 #if MMU_DPAGECACHE030
2143 		uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
2144 		uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
2145 		if (atc_data_cache_read[idx2].log == idx1) {
2146 			addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
2147 			mmu030_cache_state = atc_data_cache_read[idx2].cs;
2148 		} else
2149 #endif
2150 		{
2151 			int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2152 			if (atc_line_num>=0) {
2153 				addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
2154 			} else {
2155 				mmu030_table_search(addr, fc, false, 0);
2156 				addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_B);
2157 			}
2158 		}
2159 	}
2160 	cacheablecheck(addr);
2161 	return x_phys_get_byte(addr);
2162 }
2163 
2164 
mmu030_get_ilong(uaecptr addr,uae_u32 fc)2165 uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc)
2166 {
2167 #if MMU_IPAGECACHE030
2168 	if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
2169 #if MMU_DIRECT_ACCESS
2170 		uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
2171 		return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
2172 #else
2173 		mmu030_cache_state = mmu030.mmu030_cache_state;
2174 		return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
2175 #endif
2176 	}
2177 	mmu030.mmu030_last_logical_address = 0xffffffff;
2178 #endif
2179 
2180  	mmu030_cache_state = CACHE_ENABLE_ALL;
2181 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2182 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2183 		if (atc_line_num >= 0) {
2184 			addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
2185 		} else {
2186 			mmu030_table_search(addr, fc, false, 0);
2187 			addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_L);
2188 		}
2189 	}
2190 	cacheablecheck(addr);
2191 	return x_phys_get_ilong(addr);
2192 }
2193 
mmu030_get_iword(uaecptr addr,uae_u32 fc)2194 uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
2195 
2196 #if MMU_IPAGECACHE030
2197 	if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
2198 #if MMU_DIRECT_ACCESS
2199 		uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
2200 		return (p[0] << 8) | p[1];
2201 #else
2202 		mmu030_cache_state = mmu030.mmu030_cache_state;
2203 		return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
2204 #endif
2205 	}
2206 	mmu030.mmu030_last_logical_address = 0xffffffff;
2207 #endif
2208 
2209  	mmu030_cache_state = CACHE_ENABLE_ALL;
2210 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2211 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2212 		if (atc_line_num >= 0) {
2213 			addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
2214 		} else {
2215 			mmu030_table_search(addr, fc, false, 0);
2216 			addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_W);
2217 		}
2218 	}
2219 	cacheablecheck(addr);
2220 	return x_phys_get_iword(addr);
2221 }
2222 
2223 /* Not commonly used access function */
2224 
mmu030_put_generic_lrmw(uaecptr addr,uae_u32 val,uae_u32 fc,int size,int flags)2225 static void mmu030_put_generic_lrmw(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
2226 {
2227  	mmu030_cache_state = CACHE_ENABLE_ALL;
2228 	if (fc != 7 && (!tt_enabled || !mmu030_match_lrmw_ttr_access(addr,fc)) && mmu030.enabled) {
2229 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2230 		if (atc_line_num>=0) {
2231 			addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
2232 		} else {
2233 			mmu030_table_search(addr, fc, true, 0);
2234 			atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2235 			addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
2236 		}
2237 	}
2238 
2239 	cacheablecheck(addr);
2240 	if (size == sz_byte)
2241 		x_phys_put_byte(addr, val);
2242 	else if (size == sz_word)
2243 		x_phys_put_word(addr, val);
2244 	else
2245 		x_phys_put_long(addr, val);
2246 }
2247 
mmu030_put_generic(uaecptr addr,uae_u32 val,uae_u32 fc,int size,int flags)2248 void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
2249 {
2250  	mmu030_cache_state = CACHE_ENABLE_ALL;
2251 
2252 	if (flags & MMU030_SSW_RM) {
2253 		return mmu030_put_generic_lrmw(addr, val, fc, size, flags);
2254 	}
2255 
2256 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
2257 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2258 		if (atc_line_num>=0) {
2259 			addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
2260 		} else {
2261 			mmu030_table_search(addr, fc, true, 0);
2262 			atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2263 			addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
2264 		}
2265 	}
2266 
2267 	cacheablecheck(addr);
2268 	if (size == sz_byte)
2269 		x_phys_put_byte(addr, val);
2270 	else if (size == sz_word)
2271 		x_phys_put_word(addr, val);
2272 	else
2273 		x_phys_put_long(addr, val);
2274 }
2275 
mmu030_get_generic_lrmw(uaecptr addr,uae_u32 fc,int size,int flags)2276 static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int flags)
2277 {
2278  	mmu030_cache_state = CACHE_ENABLE_ALL;
2279 	if (fc != 7 && (!tt_enabled || !mmu030_match_lrmw_ttr_access(addr,fc)) && mmu030.enabled) {
2280 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2281 		if (atc_line_num>=0) {
2282 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
2283 		} else {
2284 			mmu030_table_search(addr, fc, true, 0);
2285 			atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
2286 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
2287 		}
2288 	}
2289 
2290 	cacheablecheck(addr);
2291 	if (size == sz_byte)
2292 		return x_phys_get_byte(addr);
2293 	else if (size == sz_word)
2294 		return x_phys_get_word(addr);
2295 	return x_phys_get_long(addr);
2296 }
2297 
mmu030_get_generic(uaecptr addr,uae_u32 fc,int size,int flags)2298 uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags)
2299 {
2300  	mmu030_cache_state = CACHE_ENABLE_ALL;
2301 
2302 	if (flags & MMU030_SSW_RM) {
2303 		return mmu030_get_generic_lrmw(addr, fc, size, flags);
2304 	}
2305 
2306 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
2307 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2308 		if (atc_line_num>=0) {
2309 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
2310 		} else {
2311 			mmu030_table_search(addr, fc, false, 0);
2312 			atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
2313 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
2314 		}
2315 	}
2316 
2317 	cacheablecheck(addr);
2318 	if (size == sz_byte)
2319 		return x_phys_get_byte(addr);
2320 	else if (size == sz_word)
2321 		return x_phys_get_word(addr);
2322 	return x_phys_get_long(addr);
2323 }
2324 
uae_mmu030_check_fc(uaecptr addr,bool write,uae_u32 size)2325 uae_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
2326 {
2327 	uae_u32 fc = regs.fc030;
2328  	mmu030_cache_state = CACHE_ENABLE_ALL;
2329 	if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,write)) && mmu030.enabled) {
2330 		uae_u32 flags = mmu030_size[size];
2331 		int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
2332 		if (atc_line_num>=0) {
2333 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, write);
2334 		} else {
2335 			mmu030_table_search(addr, fc, write, 0);
2336 			atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
2337 			addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
2338 		}
2339 	}
2340 	// MMU inhibited
2341 	if (mmu030_cache_state != CACHE_ENABLE_ALL)
2342 		return mmu030_cache_state;
2343 	return ce_cachable[addr >> 16];
2344 }
2345 
2346 /* Locked RMW is rarely used */
uae_mmu030_get_lrmw_fcx(uaecptr addr,int size,int fc)2347 uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
2348 {
2349 	if (size == sz_byte) {
2350 		return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
2351 	} else if (size == sz_word) {
2352 		if (unlikely(is_unaligned_bus(addr, 2)))
2353 			return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM);
2354 		else
2355 			return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W);
2356 	} else {
2357 		if (unlikely(is_unaligned_bus(addr, 4)))
2358 			return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM);
2359 		else
2360 			return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L);
2361 	}
2362 }
uae_mmu030_get_lrmw(uaecptr addr,int size)2363 uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
2364 {
2365 	uae_u32 fc = (regs.s ? 4 : 0) | 1;
2366 	return uae_mmu030_get_lrmw_fcx(addr, size, fc);
2367 }
2368 
uae_mmu030_put_lrmw_fcx(uaecptr addr,uae_u32 val,int size,int fc)2369 void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
2370 {
2371 	if (size == sz_byte) {
2372 		mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
2373 	} else if (size == sz_word) {
2374 		if (unlikely(is_unaligned_bus(addr, 2)))
2375 			mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM);
2376 		else
2377 			mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W);
2378 	} else {
2379 		if (unlikely(is_unaligned_bus(addr, 4)))
2380 			mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM);
2381 		else
2382 			mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L);
2383 	}
2384 }
uae_mmu030_put_lrmw(uaecptr addr,uae_u32 val,int size)2385 void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
2386 {
2387 	uae_u32 fc = (regs.s ? 4 : 0) | 1;
2388 	uae_mmu030_put_lrmw_fcx(addr, val, size, fc);
2389 }
2390 
mmu030_get_ilong_unaligned(uaecptr addr,uae_u32 fc,int flags)2391 uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
2392 {
2393 	uae_u32 res;
2394 
2395 	res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
2396 	SAVE_EXCEPTION;
2397 	TRY(prb) {
2398 		res |= mmu030_get_iword(addr + 2, fc);
2399 		RESTORE_EXCEPTION;
2400 	}
2401 	CATCH(prb) {
2402 		RESTORE_EXCEPTION;
2403 		THROW_AGAIN(prb);
2404 	} ENDTRY
2405 	return res;
2406 }
2407 
unalign_init(uaecptr addr,bool l,bool l2)2408 static void unalign_init(uaecptr addr, bool l, bool l2)
2409 {
2410 	if (l2)
2411 		mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSX;
2412 	if (l)
2413 		mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSL;
2414 	mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESS0;
2415 #if MMU030_DEBUG > 1
2416 	write_log(_T("unalign_init %08x %08x %d %d\n"), addr, mmu030_state[1], l, l2);
2417 #endif
2418 }
unalign_set(int state)2419 static void unalign_set(int state)
2420 {
2421 	mmu030_state[1] |= (1 << state) << (MMU030_STATEFLAG1_SUBACCESS_SHIFT + 1);
2422 #if MMU030_DEBUG > 1
2423 	write_log(_T("unalign_set %d %08x\n"), state, mmu030_state[1]);
2424 #endif
2425 }
unalign_clear(void)2426 static void unalign_clear(void)
2427 {
2428 #if MMU030_DEBUG > 1
2429 	write_log(_T("unalign_clear %08x %08x\n"), mmu030_state[1], mmu030_data_buffer_out);
2430 #endif
2431 	mmu030_state[1] &= ~(MMU030_STATEFLAG1_SUBACCESSL | MMU030_STATEFLAG1_SUBACCESSX |
2432 		MMU030_STATEFLAG1_SUBACCESS0 | MMU030_STATEFLAG1_SUBACCESS1 | MMU030_STATEFLAG1_SUBACCESS2 | MMU030_STATEFLAG1_SUBACCESS3);
2433 }
2434 
mmu030_get_word_unaligned(uaecptr addr,uae_u32 fc,int flags)2435 uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags)
2436 {
2437 	unalign_init(addr, false, false);
2438 	mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_W) << 8;
2439 	unalign_set(0);
2440 	mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
2441 	unalign_clear();
2442 	return mmu030_data_buffer_out;
2443 }
2444 
mmu030_get_long_unaligned(uaecptr addr,uae_u32 fc,int flags)2445 uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
2446 {
2447 	if (likely(!(addr & 1))) {
2448 		unalign_init(addr, true, false);
2449 		mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_word, flags | MMU030_SSW_SIZE_L) << 16;
2450 		unalign_set(0);
2451 		mmu030_data_buffer_out |= mmu030_get_generic(addr + 2, fc, sz_word, flags | MMU030_SSW_SIZE_W);
2452 	} else {
2453 		unalign_init(addr, true, true);
2454 		mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_L) << 24;
2455 		unalign_set(0);
2456 		mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_word, flags | MMU030_SSW_SIZE_W) << 8;
2457 		unalign_set(1);
2458 		mmu030_data_buffer_out |= mmu030_get_generic(addr + 3, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
2459 	}
2460 	unalign_clear();
2461 	return mmu030_data_buffer_out;
2462 }
2463 
mmu030_put_long_unaligned(uaecptr addr,uae_u32 val,uae_u32 fc,int flags)2464 void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags)
2465 {
2466 	if (likely(!(addr & 1))) {
2467 		unalign_init(addr, true, false);
2468 		mmu030_put_generic(addr, val >> 16, fc, sz_word, flags | MMU030_SSW_SIZE_L);
2469 		unalign_set(0);
2470 		mmu030_put_generic(addr + 2, val, fc, sz_word, flags | MMU030_SSW_SIZE_W);
2471 	} else {
2472 		unalign_init(addr, true, true);
2473 		mmu030_put_generic(addr, val >> 24, fc, sz_byte, flags | MMU030_SSW_SIZE_L);
2474 		unalign_set(0);
2475 		mmu030_put_generic(addr + 1, val >> 8, fc, sz_word, flags | MMU030_SSW_SIZE_W);
2476 		unalign_set(1);
2477 		mmu030_put_generic(addr + 3, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
2478 	}
2479 	unalign_clear();
2480 }
2481 
mmu030_put_word_unaligned(uaecptr addr,uae_u16 val,uae_u32 fc,int flags)2482 void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags)
2483 {
2484 	unalign_init(addr, false, false);
2485 	mmu030_put_generic(addr, val >> 8, fc, sz_byte, flags | MMU030_SSW_SIZE_W);
2486 	unalign_set(0);
2487 	mmu030_put_generic(addr + 1, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
2488 	unalign_clear();
2489 }
2490 
2491 
2492 /* Used by debugger */
mmu030_get_addr_atc(uaecptr addr,int l,uae_u32 fc,bool write)2493 static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write) {
2494     uae_u32 page_index = addr & mmu030.translation.page.mask;
2495     uae_u32 addr_mask = mmu030.translation.page.imask;
2496 
2497     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
2498     physical_addr += page_index;
2499 
2500 	if (mmu030.atc[l].physical.bus_error || (write && mmu030.atc[l].physical.write_protect)) {
2501         mmu030_page_fault(addr, write == 0, MMU030_SSW_SIZE_B, fc);
2502         return 0;
2503     }
2504 
2505     return physical_addr;
2506 }
mmu030_translate(uaecptr addr,bool super,bool data,bool write)2507 uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
2508 {
2509 	int fc = (super ? 4 : 0) | (data ? 1 : 2);
2510 	if ((fc==7) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (!mmu030.enabled)) {
2511 		return addr;
2512     }
2513     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
2514 
2515     if (atc_line_num>=0) {
2516         return mmu030_get_addr_atc(addr, atc_line_num, fc, write);
2517     } else {
2518         mmu030_table_search(addr, fc, false, 0);
2519         return mmu030_get_addr_atc(addr, mmu030_logical_is_in_atc(addr,fc,write), fc, write);
2520     }
2521 }
2522 
2523 /* MMU Reset */
mmu030_reset(int hardreset)2524 void mmu030_reset(int hardreset)
2525 {
2526     /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
2527     mmu030.enabled = false;
2528 #if MMU_IPAGECACHE030
2529 	mmu030.mmu030_last_logical_address = 0xffffffff;
2530 #endif
2531 	regs.mmu_page_size = 0;
2532 	if (hardreset >= 0) {
2533 		tc_030 &= ~TC_ENABLE_TRANSLATION;
2534 		tt0_030 &= ~TT_ENABLE;
2535 		tt1_030 &= ~TT_ENABLE;
2536 	}
2537 	if (hardreset > 0) {
2538 		srp_030 = crp_030 = 0;
2539 		tt0_030 = tt1_030 = tc_030 = 0;
2540         mmusr_030 = 0;
2541         mmu030_flush_atc_all();
2542 	}
2543 	mmu030_set_funcs();
2544 }
2545 
mmu030_set_funcs(void)2546 void mmu030_set_funcs(void)
2547 {
2548 	if (currprefs.mmu_model != 68030)
2549 		return;
2550 	if (currprefs.cpu_memory_cycle_exact) {
2551 		x_phys_get_iword = mem_access_delay_wordi_read_ce020;
2552 		x_phys_get_ilong = mem_access_delay_longi_read_ce020;
2553 		x_phys_get_byte = mem_access_delay_byte_read_ce020;
2554 		x_phys_get_word = mem_access_delay_word_read_ce020;
2555 		x_phys_get_long = mem_access_delay_long_read_ce020;
2556 		x_phys_put_byte = mem_access_delay_byte_write_ce020;
2557 		x_phys_put_word = mem_access_delay_word_write_ce020;
2558 		x_phys_put_long = mem_access_delay_long_write_ce020;
2559 	} else {
2560 		x_phys_get_iword = phys_get_word;
2561 		x_phys_get_ilong = phys_get_long;
2562 		x_phys_get_byte = phys_get_byte;
2563 		x_phys_get_word = phys_get_word;
2564 		x_phys_get_long = phys_get_long;
2565 		x_phys_put_byte = phys_put_byte;
2566 		x_phys_put_word = phys_put_word;
2567 		x_phys_put_long = phys_put_long;
2568 	}
2569 }
2570 
2571 #define unalign_done(f) \
2572 	st |= f; \
2573 	mmu030_state[1] = st;
2574 
2575 typedef uae_u32(*unaligned_read_func)(uaecptr addr, uae_u32 fc, int size, int flags);
2576 
mmu030_unaligned_read_continue(uaecptr addr,int fc,unaligned_read_func func)2577 static void mmu030_unaligned_read_continue(uaecptr addr, int fc, unaligned_read_func func)
2578 {
2579 	uae_u32 st = mmu030_state[1];
2580 
2581 #if MMUDEBUG
2582 	write_log(_T("unaligned_read_continue_s: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2583 #endif
2584 
2585 	if (st & MMU030_STATEFLAG1_SUBACCESSL) {
2586 		if (st & MMU030_STATEFLAG1_SUBACCESSX) {
2587 			// odd long access: byte + word + byte
2588 			if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2589 				mmu030_data_buffer_out &= 0x00ffffff;
2590 				mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
2591 #if MMUDEBUG
2592 				write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2593 #endif
2594 				unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2595 				addr++;
2596 			}
2597 			if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2598 				mmu030_data_buffer_out &= 0xff0000ff;
2599 				mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
2600 #if MMUDEBUG
2601 				write_log(_T("unaligned_read_continue_1: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2602 #endif
2603 				unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2604 				addr += 2;
2605 			}
2606 			if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
2607 				mmu030_data_buffer_out &= 0xffffff00;
2608 				mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
2609 				unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
2610 				addr++;
2611 			}
2612 		} else {
2613 			// even but unaligned long access: word + word
2614 			if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2615 				mmu030_data_buffer_out &= 0x0000ffff;
2616 				mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
2617 #if MMUDEBUG
2618 				write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2619 #endif
2620 				unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2621 				addr += 2;
2622 			}
2623 			if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2624 				mmu030_data_buffer_out &= 0xffff0000;
2625 				mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
2626 				unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2627 				addr += 2;
2628 			}
2629 		}
2630 	} else {
2631 		// odd word access: byte + byte
2632 		if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2633 			mmu030_data_buffer_out &= 0x00ff;
2634 			mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
2635 #if MMUDEBUG
2636 			write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2637 #endif
2638 			unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2639 			addr++;
2640 		}
2641 		if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2642 			mmu030_data_buffer_out &= 0xff00;
2643 			mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
2644 			unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2645 			addr++;
2646 		}
2647 	}
2648 
2649 #if MMUDEBUG
2650 	write_log(_T("unaligned_read_continue_e: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2651 #endif
2652 	unalign_clear();
2653 }
2654 
2655 typedef void (*unaligned_write_func)(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
2656 
mmu030_unaligned_write_continue(uaecptr addr,int fc,unaligned_write_func func)2657 static void mmu030_unaligned_write_continue(uaecptr addr, int fc, unaligned_write_func func)
2658 {
2659 	uae_u32 st = mmu030_state[1];
2660 
2661 #if MMUDEBUG
2662 	write_log(_T("unaligned_write_continue_s: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2663 #endif
2664 
2665 	if (st & MMU030_STATEFLAG1_SUBACCESSL) {
2666 		// odd long access: byte + word + byte
2667 		if (st & MMU030_STATEFLAG1_SUBACCESSX) {
2668 			if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2669 				func(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
2670 #if MMUDEBUG
2671 				write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2672 #endif
2673 				unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2674 				addr++;
2675 			}
2676 			if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2677 				func(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
2678 #if MMUDEBUG
2679 				write_log(_T("unaligned_write_continue_1: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2680 #endif
2681 				unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2682 				addr += 2;
2683 			}
2684 			if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
2685 				func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
2686 #if MMUDEBUG
2687 				write_log(_T("unaligned_write_continue_2: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2688 #endif
2689 				unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
2690 				addr++;
2691 			}
2692 		} else {
2693 			// even but unaligned long access: word + word
2694 			if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2695 				func(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
2696 #if MMUDEBUG
2697 				write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2698 #endif
2699 				unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2700 				addr += 2;
2701 			}
2702 			if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2703 				func(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
2704 				unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2705 				addr += 2;
2706 			}
2707 		}
2708 	} else {
2709 		// odd word access: byte + byte
2710 		if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
2711 			func(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
2712 #if MMUDEBUG
2713 			write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2714 #endif
2715 			unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
2716 			addr++;
2717 		}
2718 		if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
2719 			func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
2720 			unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
2721 			addr++;
2722 		}
2723 	}
2724 
2725 #if MMUDEBUG
2726 	write_log(_T("unaligned_write_continue_e: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
2727 #endif
2728 	unalign_clear();
2729 }
2730 
m68k_do_rte_mmu030(uaecptr a7)2731 void m68k_do_rte_mmu030 (uaecptr a7)
2732 {
2733 	struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1];
2734 
2735 	// Restore access error exception state
2736 
2737 	uae_u16 sr = get_word_mmu030(a7);
2738 	uae_u32 pc = get_long_mmu030(a7 + 2);
2739 	uae_u16 format = get_word_mmu030(a7 + 6);
2740 	uae_u16 frame = format >> 12;
2741 	uae_u16 ssw = get_word_mmu030(a7 + 10);
2742 	uae_u32 fault_addr = get_long_mmu030(a7 + 16);
2743 
2744 	// Fetch last word, real CPU does it to allow OS bus handler to map
2745 	// the page if frame crosses pages and following page is not resident.
2746 	if (frame == 0xb)
2747 		get_word_mmu030(a7 + 92 - 2);
2748 	else
2749 		get_word_mmu030(a7 + 32 - 2);
2750 
2751 	// Internal register, our opcode storage area
2752 	uae_u32 oc = get_long_mmu030(a7 + 0x14);
2753 	// Data output buffer
2754 	uae_u32 mmu030_data_buffer_out_v = get_long_mmu030(a7 + 0x18);
2755 	// get_disp_ea_020
2756 	uae_u32 mmu030_disp_store_0 = get_long_mmu030(a7 + 0x1c);
2757 	uae_u32 mmu030_disp_store_1 = get_long_mmu030(a7 + 0x1c + 4);
2758 	// Internal register, misc flags
2759 	uae_u32 ps = get_long_mmu030(a7 + 0x28);
2760 	// Data buffer
2761 	uae_u32 mmu030_data_buffer_in_v = get_long_mmu030(a7 + 0x2c);;
2762 
2763 	uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff);
2764 	// Misc state data
2765 	uae_u32 mmu030_state_0 = get_word_mmu030(a7 + 0x30);
2766 	uae_u32 mmu030_state_1 = get_word_mmu030(a7 + 0x32);
2767 	uae_u32 mmu030_state_2 = get_word_mmu030(a7 + 0x34);
2768 
2769 	uae_u32 mmu030_fmovem_store_0 = 0;
2770 	uae_u32 mmu030_fmovem_store_1 = 0;
2771 	if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
2772 		mmu030_fmovem_store_0 = get_long_mmu030(a7 + 0x5c - (7 + 1) * 4);
2773 		mmu030_fmovem_store_1 = get_long_mmu030(a7 + 0x5c - (8 + 1) * 4);
2774 	}
2775 
2776 	// Rerun "mmu030_opcode" using restored state.
2777 	mmu030_retry = true;
2778 
2779 	if (frame == 0xb) {
2780 
2781 		uae_u16 idxsize = get_word_mmu030 (a7 + 0x36);
2782 		for (int i = 0; i < idxsize + 1; i++) {
2783 			mmu030_ad_v[i].done = i < idxsize;
2784 			mmu030_ad_v[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4);
2785 		}
2786 		mmu030_ad_v[idxsize + 1].done = false;
2787 
2788 		// did we have data fault but DF bit cleared?
2789 		if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
2790 			// DF not set: mark access as done
2791 			mmu030_data_buffer_out_v = mmu030_data_buffer_in_v;
2792 			if (ssw & MMU030_SSW_RM) {
2793 				// Read-Modify-Write: whole instruction is considered done
2794 				write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
2795 				mmu030_retry = false;
2796 			} else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) {
2797 				// if movem, skip next move
2798 				mmu030_state_1 |= MMU030_STATEFLAG1_MOVEM2;
2799 			} else {
2800 				mmu030_ad_v[idxsize].done = true;
2801 				if (ssw & MMU030_SSW_RW) {
2802 					// Read and no DF: use value in data input buffer
2803 					mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v;
2804 				}
2805 			}
2806 			unalign_clear();
2807 		}
2808 		// did we have ins fault and RB bit cleared?
2809 		if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
2810 			uae_u16 stageb = get_word_mmu030 (a7 + 0x0e);
2811 			if (mmu030_opcode_v == -1U) {
2812 				mmu030_opcode_stageb = stageb;
2813 				write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb);
2814 			} else {
2815 				mmu030_ad_v[idxsize].done = true;
2816 				mmu030_ad_v[idxsize].val = stageb;
2817 				write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb);
2818 			}
2819 		}
2820 
2821 		// Retried data access is the only memory access that can be done after this.
2822 
2823 		// restore global state variables
2824 		mmu030_opcode = mmu030_opcode_v;
2825 		mmu030_state[0] = mmu030_state_0;
2826 		mmu030_state[1] = mmu030_state_1;
2827 		mmu030_state[2] = mmu030_state_2;
2828 		mmu030_disp_store[0] = mmu030_disp_store_0;
2829 		mmu030_disp_store[1] = mmu030_disp_store_1;
2830 		mmu030_fmovem_store[0] = mmu030_fmovem_store_0;
2831 		mmu030_fmovem_store[1] = mmu030_fmovem_store_1;
2832 		mmu030_data_buffer_out = mmu030_data_buffer_out_v;
2833 		mmu030_idx = idxsize;
2834 		for (int i = 0; i <= mmu030_idx + 1; i++) {
2835 			mmu030_ad[i].done = mmu030_ad_v[i].done;
2836 			mmu030_ad[i].val = mmu030_ad_v[i].val;
2837 		}
2838 
2839 		m68k_areg(regs, 7) += 92;
2840 		regs.sr = sr;
2841 		MakeFromSR_T0();
2842 		if (pc & 1) {
2843 			exception3i(0x4E73, pc);
2844 			return;
2845 		}
2846 		m68k_setpci(pc);
2847 
2848 		if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) {
2849 
2850 			// Locked-Read-Modify-Write restarts whole instruction.
2851 			mmu030_ad[0].done = false;
2852 
2853 		} else if (ssw & MMU030_SSW_DF) {
2854 
2855 			// retry faulted access
2856 			uaecptr addr = fault_addr;
2857 			bool read = (ssw & MMU030_SSW_RW) != 0;
2858 			int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long);
2859 			int fc = ssw & MMU030_SSW_FC_MASK;
2860 
2861 #if MMU030_DEBUG
2862 			if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
2863 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2864 					write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
2865 				}
2866 			}
2867 			if (mmu030_ad[idxsize].done) {
2868 				write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
2869 			}
2870 #endif
2871 
2872 #if MMU030_DEBUG
2873 			write_log(_T("%08x %08x %08x %08x %08x %d %d %d %08x %08x %04x\n"),
2874 				mmu030_state[1], mmu030_state[2], mmu030_disp_store[0], mmu030_disp_store[1],
2875 				addr, read, size, fc, mmu030_data_buffer_out, mmu030_ad[idxsize].val, ssw);
2876 #endif
2877 
2878 			if (read) {
2879 				if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
2880 					mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic);
2881 				} else {
2882 					switch (size)
2883 					{
2884 						case sz_byte:
2885 						mmu030_data_buffer_out = uae_mmu030_get_byte_fcx(addr, fc);
2886 						break;
2887 						case sz_word:
2888 						mmu030_data_buffer_out = uae_mmu030_get_word_fcx(addr, fc);
2889 						break;
2890 						case sz_long:
2891 						mmu030_data_buffer_out = uae_mmu030_get_long_fcx(addr, fc);
2892 						break;
2893 					}
2894 				}
2895 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
2896 					mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
2897 				} else {
2898 					mmu030_ad[idxsize].val = mmu030_data_buffer_out;
2899 					mmu030_ad[idxsize].done = true;
2900 				}
2901 			} else {
2902 				if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
2903 					mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic);
2904 				} else {
2905 					switch (size)
2906 					{
2907 						case sz_byte:
2908 						uae_mmu030_put_byte_fcx(addr, mmu030_data_buffer_out, fc);
2909 						break;
2910 						case sz_word:
2911 						uae_mmu030_put_word_fcx(addr, mmu030_data_buffer_out, fc);
2912 						break;
2913 						case sz_long:
2914 						uae_mmu030_put_long_fcx(addr, mmu030_data_buffer_out, fc);
2915 						break;
2916 					}
2917 				}
2918 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
2919 					mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
2920 				} else {
2921 					mmu030_ad[idxsize].done = true;
2922 				}
2923 			}
2924 
2925 		}
2926 
2927 		if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) {
2928 			mmu030_retry = false;
2929 		}
2930 
2931 #if MMU030_DEBUG
2932 		if (mmu030_idx >= MAX_MMU030_ACCESS) {
2933 			write_log(_T("mmu030_idx (RTE) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
2934 		}
2935 #endif
2936 
2937 	} else {
2938 		m68k_areg (regs, 7) += 32;
2939 	}
2940 }
2941 
flush_mmu030(uaecptr addr,int n)2942 void flush_mmu030 (uaecptr addr, int n)
2943 {
2944 }
2945 
m68k_do_rts_mmu030(void)2946 void m68k_do_rts_mmu030 (void)
2947 {
2948 	m68k_setpc (get_long_mmu030_state (m68k_areg (regs, 7)));
2949 	m68k_areg (regs, 7) += 4;
2950 }
2951 
m68k_do_bsr_mmu030(uaecptr oldpc,uae_s32 offset)2952 void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
2953 {
2954 	put_long_mmu030_state (m68k_areg (regs, 7) - 4, oldpc);
2955 	m68k_areg (regs, 7) -= 4;
2956 	m68k_incpci (offset);
2957 }
2958 
get_disp_ea_020_mmu030(uae_u32 base,int idx)2959 uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx)
2960 {
2961 	uae_u16 dp;
2962 	int reg;
2963 	uae_u32 v;
2964 	int oldidx;
2965 	int pcadd = 0;
2966 
2967 	// we need to do this hack here because in worst case we don't have enough
2968 	// stack frame space to store two very large 020 addressing mode access state
2969 	// + whatever the instruction itself does.
2970 
2971 	if (mmu030_state[1] & (1 << idx)) {
2972 		m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
2973 		return mmu030_disp_store[idx];
2974 	}
2975 
2976 	oldidx = mmu030_idx;
2977 	dp = next_iword_mmu030_state ();
2978 	pcadd += 1;
2979 
2980 	reg = (dp >> 12) & 15;
2981 	uae_s32 regd = regs.regs[reg];
2982 	if ((dp & 0x800) == 0)
2983 		regd = (uae_s32)(uae_s16)regd;
2984 	regd <<= (dp >> 9) & 3;
2985 	if (dp & 0x100) {
2986 		uae_s32 outer = 0;
2987 		if (dp & 0x80)
2988 			base = 0;
2989 		if (dp & 0x40)
2990 			regd = 0;
2991 
2992 		if ((dp & 0x30) == 0x20) {
2993 			base += (uae_s32)(uae_s16) next_iword_mmu030_state ();
2994 			pcadd += 1;
2995 		}
2996 		if ((dp & 0x30) == 0x30) {
2997 			base += next_ilong_mmu030_state ();
2998 			pcadd += 2;
2999 		}
3000 
3001 		if ((dp & 0x3) == 0x2) {
3002 			outer = (uae_s32)(uae_s16) next_iword_mmu030_state ();
3003 			pcadd += 1;
3004 		}
3005 		if ((dp & 0x3) == 0x3) {
3006 			outer = next_ilong_mmu030_state ();
3007 			pcadd += 2;
3008 		}
3009 
3010 		if ((dp & 0x4) == 0) {
3011 			base += regd;
3012 		}
3013 		if (dp & 0x3) {
3014 			base = get_long_mmu030_state (base);
3015 		}
3016 		if (dp & 0x4) {
3017 			base += regd;
3018 		}
3019 		v = base + outer;
3020 	} else {
3021 		v = base + (uae_s32)((uae_s8)dp) + regd;
3022 	}
3023 
3024 	mmu030_state[1] |= 1 << idx;
3025 	mmu030_state[2] |= pcadd << (idx * 4);
3026 	mmu030_disp_store[idx] = v;
3027 	mmu030_idx = oldidx;
3028 	mmu030_ad[mmu030_idx].done = false;
3029 
3030 	return v;
3031 }
3032 
3033 // cache
3034 
m68k_do_rts_mmu030c(void)3035 void m68k_do_rts_mmu030c (void)
3036 {
3037 	m68k_setpc (get_long_mmu030c_state (m68k_areg (regs, 7)));
3038 	m68k_areg (regs, 7) += 4;
3039 }
3040 
m68k_do_bsr_mmu030c(uaecptr oldpc,uae_s32 offset)3041 void m68k_do_bsr_mmu030c (uaecptr oldpc, uae_s32 offset)
3042 {
3043 	put_long_mmu030c_state (m68k_areg (regs, 7) - 4, oldpc);
3044 	m68k_areg (regs, 7) -= 4;
3045 	m68k_incpci (offset);
3046 }
3047 
3048 
get_disp_ea_020_mmu030c(uae_u32 base,int idx)3049 uae_u32 REGPARAM2 get_disp_ea_020_mmu030c (uae_u32 base, int idx)
3050 {
3051 	uae_u16 dp;
3052 	int reg;
3053 	uae_u32 v;
3054 	int oldidx;
3055 	int pcadd = 0;
3056 
3057 	// we need to do this hack here because in worst case we don't have enough
3058 	// stack frame space to store two very large 020 addressing mode access state
3059 	// + whatever the instruction itself does.
3060 
3061 	if (mmu030_state[1] & (1 << idx)) {
3062 		m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
3063 		return mmu030_disp_store[idx];
3064 	}
3065 
3066 	oldidx = mmu030_idx;
3067 	dp = next_iword_mmu030c_state ();
3068 	pcadd += 1;
3069 
3070 	reg = (dp >> 12) & 15;
3071 	uae_s32 regd = regs.regs[reg];
3072 	if ((dp & 0x800) == 0)
3073 		regd = (uae_s32)(uae_s16)regd;
3074 	regd <<= (dp >> 9) & 3;
3075 	if (dp & 0x100) {
3076 		uae_s32 outer = 0;
3077 		if (dp & 0x80)
3078 			base = 0;
3079 		if (dp & 0x40)
3080 			regd = 0;
3081 
3082 		if ((dp & 0x30) == 0x20) {
3083 			base += (uae_s32)(uae_s16) next_iword_mmu030c_state ();
3084 			pcadd += 1;
3085 		}
3086 		if ((dp & 0x30) == 0x30) {
3087 			base += next_ilong_mmu030c_state ();
3088 			pcadd += 2;
3089 		}
3090 
3091 		if ((dp & 0x3) == 0x2) {
3092 			outer = (uae_s32)(uae_s16) next_iword_mmu030c_state ();
3093 			pcadd += 1;
3094 		}
3095 		if ((dp & 0x3) == 0x3) {
3096 			outer = next_ilong_mmu030c_state ();
3097 			pcadd += 2;
3098 		}
3099 
3100 		if ((dp & 0x4) == 0) {
3101 			base += regd;
3102 		}
3103 		if (dp & 0x3) {
3104 			base = get_long_mmu030c_state (base);
3105 		}
3106 		if (dp & 0x4) {
3107 			base += regd;
3108 		}
3109 		v = base + outer;
3110 	} else {
3111 		v = base + (uae_s32)((uae_s8)dp) + regd;
3112 	}
3113 
3114 	mmu030_state[1] |= 1 << idx;
3115 	mmu030_state[2] |= pcadd << (idx * 4);
3116 	mmu030_disp_store[idx] = v;
3117 	mmu030_idx = oldidx;
3118 	mmu030_ad[mmu030_idx].done = false;
3119 
3120 	return v;
3121 }
3122 
m68k_do_rte_mmu030c(uaecptr a7)3123 void m68k_do_rte_mmu030c (uaecptr a7)
3124 {
3125 	struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1];
3126 
3127 	// Restore access error exception state
3128 
3129 	uae_u16 sr = get_word_mmu030c(a7);
3130 	uae_u32 pc = get_long_mmu030c(a7 + 2);
3131 	uae_u16 format = get_word_mmu030c (a7 + 6);
3132 	uae_u16 frame = format >> 12;
3133 	uae_u16 ssw = get_word_mmu030c (a7 + 10);
3134 	uae_u32 stagesbc = get_long_mmu030c(a7 + 12);
3135 	uae_u32 fault_addr = get_long_mmu030c(a7 + 16);
3136 
3137 	// Fetch last word, real CPU does it to allow OS bus handler to map
3138 	// the page if frame crosses pages and following page is not resident.
3139 	if (frame == 0xb)
3140 		get_word_mmu030c(a7 + 92 - 2);
3141 	else
3142 		get_word_mmu030c(a7 + 32 - 2);
3143 
3144 	// Internal register, our opcode storage area
3145 	uae_u32 oc = get_long_mmu030c(a7 + 0x14);
3146 	// Data output buffer
3147 	uae_u32 mmu030_data_buffer_out_v = get_long_mmu030c(a7 + 0x18);
3148 	// get_disp_ea_020
3149 	uae_u32 mmu030_disp_store_0 = get_long_mmu030c(a7 + 0x1c);
3150 	uae_u32 mmu030_disp_store_1 = get_long_mmu030c(a7 + 0x1c + 4);
3151 	// Internal register, misc flags
3152 	uae_u32 ps = get_long_mmu030c(a7 + 0x28);
3153 	// Data buffer
3154 	uae_u32 mmu030_data_buffer_in_v = get_long_mmu030c(a7 + 0x2c);;
3155 
3156 	uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff);
3157 	// Misc state data
3158 	uae_u32 mmu030_state_0 = get_word_mmu030c(a7 + 0x30);
3159 	uae_u32 mmu030_state_1 = get_word_mmu030c(a7 + 0x32);
3160 	uae_u32 mmu030_state_2 = get_word_mmu030c(a7 + 0x34);
3161 
3162 	uae_u32 mmu030_fmovem_store_0 = 0;
3163 	uae_u32 mmu030_fmovem_store_1 = 0;
3164 	if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
3165 		mmu030_fmovem_store_0 = get_long_mmu030c(a7 + 0x5c - (7 + 1) * 4);
3166 		mmu030_fmovem_store_1 = get_long_mmu030c(a7 + 0x5c - (8 + 1) * 4);
3167 	}
3168 
3169 	// Rerun "mmu030_opcode" using restored state.
3170 	mmu030_retry = true;
3171 
3172 	if (frame == 0xb) {
3173 		uae_u16 idxsize = get_word_mmu030c(a7 + 0x36);
3174 		for (int i = 0; i < idxsize + 1; i++) {
3175 			mmu030_ad_v[i].done = i < idxsize;
3176 			mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
3177 		}
3178 		mmu030_ad_v[idxsize + 1].done = false;
3179 
3180 		// did we have data fault but DF bit cleared?
3181 		if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
3182 			// DF not set: mark access as done
3183 			mmu030_data_buffer_out_v = mmu030_data_buffer_in_v;
3184 			if (ssw & MMU030_SSW_RM) {
3185 				// Read-Modify-Write: whole instruction is considered done
3186 				write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
3187 				mmu030_retry = false;
3188 			} else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) {
3189 				// if movem, skip next move
3190 				mmu030_state_1 |= MMU030_STATEFLAG1_MOVEM2;
3191 			} else {
3192 				mmu030_ad_v[idxsize].done = true;
3193 				if (ssw & MMU030_SSW_RW) {
3194 					// Read and no DF: use value in data input buffer
3195 					mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v;
3196 				}
3197 			}
3198 			unalign_clear();
3199 		}
3200 
3201 		// Retried data access is the only memory access that can be done after this.
3202 
3203 		regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0;
3204 		regs.prefetch020_valid[1] = (ps & 2) ? 1 : 0;
3205 		regs.prefetch020_valid[2] = (ps & 4) ? 1 : 0;
3206 		regs.pipeline_r8[0] = (ps >> 8) & 7;
3207 		regs.pipeline_r8[1] = (ps >> 11) & 7;
3208 		regs.pipeline_pos = (ps >> 16) & 15;
3209 		regs.pipeline_stop = ((ps >> 20) & 15) == 15 ? -1 : (int)(ps >> 20) & 15;
3210 
3211 		regs.prefetch020[2] = stagesbc;
3212 		regs.prefetch020[1] = stagesbc >> 16;
3213 		regs.prefetch020[0] = oc >> 16;
3214 
3215 		if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
3216 			regs.prefetch020_valid[2] = 1;
3217 			write_log (_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]);
3218 		}
3219 		if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) {
3220 			regs.prefetch020_valid[1] = 1;
3221 			write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]);
3222 		}
3223 
3224 		// restore global state variables
3225 		mmu030_opcode = mmu030_opcode_v;
3226 		mmu030_state[0] = mmu030_state_0;
3227 		mmu030_state[1] = mmu030_state_1;
3228 		mmu030_state[2] = mmu030_state_2;
3229 		mmu030_disp_store[0] = mmu030_disp_store_0;
3230 		mmu030_disp_store[1] = mmu030_disp_store_1;
3231 		mmu030_fmovem_store[0] = mmu030_fmovem_store_0;
3232 		mmu030_fmovem_store[1] = mmu030_fmovem_store_1;
3233 		mmu030_data_buffer_out = mmu030_data_buffer_out_v;
3234 		mmu030_idx = idxsize;
3235 		for (int i = 0; i <= mmu030_idx + 1; i++) {
3236 			mmu030_ad[i].done = mmu030_ad_v[i].done;
3237 			mmu030_ad[i].val = mmu030_ad_v[i].val;
3238 		}
3239 
3240 		m68k_areg (regs, 7) += 92;
3241 		regs.sr = sr;
3242 		MakeFromSR_T0();
3243 		if (pc & 1) {
3244 			exception3i (0x4E73, pc);
3245 			return;
3246 		}
3247 		m68k_setpci (pc);
3248 
3249 		if (!(ssw & (MMU030_SSW_DF << 1))) {
3250 			if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) {
3251 				// Prefetch was software fixed, continue pipeline refill
3252 				fill_prefetch_030_ntx_continue();
3253 			} else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) {
3254 				// Finished?
3255 				fill_prefetch_030_ntx_continue();
3256 			} else if (mmu030_opcode == -1) {
3257 				// Previous branch instruction finished successfully but its pipeline refill
3258 				// step caused the exception, retry the refill, do not retry branch instruction.
3259 				fill_prefetch_030_ntx();
3260 			}
3261 		}
3262 
3263 		if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) {
3264 
3265 			// Locked-Read-Modify-Write restarts whole instruction.
3266 			mmu030_ad[0].done = false;
3267 
3268 		} else if (ssw & MMU030_SSW_DF) {
3269 			// retry faulted access
3270 			uaecptr addr = fault_addr;
3271 			bool read = (ssw & MMU030_SSW_RW) != 0;
3272 			int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long);
3273 			int fc = ssw & 7;
3274 
3275 #if MMU030_DEBUG
3276 			if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
3277 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
3278 					write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
3279 				}
3280 			} else {
3281 				if (mmu030_ad[idxsize].done) {
3282 					write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
3283 				}
3284 			}
3285 #endif
3286 			if (read) {
3287 				if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
3288 					mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry);
3289 				} else {
3290 					switch (size)
3291 					{
3292 						case sz_byte:
3293 						mmu030_data_buffer_out = read_data_030_fc_bget(addr, fc);
3294 						break;
3295 						case sz_word:
3296 						mmu030_data_buffer_out = read_data_030_fc_wget(addr, fc);
3297 						break;
3298 						case sz_long:
3299 						mmu030_data_buffer_out = read_data_030_fc_lget(addr, fc);
3300 						break;
3301 					}
3302 				}
3303 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
3304 					mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
3305 				} else {
3306 					mmu030_ad[idxsize].val = mmu030_data_buffer_out;
3307 					mmu030_ad[idxsize].done = true;
3308 				}
3309 			} else {
3310 				if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
3311 					mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry);
3312 				} else {
3313 					switch (size)
3314 					{
3315 						case sz_byte:
3316 						write_data_030_fc_bput(addr, mmu030_data_buffer_out, fc);
3317 						break;
3318 						case sz_word:
3319 						write_data_030_fc_wput(addr, mmu030_data_buffer_out, fc);
3320 						break;
3321 						case sz_long:
3322 						write_data_030_fc_lput(addr, mmu030_data_buffer_out, fc);
3323 						break;
3324 					}
3325 				}
3326 				if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
3327 					mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
3328 				} else {
3329 					mmu030_ad[idxsize].done = true;
3330 				}
3331 			}
3332 		}
3333 
3334 		if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) {
3335 			mmu030_retry = false;
3336 			fill_prefetch_030_ntx();
3337 		}
3338 
3339 	} else {
3340 		m68k_areg (regs, 7) += 32;
3341 	}
3342 }
3343