Annotation of previous_trunk/src/cpu/cpummu.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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