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

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

unix.superglobalmegacorp.com

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