|
|
1.1.1.2 ! root 1: /* ! 2: * cpummu.cpp - MMU emulation ! 3: * ! 4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS) ! 5: * ! 6: * Inspired by UAE MMU patch ! 7: * ! 8: * This file is part of the ARAnyM project which builds a new and powerful ! 9: * TOS/FreeMiNT compatible virtual machine running on almost any hardware. ! 10: * ! 11: * ARAnyM is free software; you can redistribute it and/or modify ! 12: * it under the terms of the GNU General Public License as published by ! 13: * the Free Software Foundation; either version 2 of the License, or ! 14: * (at your option) any later version. ! 15: * ! 16: * ARAnyM is distributed in the hope that it will be useful, ! 17: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 18: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 19: * GNU General Public License for more details. ! 20: * ! 21: * You should have received a copy of the GNU General Public License ! 22: * along with ARAnyM; if not, write to the Free Software ! 23: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 24: */ ! 25: ! 26: #define DEBUG 1 ! 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: ! 46: bool mmu_is_super; ! 47: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS]; ! 48: ! 49: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr) ! 50: { ! 51: DUNUSED(label); ! 52: uae_u32 from_addr, to_addr; ! 53: ! 54: from_addr = ttr & MMU_TTR_LOGICAL_BASE; ! 55: to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8; ! 56: ! 57: ! 58: fprintf(stderr, "%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n", ! 59: label, ttr, ! 60: from_addr, to_addr, ! 61: ttr & MMU_TTR_BIT_ENABLED ? 1 : 0, ! 62: (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT, ! 63: ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0, ! 64: (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT ! 65: ); ! 66: } ! 67: ! 68: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode) ! 69: { ! 70: uae_u32 * ttr; ! 71: uae_u32 * ttr0 = datamode ? ®s.dtt0 : ®s.itt0; ! 72: uae_u32 * ttr1 = datamode ? ®s.dtt1 : ®s.itt1; ! 73: ! 74: if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0) ! 75: ttr = ttr1; ! 76: else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0) ! 77: ttr = ttr0; ! 78: else ! 79: return; ! 80: ! 81: *ttr = baseaddr & MMU_TTR_LOGICAL_BASE; ! 82: *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8; ! 83: *ttr |= MMU_TTR_BIT_ENABLED; ! 84: ! 85: fprintf(stderr, "MMU: map transparent mapping of %08x\n", *ttr); ! 86: } ! 87: ! 88: ! 89: ! 90: #if 0 ! 91: /* {{{ mmu_dump_table */ ! 92: static void mmu_dump_table(const char * label, uaecptr root_ptr) ! 93: { ! 94: DUNUSED(label); ! 95: const int ROOT_TABLE_SIZE = 128, ! 96: PTR_TABLE_SIZE = 128, ! 97: PAGE_TABLE_SIZE = 64, ! 98: ROOT_INDEX_SHIFT = 25, ! 99: PTR_INDEX_SHIFT = 18; ! 100: // const int PAGE_INDEX_SHIFT = 12; ! 101: int root_idx, ptr_idx, page_idx; ! 102: uae_u32 root_des, ptr_des, page_des; ! 103: uaecptr ptr_des_addr, page_addr, ! 104: root_log, ptr_log, page_log; ! 105: ! 106: fprintf(stderr, "%s: root=%lx\n", label, root_ptr); ! 107: ! 108: for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) { ! 109: root_des = phys_get_long(root_ptr + root_idx); ! 110: ! 111: if ((root_des & 2) == 0) ! 112: continue; /* invalid */ ! 113: ! 114: fprintf(stderr, "ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx, ! 115: root_des & 8 ? 1 : 0, ! 116: root_des & 4 ? 1 : 0, ! 117: root_des & 3 ! 118: ); ! 119: ! 120: root_log = root_idx << ROOT_INDEX_SHIFT; ! 121: ! 122: ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK; ! 123: ! 124: for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) { ! 125: struct { ! 126: uaecptr log, phys; ! 127: int start_idx, n_pages; /* number of pages covered by this entry */ ! 128: uae_u32 match; ! 129: } page_info[PAGE_TABLE_SIZE]; ! 130: int n_pages_used; ! 131: ! 132: ptr_des = phys_get_long(ptr_des_addr + ptr_idx); ! 133: ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT); ! 134: ! 135: if ((ptr_des & 2) == 0) ! 136: continue; /* invalid */ ! 137: ! 138: page_addr = ptr_des & (regs.mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4); ! 139: ! 140: n_pages_used = -1; ! 141: for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) { ! 142: ! 143: page_des = phys_get_long(page_addr + page_idx); ! 144: page_log = ptr_log | (page_idx << 2); // ??? PAGE_INDEX_SHIFT ! 145: ! 146: switch (page_des & 3) { ! 147: case 0: /* invalid */ ! 148: continue; ! 149: case 1: case 3: /* resident */ ! 150: case 2: /* indirect */ ! 151: if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) { ! 152: /* use the next entry */ ! 153: n_pages_used++; ! 154: ! 155: page_info[n_pages_used].match = page_des; ! 156: page_info[n_pages_used].n_pages = 1; ! 157: page_info[n_pages_used].start_idx = page_idx; ! 158: page_info[n_pages_used].log = page_log; ! 159: } else { ! 160: page_info[n_pages_used].n_pages++; ! 161: } ! 162: break; ! 163: } ! 164: } ! 165: ! 166: if (n_pages_used == -1) ! 167: continue; ! 168: ! 169: fprintf(stderr, " PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx, ! 170: ptr_des & 8 ? 1 : 0, ! 171: ptr_des & 4 ? 1 : 0, ! 172: ptr_des & 3 ! 173: ); ! 174: ! 175: ! 176: for (page_idx = 0; page_idx <= n_pages_used; page_idx++) { ! 177: page_des = page_info[page_idx].match; ! 178: ! 179: if ((page_des & MMU_PDT_MASK) == 2) { ! 180: fprintf(stderr, " PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n", ! 181: page_info[page_idx].start_idx, ! 182: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 183: page_info[page_idx].log, ! 184: page_des & MMU_PAGE_INDIRECT_MASK ! 185: ); ! 186: ! 187: } else { ! 188: 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", ! 189: page_info[page_idx].start_idx, ! 190: page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1, ! 191: page_info[page_idx].log, ! 192: page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4), ! 193: (page_des & (regs.mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT, ! 194: page_des & MMU_DES_GLOBAL ? 1 : 0, ! 195: (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT, ! 196: page_des & MMU_DES_SUPER ? 1 : 0, ! 197: (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT, ! 198: page_des & MMU_DES_MODIFIED ? 1 : 0, ! 199: page_des & MMU_DES_USED ? 1 : 0, ! 200: page_des & MMU_DES_WP ? 1 : 0 ! 201: ); ! 202: } ! 203: } ! 204: } ! 205: ! 206: } ! 207: } ! 208: /* }}} */ ! 209: #endif ! 210: ! 211: /* {{{ mmu_dump_atc */ ! 212: void mmu_dump_atc(void) ! 213: { ! 214: ! 215: } ! 216: /* }}} */ ! 217: ! 218: /* {{{ mmu_dump_tables */ ! 219: void mmu_dump_tables(void) ! 220: { ! 221: fprintf(stderr, "URP: %08x SRP: %08x MMUSR: %x TC: %x\n", regs.urp, regs.srp, regs.mmusr, regs.tcr); ! 222: mmu_dump_ttr(L"DTT0", regs.dtt0); ! 223: mmu_dump_ttr(L"DTT1", regs.dtt1); ! 224: mmu_dump_ttr(L"ITT0", regs.itt0); ! 225: mmu_dump_ttr(L"ITT1", regs.itt1); ! 226: mmu_dump_atc(); ! 227: #if DEBUG ! 228: // mmu_dump_table("SRP", regs.srp); ! 229: #endif ! 230: } ! 231: /* }}} */ ! 232: ! 233: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write); ! 234: ! 235: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data) ! 236: { ! 237: return (super ? 4 : 0) | (data ? 1 : 2); ! 238: } ! 239: ! 240: static void mmu_bus_error(uaecptr addr, int fc, bool write, int size) ! 241: { ! 242: uae_u16 ssw = 0; ! 243: ! 244: ssw |= fc & MMU_SSW_TM; /* Copy TM */ ! 245: switch (size) { ! 246: case sz_byte: ! 247: ssw |= MMU_SSW_SIZE_B; ! 248: break; ! 249: case sz_word: ! 250: ssw |= MMU_SSW_SIZE_W; ! 251: break; ! 252: case sz_long: ! 253: ssw |= MMU_SSW_SIZE_L; ! 254: break; ! 255: } ! 256: ! 257: regs.wb3_status = write ? 0x80 | ssw : 0; ! 258: if (!write) ! 259: ssw |= MMU_SSW_RW; ! 260: ! 261: regs.mmu_fault_addr = addr; ! 262: regs.mmu_ssw = ssw | MMU_SSW_ATC; ! 263: ! 264: fprintf(stderr, "BUS ERROR: fc=%d w=%d logical=%08x ssw=%04x PC=%08x\n", fc, write, addr, ssw, m68k_getpc()); ! 265: ! 266: THROW(2); ! 267: } ! 268: ! 269: /* ! 270: * Update the atc line for a given address by doing a mmu lookup. ! 271: */ ! 272: static uaecptr mmu_fill_atc(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l) ! 273: { ! 274: int res; ! 275: uae_u32 desc; ! 276: ! 277: SAVE_EXCEPTION; ! 278: TRY(prb) { ! 279: desc = mmu_lookup_pagetable(addr, super, write); ! 280: #if DEBUG > 2 ! 281: fprintf(stderr, "translate: %x,%u,%u,%u -> %x\n", addr, super, write, data, desc); ! 282: #endif ! 283: RESTORE_EXCEPTION; ! 284: } ! 285: CATCH(prb) { ! 286: RESTORE_EXCEPTION; ! 287: /* bus error during table search */ ! 288: desc = 0; ! 289: // goto fail; ! 290: } ENDTRY ! 291: ! 292: if ((desc & 1) == 0 || (!super && desc & MMU_MMUSR_S)) { ! 293: fail: ! 294: l->valid = 0; ! 295: l->global = 0; ! 296: } else { ! 297: l->valid = 1; ! 298: if (regs.mmu_pagesize_8k) ! 299: l->phys = (desc & ~0x1fff); ! 300: else ! 301: l->phys = (desc & ~0xfff); ! 302: l->global = (desc & MMU_MMUSR_G) != 0; ! 303: l->modified = (desc & MMU_MMUSR_M) != 0; ! 304: l->write_protect = (desc & MMU_MMUSR_W) != 0; ! 305: } ! 306: ! 307: return desc; ! 308: } ! 309: ! 310: static ALWAYS_INLINE bool mmu_fill_atc_try(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1) ! 311: { ! 312: mmu_fill_atc(addr,super,data,write,l1); ! 313: if (!(l1->valid)) { ! 314: fprintf(stderr, "MMU: non-resident page (%x,%x,%x)!\n", addr, regs.pc, regs.fault_pc); ! 315: goto fail; ! 316: } ! 317: if (write) { ! 318: if (l1->write_protect) { ! 319: fprintf(stderr, "MMU: write protected %lx by atc \n", addr); ! 320: mmu_dump_atc(); ! 321: goto fail; ! 322: } ! 323: ! 324: } ! 325: return true; ! 326: ! 327: fail: ! 328: return false; ! 329: } ! 330: ! 331: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write) ! 332: { ! 333: struct mmu_atc_line *l; ! 334: ! 335: // this should return a miss but choose a valid line ! 336: mmu_user_lookup(addr, super, data, write, &l); ! 337: ! 338: mmu_fill_atc(addr, super, data, write, l); ! 339: if (!l->valid) { ! 340: fprintf(stderr, "[MMU] mmu_translate error"); ! 341: THROW(2); ! 342: } ! 343: ! 344: return l->phys | (addr & (regs.mmu_pagesize_8k?0x00001fff:0x00000fff)); ! 345: ! 346: } ! 347: ! 348: /* ! 349: * Lookup the address by walking the page table and updating ! 350: * the page descriptors accordingly. Returns the found descriptor ! 351: * or produces a bus error. ! 352: */ ! 353: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write) ! 354: { ! 355: uae_u32 desc, desc_addr, wp; ! 356: int i; ! 357: ! 358: wp = 0; ! 359: desc = super ? regs.srp : regs.urp; ! 360: ! 361: /* fetch root table descriptor */ ! 362: i = (addr >> 23) & 0x1fc; ! 363: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; ! 364: desc = phys_get_long(desc_addr); ! 365: if ((desc & 2) == 0) { ! 366: fprintf(stderr, "MMU: invalid root descriptor %s for %lx desc at %lx desc=%lx %s at %d\n", super ? "srp":"urp", ! 367: addr,desc_addr,desc,__FILE__,__LINE__); ! 368: return 0; ! 369: } ! 370: ! 371: wp |= desc; ! 372: if ((desc & MMU_DES_USED) == 0) ! 373: phys_put_long(desc_addr, desc | MMU_DES_USED); ! 374: ! 375: /* fetch pointer table descriptor */ ! 376: i = (addr >> 16) & 0x1fc; ! 377: desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i; ! 378: desc = phys_get_long(desc_addr); ! 379: if ((desc & 2) == 0) { ! 380: fprintf(stderr, "MMU: invalid ptr descriptor %s for %lx desc at %lx desc=%lx %s at %d\n", super ? "srp":"urp", ! 381: addr,desc_addr,desc,__FILE__,__LINE__); ! 382: return 0; ! 383: } ! 384: wp |= desc; ! 385: if ((desc & MMU_DES_USED) == 0) ! 386: phys_put_long(desc_addr, desc | MMU_DES_USED); ! 387: ! 388: /* fetch page table descriptor */ ! 389: if (regs.mmu_pagesize_8k) { ! 390: i = (addr >> 11) & 0x7c; ! 391: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i; ! 392: } else { ! 393: i = (addr >> 10) & 0xfc; ! 394: desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i; ! 395: } ! 396: ! 397: desc = phys_get_long(desc_addr); ! 398: if ((desc & 3) == 2) { ! 399: /* indirect */ ! 400: desc_addr = desc & MMU_PAGE_INDIRECT_MASK; ! 401: desc = phys_get_long(desc_addr); ! 402: } ! 403: if ((desc & 1) == 0) { ! 404: fprintf(stderr, "MMU: invalid page descriptor log=%08lx desc=%08lx @%08lx %s at %d\n", addr, desc, desc_addr,__FILE__,__LINE__); ! 405: return desc; ! 406: } ! 407: ! 408: desc |= wp & MMU_DES_WP; ! 409: if (write) { ! 410: if (desc & MMU_DES_WP) { ! 411: if ((desc & MMU_DES_USED) == 0) { ! 412: desc |= MMU_DES_USED; ! 413: phys_put_long(desc_addr, desc); ! 414: } ! 415: } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) != ! 416: (MMU_DES_USED|MMU_DES_MODIFIED)) { ! 417: desc |= MMU_DES_USED|MMU_DES_MODIFIED; ! 418: phys_put_long(desc_addr, desc); ! 419: } ! 420: } else { ! 421: if ((desc & MMU_DES_USED) == 0) { ! 422: desc |= MMU_DES_USED; ! 423: phys_put_long(desc_addr, desc); ! 424: } ! 425: } ! 426: return desc; ! 427: } ! 428: ! 429: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data) ! 430: { ! 431: uae_u16 res; ! 432: ! 433: res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8; ! 434: SAVE_EXCEPTION; ! 435: TRY(prb) { ! 436: res |= mmu_get_byte(addr + 1, data, sz_word); ! 437: RESTORE_EXCEPTION; ! 438: } ! 439: CATCH(prb) { ! 440: RESTORE_EXCEPTION; ! 441: regs.mmu_fault_addr = addr; ! 442: regs.mmu_ssw |= MMU_SSW_MA; ! 443: THROW_AGAIN(prb); ! 444: } ENDTRY ! 445: return res; ! 446: } ! 447: ! 448: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data) ! 449: { ! 450: uae_u32 res; ! 451: ! 452: if (likely(!(addr & 1))) { ! 453: res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16; ! 454: SAVE_EXCEPTION; ! 455: TRY(prb) { ! 456: res |= mmu_get_word(addr + 2, data, sz_long); ! 457: RESTORE_EXCEPTION; ! 458: } ! 459: CATCH(prb) { ! 460: RESTORE_EXCEPTION; ! 461: regs.mmu_fault_addr = addr; ! 462: regs.mmu_ssw |= MMU_SSW_MA; ! 463: THROW_AGAIN(prb); ! 464: } ENDTRY ! 465: } else { ! 466: res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8; ! 467: SAVE_EXCEPTION; ! 468: TRY(prb) { ! 469: res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8; ! 470: res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8; ! 471: res |= mmu_get_byte(addr + 3, data, sz_long); ! 472: RESTORE_EXCEPTION; ! 473: } ! 474: CATCH(prb) { ! 475: RESTORE_EXCEPTION; ! 476: regs.mmu_fault_addr = addr; ! 477: regs.mmu_ssw |= MMU_SSW_MA; ! 478: THROW_AGAIN(prb); ! 479: } ENDTRY ! 480: } ! 481: return res; ! 482: } ! 483: ! 484: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data, ! 485: int size, struct mmu_atc_line *cl) ! 486: { ! 487: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) { ! 488: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 489: return 0; ! 490: } ! 491: return phys_get_byte(mmu_get_real_address(addr, cl)); ! 492: } ! 493: ! 494: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data, ! 495: int size, struct mmu_atc_line *cl) ! 496: { ! 497: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) { ! 498: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 499: return 0; ! 500: } ! 501: return phys_get_word(mmu_get_real_address(addr, cl)); ! 502: } ! 503: ! 504: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data, ! 505: int size, struct mmu_atc_line *cl) ! 506: { ! 507: if (!mmu_fill_atc_try(addr, super, data, 0, cl)) { ! 508: mmu_bus_error(addr, mmu_get_fc(super, data), 0, size); ! 509: return 0; ! 510: } ! 511: return phys_get_long(mmu_get_real_address(addr, cl)); ! 512: } ! 513: ! 514: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data) ! 515: { ! 516: SAVE_EXCEPTION; ! 517: TRY(prb) { ! 518: if (likely(!(addr & 1))) { ! 519: mmu_put_word(addr, val >> 16, data, sz_long); ! 520: mmu_put_word(addr + 2, val, data, sz_long); ! 521: } else { ! 522: mmu_put_byte(addr, val >> 24, data, sz_long); ! 523: mmu_put_byte(addr + 1, val >> 16, data, sz_long); ! 524: mmu_put_byte(addr + 2, val >> 8, data, sz_long); ! 525: mmu_put_byte(addr + 3, val, data, sz_long); ! 526: } ! 527: RESTORE_EXCEPTION; ! 528: } ! 529: CATCH(prb) { ! 530: RESTORE_EXCEPTION; ! 531: regs.wb3_data = val; ! 532: if (regs.mmu_fault_addr != addr) { ! 533: regs.mmu_fault_addr = addr; ! 534: regs.mmu_ssw |= MMU_SSW_MA; ! 535: } ! 536: THROW_AGAIN(prb); ! 537: } ENDTRY ! 538: } ! 539: ! 540: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data) ! 541: { ! 542: SAVE_EXCEPTION; ! 543: TRY(prb) { ! 544: mmu_put_byte(addr, val >> 8, data, sz_word); ! 545: mmu_put_byte(addr + 1, val, data, sz_word); ! 546: RESTORE_EXCEPTION; ! 547: } ! 548: CATCH(prb) { ! 549: RESTORE_EXCEPTION; ! 550: regs.wb3_data = val; ! 551: if (regs.mmu_fault_addr != addr) { ! 552: regs.mmu_fault_addr = addr; ! 553: regs.mmu_ssw |= MMU_SSW_MA; ! 554: } ! 555: THROW_AGAIN(prb); ! 556: } ENDTRY ! 557: } ! 558: ! 559: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data, ! 560: int size, struct mmu_atc_line *cl) ! 561: { ! 562: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) { ! 563: regs.wb3_data = val; ! 564: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 565: return; ! 566: } ! 567: phys_put_byte(mmu_get_real_address(addr, cl), val); ! 568: } ! 569: ! 570: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data, ! 571: int size, struct mmu_atc_line *cl) ! 572: { ! 573: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) { ! 574: regs.wb3_data = val; ! 575: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 576: return; ! 577: } ! 578: phys_put_word(mmu_get_real_address(addr, cl), val); ! 579: } ! 580: ! 581: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data, ! 582: int size, struct mmu_atc_line *cl) ! 583: { ! 584: if (!mmu_fill_atc_try(addr, super, data, 1, cl)) { ! 585: regs.wb3_data = val; ! 586: mmu_bus_error(addr, mmu_get_fc(super, data), 1, size); ! 587: return; ! 588: } ! 589: phys_put_long(mmu_get_real_address(addr, cl), val); ! 590: } ! 591: ! 592: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr) ! 593: { ! 594: bool super = (regs.sfc & 4) != 0; ! 595: bool data = (regs.sfc & 3) != 2; ! 596: uae_u32 res; ! 597: ! 598: if (likely(!is_unaligned(addr, 4))) ! 599: return mmu_get_user_long(addr, super, data, sz_long); ! 600: ! 601: if (likely(!(addr & 1))) { ! 602: res = (uae_u32)mmu_get_user_word(addr, super, data, sz_long) << 16; ! 603: SAVE_EXCEPTION; ! 604: TRY(prb) { ! 605: res |= mmu_get_user_word(addr + 2, super, data, sz_long); ! 606: RESTORE_EXCEPTION; ! 607: } ! 608: CATCH(prb) { ! 609: RESTORE_EXCEPTION; ! 610: regs.mmu_fault_addr = addr; ! 611: regs.mmu_ssw |= MMU_SSW_MA; ! 612: THROW_AGAIN(prb); ! 613: } ENDTRY ! 614: } else { ! 615: res = (uae_u32)mmu_get_user_byte(addr, super, data, sz_long) << 8; ! 616: SAVE_EXCEPTION; ! 617: TRY(prb) { ! 618: res = (res | mmu_get_user_byte(addr + 1, super, data, sz_long)) << 8; ! 619: res = (res | mmu_get_user_byte(addr + 2, super, data, sz_long)) << 8; ! 620: res |= mmu_get_user_byte(addr + 3, super, data, sz_long); ! 621: RESTORE_EXCEPTION; ! 622: } ! 623: CATCH(prb) { ! 624: RESTORE_EXCEPTION; ! 625: regs.mmu_fault_addr = addr; ! 626: regs.mmu_ssw |= MMU_SSW_MA; ! 627: THROW_AGAIN(prb); ! 628: } ENDTRY ! 629: } ! 630: return res; ! 631: } ! 632: ! 633: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr) ! 634: { ! 635: bool super = (regs.sfc & 4) != 0; ! 636: bool data = (regs.sfc & 3) != 2; ! 637: uae_u16 res; ! 638: ! 639: if (likely(!is_unaligned(addr, 2))) ! 640: return mmu_get_user_word(addr, super, data, sz_word); ! 641: ! 642: res = (uae_u16)mmu_get_user_byte(addr, super, data, sz_word) << 8; ! 643: SAVE_EXCEPTION; ! 644: TRY(prb) { ! 645: res |= mmu_get_user_byte(addr + 1, super, data, sz_word); ! 646: RESTORE_EXCEPTION; ! 647: } ! 648: CATCH(prb) { ! 649: RESTORE_EXCEPTION; ! 650: regs.mmu_fault_addr = addr; ! 651: regs.mmu_ssw |= MMU_SSW_MA; ! 652: THROW_AGAIN(prb); ! 653: } ENDTRY ! 654: return res; ! 655: } ! 656: ! 657: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr) ! 658: { ! 659: bool super = (regs.sfc & 4) != 0; ! 660: bool data = (regs.sfc & 3) != 2; ! 661: ! 662: return mmu_get_user_byte(addr, super, data, sz_byte); ! 663: } ! 664: ! 665: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val) ! 666: { ! 667: bool super = (regs.dfc & 4) != 0; ! 668: bool data = (regs.dfc & 3) != 2; ! 669: ! 670: SAVE_EXCEPTION; ! 671: TRY(prb) { ! 672: if (likely(!is_unaligned(addr, 4))) ! 673: mmu_put_user_long(addr, val, super, data, sz_long); ! 674: else if (likely(!(addr & 1))) { ! 675: mmu_put_user_word(addr, val >> 16, super, data, sz_long); ! 676: mmu_put_user_word(addr + 2, val, super, data, sz_long); ! 677: } else { ! 678: mmu_put_user_byte(addr, val >> 24, super, data, sz_long); ! 679: mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long); ! 680: mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long); ! 681: mmu_put_user_byte(addr + 3, val, super, data, sz_long); ! 682: } ! 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: THROW_AGAIN(prb); ! 693: } ENDTRY ! 694: } ! 695: ! 696: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val) ! 697: { ! 698: bool super = (regs.dfc & 4) != 0; ! 699: bool data = (regs.dfc & 3) != 2; ! 700: ! 701: SAVE_EXCEPTION; ! 702: TRY(prb) { ! 703: if (likely(!is_unaligned(addr, 2))) ! 704: mmu_put_user_word(addr, val, super, data, sz_word); ! 705: else { ! 706: mmu_put_user_byte(addr, val >> 8, super, data, sz_word); ! 707: mmu_put_user_byte(addr + 1, val, super, data, sz_word); ! 708: } ! 709: RESTORE_EXCEPTION; ! 710: } ! 711: CATCH(prb) { ! 712: RESTORE_EXCEPTION; ! 713: regs.wb3_data = val; ! 714: if (regs.mmu_fault_addr != addr) { ! 715: regs.mmu_fault_addr = addr; ! 716: regs.mmu_ssw |= MMU_SSW_MA; ! 717: } ! 718: THROW_AGAIN(prb); ! 719: } ENDTRY ! 720: } ! 721: ! 722: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val) ! 723: { ! 724: bool super = (regs.dfc & 4) != 0; ! 725: bool data = (regs.dfc & 3) != 2; ! 726: ! 727: SAVE_EXCEPTION; ! 728: TRY(prb) { ! 729: mmu_put_user_byte(addr, val, super, data, sz_byte); ! 730: RESTORE_EXCEPTION; ! 731: } ! 732: CATCH(prb) { ! 733: RESTORE_EXCEPTION; ! 734: regs.wb3_data = val; ! 735: THROW_AGAIN(prb); ! 736: } ENDTRY ! 737: } ! 738: ! 739: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra) ! 740: { ! 741: bool super = (regs.dfc & 4) != 0; ! 742: DUNUSED(extra); ! 743: if ((opcode & 0xFE0) == 0x0500) { ! 744: bool glob; ! 745: int regno; ! 746: //D(didflush = 0); ! 747: uae_u32 addr; ! 748: /* PFLUSH */ ! 749: regno = opcode & 7; ! 750: glob = (opcode & 8) != 0; ! 751: ! 752: if (opcode & 16) { ! 753: fprintf(stderr, "pflusha(%u,%u)\n", glob, regs.dfc); ! 754: mmu_flush_atc_all(glob); ! 755: } else { ! 756: addr = m68k_areg(regs, regno); ! 757: fprintf(stderr, "pflush(%u,%u,%x)\n", glob, regs.dfc, addr); ! 758: mmu_flush_atc(addr, super, glob); ! 759: } ! 760: flush_internals(); ! 761: #ifdef USE_JIT ! 762: flush_icache(0); ! 763: #endif ! 764: } else if ((opcode & 0x0FD8) == 0x548) { ! 765: bool write; ! 766: int regno; ! 767: uae_u32 addr; ! 768: ! 769: regno = opcode & 7; ! 770: write = (opcode & 32) == 0; ! 771: addr = m68k_areg(regs, regno); ! 772: fprintf(stderr, "PTEST%c (A%d) %08x DFC=%d\n", write ? 'W' : 'R', regno, addr, regs.dfc); ! 773: mmu_flush_atc(addr, super, true); ! 774: SAVE_EXCEPTION; ! 775: TRY(prb) { ! 776: struct mmu_atc_line *l; ! 777: uae_u32 desc; ! 778: bool data = (regs.dfc & 3) != 2; ! 779: ! 780: if (mmu_match_ttr(addr,super,data)!=TTR_NO_MATCH) ! 781: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R; ! 782: else { ! 783: mmu_user_lookup(addr, super, data, write, &l); ! 784: desc = mmu_fill_atc(addr, super, data, write, l); ! 785: if (!(l->valid)) ! 786: regs.mmusr = MMU_MMUSR_B; ! 787: else { ! 788: regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S| ! 789: MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W); ! 790: regs.mmusr |= MMU_MMUSR_R; ! 791: } ! 792: } ! 793: } ! 794: CATCH(prb) { ! 795: regs.mmusr = MMU_MMUSR_B; ! 796: } ENDTRY ! 797: RESTORE_EXCEPTION; ! 798: fprintf(stderr, "PTEST result: mmusr %08x\n", regs.mmusr); ! 799: } else ! 800: op_illg (opcode); ! 801: } ! 802: ! 803: // fixme : global parameter? ! 804: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global) ! 805: { ! 806: int way,type,index; ! 807: ! 808: addr = ((mmu_is_super?0x80000000:0x00000000)|(addr >> 1)) & (regs.mmu_pagesize_8k?0xFFFE0000:0xFFFF0000); ! 809: if (regs.mmu_pagesize_8k) ! 810: index=(addr & 0x0001E000)>>13; ! 811: else ! 812: index=(addr & 0x0000F000)>>12; ! 813: for (type=0;type<ATC_TYPE;type++) ! 814: for (way=0;way<ATC_WAYS;way++) { ! 815: if (!global && mmu_atc_array[type][way][index].global) ! 816: continue; ! 817: // if we have this ! 818: if ((addr == mmu_atc_array[type][way][index].tag) && (mmu_atc_array[type][way][index].valid)) { ! 819: mmu_atc_array[type][way][index].valid=false; ! 820: } ! 821: } ! 822: } ! 823: ! 824: void REGPARAM2 mmu_flush_atc_all(bool global) ! 825: { ! 826: unsigned int way,slot,type; ! 827: for (type=0;type<ATC_TYPE;type++) ! 828: for (way=0;way<ATC_WAYS;way++) ! 829: for (slot=0;slot<ATC_SLOTS;slot++) { ! 830: if (!global && mmu_atc_array[type][way][slot].global) ! 831: continue; ! 832: mmu_atc_array[type][way][slot].valid=false; ! 833: } ! 834: } ! 835: ! 836: void REGPARAM2 mmu_reset(void) ! 837: { ! 838: mmu_flush_atc_all(true); ! 839: } ! 840: ! 841: ! 842: void REGPARAM2 mmu_set_tc(uae_u16 tc) ! 843: { ! 844: regs.mmu_enabled = tc & 0x8000 ? 1 : 0; ! 845: regs.mmu_pagesize_8k = tc & 0x4000 ? 1 : 0; ! 846: mmu_flush_atc_all(true); ! 847: ! 848: write_log("MMU: enabled=%d page8k=%d\n", regs.mmu_enabled, regs.mmu_pagesize_8k); ! 849: } ! 850: ! 851: void REGPARAM2 mmu_set_super(bool super) ! 852: { ! 853: mmu_is_super=super; ! 854: } ! 855: ! 856: jmp_buf __exbuf; ! 857: int __exvalue; ! 858: #define MAX_TRY_STACK 256 ! 859: static int s_try_stack_size=0; ! 860: static jmp_buf s_try_stack[MAX_TRY_STACK]; ! 861: jmp_buf* __poptry(void) { ! 862: if (s_try_stack_size>0) { ! 863: s_try_stack_size--; ! 864: if (s_try_stack_size>0) ! 865: memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf)); ! 866: // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]); ! 867: return &s_try_stack[s_try_stack_size-1]; ! 868: } ! 869: else { ! 870: fprintf(stderr,"try stack underflow...\n"); ! 871: // return (NULL); ! 872: abort(); ! 873: } ! 874: } ! 875: void __pushtry(jmp_buf* j) { ! 876: if (s_try_stack_size<MAX_TRY_STACK) { ! 877: // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]); ! 878: memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf)); ! 879: s_try_stack_size++; ! 880: } else { ! 881: fprintf(stderr,"try stack overflow...\n"); ! 882: abort(); ! 883: } ! 884: } ! 885: int __is_catched(void) {return (s_try_stack_size>0); } ! 886: #else ! 887: ! 888: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/) ! 889: { ! 890: if ((opcode & 0xFE0) == 0x0500) { ! 891: /* PFLUSH instruction */ ! 892: flush_internals(); ! 893: } else if ((opcode & 0x0FD8) == 0x548) { ! 894: /* PTEST instruction */ ! 895: } else ! 896: op_illg(opcode); ! 897: } ! 898: ! 899: #endif ! 900: ! 901: /* ! 902: vim:ts=4:sw=4: ! 903: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.