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

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

unix.superglobalmegacorp.com

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