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