|
|
1.1.1.3 root 1: /*
2: * cpummu.cpp - MMU emulation
3: *
4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
1.1.1.5 root 5: *
1.1.1.3 root 6: * Inspired by UAE MMU patch
7: *
8: * This file is part of the ARAnyM project which builds a new and powerful
9: * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10: *
11: * ARAnyM is free software; you can redistribute it and/or modify
12: * it under the terms of the GNU General Public License as published by
13: * the Free Software Foundation; either version 2 of the License, or
14: * (at your option) any later version.
15: *
16: * ARAnyM is distributed in the hope that it will be useful,
17: * but WITHOUT ANY WARRANTY; without even the implied warranty of
18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19: * GNU General Public License for more details.
20: *
21: * You should have received a copy of the GNU General Public License
1.1.1.7 ! root 22: * along with ARAnyM; if not, write to the Free Software Foundation,
! 23: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
1.1.1.3 root 24: */
25:
26:
27: #include "sysconfig.h"
28: #include "sysdeps.h"
29:
1.1.1.5 root 30: #include "main.h"
31: #include "hatari-glue.h"
32:
33:
1.1.1.3 root 34: #include "options_cpu.h"
35: #include "memory.h"
36: #include "newcpu.h"
37: #include "cpummu.h"
1.1.1.5 root 38: #include "debug.h"
39:
1.1.1.7 ! root 40: #define MMUDUMP 1
1.1.1.3 root 41:
42: #define DBG_MMU_VERBOSE 1
43: #define DBG_MMU_SANITY 1
1.1.1.5 root 44: #if 0
1.1.1.3 root 45: #define write_log printf
1.1.1.5 root 46: #endif
1.1.1.3 root 47:
48: #ifdef FULLMMU
49:
1.1.1.5 root 50: uae_u32 mmu_is_super;
51: uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
1.1.1.7 ! root 52: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_SLOTS][ATC_WAYS];
1.1.1.5 root 53: bool mmu_pagesize_8k;
1.1.1.7 ! root 54: int mmu_pageshift, mmu_pageshift1m;
! 55: uae_u8 mmu_cache_state;
! 56: uae_u8 cache_default_ins, cache_default_data;
1.1.1.5 root 57:
58: int mmu060_state;
59: uae_u16 mmu_opcode;
60: bool mmu_restart;
61: static bool locked_rmw_cycle;
1.1.1.7 ! root 62: bool rmw_cycle;
1.1.1.5 root 63: static bool ismoves;
1.1.1.7 ! root 64: bool mmu_ttr_enabled, mmu_ttr_enabled_ins, mmu_ttr_enabled_data;
! 65: int mmu_atc_ways[2];
! 66: int way_random;
1.1.1.5 root 67:
68: int mmu040_movem;
69: uaecptr mmu040_movem_ea;
70: uae_u32 mmu040_move16[4];
1.1.1.3 root 71:
1.1.1.7 ! root 72: #if MMU_ICACHE
! 73: struct mmu_icache mmu_icache_data[MMU_ICACHE_SZ];
! 74: #endif
! 75: #if MMU_IPAGECACHE
! 76: uae_u32 atc_last_ins_laddr, atc_last_ins_paddr;
! 77: uae_u8 atc_last_ins_cache;
! 78: #endif
! 79: #if MMU_DPAGECACHE
! 80: struct mmufastcache atc_data_cache_read[MMUFASTCACHE_ENTRIES];
! 81: struct mmufastcache atc_data_cache_write[MMUFASTCACHE_ENTRIES];
! 82: #endif
! 83:
! 84: #if CACHE_HIT_COUNT
! 85: int mmu_ins_hit, mmu_ins_miss;
! 86: int mmu_data_read_hit, mmu_data_read_miss;
! 87: int mmu_data_write_hit, mmu_data_write_miss;
! 88: #endif
! 89:
1.1.1.3 root 90: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
91: {
92: DUNUSED(label);
1.1.1.6 root 93: #if MMUDEBUG > 0
1.1.1.3 root 94: uae_u32 from_addr, to_addr;
95:
96: from_addr = ttr & MMU_TTR_LOGICAL_BASE;
97: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
98:
1.1.1.7 ! root 99: console_out_f(_T("%s: [%08x] %08x - %08x enabled=%d supervisor=%d wp=%d cm=%02d\n"),
1.1.1.3 root 100: label, ttr,
101: from_addr, to_addr,
102: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
103: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
104: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
105: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
106: );
1.1.1.5 root 107: #endif
1.1.1.3 root 108: }
109:
110: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
111: {
112: uae_u32 * ttr;
113: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0;
114: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1;
115:
116: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
117: ttr = ttr1;
118: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
119: ttr = ttr0;
120: else
121: return;
122:
123: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
124: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
125: *ttr |= MMU_TTR_BIT_ENABLED;
126:
1.1.1.5 root 127: #if MMUDEBUG > 0
128: write_log(_T("MMU: map transparent mapping of %08x\n"), *ttr);
129: #endif
1.1.1.3 root 130: }
131:
1.1.1.5 root 132: void mmu_tt_modified (void)
1.1.1.3 root 133: {
1.1.1.7 ! root 134: mmu_ttr_enabled_ins = ((regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
! 135: mmu_ttr_enabled_data = ((regs.dtt0 | regs.dtt1) & MMU_TTR_BIT_ENABLED) != 0;
! 136: mmu_ttr_enabled = mmu_ttr_enabled_ins || mmu_ttr_enabled_data;
1.1.1.5 root 137: }
1.1.1.3 root 138:
139:
1.1.1.5 root 140: #if MMUDUMP
1.1.1.3 root 141:
1.1.1.5 root 142: /* This dump output makes much more sense than old one */
1.1.1.3 root 143:
1.1.1.7 ! root 144: #ifdef WINUAE_FOR_HATARI
! 145: #define ULONG Uint32
! 146: #endif
! 147:
1.1.1.5 root 148: #define LEVELA_SIZE 7
149: #define LEVELB_SIZE 7
150: #define LEVELC_SIZE 6
151: #define PAGE_SIZE 12 // = 1 << 12 = 4096
152:
153: #define LEVELA_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE ))) & ((1 << LEVELA_SIZE) - 1))
154: #define LEVELB_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE + LEVELB_SIZE ))) & ((1 << LEVELB_SIZE) - 1))
155: #define LEVELC_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE + LEVELB_SIZE + LEVELC_SIZE))) & ((1 << LEVELC_SIZE) - 1))
1.1.1.3 root 156:
1.1.1.5 root 157: #define LEVELA(root, x) (get_long(root + LEVELA_VAL(x) * 4))
158: #define LEVELB(a, x) (get_long((((uae_u32)a) & ~((1 << (LEVELB_SIZE + 2)) - 1)) + LEVELB_VAL(x) * 4))
159: #define LEVELC(b, x) (get_long((((uae_u32)b) & ~((1 << (LEVELC_SIZE + 2)) - 1)) + LEVELC_VAL(x) * 4))
160:
161: #define ISINVALID(x) ((((ULONG)x) & 3) == 0)
162:
163: static uae_u32 getdesc(uae_u32 root, uae_u32 addr)
1.1.1.3 root 164: {
1.1.1.5 root 165: ULONG desc;
1.1.1.3 root 166:
1.1.1.5 root 167: desc = LEVELA(root, addr);
168: if (ISINVALID(desc))
169: return desc;
170: desc = LEVELB(desc, addr);
171: if (ISINVALID(desc))
172: return desc;
173: desc = LEVELC(desc, addr);
174: return desc;
1.1.1.3 root 175: }
1.1.1.5 root 176: static void mmu_dump_table(const char * label, uaecptr root_ptr)
177: {
178: ULONG i;
179: ULONG startaddr;
180: ULONG odesc;
181: ULONG totalpages;
182: ULONG pagemask = (1 << PAGE_SIZE) - 1;
183:
1.1.1.7 ! root 184: root_ptr &= 0xfffffe00;
1.1.1.5 root 185: console_out_f(_T("MMU dump start. Root = %08x\n"), root_ptr);
186: totalpages = 1 << (32 - PAGE_SIZE);
187: startaddr = 0;
188: odesc = getdesc(root_ptr, startaddr);
189: for (i = 0; i <= totalpages; i++) {
190: ULONG addr = i << PAGE_SIZE;
191: ULONG desc = 0;
192: if (i < totalpages)
193: desc = getdesc(root_ptr, addr);
194: if ((desc & pagemask) != (odesc & pagemask) || i == totalpages) {
195: uae_u8 cm, sp;
196: cm = (odesc >> 5) & 3;
197: sp = (odesc >> 7) & 1;
198: console_out_f(_T("%08x - %08x: %08x WP=%d S=%d CM=%d (%08x)\n"),
199: startaddr, addr - 1, odesc & ~((1 << PAGE_SIZE) - 1),
200: (odesc & 4) ? 1 : 0, sp, cm, odesc);
201: startaddr = addr;
202: odesc = desc;
203: }
204: }
205: console_out_f(_T("MMU dump end\n"));
206: }
1.1.1.3 root 207:
1.1.1.5 root 208: #else
1.1.1.3 root 209: /* {{{ mmu_dump_table */
210: static void mmu_dump_table(const char * label, uaecptr root_ptr)
211: {
212: DUNUSED(label);
213: const int ROOT_TABLE_SIZE = 128,
214: PTR_TABLE_SIZE = 128,
215: PAGE_TABLE_SIZE = 64,
216: ROOT_INDEX_SHIFT = 25,
217: PTR_INDEX_SHIFT = 18;
218: // const int PAGE_INDEX_SHIFT = 12;
219: int root_idx, ptr_idx, page_idx;
220: uae_u32 root_des, ptr_des, page_des;
221: uaecptr ptr_des_addr, page_addr,
222: root_log, ptr_log, page_log;
223:
1.1.1.5 root 224: console_out_f(_T("%s: root=%x\n"), label, root_ptr);
1.1.1.3 root 225:
226: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
227: root_des = phys_get_long(root_ptr + root_idx);
228:
229: if ((root_des & 2) == 0)
230: continue; /* invalid */
231:
1.1.1.5 root 232: console_out_f(_T("ROOT: %03d U=%d W=%d UDT=%02d\n"), root_idx,
1.1.1.3 root 233: root_des & 8 ? 1 : 0,
234: root_des & 4 ? 1 : 0,
235: root_des & 3
236: );
237:
238: root_log = root_idx << ROOT_INDEX_SHIFT;
239:
240: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
241:
242: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
243: struct {
244: uaecptr log, phys;
245: int start_idx, n_pages; /* number of pages covered by this entry */
246: uae_u32 match;
247: } page_info[PAGE_TABLE_SIZE];
248: int n_pages_used;
249:
250: ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
251: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
252:
253: if ((ptr_des & 2) == 0)
254: continue; /* invalid */
255:
1.1.1.5 root 256: page_addr = ptr_des & (mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
1.1.1.3 root 257:
258: n_pages_used = -1;
259: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
260:
261: page_des = phys_get_long(page_addr + page_idx);
262: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT
263:
264: switch (page_des & 3) {
265: case 0: /* invalid */
266: continue;
267: case 1: case 3: /* resident */
268: case 2: /* indirect */
269: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
270: /* use the next entry */
271: n_pages_used++;
272:
273: page_info[n_pages_used].match = page_des;
274: page_info[n_pages_used].n_pages = 1;
275: page_info[n_pages_used].start_idx = page_idx;
276: page_info[n_pages_used].log = page_log;
277: } else {
278: page_info[n_pages_used].n_pages++;
279: }
280: break;
281: }
282: }
283:
284: if (n_pages_used == -1)
285: continue;
286:
1.1.1.5 root 287: console_out_f(_T(" PTR: %03d U=%d W=%d UDT=%02d\n"), ptr_idx,
1.1.1.3 root 288: ptr_des & 8 ? 1 : 0,
289: ptr_des & 4 ? 1 : 0,
290: ptr_des & 3
291: );
292:
293:
294: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
295: page_des = page_info[page_idx].match;
296:
297: if ((page_des & MMU_PDT_MASK) == 2) {
1.1.1.5 root 298: console_out_f(_T(" PAGE: %03d-%03d log=%08x INDIRECT --> addr=%08x\n"),
1.1.1.3 root 299: page_info[page_idx].start_idx,
300: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
301: page_info[page_idx].log,
302: page_des & MMU_PAGE_INDIRECT_MASK
303: );
304:
305: } else {
1.1.1.5 root 306: console_out_f(_T(" PAGE: %03d-%03d log=%08x addr=%08x UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n"),
1.1.1.3 root 307: page_info[page_idx].start_idx,
308: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
309: page_info[page_idx].log,
1.1.1.5 root 310: page_des & (mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
311: (page_des & (mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
1.1.1.3 root 312: page_des & MMU_DES_GLOBAL ? 1 : 0,
313: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
314: page_des & MMU_DES_SUPER ? 1 : 0,
315: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
316: page_des & MMU_DES_MODIFIED ? 1 : 0,
317: page_des & MMU_DES_USED ? 1 : 0,
318: page_des & MMU_DES_WP ? 1 : 0
319: );
320: }
321: }
322: }
323:
324: }
325: }
326: /* }}} */
327: #endif
328:
329: /* {{{ mmu_dump_atc */
1.1.1.6 root 330: static void mmu_dump_atc(void)
1.1.1.3 root 331: {
1.1.1.5 root 332:
1.1.1.3 root 333: }
334: /* }}} */
335:
336: /* {{{ mmu_dump_tables */
337: void mmu_dump_tables(void)
338: {
1.1.1.7 ! root 339: console_out_f(_T("URP: %08x SRP: %08x MMUSR: %x TC: %x\n"), regs.urp, regs.srp, regs.mmusr, regs.tcr);
1.1.1.5 root 340: mmu_dump_ttr(_T("DTT0"), regs.dtt0);
341: mmu_dump_ttr(_T("DTT1"), regs.dtt1);
342: mmu_dump_ttr(_T("ITT0"), regs.itt0);
343: mmu_dump_ttr(_T("ITT1"), regs.itt1);
1.1.1.3 root 344: mmu_dump_atc();
1.1.1.5 root 345: #if MMUDUMP
1.1.1.3 root 346: mmu_dump_table("SRP", regs.srp);
1.1.1.7 ! root 347: if (regs.urp != regs.srp)
! 348: mmu_dump_table("URP", regs.urp);
1.1.1.3 root 349: #endif
350: }
351: /* }}} */
352:
1.1.1.7 ! root 353: static void flush_shortcut_cache(uaecptr addr, bool super)
! 354: {
! 355: #if MMU_IPAGECACHE
! 356: atc_last_ins_laddr = mmu_pagemask;
! 357: #endif
! 358: #if MMU_DPAGECACHE
! 359: if (addr == 0xffffffff) {
! 360: memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
! 361: memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
! 362: } else {
! 363: int i;
! 364: for (i = 0; i < MMUFASTCACHE_ENTRIES; i++) {
! 365: uae_u32 idx = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
! 366: if (atc_data_cache_read[i].log == idx)
! 367: atc_data_cache_read[i].log = 0xffffffff;
! 368: if (atc_data_cache_write[i].log == idx)
! 369: atc_data_cache_write[i].log = 0xffffffff;
! 370: }
! 371: }
! 372: #endif
! 373: }
1.1.1.3 root 374:
375: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
376: {
377: return (super ? 4 : 0) | (data ? 1 : 2);
378: }
379:
1.1.1.7 ! root 380: void mmu_bus_error(uaecptr addr, uae_u32 val, int fc, bool write, int size,uae_u32 status060, bool nonmmu)
1.1.1.3 root 381: {
1.1.1.5 root 382: if (currprefs.mmu_model == 68040) {
383: uae_u16 ssw = 0;
1.1.1.3 root 384:
1.1.1.5 root 385: if (ismoves) {
386: // MOVES special behavior
387: int fc2 = write ? regs.dfc : regs.sfc;
388: if (fc2 == 0 || fc2 == 3 || fc2 == 4 || fc2 == 7)
389: ssw |= MMU_SSW_TT1;
390: if ((fc2 & 3) != 3)
391: fc2 &= ~2;
392: #if MMUDEBUGMISC > 0
393: write_log (_T("040 MMU MOVES fc=%d -> %d\n"), fc, fc2);
394: #endif
395: fc = fc2;
396: }
1.1.1.3 root 397:
1.1.1.5 root 398: ssw |= fc & MMU_SSW_TM; /* TM = FC */
1.1.1.3 root 399:
1.1.1.5 root 400: switch (size) {
401: case sz_byte:
402: ssw |= MMU_SSW_SIZE_B;
403: break;
404: case sz_word:
405: ssw |= MMU_SSW_SIZE_W;
406: break;
407: case sz_long:
408: ssw |= MMU_SSW_SIZE_L;
409: break;
410: }
411:
412: regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
1.1.1.7 ! root 413: regs.wb3_data = val;
1.1.1.5 root 414: regs.wb2_status = 0;
415: if (!write)
416: ssw |= MMU_SSW_RW;
417:
418: if (size == 16) { // MOVE16
419: ssw |= MMU_SSW_SIZE_CL;
420: ssw |= MMU_SSW_TT0;
421: regs.mmu_effective_addr &= ~15;
422: if (write) {
423: // clear normal writeback if MOVE16 write
424: regs.wb3_status &= ~0x80;
425: // wb2 = cacheline size writeback
426: regs.wb2_status = 0x80 | MMU_SSW_SIZE_CL | (ssw & 0x1f);
427: regs.wb2_address = regs.mmu_effective_addr;
428: write_log (_T("040 MMU MOVE16 WRITE FAULT!\n"));
429: }
430: }
431:
432: if (mmu040_movem) {
433: ssw |= MMU_SSW_CM;
434: regs.mmu_effective_addr = mmu040_movem_ea;
435: mmu040_movem = 0;
436: #if MMUDEBUGMISC > 0
437: write_log (_T("040 MMU_SSW_CM EA=%08X\n"), mmu040_movem_ea);
438: #endif
439: }
440: if (locked_rmw_cycle) {
441: ssw |= MMU_SSW_LK;
442: ssw &= ~MMU_SSW_RW;
443: #if MMUDEBUGMISC > 0
444: write_log (_T("040 MMU_SSW_LK!\n"));
445: #endif
446: }
447:
448: if (!nonmmu)
449: ssw |= MMU_SSW_ATC;
450: regs.mmu_ssw = ssw;
1.1.1.3 root 451:
1.1.1.5 root 452: #if MMUDEBUG > 0
453: write_log(_T("BF: fc=%d w=%d logical=%08x ssw=%04x PC=%08x INS=%04X\n"), fc, write, addr, ssw, m68k_getpc(), mmu_opcode);
454: #endif
455: } else {
456: uae_u32 fslw = 0;
1.1.1.3 root 457:
1.1.1.5 root 458: fslw |= write ? MMU_FSLW_W : MMU_FSLW_R;
459: fslw |= fc << 16; /* MMU_FSLW_TM */
1.1.1.3 root 460:
1.1.1.5 root 461: switch (size) {
462: case sz_byte:
463: fslw |= MMU_FSLW_SIZE_B;
464: break;
465: case sz_word:
466: fslw |= MMU_FSLW_SIZE_W;
467: break;
468: case sz_long:
469: fslw |= MMU_FSLW_SIZE_L;
470: break;
471: case 16: // MOVE16
472: addr &= ~15;
473: fslw |= MMU_FSLW_SIZE_D;
474: fslw |= MMU_FSLW_TT_16;
475: break;
476: }
477: if ((fc & 3) == 2) {
478: // instruction faults always point to opcode address
479: #if MMUDEBUGMISC > 0
480: write_log(_T("INS FAULT %08x %08x %d\n"), addr, regs.instruction_pc, mmu060_state);
481: #endif
482: addr = regs.instruction_pc;
483: if (mmu060_state == 0) {
484: fslw |= MMU_FSLW_IO; // opword fetch
485: } else {
486: fslw |= MMU_FSLW_IO | MMU_FSLW_MA; // extension word
487: }
488: }
1.1.1.7 ! root 489: if (rmw_cycle) {
1.1.1.5 root 490: fslw |= MMU_FSLW_W | MMU_FSLW_R;
491: }
492: if (locked_rmw_cycle) {
493: fslw |= MMU_FSLW_LK;
494: write_log (_T("060 MMU_FSLW_LK!\n"));
495: }
1.1.1.7 ! root 496: fslw |= status060;
1.1.1.5 root 497: regs.mmu_fslw = fslw;
498:
499: #if MMUDEBUG > 0
1.1.1.7 ! root 500: write_log(_T("BF: fc=%d w=%d s=%d log=%08x ssw=%08x rmw=%d PC=%08x INS=%04X\n"), fc, write, 1 << size, addr, fslw, rmw_cycle, m68k_getpc(), mmu_opcode);
1.1.1.5 root 501: #endif
502:
503: }
504:
1.1.1.7 ! root 505: rmw_cycle = false;
! 506: locked_rmw_cycle = false;
1.1.1.5 root 507: regs.mmu_fault_addr = addr;
508:
509: #if 0
1.1.1.7 ! root 510: activate_debugger ();
1.1.1.5 root 511: #endif
1.1.1.3 root 512:
1.1.1.7 ! root 513: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1.1.1.5 root 514:
1.1.1.7 ! root 515: THROW(2);
1.1.1.5 root 516: }
517:
1.1.1.3 root 518: /*
1.1.1.7 ! root 519: * mmu access is a 4 step process:
! 520: * if mmu is not enabled just read physical
! 521: * check transparent region, if transparent, read physical
! 522: * check ATC (address translation cache), read immediately if HIT
! 523: * read from mmu with the long path (and allocate ATC entry if needed)
1.1.1.3 root 524: */
525:
1.1.1.7 ! root 526: /* check if an address matches a ttr */
! 527: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
! 528: {
! 529: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
! 530: uae_u8 msb, mask;
! 531:
! 532: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
! 533: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
! 534:
! 535: if (!(msb & ~mask)) {
! 536:
! 537: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
! 538: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
! 539: return TTR_NO_MATCH;
! 540: }
! 541: }
! 542: if (ttr & MMU_TTR_CACHE_DISABLE) {
! 543: mmu_cache_state = CACHE_DISABLE_MMU;
! 544: } else {
! 545: mmu_cache_state = CACHE_ENABLE_ALL;
! 546: if (ttr & MMU_TTR_CACHE_MODE) {
! 547: mmu_cache_state |= CACHE_ENABLE_COPYBACK;
! 548: }
! 549: }
! 550: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
! 551: }
1.1.1.3 root 552: }
1.1.1.7 ! root 553: return TTR_NO_MATCH;
! 554: }
1.1.1.3 root 555:
1.1.1.7 ! root 556: int mmu_match_ttr_ins(uaecptr addr, bool super)
! 557: {
! 558: int res;
! 559:
! 560: if (!mmu_ttr_enabled_ins)
! 561: return TTR_NO_MATCH;
! 562: res = mmu_do_match_ttr(regs.itt0, addr, super);
! 563: if (res == TTR_NO_MATCH)
! 564: res = mmu_do_match_ttr(regs.itt1, addr, super);
! 565: return res;
1.1.1.3 root 566: }
567:
1.1.1.7 ! root 568: int mmu_match_ttr(uaecptr addr, bool super, bool data)
1.1.1.3 root 569: {
1.1.1.7 ! root 570: int res;
! 571:
! 572: if (!mmu_ttr_enabled)
! 573: return TTR_NO_MATCH;
! 574: if (data) {
! 575: res = mmu_do_match_ttr(regs.dtt0, addr, super);
! 576: if (res == TTR_NO_MATCH)
! 577: res = mmu_do_match_ttr(regs.dtt1, addr, super);
! 578: } else {
! 579: res = mmu_do_match_ttr(regs.itt0, addr, super);
! 580: if (res == TTR_NO_MATCH)
! 581: res = mmu_do_match_ttr(regs.itt1, addr, super);
1.1.1.3 root 582: }
1.1.1.7 ! root 583: return res;
! 584: }
1.1.1.3 root 585:
1.1.1.7 ! root 586: void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size)
! 587: {
! 588: uae_u32 status = 0;
! 589:
! 590: if (currprefs.mmu_model == 68060) {
! 591: status |= MMU_FSLW_TTR;
! 592: }
! 593: mmu_bus_error(addr, val, mmu_get_fc (super, data), true, size, status, false);
! 594: }
! 595:
! 596: int mmu_match_ttr_write(uaecptr addr, bool super, bool data, uae_u32 val, int size)
! 597: {
! 598: int res = TTR_NO_MATCH;
! 599: if (mmu_ttr_enabled) {
! 600: res = mmu_match_ttr(addr, super, data);
1.1.1.3 root 601: }
1.1.1.7 ! root 602: if (res == TTR_NO_WRITE || (res == TTR_NO_MATCH && !regs.mmu_enabled && (regs.tcr & MMU_TCR_DWO)))
! 603: mmu_bus_error_ttr_write_fault(addr, super, data, val, size);
! 604: return res;
1.1.1.3 root 605: }
606:
1.1.1.7 ! root 607: int mmu_match_ttr_maybe_write(uaecptr addr, bool super, bool data, int size, bool write)
1.1.1.3 root 608: {
1.1.1.7 ! root 609: int res = TTR_NO_MATCH;
! 610: if (mmu_ttr_enabled) {
! 611: res = mmu_match_ttr(addr, super, data);
1.1.1.5 root 612: }
1.1.1.7 ! root 613: if (write && ((res == TTR_NO_WRITE) || (res == TTR_NO_MATCH && !regs.mmu_enabled && (regs.tcr & MMU_TCR_DWO))))
! 614: mmu_bus_error_ttr_write_fault(addr, super, data, 0, size);
! 615: return res;
! 616: }
1.1.1.5 root 617:
1.1.1.7 ! root 618: // Descriptor read accesses can use data cache but never allocate new cache lines.
! 619: static uae_u32 desc_get_long(uaecptr addr)
! 620: {
! 621: mmu_cache_state = ce_cachable[addr >>16] | CACHE_DISABLE_ALLOCATE;
! 622: return x_phys_get_long(addr);
! 623: }
! 624: // Write accesses probably are always pushed to memomory
! 625: static void desc_put_long(uaecptr addr, uae_u32 v)
! 626: {
! 627: mmu_cache_state = CACHE_DISABLE_MMU;
! 628: x_phys_put_long(addr, v);
1.1.1.3 root 629: }
630:
631: /*
632: * Lookup the address by walking the page table and updating
633: * the page descriptors accordingly. Returns the found descriptor
634: * or produces a bus error.
635: */
1.1.1.7 ! root 636: static uae_u32 mmu_fill_atc(uaecptr addr, bool super, uae_u32 tag, bool write, struct mmu_atc_line *l, uae_u32 *status060)
1.1.1.3 root 637: {
1.1.1.7 ! root 638: uae_u32 desc, desc_addr, wp;
! 639: uae_u32 status = 0;
! 640: int i;
! 641:
! 642: wp = 0;
! 643: desc = super ? regs.srp : regs.urp;
! 644:
! 645: /* fetch root table descriptor */
! 646: i = (addr >> 23) & 0x1fc;
! 647: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
! 648:
! 649: SAVE_EXCEPTION;
! 650: TRY(prb) {
! 651: desc = desc_get_long(desc_addr);
! 652: if ((desc & 2) == 0) {
1.1.1.5 root 653: #if MMUDEBUG > 1
1.1.1.7 ! root 654: write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
! 655: addr, desc_addr, desc);
1.1.1.5 root 656: #endif
1.1.1.7 ! root 657: *status060 |= MMU_FSLW_PTA;
! 658: goto fail;
! 659: }
! 660:
! 661: wp |= desc;
! 662: if ((desc & MMU_DES_USED) == 0) {
! 663: desc_put_long(desc_addr, desc | MMU_DES_USED);
! 664: }
! 665:
! 666: /* fetch pointer table descriptor */
! 667: i = (addr >> 16) & 0x1fc;
! 668: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
! 669: desc = desc_get_long(desc_addr);
! 670: if ((desc & 2) == 0) {
1.1.1.5 root 671: #if MMUDEBUG > 1
1.1.1.7 ! root 672: write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
! 673: addr, desc_addr, desc);
1.1.1.5 root 674: #endif
1.1.1.7 ! root 675: *status060 |= MMU_FSLW_PTB;
! 676: goto fail;
! 677: }
! 678: wp |= desc;
! 679: if ((desc & MMU_DES_USED) == 0)
! 680: desc_put_long(desc_addr, desc | MMU_DES_USED);
! 681:
! 682: /* fetch page table descriptor */
! 683: if (mmu_pagesize_8k) {
! 684: i = (addr >> 11) & 0x7c;
! 685: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
! 686: } else {
! 687: i = (addr >> 10) & 0xfc;
! 688: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
! 689: }
! 690:
! 691: desc = desc_get_long(desc_addr);
! 692: if ((desc & 3) == 2) {
! 693: /* indirect */
! 694: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
! 695: desc = desc_get_long(desc_addr);
! 696: }
! 697: if ((desc & 1) == 1) {
! 698: wp |= desc;
! 699: if (write) {
! 700: if ((wp & MMU_DES_WP) || ((desc & MMU_DES_SUPER) && !super)) {
! 701: if ((desc & MMU_DES_USED) == 0) {
! 702: desc |= MMU_DES_USED;
! 703: desc_put_long(desc_addr, desc);
! 704: }
! 705: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
! 706: (MMU_DES_USED|MMU_DES_MODIFIED)) {
! 707: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
! 708: desc_put_long(desc_addr, desc);
! 709: }
! 710: } else {
! 711: if ((desc & MMU_DES_USED) == 0) {
! 712: desc |= MMU_DES_USED;
! 713: desc_put_long(desc_addr, desc);
! 714: }
! 715: }
! 716: desc |= wp & MMU_DES_WP;
! 717: } else {
! 718: if ((desc & 3) == 2) {
! 719: *status060 |= MMU_FSLW_IL;
! 720: #if MMUDEBUG > 1
! 721: write_log(_T("MMU: double indirect descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
! 722: #endif
! 723: } else {
! 724: *status060 |= MMU_FSLW_PF;
! 725: #if MMUDEBUG > 2
! 726: write_log(_T("MMU: invalid page descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
! 727: #endif
! 728: }
! 729: fail:
! 730: desc = 0;
! 731: }
! 732:
! 733: /* this will cause a bus error exception */
! 734: if (!super && (desc & MMU_DES_SUPER)) {
! 735: *status060 |= MMU_FSLW_SP;
! 736: } else if (write && (desc & MMU_DES_WP)) {
! 737: *status060 |= MMU_FSLW_WP;
! 738: }
! 739:
! 740: // 68040 always creates ATC entry. 68060 only if valid descriptor was found.
! 741: if (currprefs.mmu_model == 68040 || (desc & MMU_MMUSR_R)) {
! 742: /* Create new ATC entry and return status */
! 743: l->status = desc & (MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W|MMU_MMUSR_R);
! 744: l->phys = desc & mmu_pagemaski;
! 745: l->valid = 1;
! 746: l->tag = tag;
! 747: status = l->phys | l->status;
! 748: }
1.1.1.3 root 749:
1.1.1.7 ! root 750: RESTORE_EXCEPTION;
! 751: } CATCH(prb) {
! 752: RESTORE_EXCEPTION;
! 753:
! 754: /* bus error during table search */
! 755: if (currprefs.mmu_model == 68040) {
! 756: l->status = 0;
! 757: l->phys = 0;
! 758: l->valid = 1;
! 759: l->tag = tag;
! 760: }
! 761: status = MMU_MMUSR_B;
! 762: *status060 |= MMU_FSLW_LK | MMU_FSLW_TWE;
! 763:
! 764: #if MMUDEBUG > 0
! 765: write_log(_T("MMU: bus error during table search.\n"));
! 766: #endif
! 767: } ENDTRY
! 768:
1.1.1.5 root 769: #if MMUDEBUG > 2
1.1.1.7 ! root 770: write_log(_T("translate: %x,%u,%u -> %x\n"), addr, super, write, desc);
1.1.1.5 root 771: #endif
1.1.1.7 ! root 772:
! 773: flush_shortcut_cache(addr, super);
! 774:
! 775: return status;
! 776: }
! 777:
! 778: static void mmu_add_cache(uaecptr addr, uaecptr phys, bool super, bool data, bool write)
! 779: {
! 780: if (!data) {
! 781: #if MMU_IPAGECACHE
! 782: uae_u32 laddr = (addr & mmu_pagemaski) | (super ? 1 : 0);
! 783: atc_last_ins_laddr = laddr;
! 784: atc_last_ins_paddr = phys;
! 785: atc_last_ins_cache = mmu_cache_state;
! 786: #else
! 787: ;
! 788: #endif
! 789: #if MMU_DPAGECACHE
! 790: } else {
! 791: uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
! 792: uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
! 793: if (write) {
! 794: if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
! 795: atc_data_cache_write[idx2].log = idx1;
! 796: atc_data_cache_write[idx2].phys = phys;
! 797: atc_data_cache_write[idx2].cache_state = mmu_cache_state;
! 798: }
1.1.1.5 root 799: } else {
1.1.1.7 ! root 800: if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
! 801: atc_data_cache_read[idx2].log = idx1;
! 802: atc_data_cache_read[idx2].phys = phys;
! 803: atc_data_cache_read[idx2].cache_state = mmu_cache_state;
! 804: }
1.1.1.5 root 805: }
1.1.1.7 ! root 806: #endif
1.1.1.3 root 807: }
1.1.1.7 ! root 808: }
1.1.1.3 root 809:
1.1.1.7 ! root 810: uaecptr mmu_translate(uaecptr addr, uae_u32 val, bool super, bool data, bool write, int size)
! 811: {
! 812: int way, i, index, way_invalid;
! 813: struct mmu_atc_line *l;
! 814: uae_u32 status060 = 0;
! 815: uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
! 816:
! 817: if (mmu_pagesize_8k)
! 818: index=(addr & 0x0001E000)>>13;
! 819: else
! 820: index=(addr & 0x0000F000)>>12;
! 821: way_invalid = ATC_WAYS;
! 822: way_random++;
! 823: way = mmu_atc_ways[data];
! 824:
! 825: for (i = 0; i < ATC_WAYS; i++) {
! 826: // if we have this
! 827: l = &mmu_atc_array[data][index][way];
! 828: if (l->valid) {
! 829: if (tag == l->tag) {
! 830: atc_retry:
! 831: // check if we need to cause a page fault
! 832: if (((l->status&(MMU_MMUSR_W|MMU_MMUSR_S|MMU_MMUSR_R))!=MMU_MMUSR_R)) {
! 833: if (((l->status&MMU_MMUSR_W) && write) ||
! 834: ((l->status&MMU_MMUSR_S) && !super) ||
! 835: !(l->status&MMU_MMUSR_R)) {
! 836:
! 837: if ((l->status&MMU_MMUSR_S) && !super)
! 838: status060 |= MMU_FSLW_SP;
! 839: if ((l->status&MMU_MMUSR_W) && write)
! 840: status060 |= MMU_FSLW_WP;
! 841:
! 842: mmu_bus_error(addr, val, mmu_get_fc(super, data), write, size, status060, false);
! 843: return 0; // never reach, bus error longjumps out of the function
! 844: }
! 845: }
! 846: // if first write to this page initiate table search to set M bit (but modify this slot)
! 847: if (!(l->status&MMU_MMUSR_M) && write) {
! 848: way_invalid = way;
! 849: break;
! 850: }
! 851:
! 852: // save way for next access (likely in same page)
! 853: mmu_atc_ways[data] = way;
! 854:
! 855: if (l->status & MMU_MMUSR_CM_DISABLE) {
! 856: mmu_cache_state = CACHE_DISABLE_MMU;
! 857: } else {
! 858: mmu_cache_state = CACHE_ENABLE_ALL;
! 859: if (l->status & MMU_MMUSR_CM_MODE) {
! 860: mmu_cache_state |= CACHE_ENABLE_COPYBACK;
! 861: }
! 862: }
! 863:
! 864: mmu_add_cache(addr, l->phys, super, data, write);
! 865:
! 866: // return translated addr
! 867: return l->phys | (addr & mmu_pagemask);
! 868: } else {
! 869: way_invalid = way;
1.1.1.3 root 870: }
871: }
1.1.1.7 ! root 872: way++;
! 873: way %= ATC_WAYS;
1.1.1.3 root 874: }
1.1.1.7 ! root 875: // no entry found, we need to create a new one, first find an atc line to replace
! 876: way_random %= ATC_WAYS;
! 877: way = (way_invalid < ATC_WAYS) ? way_invalid : way_random;
! 878:
! 879: // then initiate table search and create a new entry
! 880: l = &mmu_atc_array[data][index][way];
! 881: mmu_fill_atc(addr, super, tag, write, l, &status060);
! 882:
! 883: if (status060 && currprefs.mmu_model == 68060) {
! 884: mmu_bus_error(addr, val, mmu_get_fc(super, data), write, size, status060, false);
! 885: }
! 886:
! 887: // and retry the ATC search
! 888: way_random++;
! 889: goto atc_retry;
1.1.1.3 root 890: }
891:
1.1.1.5 root 892: static void misalignednotfirst(uaecptr addr)
893: {
894: #if MMUDEBUGMISC > 0
895: write_log (_T("misalignednotfirst %08x -> %08x %08X\n"), regs.mmu_fault_addr, addr, regs.instruction_pc);
896: #endif
897: regs.mmu_fault_addr = addr;
898: regs.mmu_fslw |= MMU_FSLW_MA;
899: regs.mmu_ssw |= MMU_SSW_MA;
900: }
901:
902: static void misalignednotfirstcheck(uaecptr addr)
903: {
904: if (regs.mmu_fault_addr == addr)
905: return;
906: misalignednotfirst (addr);
907: }
908:
1.1.1.7 ! root 909: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
1.1.1.3 root 910: {
911: uae_u16 res;
912:
1.1.1.7 ! root 913: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
1.1.1.3 root 914: SAVE_EXCEPTION;
915: TRY(prb) {
1.1.1.7 ! root 916: res |= mmu_get_byte(addr + 1, data, sz_word);
1.1.1.3 root 917: RESTORE_EXCEPTION;
918: }
919: CATCH(prb) {
920: RESTORE_EXCEPTION;
1.1.1.5 root 921: misalignednotfirst(addr);
1.1.1.3 root 922: THROW_AGAIN(prb);
923: } ENDTRY
924: return res;
925: }
926:
1.1.1.7 ! root 927: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
1.1.1.3 root 928: {
929: uae_u32 res;
930:
931: if (likely(!(addr & 1))) {
1.1.1.7 ! root 932: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
1.1.1.3 root 933: SAVE_EXCEPTION;
934: TRY(prb) {
1.1.1.7 ! root 935: res |= mmu_get_word(addr + 2, data, sz_long);
1.1.1.3 root 936: RESTORE_EXCEPTION;
937: }
938: CATCH(prb) {
939: RESTORE_EXCEPTION;
1.1.1.5 root 940: misalignednotfirst(addr);
1.1.1.3 root 941: THROW_AGAIN(prb);
942: } ENDTRY
943: } else {
1.1.1.7 ! root 944: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
1.1.1.3 root 945: SAVE_EXCEPTION;
946: TRY(prb) {
1.1.1.7 ! root 947: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
! 948: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
! 949: res |= mmu_get_byte(addr + 3, data, sz_long);
1.1.1.3 root 950: RESTORE_EXCEPTION;
951: }
952: CATCH(prb) {
953: RESTORE_EXCEPTION;
1.1.1.5 root 954: misalignednotfirst(addr);
1.1.1.3 root 955: THROW_AGAIN(prb);
956: } ENDTRY
957: }
958: return res;
959: }
960:
1.1.1.5 root 961: uae_u32 REGPARAM2 mmu_get_ilong_unaligned(uaecptr addr)
1.1.1.3 root 962: {
1.1.1.5 root 963: uae_u32 res;
1.1.1.3 root 964:
1.1.1.6 root 965: res = (uae_u32)mmu_get_iword(addr, sz_long) << 16;
966: SAVE_EXCEPTION;
967: TRY(prb) {
968: res |= mmu_get_iword(addr + 2, sz_long);
969: RESTORE_EXCEPTION;
1.1.1.3 root 970: }
1.1.1.6 root 971: CATCH(prb) {
972: RESTORE_EXCEPTION;
973: misalignednotfirst(addr);
974: THROW_AGAIN(prb);
975: } ENDTRY
1.1.1.5 root 976: return res;
977: }
1.1.1.3 root 978:
1.1.1.6 root 979: static uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
1.1.1.5 root 980: {
981: uae_u16 res;
1.1.1.3 root 982:
1.1.1.7 ! root 983: res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, sz_word, true) << 8;
1.1.1.5 root 984: SAVE_EXCEPTION;
985: TRY(prb) {
1.1.1.7 ! root 986: res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_word, true);
1.1.1.5 root 987: RESTORE_EXCEPTION;
988: }
989: CATCH(prb) {
990: RESTORE_EXCEPTION;
991: misalignednotfirst(addr);
992: THROW_AGAIN(prb);
993: } ENDTRY
994: return res;
1.1.1.3 root 995: }
996:
1.1.1.6 root 997: static uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
1.1.1.3 root 998: {
1.1.1.5 root 999: uae_u32 res;
1.1.1.3 root 1000:
1.1.1.5 root 1001: if (likely(!(addr & 1))) {
1.1.1.7 ! root 1002: res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, sz_long, true) << 16;
1.1.1.5 root 1003: SAVE_EXCEPTION;
1004: TRY(prb) {
1.1.1.7 ! root 1005: res |= mmu_get_user_word(addr + 2, regs.s != 0, true, sz_long, true);
1.1.1.5 root 1006: RESTORE_EXCEPTION;
1007: }
1008: CATCH(prb) {
1009: RESTORE_EXCEPTION;
1010: misalignednotfirst(addr);
1011: THROW_AGAIN(prb);
1012: } ENDTRY
1013: } else {
1.1.1.7 ! root 1014: res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, sz_long, true) << 8;
1.1.1.5 root 1015: SAVE_EXCEPTION;
1016: TRY(prb) {
1.1.1.7 ! root 1017: res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_long, true)) << 8;
! 1018: res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, sz_long, true)) << 8;
! 1019: res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, sz_long, true);
1.1.1.5 root 1020: RESTORE_EXCEPTION;
1021: }
1022: CATCH(prb) {
1023: RESTORE_EXCEPTION;
1024: misalignednotfirst(addr);
1025: THROW_AGAIN(prb);
1026: } ENDTRY
1027: }
1028: return res;
1029: }
1.1.1.3 root 1030:
1031:
1.1.1.7 ! root 1032: static void REGPARAM2 mmu_put_lrmw_long_unaligned(uaecptr addr, uae_u32 val)
1.1.1.3 root 1033: {
1034: SAVE_EXCEPTION;
1035: TRY(prb) {
1036: if (likely(!(addr & 1))) {
1.1.1.7 ! root 1037: mmu_put_user_word(addr, val >> 16, regs.s != 0, sz_long, true);
! 1038: mmu_put_user_word(addr + 2, val, regs.s != 0, sz_long, true);
1.1.1.3 root 1039: } else {
1.1.1.7 ! root 1040: mmu_put_user_byte(addr, val >> 24, regs.s != 0, sz_long, true);
! 1041: mmu_put_user_byte(addr + 1, val >> 16, regs.s != 0, sz_long, true);
! 1042: mmu_put_user_byte(addr + 2, val >> 8, regs.s != 0, sz_long, true);
! 1043: mmu_put_user_byte(addr + 3, val, regs.s != 0, sz_long, true);
1.1.1.3 root 1044: }
1045: RESTORE_EXCEPTION;
1046: }
1047: CATCH(prb) {
1048: RESTORE_EXCEPTION;
1049: regs.wb3_data = val;
1.1.1.5 root 1050: misalignednotfirstcheck(addr);
1.1.1.3 root 1051: THROW_AGAIN(prb);
1052: } ENDTRY
1053: }
1054:
1.1.1.7 ! root 1055: static void REGPARAM2 mmu_put_lrmw_word_unaligned(uaecptr addr, uae_u16 val)
1.1.1.3 root 1056: {
1057: SAVE_EXCEPTION;
1058: TRY(prb) {
1.1.1.7 ! root 1059: mmu_put_user_byte(addr, val >> 8, regs.s != 0, sz_word, true);
! 1060: mmu_put_user_byte(addr + 1, val, regs.s != 0, sz_word, true);
1.1.1.3 root 1061: RESTORE_EXCEPTION;
1062: }
1063: CATCH(prb) {
1064: RESTORE_EXCEPTION;
1065: regs.wb3_data = val;
1.1.1.5 root 1066: misalignednotfirstcheck(addr);
1.1.1.3 root 1067: THROW_AGAIN(prb);
1068: } ENDTRY
1069: }
1070:
1071:
1.1.1.7 ! root 1072:
! 1073: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
1.1.1.3 root 1074: {
1.1.1.7 ! root 1075: SAVE_EXCEPTION;
! 1076: TRY(prb) {
! 1077: if (likely(!(addr & 1))) {
! 1078: mmu_put_word(addr, val >> 16, data, sz_long);
! 1079: mmu_put_word(addr + 2, val, data, sz_long);
! 1080: } else {
! 1081: mmu_put_byte(addr, val >> 24, data, sz_long);
! 1082: mmu_put_byte(addr + 1, val >> 16, data, sz_long);
! 1083: mmu_put_byte(addr + 2, val >> 8, data, sz_long);
! 1084: mmu_put_byte(addr + 3, val, data, sz_long);
! 1085: }
! 1086: RESTORE_EXCEPTION;
1.1.1.3 root 1087: }
1.1.1.7 ! root 1088: CATCH(prb) {
! 1089: RESTORE_EXCEPTION;
! 1090: regs.wb3_data = val;
! 1091: misalignednotfirstcheck(addr);
! 1092: THROW_AGAIN(prb);
! 1093: } ENDTRY
1.1.1.3 root 1094: }
1095:
1.1.1.7 ! root 1096: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
1.1.1.3 root 1097: {
1.1.1.7 ! root 1098: SAVE_EXCEPTION;
! 1099: TRY(prb) {
! 1100: mmu_put_byte(addr, val >> 8, data, sz_word);
! 1101: mmu_put_byte(addr + 1, val, data, sz_word);
! 1102: RESTORE_EXCEPTION;
1.1.1.3 root 1103: }
1.1.1.7 ! root 1104: CATCH(prb) {
! 1105: RESTORE_EXCEPTION;
! 1106: regs.wb3_data = val;
! 1107: misalignednotfirstcheck(addr);
! 1108: THROW_AGAIN(prb);
! 1109: } ENDTRY
1.1.1.3 root 1110: }
1111:
1112: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
1113: {
1114: bool super = (regs.sfc & 4) != 0;
1115: uae_u32 res;
1116:
1.1.1.5 root 1117: ismoves = true;
1118: if (likely(!is_unaligned(addr, 4))) {
1.1.1.7 ! root 1119: res = mmu_get_user_long(addr, super, false, sz_long, false);
1.1.1.3 root 1120: } else {
1.1.1.5 root 1121: if (likely(!(addr & 1))) {
1.1.1.7 ! root 1122: res = (uae_u32)mmu_get_user_word(addr, super, false, sz_long, false) << 16;
1.1.1.5 root 1123: SAVE_EXCEPTION;
1124: TRY(prb) {
1.1.1.7 ! root 1125: res |= mmu_get_user_word(addr + 2, super, false, sz_long, false);
1.1.1.5 root 1126: RESTORE_EXCEPTION;
1127: }
1128: CATCH(prb) {
1129: RESTORE_EXCEPTION;
1130: misalignednotfirst(addr);
1131: THROW_AGAIN(prb);
1132: } ENDTRY
1133: } else {
1.1.1.7 ! root 1134: res = (uae_u32)mmu_get_user_byte(addr, super, false, sz_long, false) << 8;
1.1.1.5 root 1135: SAVE_EXCEPTION;
1136: TRY(prb) {
1.1.1.7 ! root 1137: res = (res | mmu_get_user_byte(addr + 1, super, false, sz_long, false)) << 8;
! 1138: res = (res | mmu_get_user_byte(addr + 2, super, false, sz_long, false)) << 8;
! 1139: res |= mmu_get_user_byte(addr + 3, super, false, sz_long, false);
1.1.1.5 root 1140: RESTORE_EXCEPTION;
1141: }
1142: CATCH(prb) {
1143: RESTORE_EXCEPTION;
1144: misalignednotfirst(addr);
1145: THROW_AGAIN(prb);
1146: } ENDTRY
1.1.1.3 root 1147: }
1148: }
1.1.1.5 root 1149:
1150: ismoves = false;
1.1.1.3 root 1151: return res;
1152: }
1153:
1154: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
1155: {
1156: bool super = (regs.sfc & 4) != 0;
1157: uae_u16 res;
1158:
1.1.1.5 root 1159: ismoves = true;
1160: if (likely(!is_unaligned(addr, 2))) {
1.1.1.7 ! root 1161: res = mmu_get_user_word(addr, super, false, sz_word, false);
1.1.1.5 root 1162: } else {
1.1.1.7 ! root 1163: res = (uae_u16)mmu_get_user_byte(addr, super, false, sz_word, false) << 8;
1.1.1.5 root 1164: SAVE_EXCEPTION;
1165: TRY(prb) {
1.1.1.7 ! root 1166: res |= mmu_get_user_byte(addr + 1, super, false, sz_word, false);
1.1.1.5 root 1167: RESTORE_EXCEPTION;
1168: }
1169: CATCH(prb) {
1170: RESTORE_EXCEPTION;
1171: misalignednotfirst(addr);
1172: THROW_AGAIN(prb);
1173: } ENDTRY
1.1.1.3 root 1174: }
1.1.1.5 root 1175: ismoves = false;
1.1.1.3 root 1176: return res;
1177: }
1178:
1179: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
1180: {
1181: bool super = (regs.sfc & 4) != 0;
1.1.1.5 root 1182: uae_u8 res;
1183:
1184: ismoves = true;
1.1.1.7 ! root 1185: res = mmu_get_user_byte(addr, super, false, sz_byte, false);
1.1.1.5 root 1186: ismoves = false;
1187: return res;
1.1.1.3 root 1188: }
1189:
1190: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
1191: {
1192: bool super = (regs.dfc & 4) != 0;
1193:
1.1.1.5 root 1194: ismoves = true;
1.1.1.3 root 1195: SAVE_EXCEPTION;
1196: TRY(prb) {
1.1.1.7 ! root 1197: if (likely(!is_unaligned(addr, 4))) {
! 1198: mmu_put_user_long(addr, val, super, sz_long, false);
! 1199: } else if (likely(!(addr & 1))) {
! 1200: mmu_put_user_word(addr, val >> 16, super, sz_long, false);
! 1201: mmu_put_user_word(addr + 2, val, super, sz_long, false);
1.1.1.3 root 1202: } else {
1.1.1.7 ! root 1203: mmu_put_user_byte(addr, val >> 24, super, sz_long, false);
! 1204: mmu_put_user_byte(addr + 1, val >> 16, super, sz_long, false);
! 1205: mmu_put_user_byte(addr + 2, val >> 8, super, sz_long, false);
! 1206: mmu_put_user_byte(addr + 3, val, super, sz_long, false);
1.1.1.3 root 1207: }
1208: RESTORE_EXCEPTION;
1209: }
1210: CATCH(prb) {
1211: RESTORE_EXCEPTION;
1212: regs.wb3_data = val;
1.1.1.5 root 1213: misalignednotfirstcheck(addr);
1.1.1.3 root 1214: THROW_AGAIN(prb);
1215: } ENDTRY
1.1.1.5 root 1216: ismoves = false;
1.1.1.3 root 1217: }
1218:
1219: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
1220: {
1221: bool super = (regs.dfc & 4) != 0;
1222:
1.1.1.5 root 1223: ismoves = true;
1.1.1.3 root 1224: SAVE_EXCEPTION;
1225: TRY(prb) {
1.1.1.7 ! root 1226: if (likely(!is_unaligned(addr, 2))) {
! 1227: mmu_put_user_word(addr, val, super, sz_word, false);
! 1228: } else {
! 1229: mmu_put_user_byte(addr, val >> 8, super, sz_word, false);
! 1230: mmu_put_user_byte(addr + 1, val, super, sz_word, false);
1.1.1.3 root 1231: }
1232: RESTORE_EXCEPTION;
1233: }
1234: CATCH(prb) {
1235: RESTORE_EXCEPTION;
1236: regs.wb3_data = val;
1.1.1.5 root 1237: misalignednotfirstcheck(addr);
1.1.1.3 root 1238: THROW_AGAIN(prb);
1239: } ENDTRY
1.1.1.5 root 1240: ismoves = false;
1.1.1.3 root 1241: }
1242:
1243: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
1244: {
1245: bool super = (regs.dfc & 4) != 0;
1246:
1.1.1.5 root 1247: ismoves = true;
1.1.1.3 root 1248: SAVE_EXCEPTION;
1249: TRY(prb) {
1.1.1.7 ! root 1250: mmu_put_user_byte(addr, val, super, sz_byte, false);
1.1.1.3 root 1251: RESTORE_EXCEPTION;
1252: }
1253: CATCH(prb) {
1254: RESTORE_EXCEPTION;
1255: regs.wb3_data = val;
1256: THROW_AGAIN(prb);
1257: } ENDTRY
1.1.1.5 root 1258: ismoves = false;
1259: }
1260:
1261: void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size)
1262: {
1.1.1.7 ! root 1263: bool super = regs.s != 0;
1.1.1.5 root 1264: int i;
1.1.1.7 ! root 1265:
1.1.1.5 root 1266: addr &= ~15;
1.1.1.7 ! root 1267: if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
! 1268: addr = mmu_translate(addr, 0, super, data, false, size);
! 1269: }
! 1270: // MOVE16 read and cache miss: do not allocate new cache line
! 1271: mmu_cache_state |= CACHE_DISABLE_ALLOCATE;
1.1.1.5 root 1272: for (i = 0; i < 4; i++) {
1.1.1.7 ! root 1273: v[i] = x_phys_get_long(addr + i * 4);
1.1.1.5 root 1274: }
1.1.1.3 root 1275: }
1276:
1.1.1.5 root 1277: void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size)
1278: {
1.1.1.7 ! root 1279: bool super = regs.s != 0;
1.1.1.5 root 1280: int i;
1.1.1.7 ! root 1281:
1.1.1.5 root 1282: addr &= ~15;
1.1.1.7 ! root 1283: if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,data,val[0],size) == TTR_NO_MATCH) && regs.mmu_enabled) {
! 1284: addr = mmu_translate(addr, val[0], super, data, true, size);
! 1285: }
! 1286: // MOVE16 write invalidates existing line and also does not allocate new cache lines.
! 1287: mmu_cache_state = CACHE_DISABLE_MMU;
1.1.1.5 root 1288: for (i = 0; i < 4; i++) {
1.1.1.7 ! root 1289: x_phys_put_long(addr + i * 4, val[i]);
1.1.1.5 root 1290: }
1291: }
1292:
1293:
1.1.1.3 root 1294: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
1295: {
1296: bool super = (regs.dfc & 4) != 0;
1297: DUNUSED(extra);
1.1.1.5 root 1298: if ((opcode & 0xFE0) == 0x0500) { // PFLUSH
1.1.1.3 root 1299: bool glob;
1300: int regno;
1301: //D(didflush = 0);
1302: uae_u32 addr;
1303: /* PFLUSH */
1304: regno = opcode & 7;
1305: glob = (opcode & 8) != 0;
1306:
1307: if (opcode & 16) {
1.1.1.5 root 1308: #if MMUINSDEBUG > 1
1309: write_log(_T("pflusha(%u,%u) PC=%08x\n"), glob, regs.dfc, m68k_getpc ());
1310: #endif
1.1.1.3 root 1311: mmu_flush_atc_all(glob);
1312: } else {
1313: addr = m68k_areg(regs, regno);
1.1.1.5 root 1314: #if MMUINSDEBUG > 1
1315: write_log(_T("pflush(%u,%u,%x) PC=%08x\n"), glob, regs.dfc, addr, m68k_getpc ());
1316: #endif
1.1.1.3 root 1317: mmu_flush_atc(addr, super, glob);
1318: }
1319: flush_internals();
1320: #ifdef USE_JIT
1321: flush_icache(0);
1322: #endif
1.1.1.5 root 1323: } else if ((opcode & 0x0FD8) == 0x0548) { // PTEST (68040)
1.1.1.3 root 1324: bool write;
1325: int regno;
1326: uae_u32 addr;
1.1.1.7 ! root 1327: uae_u32 status060 = 0;
1.1.1.3 root 1328:
1329: regno = opcode & 7;
1330: write = (opcode & 32) == 0;
1331: addr = m68k_areg(regs, regno);
1.1.1.5 root 1332: #if MMUINSDEBUG > 0
1333: write_log(_T("PTEST%c (A%d) %08x DFC=%d\n"), write ? 'W' : 'R', regno, addr, regs.dfc);
1334: #endif
1.1.1.3 root 1335: mmu_flush_atc(addr, super, true);
1.1.1.7 ! root 1336: bool data = (regs.dfc & 3) != 2;
! 1337: int ttr_match = mmu_match_ttr(addr,super,data);
! 1338: if (ttr_match != TTR_NO_MATCH) {
! 1339: if (ttr_match == TTR_NO_WRITE && write) {
! 1340: regs.mmusr = MMU_MMUSR_B;
1.1.1.5 root 1341: } else {
1.1.1.7 ! root 1342: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
1.1.1.3 root 1343: }
1.1.1.7 ! root 1344: } else if (!currprefs.mmu_ec) {
! 1345: int way;
! 1346: uae_u32 index;
! 1347: uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
! 1348: if (mmu_pagesize_8k)
! 1349: index=(addr & 0x0001E000)>>13;
! 1350: else
! 1351: index=(addr & 0x0000F000)>>12;
! 1352: for (way = 0; way < ATC_WAYS; way++) {
! 1353: if (!mmu_atc_array[data][index][way].valid)
! 1354: break;
! 1355: }
! 1356: if (way >= ATC_WAYS) {
! 1357: way = way_random % ATC_WAYS;
! 1358: }
! 1359: regs.mmusr = mmu_fill_atc(addr, super, tag, write, &mmu_atc_array[data][index][way], &status060);
1.1.1.5 root 1360: #if MMUINSDEBUG > 0
1.1.1.7 ! root 1361: write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
1.1.1.5 root 1362: #endif
1.1.1.7 ! root 1363: }
1.1.1.5 root 1364: } else if ((opcode & 0xFFB8) == 0xF588) { // PLPA (68060)
1365: int write = (opcode & 0x40) == 0;
1366: int regno = opcode & 7;
1367: uae_u32 addr = m68k_areg (regs, regno);
1368: bool data = (regs.dfc & 3) != 2;
1.1.1.7 ! root 1369: int ttr;
1.1.1.5 root 1370:
1371: #if MMUINSDEBUG > 0
1372: write_log(_T("PLPA%c param: %08x\n"), write ? 'W' : 'R', addr);
1373: #endif
1.1.1.7 ! root 1374: if (write)
! 1375: ttr = mmu_match_ttr_write(addr, super, data, 0, 1);
! 1376: else
! 1377: ttr = mmu_match_ttr(addr,super,data);
! 1378: if (ttr == TTR_NO_MATCH) {
! 1379: if (!currprefs.mmu_ec) {
! 1380: m68k_areg (regs, regno) = mmu_translate(addr, 0, super, data, write, 1);
! 1381: }
1.1.1.5 root 1382: }
1383: #if MMUINSDEBUG > 0
1384: write_log(_T("PLPA%c result: %08x\n"), write ? 'W' : 'R', m68k_areg (regs, regno));
1385: #endif
1386: } else {
1.1.1.3 root 1387: op_illg (opcode);
1.1.1.5 root 1388: }
1.1.1.3 root 1389: }
1390:
1.1.1.5 root 1391: // fixme : global parameter?
1.1.1.3 root 1392: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
1393: {
1.1.1.5 root 1394: int way,type,index;
1.1.1.3 root 1395:
1.1.1.5 root 1396: uaecptr tag = ((super ? 0x80000000 : 0) | (addr >> 1)) & mmu_tagmask;
1397: if (mmu_pagesize_8k)
1398: index=(addr & 0x0001E000)>>13;
1399: else
1400: index=(addr & 0x0000F000)>>12;
1401: for (type=0;type<ATC_TYPE;type++) {
1402: for (way=0;way<ATC_WAYS;way++) {
1.1.1.7 ! root 1403: struct mmu_atc_line *l = &mmu_atc_array[type][index][way];
! 1404: if (!global && (l->status & MMU_MMUSR_G))
1.1.1.5 root 1405: continue;
1406: // if we have this
1.1.1.7 ! root 1407: if (tag == l->tag && l->valid) {
! 1408: l->valid=false;
1.1.1.5 root 1409: }
1410: }
1411: }
1.1.1.7 ! root 1412: flush_shortcut_cache(addr, super);
! 1413: mmu_flush_cache();
1.1.1.3 root 1414: }
1415:
1416: void REGPARAM2 mmu_flush_atc_all(bool global)
1417: {
1.1.1.7 ! root 1418: int way,slot,type;
1.1.1.5 root 1419: for (type=0;type<ATC_TYPE;type++) {
1.1.1.7 ! root 1420: for (slot=0;slot<ATC_SLOTS;slot++) {
! 1421: for (way=0;way<ATC_WAYS;way++) {
! 1422: struct mmu_atc_line *l = &mmu_atc_array[type][slot][way];
! 1423: if (!global && (l->status&MMU_MMUSR_G))
1.1.1.5 root 1424: continue;
1.1.1.7 ! root 1425: l->valid=false;
1.1.1.5 root 1426: }
1427: }
1.1.1.3 root 1428: }
1.1.1.7 ! root 1429: flush_shortcut_cache(0xffffffff, 0);
! 1430: mmu_flush_cache();
1.1.1.5 root 1431: }
1.1.1.3 root 1432:
1.1.1.5 root 1433: void REGPARAM2 mmu_set_funcs(void)
1434: {
1435: if (currprefs.mmu_model != 68040 && currprefs.mmu_model != 68060)
1436: return;
1.1.1.7 ! root 1437: if (currprefs.cpu_memory_cycle_exact || currprefs.cpu_compatible) {
1.1.1.5 root 1438: x_phys_get_iword = get_word_icache040;
1439: x_phys_get_ilong = get_long_icache040;
1.1.1.7 ! root 1440: if (currprefs.cpu_data_cache) {
! 1441: x_phys_get_byte = get_byte_cache_040;
! 1442: x_phys_get_word = get_word_cache_040;
! 1443: x_phys_get_long = get_long_cache_040;
! 1444: x_phys_put_byte = put_byte_cache_040;
! 1445: x_phys_put_word = put_word_cache_040;
! 1446: x_phys_put_long = put_long_cache_040;
! 1447: } else if (currprefs.cpu_memory_cycle_exact) {
! 1448: x_phys_get_byte = mem_access_delay_byte_read_c040;
! 1449: x_phys_get_word = mem_access_delay_word_read_c040;
! 1450: x_phys_get_long = mem_access_delay_long_read_c040;
! 1451: x_phys_put_byte = mem_access_delay_byte_write_c040;
! 1452: x_phys_put_word = mem_access_delay_word_write_c040;
! 1453: x_phys_put_long = mem_access_delay_long_write_c040;
! 1454: } else {
! 1455: x_phys_get_byte = phys_get_byte;
! 1456: x_phys_get_word = phys_get_word;
! 1457: x_phys_get_long = phys_get_long;
! 1458: x_phys_put_byte = phys_put_byte;
! 1459: x_phys_put_word = phys_put_word;
! 1460: x_phys_put_long = phys_put_long;
! 1461: }
1.1.1.5 root 1462: } else {
1463: x_phys_get_iword = phys_get_word;
1464: x_phys_get_ilong = phys_get_long;
1465: x_phys_get_byte = phys_get_byte;
1466: x_phys_get_word = phys_get_word;
1467: x_phys_get_long = phys_get_long;
1468: x_phys_put_byte = phys_put_byte;
1469: x_phys_put_word = phys_put_word;
1470: x_phys_put_long = phys_put_long;
1.1.1.3 root 1471: }
1472: }
1473:
1474: void REGPARAM2 mmu_reset(void)
1475: {
1476: mmu_flush_atc_all(true);
1.1.1.5 root 1477: mmu_set_funcs();
1478: }
1479:
1.1.1.7 ! root 1480: uae_u16 REGPARAM2 mmu_set_tc(uae_u16 tc)
1.1.1.5 root 1481: {
1.1.1.7 ! root 1482: if (currprefs.mmu_ec) {
! 1483: tc &= ~(0x8000 | 0x4000);
! 1484: // at least 68EC040 always returns zero when TC is read.
! 1485: if (currprefs.cpu_model == 68040)
! 1486: tc = 0;
! 1487: }
! 1488:
1.1.1.5 root 1489: regs.mmu_enabled = (tc & 0x8000) != 0;
1490: mmu_pagesize_8k = (tc & 0x4000) != 0;
1.1.1.7 ! root 1491:
1.1.1.5 root 1492: mmu_tagmask = mmu_pagesize_8k ? 0xFFFF0000 : 0xFFFF8000;
1493: mmu_pagemask = mmu_pagesize_8k ? 0x00001FFF : 0x00000FFF;
1494: mmu_pagemaski = ~mmu_pagemask;
1495: regs.mmu_page_size = mmu_pagesize_8k ? 8192 : 4096;
1.1.1.7 ! root 1496: mmu_pageshift = mmu_pagesize_8k ? 13 : 12;
! 1497: mmu_pageshift1m = mmu_pageshift - 1;
! 1498:
! 1499: cache_default_ins = CACHE_ENABLE_ALL;
! 1500: cache_default_data = CACHE_ENABLE_ALL;
! 1501: if (currprefs.mmu_model == 68060) {
! 1502: int dc = (tc >> 3) & 3;
! 1503: cache_default_ins = 0;
! 1504: if (!(dc & 2))
! 1505: cache_default_ins = CACHE_ENABLE_ALL;
! 1506: dc = (tc >> 8) & 3;
! 1507: cache_default_data = 0;
! 1508: if (!(dc & 2))
! 1509: cache_default_data = (dc & 1) ? CACHE_ENABLE_COPYBACK | CACHE_ENABLE_ALL : CACHE_ENABLE_ALL;
! 1510: }
1.1.1.5 root 1511:
1512: mmu_flush_atc_all(true);
1513:
1.1.1.7 ! root 1514: write_log(_T("%d MMU: TC=%04x enabled=%d page8k=%d PC=%08x\n"), tc, currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k, m68k_getpc());
! 1515: return tc;
1.1.1.3 root 1516: }
1517:
1.1.1.5 root 1518: void REGPARAM2 mmu_set_super(bool super)
1519: {
1520: mmu_is_super = super ? 0x80000000 : 0;
1521: }
1.1.1.3 root 1522:
1.1.1.7 ! root 1523: void REGPARAM2 mmu_flush_cache(void)
! 1524: {
! 1525: #if MMU_ICACHE
! 1526: int len = sizeof(mmu_icache_data);
! 1527: memset(&mmu_icache_data, 0xff, sizeof(mmu_icache_data));
! 1528: #endif
! 1529: }
! 1530:
1.1.1.5 root 1531: void m68k_do_rte_mmu040 (uaecptr a7)
1532: {
1533: uae_u16 ssr = get_word_mmu040 (a7 + 8 + 4);
1534: if (ssr & MMU_SSW_CT) {
1535: uaecptr src_a7 = a7 + 8 - 8;
1536: uaecptr dst_a7 = a7 + 8 + 52;
1537: put_word_mmu040 (dst_a7 + 0, get_word_mmu040 (src_a7 + 0));
1538: put_long_mmu040 (dst_a7 + 2, get_long_mmu040 (src_a7 + 2));
1539: // skip this word
1540: put_long_mmu040 (dst_a7 + 8, get_long_mmu040 (src_a7 + 8));
1541: }
1542: if (ssr & MMU_SSW_CM) {
1543: mmu040_movem = 1;
1544: mmu040_movem_ea = get_long_mmu040 (a7 + 8);
1545: #if MMUDEBUGMISC > 0
1546: write_log (_T("MMU restarted MOVEM EA=%08X\n"), mmu040_movem_ea);
1547: #endif
1548: }
1549: }
1550:
1551: void m68k_do_rte_mmu060 (uaecptr a7)
1.1.1.3 root 1552: {
1553: #if 0
1.1.1.5 root 1554: mmu060_state = 2;
1.1.1.3 root 1555: #endif
1.1.1.5 root 1556: }
1.1.1.3 root 1557:
1.1.1.5 root 1558: void flush_mmu040 (uaecptr addr, int n)
1559: {
1.1.1.7 ! root 1560: mmu_flush_cache();
1.1.1.5 root 1561: }
1.1.1.7 ! root 1562:
1.1.1.5 root 1563: void m68k_do_rts_mmu040 (void)
1564: {
1565: uaecptr stack = m68k_areg (regs, 7);
1566: uaecptr newpc = get_long_mmu040 (stack);
1567: m68k_areg (regs, 7) += 4;
1568: m68k_setpc (newpc);
1569: }
1570: void m68k_do_bsr_mmu040 (uaecptr oldpc, uae_s32 offset)
1571: {
1572: uaecptr newstack = m68k_areg (regs, 7) - 4;
1573: put_long_mmu040 (newstack, oldpc);
1574: m68k_areg (regs, 7) -= 4;
1575: m68k_incpci (offset);
1.1.1.3 root 1576: }
1577:
1.1.1.5 root 1578: void flush_mmu060 (uaecptr addr, int n)
1579: {
1.1.1.7 ! root 1580: mmu_flush_cache();
1.1.1.5 root 1581: }
1.1.1.7 ! root 1582:
1.1.1.5 root 1583: void m68k_do_rts_mmu060 (void)
1.1.1.3 root 1584: {
1.1.1.5 root 1585: uaecptr stack = m68k_areg (regs, 7);
1586: uaecptr newpc = get_long_mmu060 (stack);
1587: m68k_areg (regs, 7) += 4;
1588: m68k_setpc (newpc);
1589: }
1590: void m68k_do_bsr_mmu060 (uaecptr oldpc, uae_s32 offset)
1591: {
1592: uaecptr newstack = m68k_areg (regs, 7) - 4;
1593: put_long_mmu060 (newstack, oldpc);
1594: m68k_areg (regs, 7) -= 4;
1595: m68k_incpci (offset);
1596: }
1597:
1598: void uae_mmu_put_lrmw (uaecptr addr, uae_u32 v, int size, int type)
1599: {
1600: locked_rmw_cycle = true;
1601: if (size == sz_byte) {
1.1.1.7 ! root 1602: mmu_put_user_byte(addr, v, regs.s, sz_byte, true);
1.1.1.5 root 1603: } else if (size == sz_word) {
1604: if (unlikely(is_unaligned(addr, 2))) {
1.1.1.7 ! root 1605: mmu_put_lrmw_word_unaligned(addr, v);
1.1.1.5 root 1606: } else {
1.1.1.7 ! root 1607: mmu_put_user_word(addr, v, regs.s != 0, sz_word, true);
1.1.1.5 root 1608: }
1609: } else {
1610: if (unlikely(is_unaligned(addr, 4)))
1.1.1.7 ! root 1611: mmu_put_lrmw_long_unaligned(addr, v);
1.1.1.5 root 1612: else
1.1.1.7 ! root 1613: mmu_put_user_long(addr, v, regs.s, sz_long, true);
1.1.1.5 root 1614: }
1615: locked_rmw_cycle = false;
1616: }
1617: uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type)
1618: {
1619: uae_u32 v;
1620: locked_rmw_cycle = true;
1621: if (size == sz_byte) {
1.1.1.7 ! root 1622: v = mmu_get_user_byte(addr, regs.s != 0, true, sz_byte, true);
1.1.1.5 root 1623: } else if (size == sz_word) {
1624: if (unlikely(is_unaligned(addr, 2))) {
1625: v = mmu_get_lrmw_word_unaligned(addr);
1626: } else {
1.1.1.7 ! root 1627: v = mmu_get_user_word(addr, regs.s != 0, true, sz_word, true);
1.1.1.5 root 1628: }
1629: } else {
1630: if (unlikely(is_unaligned(addr, 4)))
1631: v = mmu_get_lrmw_long_unaligned(addr);
1632: else
1.1.1.7 ! root 1633: v = mmu_get_user_long(addr, regs.s != 0, true, sz_long, true);
1.1.1.5 root 1634: }
1635: locked_rmw_cycle = false;
1636: return v;
1637: }
1638:
1639: uae_u32 REGPARAM2 mmu060_get_rmw_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width)
1640: {
1641: uae_u32 tmp1, tmp2, res, mask;
1642:
1643: offset &= 7;
1644: mask = 0xffffffffu << (32 - width);
1645: switch ((offset + width + 7) >> 3) {
1646: case 1:
1647: tmp1 = get_rmw_byte_mmu060 (src);
1648: res = tmp1 << (24 + offset);
1649: bdata[0] = tmp1 & ~(mask >> (24 + offset));
1650: break;
1651: case 2:
1652: tmp1 = get_rmw_word_mmu060 (src);
1653: res = tmp1 << (16 + offset);
1654: bdata[0] = tmp1 & ~(mask >> (16 + offset));
1655: break;
1656: case 3:
1657: tmp1 = get_rmw_word_mmu060 (src);
1658: tmp2 = get_rmw_byte_mmu060 (src + 2);
1659: res = tmp1 << (16 + offset);
1660: bdata[0] = tmp1 & ~(mask >> (16 + offset));
1661: res |= tmp2 << (8 + offset);
1662: bdata[1] = tmp2 & ~(mask >> (8 + offset));
1663: break;
1664: case 4:
1665: tmp1 = get_rmw_long_mmu060 (src);
1666: res = tmp1 << offset;
1667: bdata[0] = tmp1 & ~(mask >> offset);
1668: break;
1669: case 5:
1670: tmp1 = get_rmw_long_mmu060 (src);
1671: tmp2 = get_rmw_byte_mmu060 (src + 4);
1672: res = tmp1 << offset;
1673: bdata[0] = tmp1 & ~(mask >> offset);
1674: res |= tmp2 >> (8 - offset);
1675: bdata[1] = tmp2 & ~(mask << (8 - offset));
1676: break;
1677: default:
1678: /* Panic? */
1679: write_log (_T("x_get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3);
1680: res = 0;
1681: break;
1682: }
1683: return res;
1684: }
1685:
1686: void REGPARAM2 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width)
1687: {
1688: offset = (offset & 7) + width;
1689: switch ((offset + 7) >> 3) {
1690: case 1:
1691: put_rmw_byte_mmu060 (dst, bdata[0] | (val << (8 - offset)));
1692: break;
1693: case 2:
1694: put_rmw_word_mmu060 (dst, bdata[0] | (val << (16 - offset)));
1695: break;
1696: case 3:
1697: put_rmw_word_mmu060 (dst, bdata[0] | (val >> (offset - 16)));
1698: put_rmw_byte_mmu060 (dst + 2, bdata[1] | (val << (24 - offset)));
1699: break;
1700: case 4:
1701: put_rmw_long_mmu060 (dst, bdata[0] | (val << (32 - offset)));
1702: break;
1703: case 5:
1704: put_rmw_long_mmu060 (dst, bdata[0] | (val >> (offset - 32)));
1705: put_rmw_byte_mmu060 (dst + 4, bdata[1] | (val << (40 - offset)));
1706: break;
1707: default:
1708: write_log (_T("x_put_bitfield() can't happen %d\n"), (offset + 7) >> 3);
1709: break;
1710: }
1.1.1.3 root 1711: }
1712:
1.1.1.5 root 1713:
1714: #ifndef __cplusplus
1.1.1.3 root 1715: jmp_buf __exbuf;
1716: int __exvalue;
1717: #define MAX_TRY_STACK 256
1718: static int s_try_stack_size=0;
1719: static jmp_buf s_try_stack[MAX_TRY_STACK];
1720: jmp_buf* __poptry(void) {
1721: if (s_try_stack_size>0) {
1.1.1.7 ! root 1722: s_try_stack_size--;
! 1723: if (s_try_stack_size == 0)
! 1724: return NULL;
! 1725: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
! 1726: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
! 1727: return &s_try_stack[s_try_stack_size-1];
! 1728: }
1.1.1.3 root 1729: else {
1730: fprintf(stderr,"try stack underflow...\n");
1.1.1.7 ! root 1731: // return (NULL);
1.1.1.5 root 1732: abort();
1.1.1.3 root 1733: }
1734: }
1735: void __pushtry(jmp_buf* j) {
1736: if (s_try_stack_size<MAX_TRY_STACK) {
1.1.1.7 ! root 1737: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
1.1.1.3 root 1738: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
1739: s_try_stack_size++;
1740: } else {
1741: fprintf(stderr,"try stack overflow...\n");
1.1.1.5 root 1742: abort();
1.1.1.3 root 1743: }
1744: }
1745: int __is_catched(void) {return (s_try_stack_size>0); }
1.1.1.5 root 1746: #endif
1747:
1.1.1.3 root 1748: #else
1749:
1750: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
1751: {
1752: if ((opcode & 0xFE0) == 0x0500) {
1753: /* PFLUSH instruction */
1754: flush_internals();
1755: } else if ((opcode & 0x0FD8) == 0x548) {
1756: /* PTEST instruction */
1757: } else
1758: op_illg(opcode);
1759: }
1760:
1761: #endif
1762:
1.1.1.5 root 1763:
1.1.1.3 root 1764: /*
1765: vim:ts=4:sw=4:
1766: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.