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