Annotation of previous/src/cpu/cpummu030.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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