Annotation of hatari/src/cpu/cpummu030.c, revision 1.1.1.6

1.1       root        1: /* Emulation of MC68030 MMU
                      2:  * This code has been written for Previous - a NeXT Computer emulator
                      3:  *
                      4:  * This file is distributed under the GNU General Public License, version 2
                      5:  * or at your option any later version. Read the file gpl.txt for details.
                      6:  *
                      7:  *
                      8:  * Written by Andreas Grabher
                      9:  *
                     10:  * Many thanks go to Thomas Huth and the Hatari community for helping
                     11:  * to test and debug this code!
                     12:  *
                     13:  *
                     14:  * Release notes:
                     15:  * 01-09-2012: First release
                     16:  * 29-09-2012: Improved function code handling
                     17:  * 16-11-2012: Improved exception handling
                     18:  *
                     19:  *
                     20:  * - Check if read-modify-write operations are correctly detected for
                     21:  *   handling transparent access (see TT matching functions)
                     22:  * - If possible, test mmu030_table_search with all kinds of translations
                     23:  *   (early termination, invalid descriptors, bus errors, indirect
                     24:  *   descriptors, PTEST in different levels, etc).
1.1.1.3   root       25:  * - Check which bits of an ATC entry or the status register should be set 
                     26:  *   and which should be un-set, if an invalid translation occurs.
1.1       root       27:  * - Handle cache inhibit bit when accessing ATC entries
                     28:  */
                     29: 
                     30: 
                     31: #include "sysconfig.h"
                     32: #include "sysdeps.h"
                     33: 
1.1.1.6 ! root       34: #ifdef WINUAE_FOR_HATARI
1.1.1.3   root       35: #include "main.h"
                     36: #include "hatari-glue.h"
1.1.1.6 ! root       37: #include "log.h"
        !            38: #endif
1.1.1.3   root       39: 
1.1       root       40: #include "options_cpu.h"
                     41: #include "memory.h"
                     42: #include "newcpu.h"
1.1.1.5   root       43: #include "debug.h"
1.1       root       44: #include "cpummu030.h"
                     45: 
                     46: #define MMU030_OP_DBG_MSG 0
                     47: #define MMU030_ATC_DBG_MSG 0
                     48: #define MMU030_REG_DBG_MSG 0
                     49: 
1.1.1.3   root       50: #define TT_FC_MASK      0x00000007
                     51: #define TT_FC_BASE      0x00000070
                     52: #define TT_RWM          0x00000100
                     53: #define TT_RW           0x00000200
                     54: #define TT_CI           0x00000400
                     55: #define TT_ENABLE       0x00008000
                     56: 
                     57: #define TT_ADDR_MASK    0x00FF0000
                     58: #define TT_ADDR_BASE    0xFF000000
                     59: 
                     60: static int bBusErrorReadWrite;
                     61: static int atcindextable[32];
                     62: static int tt_enabled;
                     63: 
                     64: int mmu030_idx;
                     65: 
                     66: uae_u32 mm030_stageb_address;
                     67: bool mmu030_retry;
                     68: int mmu030_opcode;
                     69: int mmu030_opcode_stageb;
                     70: 
                     71: int mmu030_fake_prefetch;
                     72: uaecptr mmu030_fake_prefetch_addr;
                     73: 
                     74: uae_u16 mmu030_state[3];
1.1.1.6 ! root       75: uae_u32 mmu030_data_buffer_out;
1.1.1.3   root       76: uae_u32 mmu030_disp_store[2];
                     77: uae_u32 mmu030_fmovem_store[2];
1.1.1.5   root       78: uae_u8 mmu030_cache_state;
1.1.1.6 ! root       79: struct mmu030_access mmu030_ad[MAX_MMU030_ACCESS + 1];
        !            80: 
        !            81: static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write);
        !            82: static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level);
        !            83: static TT_info mmu030_decode_tt(uae_u32 TT);
1.1       root       84: 
1.1.1.5   root       85: #if MMU_DPAGECACHE030
                     86: #define MMUFASTCACHE_ENTRIES030 256
                     87: struct mmufastcache030
                     88: {
                     89:        uae_u32 log;
                     90:        uae_u32 phys;
                     91:        uae_u8 cs;
                     92: };
                     93: static struct mmufastcache030 atc_data_cache_read[MMUFASTCACHE_ENTRIES030];
                     94: static struct mmufastcache030 atc_data_cache_write[MMUFASTCACHE_ENTRIES030];
                     95: #endif
                     96: 
1.1       root       97: /* for debugging messages */
                     98: char table_letter[4] = {'A','B','C','D'};
                     99: 
1.1.1.5   root      100: static const uae_u32 mmu030_size[3] = { MMU030_SSW_SIZE_B, MMU030_SSW_SIZE_W, MMU030_SSW_SIZE_L };
                    101: 
1.1.1.3   root      102: uae_u64 srp_030, crp_030;
                    103: uae_u32 tt0_030, tt1_030, tc_030;
                    104: uae_u16 mmusr_030;
1.1       root      105: 
                    106: /* ATC struct */
                    107: #define ATC030_NUM_ENTRIES  22
                    108: 
                    109: typedef struct {
                    110:     struct {
                    111:         uaecptr addr;
                    112:         bool modified;
                    113:         bool write_protect;
1.1.1.5   root      114:         uae_u8 cache_inhibit;
1.1       root      115:         bool bus_error;
                    116:     } physical;
                    117:     
                    118:     struct {
                    119:         uaecptr addr;
                    120:         uae_u32 fc;
                    121:         bool valid;
                    122:     } logical;
                    123:     /* history bit */
                    124:     int mru;
                    125: } MMU030_ATC_LINE;
                    126: 
                    127: 
                    128: /* MMU struct for 68030 */
1.1.1.3   root      129: static struct {
1.1       root      130:     
                    131:     /* Translation tables */
                    132:     struct {
                    133:         struct {
                    134:             uae_u32 mask;
                    135:             uae_u8 shift;
                    136:         } table[4];
                    137:         
                    138:         struct {
                    139:             uae_u32 mask;
1.1.1.3   root      140:                        uae_u32 imask;
1.1.1.5   root      141:             uae_u32 size;
                    142:                        uae_u32 size3m;
1.1       root      143:         } page;
                    144:         
                    145:         uae_u8 init_shift;
                    146:         uae_u8 last_table;
                    147:     } translation;
                    148:     
                    149:     /* Transparent translation */
                    150:     struct {
                    151:         TT_info tt0;
                    152:         TT_info tt1;
                    153:     } transparent;
                    154:     
                    155:     /* Address translation cache */
                    156:     MMU030_ATC_LINE atc[ATC030_NUM_ENTRIES];
                    157:     
                    158:     /* Condition */
                    159:     bool enabled;
                    160:     uae_u16 status;
                    161: 
1.1.1.5   root      162: #if MMU_IPAGECACHE030
                    163:        uae_u8 mmu030_cache_state;
                    164: #if MMU_DIRECT_ACCESS
                    165:        uae_u8 *mmu030_last_physical_address_real;
                    166: #else
                    167:        uae_u32 mmu030_last_physical_address;
                    168: #endif
                    169:        uae_u32 mmu030_last_logical_address;
                    170: #endif
1.1       root      171: 
1.1.1.5   root      172: } mmu030;
1.1       root      173: 
                    174: /* MMU Status Register
                    175:  *
                    176:  * ---x ---x x-xx x---
                    177:  * reserved (all 0)
                    178:  *
                    179:  * x--- ---- ---- ----
                    180:  * bus error
                    181:  *
                    182:  * -x-- ---- ---- ----
                    183:  * limit violation
                    184:  *
                    185:  * --x- ---- ---- ----
                    186:  * supervisor only
                    187:  *
                    188:  * ---- x--- ---- ----
                    189:  * write protected
                    190:  *
                    191:  * ---- -x-- ---- ----
                    192:  * invalid
                    193:  *
                    194:  * ---- --x- ---- ----
                    195:  * modified
                    196:  *
                    197:  * ---- ---- -x-- ----
                    198:  * transparent access
                    199:  *
                    200:  * ---- ---- ---- -xxx
                    201:  * number of levels (number of tables accessed during search)
                    202:  *
                    203:  */
                    204: 
                    205: #define MMUSR_BUS_ERROR         0x8000
                    206: #define MMUSR_LIMIT_VIOLATION   0x4000
                    207: #define MMUSR_SUPER_VIOLATION   0x2000
                    208: #define MMUSR_WRITE_PROTECTED   0x0800
                    209: #define MMUSR_INVALID           0x0400
                    210: #define MMUSR_MODIFIED          0x0200
                    211: #define MMUSR_TRANSP_ACCESS     0x0040
                    212: #define MMUSR_NUM_LEVELS_MASK   0x0007
                    213: 
1.1.1.5   root      214: /* -- ATC flushing functions -- */
                    215: 
                    216: static void mmu030_flush_cache(uaecptr addr)
                    217: {
                    218: #if MMU_IPAGECACHE030
                    219:        mmu030.mmu030_last_logical_address = 0xffffffff;
                    220: #endif
                    221: #if MMU_DPAGECACHE030
                    222:        if (addr == 0xffffffff) {
                    223:                memset(&atc_data_cache_read, 0xff, sizeof atc_data_cache_read);
                    224:                memset(&atc_data_cache_write, 0xff, sizeof atc_data_cache_write);
                    225:        } else {
                    226:                uae_u32 idx = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | 7;
1.1.1.6 ! root      227:                for (int i = 0; i < MMUFASTCACHE_ENTRIES030; i++) {
1.1.1.5   root      228:                        if ((atc_data_cache_read[i].log | 7) == idx)
                    229:                                atc_data_cache_read[i].log = 0xffffffff;
                    230:                        if ((atc_data_cache_write[i].log | 7) == idx)
                    231:                                atc_data_cache_write[i].log = 0xffffffff;
                    232:                }
                    233:        }
                    234: #endif
                    235: }
                    236: 
                    237: /* This function flushes ATC entries depending on their function code */
                    238: static void mmu030_flush_atc_fc(uae_u32 fc_base, uae_u32 fc_mask) {
                    239:     int i;
                    240:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                    241:         if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
                    242:             mmu030.atc[i].logical.valid) {
                    243:             mmu030.atc[i].logical.valid = false;
                    244: #if MMU030_OP_DBG_MSG
                    245:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
                    246: #endif
                    247:                }
                    248:     }
                    249:        mmu030_flush_cache(0xffffffff);
                    250: }
                    251: 
                    252: /* This function flushes ATC entries depending on their logical address
                    253:  * and their function code */
                    254: static void mmu030_flush_atc_page_fc(uaecptr logical_addr, uae_u32 fc_base, uae_u32 fc_mask) {
                    255:     int i;
                    256:        logical_addr &= mmu030.translation.page.imask;
                    257:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                    258:         if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
                    259:             (mmu030.atc[i].logical.addr == logical_addr) &&
                    260:             mmu030.atc[i].logical.valid) {
                    261:             mmu030.atc[i].logical.valid = false;
                    262: #if MMU030_OP_DBG_MSG
                    263:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
                    264: #endif
                    265:                }
                    266:     }
                    267:        mmu030_flush_cache(logical_addr);
                    268: }
                    269: 
                    270: /* This function flushes ATC entries depending on their logical address */
                    271: static void mmu030_flush_atc_page(uaecptr logical_addr) {
                    272:     int i;
                    273:        logical_addr &= mmu030.translation.page.imask;
                    274:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                    275:         if ((mmu030.atc[i].logical.addr == logical_addr) &&
                    276:             mmu030.atc[i].logical.valid) {
                    277:             mmu030.atc[i].logical.valid = false;
                    278: #if MMU030_OP_DBG_MSG
                    279:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
                    280: #endif
                    281:                }
                    282:     }
                    283:        mmu030_flush_cache(logical_addr);
                    284: }
1.1       root      285: 
1.1.1.5   root      286: /* This function flushes all ATC entries */
                    287: void mmu030_flush_atc_all(void) {
                    288: #if MMU030_OP_DBG_MSG
                    289:        write_log(_T("ATC: Flushing all entries\n"));
                    290: #endif
                    291:        int i;
                    292:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                    293:         mmu030.atc[i].logical.valid = false;
                    294:     }
                    295:        mmu030_flush_cache(0xffffffff);
                    296: }
1.1       root      297: 
1.1.1.6 ! root      298: /* -- Helper function for MMU instructions -- */
        !           299: static uae_u32 mmu_op30_helper_get_fc(uae_u16 next) {
        !           300:        switch (next & 0x0018) {
        !           301:        case 0x0010:
        !           302:        return (next & 0x7);
        !           303:        case 0x0008:
        !           304:        return (m68k_dreg(regs, next & 0x7) & 0x7);
        !           305:        case 0x0000:
        !           306:        if (next & 1) {
        !           307:                return (regs.dfc);
        !           308:        } else {
        !           309:                return (regs.sfc);
        !           310:        }
        !           311:        default:
        !           312:        write_log(_T("MMU_OP30 ERROR: bad fc source! (%04X)\n"), next & 0x0018);
        !           313:        return 0;
        !           314:        }
        !           315: }
        !           316: 
1.1       root      317: /* -- MMU instructions -- */
                    318: 
1.1.1.5   root      319: static bool mmu_op30_invea(uae_u32 opcode)
                    320: {
                    321:        int eamode = (opcode >> 3) & 7;
                    322:        int rreg = opcode & 7;
                    323: 
                    324:        // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
1.1.1.6 ! root      325:        if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || (eamode == 7 && rreg > 1))
1.1.1.5   root      326:                return true;
                    327:        return false;
                    328: }
                    329: 
1.1.1.3   root      330: bool mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1       root      331: {
                    332:        int preg = (next >> 10) & 31;
                    333:        int rw = (next >> 9) & 1;
                    334:        int fd = (next >> 8) & 1;
1.1.1.5   root      335:        int unused = (next & 0xff);
                    336:    
                    337:        if (mmu_op30_invea(opcode))
                    338:                return true;
                    339:        // unused low 8 bits must be zeroed
                    340:        if (unused)
                    341:                return true;
                    342:        // read and fd set?
                    343:        if (rw && fd)
                    344:                return true;
                    345: 
1.1       root      346: #if MMU030_OP_DBG_MSG
                    347:     switch (preg) {
                    348:         case 0x10:
1.1.1.5   root      349:             write_log(_T("PMOVE: %s TC %08X PC=%08x\n"), rw ? _T("read"):  _T("write"),
                    350:                       rw ? tc_030 : x_get_long(extra), m68k_getpc());
1.1       root      351:             break;
                    352:         case 0x12:
1.1.1.5   root      353:             write_log(_T("PMOVE: %s SRP %08X%08X PC=%08x\n"), rw ? _T("read") : _T("write"),
1.1       root      354:                       rw?(uae_u32)(srp_030>>32)&0xFFFFFFFF:x_get_long(extra),
1.1.1.5   root      355:                       rw?(uae_u32)srp_030&0xFFFFFFFF:x_get_long(extra+4), m68k_getpc());
1.1       root      356:             break;
                    357:         case 0x13:
1.1.1.5   root      358:             write_log(_T("PMOVE: %s CRP %08X%08X PC=%08x\n"), rw ? _T("read") : _T("write"),
1.1       root      359:                       rw?(uae_u32)(crp_030>>32)&0xFFFFFFFF:x_get_long(extra),
1.1.1.5   root      360:                       rw?(uae_u32)crp_030&0xFFFFFFFF:x_get_long(extra+4), m68k_getpc());
1.1       root      361:             break;
                    362:         case 0x18:
1.1.1.5   root      363:             write_log(_T("PMOVE: %s MMUSR %04X PC=%08x\n"), rw ? _T("read") : _T("write"),
                    364:                       rw?mmusr_030:x_get_word(extra), m68k_getpc());
1.1       root      365:             break;
                    366:         case 0x02:
1.1.1.5   root      367:             write_log(_T("PMOVE: %s TT0 %08X PC=%08x\n"), rw ? _T("read") : _T("write"),
                    368:                       rw?tt0_030:x_get_long(extra), m68k_getpc());
1.1       root      369:             break;
                    370:         case 0x03:
1.1.1.5   root      371:             write_log(_T("PMOVE: %s TT1 %08X PC=%08x\n"), rw ? _T("read") : _T("write"),
                    372:                       rw?tt1_030:x_get_long(extra), m68k_getpc());
1.1       root      373:             break;
                    374:         default:
                    375:             break;
                    376:     }
                    377:     if (!fd && !rw && !(preg==0x18)) {
1.1.1.3   root      378:         write_log(_T("PMOVE: flush ATC\n"));
1.1       root      379:     }
                    380: #endif
                    381:     
                    382:        switch (preg)
                    383:        {
                    384:         case 0x10: // TC
                    385:             if (rw)
                    386:                 x_put_long (extra, tc_030);
                    387:             else {
                    388:                 tc_030 = x_get_long (extra);
1.1.1.5   root      389:                 if (mmu030_decode_tc(tc_030, true))
1.1.1.3   root      390:                                        return true;
1.1       root      391:             }
                    392:             break;
                    393:         case 0x12: // SRP
                    394:             if (rw) {
                    395:                 x_put_long (extra, srp_030 >> 32);
                    396:                 x_put_long (extra + 4, srp_030);
                    397:             } else {
                    398:                 srp_030 = (uae_u64)x_get_long (extra) << 32;
                    399:                 srp_030 |= x_get_long (extra + 4);
1.1.1.3   root      400:                 if (mmu030_decode_rp(srp_030))
                    401:                                        return true;
1.1       root      402:             }
                    403:             break;
                    404:         case 0x13: // CRP
                    405:             if (rw) {
                    406:                 x_put_long (extra, crp_030 >> 32);
                    407:                 x_put_long (extra + 4, crp_030);
                    408:             } else {
                    409:                 crp_030 = (uae_u64)x_get_long (extra) << 32;
                    410:                 crp_030 |= x_get_long (extra + 4);
1.1.1.3   root      411:                 if (mmu030_decode_rp(crp_030))
                    412:                                        return true;
1.1       root      413:             }
                    414:             break;
                    415:         case 0x18: // MMUSR
1.1.1.5   root      416:                        if (fd) {
                    417:                                // FD must be always zero when MMUSR read or write
                    418:                                return true;
                    419:                        }
1.1       root      420:             if (rw)
                    421:                 x_put_word (extra, mmusr_030);
                    422:             else
                    423:                 mmusr_030 = x_get_word (extra);
                    424:             break;
                    425:         case 0x02: // TT0
                    426:             if (rw)
                    427:                 x_put_long (extra, tt0_030);
                    428:             else {
                    429:                 tt0_030 = x_get_long (extra);
                    430:                 mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
                    431:             }
                    432:             break;
                    433:         case 0x03: // TT1
                    434:             if (rw)
                    435:                 x_put_long (extra, tt1_030);
                    436:             else {
                    437:                 tt1_030 = x_get_long (extra);
                    438:                 mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
                    439:             }
                    440:             break;
                    441:         default:
1.1.1.3   root      442:             write_log (_T("Bad PMOVE at %08x\n"),m68k_getpc());
                    443:             return true;
1.1       root      444:        }
                    445:     
1.1.1.5   root      446:     if (!fd && !rw && preg != 0x18) {
1.1       root      447:         mmu030_flush_atc_all();
                    448:     }
1.1.1.3   root      449:        tt_enabled = (tt0_030 & TT_ENABLE) || (tt1_030 & TT_ENABLE);
                    450:        return false;
1.1       root      451: }
                    452: 
1.1.1.3   root      453: bool mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1       root      454: {
                    455:     mmu030.status = mmusr_030 = 0;
                    456:     
                    457:     int level = (next&0x1C00)>>10;
                    458:     int rw = (next >> 9) & 1;
                    459:     int a = (next >> 8) & 1;
                    460:     int areg = (next&0xE0)>>5;
                    461:     uae_u32 fc = mmu_op30_helper_get_fc(next);
                    462:     bool write = rw ? false : true;
                    463:     uae_u32 ret = 0;
1.1.1.5   root      464: 
                    465:        if (mmu_op30_invea(opcode))
                    466:                return true;
                    467:     if (!level && a) {
1.1.1.3   root      468:         write_log(_T("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n"));
                    469:         return true;
1.1       root      470:     }
                    471:         
                    472: #if MMU030_OP_DBG_MSG
1.1.1.5   root      473:     write_log(_T("PTEST%c: addr = %08X, fc = %i, level = %i, PC=%08x, "),
                    474:               rw?'R':'W', extra, fc, level, m68k_getpc());
1.1       root      475:     if (a) {
1.1.1.3   root      476:         write_log(_T("return descriptor to register A%i\n"), areg);
1.1       root      477:     } else {
1.1.1.3   root      478:         write_log(_T("do not return descriptor\n"));
1.1       root      479:     }
                    480: #endif
1.1.1.3   root      481:     
1.1       root      482:     if (!level) {
                    483:         mmu030_ptest_atc_search(extra, fc, write);
                    484:     } else {
1.1.1.6 ! root      485:         ret = mmu030_table_search(extra, fc, write, level);
1.1       root      486:         if (a) {
                    487:             m68k_areg (regs, areg) = ret;
                    488:         }
                    489:     }
                    490:     mmusr_030 = mmu030.status;
1.1.1.3   root      491:     
1.1       root      492: #if MMU030_OP_DBG_MSG
1.1.1.3   root      493:     write_log(_T("PTEST status: %04X, B = %i, L = %i, S = %i, W = %i, I = %i, M = %i, T = %i, N = %i\n"),
1.1       root      494:               mmusr_030, (mmusr_030&MMUSR_BUS_ERROR)?1:0, (mmusr_030&MMUSR_LIMIT_VIOLATION)?1:0,
                    495:               (mmusr_030&MMUSR_SUPER_VIOLATION)?1:0, (mmusr_030&MMUSR_WRITE_PROTECTED)?1:0,
                    496:               (mmusr_030&MMUSR_INVALID)?1:0, (mmusr_030&MMUSR_MODIFIED)?1:0,
                    497:               (mmusr_030&MMUSR_TRANSP_ACCESS)?1:0, mmusr_030&MMUSR_NUM_LEVELS_MASK);
                    498: #endif
1.1.1.3   root      499:        return false;
1.1       root      500: }
                    501: 
1.1.1.5   root      502: static bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1       root      503: {
                    504:     int rw = (next >> 9) & 1;
1.1.1.5   root      505:        int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
                    506:        uae_u32 fc = mmu_op30_helper_get_fc(next);
1.1       root      507:     bool write = rw ? false : true;
                    508: 
1.1.1.5   root      509:        if (mmu_op30_invea(opcode))
                    510:                return true;
                    511:        if (unused)
                    512:                return true;
                    513: 
1.1.1.3   root      514: #if 0
                    515:     write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
1.1       root      516: #endif
                    517: 
                    518:     mmu030_flush_atc_page(extra);
                    519:     mmu030_table_search(extra, fc, write, 0);
1.1.1.3   root      520:        return false;
1.1       root      521: }
                    522: 
1.1.1.3   root      523: bool mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
1.1       root      524: {
1.1.1.5   root      525:        uae_u16 mode = (next >> 8) & 31;
                    526:     uae_u32 fc_mask = (uae_u32)(next & 0x00E0) >> 5;
1.1       root      527:     uae_u32 fc_base = mmu_op30_helper_get_fc(next);
1.1.1.5   root      528:        uae_u32 fc_bits = next & 0x7f;
1.1       root      529:     
1.1.1.3   root      530: #if 0
1.1       root      531:     switch (mode) {
                    532:         case 0x1:
1.1.1.3   root      533:             write_log(_T("PFLUSH: Flush all entries\n"));
1.1       root      534:             break;
                    535:         case 0x4:
1.1.1.3   root      536:             write_log(_T("PFLUSH: Flush by function code only\n"));
                    537:             write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
1.1       root      538:             break;
                    539:         case 0x6:
1.1.1.3   root      540:             write_log(_T("PFLUSH: Flush by function code and effective address\n"));
                    541:             write_log(_T("PFLUSH: function code: base = %08X, mask = %08X\n"), fc_base, fc_mask);
                    542:             write_log(_T("PFLUSH: effective address = %08X\n"), extra);
1.1       root      543:             break;
                    544:         default:
                    545:             break;
                    546:     }
                    547: #endif
                    548:     
                    549:     switch (mode) {
1.1.1.6 ! root      550:                case 0x00: // PLOAD W
        !           551:                case 0x02: // PLOAD R
1.1.1.5   root      552:                        return mmu_op30_pload(pc, opcode, next, extra);
                    553:         case 0x04:
                    554:                        if (fc_bits)
                    555:                                return true;
1.1       root      556:             mmu030_flush_atc_all();
                    557:             break;
1.1.1.5   root      558:         case 0x10:
1.1       root      559:             mmu030_flush_atc_fc(fc_base, fc_mask);
                    560:             break;
1.1.1.5   root      561:         case 0x18:
                    562:                        if (mmu_op30_invea(opcode))
                    563:                                return true;
1.1       root      564:             mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
                    565:             break;
                    566:         default:
1.1.1.6 ! root      567:             write_log(_T("PFLUSH %04x-%04x ERROR: bad mode! (%i)\n"), opcode, next, mode);
1.1.1.5   root      568:                        return true;
1.1       root      569:     }
1.1.1.3   root      570:        return false;
1.1       root      571: }
                    572: 
                    573: 
                    574: /* Transparent Translation Registers (TT0 and TT1)
                    575:  *
                    576:  * ---- ---- ---- ---- -xxx x--- x--- x---
                    577:  * reserved, must be 0
                    578:  *
                    579:  * ---- ---- ---- ---- ---- ---- ---- -xxx
                    580:  * function code mask (FC bits to be ignored)
                    581:  *
                    582:  * ---- ---- ---- ---- ---- ---- -xxx ----
                    583:  * function code base (FC value for transparent block)
                    584:  *
                    585:  * ---- ---- ---- ---- ---- ---x ---- ----
                    586:  * 0 = r/w field used, 1 = read and write is transparently translated
                    587:  *
                    588:  * ---- ---- ---- ---- ---- --x- ---- ----
                    589:  * r/w field: 0 = write ..., 1 = read access transparent
                    590:  *
                    591:  * ---- ---- ---- ---- ---- -x-- ---- ----
                    592:  * cache inhibit: 0 = caching allowed, 1 = caching inhibited
                    593:  *
                    594:  * ---- ---- ---- ---- x--- ---- ---- ----
                    595:  * 0 = transparent translation enabled disabled, 1 = enabled
                    596:  *
                    597:  * ---- ---- xxxx xxxx ---- ---- ---- ----
                    598:  * logical address mask
                    599:  *
                    600:  * xxxx xxxx ---- ---- ---- ---- ---- ----
                    601:  * logical address base
                    602:  *
                    603:  */
                    604: 
1.1.1.5   root      605: /* TT comparison results */
1.1       root      606: #define TT_NO_MATCH    0x1
                    607: #define TT_OK_MATCH    0x2
                    608: #define TT_NO_READ  0x4
                    609: #define TT_NO_WRITE    0x8
                    610: 
                    611: TT_info mmu030_decode_tt(uae_u32 TT) {
                    612:     
                    613:     TT_info ret;
                    614: 
                    615:     ret.fc_mask = ~((TT&TT_FC_MASK)|0xFFFFFFF8);
                    616:     ret.fc_base = (TT&TT_FC_BASE)>>4;
                    617:     ret.addr_base = TT & TT_ADDR_BASE;
                    618:     ret.addr_mask = ~(((TT&TT_ADDR_MASK)<<8)|0x00FFFFFF);
                    619:     
1.1.1.3   root      620: #if 0
1.1       root      621:     if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
1.1.1.3   root      622:         write_log(_T("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n"));
1.1       root      623:     }
1.1.1.3   root      624: #endif
                    625: 
1.1       root      626: #if MMU030_REG_DBG_MSG /* enable or disable debugging messages */
1.1.1.3   root      627:     write_log(_T("\n"));
                    628:     write_log(_T("TRANSPARENT TRANSLATION: %08X\n"), TT);
                    629:     write_log(_T("\n"));
1.1       root      630:     
1.1.1.3   root      631:     write_log(_T("TT: transparent translation "));
1.1       root      632:     if (TT&TT_ENABLE) {
1.1.1.3   root      633:         write_log(_T("enabled\n"));
1.1       root      634:     } else {
1.1.1.3   root      635:         write_log(_T("disabled\n"));
1.1       root      636:         return ret;
                    637:     }
                    638: 
1.1.1.3   root      639:     write_log(_T("TT: caching %s\n"), (TT&TT_CI) ? _T("inhibited") : _T("enabled"));
                    640:     write_log(_T("TT: read-modify-write "));
1.1       root      641:     if (TT&TT_RWM) {
1.1.1.3   root      642:         write_log(_T("enabled\n"));
1.1       root      643:     } else {
1.1.1.3   root      644:         write_log(_T("disabled (%s only)\n"), (TT&TT_RW) ? _T("read") : _T("write"));
1.1       root      645:     }
1.1.1.3   root      646:     write_log(_T("\n"));
                    647:     write_log(_T("TT: function code base: %08X\n"), ret.fc_base);
                    648:     write_log(_T("TT: function code mask: %08X\n"), ret.fc_mask);
                    649:     write_log(_T("\n"));
                    650:     write_log(_T("TT: address base: %08X\n"), ret.addr_base);
                    651:     write_log(_T("TT: address mask: %08X\n"), ret.addr_mask);
                    652:     write_log(_T("\n"));
1.1       root      653: #endif
                    654:     
                    655:     return ret;
                    656: }
                    657: 
                    658: /* This function checks if an address matches a transparent
                    659:  * translation register */
                    660: 
                    661: /* FIXME:
                    662:  * If !(tt&TT_RMW) neither the read nor the write portion
                    663:  * of a read-modify-write cycle is transparently translated! */
                    664: 
1.1.1.5   root      665: static int mmu030_do_match_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc, bool write)
1.1       root      666: {
                    667:        if (tt & TT_ENABLE)     {       /* transparent translation enabled */
1.1.1.5   root      668: 
1.1       root      669:         /* Compare actual function code with function code base using mask */
                    670:         if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
1.1.1.5   root      671: 
1.1       root      672:             /* Compare actual address with address base using mask */
                    673:             if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
                    674:                 if (tt&TT_RWM) {  /* r/w field disabled */
                    675:                     return TT_OK_MATCH;
                    676:                 } else {
                    677:                     if (tt&TT_RW) { /* read access transparent */
                    678:                         return write ? TT_NO_WRITE : TT_OK_MATCH;
                    679:                     } else {        /* write access transparent */
                    680:                         return write ? TT_OK_MATCH : TT_NO_READ; /* TODO: check this! */
                    681:                     }
                    682:                 }
                    683:             }
                    684:                }
                    685:        }
                    686:        return TT_NO_MATCH;
                    687: }
                    688: 
1.1.1.5   root      689: static int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
1.1.1.3   root      690: {
                    691:        if ((tt & TT_ENABLE) && (tt & TT_RWM))  {       /* transparent translation enabled */
1.1.1.5   root      692: 
1.1.1.3   root      693:         /* Compare actual function code with function code base using mask */
                    694:         if ((comp.fc_base&comp.fc_mask)==(fc&comp.fc_mask)) {
1.1.1.5   root      695: 
1.1.1.3   root      696:             /* Compare actual address with address base using mask */
                    697:             if ((comp.addr_base&comp.addr_mask)==(addr&comp.addr_mask)) {
                    698:                                return TT_OK_MATCH;
                    699:             }
                    700:                }
                    701:        }
                    702:        return TT_NO_MATCH;
                    703: }
                    704: 
1.1.1.5   root      705: /* This function compares the address with both transparent
                    706:  * translation registers and returns the result */
                    707: 
                    708: static int mmu030_match_ttr(uaecptr addr, uae_u32 fc, bool write)
                    709: {
                    710:     int tt0, tt1;
                    711: 
                    712:     tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
                    713:     if (tt0&TT_OK_MATCH) {
                    714:                if (tt0_030&TT_CI)
                    715:                mmu030_cache_state = CACHE_DISABLE_MMU;
                    716:        }
                    717:     tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
                    718:     if (tt1&TT_OK_MATCH) {
                    719:                if (tt0_030&TT_CI)
                    720:                mmu030_cache_state = CACHE_DISABLE_MMU;
                    721:     }
                    722:     
                    723:     return (tt0|tt1);
                    724: }
                    725: 
                    726: static int mmu030_match_ttr_access(uaecptr addr, uae_u32 fc, bool write)
                    727: {
                    728:     int tt0, tt1;
                    729:        if (!tt_enabled)
                    730:                return 0;
                    731:     tt0 = mmu030_do_match_ttr(tt0_030, mmu030.transparent.tt0, addr, fc, write);
                    732:     tt1 = mmu030_do_match_ttr(tt1_030, mmu030.transparent.tt1, addr, fc, write);
                    733:     return (tt0|tt1) & TT_OK_MATCH;
                    734: }
                    735: 
                    736: /* Locked Read-Modify-Write */
                    737: static int mmu030_match_lrmw_ttr_access(uaecptr addr, uae_u32 fc)
                    738: {
                    739:     int tt0, tt1;
1.1       root      740: 
1.1.1.5   root      741:        if (!tt_enabled)
                    742:                return 0;
                    743:     tt0 = mmu030_do_match_lrmw_ttr(tt0_030, mmu030.transparent.tt0, addr, fc);
                    744:     tt1 = mmu030_do_match_lrmw_ttr(tt1_030, mmu030.transparent.tt1, addr, fc);
                    745:     return (tt0|tt1) & TT_OK_MATCH;
                    746: }
1.1       root      747: 
                    748: /* Translation Control Register:
                    749:  *
                    750:  * x--- ---- ---- ---- ---- ---- ---- ----
                    751:  * translation: 1 = enable, 0 = disable
                    752:  *
                    753:  * ---- --x- ---- ---- ---- ---- ---- ----
                    754:  * supervisor root: 1 = enable, 0 = disable
                    755:  *
                    756:  * ---- ---x ---- ---- ---- ---- ---- ----
                    757:  * function code lookup: 1 = enable, 0 = disable
                    758:  *
                    759:  * ---- ---- xxxx ---- ---- ---- ---- ----
                    760:  * page size:
                    761:  * 1000 = 256 bytes
                    762:  * 1001 = 512 bytes
                    763:  * 1010 =  1 kB
                    764:  * 1011 =  2 kB
                    765:  * 1100 =  4 kB
                    766:  * 1101 =  8 kB
                    767:  * 1110 = 16 kB
                    768:  * 1111 = 32 kB
                    769:  *
                    770:  * ---- ---- ---- xxxx ---- ---- ---- ----
                    771:  * initial shift
                    772:  *
                    773:  * ---- ---- ---- ---- xxxx ---- ---- ----
                    774:  * number of bits for table index A
                    775:  *
                    776:  * ---- ---- ---- ---- ---- xxxx ---- ----
                    777:  * number of bits for table index B
                    778:  *
                    779:  * ---- ---- ---- ---- ---- ---- xxxx ----
                    780:  * number of bits for table index C
                    781:  *
                    782:  * ---- ---- ---- ---- ---- ----- ---- xxxx
                    783:  * number of bits for table index D
                    784:  *
                    785:  */
                    786: 
                    787: 
                    788: #define TC_ENABLE_TRANSLATION   0x80000000
                    789: #define TC_ENABLE_SUPERVISOR    0x02000000
                    790: #define TC_ENABLE_FCL           0x01000000
                    791: 
                    792: #define TC_PS_MASK              0x00F00000
                    793: #define TC_IS_MASK              0x000F0000
                    794: 
                    795: #define TC_TIA_MASK             0x0000F000
                    796: #define TC_TIB_MASK             0x00000F00
                    797: #define TC_TIC_MASK             0x000000F0
                    798: #define TC_TID_MASK             0x0000000F
                    799: 
1.1.1.3   root      800: static void mmu030_do_fake_prefetch(void)
                    801: {
1.1.1.5   root      802:        if (currprefs.cpu_compatible)
                    803:                return;
1.1.1.3   root      804:        // fetch next opcode before MMU state switches.
                    805:        // There are programs that do following:
                    806:        // - enable MMU
                    807:        // - JMP (An)
                    808:        // "enable MMU" unmaps memory under us.
                    809:        TRY (prb) {
                    810:                uaecptr pc = m68k_getpci();
                    811:                mmu030_fake_prefetch = -1;
                    812:                mmu030_fake_prefetch_addr = mmu030_translate(pc, regs.s != 0, false, false);
                    813:                mmu030_fake_prefetch = x_prefetch(0);
                    814:                // A26x0 ROM code switches off rom
                    815:                // NOP
                    816:                // JMP (a0)
                    817:                if (mmu030_fake_prefetch == 0x4e71)
                    818:                        mmu030_fake_prefetch = x_prefetch(2);
                    819:        } CATCH (prb) {
                    820:                // didn't work, oh well..
                    821:                mmu030_fake_prefetch = -1;
                    822:        } ENDTRY
                    823: }
1.1       root      824: 
1.1.1.5   root      825: bool mmu030_decode_tc(uae_u32 TC, bool check)
1.1.1.3   root      826: {
1.1.1.5   root      827: #if MMU_IPAGECACHE030
                    828:        mmu030.mmu030_last_logical_address = 0xffffffff;
                    829: #endif
                    830: 
                    831:        if (currprefs.mmu_ec)
                    832:                TC &= ~TC_ENABLE_TRANSLATION;
1.1       root      833:     /* Set MMU condition */    
                    834:     if (TC & TC_ENABLE_TRANSLATION) {
1.1.1.5   root      835:                if (!mmu030.enabled && check)
1.1.1.3   root      836:                        mmu030_do_fake_prefetch();
1.1       root      837:         mmu030.enabled = true;
                    838:     } else {
1.1.1.3   root      839:                if (mmu030.enabled) {
                    840:                        mmu030_do_fake_prefetch();
                    841:                        write_log(_T("MMU disabled PC=%08x\n"), M68K_GETPC);
                    842:                }
1.1       root      843:         mmu030.enabled = false;
1.1.1.3   root      844:         return false;
1.1       root      845:     }
                    846:     
                    847:     /* Note: 0 = Table A, 1 = Table B, 2 = Table C, 3 = Table D */
                    848:     int i, j;
                    849:     uae_u8 TI_bits[4] = {0,0,0,0};
                    850: 
                    851:     /* Reset variables before extracting new values from TC */
                    852:     for (i = 0; i < 4; i++) {
                    853:         mmu030.translation.table[i].mask = 0;
                    854:         mmu030.translation.table[i].shift = 0;
                    855:     }
                    856:     
                    857:     
                    858:     /* Extract initial shift and page size values from TC register */
                    859:     mmu030.translation.page.size = (TC & TC_PS_MASK) >> 20;
1.1.1.5   root      860:     mmu030.translation.page.size3m =  mmu030.translation.page.size - 3;
1.1       root      861:     mmu030.translation.init_shift = (TC & TC_IS_MASK) >> 16;
1.1.1.3   root      862:        regs.mmu_page_size = 1 << mmu030.translation.page.size;
                    863: 
                    864:        write_log(_T("68030 MMU enabled. Page size = %d PC=%08x\n"), regs.mmu_page_size, M68K_GETPC);
                    865: 
                    866:        if (mmu030.translation.page.size<8) {
                    867:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad page size: %i byte)\n"),
1.1       root      868:                   1<<mmu030.translation.page.size);
1.1.1.3   root      869:         Exception(56); /* MMU Configuration Exception */
                    870:         return true;
1.1       root      871:     }
1.1.1.3   root      872:        mmu030.translation.page.mask = regs.mmu_page_size - 1;
                    873:        mmu030.translation.page.imask = ~mmu030.translation.page.mask;
1.1       root      874:     
                    875:     /* Calculate masks and shifts for later extracting table indices
                    876:      * from logical addresses using: index = (addr&mask)>>shift */
                    877:     
                    878:     /* Get number of bits for each table index */
                    879:     for (i = 0; i < 4; i++) {
                    880:         j = (3-i)*4;
                    881:         TI_bits[i] = (TC >> j) & 0xF;
                    882:     }
                    883: 
                    884:     /* Calculate masks and shifts for each table */
                    885:     mmu030.translation.last_table = 0;
                    886:     uae_u8 shift = 32 - mmu030.translation.init_shift;
                    887:     for (i = 0; (i < 4) && TI_bits[i]; i++) {
                    888:         /* Get the shift */
                    889:         shift -= TI_bits[i];
                    890:         mmu030.translation.table[i].shift = shift;
                    891:         /* Build the mask */
                    892:         for (j = 0; j < TI_bits[i]; j++) {
                    893:             mmu030.translation.table[i].mask |= (1<<(mmu030.translation.table[i].shift + j));
                    894:         }
                    895:         /* Update until reaching the last table */
                    896:         mmu030.translation.last_table = i;
                    897:     }
                    898:     
                    899: #if MMU030_REG_DBG_MSG
                    900:     /* At least one table has to be defined using at least
                    901:      * 1 bit for the index. At least 2 bits are necessary 
                    902:      * if there is no second table. If these conditions are
                    903:      * not met, it will automatically lead to a sum <32
                    904:      * and cause an exception (see below). */
                    905:     if (!TI_bits[0]) {
1.1.1.3   root      906:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n"));
1.1       root      907:     } else if ((TI_bits[0]<2) && !TI_bits[1]) {
1.1.1.3   root      908:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (no second table index defined and)\n"));
                    909:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (only 1 bit for first table index)\n"));
1.1       root      910:     }
                    911: #endif
                    912:     
                    913:     /* TI fields are summed up until a zero field is reached (see above
                    914:      * loop). The sum of all TI field values plus page size and initial
                    915:      * shift has to be 32: IS + PS + TIA + TIB + TIC + TID = 32 */
                    916:     if ((shift-mmu030.translation.page.size)!=0) {
1.1.1.3   root      917:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (bad sum)\n"));
                    918:         Exception(56); /* MMU Configuration Exception */
                    919:         return true;
1.1       root      920:     }
                    921:     
                    922: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
1.1.1.3   root      923:     write_log(_T("\n"));
                    924:     write_log(_T("TRANSLATION CONTROL: %08X\n"), TC);
                    925:     write_log(_T("\n"));
                    926:     write_log(_T("TC: translation %s\n"), (TC&TC_ENABLE_TRANSLATION ? _T("enabled") : _T("disabled")));
                    927:     write_log(_T("TC: supervisor root pointer %s\n"), (TC&TC_ENABLE_SUPERVISOR ? _T("enabled") : _T("disabled")));
                    928:     write_log(_T("TC: function code lookup %s\n"), (TC&TC_ENABLE_FCL ? _T("enabled") : _T("disabled")));
                    929:     write_log(_T("\n"));
                    930:     
                    931:     write_log(_T("TC: Initial Shift: %i\n"), mmu030.translation.init_shift);
                    932:     write_log(_T("TC: Page Size: %i byte\n"), (1<<mmu030.translation.page.size));
                    933:     write_log(_T("\n"));
1.1       root      934:     
                    935:     for (i = 0; i <= mmu030.translation.last_table; i++) {
1.1.1.3   root      936:         write_log(_T("TC: Table %c: mask = %08X, shift = %i\n"), table_letter[i], mmu030.translation.table[i].mask, mmu030.translation.table[i].shift);
1.1       root      937:     }
                    938: 
1.1.1.3   root      939:     write_log(_T("TC: Page:    mask = %08X\n"), mmu030.translation.page.mask);
                    940:     write_log(_T("\n"));
1.1       root      941: 
1.1.1.3   root      942:     write_log(_T("TC: Last Table: %c\n"), table_letter[mmu030.translation.last_table]);
                    943:     write_log(_T("\n"));
1.1       root      944: #endif
1.1.1.3   root      945:        return false;
1.1       root      946: }
                    947: 
                    948: 
                    949: 
                    950: /* Root Pointer Registers (SRP and CRP)
                    951:  *
                    952:  * ---- ---- ---- ---- xxxx xxxx xxxx xx-- ---- ---- ---- ---- ---- ---- ---- xxxx
                    953:  * reserved, must be 0
                    954:  *
                    955:  * ---- ---- ---- ---- ---- ---- ---- ---- xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
                    956:  * table A address
                    957:  *
                    958:  * ---- ---- ---- ---- ---- ---- ---- --xx ---- ---- ---- ---- ---- ---- ---- ----
                    959:  * descriptor type
                    960:  *
                    961:  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
                    962:  * limit
                    963:  *
                    964:  * x--- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
                    965:  * 0 = upper limit, 1 = lower limit
                    966:  *
                    967:  */
                    968: 
                    969: 
                    970: #define RP_ADDR_MASK    (UVAL64(0x00000000FFFFFFF0))
                    971: #define RP_DESCR_MASK   (UVAL64(0x0000000300000000))
                    972: #define RP_LIMIT_MASK   (UVAL64(0x7FFF000000000000))
                    973: #define RP_LOWER_MASK   (UVAL64(0x8000000000000000))
                    974: 
                    975: #define RP_ZERO_BITS 0x0000FFFC /* These bits in upper longword of RP must be 0 */
                    976: 
1.1.1.3   root      977: bool mmu030_decode_rp(uae_u64 RP) {
1.1       root      978:     
                    979:     uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
                    980:     if (!descriptor_type) { /* If descriptor type is invalid */
1.1.1.3   root      981:         write_log(_T("MMU Configuration Exception: Root Pointer is invalid!\n"));
                    982:         Exception(56); /* MMU Configuration Exception */
                    983:                return true;
1.1       root      984:     }
1.1.1.3   root      985:        return false;
1.1       root      986: 
                    987: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
                    988:     uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
                    989:     uae_u32 first_addr = (RP & RP_ADDR_MASK);
                    990:     
1.1.1.3   root      991:     write_log(_T("\n"));
                    992:     write_log(_T("ROOT POINTER: %08X%08X\n"), (uae_u32)(RP>>32)&0xFFFFFFFF, (uae_u32)(RP&0xFFFFFFFF));
                    993:     write_log(_T("\n"));
1.1       root      994:     
1.1.1.3   root      995:     write_log(_T("RP: descriptor type = %i "), descriptor_type);
1.1       root      996:     switch (descriptor_type) {
                    997:         case 0:
1.1.1.3   root      998:             write_log(_T("(invalid descriptor)\n"));
1.1       root      999:             break;
                   1000:         case 1:
1.1.1.3   root     1001:             write_log(_T("(early termination page descriptor)\n"));
1.1       root     1002:             break;
                   1003:         case 2:
1.1.1.3   root     1004:             write_log(_T("(valid 4 byte descriptor)\n"));
1.1       root     1005:             break;
                   1006:         case 3:
1.1.1.3   root     1007:             write_log(_T("(valid 8 byte descriptor)\n"));
1.1       root     1008:             break;
                   1009:     }
                   1010:     
1.1.1.3   root     1011:     write_log(_T("RP: %s limit = %i\n"), (RP&RP_LOWER_MASK) ? _T("lower") : _T("upper"), table_limit);
1.1       root     1012:     
1.1.1.3   root     1013:     write_log(_T("RP: first table address = %08X\n"), first_addr);
                   1014:     write_log(_T("\n"));
1.1       root     1015: #endif
                   1016: }
                   1017: 
1.1.1.5   root     1018: static void mmu030_atc_handle_history_bit(int entry_num) {
                   1019:     int j;
                   1020:     mmu030.atc[entry_num].mru = 1;
                   1021:     for (j=0; j<ATC030_NUM_ENTRIES; j++) {
                   1022:         if (!mmu030.atc[j].mru)
                   1023:             break;
                   1024:     }
                   1025:     /* If there are no more zero-bits, reset all */
                   1026:     if (j==ATC030_NUM_ENTRIES) {
                   1027:         for (j=0; j<ATC030_NUM_ENTRIES; j++) {
                   1028:             mmu030.atc[j].mru = 0;
                   1029:         }
                   1030:         mmu030.atc[entry_num].mru = 1;
                   1031: #if MMU030_ATC_DBG_MSG
                   1032:         write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
                   1033: #endif
                   1034:        }
                   1035: }
                   1036: 
1.1.1.6 ! root     1037: static void desc_put_long(uaecptr addr, uae_u32 v)
        !          1038: {
        !          1039:        x_phys_put_long(addr, v);
        !          1040: }
        !          1041: static uae_u32 desc_get_long(uaecptr addr)
        !          1042: {
        !          1043:        return x_phys_get_long(addr);
        !          1044: }
        !          1045: static void desc_get_quad(uaecptr addr, uae_u32 *descr)
        !          1046: {
        !          1047:        descr[0] = x_phys_get_long(addr);
        !          1048:        descr[1] = x_phys_get_long(addr + 4);
        !          1049: }
        !          1050: 
1.1.1.5   root     1051: /* Descriptors */
                   1052: 
                   1053: #define DESCR_TYPE_MASK         0x00000003
                   1054: 
                   1055: #define DESCR_TYPE_INVALID      0 /* all tables */
                   1056: 
                   1057: #define DESCR_TYPE_EARLY_TERM   1 /* all but lowest level table */
                   1058: #define DESCR_TYPE_PAGE         1 /* only lowest level table */
                   1059: #define DESCR_TYPE_VALID4       2 /* all but lowest level table */
                   1060: #define DESCR_TYPE_INDIRECT4    2 /* only lowest level table */
                   1061: #define DESCR_TYPE_VALID8       3 /* all but lowest level table */
                   1062: #define DESCR_TYPE_INDIRECT8    3 /* only lowest level table */
1.1       root     1063: 
                   1064: #define DESCR_TYPE_VALID_MASK       0x2 /* all but lowest level table */
                   1065: #define DESCR_TYPE_INDIRECT_MASK    0x2 /* only lowest level table */
                   1066: 
                   1067: 
                   1068: /* Short format (4 byte):
                   1069:  *
                   1070:  * ---- ---- ---- ---- ---- ---- ---- --xx
                   1071:  * descriptor type:
                   1072:  * 0 = invalid
                   1073:  * 1 = page descriptor (early termination)
                   1074:  * 2 = valid (4 byte)
                   1075:  * 3 = valid (8 byte)
                   1076:  *
                   1077:  *
                   1078:  * table descriptor:
                   1079:  * ---- ---- ---- ---- ---- ---- ---- -x--
                   1080:  * write protect
                   1081:  *
                   1082:  * ---- ---- ---- ---- ---- ---- ---- x---
                   1083:  * update
                   1084:  *
                   1085:  * xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
                   1086:  * table address
                   1087:  *
                   1088:  *
                   1089:  * (early termination) page descriptor:
                   1090:  * ---- ---- ---- ---- ---- ---- ---- -x--
                   1091:  * write protect
                   1092:  *
                   1093:  * ---- ---- ---- ---- ---- ---- ---- x---
                   1094:  * update
                   1095:  *
                   1096:  * ---- ---- ---- ---- ---- ---- ---x ----
                   1097:  * modified
                   1098:  *
                   1099:  * ---- ---- ---- ---- ---- ---- -x-- ----
                   1100:  * cache inhibit
                   1101:  *
                   1102:  * ---- ---- ---- ---- ---- ---- x-x- ----
                   1103:  * reserved (must be 0)
                   1104:  *
                   1105:  * xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
                   1106:  * page address
                   1107:  *
                   1108:  *
                   1109:  * indirect descriptor:
                   1110:  * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
                   1111:  * descriptor address
                   1112:  *
                   1113:  */
                   1114: 
                   1115: #define DESCR_WP       0x00000004
                   1116: #define DESCR_U        0x00000008
                   1117: #define DESCR_M        0x00000010 /* only last level table */
                   1118: #define DESCR_CI       0x00000040 /* only last level table */
                   1119: 
                   1120: #define DESCR_TD_ADDR_MASK 0xFFFFFFF0
                   1121: #define DESCR_PD_ADDR_MASK 0xFFFFFF00
                   1122: #define DESCR_ID_ADDR_MASK 0xFFFFFFFC
                   1123: 
                   1124: 
                   1125: /* Long format (8 byte):
                   1126:  *
                   1127:  * ---- ---- ---- ---- ---- ---- ---- --xx | ---- ---- ---- ---- ---- ---- ---- ----
                   1128:  * descriptor type:
                   1129:  * 0 = invalid
                   1130:  * 1 = page descriptor (early termination)
                   1131:  * 2 = valid (4 byte)
                   1132:  * 3 = valid (8 byte)
                   1133:  *
                   1134:  *
                   1135:  * table desctriptor:
                   1136:  * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
                   1137:  * write protect
                   1138:  *
                   1139:  * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
                   1140:  * update
                   1141:  *
                   1142:  * ---- ---- ---- ---- ---- ---- xxxx ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1143:  * reserved (must be 0)
                   1144:  *
                   1145:  * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1146:  * supervisor
                   1147:  *
                   1148:  * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1149:  * reserved (must be 1111 110)
                   1150:  *
                   1151:  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1152:  * limit
                   1153:  *
                   1154:  * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1155:  * 0 = upper limit, 1 = lower limit
                   1156:  *
                   1157:  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx ----
                   1158:  * table address
                   1159:  *
                   1160:  *
                   1161:  * (early termination) page descriptor:
                   1162:  * ---- ---- ---- ---- ---- ---- ---- -x-- | ---- ---- ---- ---- ---- ---- ---- ----
                   1163:  * write protect
                   1164:  *
                   1165:  * ---- ---- ---- ---- ---- ---- ---- x--- | ---- ---- ---- ---- ---- ---- ---- ----
                   1166:  * update
                   1167:  *
                   1168:  * ---- ---- ---- ---- ---- ---- ---x ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1169:  * modified
                   1170:  *
                   1171:  * ---- ---- ---- ---- ---- ---- -x-- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1172:  * cache inhibit
                   1173:  *
                   1174:  * ---- ---- ---- ---- ---- ---x ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1175:  * supervisor
                   1176:  *
                   1177:  * ---- ---- ---- ---- ---- ---- x-x- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1178:  * reserved (must be 0)
                   1179:  *
                   1180:  * ---- ---- ---- ---- xxxx xxx- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1181:  * reserved (must be 1111 110)
                   1182:  *
                   1183:  * -xxx xxxx xxxx xxxx ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
1.1.1.2   root     1184:  * limit (only used with early termination page descriptor)
1.1       root     1185:  *
                   1186:  * x--- ---- ---- ---- ---- ---- ---- ---- | ---- ---- ---- ---- ---- ---- ---- ----
                   1187:  * 0 = upper limit, 1 = lower limit (only used with early termination page descriptor)
                   1188:  *
                   1189:  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx ---- ----
                   1190:  * page address
                   1191:  *
                   1192:  *
                   1193:  * indirect descriptor:
                   1194:  * ---- ---- ---- ---- ---- ---- ---- ---- | xxxx xxxx xxxx xxxx xxxx xxxx xxxx xx--
                   1195:  * descriptor address
                   1196:  *
                   1197:  */
                   1198: 
                   1199: /* only for long descriptors */
                   1200: #define DESCR_S        0x00000100
                   1201: 
                   1202: #define DESCR_LIMIT_MASK   0x7FFF0000
                   1203: #define DESCR_LOWER_MASK   0x80000000
                   1204: 
                   1205: 
                   1206: 
                   1207: /* This functions searches through the translation tables. It can be used 
                   1208:  * for PTEST (levels 1 to 7). Using level 0 creates an ATC entry. */
                   1209: 
1.1.1.6 ! root     1210: static uae_u32 mmu030_table_search(uaecptr addr, uae_u32 fc, bool write, int level) {
        !          1211:     /* During table walk up to 7 different descriptors are used:
        !          1212:      * root pointer, descriptors fetched from function code lookup table,
        !          1213:      * tables A, B, C and D and one indirect descriptor */
        !          1214:     uae_u32 descr[2];
        !          1215:     uae_u32 descr_type;
        !          1216:     uaecptr descr_addr[7];
        !          1217:     uaecptr table_addr = 0;
        !          1218:     uaecptr page_addr = 0;
        !          1219:     uaecptr indirect_addr = 0;
        !          1220:     uae_u32 table_index = 0;
        !          1221:     uae_u32 limit = 0;
        !          1222:     uae_u32 unused_fields_mask = 0;
        !          1223:     bool super = (fc&4) ? true : false;
        !          1224:     bool super_violation = false;
        !          1225:     bool write_protected = false;
        !          1226:     uae_u8 cache_inhibit = CACHE_ENABLE_ALL;
        !          1227:     bool descr_modified = false;
        !          1228:         
        !          1229:     mmu030.status = 0; /* Reset status */
        !          1230:         
        !          1231:     /* Initial values for condition variables.
        !          1232:      * Note: Root pointer is long descriptor. */
        !          1233:     int t = 0;
        !          1234:     int addr_position = 1;
        !          1235:     int next_size = 0;
        !          1236:     int descr_size = 8;
        !          1237:     int descr_num = 0;
        !          1238:     bool early_termination = false;
        !          1239:     int old_s;
        !          1240:     int i;
1.1.1.3   root     1241:     
1.1.1.6 ! root     1242:        // Always use supervisor mode to access descriptors
        !          1243:     old_s = regs.s;
        !          1244:     regs.s = 1;
        !          1245: 
        !          1246:        TRY(prb) {
1.1       root     1247:         /* Use super user root pointer if enabled in TC register and access is in
                   1248:          * super user mode, else use cpu root pointer. */
                   1249:         if ((tc_030&TC_ENABLE_SUPERVISOR) && super) {
                   1250:             descr[0] = (srp_030>>32)&0xFFFFFFFF;
                   1251:             descr[1] = srp_030&0xFFFFFFFF;
                   1252: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1253:             write_log(_T("Supervisor Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1.1       root     1254: #endif // MMU030_REG_DBG_MSG
                   1255:         } else {
                   1256:             descr[0] = (crp_030>>32)&0xFFFFFFFF;
                   1257:             descr[1] = crp_030&0xFFFFFFFF;
                   1258: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1259:             write_log(_T("CPU Root Pointer: %08X%08X\n"),descr[0],descr[1]);
1.1       root     1260: #endif
1.1.1.3   root     1261:                }
1.1       root     1262:                 
                   1263:         if (descr[0]&RP_ZERO_BITS) {
1.1.1.3   root     1264: #if MMU030_REG_DBG_MSG
                   1265:                        write_log(_T("MMU Warning: Root pointer reserved bits are non-zero! %08X\n"), descr[0]);
                   1266: #endif
                   1267:                        descr[0] &= (~RP_ZERO_BITS);
1.1       root     1268:         }
                   1269:         
                   1270:         /* Check descriptor type of root pointer */
                   1271:         descr_type = descr[0]&DESCR_TYPE_MASK;
                   1272:         switch (descr_type) {
                   1273:             case DESCR_TYPE_INVALID:
1.1.1.3   root     1274:                 write_log(_T("Fatal error: Root pointer is invalid descriptor!\n"));
1.1       root     1275:                 mmu030.status |= MMUSR_INVALID;
                   1276:                 goto stop_search;
                   1277:             case DESCR_TYPE_EARLY_TERM:
1.1.1.3   root     1278:                 write_log(_T("Root pointer is early termination page descriptor.\n"));
1.1       root     1279:                 early_termination = true;
                   1280:                 goto handle_page_descriptor;
                   1281:             case DESCR_TYPE_VALID4:
                   1282:                 next_size = 4;
                   1283:                 break;
                   1284:             case DESCR_TYPE_VALID8:
                   1285:                 next_size = 8;
                   1286:                 break;
                   1287:         }
                   1288:         
                   1289:         /* If function code lookup is enabled in TC register use function code as
                   1290:          * index for top level table, limit check not required */
                   1291:         
                   1292:         if (tc_030&TC_ENABLE_FCL) {
1.1.1.3   root     1293:             write_log(_T("Function code lookup enabled, FC = %i\n"), fc);
1.1       root     1294:             
                   1295:             addr_position = (descr_size==4) ? 0 : 1;
                   1296:             table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
                   1297:             table_index = fc; /* table index is function code */
1.1.1.3   root     1298:             write_log(_T("Table FCL at %08X: index = %i, "),table_addr,table_index);
1.1       root     1299:             
                   1300:             /* Fetch next descriptor */
                   1301:             descr_num++;
                   1302:             descr_addr[descr_num] = table_addr+(table_index*next_size);
                   1303:             
                   1304:             if (next_size==4) {
1.1.1.6 ! root     1305:                 descr[0] = desc_get_long(descr_addr[descr_num]);
1.1       root     1306: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1307:                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
1.1       root     1308: #endif
                   1309:             } else {
1.1.1.6 ! root     1310:                                desc_get_quad(descr_addr[descr_num], descr);
1.1       root     1311: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1312:                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1.1       root     1313: #endif
                   1314:             }
                   1315:             
                   1316:             descr_size = next_size;
                   1317:             
                   1318:             /* Check descriptor type */
                   1319:             descr_type = descr[0]&DESCR_TYPE_MASK;
                   1320:             switch (descr_type) {
                   1321:                 case DESCR_TYPE_INVALID:
1.1.1.3   root     1322:                     write_log(_T("Invalid descriptor!\n"));
1.1       root     1323:                     /* stop table walk */
                   1324:                     mmu030.status |= MMUSR_INVALID;
                   1325:                     goto stop_search;
                   1326:                 case DESCR_TYPE_EARLY_TERM:
                   1327: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1328:                     write_log(_T("Early termination page descriptor!\n"));
1.1       root     1329: #endif
1.1.1.3   root     1330:                                        early_termination = true;
1.1       root     1331:                     goto handle_page_descriptor;
                   1332:                 case DESCR_TYPE_VALID4:
                   1333:                     next_size = 4;
                   1334:                     break;
                   1335:                 case DESCR_TYPE_VALID8:
                   1336:                     next_size = 8;
                   1337:                     break;
                   1338:             }
                   1339:         }
                   1340:         
                   1341:         
                   1342:         /* Upper level tables */
                   1343:         do {
                   1344:             if (descr_num) { /* if not root pointer */
1.1.1.3   root     1345:                 /* Check protection */
                   1346:                 if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
                   1347:                     super_violation = true;
                   1348:                 }
                   1349:                 if (descr[0]&DESCR_WP) {
                   1350:                     write_protected = true;
                   1351:                 }
                   1352:                 
1.1       root     1353:                 /* Set the updated bit */
1.1.1.3   root     1354:                 if (!level && !(descr[0]&DESCR_U) && !super_violation) {
1.1       root     1355:                     descr[0] |= DESCR_U;
1.1.1.6 ! root     1356:                     desc_put_long(descr_addr[descr_num], descr[0]);
1.1       root     1357:                 }
                   1358:                 
1.1.1.3   root     1359:                 /* Update status bits */
                   1360:                 mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
                   1361:                 mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;                
                   1362: 
1.1       root     1363:                 /* Check if ptest level is reached */
                   1364:                 if (level && (level==descr_num)) {
                   1365:                     goto stop_search;
                   1366:                 }
                   1367:             }
                   1368:             
                   1369:             addr_position = (descr_size==4) ? 0 : 1;
                   1370:             table_addr = descr[addr_position]&DESCR_TD_ADDR_MASK;
                   1371:             table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
                   1372: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1373:             write_log(_T("Table %c at %08X: index = %i, "),table_letter[t],table_addr,table_index);
1.1       root     1374: #endif // MMU030_REG_DBG_MSG
                   1375:             t++; /* Proceed to the next table */
                   1376:             
                   1377:             /* Perform limit check */
                   1378:             if (descr_size==8) {
                   1379:                 limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
                   1380:                 if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
                   1381:                     mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.3   root     1382: #if MMU030_REG_DBG_MSG
                   1383:                     write_log(_T("limit violation (lower limit %i)\n"),limit);
                   1384: #endif
1.1       root     1385:                     goto stop_search;
                   1386:                 }
                   1387:                 if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
                   1388:                     mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.3   root     1389: #if MMU030_REG_DBG_MSG
                   1390:                     write_log(_T("limit violation (upper limit %i)\n"),limit);
                   1391: #endif
1.1       root     1392:                     goto stop_search;
                   1393:                 }
                   1394:             }
                   1395:             
                   1396:             /* Fetch next descriptor */
                   1397:             descr_num++;
                   1398:             descr_addr[descr_num] = table_addr+(table_index*next_size);
                   1399:             
                   1400:             if (next_size==4) {
1.1.1.6 ! root     1401:                 descr[0] = desc_get_long(descr_addr[descr_num]);
1.1       root     1402: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1403:                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
1.1       root     1404: #endif
                   1405:             } else {
1.1.1.6 ! root     1406:                                desc_get_quad(descr_addr[descr_num], descr);
1.1       root     1407: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1408:                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
1.1       root     1409: #endif
                   1410:             }
                   1411:             
                   1412:             descr_size = next_size;
                   1413:             
                   1414:             /* Check descriptor type */
                   1415:             descr_type = descr[0]&DESCR_TYPE_MASK;
                   1416:             switch (descr_type) {
                   1417:                 case DESCR_TYPE_INVALID:
1.1.1.2   root     1418: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1419:                     write_log(_T("Invalid descriptor!\n"));
1.1.1.2   root     1420: #endif
1.1.1.3   root     1421:                                        /* stop table walk */
1.1       root     1422:                     mmu030.status |= MMUSR_INVALID;
                   1423:                     goto stop_search;
                   1424:                 case DESCR_TYPE_EARLY_TERM:
                   1425:                     /* go to last level table handling code */
                   1426:                     if (t<=mmu030.translation.last_table) {
                   1427: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1428:                         write_log(_T("Early termination page descriptor!\n"));
1.1       root     1429: #endif
1.1.1.3   root     1430:                                                early_termination = true;
1.1       root     1431:                     }
                   1432:                     goto handle_page_descriptor;
                   1433:                 case DESCR_TYPE_VALID4:
                   1434:                     next_size = 4;
                   1435:                     break;
                   1436:                 case DESCR_TYPE_VALID8:
                   1437:                     next_size = 8;
                   1438:                     break;
                   1439:             }
                   1440:         } while (t<=mmu030.translation.last_table);
                   1441:         
                   1442:         
                   1443:         /* Handle indirect descriptor */
                   1444:         
                   1445:         /* Check if ptest level is reached */
                   1446:         if (level && (level==descr_num)) {
                   1447:             goto stop_search;
                   1448:         }
                   1449:         
                   1450:         addr_position = (descr_size==4) ? 0 : 1;
                   1451:         indirect_addr = descr[addr_position]&DESCR_ID_ADDR_MASK;
1.1.1.3   root     1452: #if MMU030_REG_DBG_MSG
                   1453:         write_log(_T("Page indirect descriptor at %08X: "),indirect_addr);
                   1454: #endif
                   1455: 
1.1       root     1456:         /* Fetch indirect descriptor */
                   1457:         descr_num++;
                   1458:         descr_addr[descr_num] = indirect_addr;
                   1459:         
                   1460:         if (next_size==4) {
1.1.1.6 ! root     1461:             descr[0] = desc_get_long(descr_addr[descr_num]);
1.1.1.3   root     1462: #if MMU030_REG_DBG_MSG
                   1463:             write_log(_T("descr = %08X\n"),descr[0]);
                   1464: #endif
                   1465:                } else {
1.1.1.6 ! root     1466:                        desc_get_quad(descr_addr[descr_num], descr);
1.1.1.3   root     1467: #if MMU030_REG_DBG_MSG
                   1468:             write_log(_T("descr = %08X%08X"),descr[0],descr[1]);
                   1469: #endif
                   1470:                }
1.1       root     1471:         
                   1472:         descr_size = next_size;
                   1473:         
                   1474:         /* Check descriptor type, only page descriptor is valid */
                   1475:         descr_type = descr[0]&DESCR_TYPE_MASK;
                   1476:         if (descr_type!=DESCR_TYPE_PAGE) {
                   1477:             mmu030.status |= MMUSR_INVALID;
                   1478:             goto stop_search;
                   1479:         }
                   1480:         
                   1481:     handle_page_descriptor:
                   1482:         
                   1483:         if (descr_num) { /* if not root pointer */
1.1.1.3   root     1484:             /* check protection */
                   1485:             if ((descr_size==8) && (descr[0]&DESCR_S) && !super) {
                   1486:                 super_violation = true;
                   1487:             }
                   1488:             if (descr[0]&DESCR_WP) {
                   1489:                 write_protected = true;
                   1490:             }
                   1491: 
                   1492:             if (!level && !super_violation) {
1.1       root     1493:                 /* set modified bit */
1.1.1.3   root     1494:                 if (!(descr[0]&DESCR_M) && write && !write_protected) {
1.1       root     1495:                     descr[0] |= DESCR_M;
                   1496:                     descr_modified = true;
                   1497:                 }
                   1498:                 /* set updated bit */
                   1499:                 if (!(descr[0]&DESCR_U)) {
                   1500:                     descr[0] |= DESCR_U;
                   1501:                     descr_modified = true;
                   1502:                 }
1.1.1.5   root     1503:                 /* write modified descriptor if necessary */
1.1       root     1504:                 if (descr_modified) {
1.1.1.6 ! root     1505:                     desc_put_long(descr_addr[descr_num], descr[0]);
1.1       root     1506:                 }
                   1507:             }
                   1508:             
1.1.1.3   root     1509:             /* update status bits */
                   1510:             mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
                   1511:             mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
                   1512: 
1.1       root     1513:             /* check if caching is inhibited */
1.1.1.5   root     1514:             cache_inhibit = (descr[0]&DESCR_CI) ? CACHE_DISABLE_MMU : CACHE_ENABLE_ALL;
1.1       root     1515:             
1.1.1.3   root     1516:             /* check for the modified bit and set it in the status register */
1.1       root     1517:             mmu030.status |= (descr[0]&DESCR_M) ? MMUSR_MODIFIED : 0;
                   1518:         }
                   1519:         
                   1520:         /* Check limit using next index field of logical address.
                   1521:          * Limit is only checked on early termination. If we are
                   1522:          * still at root pointer level, only check limit, if FCL
                   1523:          * is disabled. */
                   1524:         if (early_termination) {
                   1525:             if (descr_num || !(tc_030&TC_ENABLE_FCL)) {
                   1526:                 if (descr_size==8) {
                   1527:                     table_index = (addr&mmu030.translation.table[t].mask)>>mmu030.translation.table[t].shift;
                   1528:                     limit = (descr[0]&DESCR_LIMIT_MASK)>>16;
                   1529:                     if ((descr[0]&DESCR_LOWER_MASK) && (table_index<limit)) {
                   1530:                         mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.3   root     1531: #if MMU030_REG_DBG_MSG
                   1532:                         write_log(_T("Limit violation (lower limit %i)\n"),limit);
                   1533: #endif
1.1       root     1534:                         goto stop_search;
                   1535:                     }
                   1536:                     if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
                   1537:                         mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
1.1.1.3   root     1538: #if MMU030_REG_DBG_MSG
                   1539:                         write_log(_T("Limit violation (upper limit %i)\n"),limit);
                   1540: #endif
1.1       root     1541:                         goto stop_search;
                   1542:                     }
                   1543:                 }
                   1544:             }
                   1545:             /* Get all unused bits of the logical address table index field.
                   1546:              * they are added to the page address */
1.1.1.3   root     1547:             /* TODO: They should be added via "unsigned addition". How to? */
1.1       root     1548:             do {
                   1549:                 unused_fields_mask |= mmu030.translation.table[t].mask;
                   1550:                 t++;
                   1551:             } while (t<=mmu030.translation.last_table);
                   1552:             page_addr = addr&unused_fields_mask;
                   1553: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1554:             write_log(_T("Logical address unused bits: %08X (mask = %08X)\n"),
1.1       root     1555:                       page_addr,unused_fields_mask);
                   1556: #endif
1.1.1.3   root     1557:                }
                   1558: 
1.1       root     1559:         /* Get page address */
                   1560:         addr_position = (descr_size==4) ? 0 : 1;
                   1561:         page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
                   1562: #if MMU030_REG_DBG_MSG
1.1.1.3   root     1563:         write_log(_T("Page at %08X\n"),page_addr);
1.1       root     1564: #endif // MMU030_REG_DBG_MSG
                   1565:         
                   1566:     stop_search:
                   1567:         ; /* Make compiler happy */
                   1568:     } CATCH(prb) {
1.1.1.5   root     1569:         /* We jump to this place, if a bus error occurred during table search.
1.1       root     1570:          * bBusErrorReadWrite is set in m68000.c, M68000_BusError: read = 1 */
                   1571:         if (bBusErrorReadWrite) {
                   1572:             descr_num--;
                   1573:         }
                   1574:         mmu030.status |= (MMUSR_BUS_ERROR|MMUSR_INVALID);
1.1.1.3   root     1575:         write_log(_T("MMU: Bus error while %s descriptor!\n"),
                   1576:                   bBusErrorReadWrite?_T("reading"):_T("writing"));
1.1.1.6 ! root     1577:     } ENDTRY;
1.1       root     1578: 
1.1.1.6 ! root     1579:     // Restore original supervisor state
        !          1580:     regs.s = old_s;
1.1       root     1581: 
                   1582:     /* check if we have to handle ptest */
                   1583:     if (level) {
1.1.1.3   root     1584:         /* Note: wp, m and sv bits are undefined if the invalid bit is set */
1.1       root     1585:         mmu030.status = (mmu030.status&~MMUSR_NUM_LEVELS_MASK) | descr_num;
                   1586: 
                   1587:         /* If root pointer is page descriptor (descr_num 0), return 0 */
                   1588:         return descr_num ? descr_addr[descr_num] : 0;
                   1589:     }
                   1590:     
                   1591:     /* Find an ATC entry to replace */
                   1592:     /* Search for invalid entry */
                   1593:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                   1594:         if (!mmu030.atc[i].logical.valid) {
                   1595:             break;
                   1596:         }
                   1597:     }
                   1598:     /* If there are no invalid entries, replace first entry
                   1599:      * with history bit not set */
                   1600:     if (i == ATC030_NUM_ENTRIES) {
                   1601:         for (i=0; i<ATC030_NUM_ENTRIES; i++) {
                   1602:             if (!mmu030.atc[i].mru) {
                   1603:                 break;
                   1604:             }
                   1605:         }
1.1.1.3   root     1606: #if MMU030_REG_DBG_MSG
                   1607:         write_log(_T("ATC is full. Replacing entry %i\n"), i);
1.1       root     1608: #endif
1.1.1.3   root     1609:        }
                   1610:        if (i >= ATC030_NUM_ENTRIES) {
                   1611:                i = 0;
                   1612:                write_log (_T("ATC entry not found!!!\n"));
                   1613:        }
                   1614: 
1.1       root     1615:     mmu030_atc_handle_history_bit(i);
                   1616:     
                   1617:     /* Create ATC entry */
1.1.1.3   root     1618:     mmu030.atc[i].logical.addr = addr & mmu030.translation.page.imask; /* delete page index bits */
1.1       root     1619:     mmu030.atc[i].logical.fc = fc;
                   1620:     mmu030.atc[i].logical.valid = true;
1.1.1.3   root     1621:     mmu030.atc[i].physical.addr = page_addr & mmu030.translation.page.imask; /* delete page index bits */
1.1       root     1622:     if ((mmu030.status&MMUSR_INVALID) || (mmu030.status&MMUSR_SUPER_VIOLATION)) {
                   1623:         mmu030.atc[i].physical.bus_error = true;
                   1624:     } else {
                   1625:         mmu030.atc[i].physical.bus_error = false;
                   1626:     }
                   1627:     mmu030.atc[i].physical.cache_inhibit = cache_inhibit;
1.1.1.3   root     1628:     mmu030.atc[i].physical.modified = (mmu030.status&MMUSR_MODIFIED) ? true : false;
                   1629:     mmu030.atc[i].physical.write_protect = (mmu030.status&MMUSR_WRITE_PROTECTED) ? true : false;
1.1       root     1630: 
1.1.1.5   root     1631:        mmu030_flush_cache(mmu030.atc[i].logical.addr);
                   1632: 
1.1.1.3   root     1633: #if MMU030_ATC_DBG_MSG    
                   1634:     write_log(_T("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n"), i,
1.1       root     1635:               mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
                   1636:               mmu030.atc[i].logical.fc);
1.1.1.3   root     1637:     write_log(_T("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n"), i,
1.1       root     1638:               mmu030.atc[i].physical.bus_error?1:0,
                   1639:               mmu030.atc[i].physical.cache_inhibit?1:0,
                   1640:               mmu030.atc[i].physical.write_protect?1:0,
                   1641:               mmu030.atc[i].physical.modified?1:0);
                   1642: #endif // MMU030_ATC_DBG_MSG
                   1643:     
                   1644:     return 0;
                   1645: }
                   1646: 
                   1647: /* This function is used for PTEST level 0. */
1.1.1.6 ! root     1648: static void mmu030_ptest_atc_search(uaecptr logical_addr, uae_u32 fc, bool write) {
1.1       root     1649:     int i;
                   1650:     mmu030.status = 0;
                   1651:         
                   1652:     if (mmu030_match_ttr(logical_addr, fc, write)&TT_OK_MATCH) {
                   1653:         mmu030.status |= MMUSR_TRANSP_ACCESS;
                   1654:         return;
                   1655:     }
                   1656:     
                   1657:     for (i = 0; i < ATC030_NUM_ENTRIES; i++) {
                   1658:         if ((mmu030.atc[i].logical.fc == fc) &&
                   1659:             (mmu030.atc[i].logical.addr == logical_addr) &&
                   1660:             mmu030.atc[i].logical.valid) {
                   1661:             break;
                   1662:         }
                   1663:     }
                   1664:     
                   1665:     if (i==ATC030_NUM_ENTRIES) {
                   1666:         mmu030.status |= MMUSR_INVALID;
                   1667:         return;
                   1668:     }
                   1669:     
                   1670:     mmu030.status |= mmu030.atc[i].physical.bus_error ? (MMUSR_BUS_ERROR|MMUSR_INVALID) : 0;
1.1.1.3   root     1671:     /* Note: write protect and modified bits are undefined if the invalid bit is set */
1.1       root     1672:     mmu030.status |= mmu030.atc[i].physical.write_protect ? MMUSR_WRITE_PROTECTED : 0;
                   1673:     mmu030.status |= mmu030.atc[i].physical.modified ? MMUSR_MODIFIED : 0;
                   1674: }
                   1675: 
                   1676: /* Address Translation Cache
                   1677:  *
                   1678:  * The ATC uses a pseudo-least-recently-used algorithm to keep track of
                   1679:  * least recently used entries. They are replaced if the cache is full.
                   1680:  * An internal history-bit (MRU-bit) is used to identify these entries.
                   1681:  * If an entry is accessed, its history-bit is set to 1. If after that
                   1682:  * there are no more entries with zero-bits, all other history-bits are
                   1683:  * set to 0. When no more invalid entries are in the ATC, the first entry
                   1684:  * with a zero-bit is replaced.
                   1685:  *
                   1686:  *
                   1687:  * Logical Portion (28 bit):
                   1688:  * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
                   1689:  * logical address (most significant 24 bit)
                   1690:  *
                   1691:  * oooo -xxx ---- ---- ---- ---- ---- ----
                   1692:  * function code
                   1693:  *
                   1694:  * oooo x--- ---- ---- ---- ---- ---- ----
                   1695:  * valid
                   1696:  *
                   1697:  *
                   1698:  * Physical Portion (28 bit):
                   1699:  * oooo ---- xxxx xxxx xxxx xxxx xxxx xxxx
                   1700:  * physical address
                   1701:  *
                   1702:  * oooo ---x ---- ---- ---- ---- ---- ----
                   1703:  * modified
                   1704:  *
                   1705:  * oooo --x- ---- ---- ---- ---- ---- ----
                   1706:  * write protect
                   1707:  *
                   1708:  * oooo -x-- ---- ---- ---- ---- ---- ----
                   1709:  * cache inhibit
                   1710:  *
                   1711:  * oooo x--- ---- ---- ---- ---- ---- ----
                   1712:  * bus error
                   1713:  *
                   1714:  */
                   1715: 
                   1716: #define ATC030_MASK         0x0FFFFFFF
                   1717: #define ATC030_ADDR_MASK    0x00FFFFFF /* after masking shift 8 (<< 8) */
                   1718: 
                   1719: #define ATC030_LOG_FC   0x07000000
                   1720: #define ATC030_LOG_V    0x08000000
                   1721: 
                   1722: #define ATC030_PHYS_M   0x01000000
                   1723: #define ATC030_PHYS_WP  0x02000000
                   1724: #define ATC030_PHYS_CI  0x04000000
                   1725: #define ATC030_PHYS_BE  0x08000000
                   1726: 
1.1.1.6 ! root     1727: #if MMUDEBUG
        !          1728: static void dump_opcode(uae_u16 opcode)
        !          1729: {
        !          1730:        struct mnemolookup *lookup;
        !          1731:        struct instr *dp;
        !          1732:        char size = '_';
        !          1733: 
        !          1734:        dp = table68k + opcode;
        !          1735:        if (dp->mnemo == i_ILLG) {
        !          1736:                dp = table68k + 0x4AFC;
        !          1737:        }
        !          1738:        for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++);
        !          1739: 
        !          1740:        if (!dp->unsized) {
        !          1741:                switch (dp->size)
        !          1742:                {
        !          1743:                case sz_byte:
        !          1744:                size = 'B';
        !          1745:                break;
        !          1746:                case sz_word:
        !          1747:                size = 'W';
        !          1748:                break;
        !          1749:                case sz_long:
        !          1750:                size = 'L';
        !          1751:                break;
        !          1752:                }
        !          1753:        }
        !          1754:        write_log(_T("%04x %s.%c"), opcode, lookup->name, size);
        !          1755: }
        !          1756: #endif
        !          1757: 
1.1.1.5   root     1758: void mmu030_page_fault(uaecptr addr, bool read, int flags, uae_u32 fc)
                   1759: {
                   1760:        if (flags < 0) {
                   1761:                read = (regs.mmu_ssw & MMU030_SSW_RW) ? 1 : 0;
1.1.1.6 ! root     1762:                fc = regs.mmu_ssw & MMU030_SSW_FC_MASK;
1.1.1.5   root     1763:                flags = regs.mmu_ssw & ~(MMU030_SSW_FC | MMU030_SSW_RC | MMU030_SSW_FB | MMU030_SSW_RB | MMU030_SSW_RW | 7);
                   1764:        }
1.1.1.3   root     1765:        regs.mmu_fault_addr = addr;
1.1.1.5   root     1766:        if (fc & 1) {
                   1767:                regs.mmu_ssw = MMU030_SSW_DF | (MMU030_SSW_DF << 1);
                   1768:        } else {
                   1769:                if (currprefs.cpu_compatible) {
                   1770:                        if (regs.prefetch020_valid[1] != 1 && regs.prefetch020_valid[2] == 1) {
                   1771:                                regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
                   1772:                        } else if (regs.prefetch020_valid[2] != 1) {
                   1773:                                regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
                   1774:                        } else {
1.1.1.6 ! root     1775:                                // This happens when CPU prefetches from page
        !          1776:                                // end - 4 and both pages are originally invalid.
        !          1777:                                regs.mmu_ssw = MMU030_SSW_FC | MMU030_SSW_RC;
1.1.1.5   root     1778:                        }
                   1779:                } else {
                   1780:                        regs.mmu_ssw = MMU030_SSW_FB | MMU030_SSW_RB;
                   1781:                }
                   1782:        }
1.1.1.3   root     1783:        regs.mmu_ssw |= read ? MMU030_SSW_RW : 0;
                   1784:        regs.mmu_ssw |= flags;
                   1785:        regs.mmu_ssw |= fc;
1.1.1.6 ! root     1786:        // temporary store in 68040+ variables because stack frame creation may modify them.
        !          1787:        regs.wb3_data = mmu030_data_buffer_out;
        !          1788:        regs.wb2_address = mmu030_state[1];
1.1.1.3   root     1789:     bBusErrorReadWrite = read; 
                   1790:        mm030_stageb_address = addr;
1.1.1.6 ! root     1791: 
1.1.1.3   root     1792: #if MMUDEBUG
1.1.1.6 ! root     1793:        write_log(_T("MMU: la=%08X SSW=%04x read=%d size=%d fc=%d pc=%08x ob=%08x "),
1.1.1.3   root     1794:                addr, regs.mmu_ssw, read, (flags & MMU030_SSW_SIZE_B) ? 1 : (flags & MMU030_SSW_SIZE_W) ? 2 : 4, fc,
1.1.1.6 ! root     1795:                regs.instruction_pc, mmu030_data_buffer_out, mmu030_opcode & 0xffff);
        !          1796:        dump_opcode(mmu030_opcode & 0xffff);
        !          1797:        write_log(_T("\n"));
        !          1798: #endif
        !          1799: 
        !          1800: #if 0
        !          1801:        if (addr == 0xBFE201)
        !          1802:                write_log("!");
        !          1803:        if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0)
        !          1804:                write_log("!");
        !          1805:        if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1)
        !          1806:                write_log("!");
1.1.1.3   root     1807: #endif
                   1808: 
                   1809:        THROW(2);
1.1       root     1810: }
                   1811: 
1.1.1.5   root     1812: static void mmu030_add_data_read_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
                   1813: {
                   1814: #if MMU_DPAGECACHE030
                   1815:        uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size3m) | fc;
                   1816:        uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   1817:        if (idx2 < MMUFASTCACHE_ENTRIES030 - 1) {
                   1818:                atc_data_cache_read[idx2].log = idx1;
                   1819:                atc_data_cache_read[idx2].phys = phys;
                   1820:                atc_data_cache_read[idx2].cs = mmu030_cache_state;
                   1821:        }
1.1       root     1822: #endif
                   1823: }
                   1824: 
1.1.1.5   root     1825: static void mmu030_add_data_write_cache(uaecptr addr, uaecptr phys, uae_u32 fc)
                   1826: {
                   1827: #if MMU_DPAGECACHE030
                   1828:        uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >>  mmu030.translation.page.size3m) | fc;
                   1829:        uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   1830:        if (idx2 < MMUFASTCACHE_ENTRIES030 - 1) {
                   1831:                atc_data_cache_write[idx2].log = idx1;
                   1832:                atc_data_cache_write[idx2].phys = phys;
                   1833:                atc_data_cache_write[idx2].cs = mmu030_cache_state;
                   1834:        }
1.1       root     1835: #endif
                   1836: }
                   1837: 
1.1.1.5   root     1838: static uaecptr mmu030_put_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1.1       root     1839:     uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.3   root     1840:     uae_u32 addr_mask = mmu030.translation.page.imask;
1.1       root     1841:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
                   1842: 
                   1843: #if MMU030_ATC_DBG_MSG
1.1.1.5   root     1844:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
                   1845:               l, physical_addr, page_index);
1.1       root     1846: #endif
                   1847:     
1.1.1.5   root     1848:        if (mmu030.atc[l].physical.bus_error || mmu030.atc[l].physical.write_protect) {
1.1.1.6 ! root     1849:         mmu030_page_fault(addr, false, size, fc);
1.1       root     1850:         return 0;
                   1851:     }
                   1852: 
1.1.1.5   root     1853:        mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1.1.1.3   root     1854: 
1.1.1.5   root     1855:        mmu030_add_data_write_cache(addr, physical_addr, fc);
1.1.1.3   root     1856: 
1.1.1.5   root     1857:        return physical_addr + page_index;
1.1.1.3   root     1858: }
                   1859: 
1.1.1.5   root     1860: static uaecptr mmu030_get_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1.1       root     1861:     uae_u32 page_index = addr & mmu030.translation.page.mask;
1.1.1.3   root     1862:     uae_u32 addr_mask = mmu030.translation.page.imask;
1.1       root     1863:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.5   root     1864: 
1.1       root     1865: #if MMU030_ATC_DBG_MSG
1.1.1.5   root     1866:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
                   1867:               physical_addr, page_index);
1.1       root     1868: #endif
1.1.1.5   root     1869:    
                   1870:        if (mmu030.atc[l].physical.bus_error) {
                   1871:         mmu030_page_fault(addr, true, size, fc);
1.1       root     1872:         return 0;
                   1873:     }
1.1.1.5   root     1874: 
                   1875:        mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
                   1876:        
                   1877:        mmu030_add_data_read_cache(addr, physical_addr, fc);
                   1878: 
                   1879:        return physical_addr + page_index;
1.1       root     1880: }
                   1881: 
1.1.1.5   root     1882: static uaecptr mmu030_get_i_atc(uaecptr addr, int l, uae_u32 fc, uae_u32 size) {
1.1.1.3   root     1883:        uae_u32 page_index = addr & mmu030.translation.page.mask;
                   1884:        uae_u32 addr_mask = mmu030.translation.page.imask;
                   1885:        uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
1.1.1.5   root     1886: 
1.1.1.3   root     1887: #if MMU030_ATC_DBG_MSG
1.1.1.5   root     1888:        write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
                   1889:                physical_addr, page_index);
1.1.1.3   root     1890: #endif
                   1891: 
                   1892:        if (mmu030.atc[l].physical.bus_error) {
1.1.1.5   root     1893:                mmu030_page_fault(addr, true, size, fc);
1.1.1.3   root     1894:                return 0;
                   1895:        }
                   1896: 
1.1.1.5   root     1897: #if MMU_IPAGECACHE030
                   1898:        mmu030.mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
                   1899: #if MMU_DIRECT_ACCESS
                   1900:        mmu030.mmu030_last_physical_address_real = get_real_address(physical_addr);
                   1901: #else
                   1902:        mmu030.mmu030_last_physical_address = physical_addr;
1.1       root     1903: #endif
1.1.1.5   root     1904:        mmu030.mmu030_last_logical_address = (addr & mmu030.translation.page.imask) | fc;
                   1905: #endif
                   1906: 
                   1907:        mmu030_cache_state = mmu030.atc[l].physical.cache_inhibit;
1.1       root     1908: 
1.1.1.5   root     1909:        return physical_addr + page_index;
1.1       root     1910: }
                   1911: 
1.1.1.3   root     1912: /* Generic versions of above */
1.1.1.5   root     1913: static uaecptr mmu030_put_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags) {
1.1.1.3   root     1914:     uae_u32 page_index = addr & mmu030.translation.page.mask;
                   1915:     uae_u32 addr_mask = mmu030.translation.page.imask;
                   1916:     uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1.1.1.5   root     1917: 
1.1.1.3   root     1918: #if MMU030_ATC_DBG_MSG
1.1.1.5   root     1919:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"),
                   1920:               l, physical_addr, page_index);
1.1.1.3   root     1921: #endif
                   1922:     
                   1923:     if (mmu030.atc[l].physical.write_protect || mmu030.atc[l].physical.bus_error) {
                   1924:                mmu030_page_fault(addr, false, flags, fc);
1.1.1.5   root     1925:         return 0;
1.1.1.3   root     1926:     }
                   1927: 
1.1.1.5   root     1928:        mmu030_add_data_write_cache(addr, physical_addr, fc);
                   1929: 
                   1930:        return physical_addr + page_index;
1.1.1.3   root     1931: }
1.1.1.4   root     1932: 
1.1.1.5   root     1933: static uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int flags, bool checkwrite) {
1.1.1.3   root     1934:     uae_u32 page_index = addr & mmu030.translation.page.mask;
                   1935:     uae_u32 addr_mask = mmu030.translation.page.imask;
                   1936:     uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
1.1.1.5   root     1937: 
1.1.1.3   root     1938: #if MMU030_ATC_DBG_MSG
1.1.1.5   root     1939:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X\n"), l,
                   1940:               physical_addr, page_index);
1.1.1.3   root     1941: #endif
                   1942:     
                   1943:        if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
                   1944:         mmu030_page_fault(addr, true, flags, fc);
                   1945:         return 0;
                   1946:     }
1.1.1.5   root     1947: 
                   1948:        mmu030_add_data_read_cache(addr, physical_addr, fc);
                   1949: 
                   1950:        return physical_addr + page_index;
1.1.1.3   root     1951: }
                   1952: 
1.1       root     1953: 
                   1954: /* This function checks if a certain logical address is in the ATC 
                   1955:  * by comparing the logical address and function code to the values
                   1956:  * stored in the ATC entries. If a matching entry is found it sets
                   1957:  * the history bit and returns the cache index of the entry. */
1.1.1.5   root     1958: static int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
1.1       root     1959:     uaecptr logical_addr = 0;
1.1.1.3   root     1960:     uae_u32 addr_mask = mmu030.translation.page.imask;
                   1961:        uae_u32 maddr = addr & addr_mask;
                   1962:     int offset = (maddr >> mmu030.translation.page.size) & 0x1f;
                   1963: 
                   1964:     int i, index;
                   1965:        index = atcindextable[offset];
1.1       root     1966:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
1.1.1.3   root     1967:         logical_addr = mmu030.atc[index].logical.addr;
1.1       root     1968:         /* If actual address matches address in ATC */
1.1.1.3   root     1969:         if (maddr==(logical_addr&addr_mask) &&
                   1970:             (mmu030.atc[index].logical.fc==fc) &&
                   1971:             mmu030.atc[index].logical.valid) {
                   1972:             /* If access is valid write and M bit is not set, invalidate entry
                   1973:              * else return index */
                   1974:             if (!write || mmu030.atc[index].physical.modified ||
                   1975:                 mmu030.atc[index].physical.write_protect ||
                   1976:                 mmu030.atc[index].physical.bus_error) {
1.1       root     1977:                 /* Maintain history bit */
1.1.1.3   root     1978:                                        mmu030_atc_handle_history_bit(index);
                   1979:                                        atcindextable[offset] = index;
                   1980:                                        return index;
                   1981:                                } else {
                   1982:                                        mmu030.atc[index].logical.valid = false;
                   1983:                                }
                   1984:                }
                   1985:                index++;
                   1986:                if (index >= ATC030_NUM_ENTRIES)
                   1987:                        index = 0;
1.1       root     1988:     }
1.1.1.3   root     1989:     return -1;
1.1       root     1990: }
                   1991: 
                   1992: /* Memory access functions:
                   1993:  * If the address matches one of the transparent translation registers
                   1994:  * use it directly as physical address, else check ATC for the
                   1995:  * logical address. If the logical address is not resident in the ATC
                   1996:  * create a new ATC entry and then look up the physical address. 
                   1997:  */
                   1998: 
1.1.1.5   root     1999: STATIC_INLINE void cacheablecheck(uaecptr addr)
                   2000: {
                   2001:        if (mmu030_cache_state == CACHE_ENABLE_ALL) {
                   2002:                // MMU didn't inhibit caches, use hardware cache state
                   2003:                mmu030_cache_state = ce_cachable[addr >> 16];
                   2004:        }
                   2005: }
1.1       root     2006: 
1.1.1.5   root     2007: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc)
                   2008: {
                   2009:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2010:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
                   2011: #if MMU_DPAGECACHE030
                   2012:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2013:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2014:                if (atc_data_cache_write[idx2].log == idx1) {
                   2015:                        addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
                   2016:                        mmu030_cache_state = atc_data_cache_write[idx2].cs;
                   2017:                } else
                   2018: #endif
                   2019:                {
                   2020:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2021:                        if (atc_line_num>=0) {
                   2022:                                addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
                   2023:                        } else {
                   2024:                                mmu030_table_search(addr,fc,true,0);
                   2025:                                addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_L);
                   2026:                        }
                   2027:                }
                   2028:        }
                   2029:        cacheablecheck(addr);
                   2030:        x_phys_put_long(addr,val);
                   2031: }
1.1       root     2032: 
1.1.1.5   root     2033: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc)
                   2034: {
                   2035:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2036:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
                   2037: #if MMU_DPAGECACHE030
                   2038:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2039:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2040:                if (atc_data_cache_write[idx2].log == idx1) {
                   2041:                        addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
                   2042:                        mmu030_cache_state = atc_data_cache_write[idx2].cs;
                   2043:                } else
                   2044: #endif
                   2045:                {
                   2046:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2047:                        if (atc_line_num>=0) {
                   2048:                                addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
                   2049:                        } else {
                   2050:                                mmu030_table_search(addr, fc, true, 0);
                   2051:                                addr = mmu030_put_atc(addr,  mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_W);
                   2052:                        }
                   2053:                }
                   2054:        }
                   2055:        cacheablecheck(addr);
                   2056:        x_phys_put_word(addr,val);
1.1       root     2057: }
                   2058: 
1.1.1.5   root     2059: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc)
                   2060: {
                   2061:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2062:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
                   2063: #if MMU_DPAGECACHE030
                   2064:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2065:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2066:                if (atc_data_cache_write[idx2].log == idx1) {
                   2067:                        addr = atc_data_cache_write[idx2].phys | (addr & mmu030.translation.page.mask);
                   2068:                        mmu030_cache_state = atc_data_cache_write[idx2].cs;
                   2069:                } else
                   2070: #endif
                   2071:                {
                   2072:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2073:                        if (atc_line_num>=0) {
                   2074:                                addr = mmu030_put_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
                   2075:                        } else {
                   2076:                                mmu030_table_search(addr, fc, true, 0);
                   2077:                                addr = mmu030_put_atc(addr, mmu030_logical_is_in_atc(addr,fc,true), fc, MMU030_SSW_SIZE_B);
                   2078:                        }
                   2079:                }
                   2080:        }
                   2081:        cacheablecheck(addr);
                   2082:        x_phys_put_byte(addr,val);
1.1       root     2083: }
                   2084: 
                   2085: 
1.1.1.5   root     2086: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc)
                   2087: {
                   2088:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2089:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2090: #if MMU_DPAGECACHE030
                   2091:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2092:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2093:                if (atc_data_cache_read[idx2].log == idx1) {
                   2094:                        addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
                   2095:                        mmu030_cache_state = atc_data_cache_read[idx2].cs;
                   2096:                } else
                   2097: #endif
                   2098:                {
                   2099:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2100:                        if (atc_line_num>=0) {
                   2101:                                addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
                   2102:                        } else {
                   2103:                                mmu030_table_search(addr, fc, false, 0);
                   2104:                                addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_L);
                   2105:                        }
                   2106:                }
                   2107:        }
                   2108:        cacheablecheck(addr);
                   2109:        return x_phys_get_long(addr);
1.1       root     2110: }
                   2111: 
1.1.1.5   root     2112: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc)
                   2113: {
                   2114:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2115:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2116: #if MMU_DPAGECACHE030
                   2117:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2118:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2119:                if (atc_data_cache_read[idx2].log == idx1) {
                   2120:                        addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
                   2121:                        mmu030_cache_state = atc_data_cache_read[idx2].cs;
                   2122:                } else
                   2123: #endif
                   2124:                {
                   2125:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2126:                    if (atc_line_num>=0) {
                   2127:                                addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
                   2128:                        } else {
                   2129:                                mmu030_table_search(addr, fc, false, 0);
                   2130:                                addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_W);
                   2131:                        }
                   2132:                }
                   2133:        }
                   2134:        cacheablecheck(addr);
                   2135:        return x_phys_get_word(addr);
                   2136: }
1.1.1.3   root     2137: 
1.1.1.5   root     2138: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc)
                   2139: {
                   2140:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2141:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2142: #if MMU_DPAGECACHE030
                   2143:                uae_u32 idx1 = ((addr & mmu030.translation.page.imask) >> mmu030.translation.page.size3m) | fc;
                   2144:                uae_u32 idx2 = idx1 & (MMUFASTCACHE_ENTRIES030 - 1);
                   2145:                if (atc_data_cache_read[idx2].log == idx1) {
                   2146:                        addr = atc_data_cache_read[idx2].phys | (addr & mmu030.translation.page.mask);
                   2147:                        mmu030_cache_state = atc_data_cache_read[idx2].cs;
                   2148:                } else
                   2149: #endif
                   2150:                {
                   2151:                        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2152:                        if (atc_line_num>=0) {
                   2153:                                addr = mmu030_get_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_B);
                   2154:                        } else {
                   2155:                                mmu030_table_search(addr, fc, false, 0);
                   2156:                                addr = mmu030_get_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc, MMU030_SSW_SIZE_B);
                   2157:                        }
                   2158:                }
1.1.1.3   root     2159:        }
1.1.1.5   root     2160:        cacheablecheck(addr);
                   2161:        return x_phys_get_byte(addr);
                   2162: }
1.1.1.3   root     2163: 
                   2164: 
1.1.1.5   root     2165: uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc)
                   2166: {
                   2167: #if MMU_IPAGECACHE030
                   2168:        if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
                   2169: #if MMU_DIRECT_ACCESS
                   2170:                uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
                   2171:                return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
                   2172: #else
                   2173:                mmu030_cache_state = mmu030.mmu030_cache_state;
                   2174:                return x_phys_get_ilong(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
                   2175: #endif
1.1.1.3   root     2176:        }
1.1.1.5   root     2177:        mmu030.mmu030_last_logical_address = 0xffffffff;
                   2178: #endif
1.1       root     2179: 
1.1.1.5   root     2180:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2181:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2182:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2183:                if (atc_line_num >= 0) {
                   2184:                        addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_L);
                   2185:                } else {
                   2186:                        mmu030_table_search(addr, fc, false, 0);
                   2187:                        addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_L);
                   2188:                }
                   2189:        }
                   2190:        cacheablecheck(addr);
                   2191:        return x_phys_get_ilong(addr);
1.1       root     2192: }
                   2193: 
1.1.1.3   root     2194: uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
                   2195: 
1.1.1.5   root     2196: #if MMU_IPAGECACHE030
                   2197:        if (((addr & mmu030.translation.page.imask) | fc) == mmu030.mmu030_last_logical_address) {
                   2198: #if MMU_DIRECT_ACCESS
                   2199:                uae_u8 *p = &mmu030.mmu030_last_physical_address_real[addr & mmu030.translation.page.mask];
                   2200:                return (p[0] << 8) | p[1];
                   2201: #else
                   2202:                mmu030_cache_state = mmu030.mmu030_cache_state;
                   2203:                return x_phys_get_iword(mmu030.mmu030_last_physical_address + (addr & mmu030.translation.page.mask));
                   2204: #endif
                   2205:        }
                   2206:        mmu030.mmu030_last_logical_address = 0xffffffff;
                   2207: #endif
                   2208: 
                   2209:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2210:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2211:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2212:                if (atc_line_num >= 0) {
                   2213:                        addr = mmu030_get_i_atc(addr, atc_line_num, fc, MMU030_SSW_SIZE_W);
                   2214:                } else {
                   2215:                        mmu030_table_search(addr, fc, false, 0);
                   2216:                        addr = mmu030_get_i_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc, MMU030_SSW_SIZE_W);
                   2217:                }
1.1.1.3   root     2218:        }
1.1.1.5   root     2219:        cacheablecheck(addr);
                   2220:        return x_phys_get_iword(addr);
                   2221: }
1.1.1.3   root     2222: 
1.1.1.5   root     2223: /* Not commonly used access function */
1.1.1.3   root     2224: 
1.1.1.5   root     2225: static void mmu030_put_generic_lrmw(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
                   2226: {
                   2227:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2228:        if (fc != 7 && (!tt_enabled || !mmu030_match_lrmw_ttr_access(addr,fc)) && mmu030.enabled) {
                   2229:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2230:                if (atc_line_num>=0) {
                   2231:                        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
                   2232:                } else {
                   2233:                        mmu030_table_search(addr, fc, true, 0);
                   2234:                        atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2235:                        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
                   2236:                }
1.1.1.3   root     2237:        }
1.1       root     2238: 
1.1.1.5   root     2239:        cacheablecheck(addr);
                   2240:        if (size == sz_byte)
                   2241:                x_phys_put_byte(addr, val);
                   2242:        else if (size == sz_word)
                   2243:                x_phys_put_word(addr, val);
                   2244:        else
                   2245:                x_phys_put_long(addr, val);
1.1       root     2246: }
                   2247: 
1.1.1.5   root     2248: void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags)
                   2249: {
                   2250:        mmu030_cache_state = CACHE_ENABLE_ALL;
1.1       root     2251: 
1.1.1.5   root     2252:        if (flags & MMU030_SSW_RM) {
                   2253:                return mmu030_put_generic_lrmw(addr, val, fc, size, flags);
                   2254:        }
                   2255: 
                   2256:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,true)) && mmu030.enabled) {
                   2257:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2258:                if (atc_line_num>=0) {
                   2259:                        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
                   2260:                } else {
                   2261:                        mmu030_table_search(addr, fc, true, 0);
                   2262:                        atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2263:                        addr = mmu030_put_atc_generic(addr, atc_line_num, fc, flags);
                   2264:                }
                   2265:        }
                   2266: 
                   2267:        cacheablecheck(addr);
                   2268:        if (size == sz_byte)
                   2269:                x_phys_put_byte(addr, val);
                   2270:        else if (size == sz_word)
                   2271:                x_phys_put_word(addr, val);
                   2272:        else
                   2273:                x_phys_put_long(addr, val);
1.1.1.3   root     2274: }
                   2275: 
1.1.1.5   root     2276: static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int flags)
                   2277: {
                   2278:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2279:        if (fc != 7 && (!tt_enabled || !mmu030_match_lrmw_ttr_access(addr,fc)) && mmu030.enabled) {
                   2280:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2281:                if (atc_line_num>=0) {
                   2282:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
                   2283:                } else {
                   2284:                        mmu030_table_search(addr, fc, true, 0);
                   2285:                        atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
                   2286:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, true);
                   2287:                }
                   2288:        }
1.1.1.3   root     2289: 
1.1.1.5   root     2290:        cacheablecheck(addr);
                   2291:        if (size == sz_byte)
                   2292:                return x_phys_get_byte(addr);
                   2293:        else if (size == sz_word)
                   2294:                return x_phys_get_word(addr);
                   2295:        return x_phys_get_long(addr);
1.1.1.3   root     2296: }
1.1.1.5   root     2297: 
                   2298: uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int flags)
                   2299: {
                   2300:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2301: 
1.1.1.3   root     2302:        if (flags & MMU030_SSW_RM) {
1.1.1.5   root     2303:                return mmu030_get_generic_lrmw(addr, fc, size, flags);
1.1.1.3   root     2304:        }
1.1.1.5   root     2305: 
                   2306:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,false)) && mmu030.enabled) {
                   2307:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2308:                if (atc_line_num>=0) {
                   2309:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
                   2310:                } else {
                   2311:                        mmu030_table_search(addr, fc, false, 0);
                   2312:                        atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
                   2313:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
                   2314:                }
                   2315:        }
                   2316: 
                   2317:        cacheablecheck(addr);
                   2318:        if (size == sz_byte)
                   2319:                return x_phys_get_byte(addr);
                   2320:        else if (size == sz_word)
                   2321:                return x_phys_get_word(addr);
                   2322:        return x_phys_get_long(addr);
1.1       root     2323: }
                   2324: 
1.1.1.5   root     2325: uae_u8 uae_mmu030_check_fc(uaecptr addr, bool write, uae_u32 size)
                   2326: {
                   2327:        uae_u32 fc = regs.fc030;
                   2328:        mmu030_cache_state = CACHE_ENABLE_ALL;
                   2329:        if (fc != 7 && (!tt_enabled || !mmu030_match_ttr_access(addr,fc,write)) && mmu030.enabled) {
                   2330:                uae_u32 flags = mmu030_size[size];
                   2331:                int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
                   2332:                if (atc_line_num>=0) {
                   2333:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, write);
                   2334:                } else {
                   2335:                        mmu030_table_search(addr, fc, write, 0);
                   2336:                        atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
                   2337:                        addr = mmu030_get_atc_generic(addr, atc_line_num, fc, flags, false);
                   2338:                }
                   2339:        }
                   2340:        // MMU inhibited
                   2341:        if (mmu030_cache_state != CACHE_ENABLE_ALL)
                   2342:                return mmu030_cache_state;
                   2343:        return ce_cachable[addr >> 16];
                   2344: }
1.1       root     2345: 
1.1.1.3   root     2346: /* Locked RMW is rarely used */
1.1.1.6 ! root     2347: uae_u32 uae_mmu030_get_lrmw_fcx(uaecptr addr, int size, int fc)
1.1.1.3   root     2348: {
                   2349:        if (size == sz_byte) {
1.1.1.5   root     2350:                return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
1.1.1.3   root     2351:        } else if (size == sz_word) {
1.1.1.6 ! root     2352:                if (unlikely(is_unaligned_bus(addr, 2)))
1.1.1.3   root     2353:                        return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM);
                   2354:                else
1.1.1.5   root     2355:                        return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W);
1.1.1.3   root     2356:        } else {
1.1.1.6 ! root     2357:                if (unlikely(is_unaligned_bus(addr, 4)))
1.1.1.3   root     2358:                        return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM);
                   2359:                else
1.1.1.5   root     2360:                        return mmu030_get_generic(addr, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L);
1.1.1.3   root     2361:        }
                   2362: }
1.1.1.6 ! root     2363: uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
        !          2364: {
        !          2365:        uae_u32 fc = (regs.s ? 4 : 0) | 1;
        !          2366:        return uae_mmu030_get_lrmw_fcx(addr, size, fc);
        !          2367: }
        !          2368: 
        !          2369: void uae_mmu030_put_lrmw_fcx(uaecptr addr, uae_u32 val, int size, int fc)
1.1.1.3   root     2370: {
                   2371:        if (size == sz_byte) {
1.1.1.5   root     2372:                mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_B);
1.1.1.3   root     2373:        } else if (size == sz_word) {
1.1.1.6 ! root     2374:                if (unlikely(is_unaligned_bus(addr, 2)))
1.1.1.3   root     2375:                        mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM);
                   2376:                else
1.1.1.5   root     2377:                        mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_W);
1.1.1.3   root     2378:        } else {
1.1.1.6 ! root     2379:                if (unlikely(is_unaligned_bus(addr, 4)))
1.1.1.3   root     2380:                        mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM);
                   2381:                else
1.1.1.5   root     2382:                        mmu030_put_generic(addr, val, fc, size, MMU030_SSW_RM | MMU030_SSW_SIZE_L);
1.1.1.3   root     2383:        }
                   2384: }
1.1.1.6 ! root     2385: void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
1.1       root     2386: {
1.1.1.6 ! root     2387:        uae_u32 fc = (regs.s ? 4 : 0) | 1;
        !          2388:        uae_mmu030_put_lrmw_fcx(addr, val, size, fc);
1.1       root     2389: }
                   2390: 
1.1.1.3   root     2391: uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
1.1       root     2392: {
                   2393:        uae_u32 res;
                   2394: 
1.1.1.3   root     2395:        res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
                   2396:        SAVE_EXCEPTION;
                   2397:        TRY(prb) {
                   2398:                res |= mmu030_get_iword(addr + 2, fc);
                   2399:                RESTORE_EXCEPTION;
                   2400:        }
                   2401:        CATCH(prb) {
                   2402:                RESTORE_EXCEPTION;
                   2403:                THROW_AGAIN(prb);
                   2404:        } ENDTRY
                   2405:        return res;
                   2406: }
                   2407: 
1.1.1.6 ! root     2408: static void unalign_init(uaecptr addr, bool l, bool l2)
        !          2409: {
        !          2410:        if (l2)
        !          2411:                mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSX;
        !          2412:        if (l)
        !          2413:                mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESSL;
        !          2414:        mmu030_state[1] |= MMU030_STATEFLAG1_SUBACCESS0;
        !          2415: #if MMU030_DEBUG > 1
        !          2416:        write_log(_T("unalign_init %08x %08x %d %d\n"), addr, mmu030_state[1], l, l2);
        !          2417: #endif
        !          2418: }
        !          2419: static void unalign_set(int state)
        !          2420: {
        !          2421:        mmu030_state[1] |= (1 << state) << (MMU030_STATEFLAG1_SUBACCESS_SHIFT + 1);
        !          2422: #if MMU030_DEBUG > 1
        !          2423:        write_log(_T("unalign_set %d %08x\n"), state, mmu030_state[1]);
        !          2424: #endif
        !          2425: }
        !          2426: static void unalign_clear(void)
        !          2427: {
        !          2428: #if MMU030_DEBUG > 1
        !          2429:        write_log(_T("unalign_clear %08x %08x\n"), mmu030_state[1], mmu030_data_buffer_out);
        !          2430: #endif
        !          2431:        mmu030_state[1] &= ~(MMU030_STATEFLAG1_SUBACCESSL | MMU030_STATEFLAG1_SUBACCESSX |
        !          2432:                MMU030_STATEFLAG1_SUBACCESS0 | MMU030_STATEFLAG1_SUBACCESS1 | MMU030_STATEFLAG1_SUBACCESS2 | MMU030_STATEFLAG1_SUBACCESS3);
        !          2433: }
        !          2434: 
        !          2435: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags)
        !          2436: {
        !          2437:        unalign_init(addr, false, false);
        !          2438:        mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_W) << 8;
        !          2439:        unalign_set(0);
        !          2440:        mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
        !          2441:        unalign_clear();
        !          2442:        return mmu030_data_buffer_out;
        !          2443: }
        !          2444: 
1.1.1.3   root     2445: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
                   2446: {
1.1       root     2447:        if (likely(!(addr & 1))) {
1.1.1.6 ! root     2448:                unalign_init(addr, true, false);
        !          2449:                mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_word, flags | MMU030_SSW_SIZE_L) << 16;
        !          2450:                unalign_set(0);
        !          2451:                mmu030_data_buffer_out |= mmu030_get_generic(addr + 2, fc, sz_word, flags | MMU030_SSW_SIZE_W);
1.1       root     2452:        } else {
1.1.1.6 ! root     2453:                unalign_init(addr, true, true);
        !          2454:                mmu030_data_buffer_out = mmu030_get_generic(addr, fc, sz_byte, flags | MMU030_SSW_SIZE_L) << 24;
        !          2455:                unalign_set(0);
        !          2456:                mmu030_data_buffer_out |= mmu030_get_generic(addr + 1, fc, sz_word, flags | MMU030_SSW_SIZE_W) << 8;
        !          2457:                unalign_set(1);
        !          2458:                mmu030_data_buffer_out |= mmu030_get_generic(addr + 3, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
1.1       root     2459:        }
1.1.1.6 ! root     2460:        unalign_clear();
        !          2461:        return mmu030_data_buffer_out;
1.1       root     2462: }
                   2463: 
1.1.1.3   root     2464: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags)
1.1       root     2465: {
1.1.1.6 ! root     2466:        if (likely(!(addr & 1))) {
        !          2467:                unalign_init(addr, true, false);
        !          2468:                mmu030_put_generic(addr, val >> 16, fc, sz_word, flags | MMU030_SSW_SIZE_L);
        !          2469:                unalign_set(0);
        !          2470:                mmu030_put_generic(addr + 2, val, fc, sz_word, flags | MMU030_SSW_SIZE_W);
        !          2471:        } else {
        !          2472:                unalign_init(addr, true, true);
        !          2473:                mmu030_put_generic(addr, val >> 24, fc, sz_byte, flags | MMU030_SSW_SIZE_L);
        !          2474:                unalign_set(0);
        !          2475:                mmu030_put_generic(addr + 1, val >> 8, fc, sz_word, flags | MMU030_SSW_SIZE_W);
        !          2476:                unalign_set(1);
        !          2477:                mmu030_put_generic(addr + 3, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
1.1       root     2478:        }
1.1.1.6 ! root     2479:        unalign_clear();
1.1       root     2480: }
                   2481: 
1.1.1.3   root     2482: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags)
1.1       root     2483: {
1.1.1.6 ! root     2484:        unalign_init(addr, false, false);
        !          2485:        mmu030_put_generic(addr, val >> 8, fc, sz_byte, flags | MMU030_SSW_SIZE_W);
        !          2486:        unalign_set(0);
        !          2487:        mmu030_put_generic(addr + 1, val, fc, sz_byte, flags | MMU030_SSW_SIZE_B);
        !          2488:        unalign_clear();
1.1       root     2489: }
                   2490: 
                   2491: 
1.1.1.3   root     2492: /* Used by debugger */
                   2493: static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write) {
                   2494:     uae_u32 page_index = addr & mmu030.translation.page.mask;
                   2495:     uae_u32 addr_mask = mmu030.translation.page.imask;
                   2496:     
                   2497:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
                   2498:     physical_addr += page_index;
                   2499:     
                   2500:        if (mmu030.atc[l].physical.bus_error || (write && mmu030.atc[l].physical.write_protect)) {
                   2501:         mmu030_page_fault(addr, write == 0, MMU030_SSW_SIZE_B, fc);
                   2502:         return 0;
                   2503:     }
                   2504: 
                   2505:     return physical_addr;
                   2506: }
                   2507: uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
                   2508: {
                   2509:        int fc = (super ? 4 : 0) | (data ? 1 : 2);
1.1.1.5   root     2510:        if ((fc==7) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (!mmu030.enabled)) {
1.1.1.3   root     2511:                return addr;
                   2512:     }
                   2513:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
                   2514: 
                   2515:     if (atc_line_num>=0) {
                   2516:         return mmu030_get_addr_atc(addr, atc_line_num, fc, write);
                   2517:     } else {
                   2518:         mmu030_table_search(addr, fc, false, 0);
                   2519:         return mmu030_get_addr_atc(addr, mmu030_logical_is_in_atc(addr,fc,write), fc, write);
                   2520:     }
                   2521: }
                   2522: 
1.1       root     2523: /* MMU Reset */
                   2524: void mmu030_reset(int hardreset)
                   2525: {
1.1.1.3   root     2526:     /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
                   2527:     mmu030.enabled = false;
1.1.1.5   root     2528: #if MMU_IPAGECACHE030
                   2529:        mmu030.mmu030_last_logical_address = 0xffffffff;
                   2530: #endif
1.1.1.3   root     2531:        regs.mmu_page_size = 0;
1.1.1.5   root     2532:        if (hardreset >= 0) {
                   2533:                tc_030 &= ~TC_ENABLE_TRANSLATION;
                   2534:                tt0_030 &= ~TT_ENABLE;
                   2535:                tt1_030 &= ~TT_ENABLE;
                   2536:        }
                   2537:        if (hardreset > 0) {
1.1       root     2538:                srp_030 = crp_030 = 0;
                   2539:                tt0_030 = tt1_030 = tc_030 = 0;
1.1.1.3   root     2540:         mmusr_030 = 0;
                   2541:         mmu030_flush_atc_all();
                   2542:        }
                   2543:        mmu030_set_funcs();
                   2544: }
                   2545: 
                   2546: void mmu030_set_funcs(void)
                   2547: {
                   2548:        if (currprefs.mmu_model != 68030)
                   2549:                return;
1.1.1.5   root     2550:        if (currprefs.cpu_memory_cycle_exact) {
                   2551:                x_phys_get_iword = mem_access_delay_wordi_read_ce020;
                   2552:                x_phys_get_ilong = mem_access_delay_longi_read_ce020;
                   2553:                x_phys_get_byte = mem_access_delay_byte_read_ce020;
                   2554:                x_phys_get_word = mem_access_delay_word_read_ce020;
                   2555:                x_phys_get_long = mem_access_delay_long_read_ce020;
                   2556:                x_phys_put_byte = mem_access_delay_byte_write_ce020;
                   2557:                x_phys_put_word = mem_access_delay_word_write_ce020;
                   2558:                x_phys_put_long = mem_access_delay_long_write_ce020;
1.1.1.3   root     2559:        } else {
                   2560:                x_phys_get_iword = phys_get_word;
                   2561:                x_phys_get_ilong = phys_get_long;
1.1.1.5   root     2562:                x_phys_get_byte = phys_get_byte;
                   2563:                x_phys_get_word = phys_get_word;
                   2564:                x_phys_get_long = phys_get_long;
                   2565:                x_phys_put_byte = phys_put_byte;
                   2566:                x_phys_put_word = phys_put_word;
                   2567:                x_phys_put_long = phys_put_long;
1.1       root     2568:        }
                   2569: }
                   2570: 
1.1.1.6 ! root     2571: #define unalign_done(f) \
        !          2572:        st |= f; \
        !          2573:        mmu030_state[1] = st;
        !          2574: 
        !          2575: typedef uae_u32(*unaligned_read_func)(uaecptr addr, uae_u32 fc, int size, int flags);
        !          2576: 
        !          2577: static void mmu030_unaligned_read_continue(uaecptr addr, int fc, unaligned_read_func func)
        !          2578: {
        !          2579:        uae_u32 st = mmu030_state[1];
        !          2580: 
        !          2581: #if MMUDEBUG
        !          2582:        write_log(_T("unaligned_read_continue_s: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2583: #endif
        !          2584: 
        !          2585:        if (st & MMU030_STATEFLAG1_SUBACCESSL) {
        !          2586:                if (st & MMU030_STATEFLAG1_SUBACCESSX) {
        !          2587:                        // odd long access: byte + word + byte
        !          2588:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2589:                                mmu030_data_buffer_out &= 0x00ffffff;
        !          2590:                                mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_L) << 24;
        !          2591: #if MMUDEBUG
        !          2592:                                write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2593: #endif
        !          2594:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2595:                                addr++;
        !          2596:                        }
        !          2597:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2598:                                mmu030_data_buffer_out &= 0xff0000ff;
        !          2599:                                mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 8;
        !          2600: #if MMUDEBUG
        !          2601:                                write_log(_T("unaligned_read_continue_1: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2602: #endif
        !          2603:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2604:                                addr += 2;
        !          2605:                        }
        !          2606:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
        !          2607:                                mmu030_data_buffer_out &= 0xffffff00;
        !          2608:                                mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
        !          2609:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
        !          2610:                                addr++;
        !          2611:                        }
        !          2612:                } else {
        !          2613:                        // even but unaligned long access: word + word
        !          2614:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2615:                                mmu030_data_buffer_out &= 0x0000ffff;
        !          2616:                                mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_L) << 16;
        !          2617: #if MMUDEBUG
        !          2618:                                write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2619: #endif
        !          2620:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2621:                                addr += 2;
        !          2622:                        }
        !          2623:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2624:                                mmu030_data_buffer_out &= 0xffff0000;
        !          2625:                                mmu030_data_buffer_out |= func(addr, fc, sz_word, MMU030_SSW_SIZE_W) << 0;
        !          2626:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2627:                                addr += 2;
        !          2628:                        }
        !          2629:                }
        !          2630:        } else {
        !          2631:                // odd word access: byte + byte
        !          2632:                if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2633:                        mmu030_data_buffer_out &= 0x00ff;
        !          2634:                        mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_W) << 8;
        !          2635: #if MMUDEBUG
        !          2636:                        write_log(_T("unaligned_read_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2637: #endif
        !          2638:                        unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2639:                        addr++;
        !          2640:                }
        !          2641:                if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2642:                        mmu030_data_buffer_out &= 0xff00;
        !          2643:                        mmu030_data_buffer_out |= func(addr, fc, sz_byte, MMU030_SSW_SIZE_B) << 0;
        !          2644:                        unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2645:                        addr++;
        !          2646:                }
        !          2647:        }
        !          2648: 
        !          2649: #if MMUDEBUG
        !          2650:        write_log(_T("unaligned_read_continue_e: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2651: #endif
        !          2652:        unalign_clear();
        !          2653: }
        !          2654: 
        !          2655: typedef void (*unaligned_write_func)(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int flags);
        !          2656: 
        !          2657: static void mmu030_unaligned_write_continue(uaecptr addr, int fc, unaligned_write_func func)
        !          2658: {
        !          2659:        uae_u32 st = mmu030_state[1];
        !          2660: 
        !          2661: #if MMUDEBUG
        !          2662:        write_log(_T("unaligned_write_continue_s: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2663: #endif
        !          2664: 
        !          2665:        if (st & MMU030_STATEFLAG1_SUBACCESSL) {
        !          2666:                // odd long access: byte + word + byte
        !          2667:                if (st & MMU030_STATEFLAG1_SUBACCESSX) {
        !          2668:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2669:                                func(addr, mmu030_data_buffer_out >> 24, fc, sz_byte, MMU030_SSW_SIZE_L);
        !          2670: #if MMUDEBUG
        !          2671:                                write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2672: #endif
        !          2673:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2674:                                addr++;
        !          2675:                        }
        !          2676:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2677:                                func(addr, mmu030_data_buffer_out >> 8, fc, sz_word, MMU030_SSW_SIZE_W);
        !          2678: #if MMUDEBUG
        !          2679:                                write_log(_T("unaligned_write_continue_1: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2680: #endif
        !          2681:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2682:                                addr += 2;
        !          2683:                        }
        !          2684:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS3)) {
        !          2685:                                func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
        !          2686: #if MMUDEBUG
        !          2687:                                write_log(_T("unaligned_write_continue_2: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2688: #endif
        !          2689:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS3);
        !          2690:                                addr++;
        !          2691:                        }
        !          2692:                } else {
        !          2693:                        // even but unaligned long access: word + word
        !          2694:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2695:                                func(addr, mmu030_data_buffer_out >> 16, fc, sz_word, MMU030_SSW_SIZE_L);
        !          2696: #if MMUDEBUG
        !          2697:                                write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2698: #endif
        !          2699:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2700:                                addr += 2;
        !          2701:                        }
        !          2702:                        if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2703:                                func(addr, mmu030_data_buffer_out >> 0, fc, sz_word, MMU030_SSW_SIZE_W);
        !          2704:                                unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2705:                                addr += 2;
        !          2706:                        }
        !          2707:                }
        !          2708:        } else {
        !          2709:                // odd word access: byte + byte
        !          2710:                if (!(st & MMU030_STATEFLAG1_SUBACCESS1)) {
        !          2711:                        func(addr, mmu030_data_buffer_out >> 8, fc, sz_byte, MMU030_SSW_SIZE_W);
        !          2712: #if MMUDEBUG
        !          2713:                        write_log(_T("unaligned_write_continue_0: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2714: #endif
        !          2715:                        unalign_done(MMU030_STATEFLAG1_SUBACCESS1);
        !          2716:                        addr++;
        !          2717:                }
        !          2718:                if (!(st & MMU030_STATEFLAG1_SUBACCESS2)) {
        !          2719:                        func(addr, mmu030_data_buffer_out >> 0, fc, sz_byte, MMU030_SSW_SIZE_B);
        !          2720:                        unalign_done(MMU030_STATEFLAG1_SUBACCESS2);
        !          2721:                        addr++;
        !          2722:                }
        !          2723:        }
        !          2724: 
        !          2725: #if MMUDEBUG
        !          2726:        write_log(_T("unaligned_write_continue_e: %08x %d %08x %08x\n"), addr, fc, mmu030_data_buffer_out, st);
        !          2727: #endif
        !          2728:        unalign_clear();
        !          2729: }
        !          2730: 
1.1       root     2731: void m68k_do_rte_mmu030 (uaecptr a7)
                   2732: {
1.1.1.6 ! root     2733:        struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1];
        !          2734: 
1.1.1.3   root     2735:        // Restore access error exception state
                   2736: 
1.1.1.6 ! root     2737:        uae_u16 sr = get_word_mmu030(a7);
        !          2738:        uae_u32 pc = get_long_mmu030(a7 + 2);
        !          2739:        uae_u16 format = get_word_mmu030(a7 + 6);
1.1.1.3   root     2740:        uae_u16 frame = format >> 12;
1.1.1.6 ! root     2741:        uae_u16 ssw = get_word_mmu030(a7 + 10);
        !          2742:        uae_u32 fault_addr = get_long_mmu030(a7 + 16);
1.1.1.3   root     2743: 
                   2744:        // Fetch last word, real CPU does it to allow OS bus handler to map
                   2745:        // the page if frame crosses pages and following page is not resident.
                   2746:        if (frame == 0xb)
                   2747:                get_word_mmu030(a7 + 92 - 2);
                   2748:        else
                   2749:                get_word_mmu030(a7 + 32 - 2);
                   2750: 
                   2751:        // Internal register, our opcode storage area
1.1.1.6 ! root     2752:        uae_u32 oc = get_long_mmu030(a7 + 0x14);
        !          2753:        // Data output buffer
        !          2754:        uae_u32 mmu030_data_buffer_out_v = get_long_mmu030(a7 + 0x18);
        !          2755:        // get_disp_ea_020
        !          2756:        uae_u32 mmu030_disp_store_0 = get_long_mmu030(a7 + 0x1c);
        !          2757:        uae_u32 mmu030_disp_store_1 = get_long_mmu030(a7 + 0x1c + 4);
        !          2758:        // Internal register, misc flags
        !          2759:        uae_u32 ps = get_long_mmu030(a7 + 0x28);
        !          2760:        // Data buffer
        !          2761:        uae_u32 mmu030_data_buffer_in_v = get_long_mmu030(a7 + 0x2c);;
        !          2762: 
        !          2763:        uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff);
1.1.1.3   root     2764:        // Misc state data
1.1.1.6 ! root     2765:        uae_u32 mmu030_state_0 = get_word_mmu030(a7 + 0x30);
        !          2766:        uae_u32 mmu030_state_1 = get_word_mmu030(a7 + 0x32);
        !          2767:        uae_u32 mmu030_state_2 = get_word_mmu030(a7 + 0x34);
        !          2768: 
        !          2769:        uae_u32 mmu030_fmovem_store_0 = 0;
        !          2770:        uae_u32 mmu030_fmovem_store_1 = 0;
1.1.1.3   root     2771:        if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
1.1.1.6 ! root     2772:                mmu030_fmovem_store_0 = get_long_mmu030(a7 + 0x5c - (7 + 1) * 4);
        !          2773:                mmu030_fmovem_store_1 = get_long_mmu030(a7 + 0x5c - (8 + 1) * 4);
1.1.1.3   root     2774:        }
1.1.1.6 ! root     2775: 
1.1.1.3   root     2776:        // Rerun "mmu030_opcode" using restored state.
                   2777:        mmu030_retry = true;
                   2778: 
                   2779:        if (frame == 0xb) {
1.1.1.6 ! root     2780: 
1.1.1.3   root     2781:                uae_u16 idxsize = get_word_mmu030 (a7 + 0x36);
1.1.1.6 ! root     2782:                for (int i = 0; i < idxsize + 1; i++) {
        !          2783:                        mmu030_ad_v[i].done = i < idxsize;
        !          2784:                        mmu030_ad_v[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4);
1.1.1.3   root     2785:                }
1.1.1.6 ! root     2786:                mmu030_ad_v[idxsize + 1].done = false;
        !          2787: 
1.1.1.3   root     2788:                // did we have data fault but DF bit cleared?
                   2789:                if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
                   2790:                        // DF not set: mark access as done
1.1.1.6 ! root     2791:                        mmu030_data_buffer_out_v = mmu030_data_buffer_in_v;
1.1.1.3   root     2792:                        if (ssw & MMU030_SSW_RM) {
                   2793:                                // Read-Modify-Write: whole instruction is considered done
                   2794:                                write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
                   2795:                                mmu030_retry = false;
1.1.1.6 ! root     2796:                        } else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) {
1.1.1.3   root     2797:                                // if movem, skip next move
1.1.1.6 ! root     2798:                                mmu030_state_1 |= MMU030_STATEFLAG1_MOVEM2;
1.1.1.3   root     2799:                        } else {
1.1.1.6 ! root     2800:                                mmu030_ad_v[idxsize].done = true;
1.1.1.3   root     2801:                                if (ssw & MMU030_SSW_RW) {
                   2802:                                        // Read and no DF: use value in data input buffer
1.1.1.6 ! root     2803:                                        mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v;
1.1.1.3   root     2804:                                }
                   2805:                        }
1.1.1.6 ! root     2806:                        unalign_clear();
1.1.1.3   root     2807:                }
                   2808:                // did we have ins fault and RB bit cleared?
                   2809:                if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
                   2810:                        uae_u16 stageb = get_word_mmu030 (a7 + 0x0e);
1.1.1.6 ! root     2811:                        if (mmu030_opcode_v == -1U) {
1.1.1.3   root     2812:                                mmu030_opcode_stageb = stageb;
                   2813:                                write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb);
                   2814:                        } else {
1.1.1.6 ! root     2815:                                mmu030_ad_v[idxsize].done = true;
        !          2816:                                mmu030_ad_v[idxsize].val = stageb;
        !          2817:                                write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode_v, stageb);
1.1.1.3   root     2818:                        }
                   2819:                }
1.1.1.6 ! root     2820: 
        !          2821:                // Retried data access is the only memory access that can be done after this.
        !          2822: 
        !          2823:                // restore global state variables
        !          2824:                mmu030_opcode = mmu030_opcode_v;
        !          2825:                mmu030_state[0] = mmu030_state_0;
        !          2826:                mmu030_state[1] = mmu030_state_1;
        !          2827:                mmu030_state[2] = mmu030_state_2;
        !          2828:                mmu030_disp_store[0] = mmu030_disp_store_0;
        !          2829:                mmu030_disp_store[1] = mmu030_disp_store_1;
        !          2830:                mmu030_fmovem_store[0] = mmu030_fmovem_store_0;
        !          2831:                mmu030_fmovem_store[1] = mmu030_fmovem_store_1;
        !          2832:                mmu030_data_buffer_out = mmu030_data_buffer_out_v;
        !          2833:                mmu030_idx = idxsize;
        !          2834:                for (int i = 0; i <= mmu030_idx + 1; i++) {
        !          2835:                        mmu030_ad[i].done = mmu030_ad_v[i].done;
        !          2836:                        mmu030_ad[i].val = mmu030_ad_v[i].val;
        !          2837:                }
        !          2838: 
        !          2839:                m68k_areg(regs, 7) += 92;
        !          2840:                regs.sr = sr;
        !          2841:                MakeFromSR_T0();
        !          2842:                if (pc & 1) {
        !          2843:                        exception3i(0x4E73, pc);
        !          2844:                        return;
        !          2845:                }
        !          2846:                m68k_setpci(pc);
        !          2847: 
        !          2848:                if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) {
        !          2849: 
        !          2850:                        // Locked-Read-Modify-Write restarts whole instruction.
        !          2851:                        mmu030_ad[0].done = false;
        !          2852: 
        !          2853:                } else if (ssw & MMU030_SSW_DF) {
        !          2854: 
        !          2855:                        // retry faulted access
        !          2856:                        uaecptr addr = fault_addr;
        !          2857:                        bool read = (ssw & MMU030_SSW_RW) != 0;
        !          2858:                        int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long);
        !          2859:                        int fc = ssw & MMU030_SSW_FC_MASK;
        !          2860:                        
        !          2861: #if MMU030_DEBUG
        !          2862:                        if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          2863:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
        !          2864:                                        write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
        !          2865:                                }
        !          2866:                        }
        !          2867:                        if (mmu030_ad[idxsize].done) {
        !          2868:                                write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
        !          2869:                        }
        !          2870: #endif
        !          2871: 
        !          2872: #if MMU030_DEBUG
        !          2873:                        write_log(_T("%08x %08x %08x %08x %08x %d %d %d %08x %08x %04x\n"),
        !          2874:                                mmu030_state[1], mmu030_state[2], mmu030_disp_store[0], mmu030_disp_store[1],
        !          2875:                                addr, read, size, fc, mmu030_data_buffer_out, mmu030_ad[idxsize].val, ssw);
        !          2876: #endif
        !          2877: 
        !          2878:                        if (read) {
        !          2879:                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
        !          2880:                                        mmu030_unaligned_read_continue(addr, fc, mmu030_get_generic);
        !          2881:                                } else {
        !          2882:                                        switch (size)
        !          2883:                                        {
        !          2884:                                                case sz_byte:
        !          2885:                                                mmu030_data_buffer_out = uae_mmu030_get_byte_fcx(addr, fc);
        !          2886:                                                break;
        !          2887:                                                case sz_word:
        !          2888:                                                mmu030_data_buffer_out = uae_mmu030_get_word_fcx(addr, fc);
        !          2889:                                                break;
        !          2890:                                                case sz_long:
        !          2891:                                                mmu030_data_buffer_out = uae_mmu030_get_long_fcx(addr, fc);
        !          2892:                                                break;
        !          2893:                                        }
        !          2894:                                }
        !          2895:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          2896:                                        mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
        !          2897:                                } else {
        !          2898:                                        mmu030_ad[idxsize].val = mmu030_data_buffer_out;
        !          2899:                                        mmu030_ad[idxsize].done = true;
        !          2900:                                }
        !          2901:                        } else {
        !          2902:                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
        !          2903:                                        mmu030_unaligned_write_continue(addr, fc, mmu030_put_generic);
        !          2904:                                } else {
        !          2905:                                        switch (size)
        !          2906:                                        {
        !          2907:                                                case sz_byte:
        !          2908:                                                uae_mmu030_put_byte_fcx(addr, mmu030_data_buffer_out, fc);
        !          2909:                                                break;
        !          2910:                                                case sz_word:
        !          2911:                                                uae_mmu030_put_word_fcx(addr, mmu030_data_buffer_out, fc);
        !          2912:                                                break;
        !          2913:                                                case sz_long:
        !          2914:                                                uae_mmu030_put_long_fcx(addr, mmu030_data_buffer_out, fc);
        !          2915:                                                break;
        !          2916:                                        }
        !          2917:                                }
        !          2918:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          2919:                                        mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
        !          2920:                                } else {
        !          2921:                                        mmu030_ad[idxsize].done = true;
        !          2922:                                }
        !          2923:                        }
        !          2924: 
        !          2925:                }
        !          2926: 
        !          2927:                if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) {
        !          2928:                        mmu030_retry = false;
        !          2929:                }
        !          2930: 
        !          2931: #if MMU030_DEBUG
        !          2932:                if (mmu030_idx >= MAX_MMU030_ACCESS) {
        !          2933:                        write_log(_T("mmu030_idx (RTE) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
        !          2934:                }
        !          2935: #endif
        !          2936: 
1.1.1.3   root     2937:        } else {
                   2938:                m68k_areg (regs, 7) += 32;
1.1       root     2939:        }
                   2940: }
                   2941: 
                   2942: void flush_mmu030 (uaecptr addr, int n)
                   2943: {
                   2944: }
                   2945: 
                   2946: void m68k_do_rts_mmu030 (void)
                   2947: {
1.1.1.3   root     2948:        m68k_setpc (get_long_mmu030_state (m68k_areg (regs, 7)));
1.1       root     2949:        m68k_areg (regs, 7) += 4;
                   2950: }
                   2951: 
                   2952: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
                   2953: {
1.1.1.3   root     2954:        put_long_mmu030_state (m68k_areg (regs, 7) - 4, oldpc);
1.1       root     2955:        m68k_areg (regs, 7) -= 4;
                   2956:        m68k_incpci (offset);
                   2957: }
1.1.1.3   root     2958: 
                   2959: uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx)
                   2960: {
                   2961:        uae_u16 dp;
                   2962:        int reg;
                   2963:        uae_u32 v;
                   2964:        int oldidx;
                   2965:        int pcadd = 0;
                   2966: 
                   2967:        // we need to do this hack here because in worst case we don't have enough
                   2968:        // stack frame space to store two very large 020 addressing mode access state
                   2969:        // + whatever the instruction itself does.
                   2970: 
                   2971:        if (mmu030_state[1] & (1 << idx)) {
                   2972:                m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
                   2973:                return mmu030_disp_store[idx];
                   2974:        }
                   2975: 
                   2976:        oldidx = mmu030_idx;
                   2977:        dp = next_iword_mmu030_state ();
                   2978:        pcadd += 1;
                   2979:        
                   2980:        reg = (dp >> 12) & 15;
                   2981:        uae_s32 regd = regs.regs[reg];
                   2982:        if ((dp & 0x800) == 0)
                   2983:                regd = (uae_s32)(uae_s16)regd;
                   2984:        regd <<= (dp >> 9) & 3;
                   2985:        if (dp & 0x100) {
                   2986:                uae_s32 outer = 0;
                   2987:                if (dp & 0x80)
                   2988:                        base = 0;
                   2989:                if (dp & 0x40)
                   2990:                        regd = 0;
                   2991: 
                   2992:                if ((dp & 0x30) == 0x20) {
                   2993:                        base += (uae_s32)(uae_s16) next_iword_mmu030_state ();
                   2994:                        pcadd += 1;
                   2995:                }
                   2996:                if ((dp & 0x30) == 0x30) {
                   2997:                        base += next_ilong_mmu030_state ();
                   2998:                        pcadd += 2;
                   2999:                }
                   3000: 
                   3001:                if ((dp & 0x3) == 0x2) {
                   3002:                        outer = (uae_s32)(uae_s16) next_iword_mmu030_state ();
                   3003:                        pcadd += 1;
                   3004:                }
                   3005:                if ((dp & 0x3) == 0x3) {
                   3006:                        outer = next_ilong_mmu030_state ();
                   3007:                        pcadd += 2;
                   3008:                }
                   3009: 
                   3010:                if ((dp & 0x4) == 0) {
                   3011:                        base += regd;
                   3012:                }
                   3013:                if (dp & 0x3) {
                   3014:                        base = get_long_mmu030_state (base);
                   3015:                }
                   3016:                if (dp & 0x4) {
                   3017:                        base += regd;
                   3018:                }
                   3019:                v = base + outer;
                   3020:        } else {
                   3021:                v = base + (uae_s32)((uae_s8)dp) + regd;
                   3022:        }
                   3023: 
                   3024:        mmu030_state[1] |= 1 << idx;
                   3025:        mmu030_state[2] |= pcadd << (idx * 4);
                   3026:        mmu030_disp_store[idx] = v;
                   3027:        mmu030_idx = oldidx;
                   3028:        mmu030_ad[mmu030_idx].done = false;
                   3029: 
                   3030:        return v;
                   3031: }
1.1.1.5   root     3032: 
                   3033: // cache
                   3034: 
                   3035: void m68k_do_rts_mmu030c (void)
                   3036: {
                   3037:        m68k_setpc (get_long_mmu030c_state (m68k_areg (regs, 7)));
                   3038:        m68k_areg (regs, 7) += 4;
                   3039: }
                   3040: 
                   3041: void m68k_do_bsr_mmu030c (uaecptr oldpc, uae_s32 offset)
                   3042: {
                   3043:        put_long_mmu030c_state (m68k_areg (regs, 7) - 4, oldpc);
                   3044:        m68k_areg (regs, 7) -= 4;
                   3045:        m68k_incpci (offset);
                   3046: }
                   3047: 
                   3048: 
                   3049: uae_u32 REGPARAM2 get_disp_ea_020_mmu030c (uae_u32 base, int idx)
                   3050: {
                   3051:        uae_u16 dp;
                   3052:        int reg;
                   3053:        uae_u32 v;
                   3054:        int oldidx;
                   3055:        int pcadd = 0;
                   3056: 
                   3057:        // we need to do this hack here because in worst case we don't have enough
                   3058:        // stack frame space to store two very large 020 addressing mode access state
                   3059:        // + whatever the instruction itself does.
                   3060: 
                   3061:        if (mmu030_state[1] & (1 << idx)) {
                   3062:                m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
                   3063:                return mmu030_disp_store[idx];
                   3064:        }
                   3065: 
                   3066:        oldidx = mmu030_idx;
                   3067:        dp = next_iword_mmu030c_state ();
                   3068:        pcadd += 1;
                   3069:        
                   3070:        reg = (dp >> 12) & 15;
                   3071:        uae_s32 regd = regs.regs[reg];
                   3072:        if ((dp & 0x800) == 0)
                   3073:                regd = (uae_s32)(uae_s16)regd;
                   3074:        regd <<= (dp >> 9) & 3;
                   3075:        if (dp & 0x100) {
                   3076:                uae_s32 outer = 0;
                   3077:                if (dp & 0x80)
                   3078:                        base = 0;
                   3079:                if (dp & 0x40)
                   3080:                        regd = 0;
                   3081: 
                   3082:                if ((dp & 0x30) == 0x20) {
                   3083:                        base += (uae_s32)(uae_s16) next_iword_mmu030c_state ();
                   3084:                        pcadd += 1;
                   3085:                }
                   3086:                if ((dp & 0x30) == 0x30) {
                   3087:                        base += next_ilong_mmu030c_state ();
                   3088:                        pcadd += 2;
                   3089:                }
                   3090: 
                   3091:                if ((dp & 0x3) == 0x2) {
                   3092:                        outer = (uae_s32)(uae_s16) next_iword_mmu030c_state ();
                   3093:                        pcadd += 1;
                   3094:                }
                   3095:                if ((dp & 0x3) == 0x3) {
                   3096:                        outer = next_ilong_mmu030c_state ();
                   3097:                        pcadd += 2;
                   3098:                }
                   3099: 
                   3100:                if ((dp & 0x4) == 0) {
                   3101:                        base += regd;
                   3102:                }
                   3103:                if (dp & 0x3) {
                   3104:                        base = get_long_mmu030c_state (base);
                   3105:                }
                   3106:                if (dp & 0x4) {
                   3107:                        base += regd;
                   3108:                }
                   3109:                v = base + outer;
                   3110:        } else {
                   3111:                v = base + (uae_s32)((uae_s8)dp) + regd;
                   3112:        }
                   3113: 
                   3114:        mmu030_state[1] |= 1 << idx;
                   3115:        mmu030_state[2] |= pcadd << (idx * 4);
                   3116:        mmu030_disp_store[idx] = v;
                   3117:        mmu030_idx = oldidx;
                   3118:        mmu030_ad[mmu030_idx].done = false;
                   3119: 
                   3120:        return v;
                   3121: }
                   3122: 
                   3123: void m68k_do_rte_mmu030c (uaecptr a7)
                   3124: {
1.1.1.6 ! root     3125:        struct mmu030_access mmu030_ad_v[MAX_MMU030_ACCESS + 1];
        !          3126: 
1.1.1.5   root     3127:        // Restore access error exception state
                   3128: 
1.1.1.6 ! root     3129:        uae_u16 sr = get_word_mmu030c(a7);
        !          3130:        uae_u32 pc = get_long_mmu030c(a7 + 2);
1.1.1.5   root     3131:        uae_u16 format = get_word_mmu030c (a7 + 6);
                   3132:        uae_u16 frame = format >> 12;
                   3133:        uae_u16 ssw = get_word_mmu030c (a7 + 10);
1.1.1.6 ! root     3134:        uae_u32 stagesbc = get_long_mmu030c(a7 + 12);
        !          3135:        uae_u32 fault_addr = get_long_mmu030c(a7 + 16);
1.1.1.5   root     3136: 
                   3137:        // Fetch last word, real CPU does it to allow OS bus handler to map
                   3138:        // the page if frame crosses pages and following page is not resident.
                   3139:        if (frame == 0xb)
                   3140:                get_word_mmu030c(a7 + 92 - 2);
                   3141:        else
                   3142:                get_word_mmu030c(a7 + 32 - 2);
                   3143: 
1.1.1.6 ! root     3144:        // Internal register, our opcode storage area
        !          3145:        uae_u32 oc = get_long_mmu030c(a7 + 0x14);
        !          3146:        // Data output buffer
        !          3147:        uae_u32 mmu030_data_buffer_out_v = get_long_mmu030c(a7 + 0x18);
        !          3148:        // get_disp_ea_020
        !          3149:        uae_u32 mmu030_disp_store_0 = get_long_mmu030c(a7 + 0x1c);
        !          3150:        uae_u32 mmu030_disp_store_1 = get_long_mmu030c(a7 + 0x1c + 4);
1.1.1.5   root     3151:        // Internal register, misc flags
                   3152:        uae_u32 ps = get_long_mmu030c(a7 + 0x28);
1.1.1.6 ! root     3153:        // Data buffer
        !          3154:        uae_u32 mmu030_data_buffer_in_v = get_long_mmu030c(a7 + 0x2c);;
        !          3155: 
        !          3156:        uae_u32 mmu030_opcode_v = (ps & 0x80000000) ? -1U : (oc & 0xffff);
1.1.1.5   root     3157:        // Misc state data
1.1.1.6 ! root     3158:        uae_u32 mmu030_state_0 = get_word_mmu030c(a7 + 0x30);
        !          3159:        uae_u32 mmu030_state_1 = get_word_mmu030c(a7 + 0x32);
        !          3160:        uae_u32 mmu030_state_2 = get_word_mmu030c(a7 + 0x34);
        !          3161: 
        !          3162:        uae_u32 mmu030_fmovem_store_0 = 0;
        !          3163:        uae_u32 mmu030_fmovem_store_1 = 0;
1.1.1.5   root     3164:        if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
1.1.1.6 ! root     3165:                mmu030_fmovem_store_0 = get_long_mmu030c(a7 + 0x5c - (7 + 1) * 4);
        !          3166:                mmu030_fmovem_store_1 = get_long_mmu030c(a7 + 0x5c - (8 + 1) * 4);
1.1.1.5   root     3167:        }
1.1.1.6 ! root     3168: 
1.1.1.5   root     3169:        // Rerun "mmu030_opcode" using restored state.
                   3170:        mmu030_retry = true;
                   3171: 
                   3172:        if (frame == 0xb) {
                   3173:                uae_u16 idxsize = get_word_mmu030c(a7 + 0x36);
1.1.1.6 ! root     3174:                for (int i = 0; i < idxsize + 1; i++) {
        !          3175:                        mmu030_ad_v[i].done = i < idxsize;
        !          3176:                        mmu030_ad_v[i].val = get_long_mmu030c(a7 + 0x5c - (i + 1) * 4);
1.1.1.5   root     3177:                }
1.1.1.6 ! root     3178:                mmu030_ad_v[idxsize + 1].done = false;
        !          3179: 
1.1.1.5   root     3180:                // did we have data fault but DF bit cleared?
                   3181:                if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
                   3182:                        // DF not set: mark access as done
1.1.1.6 ! root     3183:                        mmu030_data_buffer_out_v = mmu030_data_buffer_in_v;
1.1.1.5   root     3184:                        if (ssw & MMU030_SSW_RM) {
                   3185:                                // Read-Modify-Write: whole instruction is considered done
                   3186:                                write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
                   3187:                                mmu030_retry = false;
1.1.1.6 ! root     3188:                        } else if (mmu030_state_1 & MMU030_STATEFLAG1_MOVEM1) {
1.1.1.5   root     3189:                                // if movem, skip next move
1.1.1.6 ! root     3190:                                mmu030_state_1 |= MMU030_STATEFLAG1_MOVEM2;
1.1.1.5   root     3191:                        } else {
1.1.1.6 ! root     3192:                                mmu030_ad_v[idxsize].done = true;
1.1.1.5   root     3193:                                if (ssw & MMU030_SSW_RW) {
                   3194:                                        // Read and no DF: use value in data input buffer
1.1.1.6 ! root     3195:                                        mmu030_ad_v[idxsize].val = mmu030_data_buffer_in_v;
1.1.1.5   root     3196:                                }
                   3197:                        }
1.1.1.6 ! root     3198:                        unalign_clear();
1.1.1.5   root     3199:                }
                   3200: 
1.1.1.6 ! root     3201:                // Retried data access is the only memory access that can be done after this.
        !          3202: 
1.1.1.5   root     3203:                regs.prefetch020_valid[0] = (ps & 1) ? 1 : 0;
                   3204:                regs.prefetch020_valid[1] = (ps & 2) ? 1 : 0;
                   3205:                regs.prefetch020_valid[2] = (ps & 4) ? 1 : 0;
                   3206:                regs.pipeline_r8[0] = (ps >> 8) & 7;
                   3207:                regs.pipeline_r8[1] = (ps >> 11) & 7;
                   3208:                regs.pipeline_pos = (ps >> 16) & 15;
1.1.1.6 ! root     3209:                regs.pipeline_stop = ((ps >> 20) & 15) == 15 ? -1 : (int)(ps >> 20) & 15;
1.1.1.5   root     3210: 
                   3211:                regs.prefetch020[2] = stagesbc;
                   3212:                regs.prefetch020[1] = stagesbc >> 16;
                   3213:                regs.prefetch020[0] = oc >> 16;
                   3214: 
                   3215:                if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
                   3216:                        regs.prefetch020_valid[2] = 1;
                   3217:                        write_log (_T("Software fixed stage B! opcode = %04x\n"), regs.prefetch020[2]);
                   3218:                }
                   3219:                if ((ssw & MMU030_SSW_FC) && !(ssw & MMU030_SSW_RC)) {
                   3220:                        regs.prefetch020_valid[1] = 1;
                   3221:                        write_log (_T("Software fixed stage C! opcode = %04x\n"), regs.prefetch020[1]);
                   3222:                }
                   3223: 
1.1.1.6 ! root     3224:                // restore global state variables
        !          3225:                mmu030_opcode = mmu030_opcode_v;
        !          3226:                mmu030_state[0] = mmu030_state_0;
        !          3227:                mmu030_state[1] = mmu030_state_1;
        !          3228:                mmu030_state[2] = mmu030_state_2;
        !          3229:                mmu030_disp_store[0] = mmu030_disp_store_0;
        !          3230:                mmu030_disp_store[1] = mmu030_disp_store_1;
        !          3231:                mmu030_fmovem_store[0] = mmu030_fmovem_store_0;
        !          3232:                mmu030_fmovem_store[1] = mmu030_fmovem_store_1;
        !          3233:                mmu030_data_buffer_out = mmu030_data_buffer_out_v;
        !          3234:                mmu030_idx = idxsize;
        !          3235:                for (int i = 0; i <= mmu030_idx + 1; i++) {
        !          3236:                        mmu030_ad[i].done = mmu030_ad_v[i].done;
        !          3237:                        mmu030_ad[i].val = mmu030_ad_v[i].val;
        !          3238:                }
1.1.1.5   root     3239: 
1.1.1.6 ! root     3240:                m68k_areg (regs, 7) += 92;
1.1.1.5   root     3241:                regs.sr = sr;
                   3242:                MakeFromSR_T0();
                   3243:                if (pc & 1) {
                   3244:                        exception3i (0x4E73, pc);
                   3245:                        return;
                   3246:                }
                   3247:                m68k_setpci (pc);
                   3248: 
                   3249:                if (!(ssw & (MMU030_SSW_DF << 1))) {
                   3250:                        if (!regs.prefetch020_valid[0] && regs.prefetch020_valid[2]) {
                   3251:                                // Prefetch was software fixed, continue pipeline refill
                   3252:                                fill_prefetch_030_ntx_continue();
                   3253:                        } else if (regs.prefetch020_valid[0] && regs.prefetch020_valid[1]) {
                   3254:                                // Finished?
                   3255:                                fill_prefetch_030_ntx_continue();
                   3256:                        } else if (mmu030_opcode == -1) {
                   3257:                                // Previous branch instruction finished successfully but its pipeline refill
                   3258:                                // step caused the exception, retry the refill, do not retry branch instruction.
                   3259:                                fill_prefetch_030_ntx();
                   3260:                        }
                   3261:                }
                   3262: 
1.1.1.6 ! root     3263:                if ((ssw & MMU030_SSW_DF) && (ssw & MMU030_SSW_RM)) {
        !          3264: 
        !          3265:                        // Locked-Read-Modify-Write restarts whole instruction.
        !          3266:                        mmu030_ad[0].done = false;
        !          3267: 
        !          3268:                } else if (ssw & MMU030_SSW_DF) {
        !          3269:                        // retry faulted access
        !          3270:                        uaecptr addr = fault_addr;
        !          3271:                        bool read = (ssw & MMU030_SSW_RW) != 0;
        !          3272:                        int size = (ssw & MMU030_SSW_SIZE_B) ? sz_byte : ((ssw & MMU030_SSW_SIZE_W) ? sz_word : sz_long);
        !          3273:                        int fc = ssw & 7;
        !          3274: 
        !          3275: #if MMU030_DEBUG
        !          3276:                        if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          3277:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
        !          3278:                                        write_log(_T("68030 MMU MOVEM %04x retry but MMU030_STATEFLAG1_MOVEM2 was already set!?\n"), mmu030_opcode);
        !          3279:                                }
        !          3280:                        } else {
        !          3281:                                if (mmu030_ad[idxsize].done) {
        !          3282:                                        write_log(_T("68030 MMU ins %04x retry but it was already marked as done!?\n"), mmu030_opcode);
        !          3283:                                }
        !          3284:                        }
        !          3285: #endif
        !          3286:                        if (read) {
        !          3287:                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
        !          3288:                                        mmu030_unaligned_read_continue(addr, fc, read_dcache030_retry);
        !          3289:                                } else {
        !          3290:                                        switch (size)
        !          3291:                                        {
        !          3292:                                                case sz_byte:
        !          3293:                                                mmu030_data_buffer_out = read_data_030_fc_bget(addr, fc);
        !          3294:                                                break;
        !          3295:                                                case sz_word:
        !          3296:                                                mmu030_data_buffer_out = read_data_030_fc_wget(addr, fc);
        !          3297:                                                break;
        !          3298:                                                case sz_long:
        !          3299:                                                mmu030_data_buffer_out = read_data_030_fc_lget(addr, fc);
        !          3300:                                                break;
        !          3301:                                        }
        !          3302:                                }
        !          3303:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          3304:                                        mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
        !          3305:                                } else {
        !          3306:                                        mmu030_ad[idxsize].val = mmu030_data_buffer_out;
        !          3307:                                        mmu030_ad[idxsize].done = true;
        !          3308:                                }
        !          3309:                        } else {
        !          3310:                                if (mmu030_state[1] & MMU030_STATEFLAG1_SUBACCESS0) {
        !          3311:                                        mmu030_unaligned_write_continue(addr, fc, write_dcache030_retry);
        !          3312:                                } else {
        !          3313:                                        switch (size)
        !          3314:                                        {
        !          3315:                                                case sz_byte:
        !          3316:                                                write_data_030_fc_bput(addr, mmu030_data_buffer_out, fc);
        !          3317:                                                break;
        !          3318:                                                case sz_word:
        !          3319:                                                write_data_030_fc_wput(addr, mmu030_data_buffer_out, fc);
        !          3320:                                                break;
        !          3321:                                                case sz_long:
        !          3322:                                                write_data_030_fc_lput(addr, mmu030_data_buffer_out, fc);
        !          3323:                                                break;
        !          3324:                                        }
        !          3325:                                }
        !          3326:                                if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          3327:                                        mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
        !          3328:                                } else {
        !          3329:                                        mmu030_ad[idxsize].done = true;
        !          3330:                                }
        !          3331:                        }
        !          3332:                }
        !          3333: 
        !          3334:                if (mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE) {
        !          3335:                        mmu030_retry = false;
        !          3336:                        fill_prefetch_030_ntx();
        !          3337:                }
        !          3338: 
1.1.1.5   root     3339:        } else {
                   3340:                m68k_areg (regs, 7) += 32;
                   3341:        }
                   3342: }

unix.superglobalmegacorp.com

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