|
|
1.1.1.3 ! root 1: /* ! 2: * cpummu.cpp - MMU emulation ! 3: * ! 4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) ! 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: fprintf(stderr, "%s: [%08x] %08x - %08x enabled=%d supervisor=%d wp=%d cm=%02d\n", ! 63: label, ttr, ! 64: from_addr, to_addr, ! 65: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0, ! 66: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT, ! 67: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0, ! 68: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT ! 69: ); ! 70: } ! 71: ! 72: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode) ! 73: { ! 74: uae_u32 * ttr; ! 75: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0; ! 76: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1; ! 77: ! 78: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0) ! 79: ttr = ttr1; ! 80: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0) ! 81: ttr = ttr0; ! 82: else ! 83: return; ! 84: ! 85: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE; ! 86: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8; ! 87: *ttr |= MMU_TTR_BIT_ENABLED; ! 88: ! 89: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr); ! 90: } ! 91: ! 92: /* check if an address matches a ttr */ ! 93: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super) ! 94: { ! 95: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */ ! 96: uae_u8 msb, mask; ! 97: ! 98: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24; ! 99: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16; ! 100: ! 101: if (!(msb & ~mask)) { ! 102: ! 103: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) { ! 104: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) { ! 105: return TTR_NO_MATCH; ! 106: } ! 107: } ! 108: ! 109: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH; ! 110: } ! 111: } ! 112: return TTR_NO_MATCH; ! 113: } ! 114: ! 115: static inline int mmu_match_ttr(uaecptr addr, bool super, bool data) ! 116: { ! 117: int res; ! 118: ! 119: if (data) { ! 120: res = mmu_do_match_ttr(regs.dtt0, addr, super); ! 121: if (res == TTR_NO_MATCH) ! 122: res = mmu_do_match_ttr(regs.dtt1, addr, super); ! 123: } else { ! 124: res = mmu_do_match_ttr(regs.itt0, addr, super); ! 125: if (res == TTR_NO_MATCH) ! 126: res = mmu_do_match_ttr(regs.itt1, addr, super); ! 127: } ! 128: return res; ! 129: } ! 130: ! 131: #if DEBUG ! 132: /* {{{ mmu_dump_table */ ! 133: static void mmu_dump_table(const char * label, uaecptr root_ptr) ! 134: { ! 135: DUNUSED(label); ! 136: const int ROOT_TABLE_SIZE = 128, ! 137: PTR_TABLE_SIZE = 128, ! 138: PAGE_TABLE_SIZE = 64, ! 139: ROOT_INDEX_SHIFT = 25, ! 140: PTR_INDEX_SHIFT = 18; ! 141: // const int PAGE_INDEX_SHIFT = 12; ! 142: int root_idx, ptr_idx, page_idx; ! 143: uae_u32 root_des, ptr_des, page_des; ! 144: uaecptr ptr_des_addr, page_addr, ! 145: root_log, ptr_log, page_log; ! 146: ! 147: fprintf(stderr, "%s: root=%lx\n", label, root_ptr); ! 148: ! 149: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) { ! 150: root_des = phys_get_long(root_ptr + root_idx); ! 151: ! 152: if ((root_des & 2) == 0) ! 153: continue; /* invalid */ ! 154: ! 155: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx, ! 156: root_des & 8 ? 1 : 0, ! 157: root_des & 4 ? 1 : 0, ! 158: root_des & 3 ! 159: ); ! 160: ! 161: root_log = root_idx << ROOT_INDEX_SHIFT; ! 162: ! 163: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK; ! 164: ! 165: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) { ! 166: struct { ! 167: uaecptr log, phys; ! 168: int start_idx, n_pages; /* number of pages covered by this entry */ ! 169: uae_u32 match; ! 170: } page_info[PAGE_TABLE_SIZE]; ! 171: int n_pages_used; ! 172: ! 173: ptr_des = phys_get_long(ptr_des_addr + ptr_idx); ! 174: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT); ! 175: ! 176: if ((ptr_des & 2) == 0) ! 177: continue; /* invalid */ ! 178: ! 179: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4); ! 180: ! 181: n_pages_used = -1; ! 182: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) { ! 183: ! 184: page_des = phys_get_long(page_addr + page_idx); ! 185: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT ! 186: ! 187: switch (page_des & 3) { ! 188: case 0: /* invalid */ ! 189: continue; ! 190: case 1: case 3: /* resident */ ! 191: case 2: /* indirect */ ! 192: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) { ! 193: /* use the next entry */ ! 194: n_pages_used++; ! 195: ! 196: page_info[n_pages_used].match = page_des; ! 197: page_info[n_pages_used].n_pages = 1; ! 198: page_info[n_pages_used].start_idx = page_idx; ! 199: page_info[n_pages_used].log = page_log; ! 200: } else { ! 201: page_info[n_pages_used].n_pages++; ! 202: } ! 203: break; ! 204: } ! 205: } ! 206: ! 207: if (n_pages_used == -1) ! 208: continue; ! 209: ! 210: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx, ! 211: ptr_des & 8 ? 1 : 0, ! 212: ptr_des & 4 ? 1 : 0, ! 213: ptr_des & 3 ! 214: ); ! 215: ! 216: ! 217: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) { ! 218: page_des = page_info[page_idx].match; ! 219: ! 220: if ((page_des & MMU_PDT_MASK) == 2) { ! 221: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n", ! 222: page_info[page_idx].start_idx, ! 223: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 224: page_info[page_idx].log, ! 225: page_des & MMU_PAGE_INDIRECT_MASK ! 226: ); ! 227: ! 228: } else { ! 229: 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", ! 230: page_info[page_idx].start_idx, ! 231: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 232: page_info[page_idx].log, ! 233: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4), ! 234: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT, ! 235: page_des & MMU_DES_GLOBAL ? 1 : 0, ! 236: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT, ! 237: page_des & MMU_DES_SUPER ? 1 : 0, ! 238: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT, ! 239: page_des & MMU_DES_MODIFIED ? 1 : 0, ! 240: page_des & MMU_DES_USED ? 1 : 0, ! 241: page_des & MMU_DES_WP ? 1 : 0 ! 242: ); ! 243: } ! 244: } ! 245: } ! 246: ! 247: } ! 248: } ! 249: /* }}} */ ! 250: #endif ! 251: ! 252: /* {{{ mmu_dump_atc */ ! 253: static void mmu_dump_atc(void) ! 254: { ! 255: int i, j; ! 256: for (i = 0; i < 2; i++) { ! 257: for (j = 0; j < ATC_L2_SIZE; j++) { ! 258: if (atc_l2[i][j].tag == 0x8000) ! 259: continue; ! 260: fprintf(stderr, "ATC[%02d] G=%d TT=%d M=%d WP=%d VD=%d VI=%d tag=%08x --> phys=%08x\n", ! 261: j, atc_l2[i][j].global, atc_l2[i][j].tt, atc_l2[i][j].modified, ! 262: atc_l2[i][j].write_protect, atc_l2[i][j].valid_data, atc_l2[i][j].valid_inst, ! 263: atc_l2[i][j].tag, atc_l2[i][j].phys); ! 264: } ! 265: } ! 266: } ! 267: /* }}} */ ! 268: ! 269: /* {{{ mmu_dump_tables */ ! 270: void mmu_dump_tables(void) ! 271: { ! 272: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr); ! 273: mmu_dump_ttr("DTT0", regs.dtt0); ! 274: mmu_dump_ttr("DTT1", regs.dtt1); ! 275: mmu_dump_ttr("ITT0", regs.itt0); ! 276: mmu_dump_ttr("ITT1", regs.itt1); ! 277: mmu_dump_atc(); ! 278: #if DEBUG ! 279: mmu_dump_table("SRP", regs.srp); ! 280: #endif ! 281: } ! 282: /* }}} */ ! 283: ! 284: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write); ! 285: ! 286: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data) ! 287: { ! 288: return (super ? 4 : 0) | (data ? 1 : 2); ! 289: } ! 290: ! 291: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size) ! 292: { ! 293: uae_u16 ssw = 0; ! 294: ! 295: ssw |= fc & MMU_SSW_TM; /* Copy TM */ ! 296: switch (size) { ! 297: case sz_byte: ! 298: ssw |= MMU_SSW_SIZE_B; ! 299: break; ! 300: case sz_word: ! 301: ssw |= MMU_SSW_SIZE_W; ! 302: break; ! 303: case sz_long: ! 304: ssw |= MMU_SSW_SIZE_L; ! 305: break; ! 306: } ! 307: ! 308: regs.wb3_status = write ? 0x80 | ssw : 0; ! 309: if (!write) ! 310: ssw |= MMU_SSW_RW; ! 311: ! 312: regs.mmu_fault_addr = addr; ! 313: regs.mmu_ssw = ssw | MMU_SSW_ATC; ! 314: ! 315: fprintf(stderr, "BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc()); ! 316: ! 317: //write_log(L"BUS ERROR: fc=%d w=%d log=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc()); ! 318: //activate_debugger(); ! 319: ! 320: THROW(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: desc = mmu_lookup_pagetable(addr, super, write); ! 366: #if DEBUG > 2 ! 367: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc); ! 368: #endif ! 369: RESTORE_EXCEPTION; ! 370: } ! 371: CATCH(prb) { ! 372: RESTORE_EXCEPTION; ! 373: /* bus error during table search */ ! 374: desc = 0; ! 375: //goto fail; ! 376: } ENDTRY ! 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) %x\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: THROW(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 %x desc at %x desc=%x %s at %d\n", addr,desc_addr,desc,__FILE__,__LINE__); ! 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 %x desc at %x desc=%x %s at %d\n", addr,desc_addr,desc,__FILE__,__LINE__); ! 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=%08x desc=%08x @%08x %s at %d\n", addr, desc, desc_addr,__FILE__,__LINE__); ! 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: TRY(prb) { ! 541: res |= mmu_get_byte(addr + 1, data, sz_word); ! 542: RESTORE_EXCEPTION; ! 543: } ! 544: CATCH(prb) { ! 545: RESTORE_EXCEPTION; ! 546: regs.mmu_fault_addr = addr; ! 547: regs.mmu_ssw |= MMU_SSW_MA; ! 548: THROW_AGAIN(prb); ! 549: } ENDTRY ! 550: return res; ! 551: } ! 552: ! 553: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data) ! 554: { ! 555: uae_u32 res; ! 556: ! 557: if (likely(!(addr & 1))) { ! 558: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16; ! 559: SAVE_EXCEPTION; ! 560: TRY(prb) { ! 561: res |= mmu_get_word(addr + 2, data, sz_long); ! 562: RESTORE_EXCEPTION; ! 563: } ! 564: CATCH(prb) { ! 565: RESTORE_EXCEPTION; ! 566: regs.mmu_fault_addr = addr; ! 567: regs.mmu_ssw |= MMU_SSW_MA; ! 568: THROW_AGAIN(prb); ! 569: } ENDTRY ! 570: } else { ! 571: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8; ! 572: SAVE_EXCEPTION; ! 573: TRY(prb) { ! 574: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8; ! 575: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8; ! 576: res |= mmu_get_byte(addr + 3, data, sz_long); ! 577: RESTORE_EXCEPTION; ! 578: } ! 579: CATCH(prb) { ! 580: RESTORE_EXCEPTION; ! 581: regs.mmu_fault_addr = addr; ! 582: regs.mmu_ssw |= MMU_SSW_MA; ! 583: THROW_AGAIN(prb); ! 584: } ENDTRY ! 585: } ! 586: return res; ! 587: } ! 588: ! 589: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data, ! 590: int size, struct mmu_atc_line *cl) ! 591: { ! 592: uae_u32 tag = ATC_TAG(addr); ! 593: ! 594: if (USETAG && cl->tag == (uae_u16)~tag) { ! 595: redo: ! 596: if (cl->hw) ! 597: return HWget_b(cl->phys + addr); ! 598: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 599: return 0; ! 600: } ! 601: ! 602: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 603: goto redo; ! 604: ! 605: return phys_get_byte(mmu_get_real_address(addr, cl)); ! 606: } ! 607: ! 608: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data, ! 609: int size, struct mmu_atc_line *cl) ! 610: { ! 611: uae_u32 tag = ATC_TAG(addr); ! 612: ! 613: if (USETAG && cl->tag == (uae_u16)~tag) { ! 614: redo: ! 615: if (cl->hw) ! 616: return HWget_w(cl->phys + addr); ! 617: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 618: return 0; ! 619: } ! 620: ! 621: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 622: goto redo; ! 623: ! 624: return phys_get_word(mmu_get_real_address(addr, cl)); ! 625: } ! 626: ! 627: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data, ! 628: int size, struct mmu_atc_line *cl) ! 629: { ! 630: uae_u32 tag = ATC_TAG(addr); ! 631: ! 632: if (USETAG && cl->tag == (uae_u16)~tag) { ! 633: redo: ! 634: if (cl->hw) ! 635: return HWget_l(cl->phys + addr); ! 636: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 637: return 0; ! 638: } ! 639: ! 640: if (!mmu_fill_atc_l1(addr, super, data, 0, cl)) ! 641: goto redo; ! 642: ! 643: return phys_get_long(mmu_get_real_address(addr, cl)); ! 644: } ! 645: ! 646: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data) ! 647: { ! 648: SAVE_EXCEPTION; ! 649: TRY(prb) { ! 650: if (likely(!(addr & 1))) { ! 651: mmu_put_word(addr, val >> 16, data, sz_long); ! 652: mmu_put_word(addr + 2, val, data, sz_long); ! 653: } else { ! 654: mmu_put_byte(addr, val >> 24, data, sz_long); ! 655: mmu_put_byte(addr + 1, val >> 16, data, sz_long); ! 656: mmu_put_byte(addr + 2, val >> 8, data, sz_long); ! 657: mmu_put_byte(addr + 3, val, data, sz_long); ! 658: } ! 659: RESTORE_EXCEPTION; ! 660: } ! 661: CATCH(prb) { ! 662: RESTORE_EXCEPTION; ! 663: regs.wb3_data = val; ! 664: if (regs.mmu_fault_addr != addr) { ! 665: regs.mmu_fault_addr = addr; ! 666: regs.mmu_ssw |= MMU_SSW_MA; ! 667: } ! 668: THROW_AGAIN(prb); ! 669: } ENDTRY ! 670: } ! 671: ! 672: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data) ! 673: { ! 674: SAVE_EXCEPTION; ! 675: TRY(prb) { ! 676: mmu_put_byte(addr, val >> 8, data, sz_word); ! 677: mmu_put_byte(addr + 1, val, data, sz_word); ! 678: RESTORE_EXCEPTION; ! 679: } ! 680: CATCH(prb) { ! 681: RESTORE_EXCEPTION; ! 682: regs.wb3_data = val; ! 683: if (regs.mmu_fault_addr != addr) { ! 684: regs.mmu_fault_addr = addr; ! 685: regs.mmu_ssw |= MMU_SSW_MA; ! 686: } ! 687: THROW_AGAIN(prb); ! 688: } ENDTRY ! 689: } ! 690: ! 691: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data, ! 692: int size, struct mmu_atc_line *cl) ! 693: { ! 694: uae_u32 tag = ATC_TAG(addr); ! 695: ! 696: if (USETAG && cl->tag == (uae_u16)~tag) { ! 697: redo: ! 698: if (cl->hw) { ! 699: HWput_b(cl->phys + addr, val); ! 700: return; ! 701: } ! 702: regs.wb3_data = val; ! 703: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 704: return; ! 705: } ! 706: ! 707: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 708: goto redo; ! 709: ! 710: phys_put_byte(mmu_get_real_address(addr, cl), val); ! 711: } ! 712: ! 713: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data, ! 714: int size, struct mmu_atc_line *cl) ! 715: { ! 716: uae_u32 tag = ATC_TAG(addr); ! 717: ! 718: if (USETAG && cl->tag == (uae_u16)~tag) { ! 719: redo: ! 720: if (cl->hw) { ! 721: HWput_w(cl->phys + addr, val); ! 722: return; ! 723: } ! 724: regs.wb3_data = val; ! 725: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 726: return; ! 727: } ! 728: ! 729: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 730: goto redo; ! 731: ! 732: phys_put_word(mmu_get_real_address(addr, cl), val); ! 733: } ! 734: ! 735: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data, ! 736: int size, struct mmu_atc_line *cl) ! 737: { ! 738: uae_u32 tag = ATC_TAG(addr); ! 739: ! 740: if (USETAG && cl->tag == (uae_u16)~tag) { ! 741: redo: ! 742: if (cl->hw) { ! 743: HWput_l(cl->phys + addr, val); ! 744: return; ! 745: } ! 746: regs.wb3_data = val; ! 747: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 748: return; ! 749: } ! 750: ! 751: if (!mmu_fill_atc_l1(addr, super, data, 1, cl)) ! 752: goto redo; ! 753: ! 754: phys_put_long(mmu_get_real_address(addr, cl), val); ! 755: } ! 756: ! 757: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr) ! 758: { ! 759: bool super = (regs.sfc & 4) != 0; ! 760: bool data = (regs.sfc & 3) != 2; ! 761: uae_u32 res; ! 762: ! 763: if (likely(!is_unaligned(addr, 4))) ! 764: return mmu_get_user_long(addr, super, data, sz_long); ! 765: ! 766: if (likely(!(addr & 1))) { ! 767: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16; ! 768: SAVE_EXCEPTION; ! 769: TRY(prb) { ! 770: res |= mmu_get_user_word(addr + 2, super, data, sz_long); ! 771: RESTORE_EXCEPTION; ! 772: } ! 773: CATCH(prb) { ! 774: RESTORE_EXCEPTION; ! 775: regs.mmu_fault_addr = addr; ! 776: regs.mmu_ssw |= MMU_SSW_MA; ! 777: THROW_AGAIN(prb); ! 778: } ENDTRY ! 779: } else { ! 780: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8; ! 781: SAVE_EXCEPTION; ! 782: TRY(prb) { ! 783: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8; ! 784: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8; ! 785: res |= mmu_get_user_byte(addr + 3, super, data, sz_long); ! 786: RESTORE_EXCEPTION; ! 787: } ! 788: CATCH(prb) { ! 789: RESTORE_EXCEPTION; ! 790: regs.mmu_fault_addr = addr; ! 791: regs.mmu_ssw |= MMU_SSW_MA; ! 792: THROW_AGAIN(prb); ! 793: } ENDTRY ! 794: } ! 795: return res; ! 796: } ! 797: ! 798: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr) ! 799: { ! 800: bool super = (regs.sfc & 4) != 0; ! 801: bool data = (regs.sfc & 3) != 2; ! 802: uae_u16 res; ! 803: ! 804: if (likely(!is_unaligned(addr, 2))) ! 805: return mmu_get_user_word(addr, super, data, sz_word); ! 806: ! 807: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8; ! 808: SAVE_EXCEPTION; ! 809: TRY(prb) { ! 810: res |= mmu_get_user_byte(addr + 1, super, data, sz_word); ! 811: RESTORE_EXCEPTION; ! 812: } ! 813: CATCH(prb) { ! 814: RESTORE_EXCEPTION; ! 815: regs.mmu_fault_addr = addr; ! 816: regs.mmu_ssw |= MMU_SSW_MA; ! 817: THROW_AGAIN(prb); ! 818: } ENDTRY ! 819: return res; ! 820: } ! 821: ! 822: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr) ! 823: { ! 824: bool super = (regs.sfc & 4) != 0; ! 825: bool data = (regs.sfc & 3) != 2; ! 826: ! 827: return mmu_get_user_byte(addr, super, data, sz_byte); ! 828: } ! 829: ! 830: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val) ! 831: { ! 832: bool super = (regs.dfc & 4) != 0; ! 833: bool data = (regs.dfc & 3) != 2; ! 834: ! 835: SAVE_EXCEPTION; ! 836: TRY(prb) { ! 837: if (likely(!is_unaligned(addr, 4))) ! 838: mmu_put_user_long(addr, val, super, data, sz_long); ! 839: else if (likely(!(addr & 1))) { ! 840: mmu_put_user_word(addr, val >> 16, super, data, sz_long); ! 841: mmu_put_user_word(addr + 2, val, super, data, sz_long); ! 842: } else { ! 843: mmu_put_user_byte(addr, val >> 24, super, data, sz_long); ! 844: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long); ! 845: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long); ! 846: mmu_put_user_byte(addr + 3, val, super, data, sz_long); ! 847: } ! 848: RESTORE_EXCEPTION; ! 849: } ! 850: CATCH(prb) { ! 851: RESTORE_EXCEPTION; ! 852: regs.wb3_data = val; ! 853: if (regs.mmu_fault_addr != addr) { ! 854: regs.mmu_fault_addr = addr; ! 855: regs.mmu_ssw |= MMU_SSW_MA; ! 856: } ! 857: THROW_AGAIN(prb); ! 858: } ENDTRY ! 859: } ! 860: ! 861: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val) ! 862: { ! 863: bool super = (regs.dfc & 4) != 0; ! 864: bool data = (regs.dfc & 3) != 2; ! 865: ! 866: SAVE_EXCEPTION; ! 867: TRY(prb) { ! 868: if (likely(!is_unaligned(addr, 2))) ! 869: mmu_put_user_word(addr, val, super, data, sz_word); ! 870: else { ! 871: mmu_put_user_byte(addr, val >> 8, super, data, sz_word); ! 872: mmu_put_user_byte(addr + 1, val, super, data, sz_word); ! 873: } ! 874: RESTORE_EXCEPTION; ! 875: } ! 876: CATCH(prb) { ! 877: RESTORE_EXCEPTION; ! 878: regs.wb3_data = val; ! 879: if (regs.mmu_fault_addr != addr) { ! 880: regs.mmu_fault_addr = addr; ! 881: regs.mmu_ssw |= MMU_SSW_MA; ! 882: } ! 883: THROW_AGAIN(prb); ! 884: } ENDTRY ! 885: } ! 886: ! 887: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val) ! 888: { ! 889: bool super = (regs.dfc & 4) != 0; ! 890: bool data = (regs.dfc & 3) != 2; ! 891: ! 892: SAVE_EXCEPTION; ! 893: TRY(prb) { ! 894: mmu_put_user_byte(addr, val, super, data, sz_byte); ! 895: RESTORE_EXCEPTION; ! 896: } ! 897: CATCH(prb) { ! 898: RESTORE_EXCEPTION; ! 899: regs.wb3_data = val; ! 900: THROW_AGAIN(prb); ! 901: } ENDTRY ! 902: } ! 903: ! 904: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra) ! 905: { ! 906: bool super = (regs.dfc & 4) != 0; ! 907: DUNUSED(extra); ! 908: if ((opcode & 0xFE0) == 0x0500) { ! 909: bool glob; ! 910: int regno; ! 911: //D(didflush = 0); ! 912: uae_u32 addr; ! 913: /* PFLUSH */ ! 914: regno = opcode & 7; ! 915: glob = (opcode & 8) != 0; ! 916: ! 917: if (opcode & 16) { ! 918: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc); ! 919: mmu_flush_atc_all(glob); ! 920: } else { ! 921: addr = m68k_areg(regs, regno); ! 922: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr); ! 923: mmu_flush_atc(addr, super, glob); ! 924: } ! 925: flush_internals(); ! 926: #ifdef USE_JIT ! 927: flush_icache(0); ! 928: #endif ! 929: } else if ((opcode & 0x0FD8) == 0x548) { ! 930: bool write; ! 931: int regno; ! 932: uae_u32 addr; ! 933: ! 934: regno = opcode & 7; ! 935: write = (opcode & 32) == 0; ! 936: addr = m68k_areg(regs, regno); ! 937: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc); ! 938: mmu_flush_atc(addr, super, true); ! 939: SAVE_EXCEPTION; ! 940: TRY(prb) { ! 941: struct mmu_atc_line *l; ! 942: uae_u32 desc; ! 943: bool data = (regs.dfc & 3) != 2; ! 944: ! 945: l = &atc_l2[super ? 1 : 0][ATC_L2_INDEX(addr)]; ! 946: desc = mmu_fill_atc_l2(addr, super, data, write, l); ! 947: if (!(data ? l->valid_data : l->valid_inst)) ! 948: regs.mmusr = MMU_MMUSR_B; ! 949: else if (l->tt) ! 950: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R; ! 951: else { ! 952: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S| ! 953: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W); ! 954: regs.mmusr |= MMU_MMUSR_R; ! 955: } ! 956: } ! 957: CATCH(prb) { ! 958: regs.mmusr = MMU_MMUSR_B; ! 959: } ENDTRY ! 960: RESTORE_EXCEPTION; ! 961: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr); ! 962: } else ! 963: op_illg (opcode); ! 964: } ! 965: ! 966: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global) ! 967: { ! 968: struct mmu_atc_line *l; ! 969: int i, j; ! 970: ! 971: l = atc_l1[super ? 1 : 0][0][0]; ! 972: i = ATC_L1_INDEX(addr); ! 973: for (j = 0; j < 4; j++) { ! 974: if (global || !l[i].global) ! 975: l[i].tag = 0x8000; ! 976: l += ATC_L1_SIZE; ! 977: } ! 978: if (regs.mmu_pagesize_8k) { ! 979: i = ATC_L1_INDEX(addr) ^ 1; ! 980: for (j = 0; j < 4; j++) { ! 981: if (global || !l[i].global) ! 982: l[i].tag = 0x8000; ! 983: l += ATC_L1_SIZE; ! 984: } ! 985: } ! 986: l = atc_l2[super ? 1 : 0]; ! 987: i = ATC_L2_INDEX(addr); ! 988: if (global || !l[i].global) ! 989: l[i].tag = 0x8000; ! 990: if (regs.mmu_pagesize_8k) { ! 991: i ^= 1; ! 992: if (global || !l[i].global) ! 993: l[i].tag = 0x8000; ! 994: } ! 995: } ! 996: ! 997: void REGPARAM2 mmu_flush_atc_all(bool global) ! 998: { ! 999: struct mmu_atc_line *l; ! 1000: unsigned int i; ! 1001: ! 1002: l = atc_l1[0][0][0]; ! 1003: for (i = 0; i < sizeof(atc_l1) / sizeof(*l); l++, i++) { ! 1004: if (global || !l->global) ! 1005: l->tag = 0x8000; ! 1006: } ! 1007: ! 1008: l = atc_l2[0]; ! 1009: for (i = 0; i < sizeof(atc_l2) / sizeof(*l); l++, i++) { ! 1010: if (global || !l->global) ! 1011: l->tag = 0x8000; ! 1012: } ! 1013: } ! 1014: ! 1015: void REGPARAM2 mmu_reset(void) ! 1016: { ! 1017: mmu_flush_atc_all(true); ! 1018: #if 0 ! 1019: regs.urp = regs.srp = 0; ! 1020: regs.itt0 = regs.itt0 = 0; ! 1021: regs.dtt0 = regs.dtt0 = 0; ! 1022: regs.mmusr = 0; ! 1023: #endif ! 1024: } ! 1025: ! 1026: ! 1027: void REGPARAM2 mmu_set_tc(uae_u16 tc) ! 1028: { ! 1029: #if 0 ! 1030: if (regs.tcr == tc) ! 1031: return; ! 1032: regs.tcr = tc; ! 1033: #endif ! 1034: regs.mmu_enabled = tc & 0x8000 ? 1 : 0; ! 1035: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0; ! 1036: mmu_flush_atc_all(true); ! 1037: ! 1038: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k); ! 1039: } ! 1040: ! 1041: void REGPARAM2 mmu_set_super(bool super) ! 1042: { ! 1043: current_atc = &atc_l1[super ? 1 : 0]; ! 1044: } ! 1045: ! 1046: jmp_buf __exbuf; ! 1047: int __exvalue; ! 1048: #define MAX_TRY_STACK 256 ! 1049: static int s_try_stack_size=0; ! 1050: static jmp_buf s_try_stack[MAX_TRY_STACK]; ! 1051: jmp_buf* __poptry(void) { ! 1052: if (s_try_stack_size>0) { ! 1053: s_try_stack_size--; ! 1054: if (s_try_stack_size>0) ! 1055: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf)); ! 1056: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]); ! 1057: return &s_try_stack[s_try_stack_size]; ! 1058: } ! 1059: else { ! 1060: fprintf(stderr,"try stack underflow...\n"); ! 1061: exit(-1); ! 1062: } ! 1063: } ! 1064: void __pushtry(jmp_buf* j) { ! 1065: if (s_try_stack_size<MAX_TRY_STACK) { ! 1066: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]); ! 1067: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf)); ! 1068: s_try_stack_size++; ! 1069: } else { ! 1070: fprintf(stderr,"try stack overflow...\n"); ! 1071: exit(-1); ! 1072: } ! 1073: } ! 1074: int __is_catched(void) {return (s_try_stack_size>0); } ! 1075: #else ! 1076: ! 1077: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/) ! 1078: { ! 1079: if ((opcode & 0xFE0) == 0x0500) { ! 1080: /* PFLUSH instruction */ ! 1081: flush_internals(); ! 1082: } else if ((opcode & 0x0FD8) == 0x548) { ! 1083: /* PTEST instruction */ ! 1084: } else ! 1085: op_illg(opcode); ! 1086: } ! 1087: ! 1088: #endif ! 1089: ! 1090: /* ! 1091: vim:ts=4:sw=4: ! 1092: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.