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

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

unix.superglobalmegacorp.com

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