Annotation of previous_trunk/src/cpu/cpummu030.c, revision 1.1

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).
        !            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.
        !            27:  * - Handle cache inhibit bit when accessing ATC entries
        !            28:  */
        !            29: 
        !            30: 
        !            31: #include "sysconfig.h"
        !            32: #include "sysdeps.h"
        !            33: 
        !            34: #include "main.h"
        !            35: #include "hatari-glue.h"
        !            36: #include "host.h"
        !            37: 
        !            38: #include "options_cpu.h"
        !            39: #include "memory.h"
        !            40: #include "newcpu.h"
        !            41: #include "cpummu030.h"
        !            42: 
        !            43: #define MMU030_OP_DBG_MSG 0
        !            44: #define MMU030_ATC_DBG_MSG 0
        !            45: #define MMU030_REG_DBG_MSG 0
        !            46: 
        !            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
        !            53: 
        !            54: #define TT_ADDR_MASK    0x00FF0000
        !            55: #define TT_ADDR_BASE    0xFF000000
        !            56: 
        !            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;
        !            67: 
        !            68: int mmu030_fake_prefetch;
        !            69: uaecptr mmu030_fake_prefetch_addr;
        !            70: 
        !            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;
        !            83: 
        !            84: /* ATC struct */
        !            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 */
        !           107: static struct {
        !           108:     
        !           109:     /* Translation tables */
        !           110:     struct {
        !           111:         struct {
        !           112:             uae_u32 mask;
        !           113:             uae_u8 shift;
        !           114:         } table[4];
        !           115:         
        !           116:         struct {
        !           117:             uae_u32 mask;
        !           118:                        uae_u32 imask;
        !           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:     
        !           135:     /* Condition */
        !           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: 
        !           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)
        !           198: {
        !           199:        int preg = (next >> 10) & 31;
        !           200:        int rw = (next >> 9) & 1;
        !           201:        int fd = (next >> 8) & 1;
        !           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;
        !           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:     
        !           249:        switch (preg)
        !           250:        {
        !           251:         case 0x10: // TC
        !           252:             if (rw)
        !           253:                 x_put_long (extra, tc_030);
        !           254:             else {
        !           255:                 tc_030 = x_get_long (extra);
        !           256:                 if (mmu030_decode_tc(tc_030))
        !           257:                                        return true;
        !           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);
        !           267:                 host_darkmatter(srp_030 == crp_030);
        !           268:                 if (mmu030_decode_rp(srp_030))
        !           269:                                        return true;
        !           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);
        !           279:                 if (mmu030_decode_rp(crp_030))
        !           280:                                        return true;
        !           281:             }
        !           282:             break;
        !           283:         case 0x18: // MMUSR
        !           284:             if (fd) {
        !           285:                 // FD must be always zero when MMUSR read or write
        !           286:                 return true;
        !           287:             }
        !           288:             if (rw)
        !           289:                 x_put_word (extra, mmusr_030);
        !           290:             else
        !           291:                 mmusr_030 = x_get_word (extra);
        !           292:             break;
        !           293:         case 0x02: // TT0
        !           294:             if (rw)
        !           295:                 x_put_long (extra, tt0_030);
        !           296:             else {
        !           297:                 tt0_030 = x_get_long (extra);
        !           298:                 mmu030.transparent.tt0 = mmu030_decode_tt(tt0_030);
        !           299:             }
        !           300:             break;
        !           301:         case 0x03: // TT1
        !           302:             if (rw)
        !           303:                 x_put_long (extra, tt1_030);
        !           304:             else {
        !           305:                 tt1_030 = x_get_long (extra);
        !           306:                 mmu030.transparent.tt1 = mmu030_decode_tt(tt1_030);
        !           307:             }
        !           308:             break;
        !           309:         default:
        !           310:             write_log (_T("Bad PMOVE at %08x\n"),m68k_getpc());
        !           311:             return true;
        !           312:        }
        !           313:     
        !           314:     if (!fd && !rw && preg != 0x18) {
        !           315:         mmu030_flush_atc_all();
        !           316:     }
        !           317:        tt_enabled = (tt0_030 & TT_ENABLE) || (tt1_030 & TT_ENABLE);
        !           318:        return false;
        !           319: }
        !           320: 
        !           321: bool mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
        !           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:     
        !           335:     if (mmu_op30_invea(opcode))
        !           336:         return true;
        !           337:     
        !           338:     if (!level && a) {
        !           339:         write_log(_T("PTEST: Bad instruction causing F-line unimplemented instruction exception!\n"));
        !           340:         return true;
        !           341:     }
        !           342:         
        !           343: #if MMU030_OP_DBG_MSG
        !           344:     write_log(_T("PTEST%c: addr = %08X, fc = %i, level = %i, "),
        !           345:               rw?'R':'W', extra, fc, level);
        !           346:     if (a) {
        !           347:         write_log(_T("return descriptor to register A%i\n"), areg);
        !           348:     } else {
        !           349:         write_log(_T("do not return descriptor\n"));
        !           350:     }
        !           351: #endif
        !           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:     
        !           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"),
        !           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);
        !           369: #endif
        !           370:        return false;
        !           371: }
        !           372: 
        !           373: bool mmu_op30_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
        !           374: {
        !           375:     int rw = (next >> 9) & 1;
        !           376:     int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
        !           377:     uae_u32 fc = mmu_op30_helper_get_fc(next);
        !           378:     bool write = rw ? false : true;
        !           379:     
        !           380:     if (mmu_op30_invea(opcode))
        !           381:         return true;
        !           382:     if (unused)
        !           383:         return true;
        !           384:     
        !           385: #if 0
        !           386:     write_log (_T("PLOAD%c: Create ATC entry for %08X, FC = %i\n"), write?'W':'R', extra, fc);
        !           387: #endif
        !           388: 
        !           389:     mmu030_flush_atc_page(extra);
        !           390:     mmu030_table_search(extra, fc, write, 0);
        !           391:        return false;
        !           392: }
        !           393: 
        !           394: bool mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
        !           395: {
        !           396:     uae_u16 mode = (next >> 10) & 0x7;
        !           397:     uae_u32 fc_mask = (next >> 5) & 0x7;
        !           398:     uae_u32 fc_base = mmu_op30_helper_get_fc(next);
        !           399:     uae_u32 fc_bits = next & 0x1f;
        !           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:     
        !           420:     switch (mode) {
        !           421:         case 0x1:
        !           422:             if (fc_bits)
        !           423:                 return true;
        !           424:             mmu030_flush_atc_all();
        !           425:             break;
        !           426:         case 0x4:
        !           427:             mmu030_flush_atc_fc(fc_base, fc_mask);
        !           428:             break;
        !           429:         case 0x6:
        !           430:             if (mmu_op30_invea(opcode))
        !           431:                 return true;
        !           432:             mmu030_flush_atc_page_fc(extra, fc_base, fc_mask);
        !           433:             break;
        !           434:             
        !           435:         default:
        !           436:             write_log(_T("PFLUSH ERROR: bad mode! (%i)\n"),mode);
        !           437:             return true;
        !           438:     }
        !           439:        return false;
        !           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) {
        !           451:                 return (regs.dfc);
        !           452:             } else {
        !           453:                 return (regs.sfc);
        !           454:             }
        !           455:         default:
        !           456:             write_log(_T("MMU_OP30 ERROR: bad fc source! (%04X)\n"),next&0x0018);
        !           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;
        !           471: #if MMU030_OP_DBG_MSG
        !           472:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
        !           473: #endif
        !           474:                }
        !           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;
        !           482:        logical_addr &= mmu030.translation.page.imask;
        !           483:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
        !           484:         if (((fc_base&fc_mask)==(mmu030.atc[i].logical.fc&fc_mask)) &&
        !           485:             (mmu030.atc[i].logical.addr == logical_addr) &&
        !           486:             mmu030.atc[i].logical.valid) {
        !           487:             mmu030.atc[i].logical.valid = false;
        !           488: #if MMU030_OP_DBG_MSG
        !           489:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
        !           490: #endif
        !           491:                }
        !           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;
        !           498:        logical_addr &= mmu030.translation.page.imask;
        !           499:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
        !           500:         if ((mmu030.atc[i].logical.addr == logical_addr) &&
        !           501:             mmu030.atc[i].logical.valid) {
        !           502:             mmu030.atc[i].logical.valid = false;
        !           503: #if MMU030_OP_DBG_MSG
        !           504:             write_log(_T("ATC: Flushing %08X\n"), mmu030.atc[i].physical.addr);
        !           505: #endif
        !           506:                }
        !           507:     }
        !           508: }
        !           509: 
        !           510: /* This function flushes all ATC entries */
        !           511: void mmu030_flush_atc_all(void) {
        !           512: #if MMU030_OP_DBG_MSG
        !           513:        write_log(_T("ATC: Flushing all entries\n"));
        !           514: #endif
        !           515:        int i;
        !           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:     
        !           568: #if 0
        !           569:     if ((TT&TT_ENABLE) && !(TT&TT_RWM)) {
        !           570:         write_log(_T("MMU Warning: Transparent translation of read-modify-write cycle is not correctly handled!\n"));
        !           571:     }
        !           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"));
        !           578:     
        !           579:     write_log(_T("TT: transparent translation "));
        !           580:     if (TT&TT_ENABLE) {
        !           581:         write_log(_T("enabled\n"));
        !           582:     } else {
        !           583:         write_log(_T("disabled\n"));
        !           584:         return ret;
        !           585:     }
        !           586: 
        !           587:     write_log(_T("TT: caching %s\n"), (TT&TT_CI) ? _T("inhibited") : _T("enabled"));
        !           588:     write_log(_T("TT: read-modify-write "));
        !           589:     if (TT&TT_RWM) {
        !           590:         write_log(_T("enabled\n"));
        !           591:     } else {
        !           592:         write_log(_T("disabled (%s only)\n"), (TT&TT_RW) ? _T("read") : _T("write"));
        !           593:     }
        !           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"));
        !           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: }
        !           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: }
        !           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: 
        !           681: int mmu030_do_match_lrmw_ttr(uae_u32 tt, TT_info comp, uaecptr addr, uae_u32 fc)
        !           682: {
        !           683:        if ((tt & TT_ENABLE) && (tt & TT_RWM))  {       /* transparent translation enabled */
        !           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:                 
        !           691:                                return TT_OK_MATCH;
        !           692:             }
        !           693:                }
        !           694:        }
        !           695:        return TT_NO_MATCH;
        !           696: }
        !           697: 
        !           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:  *
        !           734:  * ---- ---- ---- ---- ---- ----- ---- xxxx
        !           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: 
        !           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: }
        !           774: 
        !           775: bool mmu030_decode_tc(uae_u32 TC)
        !           776: {
        !           777:     /* Set MMU condition */    
        !           778:     if (TC & TC_ENABLE_TRANSLATION) {
        !           779:                if (!mmu030.enabled)
        !           780:                        mmu030_do_fake_prefetch();
        !           781:         mmu030.enabled = true;
        !           782:     } else {
        !           783:                if (mmu030.enabled) {
        !           784:                        mmu030_do_fake_prefetch();
        !           785:                        write_log(_T("MMU disabled PC=%08x\n"), M68K_GETPC);
        !           786:                }
        !           787:         mmu030.enabled = false;
        !           788:         return false;
        !           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;
        !           805:        regs.mmu_page_size = 1 << mmu030.translation.page.size;
        !           806: 
        !           807:     
        !           808:        write_log(_T("68030 MMU enabled. Page size = %d PC=%08x\n"), regs.mmu_page_size, M68K_GETPC);
        !           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"),
        !           812:                   1<<mmu030.translation.page.size);
        !           813:         Exception(56); /* MMU Configuration Exception */
        !           814:         return true;
        !           815:     }
        !           816:        mmu030.translation.page.mask = regs.mmu_page_size - 1;
        !           817:        mmu030.translation.page.imask = ~mmu030.translation.page.mask;
        !           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:     
        !           843: #if MMU030_REG_DBG_MSG
        !           844:     /* At least one table has to be defined using at least
        !           845:      * 1 bit for the index. At least 2 bits are necessary 
        !           846:      * if there is no second table. If these conditions are
        !           847:      * not met, it will automatically lead to a sum <32
        !           848:      * and cause an exception (see below). */
        !           849:     if (!TI_bits[0]) {
        !           850:         write_log(_T("MMU Configuration Exception: Bad value in TC register! (no first table index defined)\n"));
        !           851:     } else if ((TI_bits[0]<2) && !TI_bits[1]) {
        !           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"));
        !           854:     }
        !           855: #endif
        !           856:     
        !           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 */
        !           863:         return true;
        !           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"));
        !           878:     
        !           879:     for (i = 0; i <= mmu030.translation.last_table; i++) {
        !           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);
        !           881:     }
        !           882: 
        !           883:     write_log(_T("TC: Page:    mask = %08X\n"), mmu030.translation.page.mask);
        !           884:     write_log(_T("\n"));
        !           885: 
        !           886:     write_log(_T("TC: Last Table: %c\n"), table_letter[mmu030.translation.last_table]);
        !           887:     write_log(_T("\n"));
        !           888: #endif
        !           889:        return false;
        !           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))
        !           918: 
        !           919: #define RP_ZERO_BITS 0x0000FFFC /* These bits in upper longword of RP must be 0 */
        !           920: 
        !           921: bool mmu030_decode_rp(uae_u64 RP) {
        !           922:     
        !           923:     uae_u8 descriptor_type = (RP & RP_DESCR_MASK) >> 32;
        !           924:     if (!descriptor_type) { /* If descriptor type is invalid */
        !           925:         write_log(_T("MMU Configuration Exception: Root Pointer is invalid!\n"));
        !           926:         Exception(56); /* MMU Configuration Exception */
        !           927:                return true;
        !           928:     }
        !           929:        return false;
        !           930: 
        !           931: #if MMU030_REG_DBG_MSG /* enable or disable debugging output */
        !           932:     uae_u32 table_limit = (RP & RP_LIMIT_MASK) >> 48;
        !           933:     uae_u32 first_addr = (RP & RP_ADDR_MASK);
        !           934:     
        !           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"));
        !           938:     
        !           939:     write_log(_T("RP: descriptor type = %i "), descriptor_type);
        !           940:     switch (descriptor_type) {
        !           941:         case 0:
        !           942:             write_log(_T("(invalid descriptor)\n"));
        !           943:             break;
        !           944:         case 1:
        !           945:             write_log(_T("(early termination page descriptor)\n"));
        !           946:             break;
        !           947:         case 2:
        !           948:             write_log(_T("(valid 4 byte descriptor)\n"));
        !           949:             break;
        !           950:         case 3:
        !           951:             write_log(_T("(valid 8 byte descriptor)\n"));
        !           952:             break;
        !           953:     }
        !           954:     
        !           955:     write_log(_T("RP: %s limit = %i\n"), (RP&RP_LOWER_MASK) ? _T("lower") : _T("upper"), table_limit);
        !           956:     
        !           957:     write_log(_T("RP: first table address = %08X\n"), first_addr);
        !           958:     write_log(_T("\n"));
        !           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;
        !          1137:         bool super_violation = false;
        !          1138:         bool write_protected = false;
        !          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;
        !          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
        !          1164:         } else {
        !          1165:             descr[0] = (crp_030>>32)&0xFFFFFFFF;
        !          1166:             descr[1] = crp_030&0xFFFFFFFF;
        !          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);
        !          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:
        !          1183:                 write_log(_T("Fatal error: Root pointer is invalid descriptor!\n"));
        !          1184:                 mmu030.status |= MMUSR_INVALID;
        !          1185:                 goto stop_search;
        !          1186:             case DESCR_TYPE_EARLY_TERM:
        !          1187:                 write_log(_T("Root pointer is early termination page descriptor.\n"));
        !          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) {
        !          1202:             write_log(_T("Function code lookup enabled, FC = %i\n"), fc);
        !          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 */
        !          1207:             write_log(_T("Table FCL at %08X: index = %i, "),table_addr,table_index);
        !          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]);
        !          1215: #if MMU030_REG_DBG_MSG
        !          1216:                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
        !          1217: #endif
        !          1218:             } else {
        !          1219:                 descr[0] = phys_get_long(descr_addr[descr_num]);
        !          1220:                 descr[1] = phys_get_long(descr_addr[descr_num]+4);
        !          1221: #if MMU030_REG_DBG_MSG
        !          1222:                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
        !          1223: #endif
        !          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:
        !          1232:                     write_log(_T("Invalid descriptor!\n"));
        !          1233:                     /* stop table walk */
        !          1234:                     mmu030.status |= MMUSR_INVALID;
        !          1235:                     goto stop_search;
        !          1236:                 case DESCR_TYPE_EARLY_TERM:
        !          1237: #if MMU030_REG_DBG_MSG
        !          1238:                     write_log(_T("Early termination page descriptor!\n"));
        !          1239: #endif
        !          1240:                                        early_termination = true;
        !          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 */
        !          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:                 
        !          1263:                 /* Set the updated bit */
        !          1264:                 if (!level && !(descr[0]&DESCR_U) && !super_violation) {
        !          1265:                     descr[0] |= DESCR_U;
        !          1266:                     phys_put_long(descr_addr[descr_num], descr[0]);
        !          1267:                 }
        !          1268:                 
        !          1269:                 /* Update status bits */
        !          1270:                 mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
        !          1271:                 mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;                
        !          1272: 
        !          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;
        !          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
        !          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);
        !          1292: #if MMU030_REG_DBG_MSG
        !          1293:                     write_log(_T("limit violation (lower limit %i)\n"),limit);
        !          1294: #endif
        !          1295:                     goto stop_search;
        !          1296:                 }
        !          1297:                 if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
        !          1298:                     mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
        !          1299: #if MMU030_REG_DBG_MSG
        !          1300:                     write_log(_T("limit violation (upper limit %i)\n"),limit);
        !          1301: #endif
        !          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]);
        !          1312: #if MMU030_REG_DBG_MSG
        !          1313:                 write_log(_T("Next descriptor: %08X\n"),descr[0]);
        !          1314: #endif
        !          1315:             } else {
        !          1316:                 descr[0] = phys_get_long(descr_addr[descr_num]);
        !          1317:                 descr[1] = phys_get_long(descr_addr[descr_num]+4);
        !          1318: #if MMU030_REG_DBG_MSG
        !          1319:                 write_log(_T("Next descriptor: %08X%08X\n"),descr[0],descr[1]);
        !          1320: #endif
        !          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:
        !          1329: #if MMU030_REG_DBG_MSG
        !          1330:                     write_log(_T("Invalid descriptor!\n"));
        !          1331: #endif
        !          1332:                                        /* stop table walk */
        !          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) {
        !          1338: #if MMU030_REG_DBG_MSG
        !          1339:                         write_log(_T("Early termination page descriptor!\n"));
        !          1340: #endif
        !          1341:                                                early_termination = true;
        !          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;
        !          1363: #if MMU030_REG_DBG_MSG
        !          1364:         write_log(_T("Page indirect descriptor at %08X: "),indirect_addr);
        !          1365: #endif
        !          1366: 
        !          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]);
        !          1373: #if MMU030_REG_DBG_MSG
        !          1374:             write_log(_T("descr = %08X\n"),descr[0]);
        !          1375: #endif
        !          1376:                } else {
        !          1377:             descr[0] = phys_get_long(descr_addr[descr_num]);
        !          1378:             descr[1] = phys_get_long(descr_addr[descr_num]+4);
        !          1379: #if MMU030_REG_DBG_MSG
        !          1380:             write_log(_T("descr = %08X%08X"),descr[0],descr[1]);
        !          1381: #endif
        !          1382:                }
        !          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 */
        !          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) {
        !          1405:                 /* set modified bit */
        !          1406:                 if (!(descr[0]&DESCR_M) && write && !write_protected) {
        !          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:             
        !          1421:             /* update status bits */
        !          1422:             mmu030.status |= super_violation ? MMUSR_SUPER_VIOLATION : 0;
        !          1423:             mmu030.status |= write_protected ? MMUSR_WRITE_PROTECTED : 0;
        !          1424: 
        !          1425:             /* check if caching is inhibited */
        !          1426:             cache_inhibit = descr[0]&DESCR_CI ? true : false;
        !          1427:             
        !          1428:             /* check for the modified bit and set it in the status register */
        !          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);
        !          1443: #if MMU030_REG_DBG_MSG
        !          1444:                         write_log(_T("Limit violation (lower limit %i)\n"),limit);
        !          1445: #endif
        !          1446:                         goto stop_search;
        !          1447:                     }
        !          1448:                     if (!(descr[0]&DESCR_LOWER_MASK) && (table_index>limit)) {
        !          1449:                         mmu030.status |= (MMUSR_LIMIT_VIOLATION|MMUSR_INVALID);
        !          1450: #if MMU030_REG_DBG_MSG
        !          1451:                         write_log(_T("Limit violation (upper limit %i)\n"),limit);
        !          1452: #endif
        !          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 */
        !          1459:             /* TODO: They should be added via "unsigned addition". How to? */
        !          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;
        !          1465: #if MMU030_REG_DBG_MSG
        !          1466:             write_log(_T("Logical address unused bits: %08X (mask = %08X)\n"),
        !          1467:                       page_addr,unused_fields_mask);
        !          1468: #endif
        !          1469:                }
        !          1470: 
        !          1471:         /* Get page address */
        !          1472:         addr_position = (descr_size==4) ? 0 : 1;
        !          1473:         page_addr += (descr[addr_position]&DESCR_PD_ADDR_MASK);
        !          1474: #if MMU030_REG_DBG_MSG
        !          1475:         write_log(_T("Page at %08X\n"),page_addr);
        !          1476: #endif // MMU030_REG_DBG_MSG
        !          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);
        !          1487:         write_log(_T("MMU: Bus error while %s descriptor!\n"),
        !          1488:                   bBusErrorReadWrite?_T("reading"):_T("writing"));
        !          1489:     } ENDTRY
        !          1490: 
        !          1491:     /* check if we have to handle ptest */
        !          1492:     if (level) {
        !          1493:         /* Note: wp, m and sv bits are undefined if the invalid bit is set */
        !          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:         }
        !          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: 
        !          1524:     mmu030_atc_handle_history_bit(i);
        !          1525:     
        !          1526:     /* Create ATC entry */
        !          1527:     mmu030.atc[i].logical.addr = addr & mmu030.translation.page.imask; /* delete page index bits */
        !          1528:     mmu030.atc[i].logical.fc = fc;
        !          1529:     mmu030.atc[i].logical.valid = true;
        !          1530:     mmu030.atc[i].physical.addr = page_addr & mmu030.translation.page.imask; /* delete page index bits */
        !          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;
        !          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;
        !          1539: 
        !          1540: #if MMU030_ATC_DBG_MSG    
        !          1541:     write_log(_T("ATC create entry(%i): logical = %08X, physical = %08X, FC = %i\n"), i,
        !          1542:               mmu030.atc[i].logical.addr, mmu030.atc[i].physical.addr,
        !          1543:               mmu030.atc[i].logical.fc);
        !          1544:     write_log(_T("ATC create entry(%i): B = %i, CI = %i, WP = %i, M = %i\n"), i,
        !          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);
        !          1549: #endif // MMU030_ATC_DBG_MSG
        !          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;
        !          1578:     /* Note: write protect and modified bits are undefined if the invalid bit is set */
        !          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
        !          1596:  * least recently used entries. They are replaced if the cache is full.
        !          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: 
        !          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);
        !          1662: }
        !          1663: 
        !          1664: void mmu030_put_long_atc(uaecptr addr, uae_u32 val, int l, uae_u32 fc) {
        !          1665:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1666:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1667:     
        !          1668:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1669: #if MMU030_ATC_DBG_MSG
        !          1670:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lput %08X)\n"),
        !          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) {
        !          1676:         mmu030_page_fault(addr, false, MMU030_SSW_SIZE_L, fc);
        !          1677:         return;
        !          1678:     }
        !          1679: 
        !          1680:     phys_put_long(physical_addr, val);
        !          1681: }
        !          1682: 
        !          1683: void mmu030_put_word_atc(uaecptr addr, uae_u16 val, int l, uae_u32 fc) {
        !          1684:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1685:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1686:     
        !          1687:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1688: #if MMU030_ATC_DBG_MSG
        !          1689:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wput %04X)\n"),
        !          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) {
        !          1695:         mmu030_page_fault(addr, false, MMU030_SSW_SIZE_W, fc);
        !          1696:         return;
        !          1697:     }
        !          1698: 
        !          1699:     phys_put_word(physical_addr, val);
        !          1700: }
        !          1701: 
        !          1702: void mmu030_put_byte_atc(uaecptr addr, uae_u8 val, int l, uae_u32 fc) {
        !          1703:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1704:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1705:     
        !          1706:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1707: #if MMU030_ATC_DBG_MSG
        !          1708:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bput %02X)\n"),
        !          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) {
        !          1714:         mmu030_page_fault(addr, false, MMU030_SSW_SIZE_B, fc);
        !          1715:         return;
        !          1716:     }
        !          1717: 
        !          1718:     phys_put_byte(physical_addr, val);
        !          1719: }
        !          1720: 
        !          1721: uae_u32 mmu030_get_long_atc(uaecptr addr, int l, uae_u32 fc) {
        !          1722:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1723:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1724:     
        !          1725:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1726: #if MMU030_ATC_DBG_MSG
        !          1727:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (lget %08X)\n"), l,
        !          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) {
        !          1733:         mmu030_page_fault(addr, true, MMU030_SSW_SIZE_L, fc);
        !          1734:         return 0;
        !          1735:     }
        !          1736: 
        !          1737:     return phys_get_long(physical_addr);
        !          1738: }
        !          1739: 
        !          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: 
        !          1759: uae_u16 mmu030_get_word_atc(uaecptr addr, int l, uae_u32 fc) {
        !          1760:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1761:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1762:     
        !          1763:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1764: #if MMU030_ATC_DBG_MSG
        !          1765:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (wget %04X)\n"), l,
        !          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) {
        !          1771:         mmu030_page_fault(addr, true, MMU030_SSW_SIZE_W, fc);
        !          1772:         return 0;
        !          1773:     }
        !          1774:     
        !          1775:     return phys_get_word(physical_addr);
        !          1776: }
        !          1777: 
        !          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: 
        !          1797: uae_u8 mmu030_get_byte_atc(uaecptr addr, int l, uae_u32 fc) {
        !          1798:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1799:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1800:     
        !          1801:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          1802: #if MMU030_ATC_DBG_MSG
        !          1803:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
        !          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) {
        !          1809:         mmu030_page_fault(addr, true, MMU030_SSW_SIZE_B, fc);
        !          1810:         return 0;
        !          1811:     }
        !          1812: 
        !          1813:     return phys_get_byte(physical_addr);
        !          1814: }
        !          1815: 
        !          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: }
        !          1840: uae_u32 mmu030_get_atc_generic(uaecptr addr, int l, uae_u32 fc, int size, int flags, bool checkwrite) {
        !          1841:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          1842:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1843:     
        !          1844:     uae_u32 physical_addr = mmu030.atc[l].physical.addr & addr_mask;
        !          1845: #if MMU030_ATC_DBG_MSG
        !          1846:     write_log(_T("ATC match(%i): page addr = %08X, index = %08X (bget %02X)\n"), l,
        !          1847:               physical_addr, page_index, phys_get_byte(physical_addr+page_index));
        !          1848: #endif
        !          1849:     physical_addr += page_index;
        !          1850:     
        !          1851:        if (mmu030.atc[l].physical.bus_error || (checkwrite && mmu030.atc[l].physical.write_protect)) {
        !          1852:         mmu030_page_fault(addr, true, flags, fc);
        !          1853:         return 0;
        !          1854:     }
        !          1855:        if (size == sz_byte)
        !          1856:                return phys_get_byte(physical_addr);
        !          1857:        else if (size == sz_word)
        !          1858:                return phys_get_word(physical_addr);
        !          1859:        return phys_get_long(physical_addr);
        !          1860: }
        !          1861: 
        !          1862: 
        !          1863: /* This function checks if a certain logical address is in the ATC 
        !          1864:  * by comparing the logical address and function code to the values
        !          1865:  * stored in the ATC entries. If a matching entry is found it sets
        !          1866:  * the history bit and returns the cache index of the entry. */
        !          1867: int mmu030_logical_is_in_atc(uaecptr addr, uae_u32 fc, bool write) {
        !          1868:     uaecptr logical_addr = 0;
        !          1869:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          1870:        uae_u32 maddr = addr & addr_mask;
        !          1871:     int offset = (maddr >> mmu030.translation.page.size) & 0x1f;
        !          1872: 
        !          1873:     int i, index;
        !          1874:        index = atcindextable[offset];
        !          1875:     for (i=0; i<ATC030_NUM_ENTRIES; i++) {
        !          1876:         logical_addr = mmu030.atc[index].logical.addr;
        !          1877:         /* If actual address matches address in ATC */
        !          1878:         if (maddr==(logical_addr&addr_mask) &&
        !          1879:             (mmu030.atc[index].logical.fc==fc) &&
        !          1880:             mmu030.atc[index].logical.valid) {
        !          1881:             /* If access is valid write and M bit is not set, invalidate entry
        !          1882:              * else return index */
        !          1883:             if (!write || mmu030.atc[index].physical.modified ||
        !          1884:                 mmu030.atc[index].physical.write_protect ||
        !          1885:                 mmu030.atc[index].physical.bus_error) {
        !          1886:                 /* Maintain history bit */
        !          1887:                                        mmu030_atc_handle_history_bit(index);
        !          1888:                                        atcindextable[offset] = index;
        !          1889:                                        return index;
        !          1890:                                } else {
        !          1891:                                        mmu030.atc[index].logical.valid = false;
        !          1892:                                }
        !          1893:                }
        !          1894:                index++;
        !          1895:                if (index >= ATC030_NUM_ENTRIES)
        !          1896:                        index = 0;
        !          1897:     }
        !          1898:     return -1;
        !          1899: }
        !          1900: 
        !          1901: void mmu030_atc_handle_history_bit(int entry_num) {
        !          1902:     int j;
        !          1903:     mmu030.atc[entry_num].mru = 1;
        !          1904:     for (j=0; j<ATC030_NUM_ENTRIES; j++) {
        !          1905:         if (!mmu030.atc[j].mru)
        !          1906:             break;
        !          1907:     }
        !          1908:     /* If there are no more zero-bits, reset all */
        !          1909:     if (j==ATC030_NUM_ENTRIES) {
        !          1910:         for (j=0; j<ATC030_NUM_ENTRIES; j++) {
        !          1911:             mmu030.atc[j].mru = 0;
        !          1912:         }
        !          1913:         mmu030.atc[entry_num].mru = 1;
        !          1914: #if MMU030_ATC_DBG_MSG
        !          1915:         write_log(_T("ATC: No more history zero-bits. Reset all.\n"));
        !          1916: #endif
        !          1917:        }
        !          1918: }
        !          1919: 
        !          1920: 
        !          1921: /* Memory access functions:
        !          1922:  * If the address matches one of the transparent translation registers
        !          1923:  * use it directly as physical address, else check ATC for the
        !          1924:  * logical address. If the logical address is not resident in the ATC
        !          1925:  * create a new ATC entry and then look up the physical address. 
        !          1926:  */
        !          1927: 
        !          1928: void mmu030_put_long(uaecptr addr, uae_u32 val, uae_u32 fc) {
        !          1929:     
        !          1930:     //                                      addr,fc,write
        !          1931:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
        !          1932:         phys_put_long(addr,val);
        !          1933:         return;
        !          1934:     }
        !          1935: 
        !          1936:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          1937: 
        !          1938:     if (atc_line_num>=0) {
        !          1939:         mmu030_put_long_atc(addr, val, atc_line_num, fc);
        !          1940:     } else {
        !          1941:         mmu030_table_search(addr,fc,true,0);
        !          1942:         mmu030_put_long_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
        !          1943:     }
        !          1944: }
        !          1945: 
        !          1946: void mmu030_put_word(uaecptr addr, uae_u16 val, uae_u32 fc) {
        !          1947:     
        !          1948:     //                                      addr,fc,write
        !          1949:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
        !          1950:         phys_put_word(addr,val);
        !          1951:         return;
        !          1952:     }
        !          1953:     
        !          1954:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          1955:     
        !          1956:     if (atc_line_num>=0) {
        !          1957:         mmu030_put_word_atc(addr, val, atc_line_num, fc);
        !          1958:     } else {
        !          1959:         mmu030_table_search(addr, fc, true, 0);
        !          1960:         mmu030_put_word_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
        !          1961:     }
        !          1962: }
        !          1963: 
        !          1964: void mmu030_put_byte(uaecptr addr, uae_u8 val, uae_u32 fc) {
        !          1965:     
        !          1966:     //                                      addr,fc,write
        !          1967:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
        !          1968:         phys_put_byte(addr,val);
        !          1969:         return;
        !          1970:     }
        !          1971:     
        !          1972:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          1973: 
        !          1974:     if (atc_line_num>=0) {
        !          1975:         mmu030_put_byte_atc(addr, val, atc_line_num, fc);
        !          1976:     } else {
        !          1977:         mmu030_table_search(addr, fc, true, 0);
        !          1978:         mmu030_put_byte_atc(addr, val, mmu030_logical_is_in_atc(addr,fc,true), fc);
        !          1979:     }
        !          1980: }
        !          1981: 
        !          1982: uae_u32 mmu030_get_ilong(uaecptr addr, uae_u32 fc) {
        !          1983:     
        !          1984:     //                                        addr,fc,write
        !          1985:     if ((fc == 7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          1986:         return phys_get_long(addr);
        !          1987:     }
        !          1988:     
        !          1989:        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          1990: 
        !          1991:        if (atc_line_num >= 0) {
        !          1992:                return mmu030_get_ilong_atc(addr, atc_line_num, fc);
        !          1993:        }
        !          1994:        else {
        !          1995:                mmu030_table_search(addr, fc, false, 0);
        !          1996:                return mmu030_get_ilong_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
        !          1997:        }
        !          1998: }
        !          1999: uae_u32 mmu030_get_long(uaecptr addr, uae_u32 fc) {
        !          2000:     
        !          2001:     //                                      addr,fc,write
        !          2002:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          2003:         return phys_get_long(addr);
        !          2004:     }
        !          2005:     
        !          2006:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2007: 
        !          2008:     if (atc_line_num>=0) {
        !          2009:         return mmu030_get_long_atc(addr, atc_line_num, fc);
        !          2010:     } else {
        !          2011:         mmu030_table_search(addr, fc, false, 0);
        !          2012:         return mmu030_get_long_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
        !          2013:     }
        !          2014: }
        !          2015: 
        !          2016: uae_u16 mmu030_get_iword(uaecptr addr, uae_u32 fc) {
        !          2017:     
        !          2018:     //                                        addr,fc,write
        !          2019:     if ((fc == 7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          2020:         return phys_get_word(addr);
        !          2021:     }
        !          2022:     
        !          2023:        int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2024: 
        !          2025:        if (atc_line_num >= 0) {
        !          2026:                return mmu030_get_iword_atc(addr, atc_line_num, fc);
        !          2027:        } else {
        !          2028:                mmu030_table_search(addr, fc, false, 0);
        !          2029:                return mmu030_get_iword_atc(addr, mmu030_logical_is_in_atc(addr, fc, false), fc);
        !          2030:        }
        !          2031: }
        !          2032: uae_u16 mmu030_get_word(uaecptr addr, uae_u32 fc) {
        !          2033:     
        !          2034:     //                                      addr,fc,write
        !          2035:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          2036:         return phys_get_word(addr);
        !          2037:     }
        !          2038:     
        !          2039:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2040: 
        !          2041:     if (atc_line_num>=0) {
        !          2042:         return mmu030_get_word_atc(addr, atc_line_num, fc);
        !          2043:     } else {
        !          2044:         mmu030_table_search(addr, fc, false, 0);
        !          2045:         return mmu030_get_word_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
        !          2046:     }
        !          2047: }
        !          2048: 
        !          2049: uae_u8 mmu030_get_byte(uaecptr addr, uae_u32 fc) {
        !          2050:     
        !          2051:     //                                      addr,fc,write
        !          2052:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          2053:         return phys_get_byte(addr);
        !          2054:     }
        !          2055:     
        !          2056:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2057: 
        !          2058:     if (atc_line_num>=0) {
        !          2059:         return mmu030_get_byte_atc(addr, atc_line_num, fc);
        !          2060:     } else {
        !          2061:         mmu030_table_search(addr, fc, false, 0);
        !          2062:         return mmu030_get_byte_atc(addr, mmu030_logical_is_in_atc(addr,fc,false), fc);
        !          2063:     }
        !          2064: }
        !          2065: 
        !          2066: 
        !          2067: /* Not commonly used access function */
        !          2068: void mmu030_put_generic(uaecptr addr, uae_u32 val, uae_u32 fc, int size, int accesssize, int flags) {
        !          2069:     
        !          2070:     //                                      addr,fc,write
        !          2071:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,true)) || (!mmu030.enabled)) {
        !          2072:         if (size == sz_byte)
        !          2073:             phys_put_byte(addr, val);
        !          2074:         else if (size == sz_word)
        !          2075:             phys_put_word(addr, val);
        !          2076:         else
        !          2077:             phys_put_long(addr, val);
        !          2078:         return;
        !          2079:     }
        !          2080:     
        !          2081:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          2082:     if (atc_line_num>=0) {
        !          2083:         mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
        !          2084:     } else {
        !          2085:         mmu030_table_search(addr, fc, true, 0);
        !          2086:                atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          2087:                if (accesssize == sz_byte)
        !          2088:                        flags |= MMU030_SSW_SIZE_B;
        !          2089:                else if (accesssize == sz_word)
        !          2090:                        flags |= MMU030_SSW_SIZE_W;
        !          2091:         mmu030_put_atc_generic(addr, val, atc_line_num, fc, size, flags);
        !          2092:     }
        !          2093: }
        !          2094: static uae_u32 mmu030_get_generic_lrmw(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
        !          2095:     
        !          2096:     //                                           addr,fc,write
        !          2097:     if ((fc==7) || (mmu030_match_lrmw_ttr_access(addr,fc)) || (!mmu030.enabled)) {
        !          2098:         if (size == sz_byte)
        !          2099:             return phys_get_byte(addr);
        !          2100:         else if (size == sz_word)
        !          2101:             return phys_get_word(addr);
        !          2102:         return phys_get_long(addr);
        !          2103:     }
        !          2104:     
        !          2105:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          2106:     if (atc_line_num>=0) {
        !          2107:         return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
        !          2108:     } else {
        !          2109:         mmu030_table_search(addr, fc, true, 0);
        !          2110:                atc_line_num = mmu030_logical_is_in_atc(addr, fc, true);
        !          2111:                if (accesssize == sz_byte)
        !          2112:                        flags |= MMU030_SSW_SIZE_B;
        !          2113:                else if (accesssize == sz_word)
        !          2114:                        flags |= MMU030_SSW_SIZE_W;
        !          2115:         return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, true);
        !          2116:     }
        !          2117: }
        !          2118: uae_u32 mmu030_get_generic(uaecptr addr, uae_u32 fc, int size, int accesssize, int flags) {
        !          2119:     if (flags & MMU030_SSW_RM) {
        !          2120:         return mmu030_get_generic_lrmw(addr, fc, size, accesssize, flags);
        !          2121:     }
        !          2122:     //                                      addr,fc,write
        !          2123:     if ((fc==7) || (mmu030_match_ttr_access(addr,fc,false)) || (!mmu030.enabled)) {
        !          2124:         if (size == sz_byte)
        !          2125:             return phys_get_byte(addr);
        !          2126:         else if (size == sz_word)
        !          2127:             return phys_get_word(addr);
        !          2128:         return phys_get_long(addr);
        !          2129:     }
        !          2130:     
        !          2131:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2132:     if (atc_line_num>=0) {
        !          2133:         return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
        !          2134:     } else {
        !          2135:         mmu030_table_search(addr, fc, false, 0);
        !          2136:                atc_line_num = mmu030_logical_is_in_atc(addr, fc, false);
        !          2137:                if (accesssize == sz_byte)
        !          2138:                        flags |= MMU030_SSW_SIZE_B;
        !          2139:                else if (accesssize == sz_word)
        !          2140:                        flags |= MMU030_SSW_SIZE_W;
        !          2141:         return mmu030_get_atc_generic(addr, atc_line_num, fc, size, flags, false);
        !          2142:     }
        !          2143: }
        !          2144: 
        !          2145: 
        !          2146: /* Locked RMW is rarely used */
        !          2147: uae_u32 uae_mmu030_get_lrmw(uaecptr addr, int size)
        !          2148: {
        !          2149:     uae_u32 fc = (regs.s ? 4 : 0) | 1;
        !          2150:        if (size == sz_byte) {
        !          2151:                return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
        !          2152:        } else if (size == sz_word) {
        !          2153:                if (unlikely(is_unaligned(addr, 2)))
        !          2154:                        return mmu030_get_word_unaligned(addr, fc, MMU030_SSW_RM);
        !          2155:                else
        !          2156:                        return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
        !          2157:        } else {
        !          2158:                if (unlikely(is_unaligned(addr, 4)))
        !          2159:                        return mmu030_get_long_unaligned(addr, fc, MMU030_SSW_RM);
        !          2160:                else
        !          2161:                        return mmu030_get_generic(addr, fc, size, size, MMU030_SSW_RM);
        !          2162:        }
        !          2163: }
        !          2164: void uae_mmu030_put_lrmw(uaecptr addr, uae_u32 val, int size)
        !          2165: {
        !          2166:     uae_u32 fc = (regs.s ? 4 : 0) | 1;
        !          2167:        if (size == sz_byte) {
        !          2168:                mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
        !          2169:        } else if (size == sz_word) {
        !          2170:                if (unlikely(is_unaligned(addr, 2)))
        !          2171:                        mmu030_put_word_unaligned(addr, val, fc, MMU030_SSW_RM);
        !          2172:                else
        !          2173:                        mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
        !          2174:        } else {
        !          2175:                if (unlikely(is_unaligned(addr, 4)))
        !          2176:                        mmu030_put_long_unaligned(addr, val, fc, MMU030_SSW_RM);
        !          2177:                else
        !          2178:                        mmu030_put_generic(addr, val, fc, size, size, MMU030_SSW_RM);
        !          2179:        }
        !          2180: }
        !          2181: uae_u16 REGPARAM2 mmu030_get_word_unaligned(uaecptr addr, uae_u32 fc, int flags)
        !          2182: {
        !          2183:        uae_u16 res;
        !          2184:     
        !          2185:        res = (uae_u16)mmu030_get_generic(addr, fc, sz_byte, sz_word, flags) << 8;
        !          2186:        SAVE_EXCEPTION;
        !          2187:        TRY(prb) {
        !          2188:                res |= mmu030_get_generic(addr + 1, fc, sz_byte, sz_word, flags);
        !          2189:                RESTORE_EXCEPTION;
        !          2190:        }
        !          2191:        CATCH(prb) {
        !          2192:                RESTORE_EXCEPTION;
        !          2193:                THROW_AGAIN(prb);
        !          2194:        } ENDTRY
        !          2195:        return res;
        !          2196: }
        !          2197: 
        !          2198: uae_u32 REGPARAM2 mmu030_get_ilong_unaligned(uaecptr addr, uae_u32 fc, int flags)
        !          2199: {
        !          2200:        uae_u32 res;
        !          2201: 
        !          2202:        res = (uae_u32)mmu030_get_iword(addr, fc) << 16;
        !          2203:        SAVE_EXCEPTION;
        !          2204:        TRY(prb) {
        !          2205:                res |= mmu030_get_iword(addr + 2, fc);
        !          2206:                RESTORE_EXCEPTION;
        !          2207:        }
        !          2208:        CATCH(prb) {
        !          2209:                RESTORE_EXCEPTION;
        !          2210:                THROW_AGAIN(prb);
        !          2211:        } ENDTRY
        !          2212:        return res;
        !          2213: }
        !          2214: 
        !          2215: uae_u32 REGPARAM2 mmu030_get_long_unaligned(uaecptr addr, uae_u32 fc, int flags)
        !          2216: {
        !          2217:        uae_u32 res;
        !          2218:     
        !          2219:        if (likely(!(addr & 1))) {
        !          2220:                res = (uae_u32)mmu030_get_generic(addr, fc, sz_word, sz_long, flags) << 16;
        !          2221:                SAVE_EXCEPTION;
        !          2222:                TRY(prb) {
        !          2223:                        res |= mmu030_get_generic(addr + 2, fc, sz_word, sz_long, flags);
        !          2224:                        RESTORE_EXCEPTION;
        !          2225:                }
        !          2226:                CATCH(prb) {
        !          2227:                        RESTORE_EXCEPTION;
        !          2228:                        THROW_AGAIN(prb);
        !          2229:                } ENDTRY
        !          2230:        } else {
        !          2231:                res = (uae_u32)mmu030_get_generic(addr, fc, sz_byte, sz_long, flags) << 8;
        !          2232:                SAVE_EXCEPTION;
        !          2233:                TRY(prb) {
        !          2234:                        res = (res | mmu030_get_generic(addr + 1, fc, sz_byte, sz_long, flags)) << 8;
        !          2235:                        res = (res | mmu030_get_generic(addr + 2, fc, sz_byte, sz_long, flags)) << 8;
        !          2236:                        res |= mmu030_get_generic(addr + 3, fc, sz_byte, sz_long, flags);
        !          2237:                        RESTORE_EXCEPTION;
        !          2238:                }
        !          2239:                CATCH(prb) {
        !          2240:                        RESTORE_EXCEPTION;
        !          2241:                        THROW_AGAIN(prb);
        !          2242:                } ENDTRY
        !          2243:        }
        !          2244:        return res;
        !          2245: }
        !          2246: 
        !          2247: 
        !          2248: void REGPARAM2 mmu030_put_long_unaligned(uaecptr addr, uae_u32 val, uae_u32 fc, int flags)
        !          2249: {
        !          2250:        SAVE_EXCEPTION;
        !          2251:        TRY(prb) {
        !          2252:                if (likely(!(addr & 1))) {
        !          2253:                        mmu030_put_generic(addr, val >> 16, fc, sz_word, sz_long, flags);
        !          2254:                        mmu030_put_generic(addr + 2, val, fc, sz_word, sz_long, flags);
        !          2255:                } else {
        !          2256:                        mmu030_put_generic(addr, val >> 24, fc, sz_byte, sz_long, flags);
        !          2257:                        mmu030_put_generic(addr + 1, val >> 16, fc, sz_byte, sz_long, flags);
        !          2258:                        mmu030_put_generic(addr + 2, val >> 8, fc, sz_byte, sz_long, flags);
        !          2259:                        mmu030_put_generic(addr + 3, val, fc, sz_byte, sz_long, flags);
        !          2260:                }
        !          2261:                RESTORE_EXCEPTION;
        !          2262:        }
        !          2263:        CATCH(prb) {
        !          2264:                RESTORE_EXCEPTION;
        !          2265:                regs.wb3_data = val;
        !          2266:                THROW_AGAIN(prb);
        !          2267:        } ENDTRY
        !          2268: }
        !          2269: 
        !          2270: void REGPARAM2 mmu030_put_word_unaligned(uaecptr addr, uae_u16 val, uae_u32 fc, int flags)
        !          2271: {
        !          2272:        SAVE_EXCEPTION;
        !          2273:        TRY(prb) {
        !          2274:                mmu030_put_generic(addr, val >> 8, fc, sz_byte, sz_word, flags);
        !          2275:                mmu030_put_generic(addr + 1, val, fc, sz_byte, sz_word, flags);
        !          2276:                RESTORE_EXCEPTION;
        !          2277:        }
        !          2278:        CATCH(prb) {
        !          2279:                RESTORE_EXCEPTION;
        !          2280:                regs.wb3_data = val;
        !          2281:                THROW_AGAIN(prb);
        !          2282:        } ENDTRY
        !          2283: }
        !          2284: 
        !          2285: 
        !          2286: /* Used by debugger */
        !          2287: static uaecptr mmu030_get_addr_atc(uaecptr addr, int l, uae_u32 fc, bool write) {
        !          2288:     uae_u32 page_index = addr & mmu030.translation.page.mask;
        !          2289:     uae_u32 addr_mask = mmu030.translation.page.imask;
        !          2290:     
        !          2291:     uae_u32 physical_addr = mmu030.atc[l].physical.addr&addr_mask;
        !          2292:     physical_addr += page_index;
        !          2293:     
        !          2294:        if (mmu030.atc[l].physical.bus_error || (write && mmu030.atc[l].physical.write_protect)) {
        !          2295:         mmu030_page_fault(addr, write == 0, MMU030_SSW_SIZE_B, fc);
        !          2296:         return 0;
        !          2297:     }
        !          2298: 
        !          2299:     return physical_addr;
        !          2300: }
        !          2301: uaecptr mmu030_translate(uaecptr addr, bool super, bool data, bool write)
        !          2302: {
        !          2303:     int fc = (super ? 4 : 0) | (data ? 1 : 2);
        !          2304:     if ((fc==7) || (mmu030_match_ttr(addr,fc,write)&TT_OK_MATCH) || (!mmu030.enabled)) {
        !          2305:         return addr;
        !          2306:     }
        !          2307:     int atc_line_num = mmu030_logical_is_in_atc(addr, fc, write);
        !          2308: 
        !          2309:     if (atc_line_num>=0) {
        !          2310:         return mmu030_get_addr_atc(addr, atc_line_num, fc, write);
        !          2311:     } else {
        !          2312:         mmu030_table_search(addr, fc, false, 0);
        !          2313:         return mmu030_get_addr_atc(addr, mmu030_logical_is_in_atc(addr,fc,write), fc, write);
        !          2314:     }
        !          2315: }
        !          2316: 
        !          2317: /* MMU Reset */
        !          2318: void mmu030_reset(int hardreset)
        !          2319: {
        !          2320:     /* A CPU reset causes the E-bits of TC and TT registers to be zeroed. */
        !          2321:     mmu030.enabled = false;
        !          2322:        regs.mmu_page_size = 0;
        !          2323:        tc_030 &= ~TC_ENABLE_TRANSLATION;
        !          2324:        tt0_030 &= ~TT_ENABLE;
        !          2325:        tt1_030 &= ~TT_ENABLE;
        !          2326:        if (hardreset) {
        !          2327:                srp_030 = crp_030 = 0;
        !          2328:                tt0_030 = tt1_030 = tc_030 = 0;
        !          2329:         mmusr_030 = 0;
        !          2330:         mmu030_flush_atc_all();
        !          2331:        }
        !          2332:        mmu030_set_funcs();
        !          2333: }
        !          2334: 
        !          2335: void mmu030_set_funcs(void)
        !          2336: {
        !          2337:        if (currprefs.mmu_model != 68030)
        !          2338:                return;
        !          2339: }
        !          2340: 
        !          2341: 
        !          2342: void m68k_do_rte_mmu030 (uaecptr a7)
        !          2343: {
        !          2344:        // Restore access error exception state
        !          2345: 
        !          2346:        uae_u16 format = get_word_mmu030 (a7 + 6);
        !          2347:        uae_u16 frame = format >> 12;
        !          2348:        uae_u16 ssw = get_word_mmu030 (a7 + 10);
        !          2349: 
        !          2350:        // Fetch last word, real CPU does it to allow OS bus handler to map
        !          2351:        // the page if frame crosses pages and following page is not resident.
        !          2352:        if (frame == 0xb)
        !          2353:                get_word_mmu030(a7 + 92 - 2);
        !          2354:        else
        !          2355:                get_word_mmu030(a7 + 32 - 2);
        !          2356: 
        !          2357:        // Internal register, our opcode storage area
        !          2358:        mmu030_opcode = get_long_mmu030 (a7 + 0x14);
        !          2359:        // Misc state data
        !          2360:        mmu030_state[0] = get_word_mmu030 (a7 + 0x30);
        !          2361:        mmu030_state[1] = get_word_mmu030 (a7 + 0x32);
        !          2362:        mmu030_state[2] = get_word_mmu030 (a7 + 0x34);
        !          2363:        mmu030_disp_store[0] = get_long_mmu030 (a7 + 0x1c);
        !          2364:        mmu030_disp_store[1] = get_long_mmu030 (a7 + 0x1c + 4);
        !          2365:        if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
        !          2366:                mmu030_fmovem_store[0] = get_long_mmu030 (a7 + 0x5c - (7 + 1) * 4);
        !          2367:                mmu030_fmovem_store[1] = get_long_mmu030 (a7 + 0x5c - (8 + 1) * 4);
        !          2368:        }
        !          2369:        // Rerun "mmu030_opcode" using restored state.
        !          2370:        mmu030_retry = true;
        !          2371: 
        !          2372:        if (frame == 0xb) {
        !          2373:                uae_u16 idxsize = get_word_mmu030 (a7 + 0x36);
        !          2374:                int i;
        !          2375:                for (i = 0; i < idxsize + 1; i++) {
        !          2376:                        mmu030_ad[i].done = i < idxsize;
        !          2377:                        mmu030_ad[i].val = get_long_mmu030 (a7 + 0x5c - (i + 1) * 4);
        !          2378:                }
        !          2379:                mmu030_ad[idxsize + 1].done = false;
        !          2380:                // did we have data fault but DF bit cleared?
        !          2381:                if (ssw & (MMU030_SSW_DF << 1) && !(ssw & MMU030_SSW_DF)) {
        !          2382:                        // DF not set: mark access as done
        !          2383:                        if (ssw & MMU030_SSW_RM) {
        !          2384:                                // Read-Modify-Write: whole instruction is considered done
        !          2385:                                write_log (_T("Read-Modify-Write and DF bit cleared! PC=%08x\n"), regs.instruction_pc);
        !          2386:                                mmu030_retry = false;
        !          2387:                        } else if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) {
        !          2388:                                // if movem, skip next move
        !          2389:                                mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
        !          2390:                                mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM2;
        !          2391:                        } else {
        !          2392:                                mmu030_ad[idxsize].done = true;
        !          2393:                                if (ssw & MMU030_SSW_RW) {
        !          2394:                                        // Read and no DF: use value in data input buffer
        !          2395:                                        mmu030_data_buffer = get_long_mmu030 (a7 + 0x2c);
        !          2396:                                        mmu030_ad[idxsize].val = mmu030_data_buffer;
        !          2397:                                }
        !          2398:                        }
        !          2399:                }
        !          2400:                // did we have ins fault and RB bit cleared?
        !          2401:                if ((ssw & MMU030_SSW_FB) && !(ssw & MMU030_SSW_RB)) {
        !          2402:                        uae_u16 stageb = get_word_mmu030 (a7 + 0x0e);
        !          2403:                        if (mmu030_opcode == -1) {
        !          2404:                                mmu030_opcode_stageb = stageb;
        !          2405:                                write_log (_T("Software fixed stage B! opcode = %04x\n"), stageb);
        !          2406:                        } else {
        !          2407:                                mmu030_ad[idxsize].done = true;
        !          2408:                                mmu030_ad[idxsize].val = stageb;
        !          2409:                                write_log (_T("Software fixed stage B! opcode = %04X, opword = %04x\n"), mmu030_opcode, stageb);
        !          2410:                        }
        !          2411:                }
        !          2412:                m68k_areg (regs, 7) += 92;
        !          2413:        } else {
        !          2414:                m68k_areg (regs, 7) += 32;
        !          2415:        }
        !          2416: }
        !          2417: 
        !          2418: void flush_mmu030 (uaecptr addr, int n)
        !          2419: {
        !          2420: }
        !          2421: 
        !          2422: void m68k_do_rts_mmu030 (void)
        !          2423: {
        !          2424:        m68k_setpc (get_long_mmu030_state (m68k_areg (regs, 7)));
        !          2425:        m68k_areg (regs, 7) += 4;
        !          2426: }
        !          2427: 
        !          2428: void m68k_do_bsr_mmu030 (uaecptr oldpc, uae_s32 offset)
        !          2429: {
        !          2430:        put_long_mmu030_state (m68k_areg (regs, 7) - 4, oldpc);
        !          2431:        m68k_areg (regs, 7) -= 4;
        !          2432:        m68k_incpci (offset);
        !          2433: }
        !          2434: 
        !          2435: uae_u32 REGPARAM2 get_disp_ea_020_mmu030 (uae_u32 base, int idx)
        !          2436: {
        !          2437:        uae_u16 dp;
        !          2438:        int reg;
        !          2439:        uae_u32 v;
        !          2440:        int oldidx;
        !          2441:        int pcadd = 0;
        !          2442: 
        !          2443:        // we need to do this hack here because in worst case we don't have enough
        !          2444:        // stack frame space to store two very large 020 addressing mode access state
        !          2445:        // + whatever the instruction itself does.
        !          2446: 
        !          2447:        if (mmu030_state[1] & (1 << idx)) {
        !          2448:                m68k_incpci (((mmu030_state[2] >> (idx * 4)) & 15) * 2);
        !          2449:                return mmu030_disp_store[idx];
        !          2450:        }
        !          2451: 
        !          2452:        oldidx = mmu030_idx;
        !          2453:        dp = next_iword_mmu030_state ();
        !          2454:        pcadd += 1;
        !          2455:        
        !          2456:        reg = (dp >> 12) & 15;
        !          2457:        uae_s32 regd = regs.regs[reg];
        !          2458:        if ((dp & 0x800) == 0)
        !          2459:                regd = (uae_s32)(uae_s16)regd;
        !          2460:        regd <<= (dp >> 9) & 3;
        !          2461:        if (dp & 0x100) {
        !          2462:                uae_s32 outer = 0;
        !          2463:                if (dp & 0x80)
        !          2464:                        base = 0;
        !          2465:                if (dp & 0x40)
        !          2466:                        regd = 0;
        !          2467: 
        !          2468:                if ((dp & 0x30) == 0x20) {
        !          2469:                        base += (uae_s32)(uae_s16) next_iword_mmu030_state ();
        !          2470:                        pcadd += 1;
        !          2471:                }
        !          2472:                if ((dp & 0x30) == 0x30) {
        !          2473:                        base += next_ilong_mmu030_state ();
        !          2474:                        pcadd += 2;
        !          2475:                }
        !          2476: 
        !          2477:                if ((dp & 0x3) == 0x2) {
        !          2478:                        outer = (uae_s32)(uae_s16) next_iword_mmu030_state ();
        !          2479:                        pcadd += 1;
        !          2480:                }
        !          2481:                if ((dp & 0x3) == 0x3) {
        !          2482:                        outer = next_ilong_mmu030_state ();
        !          2483:                        pcadd += 2;
        !          2484:                }
        !          2485: 
        !          2486:                if ((dp & 0x4) == 0) {
        !          2487:                        base += regd;
        !          2488:                }
        !          2489:                if (dp & 0x3) {
        !          2490:                        base = get_long_mmu030_state (base);
        !          2491:                }
        !          2492:                if (dp & 0x4) {
        !          2493:                        base += regd;
        !          2494:                }
        !          2495:                v = base + outer;
        !          2496:        } else {
        !          2497:                v = base + (uae_s32)((uae_s8)dp) + regd;
        !          2498:        }
        !          2499: 
        !          2500:        mmu030_state[1] |= 1 << idx;
        !          2501:        mmu030_state[2] |= pcadd << (idx * 4);
        !          2502:        mmu030_disp_store[idx] = v;
        !          2503:        mmu030_idx = oldidx;
        !          2504:        mmu030_ad[mmu030_idx].done = false;
        !          2505: 
        !          2506:        return v;
        !          2507: }

unix.superglobalmegacorp.com

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