|
|
1.1 ! 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: ! 26: #define DEBUG 0 ! 27: #define USETAG 0 ! 28: ! 29: #include "sysconfig.h" ! 30: #include "sysdeps.h" ! 31: ! 32: #include "options_cpu.h" ! 33: #include "memory.h" ! 34: #include "newcpu.h" ! 35: //#include "debug.h" ! 36: #include "main.h" ! 37: #include "cpummu.h" ! 38: ! 39: #define DBG_MMU_VERBOSE 1 ! 40: #define DBG_MMU_SANITY 1 ! 41: #define write_log printf ! 42: ! 43: #ifdef FULLMMU ! 44: ! 45: mmu_atc_l1_array atc_l1[2]; ! 46: mmu_atc_l1_array *current_atc; ! 47: struct mmu_atc_line atc_l2[2][ATC_L2_SIZE]; ! 48: ! 49: # ifdef ATC_STATS ! 50: static unsigned int mmu_atc_hits[ATC_L2_SIZE]; ! 51: # endif ! 52: ! 53: ! 54: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr) ! 55: { ! 56: DUNUSED(label); ! 57: uae_u32 from_addr, to_addr; ! 58: ! 59: from_addr = ttr & MMU_TTR_LOGICAL_BASE; ! 60: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8; ! 61: ! 62: ! 63: fprintf(stderr, "%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n", ! 64: label, ttr, ! 65: from_addr, to_addr, ! 66: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0, ! 67: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT, ! 68: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0, ! 69: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT ! 70: ); ! 71: } ! 72: ! 73: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode) ! 74: { ! 75: uae_u32 * ttr; ! 76: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0; ! 77: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1; ! 78: ! 79: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0) ! 80: ttr = ttr1; ! 81: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0) ! 82: ttr = ttr0; ! 83: else ! 84: return; ! 85: ! 86: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE; ! 87: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8; ! 88: *ttr |= MMU_TTR_BIT_ENABLED; ! 89: ! 90: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr); ! 91: } ! 92: ! 93: /* check if an address matches a ttr */ ! 94: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super) ! 95: { ! 96: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */ ! 97: uae_u8 msb, mask; ! 98: ! 99: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24; ! 100: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16; ! 101: ! 102: if (!(msb & ~mask)) { ! 103: ! 104: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) { ! 105: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) { ! 106: return TTR_NO_MATCH; ! 107: } ! 108: } ! 109: ! 110: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH; ! 111: } ! 112: } ! 113: return TTR_NO_MATCH; ! 114: } ! 115: ! 116: static inline int mmu_match_ttr(uaecptr addr, bool super, bool data) ! 117: { ! 118: int res; ! 119: ! 120: if (data) { ! 121: res = mmu_do_match_ttr(regs.dtt0, addr, super); ! 122: if (res == TTR_NO_MATCH) ! 123: res = mmu_do_match_ttr(regs.dtt1, addr, super); ! 124: } else { ! 125: res = mmu_do_match_ttr(regs.itt0, addr, super); ! 126: if (res == TTR_NO_MATCH) ! 127: res = mmu_do_match_ttr(regs.itt1, addr, super); ! 128: } ! 129: return res; ! 130: } ! 131: ! 132: #if DEBUG ! 133: /* {{{ mmu_dump_table */ ! 134: static void mmu_dump_table(const char * label, uaecptr root_ptr) ! 135: { ! 136: DUNUSED(label); ! 137: const int ROOT_TABLE_SIZE = 128, ! 138: PTR_TABLE_SIZE = 128, ! 139: PAGE_TABLE_SIZE = 64, ! 140: ROOT_INDEX_SHIFT = 25, ! 141: PTR_INDEX_SHIFT = 18; ! 142: // const int PAGE_INDEX_SHIFT = 12; ! 143: int root_idx, ptr_idx, page_idx; ! 144: uae_u32 root_des, ptr_des, page_des; ! 145: uaecptr ptr_des_addr, page_addr, ! 146: root_log, ptr_log, page_log; ! 147: ! 148: fprintf(stderr, "%s: root=%lx\n", label, root_ptr); ! 149: ! 150: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) { ! 151: root_des = phys_get_long(root_ptr + root_idx); ! 152: ! 153: if ((root_des & 2) == 0) ! 154: continue; /* invalid */ ! 155: ! 156: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx, ! 157: root_des & 8 ? 1 : 0, ! 158: root_des & 4 ? 1 : 0, ! 159: root_des & 3 ! 160: ); ! 161: ! 162: root_log = root_idx << ROOT_INDEX_SHIFT; ! 163: ! 164: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK; ! 165: ! 166: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) { ! 167: struct { ! 168: uaecptr log, phys; ! 169: int start_idx, n_pages; /* number of pages covered by this entry */ ! 170: uae_u32 match; ! 171: } page_info[PAGE_TABLE_SIZE]; ! 172: int n_pages_used; ! 173: ! 174: ptr_des = phys_get_long(ptr_des_addr + ptr_idx); ! 175: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT); ! 176: ! 177: if ((ptr_des & 2) == 0) ! 178: continue; /* invalid */ ! 179: ! 180: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4); ! 181: ! 182: n_pages_used = -1; ! 183: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) { ! 184: ! 185: page_des = phys_get_long(page_addr + page_idx); ! 186: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT ! 187: ! 188: switch (page_des & 3) { ! 189: case 0: /* invalid */ ! 190: continue; ! 191: case 1: case 3: /* resident */ ! 192: case 2: /* indirect */ ! 193: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) { ! 194: /* use the next entry */ ! 195: n_pages_used++; ! 196: ! 197: page_info[n_pages_used].match = page_des; ! 198: page_info[n_pages_used].n_pages = 1; ! 199: page_info[n_pages_used].start_idx = page_idx; ! 200: page_info[n_pages_used].log = page_log; ! 201: } else { ! 202: page_info[n_pages_used].n_pages++; ! 203: } ! 204: break; ! 205: } ! 206: } ! 207: ! 208: if (n_pages_used == -1) ! 209: continue; ! 210: ! 211: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx, ! 212: ptr_des & 8 ? 1 : 0, ! 213: ptr_des & 4 ? 1 : 0, ! 214: ptr_des & 3 ! 215: ); ! 216: ! 217: ! 218: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) { ! 219: page_des = page_info[page_idx].match; ! 220: ! 221: if ((page_des & MMU_PDT_MASK) == 2) { ! 222: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n", ! 223: page_info[page_idx].start_idx, ! 224: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 225: page_info[page_idx].log, ! 226: page_des & MMU_PAGE_INDIRECT_MASK ! 227: ); ! 228: ! 229: } else { ! 230: fprintf(stderr, " 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", ! 231: page_info[page_idx].start_idx, ! 232: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 233: page_info[page_idx].log, ! 234: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4), ! 235: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT, ! 236: page_des & MMU_DES_GLOBAL ? 1 : 0, ! 237: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT, ! 238: page_des & MMU_DES_SUPER ? 1 : 0, ! 239: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT, ! 240: page_des & MMU_DES_MODIFIED ? 1 : 0, ! 241: page_des & MMU_DES_USED ? 1 : 0, ! 242: page_des & MMU_DES_WP ? 1 : 0 ! 243: ); ! 244: } ! 245: } ! 246: } ! 247: ! 248: } ! 249: } ! 250: /* }}} */ ! 251: #endif ! 252: ! 253: /* {{{ mmu_dump_atc */ ! 254: void mmu_dump_atc(void) ! 255: { ! 256: int i, j; ! 257: for (i = 0; i < 2; i++) { ! 258: for (j = 0; j < ATC_L2_SIZE; j++) { ! 259: if (atc_l2[i][j].tag == 0x8000) ! 260: continue; ! 261: fprintf(stderr, "ATC[%02d] G=%d TT=%d M=%d WP=%d VD=%d VI=%d tag=%08x --> phys=%08x\n", ! 262: j, atc_l2[i][j].global, atc_l2[i][j].tt, atc_l2[i][j].modified, ! 263: atc_l2[i][j].write_protect, atc_l2[i][j].valid_data, atc_l2[i][j].valid_inst, ! 264: atc_l2[i][j].tag, atc_l2[i][j].phys); ! 265: } ! 266: } ! 267: } ! 268: /* }}} */ ! 269: ! 270: /* {{{ mmu_dump_tables */ ! 271: void mmu_dump_tables(void) ! 272: { ! 273: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr); ! 274: mmu_dump_ttr(L"DTT0", regs.dtt0); ! 275: mmu_dump_ttr(L"DTT1", regs.dtt1); ! 276: mmu_dump_ttr(L"ITT0", regs.itt0); ! 277: mmu_dump_ttr(L"ITT1", regs.itt1); ! 278: mmu_dump_atc(); ! 279: #if DEBUG ! 280: mmu_dump_table("SRP", regs.srp); ! 281: #endif ! 282: } ! 283: /* }}} */ ! 284: ! 285: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write); ! 286: ! 287: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data) ! 288: { ! 289: return (super ? 4 : 0) | (data ? 1 : 2); ! 290: } ! 291: ! 292: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size) ! 293: { ! 294: uae_u16 ssw = 0; ! 295: ! 296: ssw |= fc & MMU_SSW_TM; /* Copy TM */ ! 297: switch (size) { ! 298: case sz_byte: ! 299: ssw |= MMU_SSW_SIZE_B; ! 300: break; ! 301: case sz_word: ! 302: ssw |= MMU_SSW_SIZE_W; ! 303: break; ! 304: case sz_long: ! 305: ssw |= MMU_SSW_SIZE_L; ! 306: break; ! 307: } ! 308: ! 309: regs.wb3_status = write ? 0x80 | ssw : 0; ! 310: if (!write) ! 311: ssw |= MMU_SSW_RW; ! 312: ! 313: regs.mmu_fault_addr = addr; ! 314: regs.mmu_ssw = ssw | MMU_SSW_ATC; ! 315: ! 316: fprintf(stderr, "BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc()); ! 317: ! 318: //write_log(L"BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc()); ! 319: ! 320: except=2; ! 321: } ! 322: ! 323: /* ! 324: * Update the atc line for a given address by doing a mmu lookup. ! 325: */ ! 326: static uaecptr mmu_fill_atc_l2(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l) ! 327: { ! 328: int res; ! 329: uae_u32 desc; ! 330: ! 331: l->tag = ATC_TAG(addr); ! 332: l->hw = l->bus_fault = 0; ! 333: ! 334: /* check ttr0 */ ! 335: res = mmu_match_ttr(addr, super, data); ! 336: if (res != TTR_NO_MATCH) { ! 337: l->tt = 1; ! 338: if (data) { ! 339: l->valid_data = 1; ! 340: l->valid_inst = mmu_match_ttr(addr, super, 0) == res; ! 341: } else { ! 342: l->valid_inst = 1; ! 343: l->valid_data = mmu_match_ttr(addr, super, 1) == res; ! 344: } ! 345: l->global = 1; ! 346: l->modified = 1; ! 347: l->write_protect = (res == TTR_NO_WRITE); ! 348: l->phys = 0; ! 349: ! 350: return 0; ! 351: } ! 352: ! 353: l->tt = 0; ! 354: if (!regs.mmu_enabled) { ! 355: l->valid_data = l->valid_inst = 1; ! 356: l->global = 1; ! 357: l->modified = 1; ! 358: l->write_protect = 0; ! 359: l->phys = 0; ! 360: return 0; ! 361: } ! 362: ! 363: SAVE_EXCEPTION; ! 364: // TRY(prb) { ! 365: except = 0; ! 366: desc = mmu_lookup_pagetable(addr, super, write); ! 367: #if DEBUG > 2 ! 368: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc); ! 369: #endif ! 370: RESTORE_EXCEPTION; ! 371: CATCH(prb) { ! 372: RESTORE_EXCEPTION; ! 373: /* bus error during table search */ ! 374: desc = 0; ! 375: goto fail; ! 376: } ! 377: ! 378: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) { ! 379: fail: ! 380: l->valid_data = l->valid_inst = 0; ! 381: l->global = 0; ! 382: } else { ! 383: l->valid_data = l->valid_inst = 1; ! 384: if (regs.mmu_pagesize_8k) ! 385: l->phys = (desc & ~0x1fff) - (addr & ~0x1fff); ! 386: else ! 387: l->phys = (desc & ~0xfff) - (addr & ~0xfff); ! 388: l->global = (desc & MMU_MMUSR_G) != 0; ! 389: l->modified = (desc & MMU_MMUSR_M) != 0; ! 390: l->write_protect = (desc & MMU_MMUSR_W) != 0; ! 391: } ! 392: ! 393: return desc; ! 394: } ! 395: ! 396: static ALWAYS_INLINE bool mmu_fill_atc_l1(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1) ! 397: { ! 398: int idx = ATC_L2_INDEX(addr); ! 399: int tag = ATC_TAG(addr); ! 400: struct mmu_atc_line *l = &atc_l2[super ? 1 : 0][idx]; ! 401: ! 402: if (l->tag != tag) { ! 403: restart: ! 404: mmu_fill_atc_l2(addr, super, data, write, l); ! 405: } ! 406: if (!(data ? l->valid_data : l->valid_inst)) { ! 407: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc); ! 408: goto fail; ! 409: } ! 410: if (write) { ! 411: if (l->write_protect) { ! 412: fprintf(stderr, "MMU: write protected (via %s) %lx\n", l->tt ? "ttr" : "atc", addr); ! 413: goto fail; ! 414: } ! 415: if (!l->modified) ! 416: goto restart; ! 417: } ! 418: *l1 = *l; ! 419: #if 0 ! 420: uaecptr phys_addr = addr + l1->phys; ! 421: if ((phys_addr & 0xfff00000) == 0x00f00000) { ! 422: l1->hw = 1; ! 423: goto fail; ! 424: } ! 425: if ((phys_addr & 0xfff00000) == 0xfff00000) { ! 426: l1->hw = 1; ! 427: l1->phys -= 0xff000000; ! 428: goto fail; ! 429: } ! 430: ! 431: if (!test_ram_boundary(phys_addr, 1, super, write)) { ! 432: l1->bus_fault = 1; ! 433: goto fail; ! 434: } ! 435: #endif ! 436: return true; ! 437: ! 438: fail: ! 439: l1->tag = ~l1->tag; ! 440: return false; ! 441: } ! 442: ! 443: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write) ! 444: { ! 445: struct mmu_atc_line *l; ! 446: ! 447: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)]; ! 448: mmu_fill_atc_l2(addr, super, data, write, l); ! 449: if (!(data ? l->valid_data : l->valid_inst)) ! 450: except=2; ! 451: ! 452: return addr + l->phys; ! 453: } ! 454: ! 455: /* ! 456: * Lookup the address by walking the page table and updating ! 457: * the page descriptors accordingly. Returns the found descriptor ! 458: * or produces a bus error. ! 459: */ ! 460: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write) ! 461: { ! 462: uae_u32 desc, desc_addr, wp; ! 463: int i; ! 464: ! 465: wp = 0; ! 466: desc = super ? regs.srp : regs.urp; ! 467: ! 468: /* fetch root table descriptor */ ! 469: i = (addr >> 23) & 0x1fc; ! 470: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; ! 471: desc = phys_get_long(desc_addr); ! 472: if ((desc & 2) == 0) { ! 473: fprintf(stderr, "MMU: invalid root descriptor for %lx\n", addr); ! 474: return 0; ! 475: } ! 476: ! 477: wp |= desc; ! 478: if ((desc & MMU_DES_USED) == 0) ! 479: phys_put_long(desc_addr, desc | MMU_DES_USED); ! 480: ! 481: /* fetch pointer table descriptor */ ! 482: i = (addr >> 16) & 0x1fc; ! 483: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; ! 484: desc = phys_get_long(desc_addr); ! 485: if ((desc & 2) == 0) { ! 486: fprintf(stderr, "MMU: invalid ptr descriptor for %lx\n", addr); ! 487: return 0; ! 488: } ! 489: wp |= desc; ! 490: if ((desc & MMU_DES_USED) == 0) ! 491: phys_put_long(desc_addr, desc | MMU_DES_USED); ! 492: ! 493: /* fetch page table descriptor */ ! 494: if (regs.mmu_pagesize_8k) { ! 495: i = (addr >> 11) & 0x7c; ! 496: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) | i; ! 497: } else { ! 498: i = (addr >> 10) & 0xfc; ! 499: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) | i; ! 500: } ! 501: ! 502: desc = phys_get_long(desc_addr); ! 503: if ((desc & 3) == 2) { ! 504: /* indirect */ ! 505: desc_addr = desc & MMU_PAGE_INDIRECT_MASK; ! 506: desc = phys_get_long(desc_addr); ! 507: } ! 508: if ((desc & 1) == 0) { ! 509: fprintf(stderr, "MMU: invalid page descriptor log=%08lx desc=%08lx @%08lx\n", addr, desc, desc_addr); ! 510: return desc; ! 511: } ! 512: ! 513: desc |= wp & MMU_DES_WP; ! 514: if (write) { ! 515: if (desc & MMU_DES_WP) { ! 516: if ((desc & MMU_DES_USED) == 0) { ! 517: desc |= MMU_DES_USED; ! 518: phys_put_long(desc_addr, desc); ! 519: } ! 520: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) != ! 521: (MMU_DES_USED|MMU_DES_MODIFIED)) { ! 522: desc |= MMU_DES_USED|MMU_DES_MODIFIED; ! 523: phys_put_long(desc_addr, desc); ! 524: } ! 525: } else { ! 526: if ((desc & MMU_DES_USED) == 0) { ! 527: desc |= MMU_DES_USED; ! 528: phys_put_long(desc_addr, desc); ! 529: } ! 530: } ! 531: return desc; ! 532: } ! 533: ! 534: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data) ! 535: { ! 536: uae_u16 res; ! 537: ! 538: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8; ! 539: SAVE_EXCEPTION; ! 540: ! 541: // TRY(prb) { ! 542: except = 0; ! 543: res |= mmu_get_byte(addr + 1, data, sz_word); ! 544: RESTORE_EXCEPTION; ! 545: ! 546: CATCH(prb) { ! 547: RESTORE_EXCEPTION; ! 548: regs.mmu_fault_addr = addr; ! 549: regs.mmu_ssw |= MMU_SSW_MA; ! 550: except=2; ! 551: } ! 552: return res; ! 553: } ! 554: ! 555: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data) ! 556: { ! 557: uae_u32 res; ! 558: ! 559: if (likely(!(addr & 1))) { ! 560: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16; ! 561: SAVE_EXCEPTION; ! 562: // TRY(prb) { ! 563: except = 0; ! 564: res |= mmu_get_word(addr + 2, data, sz_long); ! 565: RESTORE_EXCEPTION; ! 566: CATCH(prb) { ! 567: RESTORE_EXCEPTION; ! 568: regs.mmu_fault_addr = addr; ! 569: regs.mmu_ssw |= MMU_SSW_MA; ! 570: except=2; ! 571: } ! 572: } else { ! 573: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8; ! 574: SAVE_EXCEPTION; ! 575: // TRY(prb) { ! 576: except = 0; ! 577: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8; ! 578: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8; ! 579: res |= mmu_get_byte(addr + 3, data, sz_long); ! 580: RESTORE_EXCEPTION; ! 581: ! 582: CATCH(prb) { ! 583: RESTORE_EXCEPTION; ! 584: regs.mmu_fault_addr = addr; ! 585: regs.mmu_ssw |= MMU_SSW_MA; ! 586: except=2; ! 587: } ! 588: } ! 589: return res; ! 590: } ! 591: ! 592: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data, ! 593: int size, struct mmu_atc_line *cl) ! 594: { ! 595: uae_u32 tag = ATC_TAG(addr); ! 596: ! 597: if (USETAG && cl->tag == (uae_u16)~tag) { ! 598: redo: ! 599: if (cl->hw) ! 600: return HWget_b(cl->phys + addr); ! 601: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 602: return 0; ! 603: } ! 604: ! 605: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 606: goto redo; ! 607: ! 608: return phys_get_byte(mmu_get_real_address(addr, cl)); ! 609: } ! 610: ! 611: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data, ! 612: int size, struct mmu_atc_line *cl) ! 613: { ! 614: uae_u32 tag = ATC_TAG(addr); ! 615: ! 616: if (USETAG && cl->tag == (uae_u16)~tag) { ! 617: redo: ! 618: if (cl->hw) ! 619: return HWget_w(cl->phys + addr); ! 620: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 621: return 0; ! 622: } ! 623: ! 624: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 625: goto redo; ! 626: ! 627: return phys_get_word(mmu_get_real_address(addr, cl)); ! 628: } ! 629: ! 630: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data, ! 631: int size, struct mmu_atc_line *cl) ! 632: { ! 633: uae_u32 tag = ATC_TAG(addr); ! 634: ! 635: if (USETAG && cl->tag == (uae_u16)~tag) { ! 636: redo: ! 637: if (cl->hw) ! 638: return HWget_l(cl->phys + addr); ! 639: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 640: return 0; ! 641: } ! 642: ! 643: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 644: goto redo; ! 645: ! 646: return phys_get_long(mmu_get_real_address(addr, cl)); ! 647: } ! 648: ! 649: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data) ! 650: { ! 651: SAVE_EXCEPTION; ! 652: // TRY(prb) { ! 653: except = 0; ! 654: if (likely(!(addr & 1))) { ! 655: mmu_put_word(addr, val >> 16, data, sz_long); ! 656: mmu_put_word(addr + 2, val, data, sz_long); ! 657: } else { ! 658: mmu_put_byte(addr, val >> 24, data, sz_long); ! 659: mmu_put_byte(addr + 1, val >> 16, data, sz_long); ! 660: mmu_put_byte(addr + 2, val >> 8, data, sz_long); ! 661: mmu_put_byte(addr + 3, val, data, sz_long); ! 662: } ! 663: RESTORE_EXCEPTION; ! 664: ! 665: CATCH(prb) { ! 666: RESTORE_EXCEPTION; ! 667: regs.wb3_data = val; ! 668: if (regs.mmu_fault_addr != addr) { ! 669: regs.mmu_fault_addr = addr; ! 670: regs.mmu_ssw |= MMU_SSW_MA; ! 671: } ! 672: except=2; ! 673: } ! 674: } ! 675: ! 676: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data) ! 677: { ! 678: SAVE_EXCEPTION; ! 679: // TRY(prb) { ! 680: except = 0; ! 681: mmu_put_byte(addr, val >> 8, data, sz_word); ! 682: mmu_put_byte(addr + 1, val, data, sz_word); ! 683: RESTORE_EXCEPTION; ! 684: ! 685: CATCH(prb) { ! 686: RESTORE_EXCEPTION; ! 687: regs.wb3_data = val; ! 688: if (regs.mmu_fault_addr != addr) { ! 689: regs.mmu_fault_addr = addr; ! 690: regs.mmu_ssw |= MMU_SSW_MA; ! 691: } ! 692: except=2; ! 693: } ! 694: } ! 695: ! 696: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data, ! 697: int size, struct mmu_atc_line *cl) ! 698: { ! 699: uae_u32 tag = ATC_TAG(addr); ! 700: ! 701: if (USETAG && cl->tag == (uae_u16)~tag) { ! 702: redo: ! 703: if (cl->hw) { ! 704: HWput_b(cl->phys + addr, val); ! 705: return; ! 706: } ! 707: regs.wb3_data = val; ! 708: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 709: return; ! 710: } ! 711: ! 712: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 713: goto redo; ! 714: ! 715: phys_put_byte(mmu_get_real_address(addr, cl), val); ! 716: } ! 717: ! 718: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data, ! 719: int size, struct mmu_atc_line *cl) ! 720: { ! 721: uae_u32 tag = ATC_TAG(addr); ! 722: ! 723: if (USETAG && cl->tag == (uae_u16)~tag) { ! 724: redo: ! 725: if (cl->hw) { ! 726: HWput_w(cl->phys + addr, val); ! 727: return; ! 728: } ! 729: regs.wb3_data = val; ! 730: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 731: return; ! 732: } ! 733: ! 734: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 735: goto redo; ! 736: ! 737: phys_put_word(mmu_get_real_address(addr, cl), val); ! 738: } ! 739: ! 740: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data, ! 741: int size, struct mmu_atc_line *cl) ! 742: { ! 743: uae_u32 tag = ATC_TAG(addr); ! 744: ! 745: if (USETAG && cl->tag == (uae_u16)~tag) { ! 746: redo: ! 747: if (cl->hw) { ! 748: HWput_l(cl->phys + addr, val); ! 749: return; ! 750: } ! 751: regs.wb3_data = val; ! 752: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 753: return; ! 754: } ! 755: ! 756: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 757: goto redo; ! 758: ! 759: phys_put_long(mmu_get_real_address(addr, cl), val); ! 760: } ! 761: ! 762: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr) ! 763: { ! 764: bool super = (regs.sfc & 4) != 0; ! 765: bool data = (regs.sfc & 3) != 2; ! 766: uae_u32 res; ! 767: ! 768: if (likely(!is_unaligned(addr, 4))) ! 769: return mmu_get_user_long(addr, super, data, sz_long); ! 770: ! 771: if (likely(!(addr & 1))) { ! 772: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16; ! 773: SAVE_EXCEPTION; ! 774: // TRY(prb) { ! 775: except = 0; ! 776: res |= mmu_get_user_word(addr + 2, super, data, sz_long); ! 777: RESTORE_EXCEPTION; ! 778: ! 779: CATCH(prb) { ! 780: RESTORE_EXCEPTION; ! 781: regs.mmu_fault_addr = addr; ! 782: regs.mmu_ssw |= MMU_SSW_MA; ! 783: except=2; ! 784: } ! 785: } else { ! 786: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8; ! 787: SAVE_EXCEPTION; ! 788: // TRY(prb) { ! 789: except = 0; ! 790: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8; ! 791: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8; ! 792: res |= mmu_get_user_byte(addr + 3, super, data, sz_long); ! 793: RESTORE_EXCEPTION; ! 794: ! 795: CATCH(prb) { ! 796: RESTORE_EXCEPTION; ! 797: regs.mmu_fault_addr = addr; ! 798: regs.mmu_ssw |= MMU_SSW_MA; ! 799: except=2; ! 800: } ! 801: } ! 802: return res; ! 803: } ! 804: ! 805: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr) ! 806: { ! 807: bool super = (regs.sfc & 4) != 0; ! 808: bool data = (regs.sfc & 3) != 2; ! 809: uae_u16 res; ! 810: ! 811: if (likely(!is_unaligned(addr, 2))) ! 812: return mmu_get_user_word(addr, super, data, sz_word); ! 813: ! 814: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8; ! 815: SAVE_EXCEPTION; ! 816: // TRY(prb) { ! 817: except = 0; ! 818: res |= mmu_get_user_byte(addr + 1, super, data, sz_word); ! 819: RESTORE_EXCEPTION; ! 820: ! 821: CATCH(prb) { ! 822: RESTORE_EXCEPTION; ! 823: regs.mmu_fault_addr = addr; ! 824: regs.mmu_ssw |= MMU_SSW_MA; ! 825: except=2; ! 826: } ! 827: return res; ! 828: } ! 829: ! 830: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr) ! 831: { ! 832: bool super = (regs.sfc & 4) != 0; ! 833: bool data = (regs.sfc & 3) != 2; ! 834: ! 835: return mmu_get_user_byte(addr, super, data, sz_byte); ! 836: } ! 837: ! 838: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val) ! 839: { ! 840: bool super = (regs.dfc & 4) != 0; ! 841: bool data = (regs.dfc & 3) != 2; ! 842: ! 843: SAVE_EXCEPTION; ! 844: // TRY(prb) { ! 845: except = 0; ! 846: if (likely(!is_unaligned(addr, 4))) ! 847: mmu_put_user_long(addr, val, super, data, sz_long); ! 848: else if (likely(!(addr & 1))) { ! 849: mmu_put_user_word(addr, val >> 16, super, data, sz_long); ! 850: mmu_put_user_word(addr + 2, val, super, data, sz_long); ! 851: } else { ! 852: mmu_put_user_byte(addr, val >> 24, super, data, sz_long); ! 853: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long); ! 854: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long); ! 855: mmu_put_user_byte(addr + 3, val, super, data, sz_long); ! 856: } ! 857: RESTORE_EXCEPTION; ! 858: ! 859: CATCH(prb) { ! 860: RESTORE_EXCEPTION; ! 861: regs.wb3_data = val; ! 862: if (regs.mmu_fault_addr != addr) { ! 863: regs.mmu_fault_addr = addr; ! 864: regs.mmu_ssw |= MMU_SSW_MA; ! 865: } ! 866: except=2; ! 867: } ! 868: } ! 869: ! 870: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val) ! 871: { ! 872: bool super = (regs.dfc & 4) != 0; ! 873: bool data = (regs.dfc & 3) != 2; ! 874: ! 875: SAVE_EXCEPTION; ! 876: // TRY(prb) { ! 877: except = 0; ! 878: if (likely(!is_unaligned(addr, 2))) ! 879: mmu_put_user_word(addr, val, super, data, sz_word); ! 880: else { ! 881: mmu_put_user_byte(addr, val >> 8, super, data, sz_word); ! 882: mmu_put_user_byte(addr + 1, val, super, data, sz_word); ! 883: } ! 884: RESTORE_EXCEPTION; ! 885: ! 886: CATCH(prb) { ! 887: RESTORE_EXCEPTION; ! 888: regs.wb3_data = val; ! 889: if (regs.mmu_fault_addr != addr) { ! 890: regs.mmu_fault_addr = addr; ! 891: regs.mmu_ssw |= MMU_SSW_MA; ! 892: } ! 893: except=2; ! 894: } ! 895: } ! 896: ! 897: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val) ! 898: { ! 899: bool super = (regs.dfc & 4) != 0; ! 900: bool data = (regs.dfc & 3) != 2; ! 901: ! 902: SAVE_EXCEPTION; ! 903: // TRY(prb) { ! 904: except = 0; ! 905: mmu_put_user_byte(addr, val, super, data, sz_byte); ! 906: RESTORE_EXCEPTION; ! 907: ! 908: CATCH(prb) { ! 909: RESTORE_EXCEPTION; ! 910: regs.wb3_data = val; ! 911: except=2; ! 912: } ! 913: } ! 914: ! 915: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra) ! 916: { ! 917: bool super = (regs.dfc & 4) != 0; ! 918: DUNUSED(extra); ! 919: if ((opcode & 0xFE0) == 0x0500) { ! 920: bool glob; ! 921: int regno; ! 922: //D(didflush = 0); ! 923: uae_u32 addr; ! 924: /* PFLUSH */ ! 925: regno = opcode & 7; ! 926: glob = (opcode & 8) != 0; ! 927: ! 928: if (opcode & 16) { ! 929: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc); ! 930: mmu_flush_atc_all(glob); ! 931: } else { ! 932: addr = m68k_areg(regs, regno); ! 933: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr); ! 934: mmu_flush_atc(addr, super, glob); ! 935: } ! 936: flush_internals(); ! 937: #ifdef USE_JIT ! 938: flush_icache(0); ! 939: #endif ! 940: } else if ((opcode & 0x0FD8) == 0x548) { ! 941: bool write; ! 942: int regno; ! 943: uae_u32 addr; ! 944: ! 945: regno = opcode & 7; ! 946: write = (opcode & 32) == 0; ! 947: addr = m68k_areg(regs, regno); ! 948: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc); ! 949: mmu_flush_atc(addr, super, true); ! 950: SAVE_EXCEPTION; ! 951: // TRY(prb) { ! 952: except = 0; ! 953: struct mmu_atc_line *l; ! 954: uae_u32 desc; ! 955: bool data = (regs.dfc & 3) != 2; ! 956: ! 957: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)]; ! 958: desc = mmu_fill_atc_l2(addr, super, data, write, l); ! 959: if (!(data ? l->valid_data : l->valid_inst)) ! 960: regs.mmusr = MMU_MMUSR_B; ! 961: else if (l->tt) ! 962: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R; ! 963: else { ! 964: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S| ! 965: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W); ! 966: regs.mmusr |= MMU_MMUSR_R; ! 967: } ! 968: ! 969: CATCH(prb) { ! 970: regs.mmusr = MMU_MMUSR_B; ! 971: } ! 972: RESTORE_EXCEPTION; ! 973: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr); ! 974: } else ! 975: op_illg (opcode); ! 976: } ! 977: ! 978: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global) ! 979: { ! 980: struct mmu_atc_line *l; ! 981: int i, j; ! 982: ! 983: l = atc_l1[super ? 1 : 0][0][0]; ! 984: i = ATC_L1_INDEX(addr); ! 985: for (j = 0; j < 4; j++) { ! 986: if (global || !l[i].global) ! 987: l[i].tag = 0x8000; ! 988: l += ATC_L1_SIZE; ! 989: } ! 990: if (regs.mmu_pagesize_8k) { ! 991: i = ATC_L1_INDEX(addr) ^ 1; ! 992: for (j = 0; j < 4; j++) { ! 993: if (global || !l[i].global) ! 994: l[i].tag = 0x8000; ! 995: l += ATC_L1_SIZE; ! 996: } ! 997: } ! 998: l = atc_l2[super ? 1 : 0]; ! 999: i = ATC_L2_INDEX(addr); ! 1000: if (global || !l[i].global) ! 1001: l[i].tag = 0x8000; ! 1002: if (regs.mmu_pagesize_8k) { ! 1003: i ^= 1; ! 1004: if (global || !l[i].global) ! 1005: l[i].tag = 0x8000; ! 1006: } ! 1007: } ! 1008: ! 1009: void REGPARAM2 mmu_flush_atc_all(bool global) ! 1010: { ! 1011: struct mmu_atc_line *l; ! 1012: unsigned int i; ! 1013: ! 1014: l = atc_l1[0][0][0]; ! 1015: for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) { ! 1016: if (global || !l->global) ! 1017: l->tag = 0x8000; ! 1018: } ! 1019: ! 1020: l = atc_l2[0]; ! 1021: for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) { ! 1022: if (global || !l->global) ! 1023: l->tag = 0x8000; ! 1024: } ! 1025: } ! 1026: ! 1027: void REGPARAM2 mmu_reset(void) ! 1028: { ! 1029: mmu_flush_atc_all(true); ! 1030: #if 0 ! 1031: regs.urp = regs.srp = 0; ! 1032: regs.itt0 = regs.itt0 = 0; ! 1033: regs.dtt0 = regs.dtt0 = 0; ! 1034: regs.mmusr = 0; ! 1035: #endif ! 1036: } ! 1037: ! 1038: ! 1039: void REGPARAM2 mmu_set_tc(uae_u16 tc) ! 1040: { ! 1041: #if 0 ! 1042: if (regs.tcr == tc) ! 1043: return; ! 1044: regs.tcr = tc; ! 1045: #endif ! 1046: regs.mmu_enabled = tc & 0x8000 ? 1 : 0; ! 1047: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0; ! 1048: mmu_flush_atc_all(true); ! 1049: ! 1050: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k); ! 1051: } ! 1052: ! 1053: void REGPARAM2 mmu_set_super(bool super) ! 1054: { ! 1055: current_atc = &atc_l1[super ? 1 : 0]; ! 1056: } ! 1057: ! 1058: #else ! 1059: ! 1060: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/) ! 1061: { ! 1062: if ((opcode & 0xFE0) == 0x0500) { ! 1063: /* PFLUSH instruction */ ! 1064: flush_internals(); ! 1065: } else if ((opcode & 0x0FD8) == 0x548) { ! 1066: /* PTEST instruction */ ! 1067: } else ! 1068: op_illg(opcode); ! 1069: } ! 1070: ! 1071: #endif ! 1072: ! 1073: /* ! 1074: vim:ts=4:sw=4: ! 1075: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.