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

unix.superglobalmegacorp.com

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