Annotation of previous/src/cpu/cpummu.c, revision 1.1.1.5

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

unix.superglobalmegacorp.com

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