|
|
1.1.1.2 root 1: /*
2: * cpummu.cpp - MMU emulation
3: *
4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
5: *
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
22: * along with ARAnyM; if not, write to the Free Software
23: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24: */
25:
1.1.1.4 ! root 26: #include <strings.h>
1.1.1.2 root 27:
28: #include "sysconfig.h"
29: #include "sysdeps.h"
30:
31: #include "options_cpu.h"
32: #include "memory.h"
33: #include "newcpu.h"
34: #include "cpummu.h"
1.1.1.4 ! root 35: #include "hatari-glue.h"
! 36: //#include "debug.h"
1.1.1.2 root 37:
38: #define DBG_MMU_VERBOSE 1
39: #define DBG_MMU_SANITY 1
1.1.1.4 ! root 40: #if 0
1.1.1.2 root 41: #define write_log printf
1.1.1.4 ! root 42: #endif
1.1.1.2 root 43:
44: #ifdef FULLMMU
45:
46:
1.1.1.4 ! root 47: uae_u32 mmu_is_super;
! 48: uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
1.1.1.2 root 49: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
1.1.1.4 ! root 50: bool mmu_pagesize_8k;
! 51:
! 52: int mmu060_state;
! 53: uae_u16 mmu_opcode;
! 54: bool mmu_restart;
! 55: static bool locked_rmw_cycle;
! 56: static bool ismoves;
! 57: bool mmu_ttr_enabled;
! 58: int mmu_atc_ways=0;
! 59:
! 60: int mmu040_movem;
! 61: uaecptr mmu040_movem_ea;
! 62: uae_u32 mmu040_move16[4];
1.1.1.2 root 63:
64: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
65: {
66: DUNUSED(label);
67: uae_u32 from_addr, to_addr;
68:
69: from_addr = ttr & MMU_TTR_LOGICAL_BASE;
70: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
71:
72:
1.1.1.4 ! root 73: #if MMUDEBUG > 0
! 74: write_log(_T("%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n"),
1.1.1.2 root 75: label, ttr,
76: from_addr, to_addr,
77: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
78: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
79: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
80: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
81: );
1.1.1.4 ! root 82: #endif
1.1.1.2 root 83: }
84:
85: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
86: {
87: uae_u32 * ttr;
88: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0;
89: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1;
90:
91: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
92: ttr = ttr1;
93: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
94: ttr = ttr0;
95: else
96: return;
97:
98: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
99: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
100: *ttr |= MMU_TTR_BIT_ENABLED;
101:
1.1.1.4 ! root 102: #if MMUDEBUG > 0
! 103: write_log(_T("MMU: map transparent mapping of %08x\n"), *ttr);
! 104: #endif
1.1.1.2 root 105: }
106:
1.1.1.4 ! root 107: void mmu_tt_modified (void)
! 108: {
! 109: mmu_ttr_enabled = ((regs.dtt0 | regs.dtt1 | regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
! 110: }
1.1.1.2 root 111:
112:
113: #if 0
114: /* {{{ mmu_dump_table */
115: static void mmu_dump_table(const char * label, uaecptr root_ptr)
116: {
117: DUNUSED(label);
118: const int ROOT_TABLE_SIZE = 128,
119: PTR_TABLE_SIZE = 128,
120: PAGE_TABLE_SIZE = 64,
121: ROOT_INDEX_SHIFT = 25,
122: PTR_INDEX_SHIFT = 18;
123: // const int PAGE_INDEX_SHIFT = 12;
124: int root_idx, ptr_idx, page_idx;
125: uae_u32 root_des, ptr_des, page_des;
126: uaecptr ptr_des_addr, page_addr,
127: root_log, ptr_log, page_log;
128:
1.1.1.4 ! root 129: write_log(_T("%s: root=%lx\n", label, root_ptr);
1.1.1.2 root 130:
131: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
132: root_des = phys_get_long(root_ptr + root_idx);
133:
134: if ((root_des & 2) == 0)
135: continue; /* invalid */
136:
1.1.1.4 ! root 137: write_log(_T("ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
1.1.1.2 root 138: root_des & 8 ? 1 : 0,
139: root_des & 4 ? 1 : 0,
140: root_des & 3
141: );
142:
143: root_log = root_idx << ROOT_INDEX_SHIFT;
144:
145: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
146:
147: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
148: struct {
149: uaecptr log, phys;
150: int start_idx, n_pages; /* number of pages covered by this entry */
151: uae_u32 match;
152: } page_info[PAGE_TABLE_SIZE];
153: int n_pages_used;
154:
155: ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
156: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
157:
158: if ((ptr_des & 2) == 0)
159: continue; /* invalid */
160:
1.1.1.4 ! root 161: page_addr = ptr_des & (mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
1.1.1.2 root 162:
163: n_pages_used = -1;
164: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
165:
166: page_des = phys_get_long(page_addr + page_idx);
167: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT
168:
169: switch (page_des & 3) {
170: case 0: /* invalid */
171: continue;
172: case 1: case 3: /* resident */
173: case 2: /* indirect */
174: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
175: /* use the next entry */
176: n_pages_used++;
177:
178: page_info[n_pages_used].match = page_des;
179: page_info[n_pages_used].n_pages = 1;
180: page_info[n_pages_used].start_idx = page_idx;
181: page_info[n_pages_used].log = page_log;
182: } else {
183: page_info[n_pages_used].n_pages++;
184: }
185: break;
186: }
187: }
188:
189: if (n_pages_used == -1)
190: continue;
191:
1.1.1.4 ! root 192: write_log(_T(" PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
1.1.1.2 root 193: ptr_des & 8 ? 1 : 0,
194: ptr_des & 4 ? 1 : 0,
195: ptr_des & 3
196: );
197:
198:
199: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
200: page_des = page_info[page_idx].match;
201:
202: if ((page_des & MMU_PDT_MASK) == 2) {
1.1.1.4 ! root 203: write_log(_T(" PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
1.1.1.2 root 204: page_info[page_idx].start_idx,
205: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
206: page_info[page_idx].log,
207: page_des & MMU_PAGE_INDIRECT_MASK
208: );
209:
210: } else {
1.1.1.4 ! root 211: write_log(_T(" PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n",
1.1.1.2 root 212: page_info[page_idx].start_idx,
213: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
214: page_info[page_idx].log,
1.1.1.4 ! root 215: page_des & (mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
! 216: (page_des & (mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
1.1.1.2 root 217: page_des & MMU_DES_GLOBAL ? 1 : 0,
218: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
219: page_des & MMU_DES_SUPER ? 1 : 0,
220: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
221: page_des & MMU_DES_MODIFIED ? 1 : 0,
222: page_des & MMU_DES_USED ? 1 : 0,
223: page_des & MMU_DES_WP ? 1 : 0
224: );
225: }
226: }
227: }
228:
229: }
230: }
231: /* }}} */
232: #endif
233:
234: /* {{{ mmu_dump_atc */
235: void mmu_dump_atc(void)
236: {
237:
238: }
239: /* }}} */
240:
241: /* {{{ mmu_dump_tables */
242: void mmu_dump_tables(void)
243: {
1.1.1.4 ! root 244: write_log(_T("URP: %08x SRP: %08x MMUSR: %x TC: %x\n"), regs.urp, regs.srp, regs.mmusr, regs.tcr);
! 245: mmu_dump_ttr(_T("DTT0"), regs.dtt0);
! 246: mmu_dump_ttr(_T("DTT1"), regs.dtt1);
! 247: mmu_dump_ttr(_T("ITT0"), regs.itt0);
! 248: mmu_dump_ttr(_T("ITT1"), regs.itt1);
1.1.1.2 root 249: mmu_dump_atc();
1.1.1.4 ! root 250: #if MMUDEBUG
1.1.1.2 root 251: // mmu_dump_table("SRP", regs.srp);
252: #endif
253: }
254: /* }}} */
255:
1.1.1.4 ! root 256: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write, uae_u32 *status);
1.1.1.2 root 257:
258: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
259: {
260: return (super ? 4 : 0) | (data ? 1 : 2);
261: }
262:
1.1.1.4 ! root 263: void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu)
1.1.1.2 root 264: {
1.1.1.4 ! root 265: if (currprefs.mmu_model == 68040) {
! 266: uae_u16 ssw = 0;
1.1.1.2 root 267:
1.1.1.4 ! root 268: if (ismoves) {
! 269: // MOVES special behavior
! 270: int fc2 = write ? regs.dfc : regs.sfc;
! 271: if (fc2 == 0 || fc2 == 3 || fc2 == 4 || fc2 == 7)
! 272: ssw |= MMU_SSW_TT1;
! 273: if ((fc2 & 3) != 3)
! 274: fc2 &= ~2;
! 275: #if MMUDEBUGMISC > 0
! 276: write_log (_T("040 MMU MOVES fc=%d -> %d\n"), fc, fc2);
! 277: #endif
! 278: fc = fc2;
! 279: }
! 280:
! 281: ssw |= fc & MMU_SSW_TM; /* TM = FC */
! 282: switch (size) {
! 283: case sz_byte:
! 284: ssw |= MMU_SSW_SIZE_B;
! 285: break;
! 286: case sz_word:
! 287: ssw |= MMU_SSW_SIZE_W;
! 288: break;
! 289: case sz_long:
! 290: ssw |= MMU_SSW_SIZE_L;
! 291: break;
! 292: }
! 293:
! 294: regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
! 295: regs.wb2_status = 0;
! 296: if (!write)
! 297: ssw |= MMU_SSW_RW;
! 298:
! 299: if (size == 16) { // MOVE16
! 300: ssw |= MMU_SSW_SIZE_CL;
! 301: ssw |= MMU_SSW_TT0;
! 302: regs.mmu_effective_addr &= ~15;
! 303: if (write) {
! 304: // clear normal writeback if MOVE16 write
! 305: regs.wb3_status &= ~0x80;
! 306: // wb2 = cacheline size writeback
! 307: regs.wb2_status = 0x80 | MMU_SSW_SIZE_CL | (ssw & 0x1f);
! 308: regs.wb2_address = regs.mmu_effective_addr;
! 309: write_log (_T("040 MMU MOVE16 WRITE FAULT!\n"));
! 310: }
! 311: }
1.1.1.2 root 312:
1.1.1.4 ! root 313: if (mmu040_movem) {
! 314: ssw |= MMU_SSW_CM;
! 315: regs.mmu_effective_addr = mmu040_movem_ea;
! 316: mmu040_movem = 0;
! 317: #if MMUDEBUGMISC > 0
! 318: write_log (_T("040 MMU_SSW_CM EA=%08X\n"), mmu040_movem_ea);
! 319: #endif
! 320: }
! 321: if (locked_rmw_cycle) {
! 322: ssw |= MMU_SSW_LK;
! 323: ssw &= ~MMU_SSW_RW;
! 324: locked_rmw_cycle = false;
! 325: #if MMUDEBUGMISC > 0
! 326: write_log (_T("040 MMU_SSW_LK!\n"));
! 327: #endif
! 328: }
! 329:
! 330: if (!nonmmu)
! 331: ssw |= MMU_SSW_ATC;
! 332: regs.mmu_ssw = ssw;
1.1.1.2 root 333:
1.1.1.4 ! root 334: #if MMUDEBUG > 0
! 335: 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);
! 336: #endif
! 337: } else {
! 338: uae_u32 fslw = 0;
! 339:
! 340: fslw |= write ? MMU_FSLW_W : MMU_FSLW_R;
! 341: fslw |= fc << 16; /* MMU_FSLW_TM */
1.1.1.2 root 342:
1.1.1.4 ! root 343: switch (size) {
! 344: case sz_byte:
! 345: fslw |= MMU_FSLW_SIZE_B;
! 346: break;
! 347: case sz_word:
! 348: fslw |= MMU_FSLW_SIZE_W;
! 349: break;
! 350: case sz_long:
! 351: fslw |= MMU_FSLW_SIZE_L;
! 352: break;
! 353: case 16: // MOVE16
! 354: addr &= ~15;
! 355: fslw |= MMU_FSLW_SIZE_D;
! 356: fslw |= MMU_FSLW_TT_16;
! 357: break;
! 358: }
! 359: if ((fc & 3) == 2) {
! 360: // instruction faults always point to opcode address
! 361: #if MMUDEBUGMISC > 0
! 362: write_log(_T("INS FAULT %08x %08x %d\n"), addr, regs.instruction_pc, mmu060_state);
! 363: #endif
! 364: addr = regs.instruction_pc;
! 365: if (mmu060_state == 0) {
! 366: fslw |= MMU_FSLW_IO; // opword fetch
! 367: } else {
! 368: fslw |= MMU_FSLW_IO | MMU_FSLW_MA; // extension word
! 369: }
! 370: }
! 371: if (rmw) {
! 372: fslw |= MMU_FSLW_W | MMU_FSLW_R;
! 373: }
! 374: if (locked_rmw_cycle) {
! 375: fslw |= MMU_FSLW_LK;
! 376: locked_rmw_cycle = false;
! 377: write_log (_T("060 MMU_FSLW_LK!\n"));
! 378: }
! 379: fslw |= status;
! 380: regs.mmu_fslw = fslw;
1.1.1.2 root 381:
1.1.1.4 ! root 382: #if MMUDEBUG > 0
! 383: 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, m68k_getpc(), mmu_opcode);
! 384: #endif
! 385:
! 386: }
! 387:
! 388: regs.mmu_fault_addr = addr;
! 389:
! 390: #if 0
! 391: if (m68k_getpc () == 0x0004B0AC) {
! 392: write_log (_T("*"));
! 393: #if 0
! 394: extern void activate_debugger(void);
! 395: activate_debugger ();
! 396: #endif
! 397: }
! 398: #endif
1.1.1.2 root 399: THROW(2);
400: }
401:
1.1.1.4 ! root 402: void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw)
! 403: {
! 404: uae_u32 status = 0;
! 405:
! 406: if (currprefs.mmu_model == 68060) {
! 407: status |= MMU_FSLW_TTR;
! 408: }
! 409: regs.wb3_data = val;
! 410: mmu_bus_error(addr, mmu_get_fc (super, data), true, size, false, status, false);
! 411: }
! 412:
! 413:
1.1.1.2 root 414: /*
415: * Update the atc line for a given address by doing a mmu lookup.
416: */
1.1.1.4 ! root 417: static uaecptr mmu_fill_atc(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l, uae_u32 *status)
1.1.1.2 root 418: {
419: uae_u32 desc;
420:
1.1.1.4 ! root 421: *status = 0;
1.1.1.2 root 422: SAVE_EXCEPTION;
423: TRY(prb) {
1.1.1.4 ! root 424: desc = mmu_lookup_pagetable(addr, super, write, status);
! 425: #if MMUDEBUG > 2
! 426: write_log(_T("translate: %x,%u,%u,%u -> %x\n"), addr, super, write, data, desc);
1.1.1.2 root 427: #endif
428: RESTORE_EXCEPTION;
429: }
430: CATCH(prb) {
431: RESTORE_EXCEPTION;
432: /* bus error during table search */
433: desc = 0;
1.1.1.4 ! root 434: *status = MMU_FSLW_TWE;
1.1.1.2 root 435: // goto fail;
436: } ENDTRY
1.1.1.4 ! root 437: if ((desc & 1) && (!super && desc & MMU_MMUSR_S)) {
! 438: *status |= MMU_FSLW_SP;
! 439: #if MMUDEBUG > 1
! 440: write_log (_T("MMU: supervisor protected %x\n"), addr);
! 441: #endif
! 442: l->valid = 0;
! 443: l->global = 0;
! 444: } else if ((desc & 1) == 0) {
1.1.1.2 root 445: l->valid = 0;
446: l->global = 0;
447: } else {
448: l->valid = 1;
1.1.1.4 ! root 449: l->phys = desc & mmu_pagemaski;
1.1.1.2 root 450: l->global = (desc & MMU_MMUSR_G) != 0;
451: l->modified = (desc & MMU_MMUSR_M) != 0;
452: l->write_protect = (desc & MMU_MMUSR_W) != 0;
453: }
454:
455: return desc;
456: }
457:
1.1.1.4 ! root 458: static ALWAYS_INLINE bool mmu_fill_atc_try(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1, uae_u32 *status)
1.1.1.2 root 459: {
1.1.1.4 ! root 460: mmu_fill_atc(addr,super,data,write,l1, status);
1.1.1.2 root 461: if (!(l1->valid)) {
1.1.1.4 ! root 462: #if MMUDEBUG > 2
! 463: write_log(_T("MMU: non-resident page (%x,%x)!\n"), addr, regs.pc);
! 464: #endif
1.1.1.2 root 465: goto fail;
466: }
467: if (write) {
468: if (l1->write_protect) {
1.1.1.4 ! root 469: *status |= MMU_FSLW_WP;
! 470: #if MMUDEBUG > 0
! 471: write_log(_T("MMU: write protected %lx by atc \n"), addr);
! 472: #endif
1.1.1.2 root 473: mmu_dump_atc();
474: goto fail;
475: }
476:
477: }
478: return true;
479:
480: fail:
481: return false;
482: }
483:
484: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
485: {
486: struct mmu_atc_line *l;
1.1.1.4 ! root 487: uae_u32 status = 0;
! 488:
1.1.1.2 root 489: // this should return a miss but choose a valid line
490: mmu_user_lookup(addr, super, data, write, &l);
491:
1.1.1.4 ! root 492: mmu_fill_atc(addr, super, data, write, l, &status);
! 493: if (!l->valid || (write && l->write_protect)) {
! 494: #if MMUDEBUG > 2
! 495: write_log(_T("[MMU] mmu_translate error"));
! 496: #endif
! 497: mmu_bus_error(addr, mmu_get_fc(super, data), write, 0, false, status, false);
! 498: return 0;
1.1.1.2 root 499: }
500:
1.1.1.4 ! root 501: return l->phys | (addr & mmu_pagemask);
1.1.1.2 root 502:
503: }
504:
505: /*
506: * Lookup the address by walking the page table and updating
507: * the page descriptors accordingly. Returns the found descriptor
508: * or produces a bus error.
509: */
1.1.1.4 ! root 510: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write, uae_u32 *status)
1.1.1.2 root 511: {
512: uae_u32 desc, desc_addr, wp;
513: int i;
514:
515: wp = 0;
516: desc = super ? regs.srp : regs.urp;
517:
518: /* fetch root table descriptor */
519: i = (addr >> 23) & 0x1fc;
520: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
521: desc = phys_get_long(desc_addr);
522: if ((desc & 2) == 0) {
1.1.1.4 ! root 523: #if MMUDEBUG > 1
! 524: write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
! 525: addr, desc_addr, desc);
! 526: #endif
! 527: *status |= MMU_FSLW_PTA;
1.1.1.2 root 528: return 0;
529: }
530:
531: wp |= desc;
532: if ((desc & MMU_DES_USED) == 0)
533: phys_put_long(desc_addr, desc | MMU_DES_USED);
534:
535: /* fetch pointer table descriptor */
536: i = (addr >> 16) & 0x1fc;
537: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
538: desc = phys_get_long(desc_addr);
539: if ((desc & 2) == 0) {
1.1.1.4 ! root 540: #if MMUDEBUG > 1
! 541: write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
! 542: addr, desc_addr, desc);
! 543: #endif
! 544: *status |= MMU_FSLW_PTB;
1.1.1.2 root 545: return 0;
546: }
547: wp |= desc;
548: if ((desc & MMU_DES_USED) == 0)
549: phys_put_long(desc_addr, desc | MMU_DES_USED);
550:
551: /* fetch page table descriptor */
1.1.1.4 ! root 552: if (mmu_pagesize_8k) {
1.1.1.2 root 553: i = (addr >> 11) & 0x7c;
554: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
555: } else {
556: i = (addr >> 10) & 0xfc;
557: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
558: }
559:
560: desc = phys_get_long(desc_addr);
561: if ((desc & 3) == 2) {
562: /* indirect */
563: desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
564: desc = phys_get_long(desc_addr);
565: }
566: if ((desc & 1) == 0) {
1.1.1.4 ! root 567: #if MMUDEBUG > 2
! 568: write_log(_T("MMU: invalid page descriptor log=%0lx desc=%08x @%08x\n"), addr, desc, desc_addr);
! 569: #endif
! 570: if ((desc & 3) == 2) {
! 571: *status |= MMU_FSLW_IL;
! 572: #if MMUDEBUG > 1
! 573: write_log(_T("MMU: double indirect descriptor log=%0lx desc=%08x @%08x\n"), addr, desc, desc_addr);
! 574: #endif
! 575: } else {
! 576: *status |= MMU_FSLW_PF;
! 577: }
1.1.1.2 root 578: return desc;
579: }
580:
581: desc |= wp & MMU_DES_WP;
582: if (write) {
583: if (desc & MMU_DES_WP) {
584: if ((desc & MMU_DES_USED) == 0) {
585: desc |= MMU_DES_USED;
586: phys_put_long(desc_addr, desc);
587: }
588: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
589: (MMU_DES_USED|MMU_DES_MODIFIED)) {
590: desc |= MMU_DES_USED|MMU_DES_MODIFIED;
591: phys_put_long(desc_addr, desc);
592: }
593: } else {
594: if ((desc & MMU_DES_USED) == 0) {
595: desc |= MMU_DES_USED;
596: phys_put_long(desc_addr, desc);
597: }
598: }
599: return desc;
600: }
601:
1.1.1.4 ! root 602: static void misalignednotfirst(uaecptr addr)
! 603: {
! 604: #if MMUDEBUGMISC > 0
! 605: write_log (_T("misalignednotfirst %08x -> %08x %08X\n"), regs.mmu_fault_addr, addr, regs.instruction_pc);
! 606: #endif
! 607: regs.mmu_fault_addr = addr;
! 608: regs.mmu_fslw |= MMU_FSLW_MA;
! 609: regs.mmu_ssw |= MMU_SSW_MA;
! 610: }
! 611:
! 612: static void misalignednotfirstcheck(uaecptr addr)
! 613: {
! 614: if (regs.mmu_fault_addr == addr)
! 615: return;
! 616: misalignednotfirst (addr);
! 617: }
! 618:
! 619: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data, bool rmw)
1.1.1.2 root 620: {
621: uae_u16 res;
622:
1.1.1.4 ! root 623: res = (uae_u16)mmu_get_byte(addr, data, sz_word, rmw) << 8;
1.1.1.2 root 624: SAVE_EXCEPTION;
625: TRY(prb) {
1.1.1.4 ! root 626: res |= mmu_get_byte(addr + 1, data, sz_word, rmw);
1.1.1.2 root 627: RESTORE_EXCEPTION;
628: }
629: CATCH(prb) {
630: RESTORE_EXCEPTION;
1.1.1.4 ! root 631: misalignednotfirst(addr);
1.1.1.2 root 632: THROW_AGAIN(prb);
633: } ENDTRY
634: return res;
635: }
636:
1.1.1.4 ! root 637: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data, bool rmw)
1.1.1.2 root 638: {
639: uae_u32 res;
640:
641: if (likely(!(addr & 1))) {
1.1.1.4 ! root 642: res = (uae_u32)mmu_get_word(addr, data, sz_long, rmw) << 16;
1.1.1.2 root 643: SAVE_EXCEPTION;
644: TRY(prb) {
1.1.1.4 ! root 645: res |= mmu_get_word(addr + 2, data, sz_long, rmw);
1.1.1.2 root 646: RESTORE_EXCEPTION;
647: }
648: CATCH(prb) {
649: RESTORE_EXCEPTION;
1.1.1.4 ! root 650: misalignednotfirst(addr);
1.1.1.2 root 651: THROW_AGAIN(prb);
652: } ENDTRY
653: } else {
1.1.1.4 ! root 654: res = (uae_u32)mmu_get_byte(addr, data, sz_long, rmw) << 8;
1.1.1.2 root 655: SAVE_EXCEPTION;
656: TRY(prb) {
1.1.1.4 ! root 657: res = (res | mmu_get_byte(addr + 1, data, sz_long, rmw)) << 8;
! 658: res = (res | mmu_get_byte(addr + 2, data, sz_long, rmw)) << 8;
! 659: res |= mmu_get_byte(addr + 3, data, sz_long, rmw);
1.1.1.2 root 660: RESTORE_EXCEPTION;
661: }
662: CATCH(prb) {
663: RESTORE_EXCEPTION;
1.1.1.4 ! root 664: misalignednotfirst(addr);
1.1.1.2 root 665: THROW_AGAIN(prb);
666: } ENDTRY
667: }
668: return res;
669: }
670:
1.1.1.4 ! root 671: uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
! 672: {
! 673: uae_u16 res;
! 674:
! 675: res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_word) << 8;
! 676: SAVE_EXCEPTION;
! 677: TRY(prb) {
! 678: res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_word);
! 679: RESTORE_EXCEPTION;
! 680: }
! 681: CATCH(prb) {
! 682: RESTORE_EXCEPTION;
! 683: misalignednotfirst(addr);
! 684: THROW_AGAIN(prb);
! 685: } ENDTRY
! 686: return res;
! 687: }
! 688:
! 689: uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
! 690: {
! 691: uae_u32 res;
! 692:
! 693: if (likely(!(addr & 1))) {
! 694: res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, true, sz_long) << 16;
! 695: SAVE_EXCEPTION;
! 696: TRY(prb) {
! 697: res |= mmu_get_user_word(addr + 2, regs.s != 0, true, true, sz_long);
! 698: RESTORE_EXCEPTION;
! 699: }
! 700: CATCH(prb) {
! 701: RESTORE_EXCEPTION;
! 702: misalignednotfirst(addr);
! 703: THROW_AGAIN(prb);
! 704: } ENDTRY
! 705: } else {
! 706: res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_long) << 8;
! 707: SAVE_EXCEPTION;
! 708: TRY(prb) {
! 709: res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_long)) << 8;
! 710: res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, true, sz_long)) << 8;
! 711: res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, true, sz_long);
! 712: RESTORE_EXCEPTION;
! 713: }
! 714: CATCH(prb) {
! 715: RESTORE_EXCEPTION;
! 716: misalignednotfirst(addr);
! 717: THROW_AGAIN(prb);
! 718: } ENDTRY
! 719: }
! 720: return res;
! 721: }
1.1.1.2 root 722: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root 723: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 724: {
1.1.1.4 ! root 725: uae_u32 status;
! 726: if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
! 727: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2 root 728: return 0;
729: }
730: return phys_get_byte(mmu_get_real_address(addr, cl));
731: }
732:
733: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root 734: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 735: {
1.1.1.4 ! root 736: uae_u32 status;
! 737: if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
! 738: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2 root 739: return 0;
740: }
741: return phys_get_word(mmu_get_real_address(addr, cl));
742: }
743:
744: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root 745: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 746: {
1.1.1.4 ! root 747: uae_u32 status;
! 748: if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
! 749: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2 root 750: return 0;
751: }
752: return phys_get_long(mmu_get_real_address(addr, cl));
753: }
754:
1.1.1.4 ! root 755: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw)
1.1.1.2 root 756: {
757: SAVE_EXCEPTION;
758: TRY(prb) {
759: if (likely(!(addr & 1))) {
1.1.1.4 ! root 760: mmu_put_word(addr, val >> 16, data, sz_long, rmw);
! 761: mmu_put_word(addr + 2, val, data, sz_long, rmw);
1.1.1.2 root 762: } else {
1.1.1.4 ! root 763: mmu_put_byte(addr, val >> 24, data, sz_long, rmw);
! 764: mmu_put_byte(addr + 1, val >> 16, data, sz_long, rmw);
! 765: mmu_put_byte(addr + 2, val >> 8, data, sz_long, rmw);
! 766: mmu_put_byte(addr + 3, val, data, sz_long, rmw);
1.1.1.2 root 767: }
768: RESTORE_EXCEPTION;
769: }
770: CATCH(prb) {
771: RESTORE_EXCEPTION;
772: regs.wb3_data = val;
1.1.1.4 ! root 773: misalignednotfirstcheck(addr);
1.1.1.2 root 774: THROW_AGAIN(prb);
775: } ENDTRY
776: }
777:
1.1.1.4 ! root 778: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data, bool rmw)
1.1.1.2 root 779: {
780: SAVE_EXCEPTION;
781: TRY(prb) {
1.1.1.4 ! root 782: mmu_put_byte(addr, val >> 8, data, sz_word, rmw);
! 783: mmu_put_byte(addr + 1, val, data, sz_word, rmw);
1.1.1.2 root 784: RESTORE_EXCEPTION;
785: }
786: CATCH(prb) {
787: RESTORE_EXCEPTION;
788: regs.wb3_data = val;
1.1.1.4 ! root 789: misalignednotfirstcheck(addr);
1.1.1.2 root 790: THROW_AGAIN(prb);
791: } ENDTRY
792: }
793:
794: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
1.1.1.4 ! root 795: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 796: {
1.1.1.4 ! root 797: uae_u32 status;
! 798: if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2 root 799: regs.wb3_data = val;
1.1.1.4 ! root 800: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2 root 801: return;
802: }
803: phys_put_byte(mmu_get_real_address(addr, cl), val);
804: }
805:
806: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
1.1.1.4 ! root 807: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 808: {
1.1.1.4 ! root 809: uae_u32 status;
! 810: if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2 root 811: regs.wb3_data = val;
1.1.1.4 ! root 812: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2 root 813: return;
814: }
815: phys_put_word(mmu_get_real_address(addr, cl), val);
816: }
817:
818: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
1.1.1.4 ! root 819: int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2 root 820: {
1.1.1.4 ! root 821: uae_u32 status;
! 822: if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2 root 823: regs.wb3_data = val;
1.1.1.4 ! root 824: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2 root 825: return;
826: }
827: phys_put_long(mmu_get_real_address(addr, cl), val);
828: }
829:
830: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
831: {
832: bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root 833: bool data = true;
1.1.1.2 root 834: uae_u32 res;
835:
1.1.1.4 ! root 836: ismoves = true;
! 837: if (likely(!is_unaligned(addr, 4))) {
! 838: res = mmu_get_user_long(addr, super, data, false, sz_long);
1.1.1.2 root 839: } else {
1.1.1.4 ! root 840: if (likely(!(addr & 1))) {
! 841: res = (uae_u32)mmu_get_user_word(addr, super, data, false, sz_long) << 16;
! 842: SAVE_EXCEPTION;
! 843: TRY(prb) {
! 844: res |= mmu_get_user_word(addr + 2, super, data, false, sz_long);
! 845: RESTORE_EXCEPTION;
! 846: }
! 847: CATCH(prb) {
! 848: RESTORE_EXCEPTION;
! 849: misalignednotfirst(addr);
! 850: THROW_AGAIN(prb);
! 851: } ENDTRY
! 852: } else {
! 853: res = (uae_u32)mmu_get_user_byte(addr, super, data, false, sz_long) << 8;
! 854: SAVE_EXCEPTION;
! 855: TRY(prb) {
! 856: res = (res | mmu_get_user_byte(addr + 1, super, data, false, sz_long)) << 8;
! 857: res = (res | mmu_get_user_byte(addr + 2, super, data, false, sz_long)) << 8;
! 858: res |= mmu_get_user_byte(addr + 3, super, data, false, sz_long);
! 859: RESTORE_EXCEPTION;
! 860: }
! 861: CATCH(prb) {
! 862: RESTORE_EXCEPTION;
! 863: misalignednotfirst(addr);
! 864: THROW_AGAIN(prb);
! 865: } ENDTRY
1.1.1.2 root 866: }
867: }
1.1.1.4 ! root 868:
! 869: ismoves = false;
1.1.1.2 root 870: return res;
871: }
872:
873: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
874: {
875: bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root 876: bool data = true;
1.1.1.2 root 877: uae_u16 res;
878:
1.1.1.4 ! root 879: ismoves = true;
! 880: if (likely(!is_unaligned(addr, 2))) {
! 881: res = mmu_get_user_word(addr, super, data, false, sz_word);
! 882: } else {
! 883: res = (uae_u16)mmu_get_user_byte(addr, super, data, false, sz_word) << 8;
! 884: SAVE_EXCEPTION;
! 885: TRY(prb) {
! 886: res |= mmu_get_user_byte(addr + 1, super, data, false, sz_word);
! 887: RESTORE_EXCEPTION;
! 888: }
! 889: CATCH(prb) {
! 890: RESTORE_EXCEPTION;
! 891: misalignednotfirst(addr);
! 892: THROW_AGAIN(prb);
! 893: } ENDTRY
1.1.1.2 root 894: }
1.1.1.4 ! root 895: ismoves = false;
1.1.1.2 root 896: return res;
897: }
898:
899: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
900: {
901: bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root 902: bool data = true;
! 903: uae_u8 res;
! 904:
! 905: ismoves = true;
! 906: res = mmu_get_user_byte(addr, super, data, false, sz_byte);
! 907: ismoves = false;
! 908: return res;
1.1.1.2 root 909: }
910:
911: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
912: {
913: bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root 914: bool data = true;
1.1.1.2 root 915:
1.1.1.4 ! root 916: ismoves = true;
1.1.1.2 root 917: SAVE_EXCEPTION;
918: TRY(prb) {
919: if (likely(!is_unaligned(addr, 4)))
920: mmu_put_user_long(addr, val, super, data, sz_long);
921: else if (likely(!(addr & 1))) {
922: mmu_put_user_word(addr, val >> 16, super, data, sz_long);
923: mmu_put_user_word(addr + 2, val, super, data, sz_long);
924: } else {
925: mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
926: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
927: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
928: mmu_put_user_byte(addr + 3, val, super, data, sz_long);
929: }
930: RESTORE_EXCEPTION;
931: }
932: CATCH(prb) {
933: RESTORE_EXCEPTION;
934: regs.wb3_data = val;
1.1.1.4 ! root 935: misalignednotfirstcheck(addr);
1.1.1.2 root 936: THROW_AGAIN(prb);
937: } ENDTRY
1.1.1.4 ! root 938: ismoves = false;
1.1.1.2 root 939: }
940:
941: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
942: {
943: bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root 944: bool data = true;
1.1.1.2 root 945:
1.1.1.4 ! root 946: ismoves = true;
1.1.1.2 root 947: SAVE_EXCEPTION;
948: TRY(prb) {
949: if (likely(!is_unaligned(addr, 2)))
950: mmu_put_user_word(addr, val, super, data, sz_word);
951: else {
952: mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
953: mmu_put_user_byte(addr + 1, val, super, data, sz_word);
954: }
955: RESTORE_EXCEPTION;
956: }
957: CATCH(prb) {
958: RESTORE_EXCEPTION;
959: regs.wb3_data = val;
1.1.1.4 ! root 960: misalignednotfirstcheck(addr);
1.1.1.2 root 961: THROW_AGAIN(prb);
962: } ENDTRY
1.1.1.4 ! root 963: ismoves = false;
1.1.1.2 root 964: }
965:
966: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
967: {
968: bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root 969: bool data = true;
1.1.1.2 root 970:
1.1.1.4 ! root 971: ismoves = true;
1.1.1.2 root 972: SAVE_EXCEPTION;
973: TRY(prb) {
974: mmu_put_user_byte(addr, val, super, data, sz_byte);
975: RESTORE_EXCEPTION;
976: }
977: CATCH(prb) {
978: RESTORE_EXCEPTION;
979: regs.wb3_data = val;
980: THROW_AGAIN(prb);
981: } ENDTRY
1.1.1.4 ! root 982: ismoves = false;
1.1.1.2 root 983: }
984:
1.1.1.4 ! root 985: void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size)
! 986: {
! 987: struct mmu_atc_line *cl;
! 988: addr &= ~15;
! 989: for (int i = 0; i < 4; i++) {
! 990: uaecptr addr2 = addr + i * 4;
! 991: // addr,super,data
! 992: if ((!regs.mmu_enabled) || (mmu_match_ttr(addr2,regs.s != 0,data,false)!=TTR_NO_MATCH))
! 993: v[i] = phys_get_long(addr2);
! 994: else if (likely(mmu_lookup(addr2, data, false, &cl)))
! 995: v[i] = phys_get_long(mmu_get_real_address(addr2, cl));
! 996: else
! 997: v[i] = mmu_get_long_slow(addr2, regs.s != 0, data, size, false, cl);
! 998: }
! 999: }
! 1000:
! 1001: void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size)
! 1002: {
! 1003: struct mmu_atc_line *cl;
! 1004: addr &= ~15;
! 1005: for (int i = 0; i < 4; i++) {
! 1006: uaecptr addr2 = addr + i * 4;
! 1007: // addr,super,data
! 1008: if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr2,regs.s != 0,data,val[i],size,false)==TTR_OK_MATCH))
! 1009: phys_put_long(addr2,val[i]);
! 1010: else if (likely(mmu_lookup(addr2, data, true, &cl)))
! 1011: phys_put_long(mmu_get_real_address(addr2, cl), val[i]);
! 1012: else
! 1013: mmu_put_long_slow(addr2, val[i], regs.s != 0, data, size, false, cl);
! 1014: }
! 1015: }
! 1016:
! 1017:
1.1.1.2 root 1018: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
1019: {
1020: bool super = (regs.dfc & 4) != 0;
1021: DUNUSED(extra);
1.1.1.4 ! root 1022: if ((opcode & 0xFE0) == 0x0500) { // PFLUSH
1.1.1.2 root 1023: bool glob;
1024: int regno;
1025: //D(didflush = 0);
1026: uae_u32 addr;
1027: /* PFLUSH */
1028: regno = opcode & 7;
1029: glob = (opcode & 8) != 0;
1030:
1031: if (opcode & 16) {
1.1.1.4 ! root 1032: #if MMUINSDEBUG > 1
! 1033: write_log(_T("pflusha(%u,%u) PC=%08x\n"), glob, regs.dfc, m68k_getpc ());
! 1034: #endif
1.1.1.2 root 1035: mmu_flush_atc_all(glob);
1036: } else {
1037: addr = m68k_areg(regs, regno);
1.1.1.4 ! root 1038: #if MMUINSDEBUG > 1
! 1039: write_log(_T("pflush(%u,%u,%x) PC=%08x\n"), glob, regs.dfc, addr, m68k_getpc ());
! 1040: #endif
1.1.1.2 root 1041: mmu_flush_atc(addr, super, glob);
1042: }
1043: flush_internals();
1044: #ifdef USE_JIT
1045: flush_icache(0);
1046: #endif
1.1.1.4 ! root 1047: } else if ((opcode & 0x0FD8) == 0x0548) { // PTEST (68040)
1.1.1.2 root 1048: bool write;
1049: int regno;
1050: uae_u32 addr;
1051:
1052: regno = opcode & 7;
1053: write = (opcode & 32) == 0;
1054: addr = m68k_areg(regs, regno);
1.1.1.4 ! root 1055: #if MMUINSDEBUG > 0
! 1056: write_log(_T("PTEST%c (A%d) %08x DFC=%d\n"), write ? 'W' : 'R', regno, addr, regs.dfc);
! 1057: #endif
1.1.1.2 root 1058: mmu_flush_atc(addr, super, true);
1059: SAVE_EXCEPTION;
1060: TRY(prb) {
1061: struct mmu_atc_line *l;
1062: uae_u32 desc;
1063: bool data = (regs.dfc & 3) != 2;
1064:
1.1.1.4 ! root 1065: if (mmu_match_ttr(addr,super,data, false)!=TTR_NO_MATCH) {
1.1.1.2 root 1066: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
1.1.1.4 ! root 1067: } else {
! 1068: uae_u32 status;
1.1.1.2 root 1069: mmu_user_lookup(addr, super, data, write, &l);
1.1.1.4 ! root 1070: desc = mmu_fill_atc(addr, super, data, write, l, &status);
! 1071: if (!(l->valid)) {
1.1.1.2 root 1072: regs.mmusr = MMU_MMUSR_B;
1.1.1.4 ! root 1073: } else {
1.1.1.2 root 1074: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
1075: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
1076: regs.mmusr |= MMU_MMUSR_R;
1077: }
1078: }
1079: }
1080: CATCH(prb) {
1081: regs.mmusr = MMU_MMUSR_B;
1082: } ENDTRY
1083: RESTORE_EXCEPTION;
1.1.1.4 ! root 1084: #if MMUINSDEBUG > 0
! 1085: write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
! 1086: #endif
! 1087: } else if ((opcode & 0xFFB8) == 0xF588) { // PLPA (68060)
! 1088: int write = (opcode & 0x40) == 0;
! 1089: int regno = opcode & 7;
! 1090: uae_u32 addr = m68k_areg (regs, regno);
! 1091: bool data = (regs.dfc & 3) != 2;
! 1092:
! 1093: #if MMUINSDEBUG > 0
! 1094: write_log(_T("PLPA%c param: %08x\n"), write ? 'W' : 'R', addr);
! 1095: #endif
! 1096: if (mmu_match_ttr(addr,super,data,false)==TTR_NO_MATCH) {
! 1097: m68k_areg (regs, regno) = mmu_translate (addr, super, data, write != 0);
! 1098: }
! 1099: #if MMUINSDEBUG > 0
! 1100: write_log(_T("PLPA%c result: %08x\n"), write ? 'W' : 'R', m68k_areg (regs, regno));
! 1101: #endif
! 1102: } else {
1.1.1.2 root 1103: op_illg (opcode);
1.1.1.4 ! root 1104: }
1.1.1.2 root 1105: }
1106:
1107: // fixme : global parameter?
1108: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
1109: {
1110: int way,type,index;
1111:
1.1.1.4 ! root 1112: uaecptr tag = ((super ? 0x80000000 : 0) | (addr >> 1)) & mmu_tagmask;
! 1113: if (mmu_pagesize_8k)
1.1.1.2 root 1114: index=(addr & 0x0001E000)>>13;
1115: else
1116: index=(addr & 0x0000F000)>>12;
1.1.1.4 ! root 1117: for (type=0;type<ATC_TYPE;type++) {
! 1118: for (way=0;way<ATC_WAYS;way++) {
! 1119: if (!global && mmu_atc_array[type][way][index].global)
! 1120: continue;
! 1121: // if we have this
! 1122: if ((tag == mmu_atc_array[type][way][index].tag) && (mmu_atc_array[type][way][index].valid)) {
! 1123: mmu_atc_array[type][way][index].valid=false;
! 1124: }
1.1.1.2 root 1125: }
1126: }
1127: }
1128:
1129: void REGPARAM2 mmu_flush_atc_all(bool global)
1130: {
1131: unsigned int way,slot,type;
1.1.1.4 ! root 1132: for (type=0;type<ATC_TYPE;type++) {
! 1133: for (way=0;way<ATC_WAYS;way++) {
! 1134: for (slot=0;slot<ATC_SLOTS;slot++) {
! 1135: if (!global && mmu_atc_array[type][way][slot].global)
! 1136: continue;
! 1137: mmu_atc_array[type][way][slot].valid=false;
! 1138: }
! 1139: }
1.1.1.2 root 1140: }
1141: }
1142:
1143: void REGPARAM2 mmu_reset(void)
1144: {
1145: mmu_flush_atc_all(true);
1146: }
1147:
1148:
1149: void REGPARAM2 mmu_set_tc(uae_u16 tc)
1150: {
1.1.1.4 ! root 1151: regs.mmu_enabled = (tc & 0x8000) != 0;
! 1152: mmu_pagesize_8k = (tc & 0x4000) != 0;
! 1153: mmu_tagmask = mmu_pagesize_8k ? 0xFFFF0000 : 0xFFFF8000;
! 1154: mmu_pagemask = mmu_pagesize_8k ? 0x00001FFF : 0x00000FFF;
! 1155: mmu_pagemaski = ~mmu_pagemask;
! 1156: regs.mmu_page_size = mmu_pagesize_8k ? 8192 : 4096;
! 1157:
1.1.1.2 root 1158: mmu_flush_atc_all(true);
1159:
1.1.1.4 ! root 1160: write_log(_T("%d MMU: enabled=%d page8k=%d\n"), currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k);
1.1.1.2 root 1161: }
1162:
1163: void REGPARAM2 mmu_set_super(bool super)
1164: {
1.1.1.4 ! root 1165: mmu_is_super = super ? 0x80000000 : 0;
! 1166: }
! 1167:
! 1168: void m68k_do_rte_mmu040 (uaecptr a7)
! 1169: {
! 1170: uae_u16 ssr = get_word_mmu040 (a7 + 8 + 4);
! 1171: if (ssr & MMU_SSW_CT) {
! 1172: uaecptr src_a7 = a7 + 8 - 8;
! 1173: uaecptr dst_a7 = a7 + 8 + 52;
! 1174: put_word_mmu040 (dst_a7 + 0, get_word_mmu040 (src_a7 + 0));
! 1175: put_long_mmu040 (dst_a7 + 2, get_long_mmu040 (src_a7 + 2));
! 1176: // skip this word
! 1177: put_long_mmu040 (dst_a7 + 8, get_long_mmu040 (src_a7 + 8));
! 1178: }
! 1179: if (ssr & MMU_SSW_CM) {
! 1180: mmu040_movem = 1;
! 1181: mmu040_movem_ea = get_long_mmu040 (a7 + 8);
! 1182: #if MMUDEBUGMISC > 0
! 1183: write_log (_T("MMU restarted MOVEM EA=%08X\n"), mmu040_movem_ea);
! 1184: #endif
! 1185: }
! 1186: }
! 1187:
! 1188: void m68k_do_rte_mmu060 (uaecptr a7)
! 1189: {
! 1190: #if 0
! 1191: mmu060_state = 2;
! 1192: #endif
! 1193: }
! 1194:
! 1195: void flush_mmu040 (uaecptr addr, int n)
! 1196: {
! 1197: }
! 1198: void m68k_do_rts_mmu040 (void)
! 1199: {
! 1200: uaecptr stack = m68k_areg (regs, 7);
! 1201: uaecptr newpc = get_long_mmu040 (stack);
! 1202: m68k_areg (regs, 7) += 4;
! 1203: m68k_setpc (newpc);
! 1204: }
! 1205: void m68k_do_bsr_mmu040 (uaecptr oldpc, uae_s32 offset)
! 1206: {
! 1207: uaecptr newstack = m68k_areg (regs, 7) - 4;
! 1208: put_long_mmu040 (newstack, oldpc);
! 1209: m68k_areg (regs, 7) -= 4;
! 1210: m68k_incpci (offset);
1.1.1.2 root 1211: }
1212:
1.1.1.4 ! root 1213: void flush_mmu060 (uaecptr addr, int n)
! 1214: {
! 1215: }
! 1216: void m68k_do_rts_mmu060 (void)
! 1217: {
! 1218: uaecptr stack = m68k_areg (regs, 7);
! 1219: uaecptr newpc = get_long_mmu060 (stack);
! 1220: m68k_areg (regs, 7) += 4;
! 1221: m68k_setpc (newpc);
! 1222: }
! 1223: void m68k_do_bsr_mmu060 (uaecptr oldpc, uae_s32 offset)
! 1224: {
! 1225: uaecptr newstack = m68k_areg (regs, 7) - 4;
! 1226: put_long_mmu060 (newstack, oldpc);
! 1227: m68k_areg (regs, 7) -= 4;
! 1228: m68k_incpci (offset);
! 1229: }
! 1230:
! 1231: void uae_mmu_put_lrmw (uaecptr addr, uae_u32 v, int size, int type)
! 1232: {
! 1233: locked_rmw_cycle = true;
! 1234: if (size == sz_byte) {
! 1235: mmu_put_byte(addr, v, true, sz_byte, true);
! 1236: } else if (size == sz_word) {
! 1237: if (unlikely(is_unaligned(addr, 2))) {
! 1238: mmu_put_word_unaligned(addr, v, true, true);
! 1239: } else {
! 1240: mmu_put_word(addr, v, true, sz_word, true);
! 1241: }
! 1242: } else {
! 1243: if (unlikely(is_unaligned(addr, 4)))
! 1244: mmu_put_long_unaligned(addr, v, true, true);
! 1245: else
! 1246: mmu_put_long(addr, v, true, sz_long, true);
! 1247: }
! 1248: locked_rmw_cycle = false;
! 1249: }
! 1250: uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type)
! 1251: {
! 1252: uae_u32 v;
! 1253: locked_rmw_cycle = true;
! 1254: if (size == sz_byte) {
! 1255: v = mmu_get_user_byte(addr, regs.s != 0, true, true, sz_byte);
! 1256: } else if (size == sz_word) {
! 1257: if (unlikely(is_unaligned(addr, 2))) {
! 1258: v = mmu_get_lrmw_word_unaligned(addr);
! 1259: } else {
! 1260: v = mmu_get_user_word(addr, regs.s != 0, true, true, sz_word);
! 1261: }
! 1262: } else {
! 1263: if (unlikely(is_unaligned(addr, 4)))
! 1264: v = mmu_get_lrmw_long_unaligned(addr);
! 1265: else
! 1266: v = mmu_get_user_long(addr, regs.s != 0, true, true, sz_long);
! 1267: }
! 1268: locked_rmw_cycle = false;
! 1269: return v;
! 1270: }
! 1271:
! 1272: uae_u32 REGPARAM2 mmu060_get_rmw_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width)
! 1273: {
! 1274: uae_u32 tmp1, tmp2, res, mask;
! 1275:
! 1276: offset &= 7;
! 1277: mask = 0xffffffffu << (32 - width);
! 1278: switch ((offset + width + 7) >> 3) {
! 1279: case 1:
! 1280: tmp1 = get_rmw_byte_mmu060 (src);
! 1281: res = tmp1 << (24 + offset);
! 1282: bdata[0] = tmp1 & ~(mask >> (24 + offset));
! 1283: break;
! 1284: case 2:
! 1285: tmp1 = get_rmw_word_mmu060 (src);
! 1286: res = tmp1 << (16 + offset);
! 1287: bdata[0] = tmp1 & ~(mask >> (16 + offset));
! 1288: break;
! 1289: case 3:
! 1290: tmp1 = get_rmw_word_mmu060 (src);
! 1291: tmp2 = get_rmw_byte_mmu060 (src + 2);
! 1292: res = tmp1 << (16 + offset);
! 1293: bdata[0] = tmp1 & ~(mask >> (16 + offset));
! 1294: res |= tmp2 << (8 + offset);
! 1295: bdata[1] = tmp2 & ~(mask >> (8 + offset));
! 1296: break;
! 1297: case 4:
! 1298: tmp1 = get_rmw_long_mmu060 (src);
! 1299: res = tmp1 << offset;
! 1300: bdata[0] = tmp1 & ~(mask >> offset);
! 1301: break;
! 1302: case 5:
! 1303: tmp1 = get_rmw_long_mmu060 (src);
! 1304: tmp2 = get_rmw_byte_mmu060 (src + 4);
! 1305: res = tmp1 << offset;
! 1306: bdata[0] = tmp1 & ~(mask >> offset);
! 1307: res |= tmp2 >> (8 - offset);
! 1308: bdata[1] = tmp2 & ~(mask << (8 - offset));
! 1309: break;
! 1310: default:
! 1311: /* Panic? */
! 1312: write_log (_T("x_get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3);
! 1313: res = 0;
! 1314: break;
! 1315: }
! 1316: return res;
! 1317: }
! 1318:
! 1319: void REGPARAM2 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width)
! 1320: {
! 1321: offset = (offset & 7) + width;
! 1322: switch ((offset + 7) >> 3) {
! 1323: case 1:
! 1324: put_rmw_byte_mmu060 (dst, bdata[0] | (val << (8 - offset)));
! 1325: break;
! 1326: case 2:
! 1327: put_rmw_word_mmu060 (dst, bdata[0] | (val << (16 - offset)));
! 1328: break;
! 1329: case 3:
! 1330: put_rmw_word_mmu060 (dst, bdata[0] | (val >> (offset - 16)));
! 1331: put_rmw_byte_mmu060 (dst + 2, bdata[1] | (val << (24 - offset)));
! 1332: break;
! 1333: case 4:
! 1334: put_rmw_long_mmu060 (dst, bdata[0] | (val << (32 - offset)));
! 1335: break;
! 1336: case 5:
! 1337: put_rmw_long_mmu060 (dst, bdata[0] | (val >> (offset - 32)));
! 1338: put_rmw_byte_mmu060 (dst + 4, bdata[1] | (val << (40 - offset)));
! 1339: break;
! 1340: default:
! 1341: write_log (_T("x_put_bitfield() can't happen %d\n"), (offset + 7) >> 3);
! 1342: break;
! 1343: }
! 1344: }
! 1345:
! 1346:
! 1347: #ifndef __cplusplus
1.1.1.2 root 1348: jmp_buf __exbuf;
1349: int __exvalue;
1350: #define MAX_TRY_STACK 256
1351: static int s_try_stack_size=0;
1352: static jmp_buf s_try_stack[MAX_TRY_STACK];
1353: jmp_buf* __poptry(void) {
1354: if (s_try_stack_size>0) {
1.1.1.3 root 1355: s_try_stack_size--;
1356: if (s_try_stack_size == 0)
1357: return NULL;
1358: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
1359: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
1360: return &s_try_stack[s_try_stack_size-1];
1361: }
1.1.1.2 root 1362: else {
1363: fprintf(stderr,"try stack underflow...\n");
1364: // return (NULL);
1365: abort();
1366: }
1367: }
1.1.1.3 root 1368: void __pushtry(jmp_buf* j) {
1.1.1.2 root 1369: if (s_try_stack_size<MAX_TRY_STACK) {
1370: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
1371: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
1372: s_try_stack_size++;
1373: } else {
1374: fprintf(stderr,"try stack overflow...\n");
1375: abort();
1376: }
1377: }
1378: int __is_catched(void) {return (s_try_stack_size>0); }
1.1.1.4 ! root 1379: #endif
! 1380:
1.1.1.2 root 1381: #else
1382:
1383: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
1384: {
1385: if ((opcode & 0xFE0) == 0x0500) {
1386: /* PFLUSH instruction */
1387: flush_internals();
1388: } else if ((opcode & 0x0FD8) == 0x548) {
1389: /* PTEST instruction */
1390: } else
1391: op_illg(opcode);
1392: }
1393:
1394: #endif
1395:
1396: /*
1397: vim:ts=4:sw=4:
1398: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.