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

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

unix.superglobalmegacorp.com

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