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

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

unix.superglobalmegacorp.com

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