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

unix.superglobalmegacorp.com

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