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

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

unix.superglobalmegacorp.com

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