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

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

unix.superglobalmegacorp.com

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