Annotation of hatari/src/cpu/cpummu.c, revision 1.1.1.7

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)
1.1.1.5   root        5:  * 
1.1.1.3   root        6:  * Inspired by UAE MMU patch
                      7:  *
                      8:  * This file is part of the ARAnyM project which builds a new and powerful
                      9:  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
                     10:  *
                     11:  * ARAnyM is free software; you can redistribute it and/or modify
                     12:  * it under the terms of the GNU General Public License as published by
                     13:  * the Free Software Foundation; either version 2 of the License, or
                     14:  * (at your option) any later version.
                     15:  *
                     16:  * ARAnyM is distributed in the hope that it will be useful,
                     17:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19:  * GNU General Public License for more details.
                     20:  *
                     21:  * You should have received a copy of the GNU General Public License
1.1.1.7 ! root       22:  * along with ARAnyM; if not, write to the Free Software Foundation,
        !            23:  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
1.1.1.3   root       24:  */
                     25: 
                     26: 
                     27: #include "sysconfig.h"
                     28: #include "sysdeps.h"
                     29: 
1.1.1.5   root       30: #include "main.h"
                     31: #include "hatari-glue.h"
                     32: 
                     33: 
1.1.1.3   root       34: #include "options_cpu.h"
                     35: #include "memory.h"
                     36: #include "newcpu.h"
                     37: #include "cpummu.h"
1.1.1.5   root       38: #include "debug.h"
                     39: 
1.1.1.7 ! root       40: #define MMUDUMP 1
1.1.1.3   root       41: 
                     42: #define DBG_MMU_VERBOSE        1
                     43: #define DBG_MMU_SANITY 1
1.1.1.5   root       44: #if 0
1.1.1.3   root       45: #define write_log printf
1.1.1.5   root       46: #endif
1.1.1.3   root       47: 
                     48: #ifdef FULLMMU
                     49: 
1.1.1.5   root       50: uae_u32 mmu_is_super;
                     51: uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
1.1.1.7 ! root       52: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_SLOTS][ATC_WAYS];
1.1.1.5   root       53: bool mmu_pagesize_8k;
1.1.1.7 ! root       54: int mmu_pageshift, mmu_pageshift1m;
        !            55: uae_u8 mmu_cache_state;
        !            56: uae_u8 cache_default_ins, cache_default_data;
1.1.1.5   root       57: 
                     58: int mmu060_state;
                     59: uae_u16 mmu_opcode;
                     60: bool mmu_restart;
                     61: static bool locked_rmw_cycle;
1.1.1.7 ! root       62: bool rmw_cycle;
1.1.1.5   root       63: static bool ismoves;
1.1.1.7 ! root       64: bool mmu_ttr_enabled, mmu_ttr_enabled_ins, mmu_ttr_enabled_data;
        !            65: int mmu_atc_ways[2];
        !            66: int way_random;
1.1.1.5   root       67: 
                     68: int mmu040_movem;
                     69: uaecptr mmu040_movem_ea;
                     70: uae_u32 mmu040_move16[4];
1.1.1.3   root       71: 
1.1.1.7 ! root       72: #if MMU_ICACHE
        !            73: struct mmu_icache mmu_icache_data[MMU_ICACHE_SZ];
        !            74: #endif
        !            75: #if MMU_IPAGECACHE
        !            76: uae_u32 atc_last_ins_laddr, atc_last_ins_paddr;
        !            77: uae_u8 atc_last_ins_cache;
        !            78: #endif
        !            79: #if MMU_DPAGECACHE
        !            80: struct mmufastcache atc_data_cache_read[MMUFASTCACHE_ENTRIES];
        !            81: struct mmufastcache atc_data_cache_write[MMUFASTCACHE_ENTRIES];
        !            82: #endif
        !            83: 
        !            84: #if CACHE_HIT_COUNT
        !            85: int mmu_ins_hit, mmu_ins_miss;
        !            86: int mmu_data_read_hit, mmu_data_read_miss;
        !            87: int mmu_data_write_hit, mmu_data_write_miss;
        !            88: #endif
        !            89: 
1.1.1.3   root       90: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
                     91: {
                     92:        DUNUSED(label);
1.1.1.6   root       93: #if MMUDEBUG > 0
1.1.1.3   root       94:        uae_u32 from_addr, to_addr;
                     95: 
                     96:        from_addr = ttr & MMU_TTR_LOGICAL_BASE;
                     97:        to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
                     98: 
1.1.1.7 ! root       99:        console_out_f(_T("%s: [%08x] %08x - %08x enabled=%d supervisor=%d wp=%d cm=%02d\n"),
1.1.1.3   root      100:                        label, ttr,
                    101:                        from_addr, to_addr,
                    102:                        ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
                    103:                        (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
                    104:                        ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
                    105:                        (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
                    106:                  );
1.1.1.5   root      107: #endif
1.1.1.3   root      108: }
                    109: 
                    110: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
                    111: {
                    112:        uae_u32 * ttr;
                    113:        uae_u32 * ttr0 = datamode ? &regs.dtt0 : &regs.itt0;
                    114:        uae_u32 * ttr1 = datamode ? &regs.dtt1 : &regs.itt1;
                    115: 
                    116:        if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
                    117:                ttr = ttr1;
                    118:        else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
                    119:                ttr = ttr0;
                    120:        else
                    121:                return;
                    122: 
                    123:        *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
                    124:        *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
                    125:        *ttr |= MMU_TTR_BIT_ENABLED;
                    126: 
1.1.1.5   root      127: #if MMUDEBUG > 0
                    128:        write_log(_T("MMU: map transparent mapping of %08x\n"), *ttr);
                    129: #endif
1.1.1.3   root      130: }
                    131: 
1.1.1.5   root      132: void mmu_tt_modified (void)
1.1.1.3   root      133: {
1.1.1.7 ! root      134:        mmu_ttr_enabled_ins = ((regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
        !           135:        mmu_ttr_enabled_data = ((regs.dtt0 | regs.dtt1) & MMU_TTR_BIT_ENABLED) != 0;
        !           136:        mmu_ttr_enabled = mmu_ttr_enabled_ins || mmu_ttr_enabled_data;
1.1.1.5   root      137: }
1.1.1.3   root      138: 
                    139: 
1.1.1.5   root      140: #if MMUDUMP
1.1.1.3   root      141: 
1.1.1.5   root      142: /* This dump output makes much more sense than old one */
1.1.1.3   root      143: 
1.1.1.7 ! root      144: #ifdef WINUAE_FOR_HATARI
        !           145: #define        ULONG   Uint32
        !           146: #endif
        !           147: 
1.1.1.5   root      148: #define LEVELA_SIZE 7
                    149: #define LEVELB_SIZE 7
                    150: #define LEVELC_SIZE 6
                    151: #define PAGE_SIZE 12 // = 1 << 12 = 4096
                    152: 
                    153: #define LEVELA_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE                            ))) & ((1 << LEVELA_SIZE) - 1))
                    154: #define LEVELB_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE + LEVELB_SIZE              ))) & ((1 << LEVELB_SIZE) - 1))
                    155: #define LEVELC_VAL(x) ((((uae_u32)(x)) >> (32 - (LEVELA_SIZE + LEVELB_SIZE + LEVELC_SIZE))) & ((1 << LEVELC_SIZE) - 1))
1.1.1.3   root      156: 
1.1.1.5   root      157: #define LEVELA(root, x) (get_long(root + LEVELA_VAL(x) * 4))
                    158: #define LEVELB(a, x) (get_long((((uae_u32)a) & ~((1 << (LEVELB_SIZE + 2)) - 1)) + LEVELB_VAL(x) * 4))
                    159: #define LEVELC(b, x) (get_long((((uae_u32)b) & ~((1 << (LEVELC_SIZE + 2)) - 1)) + LEVELC_VAL(x) * 4))
                    160: 
                    161: #define ISINVALID(x) ((((ULONG)x) & 3) == 0)
                    162: 
                    163: static uae_u32 getdesc(uae_u32 root, uae_u32 addr)
1.1.1.3   root      164: {
1.1.1.5   root      165:        ULONG desc;
1.1.1.3   root      166: 
1.1.1.5   root      167:        desc = LEVELA(root, addr);
                    168:        if (ISINVALID(desc))
                    169:                return desc;
                    170:        desc = LEVELB(desc, addr);
                    171:        if (ISINVALID(desc))
                    172:                return desc;
                    173:        desc = LEVELC(desc, addr);
                    174:        return desc;
1.1.1.3   root      175: }
1.1.1.5   root      176: static void mmu_dump_table(const char * label, uaecptr root_ptr)
                    177: {
                    178:        ULONG i;
                    179:        ULONG startaddr;
                    180:        ULONG odesc;
                    181:        ULONG totalpages;
                    182:        ULONG pagemask = (1 << PAGE_SIZE) - 1;
                    183: 
1.1.1.7 ! root      184:        root_ptr &= 0xfffffe00;
1.1.1.5   root      185:        console_out_f(_T("MMU dump start. Root = %08x\n"), root_ptr);
                    186:        totalpages = 1 << (32 - PAGE_SIZE);
                    187:        startaddr = 0;
                    188:        odesc = getdesc(root_ptr, startaddr);
                    189:        for (i = 0; i <= totalpages; i++) {
                    190:                ULONG addr = i << PAGE_SIZE;
                    191:                ULONG desc = 0;
                    192:                if (i < totalpages)
                    193:                        desc = getdesc(root_ptr, addr);
                    194:                if ((desc & pagemask) != (odesc & pagemask) || i == totalpages) {
                    195:                        uae_u8 cm, sp;
                    196:                        cm = (odesc >> 5) & 3;
                    197:                        sp = (odesc >> 7) & 1;
                    198:                        console_out_f(_T("%08x - %08x: %08x WP=%d S=%d CM=%d (%08x)\n"),
                    199:                                startaddr, addr - 1, odesc & ~((1 << PAGE_SIZE) - 1),
                    200:                                (odesc & 4) ? 1 : 0, sp, cm, odesc);
                    201:                        startaddr = addr;
                    202:                        odesc = desc;
                    203:                }
                    204:        }
                    205:        console_out_f(_T("MMU dump end\n"));
                    206: }                      
1.1.1.3   root      207: 
1.1.1.5   root      208: #else
1.1.1.3   root      209: /* {{{ mmu_dump_table */
                    210: static void mmu_dump_table(const char * label, uaecptr root_ptr)
                    211: {
                    212:        DUNUSED(label);
                    213:        const int ROOT_TABLE_SIZE = 128,
                    214:                PTR_TABLE_SIZE = 128,
                    215:                PAGE_TABLE_SIZE = 64,
                    216:                ROOT_INDEX_SHIFT = 25,
                    217:                PTR_INDEX_SHIFT = 18;
                    218:        // const int PAGE_INDEX_SHIFT = 12;
                    219:        int root_idx, ptr_idx, page_idx;
                    220:        uae_u32 root_des, ptr_des, page_des;
                    221:        uaecptr ptr_des_addr, page_addr,
                    222:                root_log, ptr_log, page_log;
                    223: 
1.1.1.5   root      224:        console_out_f(_T("%s: root=%x\n"), label, root_ptr);
1.1.1.3   root      225: 
                    226:        for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
                    227:                root_des = phys_get_long(root_ptr + root_idx);
                    228: 
                    229:                if ((root_des & 2) == 0)
                    230:                        continue;       /* invalid */
                    231: 
1.1.1.5   root      232:                console_out_f(_T("ROOT: %03d U=%d W=%d UDT=%02d\n"), root_idx,
1.1.1.3   root      233:                                root_des & 8 ? 1 : 0,
                    234:                                root_des & 4 ? 1 : 0,
                    235:                                root_des & 3
                    236:                          );
                    237: 
                    238:                root_log = root_idx << ROOT_INDEX_SHIFT;
                    239: 
                    240:                ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
                    241: 
                    242:                for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
                    243:                        struct {
                    244:                                uaecptr log, phys;
                    245:                                int start_idx, n_pages; /* number of pages covered by this entry */
                    246:                                uae_u32 match;
                    247:                        } page_info[PAGE_TABLE_SIZE];
                    248:                        int n_pages_used;
                    249: 
                    250:                        ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
                    251:                        ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
                    252: 
                    253:                        if ((ptr_des & 2) == 0)
                    254:                                continue; /* invalid */
                    255: 
1.1.1.5   root      256:                        page_addr = ptr_des & (mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
1.1.1.3   root      257: 
                    258:                        n_pages_used = -1;
                    259:                        for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
                    260: 
                    261:                                page_des = phys_get_long(page_addr + page_idx);
                    262:                                page_log = ptr_log | (page_idx << 2);           // ??? PAGE_INDEX_SHIFT
                    263: 
                    264:                                switch (page_des & 3) {
                    265:                                        case 0: /* invalid */
                    266:                                                continue;
                    267:                                        case 1: case 3: /* resident */
                    268:                                        case 2: /* indirect */
                    269:                                                if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
                    270:                                                        /* use the next entry */
                    271:                                                        n_pages_used++;
                    272: 
                    273:                                                        page_info[n_pages_used].match = page_des;
                    274:                                                        page_info[n_pages_used].n_pages = 1;
                    275:                                                        page_info[n_pages_used].start_idx = page_idx;
                    276:                                                        page_info[n_pages_used].log = page_log;
                    277:                                                } else {
                    278:                                                        page_info[n_pages_used].n_pages++;
                    279:                                                }
                    280:                                                break;
                    281:                                }
                    282:                        }
                    283: 
                    284:                        if (n_pages_used == -1)
                    285:                                continue;
                    286: 
1.1.1.5   root      287:                        console_out_f(_T(" PTR: %03d U=%d W=%d UDT=%02d\n"), ptr_idx,
1.1.1.3   root      288:                                ptr_des & 8 ? 1 : 0,
                    289:                                ptr_des & 4 ? 1 : 0,
                    290:                                ptr_des & 3
                    291:                          );
                    292: 
                    293: 
                    294:                        for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
                    295:                                page_des = page_info[page_idx].match;
                    296: 
                    297:                                if ((page_des & MMU_PDT_MASK) == 2) {
1.1.1.5   root      298:                                        console_out_f(_T("  PAGE: %03d-%03d log=%08x INDIRECT --> addr=%08x\n"),
1.1.1.3   root      299:                                                        page_info[page_idx].start_idx,
                    300:                                                        page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
                    301:                                                        page_info[page_idx].log,
                    302:                                                        page_des & MMU_PAGE_INDIRECT_MASK
                    303:                                                  );
                    304: 
                    305:                                } else {
1.1.1.5   root      306:                                        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"),
1.1.1.3   root      307:                                                        page_info[page_idx].start_idx,
                    308:                                                        page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
                    309:                                                        page_info[page_idx].log,
1.1.1.5   root      310:                                                        page_des & (mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
                    311:                                                        (page_des & (mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
1.1.1.3   root      312:                                                        page_des & MMU_DES_GLOBAL ? 1 : 0,
                    313:                                                        (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
                    314:                                                        page_des & MMU_DES_SUPER ? 1 : 0,
                    315:                                                        (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
                    316:                                                        page_des & MMU_DES_MODIFIED ? 1 : 0,
                    317:                                                        page_des & MMU_DES_USED ? 1 : 0,
                    318:                                                        page_des & MMU_DES_WP ? 1 : 0
                    319:                                                  );
                    320:                                }
                    321:                        }
                    322:                }
                    323: 
                    324:        }
                    325: }
                    326: /* }}} */
                    327: #endif
                    328: 
                    329: /* {{{ mmu_dump_atc */
1.1.1.6   root      330: static void mmu_dump_atc(void)
1.1.1.3   root      331: {
1.1.1.5   root      332: 
1.1.1.3   root      333: }
                    334: /* }}} */
                    335: 
                    336: /* {{{ mmu_dump_tables */
                    337: void mmu_dump_tables(void)
                    338: {
1.1.1.7 ! root      339:        console_out_f(_T("URP: %08x   SRP: %08x  MMUSR: %x  TC: %x\n"), regs.urp, regs.srp, regs.mmusr, regs.tcr);
1.1.1.5   root      340:        mmu_dump_ttr(_T("DTT0"), regs.dtt0);
                    341:        mmu_dump_ttr(_T("DTT1"), regs.dtt1);
                    342:        mmu_dump_ttr(_T("ITT0"), regs.itt0);
                    343:        mmu_dump_ttr(_T("ITT1"), regs.itt1);
1.1.1.3   root      344:        mmu_dump_atc();
1.1.1.5   root      345: #if MMUDUMP
1.1.1.3   root      346:        mmu_dump_table("SRP", regs.srp);
1.1.1.7 ! root      347:        if (regs.urp != regs.srp)
        !           348:                mmu_dump_table("URP", regs.urp);
1.1.1.3   root      349: #endif
                    350: }
                    351: /* }}} */
                    352: 
1.1.1.7 ! root      353: static void flush_shortcut_cache(uaecptr addr, bool super)
        !           354: {
        !           355: #if MMU_IPAGECACHE
        !           356:        atc_last_ins_laddr = mmu_pagemask;
        !           357: #endif
        !           358: #if MMU_DPAGECACHE
        !           359:        if (addr == 0xffffffff) {
        !           360:                memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
        !           361:                memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
        !           362:        } else {
        !           363:                int i;
        !           364:                for (i = 0; i < MMUFASTCACHE_ENTRIES; i++) {
        !           365:                        uae_u32 idx = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
        !           366:                        if (atc_data_cache_read[i].log == idx)
        !           367:                                atc_data_cache_read[i].log = 0xffffffff;
        !           368:                        if (atc_data_cache_write[i].log == idx)
        !           369:                                atc_data_cache_write[i].log = 0xffffffff;
        !           370:                }
        !           371:        }
        !           372: #endif
        !           373: }
1.1.1.3   root      374: 
                    375: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
                    376: {
                    377:        return (super ? 4 : 0) | (data ? 1 : 2);
                    378: }
                    379: 
1.1.1.7 ! root      380: void mmu_bus_error(uaecptr addr, uae_u32 val, int fc, bool write, int size,uae_u32 status060, bool nonmmu)
1.1.1.3   root      381: {
1.1.1.5   root      382:        if (currprefs.mmu_model == 68040) {
                    383:                uae_u16 ssw = 0;
1.1.1.3   root      384: 
1.1.1.5   root      385:                if (ismoves) {
                    386:                        // MOVES special behavior
                    387:                        int fc2 = write ? regs.dfc : regs.sfc;
                    388:                        if (fc2 == 0 || fc2 == 3 || fc2 == 4 || fc2 == 7)
                    389:                                ssw |= MMU_SSW_TT1;
                    390:                        if ((fc2 & 3) != 3)
                    391:                                fc2 &= ~2;
                    392: #if MMUDEBUGMISC > 0
                    393:                        write_log (_T("040 MMU MOVES fc=%d -> %d\n"), fc, fc2);
                    394: #endif
                    395:                        fc = fc2;
                    396:                }
1.1.1.3   root      397: 
1.1.1.5   root      398:                ssw |= fc & MMU_SSW_TM;                         /* TM = FC */
1.1.1.3   root      399: 
1.1.1.5   root      400:                switch (size) {
                    401:                case sz_byte:
                    402:                        ssw |= MMU_SSW_SIZE_B;
                    403:                        break;
                    404:                case sz_word:
                    405:                        ssw |= MMU_SSW_SIZE_W;
                    406:                        break;
                    407:                case sz_long:
                    408:                        ssw |= MMU_SSW_SIZE_L;
                    409:                        break;
                    410:                }
                    411: 
                    412:                regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
1.1.1.7 ! root      413:                regs.wb3_data = val;
1.1.1.5   root      414:                regs.wb2_status = 0;
                    415:                if (!write)
                    416:                        ssw |= MMU_SSW_RW;
                    417: 
                    418:                if (size == 16) { // MOVE16
                    419:                        ssw |= MMU_SSW_SIZE_CL;
                    420:                        ssw |= MMU_SSW_TT0;
                    421:                        regs.mmu_effective_addr &= ~15;
                    422:                        if (write) {
                    423:                                // clear normal writeback if MOVE16 write
                    424:                                regs.wb3_status &= ~0x80;
                    425:                                // wb2 = cacheline size writeback
                    426:                                regs.wb2_status = 0x80 | MMU_SSW_SIZE_CL | (ssw & 0x1f);
                    427:                                regs.wb2_address = regs.mmu_effective_addr;
                    428:                                write_log (_T("040 MMU MOVE16 WRITE FAULT!\n"));
                    429:                        }
                    430:                }
                    431: 
                    432:                if (mmu040_movem) {
                    433:                        ssw |= MMU_SSW_CM;
                    434:                        regs.mmu_effective_addr = mmu040_movem_ea;
                    435:                        mmu040_movem = 0;
                    436: #if MMUDEBUGMISC > 0
                    437:                        write_log (_T("040 MMU_SSW_CM EA=%08X\n"), mmu040_movem_ea);
                    438: #endif
                    439:                }
                    440:                if (locked_rmw_cycle) {
                    441:                        ssw |= MMU_SSW_LK;
                    442:                        ssw &= ~MMU_SSW_RW;
                    443: #if MMUDEBUGMISC > 0
                    444:                        write_log (_T("040 MMU_SSW_LK!\n"));
                    445: #endif
                    446:                }
                    447: 
                    448:                if (!nonmmu)
                    449:                        ssw |= MMU_SSW_ATC;
                    450:                regs.mmu_ssw = ssw;
1.1.1.3   root      451: 
1.1.1.5   root      452: #if MMUDEBUG > 0
                    453:                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);
                    454: #endif
                    455:        } else {
                    456:                uae_u32 fslw = 0;
1.1.1.3   root      457: 
1.1.1.5   root      458:                fslw |= write ? MMU_FSLW_W : MMU_FSLW_R;
                    459:                fslw |= fc << 16; /* MMU_FSLW_TM */
1.1.1.3   root      460: 
1.1.1.5   root      461:                switch (size) {
                    462:                case sz_byte:
                    463:                        fslw |= MMU_FSLW_SIZE_B;
                    464:                        break;
                    465:                case sz_word:
                    466:                        fslw |= MMU_FSLW_SIZE_W;
                    467:                        break;
                    468:                case sz_long:
                    469:                        fslw |= MMU_FSLW_SIZE_L;
                    470:                        break;
                    471:                case 16: // MOVE16
                    472:                        addr &= ~15;
                    473:                        fslw |= MMU_FSLW_SIZE_D;
                    474:                        fslw |= MMU_FSLW_TT_16;
                    475:                        break;
                    476:                }
                    477:                if ((fc & 3) == 2) {
                    478:                        // instruction faults always point to opcode address
                    479: #if MMUDEBUGMISC > 0
                    480:                        write_log(_T("INS FAULT %08x %08x %d\n"), addr, regs.instruction_pc, mmu060_state);
                    481: #endif
                    482:                        addr = regs.instruction_pc;
                    483:                        if (mmu060_state == 0) {
                    484:                                fslw |= MMU_FSLW_IO; // opword fetch
                    485:                        } else {
                    486:                                fslw |= MMU_FSLW_IO | MMU_FSLW_MA; // extension word
                    487:                        }
                    488:                }
1.1.1.7 ! root      489:                if (rmw_cycle) {
1.1.1.5   root      490:                        fslw |=  MMU_FSLW_W | MMU_FSLW_R;
                    491:                }
                    492:                if (locked_rmw_cycle) {
                    493:                        fslw |= MMU_FSLW_LK;
                    494:                        write_log (_T("060 MMU_FSLW_LK!\n"));
                    495:                }
1.1.1.7 ! root      496:                fslw |= status060;
1.1.1.5   root      497:                regs.mmu_fslw = fslw;
                    498: 
                    499: #if MMUDEBUG > 0
1.1.1.7 ! root      500:                write_log(_T("BF: fc=%d w=%d s=%d log=%08x ssw=%08x rmw=%d PC=%08x INS=%04X\n"), fc, write, 1 << size, addr, fslw, rmw_cycle, m68k_getpc(), mmu_opcode);
1.1.1.5   root      501: #endif
                    502: 
                    503:        }
                    504: 
1.1.1.7 ! root      505:        rmw_cycle = false;
        !           506:        locked_rmw_cycle = false;
1.1.1.5   root      507:        regs.mmu_fault_addr = addr;
                    508: 
                    509: #if 0
1.1.1.7 ! root      510:        activate_debugger ();
1.1.1.5   root      511: #endif
1.1.1.3   root      512: 
1.1.1.7 ! root      513:        cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1.1.1.5   root      514: 
1.1.1.7 ! root      515:        THROW(2);
1.1.1.5   root      516: }
                    517: 
1.1.1.3   root      518: /*
1.1.1.7 ! root      519:  * mmu access is a 4 step process:
        !           520:  * if mmu is not enabled just read physical
        !           521:  * check transparent region, if transparent, read physical
        !           522:  * check ATC (address translation cache), read immediately if HIT
        !           523:  * read from mmu with the long path (and allocate ATC entry if needed)
1.1.1.3   root      524:  */
                    525: 
1.1.1.7 ! root      526: /* check if an address matches a ttr */
        !           527: static int mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
        !           528: {
        !           529:        if (ttr & MMU_TTR_BIT_ENABLED)  {       /* TTR enabled */
        !           530:                uae_u8 msb, mask;
        !           531:                
        !           532:                msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
        !           533:                mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
        !           534:                
        !           535:                if (!(msb & ~mask)) {
        !           536:                        
        !           537:                        if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
        !           538:                                if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
        !           539:                                        return TTR_NO_MATCH;
        !           540:                                }
        !           541:                        }
        !           542:                        if (ttr & MMU_TTR_CACHE_DISABLE) {
        !           543:                                mmu_cache_state = CACHE_DISABLE_MMU;
        !           544:                        } else {
        !           545:                                mmu_cache_state = CACHE_ENABLE_ALL;
        !           546:                                if (ttr & MMU_TTR_CACHE_MODE) {
        !           547:                                        mmu_cache_state |= CACHE_ENABLE_COPYBACK;
        !           548:                                }
        !           549:                        }
        !           550:                        return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
        !           551:                }
1.1.1.3   root      552:        }
1.1.1.7 ! root      553:        return TTR_NO_MATCH;
        !           554: }
1.1.1.3   root      555: 
1.1.1.7 ! root      556: int mmu_match_ttr_ins(uaecptr addr, bool super)
        !           557: {
        !           558:        int res;
        !           559:        
        !           560:        if (!mmu_ttr_enabled_ins)
        !           561:                return TTR_NO_MATCH;
        !           562:        res = mmu_do_match_ttr(regs.itt0, addr, super);
        !           563:        if (res == TTR_NO_MATCH)
        !           564:                res = mmu_do_match_ttr(regs.itt1, addr, super);
        !           565:        return res;
1.1.1.3   root      566: }
                    567: 
1.1.1.7 ! root      568: int mmu_match_ttr(uaecptr addr, bool super, bool data)
1.1.1.3   root      569: {
1.1.1.7 ! root      570:        int res;
        !           571:        
        !           572:        if (!mmu_ttr_enabled)
        !           573:                return TTR_NO_MATCH;
        !           574:        if (data) {
        !           575:                res = mmu_do_match_ttr(regs.dtt0, addr, super);
        !           576:                if (res == TTR_NO_MATCH)
        !           577:                        res = mmu_do_match_ttr(regs.dtt1, addr, super);
        !           578:        } else {
        !           579:                res = mmu_do_match_ttr(regs.itt0, addr, super);
        !           580:                if (res == TTR_NO_MATCH)
        !           581:                        res = mmu_do_match_ttr(regs.itt1, addr, super);
1.1.1.3   root      582:        }
1.1.1.7 ! root      583:        return res;
        !           584: }
1.1.1.3   root      585: 
1.1.1.7 ! root      586: void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size)
        !           587:  {
        !           588:         uae_u32 status = 0;
        !           589:         
        !           590:         if (currprefs.mmu_model == 68060) {
        !           591:                 status |= MMU_FSLW_TTR;
        !           592:         }
        !           593:        mmu_bus_error(addr, val, mmu_get_fc (super, data), true, size, status, false);
        !           594: }
        !           595: 
        !           596: int mmu_match_ttr_write(uaecptr addr, bool super, bool data, uae_u32 val, int size)
        !           597: {
        !           598:        int res = TTR_NO_MATCH;
        !           599:        if (mmu_ttr_enabled) {
        !           600:                res = mmu_match_ttr(addr, super, data);
1.1.1.3   root      601:        }
1.1.1.7 ! root      602:        if (res == TTR_NO_WRITE || (res == TTR_NO_MATCH && !regs.mmu_enabled && (regs.tcr & MMU_TCR_DWO)))
        !           603:                mmu_bus_error_ttr_write_fault(addr, super, data, val, size);
        !           604:        return res;
1.1.1.3   root      605: }
                    606: 
1.1.1.7 ! root      607: int mmu_match_ttr_maybe_write(uaecptr addr, bool super, bool data, int size, bool write)
1.1.1.3   root      608: {
1.1.1.7 ! root      609:        int res = TTR_NO_MATCH;
        !           610:        if (mmu_ttr_enabled) {
        !           611:                res = mmu_match_ttr(addr, super, data);
1.1.1.5   root      612:        }
1.1.1.7 ! root      613:        if (write && ((res == TTR_NO_WRITE) || (res == TTR_NO_MATCH && !regs.mmu_enabled && (regs.tcr & MMU_TCR_DWO))))
        !           614:                mmu_bus_error_ttr_write_fault(addr, super, data, 0, size);
        !           615:        return res;
        !           616: }
1.1.1.5   root      617: 
1.1.1.7 ! root      618: // Descriptor read accesses can use data cache but never allocate new cache lines.
        !           619: static uae_u32 desc_get_long(uaecptr addr)
        !           620: {
        !           621:        mmu_cache_state = ce_cachable[addr >>16] | CACHE_DISABLE_ALLOCATE;
        !           622:        return x_phys_get_long(addr);
        !           623: }
        !           624: // Write accesses probably are always pushed to memomory
        !           625: static void desc_put_long(uaecptr addr, uae_u32 v)
        !           626: {
        !           627:        mmu_cache_state = CACHE_DISABLE_MMU;
        !           628:        x_phys_put_long(addr, v);
1.1.1.3   root      629: }
                    630: 
                    631: /*
                    632:  * Lookup the address by walking the page table and updating
                    633:  * the page descriptors accordingly. Returns the found descriptor
                    634:  * or produces a bus error.
                    635:  */
1.1.1.7 ! root      636: static uae_u32 mmu_fill_atc(uaecptr addr, bool super, uae_u32 tag, bool write, struct mmu_atc_line *l, uae_u32 *status060)
1.1.1.3   root      637: {
1.1.1.7 ! root      638:     uae_u32 desc, desc_addr, wp;
        !           639:        uae_u32 status = 0;
        !           640:     int i;
        !           641:     
        !           642:     wp = 0;
        !           643:     desc = super ? regs.srp : regs.urp;
        !           644:     
        !           645:     /* fetch root table descriptor */
        !           646:     i = (addr >> 23) & 0x1fc;
        !           647:     desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
        !           648:     
        !           649:     SAVE_EXCEPTION;
        !           650:     TRY(prb) {
        !           651:         desc = desc_get_long(desc_addr);
        !           652:         if ((desc & 2) == 0) {
1.1.1.5   root      653: #if MMUDEBUG > 1
1.1.1.7 ! root      654:             write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
        !           655:                       addr, desc_addr, desc);
1.1.1.5   root      656: #endif
1.1.1.7 ! root      657:                        *status060 |= MMU_FSLW_PTA;
        !           658:             goto fail;
        !           659:         }
        !           660:         
        !           661:         wp |= desc;
        !           662:         if ((desc & MMU_DES_USED) == 0) {
        !           663:             desc_put_long(desc_addr, desc | MMU_DES_USED);
        !           664:                }
        !           665:         
        !           666:         /* fetch pointer table descriptor */
        !           667:         i = (addr >> 16) & 0x1fc;
        !           668:         desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
        !           669:         desc = desc_get_long(desc_addr);
        !           670:         if ((desc & 2) == 0) {
1.1.1.5   root      671: #if MMUDEBUG > 1
1.1.1.7 ! root      672:             write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
        !           673:                       addr, desc_addr, desc);
1.1.1.5   root      674: #endif
1.1.1.7 ! root      675:                        *status060 |= MMU_FSLW_PTB;
        !           676:             goto fail;
        !           677:         }
        !           678:         wp |= desc;
        !           679:         if ((desc & MMU_DES_USED) == 0)
        !           680:             desc_put_long(desc_addr, desc | MMU_DES_USED);
        !           681:         
        !           682:         /* fetch page table descriptor */
        !           683:         if (mmu_pagesize_8k) {
        !           684:             i = (addr >> 11) & 0x7c;
        !           685:             desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
        !           686:         } else {
        !           687:             i = (addr >> 10) & 0xfc;
        !           688:             desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
        !           689:         }
        !           690:         
        !           691:         desc = desc_get_long(desc_addr);
        !           692:         if ((desc & 3) == 2) {
        !           693:             /* indirect */
        !           694:             desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
        !           695:             desc = desc_get_long(desc_addr);
        !           696:         }
        !           697:         if ((desc & 1) == 1) {
        !           698:             wp |= desc;
        !           699:             if (write) {
        !           700:                 if ((wp & MMU_DES_WP) || ((desc & MMU_DES_SUPER) && !super)) {
        !           701:                     if ((desc & MMU_DES_USED) == 0) {
        !           702:                         desc |= MMU_DES_USED;
        !           703:                         desc_put_long(desc_addr, desc);
        !           704:                     }
        !           705:                 } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
        !           706:                            (MMU_DES_USED|MMU_DES_MODIFIED)) {
        !           707:                     desc |= MMU_DES_USED|MMU_DES_MODIFIED;
        !           708:                     desc_put_long(desc_addr, desc);
        !           709:                 }
        !           710:             } else {
        !           711:                 if ((desc & MMU_DES_USED) == 0) {
        !           712:                     desc |= MMU_DES_USED;
        !           713:                     desc_put_long(desc_addr, desc);
        !           714:                 }
        !           715:             }
        !           716:             desc |= wp & MMU_DES_WP;
        !           717:         } else {
        !           718:             if ((desc & 3) == 2) {
        !           719:                                *status060 |= MMU_FSLW_IL;
        !           720: #if MMUDEBUG > 1
        !           721:                 write_log(_T("MMU: double indirect descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
        !           722: #endif
        !           723:             } else {
        !           724:                                *status060 |= MMU_FSLW_PF;
        !           725: #if MMUDEBUG > 2
        !           726:                                write_log(_T("MMU: invalid page descriptor log=%0x desc=%08x @%08x\n"), addr, desc, desc_addr);
        !           727: #endif
        !           728:                        }
        !           729: fail:
        !           730:             desc = 0;
        !           731:         }
        !           732:         
        !           733:                /* this will cause a bus error exception */
        !           734:                if (!super && (desc & MMU_DES_SUPER)) {
        !           735:                        *status060 |= MMU_FSLW_SP;
        !           736:                } else if (write && (desc & MMU_DES_WP)) {
        !           737:                        *status060 |= MMU_FSLW_WP;
        !           738:                }
        !           739: 
        !           740:                // 68040 always creates ATC entry. 68060 only if valid descriptor was found.
        !           741:                if (currprefs.mmu_model == 68040 || (desc & MMU_MMUSR_R)) {
        !           742:                        /* Create new ATC entry and return status */
        !           743:                        l->status = desc & (MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W|MMU_MMUSR_R);
        !           744:                        l->phys = desc & mmu_pagemaski;
        !           745:                        l->valid = 1;
        !           746:                        l->tag = tag;
        !           747:                        status = l->phys | l->status;
        !           748:                }
1.1.1.3   root      749: 
1.1.1.7 ! root      750:                RESTORE_EXCEPTION;
        !           751:     } CATCH(prb) {
        !           752:         RESTORE_EXCEPTION;
        !           753: 
        !           754:                /* bus error during table search */
        !           755:                if (currprefs.mmu_model == 68040) {
        !           756:                l->status = 0;
        !           757:                l->phys = 0;
        !           758:                    l->valid = 1;
        !           759:                    l->tag = tag;
        !           760:                }
        !           761:         status = MMU_MMUSR_B;
        !           762:                *status060 |= MMU_FSLW_LK | MMU_FSLW_TWE;
        !           763: 
        !           764: #if MMUDEBUG > 0
        !           765:         write_log(_T("MMU: bus error during table search.\n"));
        !           766: #endif
        !           767:     } ENDTRY
        !           768:     
1.1.1.5   root      769: #if MMUDEBUG > 2
1.1.1.7 ! root      770:     write_log(_T("translate: %x,%u,%u -> %x\n"), addr, super, write, desc);
1.1.1.5   root      771: #endif
1.1.1.7 ! root      772: 
        !           773:        flush_shortcut_cache(addr, super);
        !           774: 
        !           775:        return status;
        !           776: }
        !           777: 
        !           778: static void mmu_add_cache(uaecptr addr, uaecptr phys, bool super, bool data, bool write)
        !           779: {
        !           780:        if (!data) {
        !           781: #if MMU_IPAGECACHE
        !           782:                uae_u32 laddr = (addr & mmu_pagemaski) | (super ? 1 : 0);
        !           783:                atc_last_ins_laddr = laddr;
        !           784:                atc_last_ins_paddr = phys;
        !           785:                atc_last_ins_cache = mmu_cache_state;
        !           786: #else
        !           787:        ;
        !           788: #endif
        !           789: #if MMU_DPAGECACHE
        !           790:        } else {
        !           791:                uae_u32 idx1 = ((addr & mmu_pagemaski) >> mmu_pageshift1m) | (super ? 1 : 0);
        !           792:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES - 1);
        !           793:                if (write) {
        !           794:                        if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
        !           795:                                atc_data_cache_write[idx2].log = idx1;
        !           796:                                atc_data_cache_write[idx2].phys = phys;
        !           797:                                atc_data_cache_write[idx2].cache_state = mmu_cache_state;
        !           798:                        }
1.1.1.5   root      799:                } else {
1.1.1.7 ! root      800:                        if (idx2 < MMUFASTCACHE_ENTRIES - 1) {
        !           801:                                atc_data_cache_read[idx2].log = idx1;
        !           802:                                atc_data_cache_read[idx2].phys = phys;
        !           803:                                atc_data_cache_read[idx2].cache_state = mmu_cache_state;
        !           804:                        }
1.1.1.5   root      805:                }
1.1.1.7 ! root      806: #endif
1.1.1.3   root      807:        }
1.1.1.7 ! root      808: }
1.1.1.3   root      809: 
1.1.1.7 ! root      810: uaecptr mmu_translate(uaecptr addr, uae_u32 val, bool super, bool data, bool write, int size)
        !           811: {
        !           812:        int way, i, index, way_invalid;
        !           813:        struct mmu_atc_line *l;
        !           814:        uae_u32 status060 = 0;
        !           815:        uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
        !           816: 
        !           817:        if (mmu_pagesize_8k)
        !           818:                index=(addr & 0x0001E000)>>13;
        !           819:        else
        !           820:                index=(addr & 0x0000F000)>>12;
        !           821:        way_invalid = ATC_WAYS;
        !           822:        way_random++;
        !           823:        way = mmu_atc_ways[data];
        !           824: 
        !           825:        for (i = 0; i < ATC_WAYS; i++) {
        !           826:                // if we have this
        !           827:                l = &mmu_atc_array[data][index][way];
        !           828:                if (l->valid) {
        !           829:                        if (tag == l->tag) {
        !           830: atc_retry:
        !           831:                                // check if we need to cause a page fault
        !           832:                                if (((l->status&(MMU_MMUSR_W|MMU_MMUSR_S|MMU_MMUSR_R))!=MMU_MMUSR_R)) {
        !           833:                                        if (((l->status&MMU_MMUSR_W) && write) ||
        !           834:                                                ((l->status&MMU_MMUSR_S) && !super) ||
        !           835:                                                !(l->status&MMU_MMUSR_R)) {
        !           836: 
        !           837:                                                if ((l->status&MMU_MMUSR_S) && !super)
        !           838:                                                        status060 |= MMU_FSLW_SP;
        !           839:                                                if ((l->status&MMU_MMUSR_W) && write)
        !           840:                                                        status060 |= MMU_FSLW_WP;
        !           841: 
        !           842:                                                mmu_bus_error(addr, val, mmu_get_fc(super, data), write, size, status060, false);
        !           843:                                                return 0; // never reach, bus error longjumps out of the function
        !           844:                                        }
        !           845:                                }
        !           846:                                // if first write to this page initiate table search to set M bit (but modify this slot)
        !           847:                                if (!(l->status&MMU_MMUSR_M) && write) {
        !           848:                                        way_invalid = way;
        !           849:                                        break;
        !           850:                                }
        !           851: 
        !           852:                                // save way for next access (likely in same page)
        !           853:                                mmu_atc_ways[data] = way;
        !           854: 
        !           855:                                if (l->status & MMU_MMUSR_CM_DISABLE) {
        !           856:                                        mmu_cache_state = CACHE_DISABLE_MMU;
        !           857:                                } else {
        !           858:                                        mmu_cache_state = CACHE_ENABLE_ALL;
        !           859:                                        if (l->status & MMU_MMUSR_CM_MODE) {
        !           860:                                                mmu_cache_state |= CACHE_ENABLE_COPYBACK;
        !           861:                                        }
        !           862:                                }
        !           863: 
        !           864:                                mmu_add_cache(addr, l->phys, super, data, write);
        !           865: 
        !           866:                                // return translated addr
        !           867:                                return l->phys | (addr & mmu_pagemask);
        !           868:                        } else {
        !           869:                                way_invalid = way;
1.1.1.3   root      870:                        }
                    871:                }
1.1.1.7 ! root      872:                way++;
        !           873:                way %= ATC_WAYS;
1.1.1.3   root      874:        }
1.1.1.7 ! root      875:        // no entry found, we need to create a new one, first find an atc line to replace
        !           876:        way_random %= ATC_WAYS;
        !           877:        way = (way_invalid < ATC_WAYS) ? way_invalid : way_random;
        !           878:        
        !           879:        // then initiate table search and create a new entry
        !           880:        l = &mmu_atc_array[data][index][way];
        !           881:        mmu_fill_atc(addr, super, tag, write, l, &status060);
        !           882: 
        !           883:        if (status060 && currprefs.mmu_model == 68060) {
        !           884:                mmu_bus_error(addr, val, mmu_get_fc(super, data), write, size, status060, false);
        !           885:        }
        !           886:        
        !           887:        // and retry the ATC search
        !           888:        way_random++;
        !           889:        goto atc_retry;
1.1.1.3   root      890: }
                    891: 
1.1.1.5   root      892: static void misalignednotfirst(uaecptr addr)
                    893: {
                    894: #if MMUDEBUGMISC > 0
                    895:        write_log (_T("misalignednotfirst %08x -> %08x %08X\n"), regs.mmu_fault_addr, addr, regs.instruction_pc);
                    896: #endif
                    897:        regs.mmu_fault_addr = addr;
                    898:        regs.mmu_fslw |= MMU_FSLW_MA;
                    899:        regs.mmu_ssw |= MMU_SSW_MA;
                    900: }
                    901: 
                    902: static void misalignednotfirstcheck(uaecptr addr)
                    903: {
                    904:        if (regs.mmu_fault_addr == addr)
                    905:                return;
                    906:        misalignednotfirst (addr);
                    907: }
                    908: 
1.1.1.7 ! root      909: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data)
1.1.1.3   root      910: {
                    911:        uae_u16 res;
                    912: 
1.1.1.7 ! root      913:        res = (uae_u16)mmu_get_byte(addr, data, sz_word) << 8;
1.1.1.3   root      914:        SAVE_EXCEPTION;
                    915:        TRY(prb) {
1.1.1.7 ! root      916:                res |= mmu_get_byte(addr + 1, data, sz_word);
1.1.1.3   root      917:                RESTORE_EXCEPTION;
                    918:        }
                    919:        CATCH(prb) {
                    920:                RESTORE_EXCEPTION;
1.1.1.5   root      921:                misalignednotfirst(addr);
1.1.1.3   root      922:                THROW_AGAIN(prb);
                    923:        } ENDTRY
                    924:        return res;
                    925: }
                    926: 
1.1.1.7 ! root      927: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data)
1.1.1.3   root      928: {
                    929:        uae_u32 res;
                    930: 
                    931:        if (likely(!(addr & 1))) {
1.1.1.7 ! root      932:                res = (uae_u32)mmu_get_word(addr, data, sz_long) << 16;
1.1.1.3   root      933:                SAVE_EXCEPTION;
                    934:                TRY(prb) {
1.1.1.7 ! root      935:                        res |= mmu_get_word(addr + 2, data, sz_long);
1.1.1.3   root      936:                        RESTORE_EXCEPTION;
                    937:                }
                    938:                CATCH(prb) {
                    939:                        RESTORE_EXCEPTION;
1.1.1.5   root      940:                        misalignednotfirst(addr);
1.1.1.3   root      941:                        THROW_AGAIN(prb);
                    942:                } ENDTRY
                    943:        } else {
1.1.1.7 ! root      944:                res = (uae_u32)mmu_get_byte(addr, data, sz_long) << 8;
1.1.1.3   root      945:                SAVE_EXCEPTION;
                    946:                TRY(prb) {
1.1.1.7 ! root      947:                        res = (res | mmu_get_byte(addr + 1, data, sz_long)) << 8;
        !           948:                        res = (res | mmu_get_byte(addr + 2, data, sz_long)) << 8;
        !           949:                        res |= mmu_get_byte(addr + 3, data, sz_long);
1.1.1.3   root      950:                        RESTORE_EXCEPTION;
                    951:                }
                    952:                CATCH(prb) {
                    953:                        RESTORE_EXCEPTION;
1.1.1.5   root      954:                        misalignednotfirst(addr);
1.1.1.3   root      955:                        THROW_AGAIN(prb);
                    956:                } ENDTRY
                    957:        }
                    958:        return res;
                    959: }
                    960: 
1.1.1.5   root      961: uae_u32 REGPARAM2 mmu_get_ilong_unaligned(uaecptr addr)
1.1.1.3   root      962: {
1.1.1.5   root      963:        uae_u32 res;
1.1.1.3   root      964: 
1.1.1.6   root      965:        res = (uae_u32)mmu_get_iword(addr, sz_long) << 16;
                    966:        SAVE_EXCEPTION;
                    967:        TRY(prb) {
                    968:                res |= mmu_get_iword(addr + 2, sz_long);
                    969:                RESTORE_EXCEPTION;
1.1.1.3   root      970:        }
1.1.1.6   root      971:        CATCH(prb) {
                    972:                RESTORE_EXCEPTION;
                    973:                misalignednotfirst(addr);
                    974:                THROW_AGAIN(prb);
                    975:        } ENDTRY
1.1.1.5   root      976:        return res;
                    977: }
1.1.1.3   root      978: 
1.1.1.6   root      979: static uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
1.1.1.5   root      980: {
                    981:        uae_u16 res;
1.1.1.3   root      982: 
1.1.1.7 ! root      983:        res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, sz_word, true) << 8;
1.1.1.5   root      984:        SAVE_EXCEPTION;
                    985:        TRY(prb) {
1.1.1.7 ! root      986:                res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_word, true);
1.1.1.5   root      987:                RESTORE_EXCEPTION;
                    988:        }
                    989:        CATCH(prb) {
                    990:                RESTORE_EXCEPTION;
                    991:                misalignednotfirst(addr);
                    992:                THROW_AGAIN(prb);
                    993:        } ENDTRY
                    994:        return res;
1.1.1.3   root      995: }
                    996: 
1.1.1.6   root      997: static uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
1.1.1.3   root      998: {
1.1.1.5   root      999:        uae_u32 res;
1.1.1.3   root     1000: 
1.1.1.5   root     1001:        if (likely(!(addr & 1))) {
1.1.1.7 ! root     1002:                res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, sz_long, true) << 16;
1.1.1.5   root     1003:                SAVE_EXCEPTION;
                   1004:                TRY(prb) {
1.1.1.7 ! root     1005:                        res |= mmu_get_user_word(addr + 2, regs.s != 0, true, sz_long, true);
1.1.1.5   root     1006:                        RESTORE_EXCEPTION;
                   1007:                }
                   1008:                CATCH(prb) {
                   1009:                        RESTORE_EXCEPTION;
                   1010:                        misalignednotfirst(addr);
                   1011:                        THROW_AGAIN(prb);
                   1012:                } ENDTRY
                   1013:        } else {
1.1.1.7 ! root     1014:                res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, sz_long, true) << 8;
1.1.1.5   root     1015:                SAVE_EXCEPTION;
                   1016:                TRY(prb) {
1.1.1.7 ! root     1017:                        res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, sz_long, true)) << 8;
        !          1018:                        res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, sz_long, true)) << 8;
        !          1019:                        res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, sz_long, true);
1.1.1.5   root     1020:                        RESTORE_EXCEPTION;
                   1021:                }
                   1022:                CATCH(prb) {
                   1023:                        RESTORE_EXCEPTION;
                   1024:                        misalignednotfirst(addr);
                   1025:                        THROW_AGAIN(prb);
                   1026:                } ENDTRY
                   1027:        }
                   1028:        return res;
                   1029: }
1.1.1.3   root     1030: 
                   1031: 
1.1.1.7 ! root     1032: static void REGPARAM2 mmu_put_lrmw_long_unaligned(uaecptr addr, uae_u32 val)
1.1.1.3   root     1033: {
                   1034:        SAVE_EXCEPTION;
                   1035:        TRY(prb) {
                   1036:                if (likely(!(addr & 1))) {
1.1.1.7 ! root     1037:                        mmu_put_user_word(addr, val >> 16, regs.s != 0, sz_long, true);
        !          1038:                        mmu_put_user_word(addr + 2, val, regs.s != 0, sz_long, true);
1.1.1.3   root     1039:                } else {
1.1.1.7 ! root     1040:                        mmu_put_user_byte(addr, val >> 24, regs.s != 0, sz_long, true);
        !          1041:                        mmu_put_user_byte(addr + 1, val >> 16, regs.s != 0, sz_long, true);
        !          1042:                        mmu_put_user_byte(addr + 2, val >> 8, regs.s != 0, sz_long, true);
        !          1043:                        mmu_put_user_byte(addr + 3, val, regs.s != 0, sz_long, true);
1.1.1.3   root     1044:                }
                   1045:                RESTORE_EXCEPTION;
                   1046:        }
                   1047:        CATCH(prb) {
                   1048:                RESTORE_EXCEPTION;
                   1049:                regs.wb3_data = val;
1.1.1.5   root     1050:                misalignednotfirstcheck(addr);
1.1.1.3   root     1051:                THROW_AGAIN(prb);
                   1052:        } ENDTRY
                   1053: }
                   1054: 
1.1.1.7 ! root     1055: static void REGPARAM2 mmu_put_lrmw_word_unaligned(uaecptr addr, uae_u16 val)
1.1.1.3   root     1056: {
                   1057:        SAVE_EXCEPTION;
                   1058:        TRY(prb) {
1.1.1.7 ! root     1059:                mmu_put_user_byte(addr, val >> 8, regs.s != 0, sz_word, true);
        !          1060:                mmu_put_user_byte(addr + 1, val, regs.s != 0, sz_word, true);
1.1.1.3   root     1061:                RESTORE_EXCEPTION;
                   1062:        }
                   1063:        CATCH(prb) {
                   1064:                RESTORE_EXCEPTION;
                   1065:                regs.wb3_data = val;
1.1.1.5   root     1066:                misalignednotfirstcheck(addr);
1.1.1.3   root     1067:                THROW_AGAIN(prb);
                   1068:        } ENDTRY
                   1069: }
                   1070: 
                   1071: 
1.1.1.7 ! root     1072: 
        !          1073: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data)
1.1.1.3   root     1074: {
1.1.1.7 ! root     1075:        SAVE_EXCEPTION;
        !          1076:        TRY(prb) {
        !          1077:                if (likely(!(addr & 1))) {
        !          1078:                        mmu_put_word(addr, val >> 16, data, sz_long);
        !          1079:                        mmu_put_word(addr + 2, val, data, sz_long);
        !          1080:                } else {
        !          1081:                        mmu_put_byte(addr, val >> 24, data, sz_long);
        !          1082:                        mmu_put_byte(addr + 1, val >> 16, data, sz_long);
        !          1083:                        mmu_put_byte(addr + 2, val >> 8, data, sz_long);
        !          1084:                        mmu_put_byte(addr + 3, val, data, sz_long);
        !          1085:                }
        !          1086:                RESTORE_EXCEPTION;
1.1.1.3   root     1087:        }
1.1.1.7 ! root     1088:        CATCH(prb) {
        !          1089:                RESTORE_EXCEPTION;
        !          1090:                regs.wb3_data = val;
        !          1091:                misalignednotfirstcheck(addr);
        !          1092:                THROW_AGAIN(prb);
        !          1093:        } ENDTRY
1.1.1.3   root     1094: }
                   1095: 
1.1.1.7 ! root     1096: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data)
1.1.1.3   root     1097: {
1.1.1.7 ! root     1098:        SAVE_EXCEPTION;
        !          1099:        TRY(prb) {
        !          1100:                mmu_put_byte(addr, val >> 8, data, sz_word);
        !          1101:                mmu_put_byte(addr + 1, val, data, sz_word);
        !          1102:                RESTORE_EXCEPTION;
1.1.1.3   root     1103:        }
1.1.1.7 ! root     1104:        CATCH(prb) {
        !          1105:                RESTORE_EXCEPTION;
        !          1106:                regs.wb3_data = val;
        !          1107:                misalignednotfirstcheck(addr);
        !          1108:                THROW_AGAIN(prb);
        !          1109:        } ENDTRY
1.1.1.3   root     1110: }
                   1111: 
                   1112: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
                   1113: {
                   1114:        bool super = (regs.sfc & 4) != 0;
                   1115:        uae_u32 res;
                   1116: 
1.1.1.5   root     1117:        ismoves = true;
                   1118:        if (likely(!is_unaligned(addr, 4))) {
1.1.1.7 ! root     1119:                res = mmu_get_user_long(addr, super, false, sz_long, false);
1.1.1.3   root     1120:        } else {
1.1.1.5   root     1121:                if (likely(!(addr & 1))) {
1.1.1.7 ! root     1122:                        res = (uae_u32)mmu_get_user_word(addr, super, false, sz_long, false) << 16;
1.1.1.5   root     1123:                        SAVE_EXCEPTION;
                   1124:                        TRY(prb) {
1.1.1.7 ! root     1125:                                res |= mmu_get_user_word(addr + 2, super, false, sz_long, false);
1.1.1.5   root     1126:                                RESTORE_EXCEPTION;
                   1127:                        }
                   1128:                        CATCH(prb) {
                   1129:                                RESTORE_EXCEPTION;
                   1130:                                misalignednotfirst(addr);
                   1131:                                THROW_AGAIN(prb);
                   1132:                        } ENDTRY
                   1133:                } else {
1.1.1.7 ! root     1134:                        res = (uae_u32)mmu_get_user_byte(addr, super, false, sz_long, false) << 8;
1.1.1.5   root     1135:                        SAVE_EXCEPTION;
                   1136:                        TRY(prb) {
1.1.1.7 ! root     1137:                                res = (res | mmu_get_user_byte(addr + 1, super, false, sz_long, false)) << 8;
        !          1138:                                res = (res | mmu_get_user_byte(addr + 2, super, false, sz_long, false)) << 8;
        !          1139:                                res |= mmu_get_user_byte(addr + 3, super, false, sz_long, false);
1.1.1.5   root     1140:                                RESTORE_EXCEPTION;
                   1141:                        }
                   1142:                        CATCH(prb) {
                   1143:                                RESTORE_EXCEPTION;
                   1144:                                misalignednotfirst(addr);
                   1145:                                THROW_AGAIN(prb);
                   1146:                        } ENDTRY
1.1.1.3   root     1147:                }
                   1148:        }
1.1.1.5   root     1149: 
                   1150:        ismoves = false;
1.1.1.3   root     1151:        return res;
                   1152: }
                   1153: 
                   1154: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
                   1155: {
                   1156:        bool super = (regs.sfc & 4) != 0;
                   1157:        uae_u16 res;
                   1158: 
1.1.1.5   root     1159:        ismoves = true;
                   1160:        if (likely(!is_unaligned(addr, 2))) {
1.1.1.7 ! root     1161:                res = mmu_get_user_word(addr, super, false, sz_word, false);
1.1.1.5   root     1162:        } else {
1.1.1.7 ! root     1163:                res = (uae_u16)mmu_get_user_byte(addr, super, false, sz_word, false) << 8;
1.1.1.5   root     1164:                SAVE_EXCEPTION;
                   1165:                TRY(prb) {
1.1.1.7 ! root     1166:                        res |= mmu_get_user_byte(addr + 1, super, false, sz_word, false);
1.1.1.5   root     1167:                        RESTORE_EXCEPTION;
                   1168:                }
                   1169:                CATCH(prb) {
                   1170:                        RESTORE_EXCEPTION;
                   1171:                        misalignednotfirst(addr);
                   1172:                        THROW_AGAIN(prb);
                   1173:                } ENDTRY
1.1.1.3   root     1174:        }
1.1.1.5   root     1175:        ismoves = false;
1.1.1.3   root     1176:        return res;
                   1177: }
                   1178: 
                   1179: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
                   1180: {
                   1181:        bool super = (regs.sfc & 4) != 0;
1.1.1.5   root     1182:        uae_u8 res;
                   1183:        
                   1184:        ismoves = true;
1.1.1.7 ! root     1185:        res = mmu_get_user_byte(addr, super, false, sz_byte, false);
1.1.1.5   root     1186:        ismoves = false;
                   1187:        return res;
1.1.1.3   root     1188: }
                   1189: 
                   1190: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
                   1191: {
                   1192:        bool super = (regs.dfc & 4) != 0;
                   1193: 
1.1.1.5   root     1194:        ismoves = true;
1.1.1.3   root     1195:        SAVE_EXCEPTION;
                   1196:        TRY(prb) {
1.1.1.7 ! root     1197:                if (likely(!is_unaligned(addr, 4))) {
        !          1198:                        mmu_put_user_long(addr, val, super, sz_long, false);
        !          1199:                } else if (likely(!(addr & 1))) {
        !          1200:                        mmu_put_user_word(addr, val >> 16, super, sz_long, false);
        !          1201:                        mmu_put_user_word(addr + 2, val, super, sz_long, false);
1.1.1.3   root     1202:                } else {
1.1.1.7 ! root     1203:                        mmu_put_user_byte(addr, val >> 24, super, sz_long, false);
        !          1204:                        mmu_put_user_byte(addr + 1, val >> 16, super, sz_long, false);
        !          1205:                        mmu_put_user_byte(addr + 2, val >> 8, super, sz_long, false);
        !          1206:                        mmu_put_user_byte(addr + 3, val, super, sz_long, false);
1.1.1.3   root     1207:                }
                   1208:                RESTORE_EXCEPTION;
                   1209:        }
                   1210:        CATCH(prb) {
                   1211:                RESTORE_EXCEPTION;
                   1212:                regs.wb3_data = val;
1.1.1.5   root     1213:                misalignednotfirstcheck(addr);
1.1.1.3   root     1214:                THROW_AGAIN(prb);
                   1215:        } ENDTRY
1.1.1.5   root     1216:        ismoves = false;
1.1.1.3   root     1217: }
                   1218: 
                   1219: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
                   1220: {
                   1221:        bool super = (regs.dfc & 4) != 0;
                   1222: 
1.1.1.5   root     1223:        ismoves = true;
1.1.1.3   root     1224:        SAVE_EXCEPTION;
                   1225:        TRY(prb) {
1.1.1.7 ! root     1226:                if (likely(!is_unaligned(addr, 2))) {
        !          1227:                        mmu_put_user_word(addr, val, super, sz_word, false);
        !          1228:                } else {
        !          1229:                        mmu_put_user_byte(addr, val >> 8, super, sz_word, false);
        !          1230:                        mmu_put_user_byte(addr + 1, val, super, sz_word, false);
1.1.1.3   root     1231:                }
                   1232:                RESTORE_EXCEPTION;
                   1233:        }
                   1234:        CATCH(prb) {
                   1235:                RESTORE_EXCEPTION;
                   1236:                regs.wb3_data = val;
1.1.1.5   root     1237:                misalignednotfirstcheck(addr);
1.1.1.3   root     1238:                THROW_AGAIN(prb);
                   1239:        } ENDTRY
1.1.1.5   root     1240:        ismoves = false;
1.1.1.3   root     1241: }
                   1242: 
                   1243: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
                   1244: {
                   1245:        bool super = (regs.dfc & 4) != 0;
                   1246: 
1.1.1.5   root     1247:        ismoves = true;
1.1.1.3   root     1248:        SAVE_EXCEPTION;
                   1249:        TRY(prb) {
1.1.1.7 ! root     1250:                mmu_put_user_byte(addr, val, super, sz_byte, false);
1.1.1.3   root     1251:                RESTORE_EXCEPTION;
                   1252:        }
                   1253:        CATCH(prb) {
                   1254:                RESTORE_EXCEPTION;
                   1255:                regs.wb3_data = val;
                   1256:                THROW_AGAIN(prb);
                   1257:        } ENDTRY
1.1.1.5   root     1258:        ismoves = false;
                   1259: }
                   1260: 
                   1261: void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size)
                   1262: {
1.1.1.7 ! root     1263:        bool super = regs.s != 0;
1.1.1.5   root     1264:        int i;
1.1.1.7 ! root     1265: 
1.1.1.5   root     1266:        addr &= ~15;
1.1.1.7 ! root     1267:        if ((!mmu_ttr_enabled || mmu_match_ttr(addr,super,data) == TTR_NO_MATCH) && regs.mmu_enabled) {
        !          1268:                addr = mmu_translate(addr, 0, super, data, false, size);
        !          1269:        }
        !          1270:        // MOVE16 read and cache miss: do not allocate new cache line
        !          1271:        mmu_cache_state |= CACHE_DISABLE_ALLOCATE;
1.1.1.5   root     1272:        for (i = 0; i < 4; i++) {
1.1.1.7 ! root     1273:                v[i] = x_phys_get_long(addr + i * 4);
1.1.1.5   root     1274:        }
1.1.1.3   root     1275: }
                   1276: 
1.1.1.5   root     1277: void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size)
                   1278: {
1.1.1.7 ! root     1279:        bool super = regs.s != 0;
1.1.1.5   root     1280:        int i;
1.1.1.7 ! root     1281: 
1.1.1.5   root     1282:        addr &= ~15;
1.1.1.7 ! root     1283:        if ((!mmu_ttr_enabled || mmu_match_ttr_write(addr,super,data,val[0],size) == TTR_NO_MATCH) && regs.mmu_enabled) {
        !          1284:                addr = mmu_translate(addr, val[0], super, data, true, size);
        !          1285:        }
        !          1286:        // MOVE16 write invalidates existing line and also does not allocate new cache lines.
        !          1287:        mmu_cache_state = CACHE_DISABLE_MMU;
1.1.1.5   root     1288:        for (i = 0; i < 4; i++) {
1.1.1.7 ! root     1289:                x_phys_put_long(addr + i * 4, val[i]);
1.1.1.5   root     1290:        }
                   1291: }
                   1292: 
                   1293: 
1.1.1.3   root     1294: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
                   1295: {
                   1296:        bool super = (regs.dfc & 4) != 0;
                   1297:        DUNUSED(extra);
1.1.1.5   root     1298:        if ((opcode & 0xFE0) == 0x0500) { // PFLUSH
1.1.1.3   root     1299:                bool glob;
                   1300:                int regno;
                   1301:                //D(didflush = 0);
                   1302:                uae_u32 addr;
                   1303:                /* PFLUSH */
                   1304:                regno = opcode & 7;
                   1305:                glob = (opcode & 8) != 0;
                   1306: 
                   1307:                if (opcode & 16) {
1.1.1.5   root     1308: #if MMUINSDEBUG > 1
                   1309:                        write_log(_T("pflusha(%u,%u) PC=%08x\n"), glob, regs.dfc, m68k_getpc ());
                   1310: #endif
1.1.1.3   root     1311:                        mmu_flush_atc_all(glob);
                   1312:                } else {
                   1313:                        addr = m68k_areg(regs, regno);
1.1.1.5   root     1314: #if MMUINSDEBUG > 1
                   1315:                        write_log(_T("pflush(%u,%u,%x) PC=%08x\n"), glob, regs.dfc, addr, m68k_getpc ());
                   1316: #endif
1.1.1.3   root     1317:                        mmu_flush_atc(addr, super, glob);
                   1318:                }
                   1319:                flush_internals();
                   1320: #ifdef USE_JIT
                   1321:                flush_icache(0);
                   1322: #endif
1.1.1.5   root     1323:        } else if ((opcode & 0x0FD8) == 0x0548) { // PTEST (68040)
1.1.1.3   root     1324:                bool write;
                   1325:                int regno;
                   1326:                uae_u32 addr;
1.1.1.7 ! root     1327:                uae_u32 status060 = 0;
1.1.1.3   root     1328: 
                   1329:                regno = opcode & 7;
                   1330:                write = (opcode & 32) == 0;
                   1331:                addr = m68k_areg(regs, regno);
1.1.1.5   root     1332: #if MMUINSDEBUG > 0
                   1333:                write_log(_T("PTEST%c (A%d) %08x DFC=%d\n"), write ? 'W' : 'R', regno, addr, regs.dfc);
                   1334: #endif
1.1.1.3   root     1335:                mmu_flush_atc(addr, super, true);
1.1.1.7 ! root     1336:                bool data = (regs.dfc & 3) != 2;
        !          1337:                int ttr_match = mmu_match_ttr(addr,super,data);
        !          1338:                if (ttr_match != TTR_NO_MATCH) {
        !          1339:                        if (ttr_match == TTR_NO_WRITE && write) {
        !          1340:                                regs.mmusr = MMU_MMUSR_B;
1.1.1.5   root     1341:                        } else {
1.1.1.7 ! root     1342:                                regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
1.1.1.3   root     1343:                        }
1.1.1.7 ! root     1344:                } else if (!currprefs.mmu_ec) {
        !          1345:                        int way;
        !          1346:                        uae_u32 index;
        !          1347:                        uae_u32 tag = ((super ? 0x80000000 : 0x00000000) | (addr >> 1)) & mmu_tagmask;
        !          1348:                        if (mmu_pagesize_8k)
        !          1349:                                index=(addr & 0x0001E000)>>13;
        !          1350:                        else
        !          1351:                                index=(addr & 0x0000F000)>>12;
        !          1352:                        for (way = 0; way < ATC_WAYS; way++) {
        !          1353:                                if (!mmu_atc_array[data][index][way].valid)
        !          1354:                                        break;
        !          1355:                        }
        !          1356:                        if (way >= ATC_WAYS) {
        !          1357:                                way = way_random % ATC_WAYS;
        !          1358:                        }
        !          1359:                        regs.mmusr = mmu_fill_atc(addr, super, tag, write, &mmu_atc_array[data][index][way], &status060);
1.1.1.5   root     1360: #if MMUINSDEBUG > 0
1.1.1.7 ! root     1361:                        write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
1.1.1.5   root     1362: #endif
1.1.1.7 ! root     1363:                }
1.1.1.5   root     1364:        } else if ((opcode & 0xFFB8) == 0xF588) { // PLPA (68060)
                   1365:                int write = (opcode & 0x40) == 0;
                   1366:                int regno = opcode & 7;
                   1367:                uae_u32 addr = m68k_areg (regs, regno);
                   1368:                bool data = (regs.dfc & 3) != 2;
1.1.1.7 ! root     1369:                int ttr;
1.1.1.5   root     1370: 
                   1371: #if MMUINSDEBUG > 0
                   1372:                write_log(_T("PLPA%c param: %08x\n"), write ? 'W' : 'R', addr);
                   1373: #endif
1.1.1.7 ! root     1374:                if (write)
        !          1375:                        ttr = mmu_match_ttr_write(addr, super, data, 0, 1);
        !          1376:                else
        !          1377:                        ttr = mmu_match_ttr(addr,super,data);
        !          1378:                if (ttr == TTR_NO_MATCH) {
        !          1379:                        if (!currprefs.mmu_ec) {
        !          1380:                                m68k_areg (regs, regno) = mmu_translate(addr, 0, super, data, write, 1);
        !          1381:                        }
1.1.1.5   root     1382:                }
                   1383: #if MMUINSDEBUG > 0
                   1384:                write_log(_T("PLPA%c result: %08x\n"), write ? 'W' : 'R', m68k_areg (regs, regno));
                   1385: #endif
                   1386:        } else {
1.1.1.3   root     1387:                op_illg (opcode);
1.1.1.5   root     1388:        }
1.1.1.3   root     1389: }
                   1390: 
1.1.1.5   root     1391: // fixme : global parameter?
1.1.1.3   root     1392: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
                   1393: {
1.1.1.5   root     1394:        int way,type,index;
1.1.1.3   root     1395: 
1.1.1.5   root     1396:        uaecptr tag = ((super ? 0x80000000 : 0) | (addr >> 1)) & mmu_tagmask;
                   1397:        if (mmu_pagesize_8k)
                   1398:                index=(addr & 0x0001E000)>>13;
                   1399:        else
                   1400:                index=(addr & 0x0000F000)>>12;
                   1401:        for (type=0;type<ATC_TYPE;type++) {
                   1402:                for (way=0;way<ATC_WAYS;way++) {
1.1.1.7 ! root     1403:                        struct mmu_atc_line *l = &mmu_atc_array[type][index][way];
        !          1404:                        if (!global && (l->status & MMU_MMUSR_G))
1.1.1.5   root     1405:                                continue;
                   1406:                        // if we have this 
1.1.1.7 ! root     1407:                        if (tag == l->tag && l->valid) {
        !          1408:                                l->valid=false;
1.1.1.5   root     1409:                        }
                   1410:                }
                   1411:        }       
1.1.1.7 ! root     1412:        flush_shortcut_cache(addr, super);
        !          1413:        mmu_flush_cache();
1.1.1.3   root     1414: }
                   1415: 
                   1416: void REGPARAM2 mmu_flush_atc_all(bool global)
                   1417: {
1.1.1.7 ! root     1418:        int way,slot,type;
1.1.1.5   root     1419:        for (type=0;type<ATC_TYPE;type++) {
1.1.1.7 ! root     1420:                for (slot=0;slot<ATC_SLOTS;slot++) {
        !          1421:                        for (way=0;way<ATC_WAYS;way++) {
        !          1422:                                struct mmu_atc_line *l = &mmu_atc_array[type][slot][way];
        !          1423:                                if (!global && (l->status&MMU_MMUSR_G))
1.1.1.5   root     1424:                                        continue;
1.1.1.7 ! root     1425:                                l->valid=false;
1.1.1.5   root     1426:                        }
                   1427:                }
1.1.1.3   root     1428:        }
1.1.1.7 ! root     1429:        flush_shortcut_cache(0xffffffff, 0);
        !          1430:        mmu_flush_cache();
1.1.1.5   root     1431: }
1.1.1.3   root     1432: 
1.1.1.5   root     1433: void REGPARAM2 mmu_set_funcs(void)
                   1434: {
                   1435:        if (currprefs.mmu_model != 68040 && currprefs.mmu_model != 68060)
                   1436:                return;
1.1.1.7 ! root     1437:        if (currprefs.cpu_memory_cycle_exact || currprefs.cpu_compatible) {
1.1.1.5   root     1438:                x_phys_get_iword = get_word_icache040;
                   1439:                x_phys_get_ilong = get_long_icache040;
1.1.1.7 ! root     1440:                if (currprefs.cpu_data_cache) {
        !          1441:                        x_phys_get_byte = get_byte_cache_040;
        !          1442:                        x_phys_get_word = get_word_cache_040;
        !          1443:                        x_phys_get_long = get_long_cache_040;
        !          1444:                        x_phys_put_byte = put_byte_cache_040;
        !          1445:                        x_phys_put_word = put_word_cache_040;
        !          1446:                        x_phys_put_long = put_long_cache_040;
        !          1447:                } else if (currprefs.cpu_memory_cycle_exact) {
        !          1448:                        x_phys_get_byte = mem_access_delay_byte_read_c040;
        !          1449:                        x_phys_get_word = mem_access_delay_word_read_c040;
        !          1450:                        x_phys_get_long = mem_access_delay_long_read_c040;
        !          1451:                        x_phys_put_byte = mem_access_delay_byte_write_c040;
        !          1452:                        x_phys_put_word = mem_access_delay_word_write_c040;
        !          1453:                        x_phys_put_long = mem_access_delay_long_write_c040;
        !          1454:                } else {
        !          1455:                        x_phys_get_byte = phys_get_byte;
        !          1456:                        x_phys_get_word = phys_get_word;
        !          1457:                        x_phys_get_long = phys_get_long;
        !          1458:                        x_phys_put_byte = phys_put_byte;
        !          1459:                        x_phys_put_word = phys_put_word;
        !          1460:                        x_phys_put_long = phys_put_long;
        !          1461:                }
1.1.1.5   root     1462:        } else {
                   1463:                x_phys_get_iword = phys_get_word;
                   1464:                x_phys_get_ilong = phys_get_long;
                   1465:                x_phys_get_byte = phys_get_byte;
                   1466:                x_phys_get_word = phys_get_word;
                   1467:                x_phys_get_long = phys_get_long;
                   1468:                x_phys_put_byte = phys_put_byte;
                   1469:                x_phys_put_word = phys_put_word;
                   1470:                x_phys_put_long = phys_put_long;
1.1.1.3   root     1471:        }
                   1472: }
                   1473: 
                   1474: void REGPARAM2 mmu_reset(void)
                   1475: {
                   1476:        mmu_flush_atc_all(true);
1.1.1.5   root     1477:        mmu_set_funcs();
                   1478: }
                   1479: 
1.1.1.7 ! root     1480: uae_u16 REGPARAM2 mmu_set_tc(uae_u16 tc)
1.1.1.5   root     1481: {
1.1.1.7 ! root     1482:        if (currprefs.mmu_ec) {
        !          1483:                tc &= ~(0x8000 | 0x4000);
        !          1484:                // at least 68EC040 always returns zero when TC is read.
        !          1485:                if (currprefs.cpu_model == 68040)
        !          1486:                        tc = 0;
        !          1487:        }
        !          1488: 
1.1.1.5   root     1489:        regs.mmu_enabled = (tc & 0x8000) != 0;
                   1490:        mmu_pagesize_8k = (tc & 0x4000) != 0;
1.1.1.7 ! root     1491: 
1.1.1.5   root     1492:        mmu_tagmask  = mmu_pagesize_8k ? 0xFFFF0000 : 0xFFFF8000;
                   1493:        mmu_pagemask = mmu_pagesize_8k ? 0x00001FFF : 0x00000FFF;
                   1494:        mmu_pagemaski = ~mmu_pagemask;
                   1495:        regs.mmu_page_size = mmu_pagesize_8k ? 8192 : 4096;
1.1.1.7 ! root     1496:        mmu_pageshift = mmu_pagesize_8k ? 13 : 12;
        !          1497:        mmu_pageshift1m = mmu_pageshift - 1;
        !          1498: 
        !          1499:        cache_default_ins = CACHE_ENABLE_ALL;
        !          1500:        cache_default_data = CACHE_ENABLE_ALL;
        !          1501:        if (currprefs.mmu_model == 68060) {
        !          1502:                int dc = (tc >> 3) & 3;
        !          1503:                cache_default_ins = 0;
        !          1504:                if (!(dc & 2))
        !          1505:                        cache_default_ins = CACHE_ENABLE_ALL;
        !          1506:                dc = (tc >> 8) & 3;
        !          1507:                cache_default_data = 0;
        !          1508:                if (!(dc & 2))
        !          1509:                        cache_default_data = (dc & 1) ? CACHE_ENABLE_COPYBACK | CACHE_ENABLE_ALL : CACHE_ENABLE_ALL;
        !          1510:        }
1.1.1.5   root     1511: 
                   1512:        mmu_flush_atc_all(true);
                   1513: 
1.1.1.7 ! root     1514:        write_log(_T("%d MMU: TC=%04x enabled=%d page8k=%d PC=%08x\n"), tc, currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k, m68k_getpc());
        !          1515:        return tc;
1.1.1.3   root     1516: }
                   1517: 
1.1.1.5   root     1518: void REGPARAM2 mmu_set_super(bool super)
                   1519: {
                   1520:        mmu_is_super = super ? 0x80000000 : 0;
                   1521: }
1.1.1.3   root     1522: 
1.1.1.7 ! root     1523: void REGPARAM2 mmu_flush_cache(void)
        !          1524: {
        !          1525: #if MMU_ICACHE
        !          1526:        int len = sizeof(mmu_icache_data);
        !          1527:        memset(&mmu_icache_data, 0xff, sizeof(mmu_icache_data));
        !          1528: #endif
        !          1529: }
        !          1530: 
1.1.1.5   root     1531: void m68k_do_rte_mmu040 (uaecptr a7)
                   1532: {
                   1533:        uae_u16 ssr = get_word_mmu040 (a7 + 8 + 4);
                   1534:        if (ssr & MMU_SSW_CT) {
                   1535:                uaecptr src_a7 = a7 + 8 - 8;
                   1536:                uaecptr dst_a7 = a7 + 8 + 52;
                   1537:                put_word_mmu040 (dst_a7 + 0, get_word_mmu040 (src_a7 + 0));
                   1538:                put_long_mmu040 (dst_a7 + 2, get_long_mmu040 (src_a7 + 2));
                   1539:                // skip this word
                   1540:                put_long_mmu040 (dst_a7 + 8, get_long_mmu040 (src_a7 + 8));
                   1541:        }
                   1542:        if (ssr & MMU_SSW_CM) {
                   1543:                mmu040_movem = 1;
                   1544:                mmu040_movem_ea = get_long_mmu040 (a7 + 8);
                   1545: #if MMUDEBUGMISC > 0
                   1546:                write_log (_T("MMU restarted MOVEM EA=%08X\n"), mmu040_movem_ea);
                   1547: #endif
                   1548:        }
                   1549: }
                   1550: 
                   1551: void m68k_do_rte_mmu060 (uaecptr a7)
1.1.1.3   root     1552: {
                   1553: #if 0
1.1.1.5   root     1554:        mmu060_state = 2;
1.1.1.3   root     1555: #endif
1.1.1.5   root     1556: }
1.1.1.3   root     1557: 
1.1.1.5   root     1558: void flush_mmu040 (uaecptr addr, int n)
                   1559: {
1.1.1.7 ! root     1560:        mmu_flush_cache();
1.1.1.5   root     1561: }
1.1.1.7 ! root     1562: 
1.1.1.5   root     1563: void m68k_do_rts_mmu040 (void)
                   1564: {
                   1565:        uaecptr stack = m68k_areg (regs, 7);
                   1566:        uaecptr newpc = get_long_mmu040 (stack);
                   1567:        m68k_areg (regs, 7) += 4;
                   1568:        m68k_setpc (newpc);
                   1569: }
                   1570: void m68k_do_bsr_mmu040 (uaecptr oldpc, uae_s32 offset)
                   1571: {
                   1572:        uaecptr newstack = m68k_areg (regs, 7) - 4;
                   1573:        put_long_mmu040 (newstack, oldpc);
                   1574:        m68k_areg (regs, 7) -= 4;
                   1575:        m68k_incpci (offset);
1.1.1.3   root     1576: }
                   1577: 
1.1.1.5   root     1578: void flush_mmu060 (uaecptr addr, int n)
                   1579: {
1.1.1.7 ! root     1580:        mmu_flush_cache();
1.1.1.5   root     1581: }
1.1.1.7 ! root     1582: 
1.1.1.5   root     1583: void m68k_do_rts_mmu060 (void)
1.1.1.3   root     1584: {
1.1.1.5   root     1585:        uaecptr stack = m68k_areg (regs, 7);
                   1586:        uaecptr newpc = get_long_mmu060 (stack);
                   1587:        m68k_areg (regs, 7) += 4;
                   1588:        m68k_setpc (newpc);
                   1589: }
                   1590: void m68k_do_bsr_mmu060 (uaecptr oldpc, uae_s32 offset)
                   1591: {
                   1592:        uaecptr newstack = m68k_areg (regs, 7) - 4;
                   1593:        put_long_mmu060 (newstack, oldpc);
                   1594:        m68k_areg (regs, 7) -= 4;
                   1595:        m68k_incpci (offset);
                   1596: }
                   1597: 
                   1598: void uae_mmu_put_lrmw (uaecptr addr, uae_u32 v, int size, int type)
                   1599: {
                   1600:        locked_rmw_cycle = true;
                   1601:        if (size == sz_byte) {
1.1.1.7 ! root     1602:                mmu_put_user_byte(addr, v, regs.s, sz_byte, true);
1.1.1.5   root     1603:        } else if (size == sz_word) {
                   1604:                if (unlikely(is_unaligned(addr, 2))) {
1.1.1.7 ! root     1605:                        mmu_put_lrmw_word_unaligned(addr, v);
1.1.1.5   root     1606:                } else {
1.1.1.7 ! root     1607:                        mmu_put_user_word(addr, v, regs.s != 0, sz_word, true);
1.1.1.5   root     1608:                }
                   1609:        } else {
                   1610:                if (unlikely(is_unaligned(addr, 4)))
1.1.1.7 ! root     1611:                        mmu_put_lrmw_long_unaligned(addr, v);
1.1.1.5   root     1612:                else
1.1.1.7 ! root     1613:                        mmu_put_user_long(addr, v, regs.s, sz_long, true);
1.1.1.5   root     1614:        }
                   1615:        locked_rmw_cycle = false;
                   1616: }
                   1617: uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type)
                   1618: {
                   1619:        uae_u32 v;
                   1620:        locked_rmw_cycle = true;
                   1621:        if (size == sz_byte) {
1.1.1.7 ! root     1622:                v = mmu_get_user_byte(addr, regs.s != 0, true, sz_byte, true);
1.1.1.5   root     1623:        } else if (size == sz_word) {
                   1624:                if (unlikely(is_unaligned(addr, 2))) {
                   1625:                        v = mmu_get_lrmw_word_unaligned(addr);
                   1626:                } else {
1.1.1.7 ! root     1627:                        v = mmu_get_user_word(addr, regs.s != 0, true, sz_word, true);
1.1.1.5   root     1628:                }
                   1629:        } else {
                   1630:                if (unlikely(is_unaligned(addr, 4)))
                   1631:                        v = mmu_get_lrmw_long_unaligned(addr);
                   1632:                else
1.1.1.7 ! root     1633:                        v = mmu_get_user_long(addr, regs.s != 0, true, sz_long, true);
1.1.1.5   root     1634:        }
                   1635:        locked_rmw_cycle = false;
                   1636:        return v;
                   1637: }
                   1638: 
                   1639: uae_u32 REGPARAM2 mmu060_get_rmw_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width)
                   1640: {
                   1641:        uae_u32 tmp1, tmp2, res, mask;
                   1642: 
                   1643:        offset &= 7;
                   1644:        mask = 0xffffffffu << (32 - width);
                   1645:        switch ((offset + width + 7) >> 3) {
                   1646:        case 1:
                   1647:                tmp1 = get_rmw_byte_mmu060 (src);
                   1648:                res = tmp1 << (24 + offset);
                   1649:                bdata[0] = tmp1 & ~(mask >> (24 + offset));
                   1650:                break;
                   1651:        case 2:
                   1652:                tmp1 = get_rmw_word_mmu060 (src);
                   1653:                res = tmp1 << (16 + offset);
                   1654:                bdata[0] = tmp1 & ~(mask >> (16 + offset));
                   1655:                break;
                   1656:        case 3:
                   1657:                tmp1 = get_rmw_word_mmu060 (src);
                   1658:                tmp2 = get_rmw_byte_mmu060 (src + 2);
                   1659:                res = tmp1 << (16 + offset);
                   1660:                bdata[0] = tmp1 & ~(mask >> (16 + offset));
                   1661:                res |= tmp2 << (8 + offset);
                   1662:                bdata[1] = tmp2 & ~(mask >> (8 + offset));
                   1663:                break;
                   1664:        case 4:
                   1665:                tmp1 = get_rmw_long_mmu060 (src);
                   1666:                res = tmp1 << offset;
                   1667:                bdata[0] = tmp1 & ~(mask >> offset);
                   1668:                break;
                   1669:        case 5:
                   1670:                tmp1 = get_rmw_long_mmu060 (src);
                   1671:                tmp2 = get_rmw_byte_mmu060 (src + 4);
                   1672:                res = tmp1 << offset;
                   1673:                bdata[0] = tmp1 & ~(mask >> offset);
                   1674:                res |= tmp2 >> (8 - offset);
                   1675:                bdata[1] = tmp2 & ~(mask << (8 - offset));
                   1676:                break;
                   1677:        default:
                   1678:                /* Panic? */
                   1679:                write_log (_T("x_get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3);
                   1680:                res = 0;
                   1681:                break;
                   1682:        }
                   1683:        return res;
                   1684: }
                   1685: 
                   1686: void REGPARAM2 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width)
                   1687: {
                   1688:        offset = (offset & 7) + width;
                   1689:        switch ((offset + 7) >> 3) {
                   1690:        case 1:
                   1691:                put_rmw_byte_mmu060 (dst, bdata[0] | (val << (8 - offset)));
                   1692:                break;
                   1693:        case 2:
                   1694:                put_rmw_word_mmu060 (dst, bdata[0] | (val << (16 - offset)));
                   1695:                break;
                   1696:        case 3:
                   1697:                put_rmw_word_mmu060 (dst, bdata[0] | (val >> (offset - 16)));
                   1698:                put_rmw_byte_mmu060 (dst + 2, bdata[1] | (val << (24 - offset)));
                   1699:                break;
                   1700:        case 4:
                   1701:                put_rmw_long_mmu060 (dst, bdata[0] | (val << (32 - offset)));
                   1702:                break;
                   1703:        case 5:
                   1704:                put_rmw_long_mmu060 (dst, bdata[0] | (val >> (offset - 32)));
                   1705:                put_rmw_byte_mmu060 (dst + 4, bdata[1] | (val << (40 - offset)));
                   1706:                break;
                   1707:        default:
                   1708:                write_log (_T("x_put_bitfield() can't happen %d\n"), (offset + 7) >> 3);
                   1709:                break;
                   1710:        }
1.1.1.3   root     1711: }
                   1712: 
1.1.1.5   root     1713: 
                   1714: #ifndef __cplusplus
1.1.1.3   root     1715: jmp_buf __exbuf;
                   1716: int     __exvalue;
                   1717: #define MAX_TRY_STACK 256
                   1718: static int s_try_stack_size=0;
                   1719: static jmp_buf s_try_stack[MAX_TRY_STACK];
                   1720: jmp_buf* __poptry(void) {
                   1721:        if (s_try_stack_size>0) {
1.1.1.7 ! root     1722:                s_try_stack_size--;
        !          1723:                if (s_try_stack_size == 0)
        !          1724:                        return NULL;
        !          1725:                memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
        !          1726:                // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
        !          1727:                return &s_try_stack[s_try_stack_size-1];
        !          1728:        }
1.1.1.3   root     1729:        else {
                   1730:                fprintf(stderr,"try stack underflow...\n");
1.1.1.7 ! root     1731:                // return (NULL);
1.1.1.5   root     1732:                abort();
1.1.1.3   root     1733:        }
                   1734: }
                   1735: void __pushtry(jmp_buf* j) {
                   1736:        if (s_try_stack_size<MAX_TRY_STACK) {
1.1.1.7 ! root     1737:                // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
1.1.1.3   root     1738:                memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
                   1739:                s_try_stack_size++;
                   1740:        } else {
                   1741:                fprintf(stderr,"try stack overflow...\n");
1.1.1.5   root     1742:                abort();
1.1.1.3   root     1743:        }
                   1744: }
                   1745: int __is_catched(void) {return (s_try_stack_size>0); }
1.1.1.5   root     1746: #endif
                   1747: 
1.1.1.3   root     1748: #else
                   1749: 
                   1750: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
                   1751: {
                   1752:        if ((opcode & 0xFE0) == 0x0500) {
                   1753:                /* PFLUSH instruction */
                   1754:                flush_internals();
                   1755:        } else if ((opcode & 0x0FD8) == 0x548) {
                   1756:                /* PTEST instruction */
                   1757:        } else
                   1758:                op_illg(opcode);
                   1759: }
                   1760: 
                   1761: #endif
                   1762: 
1.1.1.5   root     1763: 
1.1.1.3   root     1764: /*
                   1765: vim:ts=4:sw=4:
                   1766: */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.