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

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

unix.superglobalmegacorp.com

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