Annotation of nono/m680x0/m68030mmu.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.8   root        7: #include "mpu680x0.h"
1.1       root        8: #include "m68030mmu.h"
1.1.1.8   root        9: #include "mainbus.h"
1.1       root       10: 
                     11: #define TIA            (0)
                     12: #define TIB            (1)
                     13: #define TIC            (2)
                     14: #define TID            (3)
                     15: #define FCL            (4)     // 便宜上ね
                     16: #define MAX_LV (5)
                     17: 
                     18: // ディスクリプタタイプ
                     19: #define GET_DT(x)      (x & 0x03)
                     20: #define DT_INVALID     (0)
                     21: #define DT_PAGE                (1)
                     22: #define DT_VALID4      (2)
                     23: #define DT_VALID8      (3)
                     24: 
                     25: // ディスクリプタ
                     26: #define MMU_DESC_S     (0x00000100)
                     27: #define MMU_DESC_CI    (0x00000040)
1.1.1.4   root       28: #define MMU_DESC_M     (0x00000010)
                     29: #define MMU_DESC_U     (0x00000008)
1.1       root       30: #define MMU_DESC_WP    (0x00000004)
                     31: #define MMU_DESC_DT    (0x00000003)
                     32: 
                     33: // エントリの状態
                     34: enum ATCtype {
                     35:        INVALID,
                     36:        NORMAL,
                     37:        EARLY,
                     38:        INDIRECT,
                     39: };
                     40: 
                     41: //
                     42: // デバッグ表示
                     43: //
                     44: 
                     45: // デバッグ表示のため値の表示に必要な桁数を返す
                     46: #define NIBBLE(x)              ( (x) == 0 ? 1 : ((x) + 3) / 4 )
                     47: 
1.1.1.6   root       48: // インデント付き string_format
                     49: static std::string indent_format(int indent, const char *fmt, ...)
                     50:        __printflike(2, 3);
                     51: static std::string
                     52: indent_format(int indent, const char *fmt, ...)
1.1       root       53: {
                     54:        va_list ap;
1.1.1.6   root       55:        char *buf;
1.1       root       56: 
                     57:        va_start(ap, fmt);
1.1.1.6   root       58:        vasprintf(&buf, fmt, ap);
1.1       root       59:        va_end(ap);
                     60: 
1.1.1.6   root       61:        std::string rv(indent, ' ');
                     62:        rv += buf;
                     63:        free(buf);
1.1       root       64: 
1.1.1.6   root       65:        return rv;
                     66: }
1.1       root       67: 
1.1.1.9   root       68: #define MMULOG(lv, indent, arg...) do { \
                     69:        if (__predict_false(loglevel >= (lv))) {        \
                     70:                cpu->putlogf(lv, [&, lam_func = __func__] { \
                     71:                        (void)lam_func; \
                     72:                        return indent_format(indent, arg); \
                     73:                });     \
                     74:        }       \
                     75: } while (0)
1.1       root       76: 
                     77: // テーブルサーチ操作クラス
1.1.1.3   root       78: class m68030MMU final
1.1       root       79: {
                     80:  public:
1.1.1.11! root       81:        m68030MMU(MPU68030Device *, int loglevel_);
1.1.1.8   root       82:        ~m68030MMU();
1.1       root       83: 
                     84:        // サーチを実行
1.1.1.10  root       85:        void search(int level, busaddr laddr);
1.1       root       86: 
                     87:        // ATC にエントリを作成
                     88:        void make_atc(m68030ATCLine *);
                     89: 
                     90:        // ATC にエントリを作成 (デバッガアクセス用)
1.1.1.9   root       91:        busaddr make_atc_debugger() const;
1.1       root       92: 
                     93:  private:
                     94:        // リミットチェック
                     95:        bool limitcheck() const;
                     96: 
                     97:        // ディスクリプタを取得
                     98:        bool fetch_desc(uint32, int);
                     99: 
                    100:        // ディスクリプタを表示用に (デバッグ用)
                    101:        std::string sprintf_desc();
                    102: 
                    103:        // ディスクリプタタイプ文字列 (デバッグ用)
                    104:        const char *dtname(uint32 dt);
                    105: 
                    106:  public:
1.1.1.9   root      107:        ATCtype m_type {};              // 状態
                    108:        bool    m_s {};                 // S ビット
                    109:        bool    m_wp {};                // WP ビット
                    110:        bool    m_ci {};                // CI ビット
                    111:        bool    m_m {};                 // ページディスクリプタの M が立っているか
                    112:        bool    m_lim {};               // サーチ中にリミットを越えた
                    113:        bool    m_berr {};              // テーブルサーチ中にバスエラー
                    114:        bool    m_ptest {};             // PTEST[RW] 命令中なら真
                    115:        bool    m_debugger {};  // デバッガからのアクセスなら true にする
                    116:        int     x {};                   // 段数 TIA〜TID, FCL
                    117:        uint32  m_lastaddr {};  // 最後にアクセスしたディスクリプタアドレス(PTEST)
1.1.1.8   root      118:  private:
1.1.1.9   root      119:        int     m_lv[MAX_LV] {};
                    120:        uint32  m_desc1 {};             // ディスクリプタ
                    121:        uint32  m_desc2 {};             // ロングディスクリプタの後半部
                    122:        int     m_descsize {};  // ディスクリプタサイズ (4 or 8)
                    123:        int     m_lastsize {};  // 前段のディスクリプタサイズ
1.1       root      124: 
                    125:        // デバッグ用文字列
                    126:        static const char * const m_lvname[MAX_LV];
                    127: 
1.1.1.9   root      128:        int loglevel {};
                    129: 
1.1.1.11! root      130:        MPU68030Device *cpu;
1.1       root      131: };
                    132: 
                    133: // 現在の TC:E、TT:E の状態に応じてアドレス変換の有無を切り替える。
                    134: // mmu_enable ならアドレス変換ありのバスアクセスを使う。see m68030bus.cpp
                    135: void
1.1.1.11! root      136: MPU68030Device::mmu_enable_changed()
1.1       root      137: {
                    138:        bool enable;
                    139: 
                    140:        // TC、TT0、TT1 のいずれかが有効ならアドレス変換あり
                    141:        enable = (mmu_tc.e || mmu_tt[0].e || mmu_tt[1].e);
                    142: 
                    143:        // 変化した時だけ
                    144:        if (mmu_enable && !enable) {
                    145:                // 無効にする
                    146:                mmu_enable = false;
1.1.1.8   root      147:                putlog(1, "MMU Translation Disabled");
1.1       root      148:        } else if (!mmu_enable && enable) {
                    149:                // 有効にする
                    150:                mmu_enable = true;
1.1.1.8   root      151:                putlog(1, "MMU Translation Enabled");
1.1       root      152:        }
                    153: }
                    154: 
                    155: 
                    156: //
                    157: // レジスタクラス
                    158: //
                    159: 
1.1.1.8   root      160: bool
1.1.1.11! root      161: MPU68030Device::SetSRP(uint32 h, uint32 l)
1.1       root      162: {
1.1.1.8   root      163:        if ((h & m68030RP::DT_MASK) == 0) {
                    164:                return false;
                    165:        }
1.1       root      166:        reg.srp.h = h & m68030RP::H_MASK;
                    167:        reg.srp.l = l & m68030RP::L_MASK;
1.1.1.8   root      168:        return true;
1.1       root      169: }
                    170: 
1.1.1.8   root      171: bool
1.1.1.11! root      172: MPU68030Device::SetCRP(uint32 h, uint32 l)
1.1       root      173: {
1.1.1.8   root      174:        if ((h & m68030RP::DT_MASK) == 0) {
                    175:                return false;
                    176:        }
1.1       root      177:        reg.crp.h = h & m68030RP::H_MASK;
                    178:        reg.crp.l = l & m68030RP::L_MASK;
1.1.1.8   root      179:        return true;
1.1       root      180: }
                    181: 
                    182: void
1.1.1.11! root      183: MPU68030Device::SetTT(int n, uint32 data)
1.1       root      184: {
                    185:        uint32 lbase;
                    186:        uint32 lmask;
                    187:        uint32 sbase;
                    188:        uint32 smask;
                    189: 
1.1.1.10  root      190:        // ハッシュから TT#n の成分を一旦クリアする。
                    191:        if (mmu_tt[n].e) {
                    192:                // 変更前の TT#n にマッチして、現在の TT#(1-n) にマッチしない
                    193:                // アドレスブロックに対応する 4096 エントリをクリア。
                    194:                for (int fc = 0; fc < 8; fc++) {
                    195:                        auto *table = atc.fctables[fc];
                    196:                        if (table) {
                    197:                                busaddr laddr = busaddr(0) | busaddr::FC(fc);
                    198:                                for (int i = 0; i < 256; i++) {
                    199:                                        // XXX R/W は?
                    200:                                        if (mmu_tt[n].Match(laddr) &&
                    201:                                                mmu_tt[1 - n].Match(laddr) == false)
                    202:                                        {
                    203:                                                uint32 baseidx = i << (24 - 12);
                    204:                                                memset(&table->hash[baseidx],
                    205:                                                        m68030ATCTable::HASH_NONE, 4096);
                    206:                                        }
                    207:                                        laddr += 0x0100'0000;
                    208:                                }
                    209:                        }
                    210:                }
                    211:        }
                    212: 
1.1       root      213:        // マスクしてレジスタイメージにセット
                    214:        reg.tt[n] = data & m68030TT::MASK;
                    215: 
                    216:        // data を分解してメンバにセット。
                    217:        //
                    218:        //    3                   2                   1                   0
                    219:        //  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
                    220:        // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
                    221:        // |LogicalAddrBase|LogicalAddrMask|E|       |C|R|M| | FCB | | FCM |
                    222:        // +---------------+---------------+-+-+-+-+-+-+-+-+-+-----+-+-----+
                    223: 
                    224:        mmu_tt[n].e      = (data & m68030TT::E);
                    225:        mmu_tt[n].ci     = (data & m68030TT::CI);
                    226: 
                    227:        // 下位ロングワード
                    228:        // ・lbase は比較先アドレスで、ff000000の位置。
                    229:        // ・lmask はアドレスマスク。%1 が無視を表しているので NOT しておく。
                    230:        //
                    231:        //  target  AAAAAAAA xxxxxxxx xxxxxxxx xxxxxxxx : Aは論理アドレス
                    232:        //        ^                                     : xは不問
                    233:        //  lbase   BBBBBBBB 00000000 00000000 00000000 : Bは論理アドレスベース
                    234:        //        &
                    235:        //  lmask   MMMMMMMM 00000000 00000000 00000000 : Mは論理アドレスマスク
                    236:        //
                    237:        lbase  = (data & m68030TT::LBASE_MASK);
                    238:        lmask  = (~data & m68030TT::LMASK_MASK) << 8;
                    239: 
                    240:        // 上位ロングワード
                    241:        // ・E ビットは位置はどこでもいいので TT:E ビットの
                    242:        //   位置をそのまま使用する。target 側のこの位置は必ずビットが落ちている
                    243:        //   ため base 側にビットを立てておくと必ず不一致になることを利用して、
                    244:        //   E ビットの評価も一度に行う。
                    245:        // ・RW ビットは SSW の RW と比較するので、SSW_RW のビット位置を使う
1.1.1.8   root      246:        //   (0x00000040 の位置)。TT:RW も SSW_RW も Read が %1。
1.1       root      247:        // ・RWM が %1 なら R/W は無視、RWM が %0 なら R/W の一致も検査するので
                    248:        //   RWM が %0 の時は RW のマスクビットを立てておく。
1.1.1.9   root      249:        // ・FC は busaddr の配置に合わせて1ビット左シフトしたところを使う。
1.1       root      250:        // ・FCMask は %1 が無視を表しているので NOT しておく。
                    251:        //
1.1.1.9   root      252:        //  target  00000000 00000000 00000000 0R00FFFS : R はアクセス R/~W
1.1       root      253:        //        ^                                     : F はアクセス FC
1.1.1.9   root      254:        //                                              : S は FC2 のコピー
                    255:        //  base    00000000 00000000 E0000000 0R00FFF0 : R は期待する R/~W
1.1       root      256:        //        &                                     : F は期待する FC
                    257:        //                                              : E は ~TT:E
1.1.1.9   root      258:        //  mask    00000000 00000000 10000000 0M00CCC0 : M は R/~W マスク
1.1       root      259:        //                                              : C は FC マスク
1.1.1.8   root      260:        sbase  = ~data & m68030TT::E;
                    261:        sbase |= (data & m68030TT::RW) >> 3;
1.1.1.9   root      262:        sbase |= (data & m68030TT::FCBASE_MASK) >> 3;
1.1       root      263:        smask  = m68030TT::E;
                    264:        if ((data & m68030TT::RWM) == 0) {
1.1.1.11! root      265:                smask |= M68030::SSW_RW;
1.1       root      266:        }
1.1.1.9   root      267:        smask |= (~data & m68030TT::FCMASK_MASK) << 1;
1.1       root      268: 
                    269:        mmu_tt[n].base = lbase | (((uint64)sbase) << 32);
                    270:        mmu_tt[n].mask = lmask | (((uint64)smask) << 32);
                    271: 
1.1.1.10  root      272:        // 更新後にこの TT が有効ならハッシュも更新。
                    273:        if (mmu_tt[n].e) {
                    274:                // この TT#n にマッチするアドレスブロックに対応する 4096 エントリを
                    275:                // TT 印にする。
                    276:                for (uint fc = 0; fc < 8; fc++) {
                    277:                        auto *table = atc.fctables[fc];
                    278:                        if (table) {
                    279:                                busaddr laddr = busaddr(0) | busaddr::FC(fc);
                    280:                                for (uint i = 0; i < 256; i++) {
                    281:                                        // XXX R/W は?
                    282:                                        if (mmu_tt[n].Match(laddr)) {
                    283:                                                uint32 baseidx = i << (24 - 12);
                    284:                                                memset(&table->hash[baseidx],
                    285:                                                        m68030ATCTable::HASH_TT, 4096);
                    286:                                        }
                    287:                                        laddr += 0x0100'0000;
                    288:                                }
                    289:                        }
1.1       root      290:                }
                    291:        }
                    292: 
                    293:        mmu_enable_changed();
                    294: }
                    295: 
1.1.1.5   root      296: // アクセスがこの TT とマッチするか調べる。
1.1.1.9   root      297: // laddr の上位ワードはそのまま使える。
                    298: // 下位32ビットが論理アドレス (下24ビットは呼び出し側でマスクしなくてよい)。
1.1.1.5   root      299: // この TT が有効でアドレスがマッチすれば true を返す。
                    300: // (TT:E は演算に織り込んである、このすぐ上の SetTT() のコメント参照)
1.1       root      301: bool
1.1.1.9   root      302: m68030TT::Match(busaddr laddr) const
1.1       root      303: {
1.1.1.9   root      304:        bool rv = (((laddr.Get() ^ base) & mask) == 0);
1.1       root      305:        return rv;
                    306: }
                    307: 
                    308: // 成功すれば true、MMU 構成例外が起きる場合は false を返す。
                    309: // 呼び出し側で例外を起こすこと。
                    310: bool
1.1.1.11! root      311: MPU68030Device::SetTC(uint32 data)
1.1       root      312: {
                    313:        // マスクしてレジスタイメージにセット
                    314:        reg.tc = data & m68030TC::MASK;
                    315: 
                    316:        // data を分解してメンバにセット
                    317:        mmu_tc.Set(data);
                    318: 
                    319:        // 有効にする場合は一貫性を確認
                    320:        if (mmu_tc.e) {
                    321:                if (mmu_tc.Check() == false) {
                    322:                        // エラーなら E をクリアして MMU 構成例外。
                    323:                        // (例外処理自体は呼び出し側で行う)
1.1.1.9   root      324:                        mmu_tc.e = false;
1.1       root      325:                        mmu_enable_changed();
                    326:                        return false;
                    327:                }
                    328:        }
                    329: 
                    330:        // マスクをあらかじめ用意しておく
                    331:        mmu_tc.MakeMask();
                    332: 
1.1.1.10  root      333:        // ATC でも PS を覚えておく必要がある。
                    334:        for (int i = 0; i < countof(atc.tables); i++) {
                    335:                auto *table = atc.tables[i].get();
                    336:                table->ps4k = mmu_tc.ps - 12;
                    337:        }
                    338: 
1.1       root      339:        // TC:E が変更されていればスイッチ更新
                    340:        mmu_enable_changed();
                    341:        return true;
                    342: 
                    343: }
                    344: 
                    345: // TC レジスタへの書き込み値を m68030TC クラスにセットする。
                    346: void
                    347: m68030TC::Set(uint32 data)
                    348: {
                    349:        e   = data & TC_E;
                    350:        sre = data & TC_SRE;
                    351:        fcl = data & TC_FCL;
                    352:        tid = (data)       & 0x0f;
                    353:        tic = (data >>= 4) & 0x0f;
                    354:        tib = (data >>= 4) & 0x0f;
                    355:        tia = (data >>= 4) & 0x0f;
                    356:        is  = (data >>= 4) & 0x0f;
                    357:        ps  = (data >>= 4) & 0x0f;
                    358: }
                    359: 
                    360: // 現在の値が MMU 構成例外になるなら false を返す。
                    361: bool
                    362: m68030TC::Check() const
                    363: {
                    364:        if (ps < 8)
                    365:                return false;
                    366:        if (tia == 0)
                    367:                return false;
                    368:        if (tib == 0 && (tic > 0 || tid > 0))
                    369:                return false;
                    370:        if (tic == 0 && tid > 0)
                    371:                return false;
                    372:        if (ps + is + tia + tib + tic + tid != 32)
                    373:                return false;
                    374: 
                    375:        return true;
                    376: }
                    377: 
                    378: // 論理マスク、ページマスクを作成。(テーブルサーチで参照される)
                    379: void
                    380: m68030TC::MakeMask()
                    381: {
                    382:        // lmask (論理マスク) は TIA〜TID 部分のマスク。
                    383:        // pgmask (ページマスク) は PS 部分のマスク。
                    384:        //
                    385:        // 例えば IS=$8, TIA=$3, TIB=$4, TIC=$4, TID=$0, PS=$d
                    386:        // (X68030 IPL 内の MMU 判定のケース) なら
                    387:        //
                    388:        //           3          2          1          0
                    389:        //          10987654 32109876 54321098 76543210
                    390:        //         +--------+--------+--------+--------+
                    391:        //         |IIIIIIII AAABBBBC CCCPPPPP PPPPPPPP|
                    392:        //         +--------+--------+--------+--------+
                    393:        // lmask  = 00000000 11111111 11100000 00000000
                    394:        // pgmask = 00000000 00000000 00011111 11111111
                    395:        lmask = (1 << (tia + tib + tic + tid)) - 1;
                    396:        lmask <<= ps;
                    397:        pgmask = (1 << ps) - 1;
                    398: 
                    399:        // アドレスを (IS,) TIA 〜 TID に分解。
                    400:        //
                    401:        // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。
                    402:        // 使ってない TIC, TID については tix[TIC] == 0 で判断する。
                    403:        //
                    404:        //                    A              B             PS
                    405:        //           +----------------+--------------+--------------+
                    406:        // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx |
                    407:        //           +----------------+--------------+--------------+
                    408:        //            shift[TIA]=20     shift[TIB]=10
                    409:        //            mask[TIA]=0xfff   mask[TIB]=0x3ff
1.1.1.10  root      410:        uint sh = ps;
1.1       root      411:        for (int i = TID; i >= TIA; i--) {
                    412:                if (tix[i] > 0) {
                    413:                        shift[i] = sh;
                    414:                        mask[i] = (1 << tix[i]) - 1;
                    415:                        sh += tix[i];
                    416:                }
                    417:        }
                    418: }
                    419: 
                    420: void
1.1.1.11! root      421: MPU68030Device::SetMMUSR(uint16 data)
1.1       root      422: {
                    423:        reg.mmusr = data & m68030MMUSR::MASK;
                    424: }
                    425: 
1.1.1.11! root      426: // リセット例外の CPU 固有部分。
        !           427: void
        !           428: MPU68030Device::ResetMMU()
        !           429: {
        !           430:        SetTC(GetTC() & ~m68030TC::TC_E);
        !           431:        SetTT(0, GetTT(0) & ~m68030TT::E);
        !           432:        SetTT(1, GetTT(1) & ~m68030TT::E);
        !           433: }
        !           434: 
1.1       root      435: 
                    436: //
                    437: // ATC
                    438: //
1.1.1.10  root      439: // 今となっては独立したクラスである必要はなくなっているが、これを
1.1.1.11! root      440: // MPU68030Device にマージするとパフォーマンスが下がるので維持してある。
1.1.1.10  root      441: //
1.1       root      442: 
                    443: // コンストラクタ
1.1.1.11! root      444: m68030ATC::m68030ATC(MPU68030Device *cpu_)
1.1.1.8   root      445: {
                    446:        cpu = cpu_;
1.1.1.9   root      447: 
1.1.1.10  root      448:        tables[0].reset(new m68030ATCTable(cpu, 1));
                    449:        tables[1].reset(new m68030ATCTable(cpu, 2));
                    450:        tables[2].reset(new m68030ATCTable(cpu, 5));
                    451:        tables[3].reset(new m68030ATCTable(cpu, 6));
                    452: 
                    453:        fctables[1] = tables[0].get();
                    454:        fctables[2] = tables[1].get();
                    455:        fctables[5] = tables[2].get();
                    456:        fctables[6] = tables[3].get();
1.1.1.8   root      457: }
                    458: 
                    459: // デストラクタ
                    460: m68030ATC::~m68030ATC()
1.1       root      461: {
                    462: }
                    463: 
1.1.1.9   root      464: // ログレベルの設定。
                    465: // これは Object のオーバーライドではないが、同じ使い方をする。
                    466: void
                    467: m68030ATC::SetLogLevel(int loglevel_)
                    468: {
                    469:        loglevel = loglevel_;
1.1.1.10  root      470:        for (int i = 0; i < countof(tables); i++) {
                    471:                auto *table = tables[i].get();
                    472:                table->loglevel = loglevel_;
1.1.1.9   root      473:        }
                    474: }
                    475: 
1.1.1.10  root      476: // ATC をすべてフラッシュする。命令からコールされる
1.1       root      477: void
1.1.1.10  root      478: m68030ATC::flush()
1.1       root      479: {
1.1.1.10  root      480:        for (int i = 0; i < countof(tables); i++) {
                    481:                auto *table = tables[i].get();
                    482:                table->Flush();
1.1       root      483:        }
                    484: }
                    485: 
1.1.1.10  root      486: // ATC の fc, mask が一致するエントリをフラッシュする。
                    487: // 命令からコールされる。
1.1       root      488: void
1.1.1.10  root      489: m68030ATC::flush(uint32 fc, uint32 mask)
1.1       root      490: {
1.1.1.10  root      491:        for (uint i = 0; i < 8; i++) {
                    492:                if (((i ^ fc) & mask) == 0) {
                    493:                        // FC が一致したテーブルを全フラッシュ
                    494:                        auto *table = fctables[i];
                    495:                        if (table) {
                    496:                                table->Flush();
                    497:                        }
1.1       root      498:                }
                    499:        }
                    500: }
                    501: 
1.1.1.10  root      502: // ATC の fc, mask, addr が一致するエントリをフラッシュする。
                    503: // 命令からコールされる。
1.1       root      504: void
1.1.1.10  root      505: m68030ATC::flush(uint32 fc, uint32 mask, uint32 addr)
1.1       root      506: {
1.1.1.10  root      507:        for (uint i = 0; i < 8; i++) {
                    508:                if (((i ^ fc) & mask) == 0) {
                    509:                        // FC が一致したテーブルから addr が一致したエントリをフラッシュ
                    510:                        auto *table = fctables[i];
                    511:                        if (table) {
                    512:                                table->Flush(addr);
                    513:                        }
                    514:                }
1.1       root      515:        }
                    516: }
                    517: 
                    518: 
1.1.1.10  root      519: //
                    520: // ATC テーブル
                    521: //
1.1       root      522: 
1.1.1.10  root      523: // アドレス変換の本来のフローはこんな感じだが、
                    524: //
                    525: //  if (TT*.E || TC.E) {
                    526: //     if (TT*.E が有効) {
                    527: //             laddr,RW が TT[01] とマッチしたら、paddr = laddr,CI
                    528: //     }
                    529: //     if (TC.E が有効) {
                    530: //             ATC とマッチしたら、paddr = atc[n].paddr,CI
                    531: //             そうでなければ、 paddr = テーブルサーチ
                    532: //     }
                    533: //  } else {
                    534: //     paddr = laddr (アドレス変換オフ)
                    535: //  }
                    536: //
                    537: // ハッシュで一度に引く。
                    538: //     switch (hash[laddr>>12]) {
                    539: //   case HASH_TT:
                    540: //     laddr,RW が TT[01] とマッチしたら、paddr = laddr,CI
                    541: //   case HASH_ATC:
                    542: //     paddr = atc[n].paddr,CI
                    543: //   case HASH_NONE:
                    544: //     TC.E なら paddr = テーブルサーチ
                    545: //     そうでなければ、paddr = laddr (アドレス変換オフ)
                    546: //   case HASH_SUB:
                    547: //     PS が 4KB 未満だとハッシュの1エントリに2つ以上が混在するので、
                    548: //     この場合は諦めて ATC を線形探索。通常起きないので性能無視。
                    549: //  }
                    550: 
                    551: // ATC テーブルは本来は 1つ(FC混合) x 22 ラインだが、
                    552: // 高速化のため FC別(4テーブル) x 22 ラインのモードを用意する。
                    553: // FC 混合版ではテーブルは tables[0] のみで、FC(1,0,2) は busaddr の
                    554: // 34-32 ビット部分として laddr と一緒に検索キーにする。
                    555: // FC 分離版ではテーブルは fctables[fc] で検索キーは laddr(下位32ビット部分)。
                    556: //
                    557: // ハッシュなのでライン間の順序関係はないが、LRU で古いのを捨てる時や
                    558: // PS<4K の時に前から探索する時のために、age を使った順序管理をする。
                    559: // ラインを使用するたびに age に ++latest_age を代入しておくことで、
                    560: // 順序が必要な時には age の大きい順にすれば最近使った順になる。
                    561: // 32 ビット符号なし整数が折り返すと事故るがたぶんそれより高い頻度で
                    562: // フラッシュが起きるんじゃないかな…
1.1       root      563: 
1.1.1.10  root      564: // コンストラクタ
1.1.1.11! root      565: m68030ATCTable::m68030ATCTable(MPU68030Device *cpu_, uint fc_)
1.1       root      566: {
1.1.1.10  root      567:        cpu = cpu_;
                    568:        fc = fc_;
1.1       root      569: 
1.1.1.10  root      570:        std::fill(hash.begin(), hash.end(), HASH_NONE);
1.1       root      571: 
1.1.1.10  root      572:        latest_age = 0;
                    573:        Flush();
1.1       root      574: }
                    575: 
1.1.1.10  root      576: // デストラクタ
                    577: m68030ATCTable::~m68030ATCTable()
1.1       root      578: {
                    579: }
                    580: 
1.1.1.10  root      581: // この ATC テーブルのエントリをすべてフラッシュする。
                    582: void
                    583: m68030ATCTable::Flush()
1.1       root      584: {
1.1.1.10  root      585:        for (int i = 0; i < LINES; i++) {
                    586:                Invalidate(&line[i]);
                    587:        }
1.1       root      588: }
                    589: 
1.1.1.10  root      590: // この ATC テーブルから addr が一致するエントリをすべてフラッシュする。
                    591: void
                    592: m68030ATCTable::Flush(uint32 addr)
1.1       root      593: {
1.1.1.10  root      594:        for (int i = 0; i < LINES; i++) {
                    595:                m68030ATCLine *a = &line[i];
                    596:                if (a->GetTag() == addr) {
                    597:                        Invalidate(a);
1.1       root      598:                }
                    599:        }
                    600: }
                    601: 
1.1.1.10  root      602: // この要素を先頭に移動。
                    603: inline void
                    604: m68030ATCTable::MoveHead(m68030ATCLine *a)
1.1       root      605: {
1.1.1.10  root      606:        a->age = ++latest_age;
1.1       root      607: }
                    608: 
1.1.1.10  root      609: // このテーブルのうち最も古い要素を差し出す。
1.1       root      610: m68030ATCLine *
1.1.1.10  root      611: m68030ATCTable::RemoveTail()
1.1       root      612: {
1.1.1.10  root      613:        m68030ATCLine *a = NULL;
                    614:        uint32 min = (uint32)~0;
                    615:        uint32 minidx = 0;
1.1       root      616: 
1.1.1.10  root      617:        // 最後に使われたの (あるいは空き) を探す。
                    618:        for (int i = 0; i < LINES; i++) {
                    619:                if (line[i].IsInvalid()) {
                    620:                        a = &line[i];
                    621:                        break;
1.1       root      622:                }
1.1.1.10  root      623:                if (line[i].age < min) {
                    624:                        min = line[i].age;
1.1       root      625:                        minidx = i;
                    626:                }
                    627:        }
1.1.1.10  root      628:        if (a == NULL) {
                    629:                a = &line[minidx];
1.1       root      630:        }
                    631: 
1.1.1.10  root      632:        // ハッシュから削除。
                    633:        Invalidate(a);
1.1       root      634: 
                    635:        return a;
                    636: }
                    637: 
1.1.1.10  root      638: // a からハッシュを作成する。
1.1       root      639: void
1.1.1.10  root      640: m68030ATCTable::MakeHash(m68030ATCLine *a)
1.1       root      641: {
1.1.1.10  root      642:        uint32 addr4k = a->GetLAddr() >> 12;
                    643:        int idx = a - &line[0];
                    644: 
                    645:        if (__predict_true(ps4k == 0)) {
                    646:                hash[addr4k] = idx;
                    647:        } else if (ps4k > 0) {
                    648:                for (int i = 0; i < (1 << ps4k); i++) {
                    649:                        hash[addr4k + i] = idx;
                    650:                }
                    651:        } else {
                    652:                hash[addr4k] = HASH_SUB;
1.1       root      653:        }
                    654: }
                    655: 
1.1.1.10  root      656: // ATC a を無効にする。すでに無効なら何もしない。
1.1       root      657: void
1.1.1.10  root      658: m68030ATCTable::Invalidate(m68030ATCLine *a)
1.1       root      659: {
1.1.1.10  root      660:        if (a->IsValid()) {
                    661:                // 有効ならハッシュから削除。
                    662:                if (__predict_true(ps4k == 0)) {
                    663:                        uint32 addr4k = a->GetLAddr() >> 12;
                    664:                        hash[addr4k] = HASH_NONE;
                    665:                } else if (ps4k > 0) {
                    666:                        // PS>4KB
                    667:                        uint32 addr4k = a->GetLAddr() >> 12;
                    668:                        for (int i = 0; i < (1U << ps4k); i++) {
                    669:                                hash[addr4k + i] = HASH_NONE;
                    670:                        }
                    671:                } else {
                    672:                        // PS<4KB、自分が抜けることでこの枠が空くかどうか
                    673:                        InvalidateSub(a);
1.1       root      674:                }
1.1.1.10  root      675: 
                    676:                a->Invalidate();
1.1       root      677:        }
                    678: }
                    679: 
1.1.1.10  root      680: // PS<4KB の場合に aa が抜けることでこの addr4k の枠が空けばハッシュから削除。
1.1       root      681: void
1.1.1.10  root      682: m68030ATCTable::InvalidateSub(const m68030ATCLine *aa)
1.1       root      683: {
1.1.1.10  root      684:        const uint32 MASK_4K = 0xfffff000 | m68030ATCLine::INVALID;
                    685:        uint32 target_laddr = aa->GetTag() & MASK_4K;
                    686:        bool in_use = false;
                    687: 
                    688:        for (int i = 0; i < LINES; i++) {
                    689:                auto *a = &line[i];
                    690:                // 自分自身は今から削除予定なので除く。
                    691:                if (a == aa) {
                    692:                        continue;
                    693:                }
                    694:                // それ以外で有効なものがあるか。
                    695:                if ((a->GetTag() & MASK_4K) == target_laddr) {
                    696:                        in_use = true;
                    697:                        break;
1.1       root      698:                }
                    699:        }
                    700: 
1.1.1.10  root      701:        // 誰もいなくなれば削除。
                    702:        if (in_use == false) {
                    703:                hash[target_laddr >> 12] = HASH_NONE;
1.1       root      704:        }
                    705: }
                    706: 
1.1.1.10  root      707: // laddr を ATC から探す。見つからなければ NULL を返す。
                    708: m68030ATCLine *
                    709: m68030ATCTable::FindSub(const busaddr laddr)
1.1       root      710: {
1.1.1.10  root      711:        uint32 addr = laddr.Addr() & cpu->mmu_tc.lmask;
                    712: 
                    713:        // 同じエントリはないはずなので、順序通りに探さなくてもいいはず。
                    714:        for (int i = 0; i < LINES; i++) {
                    715:                auto *a = &line[i];
                    716:                if (a->GetTag() == addr) {
                    717:                        return a;
1.1       root      718:                }
                    719:        }
1.1.1.10  root      720:        return NULL;
1.1       root      721: }
1.1.1.10  root      722: 
                    723: // テーブルサーチを行う。
                    724: // テーブルという用語がぶつかっているので MMU Search にしてある。
                    725: m68030ATCLine *
                    726: m68030ATCTable::MMUSearch(busaddr laddr)
1.1       root      727: {
1.1.1.10  root      728:        m68030ATCLine *a = RemoveTail();
                    729:        a->tag = laddr.Addr() & cpu->mmu_tc.lmask;
                    730: 
                    731:        m68030MMU mmu(cpu, loglevel);
                    732:        mmu.search(7, laddr);
                    733:        mmu.make_atc(a);
                    734: 
                    735:        MakeHash(a);
                    736:        return a;
1.1       root      737: }
                    738: 
1.1.1.10  root      739: // デバッグ表示。
                    740: std::string
                    741: m68030ATCTable::LineToStr(const m68030ATCLine *a) const
1.1       root      742: {
1.1.1.10  root      743:        uint32 laddr = a->GetLAddr();
                    744: 
                    745:        if (!a->IsBusError()) {
                    746:                uint32 paddr = a->GetPAddr();
                    747:                uint32 ci    = a->IsCInhibit();
                    748:                uint32 wp    = a->IsWProtect();
                    749:                uint32 mod   = a->IsModified();
                    750:                return indent_format(1,
                    751:                        "ATC: match %u:$%08x -> $%08x CI=%u WP=%u M=%u",
                    752:                        fc, laddr, paddr, ci, wp, mod);
                    753:        } else {
                    754:                return indent_format(1,
                    755:                        "ATC: match %u:$%08x -> BusErr",
                    756:                        fc, laddr);
1.1       root      757:        }
                    758: }
                    759: 
                    760: 
                    761: //
                    762: // テーブルサーチ
                    763: //
                    764: 
                    765: // コンストラクタ
1.1.1.11! root      766: m68030MMU::m68030MMU(MPU68030Device *cpu_, int loglevel_)
1.1       root      767: {
1.1.1.8   root      768:        cpu = cpu_;
1.1.1.9   root      769:        loglevel = loglevel_;
1.1       root      770: 
                    771:        m_type = INVALID;
                    772:        x = -1;
                    773: }
                    774: 
1.1.1.8   root      775: // デストラクタ
                    776: m68030MMU::~m68030MMU()
                    777: {
                    778: }
                    779: 
1.1       root      780: // テーブルサーチのメイン部分。
                    781: // m_type および ATC 作成に必要な情報を埋めてから帰る。
                    782: // ATC は帰った先で作成する。
                    783: void
1.1.1.10  root      784: m68030MMU::search(int level, busaddr laddr)
1.1       root      785: {
                    786:        const char *rpname;
1.1.1.10  root      787:        uint32 addr;
                    788:        uint32 fc;
1.1       root      789:        int dt;
                    790:        bool is_super;
                    791: 
1.1.1.10  root      792:        addr = laddr.Addr();
                    793:        fc   = laddr.GetFC();
1.1       root      794: 
1.1.1.10  root      795:        is_super = (fc & 0x04);
1.1       root      796: 
                    797:        // アドレスを (IS,) TIA .. TID に分解。
                    798:        //
                    799:        // TIA=$C, TIB=$A, (TIC = TID = 0), PS=$A の場合以下のようにする。
                    800:        // 使ってない TIC, TID については cpu->mmu_tc->{tic,tid} == 0 で判断する。
                    801:        //
                    802:        //                    A              B             PS
                    803:        //           +----------------+--------------+--------------+
                    804:        // $00A01A00 | 0000 0000 1010 | 0000 0001 10 | xx xxxx xxxx |
                    805:        //           +----------------+--------------+--------------+
                    806:        //            shift[TIA] =20   shift[TIB] =10
                    807:        //            lv[TIA].idx=0xA  lv[TIB].idx=0x6
                    808:        //
                    809:        for (int i = TID; i >= TIA; i--) {
                    810:                if (cpu->mmu_tc.tix[i] > 0) {
                    811:                        uint32 mask = cpu->mmu_tc.mask[i];
1.1.1.10  root      812:                        m_lv[i] = (addr >> cpu->mmu_tc.shift[i]) & mask;
1.1       root      813:                }
                    814:        }
1.1.1.10  root      815:        m_lv[FCL] = fc;
1.1       root      816: 
1.1.1.8   root      817:        cpu->putlogf(3, [&] {
1.1       root      818:                std::string buf;
                    819: 
1.1.1.10  root      820:                buf = indent_format(2, "search: laddr=$%08x ->", addr);
1.1       root      821:                if (cpu->mmu_tc.is > 0)
1.1.1.10  root      822:                        buf += string_format(" IS=%u", cpu->mmu_tc.is);
1.1       root      823:                if (cpu->mmu_tc.fcl)
1.1.1.10  root      824:                        buf += string_format(" FC=%u", m_lv[FCL]);
1.1       root      825:                for (int i = TIA; i <= TID; i++) {
                    826:                        if (cpu->mmu_tc.tix[i] > 0) {
1.1.1.10  root      827:                                buf += string_format(" %s=%u($%0*x)",
1.1       root      828:                                        m_lvname[i], cpu->mmu_tc.tix[i],
                    829:                                        NIBBLE(cpu->mmu_tc.tix[i]), m_lv[i]);
                    830:                        }
                    831:                }
1.1.1.6   root      832:                return buf;
                    833:        });
1.1       root      834: 
1.1.1.9   root      835:        // この辺に図9-26 の初期化だがコンストラクタで初期化済み。
1.1       root      836: 
                    837:        // ここから図9-25。
                    838: 
                    839:        // 使用するルートポインタを決定
                    840:        if (cpu->mmu_tc.sre && is_super) {
                    841:                rpname = "SRP";
                    842:                m_desc1 = cpu->GetSRPh();
                    843:                m_desc2 = cpu->GetSRPl();
                    844:        } else {
                    845:                rpname = "CRP";
                    846:                m_desc1 = cpu->GetCRPh();
                    847:                m_desc2 = cpu->GetCRPl();
                    848:        }
                    849: 
                    850:        // ルートポインタの DT をチェック
                    851:        dt = GET_DT(m_desc1);
1.1.1.9   root      852:        MMULOG(3, 2, "%s: %s dt=%s", lam_func, rpname, dtname(dt));
1.1       root      853:        switch (dt) {
1.1.1.8   root      854:         case DT_INVALID:
                    855:                // 無効は設定できないはずなので、ここに来ないはず
                    856:                PANIC("%s.DT==Invalid", rpname);
                    857:                break;
                    858: 
1.1       root      859:         case DT_PAGE:          // ページディスクリプタ
                    860:                m_type = EARLY;
                    861:                return;
                    862: 
                    863:         case DT_VALID4:        // 有効(4バイト)
                    864:         case DT_VALID8:        // 有効(8バイト)
                    865:                // descsize は DT=$2 なら 4、DT=$3 なら 8 になる
                    866:                m_descsize = 1 << dt;
                    867:                m_lastsize = 8;
                    868:                break;
                    869:        }
                    870: 
                    871:        // 必要ならファンクションコード・ルックアップ
                    872:        if (cpu->mmu_tc.fcl) {
                    873:                x = FCL;
1.1.1.8   root      874:                // たぶん検索レベルを1つ消費するはず。未確認。
                    875:                level--;
                    876: 
1.1.1.9   root      877:                MMULOG(3, 2, "%s: %s tableaddr=$%08x idx=$%x", lam_func,
1.1       root      878:                        m_lvname[x], m_desc2, m_lv[x]);
                    879: 
                    880:                // ディスクリプタをフェッチ
                    881:                if (fetch_desc(m_desc2, m_lv[x]) == false) {
                    882:                        return;
                    883:                }
                    884: 
                    885:                // ディスクリプタタイプをチェック
                    886:                dt = GET_DT(m_desc1);
                    887:                switch (dt) {
                    888:                 case DT_INVALID:       // 無効
                    889:                        m_type = INVALID;
                    890:                        return;
                    891: 
                    892:                 case DT_PAGE:          // ページディスクリプタ
                    893:                        m_type = EARLY;
                    894:                        return;
                    895: 
                    896:                 case DT_VALID4:        // 有効4バイト
                    897:                 case DT_VALID8:        // 有効8バイト
                    898:                        m_lastsize = m_descsize;
                    899:                        m_descsize = 1 << dt;
                    900:                        break;
                    901:                }
                    902:        }
                    903: 
                    904:        // TIx のテーブルサーチに入る。図9-25 の下半分。
                    905: 
1.1.1.8   root      906:        for (x = TIA; x < level; x++) {
1.1       root      907:                // リミットチェック
                    908:                if (m_lastsize == 8 && limitcheck() == false) {
                    909:                        m_type = INVALID;
1.1.1.9   root      910:                        m_lim = true;
1.1       root      911:                        return;
                    912:                }
                    913: 
                    914:                // テーブルアドレス
                    915:                uint32 tableaddr;
                    916:                tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2;
                    917:                tableaddr &= 0xfffffff0;
1.1.1.9   root      918:                MMULOG(3, 2, "%s: %s tableaddr=$%08x idx=$%x", lam_func,
1.1       root      919:                        m_lvname[x], tableaddr, m_lv[x]);
                    920: 
                    921:                // ディスクリプタをフェッチ
                    922:                if (fetch_desc(tableaddr, m_lv[x]) == false) {
                    923:                        return;
                    924:                }
                    925: 
                    926:                // ディスクリプタタイプをチェック
                    927:                dt = GET_DT(m_desc1);
                    928:                switch (dt) {
                    929:                 case DT_INVALID:       // 無効
                    930:                        m_type = INVALID;
                    931:                        return;
                    932: 
                    933:                 case DT_PAGE:          // ページディスクリプタ
                    934:                        if (x == TID) {
                    935:                                m_type = NORMAL;
                    936:                        } else {
                    937:                                if (cpu->mmu_tc.tix[x + 1] == 0) {
                    938:                                        m_type = NORMAL;
                    939:                                } else {
                    940:                                        m_type = EARLY;
                    941:                                }
                    942:                        }
                    943:                        return;
                    944: 
                    945:                 case DT_VALID4:        // 有効4バイト
                    946:                 case DT_VALID8:        // 有効8バイト
                    947:                        m_lastsize = m_descsize;
                    948:                        m_descsize = 1 << dt;
                    949: 
                    950:                        if (x == TID || cpu->mmu_tc.tix[x + 1] == 0) {
                    951:                                // 間接
                    952:                                m_type = INDIRECT;
                    953: 
                    954:                                // ディスクリプタをフェッチ
                    955:                                tableaddr = (m_lastsize == 4) ? m_desc1 : m_desc2;
                    956:                                tableaddr &= 0xfffffff0;
                    957:                                if (fetch_desc(tableaddr, 0) == false) {
                    958:                                        return;
                    959:                                }
                    960:                                if (GET_DT(m_desc1) != DT_PAGE) {
                    961:                                        m_type = INVALID;
                    962:                                }
                    963:                                return;
                    964:                        }
                    965:                        // 次段のサーチを繰り返す
1.1.1.8   root      966:                        break;
1.1       root      967:                }
                    968:        }
1.1.1.8   root      969: 
                    970:        // レベル上限にひっかかった場合、x は過ぎているので一つ戻しておく。
                    971:        x--;
1.1       root      972: }
                    973: 
                    974: // リミットチェックを実行。図9-28。
                    975: // 無効のケースに落ちたら false を返す。
                    976: bool
                    977: m68030MMU::limitcheck() const
                    978: {
1.1.1.8   root      979:        uint16 limit = (m_desc1 >> 16) & 0x7fff;
1.1       root      980: 
1.1.1.8   root      981:        // 最上位ビットが L/U
                    982:        if ((int32)m_desc1 < 0) {
                    983:                if (m_lv[x] < limit) {
1.1.1.9   root      984:                        MMULOG(3, 2, "%s: $%04x < $%04x", lam_func, m_lv[x], limit);
1.1.1.8   root      985:                        return false;
                    986:                }
                    987:        } else {
                    988:                if (m_lv[x] > limit) {
1.1.1.9   root      989:                        MMULOG(3, 2, "%s: $%04x > $%04x", lam_func, m_lv[x], limit);
1.1.1.8   root      990:                        return false;
                    991:                }
1.1       root      992:        }
                    993:        return true;
                    994: }
                    995: 
                    996: // ディスクリプタ中のフラグの更新 (を予約する)
                    997: #define UPDATE_DESC(flag)      do { \
                    998:        if ((m_desc1 & (flag)) == 0) { \
                    999:                m_desc1 |= (flag); \
                   1000:                do_write = true; \
                   1001:        } \
                   1002: } while (0)
                   1003: 
                   1004: // ディスクリプタのフェッチと、ヒストリおよびステータスの更新。
                   1005: // 図9-29。
                   1006: // ディスクリプタを取得できれば true、
                   1007: // ATC エントリの作成に向かう場合は false。
                   1008: bool
                   1009: m68030MMU::fetch_desc(uint32 tableaddr, int idx)
                   1010: {
                   1011:        uint32 descaddr;
                   1012:        bool do_write;
                   1013:        uint dt;
                   1014: 
                   1015:        // ディスクリプタのアドレスを計算。ここだけマニュアルの説明が雑すぎ。
                   1016:        // インダイレクトなら idx = 0 でコールしてあるので、
                   1017:        // tableaddr がそのまま PA になるという寸法。
                   1018:        descaddr = tableaddr + idx * m_descsize;
1.1.1.10  root     1019:        MMULOG(3, 2, "%s: descsize=%u descaddr=$%08x", lam_func,
1.1       root     1020:                m_descsize, descaddr);
                   1021: 
                   1022:        // バスエラー発生フラグをクリアしておく
                   1023:        m_berr = false;
                   1024: 
                   1025:        // ディスクリプタを取得
                   1026:        if (m_debugger) {
                   1027:                // デバッガアクセス
                   1028:                uint64 data;
1.1.1.10  root     1029:                data = cpu->mainbus->Peek4(descaddr);
1.1       root     1030:                if ((int64)data < 0) {
                   1031:                        goto buserr;
                   1032:                }
                   1033:                m_desc1 = data;
                   1034: 
                   1035:                if (m_descsize == 8) {
1.1.1.10  root     1036:                        data = cpu->mainbus->Peek4(descaddr + 4);
1.1       root     1037:                        if ((int64)data < 0) {
                   1038:                                goto buserr;
                   1039:                        }
                   1040:                        m_desc2 = data;
                   1041:                }
                   1042:        } else {
1.1.1.9   root     1043:                busdata bd;
1.1       root     1044: 
1.1.1.11! root     1045:                bd = cpu->read_phys_4(descaddr);
1.1.1.9   root     1046:                if (bd.IsBusErr()) {
1.1       root     1047:                        goto buserr;
                   1048:                }
1.1.1.9   root     1049:                m_desc1 = bd.Data();
1.1       root     1050: 
                   1051:                if (m_descsize == 8) {
1.1.1.11! root     1052:                        bd = cpu->read_phys_4(descaddr + 4);
1.1.1.9   root     1053:                        if (bd.IsBusErr()) {
1.1       root     1054:                                goto buserr;
                   1055:                        }
1.1.1.9   root     1056:                        m_desc2 = bd.Data();
1.1       root     1057:                }
1.1.1.8   root     1058: 
                   1059:                m_lastaddr = descaddr;
1.1       root     1060:        }
                   1061: 
                   1062:        // ディスクリプタタイプをチェック
                   1063:        // DT は必ず最初のロングワードの下位2ビット。
                   1064:        do_write = false;
                   1065:        dt = GET_DT(m_desc1);
1.1.1.9   root     1066:        MMULOG(3, 2, "%s: desc=%s dt=%s", lam_func,
1.1       root     1067:                sprintf_desc().c_str(), dtname(dt));
                   1068:        switch (dt) {
                   1069:         case DT_INVALID:       // 無効
                   1070:                return true;
                   1071: 
                   1072:         case DT_PAGE:          // ページディスクリプタ
                   1073:                // U ビットを更新
                   1074:                UPDATE_DESC(MMU_DESC_U);
                   1075: 
                   1076:                // 書き込み操作なら M を更新
                   1077:                if (cpu->bus.IsWrite() && !m_ptest) {
                   1078:                        UPDATE_DESC(MMU_DESC_M);
                   1079:                }
                   1080:                // 図にはないけど、ATC 更新のためと PTEST のために
                   1081:                // ページディスクリプタの M ビットを記録。
                   1082:                if ((m_desc1 & MMU_DESC_M))
1.1.1.9   root     1083:                        m_m = true;
1.1       root     1084:                break;
                   1085: 
                   1086:         case DT_VALID4:        // 有効4バイト
                   1087:         case DT_VALID8:        // 有効8バイト
                   1088:                // U ビットを更新
                   1089:                UPDATE_DESC(MMU_DESC_U);
                   1090:                break;
                   1091:        }
                   1092: 
                   1093:        // デバッガ自身がアドレス変換を実施している時は書き込みは行わない
                   1094:        if (m_debugger) {
                   1095:                do_write = false;
                   1096:        }
                   1097: 
                   1098:        // ライトライクルの実行
                   1099:        if (do_write) {
1.1.1.11! root     1100:                busdata bd = cpu->write_phys_4(descaddr, m_desc1);
1.1.1.9   root     1101:                if (bd.IsBusErr()) {
1.1       root     1102:                        goto buserr;
                   1103:                }
                   1104:                // バス動作正常終了
1.1.1.9   root     1105:                MMULOG(3, 2, "%s: desc=%s updated", lam_func, sprintf_desc().c_str());
1.1       root     1106:        }
                   1107: 
1.1.1.9   root     1108:        // ステータス更新 (OR していく)
1.1       root     1109:        // XXX 実際には CI はページディスクリプタにしかないけど
1.1.1.9   root     1110:        m_wp |= (m_desc1 & MMU_DESC_WP);
                   1111:        m_ci |= (m_desc1 & MMU_DESC_CI);
                   1112:        if (__predict_false(m_descsize == 8)) {
                   1113:                m_s |= (m_desc1 & MMU_DESC_S);
1.1       root     1114:        }
                   1115: 
                   1116:        return true;
                   1117: 
                   1118:        // バスエラー
                   1119:  buserr:
                   1120:        m_type = INVALID;
                   1121:        m_berr = true;
                   1122:        return false;
                   1123: }
                   1124: 
                   1125: // ATC エントリを作成。実行系用。
                   1126: // 図9-27 だが雑すぎ。
                   1127: void
                   1128: m68030MMU::make_atc(m68030ATCLine *a)
                   1129: {
                   1130:        std::string buf;
                   1131:        uint32 paddr;
                   1132: 
                   1133:        a->data = 0;
                   1134:        switch (m_type) {
                   1135:         case INVALID:  // 無効
                   1136:                a->data |= m68030ATCLine::BUSERROR;
1.1.1.9   root     1137:                MMULOG(3, 2, "%s: type=INVALID -> BusErr", lam_func);
1.1       root     1138:                return;
                   1139: 
                   1140:         case NORMAL:   // ノーマル
                   1141:         case INDIRECT: // 間接
                   1142:                paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1.1.1.9   root     1143:                MMULOG(3, 2, "%s: type=NORMAL paddr=$%08x", lam_func,
                   1144:                        paddr & 0xffffff00);
1.1       root     1145:                break;
                   1146: 
                   1147:         case EARLY:    // アーリーターミネーション
                   1148:                paddr = (m_descsize == 4) ? m_desc1 : m_desc2;
1.1.1.9   root     1149:                buf = string_format("type=EARLY paddr=$%08x", paddr & 0xffffff00);
1.1       root     1150: 
                   1151:                // 残ってるビットも足して返す
                   1152:                for (int i = x + 1; i <= TID; i++) {
                   1153:                        if (cpu->mmu_tc.tix[i] > 0) {
                   1154:                                paddr |= m_lv[i] << cpu->mmu_tc.shift[i];
                   1155:                                buf += string_format(" +%s=%08x", m_lvname[i], paddr);
                   1156:                        }
                   1157:                }
1.1.1.9   root     1158:                MMULOG(3, 2, "%s: %s", lam_func, buf.c_str());
1.1       root     1159:                break;
                   1160:         default:
1.1.1.10  root     1161:                PANIC("corrupted m_type=%u", (uint)m_type);
1.1       root     1162:        }
                   1163: 
                   1164:        // PS の部分は反映しない
                   1165:        a->paddr = paddr & cpu->mmu_tc.lmask;
                   1166: 
1.1.1.9   root     1167:        if (m_ci)
                   1168:                a->data |= m68030ATCLine::CINHIBIT;
1.1       root     1169:        if (m_wp)
                   1170:                a->data |= m68030ATCLine::WPROTECT;
                   1171:        if (m_m)
                   1172:                a->data |= m68030ATCLine::MODIFIED;
                   1173: }
                   1174: 
                   1175: // make_atc() と同様にテーブルサーチの結果から物理ページアドレスを返す。
1.1.1.9   root     1176: // バスエラーになるケースなら BusErr を返す。
1.1       root     1177: // デバッガアクセスなので、VM に一切干渉しない。
1.1.1.9   root     1178: busaddr
                   1179: m68030MMU::make_atc_debugger() const
1.1       root     1180: {
1.1.1.10  root     1181:        busaddr paddr;
1.1       root     1182: 
                   1183:        switch (m_type) {
                   1184:         case INVALID:  // 無効
1.1.1.10  root     1185:                paddr = BusAddr::BusErr;
1.1       root     1186:                break;
                   1187: 
                   1188:         case NORMAL:   // ノーマル
                   1189:         case INDIRECT: // 間接
1.1.1.10  root     1190:         {
                   1191:                uint32 descaddr;
                   1192:                descaddr = (m_descsize == 4) ? m_desc1 : m_desc2;
                   1193:                descaddr &= 0xffffff00;
                   1194:                paddr = busaddr(descaddr);
1.1       root     1195:                break;
1.1.1.10  root     1196:         }
1.1       root     1197: 
                   1198:         case EARLY:    // アーリーターミネーション
1.1.1.10  root     1199:         {
                   1200:                uint32 descaddr;
                   1201:                descaddr = (m_descsize == 4) ? m_desc1 : m_desc2;
                   1202:                descaddr &= 0xffffff00;
1.1       root     1203:                // 残ってるビットも足して返す
                   1204:                for (int i = x + 1; i <= TID; i++) {
                   1205:                        if (cpu->mmu_tc.tix[i] > 0) {
1.1.1.10  root     1206:                                descaddr |= m_lv[i] << cpu->mmu_tc.shift[i];
1.1       root     1207:                        }
                   1208:                }
1.1.1.10  root     1209:                paddr = busaddr(descaddr);
1.1       root     1210:                break;
1.1.1.10  root     1211:         }
1.1.1.9   root     1212: 
1.1       root     1213:         default:
1.1.1.10  root     1214:                PANIC("corrupted m_type=%u", (uint)m_type);
1.1       root     1215:        }
1.1.1.9   root     1216: 
1.1.1.10  root     1217:        paddr |= BusAddr::TableSearched;
1.1       root     1218:        return paddr;
                   1219: }
                   1220: 
                   1221: // ディスクリプタ表示用の文字列を返す。
                   1222: // m_descsize によって m_desc1, m_desc2 を適切に文字列にする。
                   1223: std::string
                   1224: m68030MMU::sprintf_desc()
                   1225: {
                   1226:        std::string buf;
                   1227: 
                   1228:        if (m_descsize == 4) {
                   1229:                buf = string_format("%08x", m_desc1);
                   1230:        } else {
                   1231:                buf = string_format("%08x_%08x", m_desc1, m_desc2);
                   1232:        }
                   1233: 
                   1234:        // フラグの出現条件がややこしいので注意
                   1235:        int dt = GET_DT(m_desc1);
                   1236:        buf += string_format(" (%s%s%s%c%c)",
                   1237:                ((m_descsize == 4) ? "x" : ((m_desc1 & MMU_DESC_S) ? "S" : "-")),
                   1238:                ((dt != DT_PAGE)   ? "x" : ((m_desc1 & MMU_DESC_CI) ? "C" : "-")),
                   1239:                ((dt != DT_PAGE)   ? "x" : ((m_desc1 & MMU_DESC_M)  ? "M" : "-")),
                   1240:                (m_desc1 & MMU_DESC_U)  ? 'U' : '-',
                   1241:                (m_desc1 & MMU_DESC_WP) ? 'W' : '-'
                   1242:        );
                   1243: 
                   1244:        return buf;
                   1245: }
                   1246: 
                   1247: // ディスクリプタタイプ文字列 (デバッグ用)
                   1248: const char *
                   1249: m68030MMU::dtname(uint32 dt)
                   1250: {
                   1251:        static char buf[32];
                   1252:        switch (dt) {
                   1253:         case DT_INVALID:       return "invalid";
1.1.1.4   root     1254:         case DT_PAGE:          return "page";
1.1       root     1255:         case DT_VALID4:        return "valid4";
                   1256:         case DT_VALID8:        return "valid8";
                   1257:        }
1.1.1.10  root     1258:        snprintf(buf, sizeof(buf), "(invalid DT %u)", dt);
1.1       root     1259:        return buf;
                   1260: }
                   1261: 
                   1262: // デバッグ用文字列
                   1263: const char * const m68030MMU::m_lvname[MAX_LV] = {
                   1264:        "TIA",
                   1265:        "TIB",
                   1266:        "TIC",
                   1267:        "TID",
                   1268:        "FCL",  // この順ではないが、便宜上ここにおいてある
                   1269: };
                   1270: 
                   1271: //
                   1272: // アドレス変換
                   1273: //
                   1274: 
1.1.1.9   root     1275: // 論理アドレスが TT0/TT1 どちらかと一致すれば (bus.ci を更新して) true を返す。
1.1       root     1276: // 一致しなければ false を返す。
1.1.1.8   root     1277: bool
1.1.1.11! root     1278: MPU68030Device::CheckTT()
1.1       root     1279: {
                   1280:        bool ci;
                   1281:        int match;
                   1282: 
                   1283:        match = 0;
                   1284:        ci = false;
                   1285:        for (int i = 0; i < 2; i++) {
1.1.1.8   root     1286:                const m68030TT& tt = mmu_tt[i];
1.1.1.9   root     1287:                if (tt.Match(bus.laddr)) {
1.1       root     1288:                        // 一致した
                   1289:                        match += i + 1;
                   1290:                        ci |= tt.ci != 0;
1.1.1.10  root     1291:                        putlog(3, " %s: TT%u match", __func__, i);
1.1       root     1292:                }
                   1293:        }
                   1294: 
                   1295:        // 一致したら PA <- LA
                   1296:        if (match != 0) {
1.1.1.9   root     1297:                putlog(3, "%s: result %08x (match TT%s)", __func__,
1.1.1.10  root     1298:                        bus.laddr.Addr(),
1.1       root     1299:                        (match == 3) ? "0 and TT1" : ((match == 1) ? "0" : "1"));
1.1.1.9   root     1300:                bus.ci = ci;
1.1       root     1301:                return true;
                   1302:        }
                   1303:        return false;
                   1304: }
                   1305: 
1.1.1.10  root     1306: // リード/フェッチ用のアドレス変換を行う。
1.1       root     1307: // 変換できれば true、バスエラーなら false を返す。
                   1308: bool
1.1.1.11! root     1309: MPU68030Device::TranslateRead()
1.1       root     1310: {
1.1.1.10  root     1311:        m68030ATCLine *a;
                   1312:        busaddr& laddr = bus.laddr;
                   1313:        uint32 addr = laddr.Addr();
                   1314:        uint32 fc   = laddr.GetFC();
1.1.1.9   root     1315: 
1.1       root     1316:        // 状態表示
1.1.1.9   root     1317:        putlog(3, "%s:  enter  %c:$%08x pc=%c:$%08x", __func__,
1.1.1.10  root     1318:                (laddr.IsSuper() ? 'S' : 'U'),
                   1319:                addr,
1.1.1.8   root     1320:                IsSuper() ? 'S' : 'U',
                   1321:                ppc);
1.1       root     1322: 
                   1323: 
1.1.1.10  root     1324:        m68030ATCTable *table = atc.fctables[fc];
                   1325:        uint8 n = table->hash[addr >> 12];
                   1326:        if (__predict_true((int8)n >= 0)) {
                   1327:                // ATC #(n)
                   1328:                table->atcstat.total++;
                   1329:                a = &table->line[n];
                   1330:        } else {
                   1331:                if (n == m68030ATCTable::HASH_NONE) {
                   1332:                        if (__predict_true(mmu_tc.e)) {
                   1333:                                // TC.E 有効で対応なしなら、テーブルサーチ。
                   1334:                                table->atcstat.total++;
                   1335:                                table->atcstat.miss++;
                   1336:                                a = table->MMUSearch(laddr);
                   1337:                        } else {
                   1338:                                // TC.E 無効。(total もカウントしない)
                   1339:                                return true;
                   1340:                        }
                   1341:                } else if (n == m68030ATCTable::HASH_TT) {
                   1342:                        // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。
                   1343:                        table->atcstat.total++;
                   1344:                        table->atcstat.tthit++;
                   1345:                        if (__predict_true(CheckTT())) {
                   1346:                                return true;
                   1347:                        } else {
                   1348:                                return false;
                   1349:                        }
                   1350:                } else {
                   1351:                        // PS<4KB でマッチしたので再検査。
                   1352:                        table->atcstat.total++;
                   1353:                        a = table->FindSub(laddr);
                   1354:                        if (a == NULL) {
                   1355:                                table->atcstat.miss++;
                   1356:                                a = table->MMUSearch(laddr);
                   1357:                        }
1.1       root     1358:                }
                   1359:        }
                   1360: 
1.1.1.10  root     1361:        // ATC a でマッチした
                   1362:        table->MoveHead(a);
                   1363:        putlog(3, "%s", table->LineToStr(a).c_str());
                   1364:        if (__predict_false(a->IsBusError())) {
                   1365:                return false;
                   1366:        }
                   1367:        bus.paddr.ChangeAddr(a->GetPAddr() | (addr & mmu_tc.pgmask));
                   1368:        bus.ci = a->IsCInhibit();
1.1       root     1369:        return true;
                   1370: }
                   1371: 
                   1372: // ライト用のアドレス変換を行う。
                   1373: // 変換できれば true、バスエラーなら false を返す。
                   1374: bool
1.1.1.11! root     1375: MPU68030Device::TranslateWrite()
1.1       root     1376: {
1.1.1.10  root     1377:        m68030ATCLine *a;
                   1378:        busaddr& laddr = bus.laddr;
                   1379:        uint32 addr = laddr.Addr();
                   1380:        uint32 fc   = laddr.GetFC();
1.1.1.9   root     1381: 
1.1       root     1382:        // 状態表示
1.1.1.9   root     1383:        putlog(3, "%s: enter  %c:$%08x pc=%c:$%08x", __func__,
1.1.1.10  root     1384:                (laddr.IsSuper() ? 'S' : 'U'),
                   1385:                addr,
1.1.1.8   root     1386:                IsSuper() ? 'S' : 'U',
                   1387:                ppc);
1.1       root     1388: 
1.1.1.10  root     1389:        m68030ATCTable *table = atc.fctables[fc];
                   1390:        uint8 n = table->hash[addr >> 12];
                   1391:        if (__predict_true((int8)n >= 0)) {
                   1392:                // ATC #(n)
                   1393:                table->atcstat.total++;
                   1394:                a = &table->line[n];
                   1395:        } else {
                   1396:                if (n == m68030ATCTable::HASH_NONE) {
                   1397:                        if (__predict_true(mmu_tc.e)) {
                   1398:                                // TC.E 有効で対応なしなら、テーブルサーチ。
                   1399:                                table->atcstat.total++;
                   1400:                                table->atcstat.miss++;
                   1401:                                a = table->MMUSearch(laddr);
                   1402:                        } else {
                   1403:                                // TC.E 無効。(total もカウントしない)
                   1404:                                return true;
                   1405:                        }
                   1406:                } else if (n == m68030ATCTable::HASH_TT) {
                   1407:                        // TT。CheckTT で外れたかどうかはカウントしない。ほぼ 0 なので。
                   1408:                        table->atcstat.total++;
                   1409:                        table->atcstat.tthit++;
                   1410:                        if (__predict_true(CheckTT())) {
                   1411:                                return true;
                   1412:                        } else {
                   1413:                                return false;
                   1414:                        }
                   1415:                } else {
                   1416:                        // PS<4KB でマッチしたので再検査。
                   1417:                        table->atcstat.total++;
                   1418:                        a = table->FindSub(laddr);
                   1419:                        if (a == NULL) {
                   1420:                                table->atcstat.miss++;
                   1421:                                a = table->MMUSearch(laddr);
                   1422:                        }
1.1       root     1423:                }
                   1424:        }
                   1425: 
1.1.1.10  root     1426:        // ATC a でマッチした
                   1427:        table->MoveHead(a);
1.1       root     1428: 
1.1.1.10  root     1429:        if (__predict_false(a->IsBusError())) {
                   1430:                return false;
                   1431:        }
                   1432:        if (__predict_false(a->IsWProtect())) {
                   1433:                // Write アクセスで WP が立ってたらバスエラー
                   1434:                putlog(3, "%s: result Buserr (ATC:WP)", __func__);
                   1435:                return false;
1.1       root     1436:        }
                   1437: 
1.1.1.10  root     1438:        putlog(3, "%s", table->LineToStr(a).c_str());
                   1439:        bus.paddr.ChangeAddr(a->GetPAddr() | (addr & mmu_tc.pgmask));
                   1440:        bus.ci = a->IsCInhibit();
1.1       root     1441:        return true;
                   1442: }
                   1443: 
                   1444: // ピーク用のアドレス変換を行う。
1.1.1.9   root     1445: // 変換できれば対応する物理アドレスを、バスエラーなら BusErr を返す。
                   1446: // テーブルサーチを行ったら TableSearched ビットを立てる。
                   1447: busaddr
1.1.1.11! root     1448: MPU68030Device::TranslatePeek(busaddr laddr)
1.1       root     1449: {
1.1.1.10  root     1450:        const m68030ATCLine *a;
1.1.1.9   root     1451:        busaddr paddr;
1.1.1.10  root     1452:        uint32 addr = laddr.Addr();
                   1453:        uint32 fc   = laddr.GetFC();
1.1       root     1454: 
                   1455:        // 状態表示
1.1.1.9   root     1456:        putlog(3, "%s:  enter  %c:$%08x", __func__,
1.1.1.10  root     1457:                (laddr.IsSuper() ? 'S' : 'U'),
                   1458:                addr);
1.1       root     1459: 
1.1.1.10  root     1460:        m68030ATCTable *table = atc.fctables[fc];
                   1461:        uint8 n = table->hash[addr >> 12];
                   1462:        if (__predict_true((int8)n >= 0)) {
                   1463:                // ATC #(n)
                   1464:                a = &table->line[n];
                   1465:  atc_found:
                   1466:                paddr = busaddr(a->GetPAddr());
                   1467:                paddr |= addr & mmu_tc.pgmask;
                   1468:                putlog(3, "%s:  result $%08x (match atc)", __func__, paddr.Addr());
                   1469:                return paddr;
                   1470:        } else {
                   1471:                if (++n == 0) {
                   1472:                        if (__predict_true(mmu_tc.e)) {
                   1473:  table_search:
                   1474:                                // TC.E 有効で対応なしなら、こっそりテーブルサーチ。
                   1475: 
                   1476:                                // mmu.search() はさすがに bus を使うので事前に退避。
                   1477:                                m68kbus backup = bus;
                   1478: 
                   1479:                                m68030MMU mmu(this, loglevel);
                   1480:                                mmu.m_debugger = true;
                   1481:                                mmu.search(7, laddr);
                   1482:                                paddr = mmu.make_atc_debugger();
                   1483:                                // リストア
                   1484:                                bus = backup;
                   1485: 
                   1486:                                if (paddr.IsBusErr()) {
                   1487:                                        // TC が有効だがヒットしなかったらバスエラー
                   1488:                                        putlog(3, "%s:  result BusErr", __func__);
                   1489:                                } else {
                   1490:                                        paddr |= addr & mmu_tc.pgmask;
                   1491:                                        putlog(3, "%s:  result $%08x (table search)",
                   1492:                                                __func__, paddr.Addr());
                   1493:                                }
                   1494:                                return paddr;
                   1495:                        } else {
                   1496:                                // TC.E 無効
                   1497:                                paddr = laddr;
                   1498:                                putlog(3, "%s:  result $%08x (no translation)",
                   1499:                                        __func__, paddr.Addr());
1.1.1.5   root     1500:                                return paddr;
                   1501:                        }
1.1.1.10  root     1502:                } else if (++n == 0) {
                   1503:                        // TT をこっそりチェック。
                   1504:                        for (int i = 0; i < 2; i++) {
                   1505:                                m68030TT& tt = mmu_tt[i];
                   1506:                                if (tt.Match(laddr)) {
                   1507:                                        // 一致した。
                   1508:                                        // CI はここでは使わないため、一致したことだけわかればよい
                   1509:                                        putlog(3, "%s:  result $%08x (match tt)",
                   1510:                                                __func__, paddr.Addr());
                   1511:                                        return paddr;
                   1512:                                }
                   1513:                        }
                   1514:                        return BusAddr::BusErr;
1.1.1.9   root     1515:                } else {
1.1.1.10  root     1516:                        // PS<4KB でマッチしたので再検査。
                   1517:                        a = table->FindSub(laddr);
                   1518:                        if (a) {
                   1519:                                goto atc_found;
                   1520:                        } else {
                   1521:                                goto table_search;
                   1522:                        }
1.1.1.9   root     1523:                }
1.1       root     1524:        }
                   1525: }
                   1526: 
                   1527: //
                   1528: // 命令
                   1529: //
                   1530: 
1.1.1.8   root     1531: // ir2 の下位5ビットから FC を返す。
1.1       root     1532: // 不当パターンなら C++ の例外をスローする。
1.1.1.8   root     1533: uint32
1.1.1.11! root     1534: MPU68030Device::get_fc()
1.1       root     1535: {
1.1.1.8   root     1536:        uint fcfield = ir2 & 0x1f;
1.1       root     1537: 
                   1538:        if (fcfield == 0) {
1.1.1.9   root     1539:                return reg.GetSFC();
1.1       root     1540:        } else if (fcfield == 1) {
1.1.1.9   root     1541:                return reg.GetDFC();
1.1       root     1542:        } else if (fcfield < 0x08) {
                   1543:                // break;
                   1544:        } else if (fcfield < 0x10) {
1.1.1.8   root     1545:                return reg.D[fcfield & 7] & 7;
1.1       root     1546:        } else if (fcfield < 0x18) {
                   1547:                return fcfield & 7;
                   1548:        }
                   1549:        // 不当命令
1.1.1.8   root     1550:        throw M68K::EXCEP_ILLEGAL;
1.1       root     1551: }
                   1552: 
                   1553: // MMU 不当命令 (2ワード目で確定)
1.1.1.8   root     1554: void
1.1.1.11! root     1555: MPU68030Device::mmu_op_illg2()
1.1       root     1556: {
1.1.1.8   root     1557:        putlog(1, "MMU illegal instruction %04x %04x", ir, ir2);
                   1558:        Exception(M68K::EXCEP_FLINE);
1.1       root     1559: }
                   1560: 
                   1561: // PFLUSH fc,#mask 命令 (EA を持たない方)
                   1562: void
1.1.1.11! root     1563: MPU68030Device::mmu_op_pflush()
1.1       root     1564: {
                   1565:        uint32 mask;
                   1566:        uint32 fc;
                   1567: 
1.1.1.8   root     1568:        mask = (ir2 >> 5) & 7;
                   1569:        fc = get_fc();
                   1570:        atc.flush(fc, mask);
1.1       root     1571: }
                   1572: 
                   1573: // PFLUSH fc,#mask,ea 命令
                   1574: void
1.1.1.11! root     1575: MPU68030Device::mmu_op_pflush_ea()
1.1       root     1576: {
                   1577:        uint32 ea;
                   1578:        uint32 mask;
                   1579:        uint32 fc;
                   1580: 
1.1.1.8   root     1581:        ea = cea_copro();
                   1582:        mask = (ir2 >> 5) & 7;
                   1583:        fc = get_fc();
                   1584:        atc.flush(fc, mask, ea);
1.1       root     1585: }
                   1586: 
                   1587: // PLOADR/PLOADW 命令
                   1588: void
1.1.1.11! root     1589: MPU68030Device::mmu_op_pload()
1.1       root     1590: {
                   1591:        uint32 ea;
                   1592:        uint32 fc;
1.1.1.10  root     1593:        busaddr laddr;
1.1       root     1594: 
1.1.1.8   root     1595:        if ((ir2 & 0x01e0) != 0) {
                   1596:                mmu_op_illg2();
1.1       root     1597:                return;
                   1598:        }
1.1.1.8   root     1599:        ea = cea_copro();
                   1600:        fc = get_fc();
1.1       root     1601: 
                   1602:        // 実効アドレスを論理アドレスとする ATC を作成。
                   1603:        // ってこれでいいのか?
1.1.1.8   root     1604:        if ((ir2 & 0x0200)) {
1.1.1.10  root     1605:                laddr = busaddr(ea) | busaddr::FC(fc) | BusAddr::R;
1.1       root     1606:        } else {
1.1.1.10  root     1607:                laddr = busaddr(ea) | busaddr::FC(fc) | BusAddr::W;
                   1608:        }
                   1609: 
                   1610:        m68030ATCTable *table = atc.fctables[fc];
                   1611:        uint8 n = table->hash[laddr.Addr() >> 12];
                   1612:        if ((int8)n >= 0) {
                   1613:                // すでにエントリがある場合
                   1614:                if (laddr.IsWrite() == false) {
                   1615:                        return;
                   1616:                }
                   1617:                // 命令が ploadw でエントリが WProtect==0 && Modified==0 なら、
                   1618:                // 一回破棄して書き込み用に作り直すため下に合流。
                   1619:                m68030ATCLine *a = &table->line[n];
                   1620:                if (a->IsWProtect() == false && a->IsModified() == false) {
                   1621:                        table->Invalidate(a);
                   1622:                        n = m68030ATCTable::HASH_NONE;
                   1623:                        // FALLTHORUGH
                   1624:                } else {
                   1625:                        return;
                   1626:                }
                   1627:        }
                   1628:        if (n == m68030ATCTable::HASH_NONE || n == m68030ATCTable::HASH_SUB) {
                   1629:                if (__predict_true(mmu_tc.e)) {
                   1630:                        // TC.E 有効で対応なしなら、テーブルサーチを行って
                   1631:                        // ATC を作成。
                   1632:                        m68030ATCLine *a __unused;
                   1633:                        a = table->MMUSearch(laddr);
                   1634:                } else {
                   1635:                        // TC.E 無効なら何もしない?
                   1636:                        return;
                   1637:                }
                   1638:        } else if (n == m68030ATCTable::HASH_TT) {
                   1639:                // TT の領域なら何もしてはいけない。
                   1640:                return;
1.1       root     1641:        }
                   1642: }
                   1643: 
                   1644: // PTESTR/PTESTW 命令
                   1645: void
1.1.1.11! root     1646: MPU68030Device::mmu_op_ptest()
1.1       root     1647: {
1.1.1.8   root     1648:        uint level = (ir2 >> 10) & 7;
1.1.1.10  root     1649:        busaddr rw = (ir2 & 0x0200) ? BusAddr::R : BusAddr::W;
1.1.1.8   root     1650:        uint rn    = (ir2 >> 5) & 0xf;
1.1       root     1651:        uint32 ea;
                   1652:        uint32 fc;
                   1653:        uint16 mmusr;
                   1654: 
1.1.1.8   root     1655:        ea = cea_copro();
                   1656:        fc = get_fc();
                   1657:        mmusr = 0;
1.1       root     1658: 
                   1659:        if (level == 0) {
1.1.1.8   root     1660:                if (rn != 0) {
                   1661:                        // レベル0で An 指定なら Fライン例外
                   1662:                        mmu_op_illg2();
                   1663:                        return;
                   1664:                }
1.1       root     1665: 
1.1.1.8   root     1666:                // laddr は IS と PS のところを落としたもの。
                   1667:                // ssw_laddr のアドレスは IS を落とさないもの (PSは不問)。
1.1.1.10  root     1668:                busaddr laddr = busaddr(ea) | busaddr::FC(fc) | rw;
                   1669:                uint32 addr = ea & mmu_tc.lmask;
                   1670: 
                   1671:                m68030ATCTable *table = atc.fctables[fc];
                   1672:                m68030ATCLine *a = NULL;
                   1673:                uint8 n = table->hash[addr >> 12];
                   1674:                if (__predict_true((int8)n >= 0)) {
                   1675:                        // ATC #(n) で見付かった。
                   1676:                        a = &table->line[n];
                   1677:                } else {
                   1678:                        if (n == m68030ATCTable::HASH_NONE) {
                   1679:                                // ATC に見付からなかった。Invalid を立てる。
                   1680:                                mmusr = m68030MMUSR::I;
                   1681:                        } else if (n == m68030ATCTable::HASH_TT) {
                   1682:                                for (int i = 0; i < 2; i++) {
                   1683:                                        m68030TT& tt = mmu_tt[i];
                   1684:                                        if (tt.Match(laddr)) {
                   1685:                                                mmusr |= m68030MMUSR::T;
                   1686:                                        }
                   1687:                                }
                   1688:                        } else {
                   1689:                                // PS<4KB
                   1690:                                a = table->FindSub(laddr);
                   1691:                                if (a == NULL) {
                   1692:                                        mmusr = m68030MMUSR::I;
                   1693:                                }
                   1694:                        }
                   1695:                }
1.1.1.8   root     1696: 
                   1697:                if (a) {
1.1.1.10  root     1698:                        // 見付かれば Modified 等の状態を返す。
1.1.1.8   root     1699:                        if (a->IsBusError()) {
                   1700:                                mmusr |= m68030MMUSR::B;
                   1701:                        } else if (a->IsWProtect()) {
                   1702:                                mmusr |= m68030MMUSR::W;
                   1703:                        } else if (a->IsModified()) {
                   1704:                                mmusr |= m68030MMUSR::M;
                   1705:                        }
1.1       root     1706:                }
                   1707:        } else {
1.1.1.8   root     1708:                // レベル 1-7 ならテーブルサーチを実行。
                   1709: 
1.1.1.10  root     1710:                m68030MMU mmu(this, loglevel);
                   1711:                mmu.m_ptest = true;
                   1712:                mmu.search(level, busaddr(ea) | busaddr::FC(fc) | rw);
1.1.1.8   root     1713: 
1.1.1.10  root     1714:                if (mmu.m_berr) {
1.1       root     1715:                        mmusr |= m68030MMUSR::B;
                   1716:                }
1.1.1.10  root     1717:                if (mmu.m_lim) {
1.1.1.8   root     1718:                        // XXX not tested
                   1719:                        mmusr |= m68030MMUSR::L;
                   1720:                }
1.1.1.10  root     1721:                if (mmu.m_s && (fc & 4)) {
1.1.1.8   root     1722:                        // XXX not tested
                   1723:                        mmusr |= m68030MMUSR::S;
                   1724:                }
1.1.1.10  root     1725:                if (mmu.m_wp) {
1.1.1.8   root     1726:                        mmusr |= m68030MMUSR::W;
                   1727:                }
1.1.1.10  root     1728:                if (mmu.m_type == INVALID) {
1.1.1.8   root     1729:                        mmusr |= m68030MMUSR::I;
                   1730:                }
1.1.1.10  root     1731:                if (mmu.m_m) {
1.1.1.8   root     1732:                        mmusr |= m68030MMUSR::M;
                   1733:                }
                   1734:                // N を求める。
                   1735:                // もともとそういう風には出来ていないので逆算している。
                   1736:                int n;
                   1737:                if (mmu_tc.fcl) {
                   1738:                        // たぶんファンクションテーブルで1段消費する? (未確認)
1.1.1.10  root     1739:                        if (mmu.x == FCL) {
1.1.1.8   root     1740:                                n = 1;
                   1741:                        } else {
1.1.1.10  root     1742:                                n = mmu.x + 2;
1.1.1.8   root     1743:                        }
                   1744:                } else {
1.1.1.10  root     1745:                        n = mmu.x + 1;
1.1.1.8   root     1746:                }
                   1747:                mmusr |= n;
                   1748: 
                   1749:                // アドレスレジスタ指定があれば、最後のディスクリプタアドレスを返す。
                   1750:                // rn は有効なら 8-15。
                   1751:                if (rn != 0) {
                   1752:                        // XXX 途中でバスエラーが起きるケースは未実装
1.1.1.10  root     1753:                        if (mmu.m_berr == false) {
                   1754:                                reg.R[rn] = mmu.m_lastaddr;
1.1.1.8   root     1755:                        }
                   1756:                }
1.1       root     1757:        }
                   1758: 
1.1.1.8   root     1759:        SetMMUSR(mmusr);
1.1       root     1760: }

unix.superglobalmegacorp.com

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