Annotation of previous/src/cpu/cpummu.c, revision 1.1.1.4

1.1.1.2   root        1: /*
                      2:  * cpummu.cpp -  MMU emulation
                      3:  *
                      4:  * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
                      5:  * 
                      6:  * Inspired by UAE MMU patch
                      7:  *
                      8:  * This file is part of the ARAnyM project which builds a new and powerful
                      9:  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
                     10:  *
                     11:  * ARAnyM is free software; you can redistribute it and/or modify
                     12:  * it under the terms of the GNU General Public License as published by
                     13:  * the Free Software Foundation; either version 2 of the License, or
                     14:  * (at your option) any later version.
                     15:  *
                     16:  * ARAnyM is distributed in the hope that it will be useful,
                     17:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19:  * GNU General Public License for more details.
                     20:  *
                     21:  * You should have received a copy of the GNU General Public License
                     22:  * along with ARAnyM; if not, write to the Free Software
                     23:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24:  */
                     25: 
1.1.1.4 ! root       26: #include <strings.h>
1.1.1.2   root       27: 
                     28: #include "sysconfig.h"
                     29: #include "sysdeps.h"
                     30: 
                     31: #include "options_cpu.h"
                     32: #include "memory.h"
                     33: #include "newcpu.h"
                     34: #include "cpummu.h"
1.1.1.4 ! root       35: #include "hatari-glue.h"
        !            36: //#include "debug.h"
1.1.1.2   root       37: 
                     38: #define DBG_MMU_VERBOSE        1
                     39: #define DBG_MMU_SANITY 1
1.1.1.4 ! root       40: #if 0
1.1.1.2   root       41: #define write_log printf
1.1.1.4 ! root       42: #endif
1.1.1.2   root       43: 
                     44: #ifdef FULLMMU
                     45: 
                     46: 
1.1.1.4 ! root       47: uae_u32 mmu_is_super;
        !            48: uae_u32 mmu_tagmask, mmu_pagemask, mmu_pagemaski;
1.1.1.2   root       49: struct mmu_atc_line mmu_atc_array[ATC_TYPE][ATC_WAYS][ATC_SLOTS];
1.1.1.4 ! root       50: bool mmu_pagesize_8k;
        !            51: 
        !            52: int mmu060_state;
        !            53: uae_u16 mmu_opcode;
        !            54: bool mmu_restart;
        !            55: static bool locked_rmw_cycle;
        !            56: static bool ismoves;
        !            57: bool mmu_ttr_enabled;
        !            58: int mmu_atc_ways=0;
        !            59: 
        !            60: int mmu040_movem;
        !            61: uaecptr mmu040_movem_ea;
        !            62: uae_u32 mmu040_move16[4];
1.1.1.2   root       63: 
                     64: static void mmu_dump_ttr(const TCHAR * label, uae_u32 ttr)
                     65: {
                     66:        DUNUSED(label);
                     67:        uae_u32 from_addr, to_addr;
                     68: 
                     69:        from_addr = ttr & MMU_TTR_LOGICAL_BASE;
                     70:        to_addr = (ttr & MMU_TTR_LOGICAL_MASK) << 8;
                     71: 
                     72:        
1.1.1.4 ! root       73: #if MMUDEBUG > 0
        !            74:        write_log(_T("%s: [%08lx] %08lx - %08lx enabled=%d supervisor=%d wp=%d cm=%02d\n"),
1.1.1.2   root       75:                        label, ttr,
                     76:                        from_addr, to_addr,
                     77:                        ttr & MMU_TTR_BIT_ENABLED ? 1 : 0,
                     78:                        (ttr & (MMU_TTR_BIT_SFIELD_ENABLED | MMU_TTR_BIT_SFIELD_SUPER)) >> MMU_TTR_SFIELD_SHIFT,
                     79:                        ttr & MMU_TTR_BIT_WRITE_PROTECT ? 1 : 0,
                     80:                        (ttr & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT
                     81:                  );
1.1.1.4 ! root       82: #endif
1.1.1.2   root       83: }
                     84: 
                     85: void mmu_make_transparent_region(uaecptr baseaddr, uae_u32 size, int datamode)
                     86: {
                     87:        uae_u32 * ttr;
                     88:        uae_u32 * ttr0 = datamode ? &regs.dtt0 : &regs.itt0;
                     89:        uae_u32 * ttr1 = datamode ? &regs.dtt1 : &regs.itt1;
                     90: 
                     91:        if ((*ttr1 & MMU_TTR_BIT_ENABLED) == 0)
                     92:                ttr = ttr1;
                     93:        else if ((*ttr0 & MMU_TTR_BIT_ENABLED) == 0)
                     94:                ttr = ttr0;
                     95:        else
                     96:                return;
                     97: 
                     98:        *ttr = baseaddr & MMU_TTR_LOGICAL_BASE;
                     99:        *ttr |= ((baseaddr + size - 1) & MMU_TTR_LOGICAL_BASE) >> 8;
                    100:        *ttr |= MMU_TTR_BIT_ENABLED;
                    101: 
1.1.1.4 ! root      102: #if MMUDEBUG > 0
        !           103:        write_log(_T("MMU: map transparent mapping of %08x\n"), *ttr);
        !           104: #endif
1.1.1.2   root      105: }
                    106: 
1.1.1.4 ! root      107: void mmu_tt_modified (void)
        !           108: {
        !           109:        mmu_ttr_enabled = ((regs.dtt0 | regs.dtt1 | regs.itt0 | regs.itt1) & MMU_TTR_BIT_ENABLED) != 0;
        !           110: }
1.1.1.2   root      111: 
                    112: 
                    113: #if 0
                    114: /* {{{ mmu_dump_table */
                    115: static void mmu_dump_table(const char * label, uaecptr root_ptr)
                    116: {
                    117:        DUNUSED(label);
                    118:        const int ROOT_TABLE_SIZE = 128,
                    119:                PTR_TABLE_SIZE = 128,
                    120:                PAGE_TABLE_SIZE = 64,
                    121:                ROOT_INDEX_SHIFT = 25,
                    122:                PTR_INDEX_SHIFT = 18;
                    123:        // const int PAGE_INDEX_SHIFT = 12;
                    124:        int root_idx, ptr_idx, page_idx;
                    125:        uae_u32 root_des, ptr_des, page_des;
                    126:        uaecptr ptr_des_addr, page_addr,
                    127:                root_log, ptr_log, page_log;
                    128: 
1.1.1.4 ! root      129:        write_log(_T("%s: root=%lx\n", label, root_ptr);
1.1.1.2   root      130: 
                    131:        for (root_idx = 0; root_idx < ROOT_TABLE_SIZE; root_idx++) {
                    132:                root_des = phys_get_long(root_ptr + root_idx);
                    133: 
                    134:                if ((root_des & 2) == 0)
                    135:                        continue;       /* invalid */
                    136: 
1.1.1.4 ! root      137:                write_log(_T("ROOT: %03d U=%d W=%d UDT=%02d\n", root_idx,
1.1.1.2   root      138:                                root_des & 8 ? 1 : 0,
                    139:                                root_des & 4 ? 1 : 0,
                    140:                                root_des & 3
                    141:                          );
                    142: 
                    143:                root_log = root_idx << ROOT_INDEX_SHIFT;
                    144: 
                    145:                ptr_des_addr = root_des & MMU_ROOT_PTR_ADDR_MASK;
                    146: 
                    147:                for (ptr_idx = 0; ptr_idx < PTR_TABLE_SIZE; ptr_idx++) {
                    148:                        struct {
                    149:                                uaecptr log, phys;
                    150:                                int start_idx, n_pages; /* number of pages covered by this entry */
                    151:                                uae_u32 match;
                    152:                        } page_info[PAGE_TABLE_SIZE];
                    153:                        int n_pages_used;
                    154: 
                    155:                        ptr_des = phys_get_long(ptr_des_addr + ptr_idx);
                    156:                        ptr_log = root_log | (ptr_idx << PTR_INDEX_SHIFT);
                    157: 
                    158:                        if ((ptr_des & 2) == 0)
                    159:                                continue; /* invalid */
                    160: 
1.1.1.4 ! root      161:                        page_addr = ptr_des & (mmu_pagesize_8k ? MMU_PTR_PAGE_ADDR_MASK_8 : MMU_PTR_PAGE_ADDR_MASK_4);
1.1.1.2   root      162: 
                    163:                        n_pages_used = -1;
                    164:                        for (page_idx = 0; page_idx < PAGE_TABLE_SIZE; page_idx++) {
                    165: 
                    166:                                page_des = phys_get_long(page_addr + page_idx);
                    167:                                page_log = ptr_log | (page_idx << 2);           // ??? PAGE_INDEX_SHIFT
                    168: 
                    169:                                switch (page_des & 3) {
                    170:                                        case 0: /* invalid */
                    171:                                                continue;
                    172:                                        case 1: case 3: /* resident */
                    173:                                        case 2: /* indirect */
                    174:                                                if (n_pages_used == -1 || page_info[n_pages_used].match != page_des) {
                    175:                                                        /* use the next entry */
                    176:                                                        n_pages_used++;
                    177: 
                    178:                                                        page_info[n_pages_used].match = page_des;
                    179:                                                        page_info[n_pages_used].n_pages = 1;
                    180:                                                        page_info[n_pages_used].start_idx = page_idx;
                    181:                                                        page_info[n_pages_used].log = page_log;
                    182:                                                } else {
                    183:                                                        page_info[n_pages_used].n_pages++;
                    184:                                                }
                    185:                                                break;
                    186:                                }
                    187:                        }
                    188: 
                    189:                        if (n_pages_used == -1)
                    190:                                continue;
                    191: 
1.1.1.4 ! root      192:                        write_log(_T(" PTR: %03d U=%d W=%d UDT=%02d\n", ptr_idx,
1.1.1.2   root      193:                                ptr_des & 8 ? 1 : 0,
                    194:                                ptr_des & 4 ? 1 : 0,
                    195:                                ptr_des & 3
                    196:                          );
                    197: 
                    198: 
                    199:                        for (page_idx = 0; page_idx <= n_pages_used; page_idx++) {
                    200:                                page_des = page_info[page_idx].match;
                    201: 
                    202:                                if ((page_des & MMU_PDT_MASK) == 2) {
1.1.1.4 ! root      203:                                        write_log(_T("  PAGE: %03d-%03d log=%08lx INDIRECT --> addr=%08lx\n",
1.1.1.2   root      204:                                                        page_info[page_idx].start_idx,
                    205:                                                        page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
                    206:                                                        page_info[page_idx].log,
                    207:                                                        page_des & MMU_PAGE_INDIRECT_MASK
                    208:                                                  );
                    209: 
                    210:                                } else {
1.1.1.4 ! root      211:                                        write_log(_T("  PAGE: %03d-%03d log=%08lx addr=%08lx UR=%02d G=%d U1/0=%d S=%d CM=%d M=%d U=%d W=%d\n",
1.1.1.2   root      212:                                                        page_info[page_idx].start_idx,
                    213:                                                        page_info[page_idx].start_idx + page_info[page_idx].n_pages - 1,
                    214:                                                        page_info[page_idx].log,
1.1.1.4 ! root      215:                                                        page_des & (mmu_pagesize_8k ? MMU_PAGE_ADDR_MASK_8 : MMU_PAGE_ADDR_MASK_4),
        !           216:                                                        (page_des & (mmu_pagesize_8k ? MMU_PAGE_UR_MASK_8 : MMU_PAGE_UR_MASK_4)) >> MMU_PAGE_UR_SHIFT,
1.1.1.2   root      217:                                                        page_des & MMU_DES_GLOBAL ? 1 : 0,
                    218:                                                        (page_des & MMU_TTR_UX_MASK) >> MMU_TTR_UX_SHIFT,
                    219:                                                        page_des & MMU_DES_SUPER ? 1 : 0,
                    220:                                                        (page_des & MMU_TTR_CACHE_MASK) >> MMU_TTR_CACHE_SHIFT,
                    221:                                                        page_des & MMU_DES_MODIFIED ? 1 : 0,
                    222:                                                        page_des & MMU_DES_USED ? 1 : 0,
                    223:                                                        page_des & MMU_DES_WP ? 1 : 0
                    224:                                                  );
                    225:                                }
                    226:                        }
                    227:                }
                    228: 
                    229:        }
                    230: }
                    231: /* }}} */
                    232: #endif
                    233: 
                    234: /* {{{ mmu_dump_atc */
                    235: void mmu_dump_atc(void)
                    236: {
                    237: 
                    238: }
                    239: /* }}} */
                    240: 
                    241: /* {{{ mmu_dump_tables */
                    242: void mmu_dump_tables(void)
                    243: {
1.1.1.4 ! root      244:        write_log(_T("URP: %08x   SRP: %08x  MMUSR: %x  TC: %x\n"), regs.urp, regs.srp, regs.mmusr, regs.tcr);
        !           245:        mmu_dump_ttr(_T("DTT0"), regs.dtt0);
        !           246:        mmu_dump_ttr(_T("DTT1"), regs.dtt1);
        !           247:        mmu_dump_ttr(_T("ITT0"), regs.itt0);
        !           248:        mmu_dump_ttr(_T("ITT1"), regs.itt1);
1.1.1.2   root      249:        mmu_dump_atc();
1.1.1.4 ! root      250: #if MMUDEBUG
1.1.1.2   root      251:        // mmu_dump_table("SRP", regs.srp);
                    252: #endif
                    253: }
                    254: /* }}} */
                    255: 
1.1.1.4 ! root      256: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write, uae_u32 *status);
1.1.1.2   root      257: 
                    258: static ALWAYS_INLINE int mmu_get_fc(bool super, bool data)
                    259: {
                    260:        return (super ? 4 : 0) | (data ? 1 : 2);
                    261: }
                    262: 
1.1.1.4 ! root      263: void mmu_bus_error(uaecptr addr, int fc, bool write, int size, bool rmw, uae_u32 status, bool nonmmu)
1.1.1.2   root      264: {
1.1.1.4 ! root      265:        if (currprefs.mmu_model == 68040) {
        !           266:                uae_u16 ssw = 0;
1.1.1.2   root      267: 
1.1.1.4 ! root      268:                if (ismoves) {
        !           269:                        // MOVES special behavior
        !           270:                        int fc2 = write ? regs.dfc : regs.sfc;
        !           271:                        if (fc2 == 0 || fc2 == 3 || fc2 == 4 || fc2 == 7)
        !           272:                                ssw |= MMU_SSW_TT1;
        !           273:                        if ((fc2 & 3) != 3)
        !           274:                                fc2 &= ~2;
        !           275: #if MMUDEBUGMISC > 0
        !           276:                        write_log (_T("040 MMU MOVES fc=%d -> %d\n"), fc, fc2);
        !           277: #endif
        !           278:                        fc = fc2;
        !           279:                }
        !           280: 
        !           281:                ssw |= fc & MMU_SSW_TM;                         /* TM = FC */
        !           282:                switch (size) {
        !           283:                case sz_byte:
        !           284:                        ssw |= MMU_SSW_SIZE_B;
        !           285:                        break;
        !           286:                case sz_word:
        !           287:                        ssw |= MMU_SSW_SIZE_W;
        !           288:                        break;
        !           289:                case sz_long:
        !           290:                        ssw |= MMU_SSW_SIZE_L;
        !           291:                        break;
        !           292:         }
        !           293:         
        !           294:         regs.wb3_status = write ? 0x80 | (ssw & 0x7f) : 0;
        !           295:         regs.wb2_status = 0;
        !           296:         if (!write)
        !           297:             ssw |= MMU_SSW_RW;
        !           298:         
        !           299:         if (size == 16) { // MOVE16
        !           300:                        ssw |= MMU_SSW_SIZE_CL;
        !           301:                        ssw |= MMU_SSW_TT0;
        !           302:                        regs.mmu_effective_addr &= ~15;
        !           303:                        if (write) {
        !           304:                                // clear normal writeback if MOVE16 write
        !           305:                                regs.wb3_status &= ~0x80;
        !           306:                                // wb2 = cacheline size writeback
        !           307:                                regs.wb2_status = 0x80 | MMU_SSW_SIZE_CL | (ssw & 0x1f);
        !           308:                                regs.wb2_address = regs.mmu_effective_addr;
        !           309:                                write_log (_T("040 MMU MOVE16 WRITE FAULT!\n"));
        !           310:                        }
        !           311:                }
1.1.1.2   root      312: 
1.1.1.4 ! root      313:                if (mmu040_movem) {
        !           314:                        ssw |= MMU_SSW_CM;
        !           315:                        regs.mmu_effective_addr = mmu040_movem_ea;
        !           316:                        mmu040_movem = 0;
        !           317: #if MMUDEBUGMISC > 0
        !           318:                        write_log (_T("040 MMU_SSW_CM EA=%08X\n"), mmu040_movem_ea);
        !           319: #endif
        !           320:                }
        !           321:                if (locked_rmw_cycle) {
        !           322:                        ssw |= MMU_SSW_LK;
        !           323:                        ssw &= ~MMU_SSW_RW;
        !           324:                        locked_rmw_cycle = false;
        !           325: #if MMUDEBUGMISC > 0
        !           326:                        write_log (_T("040 MMU_SSW_LK!\n"));
        !           327: #endif
        !           328:                }
        !           329:                
        !           330:                if (!nonmmu)
        !           331:                        ssw |= MMU_SSW_ATC;
        !           332:                regs.mmu_ssw = ssw;
1.1.1.2   root      333: 
1.1.1.4 ! root      334: #if MMUDEBUG > 0
        !           335:                write_log(_T("BF: fc=%d w=%d logical=%08x ssw=%04x PC=%08x INS=%04X\n"), fc, write, addr, ssw, m68k_getpc(), mmu_opcode);
        !           336: #endif
        !           337:        } else {
        !           338:                uae_u32 fslw = 0;
        !           339: 
        !           340:                fslw |= write ? MMU_FSLW_W : MMU_FSLW_R;
        !           341:                fslw |= fc << 16; /* MMU_FSLW_TM */
1.1.1.2   root      342: 
1.1.1.4 ! root      343:                switch (size) {
        !           344:                case sz_byte:
        !           345:                        fslw |= MMU_FSLW_SIZE_B;
        !           346:                        break;
        !           347:                case sz_word:
        !           348:                        fslw |= MMU_FSLW_SIZE_W;
        !           349:                        break;
        !           350:                case sz_long:
        !           351:                        fslw |= MMU_FSLW_SIZE_L;
        !           352:                        break;
        !           353:                case 16: // MOVE16
        !           354:                        addr &= ~15;
        !           355:                        fslw |= MMU_FSLW_SIZE_D;
        !           356:                        fslw |= MMU_FSLW_TT_16;
        !           357:                        break;
        !           358:                }
        !           359:                if ((fc & 3) == 2) {
        !           360:                        // instruction faults always point to opcode address
        !           361: #if MMUDEBUGMISC > 0
        !           362:                        write_log(_T("INS FAULT %08x %08x %d\n"), addr, regs.instruction_pc, mmu060_state);
        !           363: #endif
        !           364:                        addr = regs.instruction_pc;
        !           365:                        if (mmu060_state == 0) {
        !           366:                                fslw |= MMU_FSLW_IO; // opword fetch
        !           367:                        } else {
        !           368:                                fslw |= MMU_FSLW_IO | MMU_FSLW_MA; // extension word
        !           369:                        }
        !           370:                }
        !           371:                if (rmw) {
        !           372:                        fslw |=  MMU_FSLW_W | MMU_FSLW_R;
        !           373:                }
        !           374:                if (locked_rmw_cycle) {
        !           375:                        fslw |= MMU_FSLW_LK;
        !           376:                        locked_rmw_cycle = false;
        !           377:                        write_log (_T("060 MMU_FSLW_LK!\n"));
        !           378:                }
        !           379:                fslw |= status;
        !           380:                regs.mmu_fslw = fslw;
1.1.1.2   root      381: 
1.1.1.4 ! root      382: #if MMUDEBUG > 0
        !           383:                write_log(_T("BF: fc=%d w=%d s=%d log=%08x ssw=%08x rmw=%d PC=%08x INS=%04X\n"), fc, write, 1 << size, addr, fslw, rmw, m68k_getpc(), mmu_opcode);
        !           384: #endif
        !           385: 
        !           386:        }
        !           387: 
        !           388:        regs.mmu_fault_addr = addr;
        !           389: 
        !           390: #if 0
        !           391:        if (m68k_getpc () == 0x0004B0AC) {
        !           392:                write_log (_T("*"));
        !           393: #if 0
        !           394:                extern void activate_debugger(void);
        !           395:                activate_debugger ();
        !           396: #endif
        !           397:        }
        !           398: #endif
1.1.1.2   root      399:        THROW(2);
                    400: }
                    401: 
1.1.1.4 ! root      402: void mmu_bus_error_ttr_write_fault(uaecptr addr, bool super, bool data, uae_u32 val, int size, bool rmw)
        !           403: {
        !           404:        uae_u32 status = 0;
        !           405: 
        !           406:        if (currprefs.mmu_model == 68060) {
        !           407:                status |= MMU_FSLW_TTR;
        !           408:        }
        !           409:        regs.wb3_data = val;
        !           410:        mmu_bus_error(addr, mmu_get_fc (super, data), true, size, false, status, false);
        !           411: }
        !           412: 
        !           413: 
1.1.1.2   root      414: /*
                    415:  * Update the atc line for a given address by doing a mmu lookup.
                    416:  */
1.1.1.4 ! root      417: static uaecptr mmu_fill_atc(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l, uae_u32 *status)
1.1.1.2   root      418: {
                    419:        uae_u32 desc;
                    420: 
1.1.1.4 ! root      421:        *status = 0;
1.1.1.2   root      422:        SAVE_EXCEPTION;
                    423:        TRY(prb) {
1.1.1.4 ! root      424:                desc = mmu_lookup_pagetable(addr, super, write, status);
        !           425: #if MMUDEBUG > 2
        !           426:                write_log(_T("translate: %x,%u,%u,%u -> %x\n"), addr, super, write, data, desc);
1.1.1.2   root      427: #endif
                    428:                RESTORE_EXCEPTION;
                    429:        }
                    430:        CATCH(prb) {
                    431:                RESTORE_EXCEPTION;
                    432:                /* bus error during table search */
                    433:                desc = 0;
1.1.1.4 ! root      434:                *status = MMU_FSLW_TWE;
1.1.1.2   root      435:                // goto fail;
                    436:        } ENDTRY
1.1.1.4 ! root      437:        if ((desc & 1) && (!super && desc & MMU_MMUSR_S)) {
        !           438:                *status |= MMU_FSLW_SP;
        !           439: #if MMUDEBUG > 1
        !           440:                write_log (_T("MMU: supervisor protected %x\n"), addr);
        !           441: #endif
        !           442:                l->valid = 0;
        !           443:                l->global = 0;
        !           444:        } else if ((desc & 1) == 0) {
1.1.1.2   root      445:                l->valid = 0;
                    446:                l->global = 0;
                    447:        } else {
                    448:                l->valid = 1;
1.1.1.4 ! root      449:                l->phys = desc & mmu_pagemaski;
1.1.1.2   root      450:                l->global = (desc & MMU_MMUSR_G) != 0;
                    451:                l->modified = (desc & MMU_MMUSR_M) != 0;
                    452:                l->write_protect = (desc & MMU_MMUSR_W) != 0;
                    453:        }
                    454: 
                    455:        return desc;
                    456: }
                    457: 
1.1.1.4 ! root      458: static ALWAYS_INLINE bool mmu_fill_atc_try(uaecptr addr, bool super, bool data, bool write, struct mmu_atc_line *l1, uae_u32 *status)
1.1.1.2   root      459: {
1.1.1.4 ! root      460:        mmu_fill_atc(addr,super,data,write,l1, status);
1.1.1.2   root      461:        if (!(l1->valid)) {
1.1.1.4 ! root      462: #if MMUDEBUG > 2
        !           463:                write_log(_T("MMU: non-resident page (%x,%x)!\n"), addr, regs.pc);
        !           464: #endif
1.1.1.2   root      465:                goto fail;
                    466:        }
                    467:        if (write) {
                    468:                if (l1->write_protect) {
1.1.1.4 ! root      469:                        *status |= MMU_FSLW_WP;
        !           470: #if MMUDEBUG > 0
        !           471:                        write_log(_T("MMU: write protected %lx by atc \n"), addr);
        !           472: #endif
1.1.1.2   root      473:                        mmu_dump_atc();
                    474:                        goto fail;
                    475:                }
                    476: 
                    477:        }
                    478:        return true;
                    479: 
                    480: fail:
                    481:        return false;
                    482: }
                    483: 
                    484: uaecptr REGPARAM2 mmu_translate(uaecptr addr, bool super, bool data, bool write)
                    485: {
                    486:        struct mmu_atc_line *l;
1.1.1.4 ! root      487:        uae_u32 status = 0;
        !           488: 
1.1.1.2   root      489:        // this should return a miss but choose a valid line
                    490:        mmu_user_lookup(addr, super, data, write, &l);
                    491: 
1.1.1.4 ! root      492:        mmu_fill_atc(addr, super, data, write, l, &status);
        !           493:        if (!l->valid || (write && l->write_protect)) {
        !           494: #if MMUDEBUG > 2
        !           495:                write_log(_T("[MMU] mmu_translate error"));
        !           496: #endif
        !           497:                mmu_bus_error(addr, mmu_get_fc(super, data), write, 0, false, status, false);
        !           498:                return 0;
1.1.1.2   root      499:        }
                    500: 
1.1.1.4 ! root      501:     return l->phys | (addr & mmu_pagemask);
1.1.1.2   root      502: 
                    503: }
                    504: 
                    505: /*
                    506:  * Lookup the address by walking the page table and updating
                    507:  * the page descriptors accordingly. Returns the found descriptor
                    508:  * or produces a bus error.
                    509:  */
1.1.1.4 ! root      510: static uaecptr REGPARAM2 mmu_lookup_pagetable(uaecptr addr, bool super, bool write, uae_u32 *status)
1.1.1.2   root      511: {
                    512:        uae_u32 desc, desc_addr, wp;
                    513:        int i;
                    514: 
                    515:        wp = 0;
                    516:        desc = super ? regs.srp : regs.urp;
                    517: 
                    518:        /* fetch root table descriptor */
                    519:        i = (addr >> 23) & 0x1fc;
                    520:        desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
                    521:        desc = phys_get_long(desc_addr);
                    522:        if ((desc & 2) == 0) {
1.1.1.4 ! root      523: #if MMUDEBUG > 1
        !           524:                write_log(_T("MMU: invalid root descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"),
        !           525:                                addr, desc_addr, desc);
        !           526: #endif
        !           527:                *status |= MMU_FSLW_PTA;
1.1.1.2   root      528:                return 0;
                    529:        }
                    530: 
                    531:        wp |= desc;
                    532:        if ((desc & MMU_DES_USED) == 0)
                    533:                phys_put_long(desc_addr, desc | MMU_DES_USED);
                    534: 
                    535:        /* fetch pointer table descriptor */
                    536:        i = (addr >> 16) & 0x1fc;
                    537:        desc_addr = (desc & MMU_ROOT_PTR_ADDR_MASK) | i;
                    538:        desc = phys_get_long(desc_addr);
                    539:        if ((desc & 2) == 0) {
1.1.1.4 ! root      540: #if MMUDEBUG > 1
        !           541:                write_log(_T("MMU: invalid ptr descriptor %s for %x desc at %x desc=%x\n"), super ? _T("srp"):_T("urp"), 
        !           542:                                addr, desc_addr, desc);
        !           543: #endif
        !           544:                *status |= MMU_FSLW_PTB;
1.1.1.2   root      545:                return 0;
                    546:        }
                    547:        wp |= desc;
                    548:        if ((desc & MMU_DES_USED) == 0)
                    549:                phys_put_long(desc_addr, desc | MMU_DES_USED);
                    550: 
                    551:        /* fetch page table descriptor */
1.1.1.4 ! root      552:        if (mmu_pagesize_8k) {
1.1.1.2   root      553:                i = (addr >> 11) & 0x7c;
                    554:                desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_8) + i;
                    555:        } else {
                    556:                i = (addr >> 10) & 0xfc;
                    557:                desc_addr = (desc & MMU_PTR_PAGE_ADDR_MASK_4) + i;
                    558:        }
                    559: 
                    560:        desc = phys_get_long(desc_addr);
                    561:        if ((desc & 3) == 2) {
                    562:                /* indirect */
                    563:                desc_addr = desc & MMU_PAGE_INDIRECT_MASK;
                    564:                desc = phys_get_long(desc_addr);
                    565:        }
                    566:        if ((desc & 1) == 0) {
1.1.1.4 ! root      567: #if MMUDEBUG > 2
        !           568:                write_log(_T("MMU: invalid page descriptor log=%0lx desc=%08x @%08x\n"), addr, desc, desc_addr);
        !           569: #endif
        !           570:                if ((desc & 3) == 2) {
        !           571:                        *status |= MMU_FSLW_IL;
        !           572: #if MMUDEBUG > 1
        !           573:                        write_log(_T("MMU: double indirect descriptor log=%0lx desc=%08x @%08x\n"), addr, desc, desc_addr);
        !           574: #endif 
        !           575:                } else {
        !           576:                        *status |= MMU_FSLW_PF;
        !           577:                }
1.1.1.2   root      578:                return desc;
                    579:        }
                    580: 
                    581:        desc |= wp & MMU_DES_WP;
                    582:        if (write) {
                    583:                if (desc & MMU_DES_WP) {
                    584:                        if ((desc & MMU_DES_USED) == 0) {
                    585:                                desc |= MMU_DES_USED;
                    586:                                phys_put_long(desc_addr, desc);
                    587:                        }
                    588:                } else if ((desc & (MMU_DES_USED|MMU_DES_MODIFIED)) !=
                    589:                                   (MMU_DES_USED|MMU_DES_MODIFIED)) {
                    590:                        desc |= MMU_DES_USED|MMU_DES_MODIFIED;
                    591:                        phys_put_long(desc_addr, desc);
                    592:                }
                    593:        } else {
                    594:                if ((desc & MMU_DES_USED) == 0) {
                    595:                        desc |= MMU_DES_USED;
                    596:                        phys_put_long(desc_addr, desc);
                    597:                }
                    598:        }
                    599:        return desc;
                    600: }
                    601: 
1.1.1.4 ! root      602: static void misalignednotfirst(uaecptr addr)
        !           603: {
        !           604: #if MMUDEBUGMISC > 0
        !           605:        write_log (_T("misalignednotfirst %08x -> %08x %08X\n"), regs.mmu_fault_addr, addr, regs.instruction_pc);
        !           606: #endif
        !           607:        regs.mmu_fault_addr = addr;
        !           608:        regs.mmu_fslw |= MMU_FSLW_MA;
        !           609:        regs.mmu_ssw |= MMU_SSW_MA;
        !           610: }
        !           611: 
        !           612: static void misalignednotfirstcheck(uaecptr addr)
        !           613: {
        !           614:        if (regs.mmu_fault_addr == addr)
        !           615:                return;
        !           616:        misalignednotfirst (addr);
        !           617: }
        !           618: 
        !           619: uae_u16 REGPARAM2 mmu_get_word_unaligned(uaecptr addr, bool data, bool rmw)
1.1.1.2   root      620: {
                    621:        uae_u16 res;
                    622: 
1.1.1.4 ! root      623:        res = (uae_u16)mmu_get_byte(addr, data, sz_word, rmw) << 8;
1.1.1.2   root      624:        SAVE_EXCEPTION;
                    625:        TRY(prb) {
1.1.1.4 ! root      626:                res |= mmu_get_byte(addr + 1, data, sz_word, rmw);
1.1.1.2   root      627:                RESTORE_EXCEPTION;
                    628:        }
                    629:        CATCH(prb) {
                    630:                RESTORE_EXCEPTION;
1.1.1.4 ! root      631:                misalignednotfirst(addr);
1.1.1.2   root      632:                THROW_AGAIN(prb);
                    633:        } ENDTRY
                    634:        return res;
                    635: }
                    636: 
1.1.1.4 ! root      637: uae_u32 REGPARAM2 mmu_get_long_unaligned(uaecptr addr, bool data, bool rmw)
1.1.1.2   root      638: {
                    639:        uae_u32 res;
                    640: 
                    641:        if (likely(!(addr & 1))) {
1.1.1.4 ! root      642:                res = (uae_u32)mmu_get_word(addr, data, sz_long, rmw) << 16;
1.1.1.2   root      643:                SAVE_EXCEPTION;
                    644:                TRY(prb) {
1.1.1.4 ! root      645:                        res |= mmu_get_word(addr + 2, data, sz_long, rmw);
1.1.1.2   root      646:                        RESTORE_EXCEPTION;
                    647:                }
                    648:                CATCH(prb) {
                    649:                        RESTORE_EXCEPTION;
1.1.1.4 ! root      650:                        misalignednotfirst(addr);
1.1.1.2   root      651:                        THROW_AGAIN(prb);
                    652:                } ENDTRY
                    653:        } else {
1.1.1.4 ! root      654:                res = (uae_u32)mmu_get_byte(addr, data, sz_long, rmw) << 8;
1.1.1.2   root      655:                SAVE_EXCEPTION;
                    656:                TRY(prb) {
1.1.1.4 ! root      657:                        res = (res | mmu_get_byte(addr + 1, data, sz_long, rmw)) << 8;
        !           658:                        res = (res | mmu_get_byte(addr + 2, data, sz_long, rmw)) << 8;
        !           659:                        res |= mmu_get_byte(addr + 3, data, sz_long, rmw);
1.1.1.2   root      660:                        RESTORE_EXCEPTION;
                    661:                }
                    662:                CATCH(prb) {
                    663:                        RESTORE_EXCEPTION;
1.1.1.4 ! root      664:                        misalignednotfirst(addr);
1.1.1.2   root      665:                        THROW_AGAIN(prb);
                    666:                } ENDTRY
                    667:        }
                    668:        return res;
                    669: }
                    670: 
1.1.1.4 ! root      671: uae_u16 REGPARAM2 mmu_get_lrmw_word_unaligned(uaecptr addr)
        !           672: {
        !           673:        uae_u16 res;
        !           674: 
        !           675:        res = (uae_u16)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_word) << 8;
        !           676:        SAVE_EXCEPTION;
        !           677:        TRY(prb) {
        !           678:                res |= mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_word);
        !           679:                RESTORE_EXCEPTION;
        !           680:        }
        !           681:        CATCH(prb) {
        !           682:                RESTORE_EXCEPTION;
        !           683:                misalignednotfirst(addr);
        !           684:                THROW_AGAIN(prb);
        !           685:        } ENDTRY
        !           686:        return res;
        !           687: }
        !           688: 
        !           689: uae_u32 REGPARAM2 mmu_get_lrmw_long_unaligned(uaecptr addr)
        !           690: {
        !           691:        uae_u32 res;
        !           692: 
        !           693:        if (likely(!(addr & 1))) {
        !           694:                res = (uae_u32)mmu_get_user_word(addr, regs.s != 0, true, true, sz_long) << 16;
        !           695:                SAVE_EXCEPTION;
        !           696:                TRY(prb) {
        !           697:                        res |= mmu_get_user_word(addr + 2, regs.s != 0, true, true, sz_long);
        !           698:                        RESTORE_EXCEPTION;
        !           699:                }
        !           700:                CATCH(prb) {
        !           701:                        RESTORE_EXCEPTION;
        !           702:                        misalignednotfirst(addr);
        !           703:                        THROW_AGAIN(prb);
        !           704:                } ENDTRY
        !           705:        } else {
        !           706:                res = (uae_u32)mmu_get_user_byte(addr, regs.s != 0, true, true, sz_long) << 8;
        !           707:                SAVE_EXCEPTION;
        !           708:                TRY(prb) {
        !           709:                        res = (res | mmu_get_user_byte(addr + 1, regs.s != 0, true, true, sz_long)) << 8;
        !           710:                        res = (res | mmu_get_user_byte(addr + 2, regs.s != 0, true, true, sz_long)) << 8;
        !           711:                        res |= mmu_get_user_byte(addr + 3, regs.s != 0, true, true, sz_long);
        !           712:                        RESTORE_EXCEPTION;
        !           713:                }
        !           714:                CATCH(prb) {
        !           715:                        RESTORE_EXCEPTION;
        !           716:                        misalignednotfirst(addr);
        !           717:                        THROW_AGAIN(prb);
        !           718:                } ENDTRY
        !           719:        }
        !           720:        return res;
        !           721: }
1.1.1.2   root      722: uae_u8 REGPARAM2 mmu_get_byte_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root      723:                                                 int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      724: {
1.1.1.4 ! root      725:        uae_u32 status;
        !           726:        if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
        !           727:                mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2   root      728:                return 0;
                    729:        }
                    730:        return phys_get_byte(mmu_get_real_address(addr, cl));
                    731: }
                    732: 
                    733: uae_u16 REGPARAM2 mmu_get_word_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root      734:                                                  int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      735: {
1.1.1.4 ! root      736:        uae_u32 status;
        !           737:        if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
        !           738:                mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2   root      739:                return 0;
                    740:        }
                    741:        return phys_get_word(mmu_get_real_address(addr, cl));
                    742: }
                    743: 
                    744: uae_u32 REGPARAM2 mmu_get_long_slow(uaecptr addr, bool super, bool data,
1.1.1.4 ! root      745:                                                  int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      746: {
1.1.1.4 ! root      747:        uae_u32 status;
        !           748:        if (!mmu_fill_atc_try(addr, super, data, 0, cl, &status)) {
        !           749:                mmu_bus_error(addr, mmu_get_fc(super, data), 0, size, rmw, status, false);
1.1.1.2   root      750:                return 0;
                    751:        }
                    752:        return phys_get_long(mmu_get_real_address(addr, cl));
                    753: }
                    754: 
1.1.1.4 ! root      755: void REGPARAM2 mmu_put_long_unaligned(uaecptr addr, uae_u32 val, bool data, bool rmw)
1.1.1.2   root      756: {
                    757:        SAVE_EXCEPTION;
                    758:        TRY(prb) {
                    759:                if (likely(!(addr & 1))) {
1.1.1.4 ! root      760:                        mmu_put_word(addr, val >> 16, data, sz_long, rmw);
        !           761:                        mmu_put_word(addr + 2, val, data, sz_long, rmw);
1.1.1.2   root      762:                } else {
1.1.1.4 ! root      763:                        mmu_put_byte(addr, val >> 24, data, sz_long, rmw);
        !           764:                        mmu_put_byte(addr + 1, val >> 16, data, sz_long, rmw);
        !           765:                        mmu_put_byte(addr + 2, val >> 8, data, sz_long, rmw);
        !           766:                        mmu_put_byte(addr + 3, val, data, sz_long, rmw);
1.1.1.2   root      767:                }
                    768:                RESTORE_EXCEPTION;
                    769:        }
                    770:        CATCH(prb) {
                    771:                RESTORE_EXCEPTION;
                    772:                regs.wb3_data = val;
1.1.1.4 ! root      773:                misalignednotfirstcheck(addr);
1.1.1.2   root      774:                THROW_AGAIN(prb);
                    775:        } ENDTRY
                    776: }
                    777: 
1.1.1.4 ! root      778: void REGPARAM2 mmu_put_word_unaligned(uaecptr addr, uae_u16 val, bool data, bool rmw)
1.1.1.2   root      779: {
                    780:        SAVE_EXCEPTION;
                    781:        TRY(prb) {
1.1.1.4 ! root      782:                mmu_put_byte(addr, val >> 8, data, sz_word, rmw);
        !           783:                mmu_put_byte(addr + 1, val, data, sz_word, rmw);
1.1.1.2   root      784:                RESTORE_EXCEPTION;
                    785:        }
                    786:        CATCH(prb) {
                    787:                RESTORE_EXCEPTION;
                    788:                regs.wb3_data = val;
1.1.1.4 ! root      789:                misalignednotfirstcheck(addr);
1.1.1.2   root      790:                THROW_AGAIN(prb);
                    791:        } ENDTRY
                    792: }
                    793: 
                    794: void REGPARAM2 mmu_put_byte_slow(uaecptr addr, uae_u8 val, bool super, bool data,
1.1.1.4 ! root      795:                                                                 int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      796: {
1.1.1.4 ! root      797:        uae_u32 status;
        !           798:        if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2   root      799:                regs.wb3_data = val;
1.1.1.4 ! root      800:                mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2   root      801:                return;
                    802:        }
                    803:        phys_put_byte(mmu_get_real_address(addr, cl), val);
                    804: }
                    805: 
                    806: void REGPARAM2 mmu_put_word_slow(uaecptr addr, uae_u16 val, bool super, bool data,
1.1.1.4 ! root      807:                                                                 int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      808: {
1.1.1.4 ! root      809:        uae_u32 status;
        !           810:        if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2   root      811:                regs.wb3_data = val;
1.1.1.4 ! root      812:                mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2   root      813:                return;
                    814:        }
                    815:        phys_put_word(mmu_get_real_address(addr, cl), val);
                    816: }
                    817: 
                    818: void REGPARAM2 mmu_put_long_slow(uaecptr addr, uae_u32 val, bool super, bool data,
1.1.1.4 ! root      819:                                                                 int size, bool rmw, struct mmu_atc_line *cl)
1.1.1.2   root      820: {
1.1.1.4 ! root      821:        uae_u32 status;
        !           822:        if (!mmu_fill_atc_try(addr, super, data, 1, cl, &status)) {
1.1.1.2   root      823:                regs.wb3_data = val;
1.1.1.4 ! root      824:                mmu_bus_error(addr, mmu_get_fc(super, data), 1, size, rmw, status, false);
1.1.1.2   root      825:                return;
                    826:        }
                    827:        phys_put_long(mmu_get_real_address(addr, cl), val);
                    828: }
                    829: 
                    830: uae_u32 REGPARAM2 sfc_get_long(uaecptr addr)
                    831: {
                    832:        bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root      833:        bool data = true;
1.1.1.2   root      834:        uae_u32 res;
                    835: 
1.1.1.4 ! root      836:        ismoves = true;
        !           837:        if (likely(!is_unaligned(addr, 4))) {
        !           838:                res = mmu_get_user_long(addr, super, data, false, sz_long);
1.1.1.2   root      839:        } else {
1.1.1.4 ! root      840:                if (likely(!(addr & 1))) {
        !           841:                        res = (uae_u32)mmu_get_user_word(addr, super, data, false, sz_long) << 16;
        !           842:                        SAVE_EXCEPTION;
        !           843:                        TRY(prb) {
        !           844:                                res |= mmu_get_user_word(addr + 2, super, data, false, sz_long);
        !           845:                                RESTORE_EXCEPTION;
        !           846:                        }
        !           847:                        CATCH(prb) {
        !           848:                                RESTORE_EXCEPTION;
        !           849:                                misalignednotfirst(addr);
        !           850:                                THROW_AGAIN(prb);
        !           851:                        } ENDTRY
        !           852:                } else {
        !           853:                        res = (uae_u32)mmu_get_user_byte(addr, super, data, false, sz_long) << 8;
        !           854:                        SAVE_EXCEPTION;
        !           855:                        TRY(prb) {
        !           856:                                res = (res | mmu_get_user_byte(addr + 1, super, data, false, sz_long)) << 8;
        !           857:                                res = (res | mmu_get_user_byte(addr + 2, super, data, false, sz_long)) << 8;
        !           858:                                res |= mmu_get_user_byte(addr + 3, super, data, false, sz_long);
        !           859:                                RESTORE_EXCEPTION;
        !           860:                        }
        !           861:                        CATCH(prb) {
        !           862:                                RESTORE_EXCEPTION;
        !           863:                                misalignednotfirst(addr);
        !           864:                                THROW_AGAIN(prb);
        !           865:                        } ENDTRY
1.1.1.2   root      866:                }
                    867:        }
1.1.1.4 ! root      868: 
        !           869:        ismoves = false;
1.1.1.2   root      870:        return res;
                    871: }
                    872: 
                    873: uae_u16 REGPARAM2 sfc_get_word(uaecptr addr)
                    874: {
                    875:        bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root      876:        bool data = true;
1.1.1.2   root      877:        uae_u16 res;
                    878: 
1.1.1.4 ! root      879:        ismoves = true;
        !           880:        if (likely(!is_unaligned(addr, 2))) {
        !           881:                res = mmu_get_user_word(addr, super, data, false, sz_word);
        !           882:        } else {
        !           883:                res = (uae_u16)mmu_get_user_byte(addr, super, data, false, sz_word) << 8;
        !           884:                SAVE_EXCEPTION;
        !           885:                TRY(prb) {
        !           886:                        res |= mmu_get_user_byte(addr + 1, super, data, false, sz_word);
        !           887:                        RESTORE_EXCEPTION;
        !           888:                }
        !           889:                CATCH(prb) {
        !           890:                        RESTORE_EXCEPTION;
        !           891:                        misalignednotfirst(addr);
        !           892:                        THROW_AGAIN(prb);
        !           893:                } ENDTRY
1.1.1.2   root      894:        }
1.1.1.4 ! root      895:        ismoves = false;
1.1.1.2   root      896:        return res;
                    897: }
                    898: 
                    899: uae_u8 REGPARAM2 sfc_get_byte(uaecptr addr)
                    900: {
                    901:        bool super = (regs.sfc & 4) != 0;
1.1.1.4 ! root      902:        bool data = true;
        !           903:        uae_u8 res;
        !           904:        
        !           905:        ismoves = true;
        !           906:        res = mmu_get_user_byte(addr, super, data, false, sz_byte);
        !           907:        ismoves = false;
        !           908:        return res;
1.1.1.2   root      909: }
                    910: 
                    911: void REGPARAM2 dfc_put_long(uaecptr addr, uae_u32 val)
                    912: {
                    913:        bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root      914:        bool data = true;
1.1.1.2   root      915: 
1.1.1.4 ! root      916:        ismoves = true;
1.1.1.2   root      917:        SAVE_EXCEPTION;
                    918:        TRY(prb) {
                    919:                if (likely(!is_unaligned(addr, 4)))
                    920:                        mmu_put_user_long(addr, val, super, data, sz_long);
                    921:                else if (likely(!(addr & 1))) {
                    922:                        mmu_put_user_word(addr, val >> 16, super, data, sz_long);
                    923:                        mmu_put_user_word(addr + 2, val, super, data, sz_long);
                    924:                } else {
                    925:                        mmu_put_user_byte(addr, val >> 24, super, data, sz_long);
                    926:                        mmu_put_user_byte(addr + 1, val >> 16, super, data, sz_long);
                    927:                        mmu_put_user_byte(addr + 2, val >> 8, super, data, sz_long);
                    928:                        mmu_put_user_byte(addr + 3, val, super, data, sz_long);
                    929:                }
                    930:                RESTORE_EXCEPTION;
                    931:        }
                    932:        CATCH(prb) {
                    933:                RESTORE_EXCEPTION;
                    934:                regs.wb3_data = val;
1.1.1.4 ! root      935:                misalignednotfirstcheck(addr);
1.1.1.2   root      936:                THROW_AGAIN(prb);
                    937:        } ENDTRY
1.1.1.4 ! root      938:        ismoves = false;
1.1.1.2   root      939: }
                    940: 
                    941: void REGPARAM2 dfc_put_word(uaecptr addr, uae_u16 val)
                    942: {
                    943:        bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root      944:        bool data = true;
1.1.1.2   root      945: 
1.1.1.4 ! root      946:        ismoves = true;
1.1.1.2   root      947:        SAVE_EXCEPTION;
                    948:        TRY(prb) {
                    949:                if (likely(!is_unaligned(addr, 2)))
                    950:                        mmu_put_user_word(addr, val, super, data, sz_word);
                    951:                else {
                    952:                        mmu_put_user_byte(addr, val >> 8, super, data, sz_word);
                    953:                        mmu_put_user_byte(addr + 1, val, super, data, sz_word);
                    954:                }
                    955:                RESTORE_EXCEPTION;
                    956:        }
                    957:        CATCH(prb) {
                    958:                RESTORE_EXCEPTION;
                    959:                regs.wb3_data = val;
1.1.1.4 ! root      960:                misalignednotfirstcheck(addr);
1.1.1.2   root      961:                THROW_AGAIN(prb);
                    962:        } ENDTRY
1.1.1.4 ! root      963:        ismoves = false;
1.1.1.2   root      964: }
                    965: 
                    966: void REGPARAM2 dfc_put_byte(uaecptr addr, uae_u8 val)
                    967: {
                    968:        bool super = (regs.dfc & 4) != 0;
1.1.1.4 ! root      969:        bool data = true;
1.1.1.2   root      970: 
1.1.1.4 ! root      971:        ismoves = true;
1.1.1.2   root      972:        SAVE_EXCEPTION;
                    973:        TRY(prb) {
                    974:                mmu_put_user_byte(addr, val, super, data, sz_byte);
                    975:                RESTORE_EXCEPTION;
                    976:        }
                    977:        CATCH(prb) {
                    978:                RESTORE_EXCEPTION;
                    979:                regs.wb3_data = val;
                    980:                THROW_AGAIN(prb);
                    981:        } ENDTRY
1.1.1.4 ! root      982:        ismoves = false;
1.1.1.2   root      983: }
                    984: 
1.1.1.4 ! root      985: void mmu_get_move16(uaecptr addr, uae_u32 *v, bool data, int size)
        !           986: {
        !           987:        struct mmu_atc_line *cl;
        !           988:        addr &= ~15;
        !           989:        for (int i = 0; i < 4; i++) {
        !           990:                uaecptr addr2 = addr + i * 4;
        !           991:                //                                       addr,super,data
        !           992:                if ((!regs.mmu_enabled) || (mmu_match_ttr(addr2,regs.s != 0,data,false)!=TTR_NO_MATCH))
        !           993:                        v[i] = phys_get_long(addr2);
        !           994:                else if (likely(mmu_lookup(addr2, data, false, &cl)))
        !           995:                        v[i] = phys_get_long(mmu_get_real_address(addr2, cl));
        !           996:                else
        !           997:                        v[i] = mmu_get_long_slow(addr2, regs.s != 0, data, size, false, cl);
        !           998:        }
        !           999: }
        !          1000: 
        !          1001: void mmu_put_move16(uaecptr addr, uae_u32 *val, bool data, int size)
        !          1002: {
        !          1003:        struct mmu_atc_line *cl;
        !          1004:        addr &= ~15;
        !          1005:        for (int i = 0; i < 4; i++) {
        !          1006:                uaecptr addr2 = addr + i * 4;
        !          1007:                //                                        addr,super,data
        !          1008:                if ((!regs.mmu_enabled) || (mmu_match_ttr_write(addr2,regs.s != 0,data,val[i],size,false)==TTR_OK_MATCH))
        !          1009:                        phys_put_long(addr2,val[i]);
        !          1010:                else if (likely(mmu_lookup(addr2, data, true, &cl)))
        !          1011:                        phys_put_long(mmu_get_real_address(addr2, cl), val[i]);
        !          1012:                else
        !          1013:                        mmu_put_long_slow(addr2, val[i], regs.s != 0, data, size, false, cl);
        !          1014:        }
        !          1015: }
        !          1016: 
        !          1017: 
1.1.1.2   root     1018: void REGPARAM2 mmu_op_real(uae_u32 opcode, uae_u16 extra)
                   1019: {
                   1020:        bool super = (regs.dfc & 4) != 0;
                   1021:        DUNUSED(extra);
1.1.1.4 ! root     1022:        if ((opcode & 0xFE0) == 0x0500) { // PFLUSH
1.1.1.2   root     1023:                bool glob;
                   1024:                int regno;
                   1025:                //D(didflush = 0);
                   1026:                uae_u32 addr;
                   1027:                /* PFLUSH */
                   1028:                regno = opcode & 7;
                   1029:                glob = (opcode & 8) != 0;
                   1030: 
                   1031:                if (opcode & 16) {
1.1.1.4 ! root     1032: #if MMUINSDEBUG > 1
        !          1033:                        write_log(_T("pflusha(%u,%u) PC=%08x\n"), glob, regs.dfc, m68k_getpc ());
        !          1034: #endif
1.1.1.2   root     1035:                        mmu_flush_atc_all(glob);
                   1036:                } else {
                   1037:                        addr = m68k_areg(regs, regno);
1.1.1.4 ! root     1038: #if MMUINSDEBUG > 1
        !          1039:                        write_log(_T("pflush(%u,%u,%x) PC=%08x\n"), glob, regs.dfc, addr, m68k_getpc ());
        !          1040: #endif
1.1.1.2   root     1041:                        mmu_flush_atc(addr, super, glob);
                   1042:                }
                   1043:                flush_internals();
                   1044: #ifdef USE_JIT
                   1045:                flush_icache(0);
                   1046: #endif
1.1.1.4 ! root     1047:        } else if ((opcode & 0x0FD8) == 0x0548) { // PTEST (68040)
1.1.1.2   root     1048:                bool write;
                   1049:                int regno;
                   1050:                uae_u32 addr;
                   1051: 
                   1052:                regno = opcode & 7;
                   1053:                write = (opcode & 32) == 0;
                   1054:                addr = m68k_areg(regs, regno);
1.1.1.4 ! root     1055: #if MMUINSDEBUG > 0
        !          1056:                write_log(_T("PTEST%c (A%d) %08x DFC=%d\n"), write ? 'W' : 'R', regno, addr, regs.dfc);
        !          1057: #endif
1.1.1.2   root     1058:                mmu_flush_atc(addr, super, true);
                   1059:                SAVE_EXCEPTION;
                   1060:                TRY(prb) {
                   1061:                        struct mmu_atc_line *l;
                   1062:                        uae_u32 desc;
                   1063:                        bool data = (regs.dfc & 3) != 2;
                   1064: 
1.1.1.4 ! root     1065:                        if (mmu_match_ttr(addr,super,data, false)!=TTR_NO_MATCH) {
1.1.1.2   root     1066:                                regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
1.1.1.4 ! root     1067:                        } else {
        !          1068:                                uae_u32 status;
1.1.1.2   root     1069:                                mmu_user_lookup(addr, super, data, write, &l);
1.1.1.4 ! root     1070:                                desc = mmu_fill_atc(addr, super, data, write, l, &status);
        !          1071:                                if (!(l->valid)) {
1.1.1.2   root     1072:                                        regs.mmusr = MMU_MMUSR_B;
1.1.1.4 ! root     1073:                                } else {
1.1.1.2   root     1074:                                        regs.mmusr = desc & (~0xfff|MMU_MMUSR_G|MMU_MMUSR_Ux|MMU_MMUSR_S|
                   1075:                                                                                 MMU_MMUSR_CM|MMU_MMUSR_M|MMU_MMUSR_W);
                   1076:                                        regs.mmusr |= MMU_MMUSR_R;
                   1077:                                }
                   1078:                        }
                   1079:                }
                   1080:                CATCH(prb) {
                   1081:                        regs.mmusr = MMU_MMUSR_B;
                   1082:                } ENDTRY
                   1083:                RESTORE_EXCEPTION;
1.1.1.4 ! root     1084: #if MMUINSDEBUG > 0
        !          1085:                write_log(_T("PTEST result: mmusr %08x\n"), regs.mmusr);
        !          1086: #endif
        !          1087:        } else if ((opcode & 0xFFB8) == 0xF588) { // PLPA (68060)
        !          1088:                int write = (opcode & 0x40) == 0;
        !          1089:                int regno = opcode & 7;
        !          1090:                uae_u32 addr = m68k_areg (regs, regno);
        !          1091:                bool data = (regs.dfc & 3) != 2;
        !          1092: 
        !          1093: #if MMUINSDEBUG > 0
        !          1094:                write_log(_T("PLPA%c param: %08x\n"), write ? 'W' : 'R', addr);
        !          1095: #endif
        !          1096:                if (mmu_match_ttr(addr,super,data,false)==TTR_NO_MATCH) {
        !          1097:                        m68k_areg (regs, regno) = mmu_translate (addr, super, data, write != 0);
        !          1098:                }
        !          1099: #if MMUINSDEBUG > 0
        !          1100:                write_log(_T("PLPA%c result: %08x\n"), write ? 'W' : 'R', m68k_areg (regs, regno));
        !          1101: #endif
        !          1102:        } else {
1.1.1.2   root     1103:                op_illg (opcode);
1.1.1.4 ! root     1104:        }
1.1.1.2   root     1105: }
                   1106: 
                   1107: // fixme : global parameter?
                   1108: void REGPARAM2 mmu_flush_atc(uaecptr addr, bool super, bool global)
                   1109: {
                   1110:        int way,type,index;
                   1111: 
1.1.1.4 ! root     1112:        uaecptr tag = ((super ? 0x80000000 : 0) | (addr >> 1)) & mmu_tagmask;
        !          1113:        if (mmu_pagesize_8k)
1.1.1.2   root     1114:                index=(addr & 0x0001E000)>>13;
                   1115:        else
                   1116:                index=(addr & 0x0000F000)>>12;
1.1.1.4 ! root     1117:        for (type=0;type<ATC_TYPE;type++) {
        !          1118:                for (way=0;way<ATC_WAYS;way++) {
        !          1119:                        if (!global && mmu_atc_array[type][way][index].global)
        !          1120:                                continue;
        !          1121:                        // if we have this 
        !          1122:                        if ((tag == mmu_atc_array[type][way][index].tag) && (mmu_atc_array[type][way][index].valid)) {
        !          1123:                                mmu_atc_array[type][way][index].valid=false;
        !          1124:                        }
1.1.1.2   root     1125:                }
                   1126:        }       
                   1127: }
                   1128: 
                   1129: void REGPARAM2 mmu_flush_atc_all(bool global)
                   1130: {
                   1131:        unsigned int way,slot,type;
1.1.1.4 ! root     1132:        for (type=0;type<ATC_TYPE;type++) {
        !          1133:                for (way=0;way<ATC_WAYS;way++) {
        !          1134:                        for (slot=0;slot<ATC_SLOTS;slot++) {
        !          1135:                                if (!global && mmu_atc_array[type][way][slot].global)
        !          1136:                                        continue;
        !          1137:                                mmu_atc_array[type][way][slot].valid=false;
        !          1138:                        }
        !          1139:                }
1.1.1.2   root     1140:        }
                   1141: }
                   1142: 
                   1143: void REGPARAM2 mmu_reset(void)
                   1144: {
                   1145:        mmu_flush_atc_all(true);
                   1146: }
                   1147: 
                   1148: 
                   1149: void REGPARAM2 mmu_set_tc(uae_u16 tc)
                   1150: {
1.1.1.4 ! root     1151:        regs.mmu_enabled = (tc & 0x8000) != 0;
        !          1152:        mmu_pagesize_8k = (tc & 0x4000) != 0;
        !          1153:        mmu_tagmask  = mmu_pagesize_8k ? 0xFFFF0000 : 0xFFFF8000;
        !          1154:        mmu_pagemask = mmu_pagesize_8k ? 0x00001FFF : 0x00000FFF;
        !          1155:        mmu_pagemaski = ~mmu_pagemask;
        !          1156:        regs.mmu_page_size = mmu_pagesize_8k ? 8192 : 4096;
        !          1157: 
1.1.1.2   root     1158:        mmu_flush_atc_all(true);
                   1159: 
1.1.1.4 ! root     1160:        write_log(_T("%d MMU: enabled=%d page8k=%d\n"), currprefs.mmu_model, regs.mmu_enabled, mmu_pagesize_8k);
1.1.1.2   root     1161: }
                   1162: 
                   1163: void REGPARAM2 mmu_set_super(bool super)
                   1164: {
1.1.1.4 ! root     1165:        mmu_is_super = super ? 0x80000000 : 0;
        !          1166: }
        !          1167: 
        !          1168: void m68k_do_rte_mmu040 (uaecptr a7)
        !          1169: {
        !          1170:        uae_u16 ssr = get_word_mmu040 (a7 + 8 + 4);
        !          1171:        if (ssr & MMU_SSW_CT) {
        !          1172:                uaecptr src_a7 = a7 + 8 - 8;
        !          1173:                uaecptr dst_a7 = a7 + 8 + 52;
        !          1174:                put_word_mmu040 (dst_a7 + 0, get_word_mmu040 (src_a7 + 0));
        !          1175:                put_long_mmu040 (dst_a7 + 2, get_long_mmu040 (src_a7 + 2));
        !          1176:                // skip this word
        !          1177:                put_long_mmu040 (dst_a7 + 8, get_long_mmu040 (src_a7 + 8));
        !          1178:        }
        !          1179:        if (ssr & MMU_SSW_CM) {
        !          1180:                mmu040_movem = 1;
        !          1181:                mmu040_movem_ea = get_long_mmu040 (a7 + 8);
        !          1182: #if MMUDEBUGMISC > 0
        !          1183:                write_log (_T("MMU restarted MOVEM EA=%08X\n"), mmu040_movem_ea);
        !          1184: #endif
        !          1185:        }
        !          1186: }
        !          1187: 
        !          1188: void m68k_do_rte_mmu060 (uaecptr a7)
        !          1189: {
        !          1190: #if 0
        !          1191:        mmu060_state = 2;
        !          1192: #endif
        !          1193: }
        !          1194: 
        !          1195: void flush_mmu040 (uaecptr addr, int n)
        !          1196: {
        !          1197: }
        !          1198: void m68k_do_rts_mmu040 (void)
        !          1199: {
        !          1200:        uaecptr stack = m68k_areg (regs, 7);
        !          1201:        uaecptr newpc = get_long_mmu040 (stack);
        !          1202:        m68k_areg (regs, 7) += 4;
        !          1203:        m68k_setpc (newpc);
        !          1204: }
        !          1205: void m68k_do_bsr_mmu040 (uaecptr oldpc, uae_s32 offset)
        !          1206: {
        !          1207:        uaecptr newstack = m68k_areg (regs, 7) - 4;
        !          1208:        put_long_mmu040 (newstack, oldpc);
        !          1209:        m68k_areg (regs, 7) -= 4;
        !          1210:        m68k_incpci (offset);
1.1.1.2   root     1211: }
                   1212: 
1.1.1.4 ! root     1213: void flush_mmu060 (uaecptr addr, int n)
        !          1214: {
        !          1215: }
        !          1216: void m68k_do_rts_mmu060 (void)
        !          1217: {
        !          1218:        uaecptr stack = m68k_areg (regs, 7);
        !          1219:        uaecptr newpc = get_long_mmu060 (stack);
        !          1220:        m68k_areg (regs, 7) += 4;
        !          1221:        m68k_setpc (newpc);
        !          1222: }
        !          1223: void m68k_do_bsr_mmu060 (uaecptr oldpc, uae_s32 offset)
        !          1224: {
        !          1225:        uaecptr newstack = m68k_areg (regs, 7) - 4;
        !          1226:        put_long_mmu060 (newstack, oldpc);
        !          1227:        m68k_areg (regs, 7) -= 4;
        !          1228:        m68k_incpci (offset);
        !          1229: }
        !          1230: 
        !          1231: void uae_mmu_put_lrmw (uaecptr addr, uae_u32 v, int size, int type)
        !          1232: {
        !          1233:        locked_rmw_cycle = true;
        !          1234:        if (size == sz_byte) {
        !          1235:                mmu_put_byte(addr, v, true, sz_byte, true);
        !          1236:        } else if (size == sz_word) {
        !          1237:                if (unlikely(is_unaligned(addr, 2))) {
        !          1238:                        mmu_put_word_unaligned(addr, v, true, true);
        !          1239:                } else {
        !          1240:                        mmu_put_word(addr, v, true, sz_word, true);
        !          1241:                }
        !          1242:        } else {
        !          1243:                if (unlikely(is_unaligned(addr, 4)))
        !          1244:                        mmu_put_long_unaligned(addr, v, true, true);
        !          1245:                else
        !          1246:                        mmu_put_long(addr, v, true, sz_long, true);
        !          1247:        }
        !          1248:        locked_rmw_cycle = false;
        !          1249: }
        !          1250: uae_u32 uae_mmu_get_lrmw (uaecptr addr, int size, int type)
        !          1251: {
        !          1252:        uae_u32 v;
        !          1253:        locked_rmw_cycle = true;
        !          1254:        if (size == sz_byte) {
        !          1255:                v = mmu_get_user_byte(addr, regs.s != 0, true, true, sz_byte);
        !          1256:        } else if (size == sz_word) {
        !          1257:                if (unlikely(is_unaligned(addr, 2))) {
        !          1258:                        v = mmu_get_lrmw_word_unaligned(addr);
        !          1259:                } else {
        !          1260:                        v = mmu_get_user_word(addr, regs.s != 0, true, true, sz_word);
        !          1261:                }
        !          1262:        } else {
        !          1263:                if (unlikely(is_unaligned(addr, 4)))
        !          1264:                        v = mmu_get_lrmw_long_unaligned(addr);
        !          1265:                else
        !          1266:                        v = mmu_get_user_long(addr, regs.s != 0, true, true, sz_long);
        !          1267:        }
        !          1268:        locked_rmw_cycle = false;
        !          1269:        return v;
        !          1270: }
        !          1271: 
        !          1272: uae_u32 REGPARAM2 mmu060_get_rmw_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width)
        !          1273: {
        !          1274:        uae_u32 tmp1, tmp2, res, mask;
        !          1275: 
        !          1276:        offset &= 7;
        !          1277:        mask = 0xffffffffu << (32 - width);
        !          1278:        switch ((offset + width + 7) >> 3) {
        !          1279:        case 1:
        !          1280:                tmp1 = get_rmw_byte_mmu060 (src);
        !          1281:                res = tmp1 << (24 + offset);
        !          1282:                bdata[0] = tmp1 & ~(mask >> (24 + offset));
        !          1283:                break;
        !          1284:        case 2:
        !          1285:                tmp1 = get_rmw_word_mmu060 (src);
        !          1286:                res = tmp1 << (16 + offset);
        !          1287:                bdata[0] = tmp1 & ~(mask >> (16 + offset));
        !          1288:                break;
        !          1289:        case 3:
        !          1290:                tmp1 = get_rmw_word_mmu060 (src);
        !          1291:                tmp2 = get_rmw_byte_mmu060 (src + 2);
        !          1292:                res = tmp1 << (16 + offset);
        !          1293:                bdata[0] = tmp1 & ~(mask >> (16 + offset));
        !          1294:                res |= tmp2 << (8 + offset);
        !          1295:                bdata[1] = tmp2 & ~(mask >> (8 + offset));
        !          1296:                break;
        !          1297:        case 4:
        !          1298:                tmp1 = get_rmw_long_mmu060 (src);
        !          1299:                res = tmp1 << offset;
        !          1300:                bdata[0] = tmp1 & ~(mask >> offset);
        !          1301:                break;
        !          1302:        case 5:
        !          1303:                tmp1 = get_rmw_long_mmu060 (src);
        !          1304:                tmp2 = get_rmw_byte_mmu060 (src + 4);
        !          1305:                res = tmp1 << offset;
        !          1306:                bdata[0] = tmp1 & ~(mask >> offset);
        !          1307:                res |= tmp2 >> (8 - offset);
        !          1308:                bdata[1] = tmp2 & ~(mask << (8 - offset));
        !          1309:                break;
        !          1310:        default:
        !          1311:                /* Panic? */
        !          1312:                write_log (_T("x_get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3);
        !          1313:                res = 0;
        !          1314:                break;
        !          1315:        }
        !          1316:        return res;
        !          1317: }
        !          1318: 
        !          1319: void REGPARAM2 mmu060_put_rmw_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width)
        !          1320: {
        !          1321:        offset = (offset & 7) + width;
        !          1322:        switch ((offset + 7) >> 3) {
        !          1323:        case 1:
        !          1324:                put_rmw_byte_mmu060 (dst, bdata[0] | (val << (8 - offset)));
        !          1325:                break;
        !          1326:        case 2:
        !          1327:                put_rmw_word_mmu060 (dst, bdata[0] | (val << (16 - offset)));
        !          1328:                break;
        !          1329:        case 3:
        !          1330:                put_rmw_word_mmu060 (dst, bdata[0] | (val >> (offset - 16)));
        !          1331:                put_rmw_byte_mmu060 (dst + 2, bdata[1] | (val << (24 - offset)));
        !          1332:                break;
        !          1333:        case 4:
        !          1334:                put_rmw_long_mmu060 (dst, bdata[0] | (val << (32 - offset)));
        !          1335:                break;
        !          1336:        case 5:
        !          1337:                put_rmw_long_mmu060 (dst, bdata[0] | (val >> (offset - 32)));
        !          1338:                put_rmw_byte_mmu060 (dst + 4, bdata[1] | (val << (40 - offset)));
        !          1339:                break;
        !          1340:        default:
        !          1341:                write_log (_T("x_put_bitfield() can't happen %d\n"), (offset + 7) >> 3);
        !          1342:                break;
        !          1343:        }
        !          1344: }
        !          1345: 
        !          1346: 
        !          1347: #ifndef __cplusplus
1.1.1.2   root     1348: jmp_buf __exbuf;
                   1349: int     __exvalue;
                   1350: #define MAX_TRY_STACK 256
                   1351: static int s_try_stack_size=0;
                   1352: static jmp_buf s_try_stack[MAX_TRY_STACK];
                   1353: jmp_buf* __poptry(void) {
                   1354:        if (s_try_stack_size>0) {
1.1.1.3   root     1355:         s_try_stack_size--;
                   1356:         if (s_try_stack_size == 0)
                   1357:             return NULL;
                   1358:         memcpy(&__exbuf,&s_try_stack[s_try_stack_size-1],sizeof(jmp_buf));
                   1359:         // fprintf(stderr,"pop jmpbuf=%08x\n",s_try_stack[s_try_stack_size][0]);
                   1360:         return &s_try_stack[s_try_stack_size-1];
                   1361:     }
1.1.1.2   root     1362:        else {
                   1363:                fprintf(stderr,"try stack underflow...\n");
                   1364:            // return (NULL);
                   1365:                abort();
                   1366:        }
                   1367: }
1.1.1.3   root     1368: void __pushtry(jmp_buf* j) {
1.1.1.2   root     1369:        if (s_try_stack_size<MAX_TRY_STACK) {
                   1370:                // fprintf(stderr,"push jmpbuf=%08x\n",(*j)[0]);
                   1371:                memcpy(&s_try_stack[s_try_stack_size],j,sizeof(jmp_buf));
                   1372:                s_try_stack_size++;
                   1373:        } else {
                   1374:                fprintf(stderr,"try stack overflow...\n");
                   1375:                abort();
                   1376:        }
                   1377: }
                   1378: int __is_catched(void) {return (s_try_stack_size>0); }
1.1.1.4 ! root     1379: #endif
        !          1380: 
1.1.1.2   root     1381: #else
                   1382: 
                   1383: void mmu_op(uae_u32 opcode, uae_u16 /*extra*/)
                   1384: {
                   1385:        if ((opcode & 0xFE0) == 0x0500) {
                   1386:                /* PFLUSH instruction */
                   1387:                flush_internals();
                   1388:        } else if ((opcode & 0x0FD8) == 0x548) {
                   1389:                /* PTEST instruction */
                   1390:        } else
                   1391:                op_illg(opcode);
                   1392: }
                   1393: 
                   1394: #endif
                   1395: 
                   1396: /*
                   1397: vim:ts=4:sw=4:
                   1398: */

unix.superglobalmegacorp.com

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