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