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

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

unix.superglobalmegacorp.com

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