Annotation of nono/m88xx0/m88200.cpp, revision 1.1.1.7

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: // MC88200(CMMU)
                      8: 
                      9: #include "m88100.h"
                     10: #include "m88200.h"
                     11: 
1.1.1.3   root       12: // static 変数
                     13: m88200 *m88200::mbus_master = NULL;
                     14: 
1.1       root       15: // m88200 コンストラクタ
1.1.1.7 ! root       16: //
        !            17: // ここのオブジェクト名は仮で、ID が確定した時点でもう一度セットする
        !            18: // (see SetID())
1.1       root       19: m88200::m88200()
1.1.1.7 ! root       20:        : inherited("CMMU")
1.1       root       21: {
1.1.1.7 ! root       22:        // objname 等は SetID() で確定する
1.1       root       23: 
1.1.1.7 ! root       24:        reg_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateReg;
        !            25:        reg_monitor.SetSize(52, 8);
        !            26:        atc_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateATC;
        !            27:        atc_monitor.SetSize(65, 38);
        !            28:        cache_monitor.func = (MonitorCallback_t)&m88200::MonitorUpdateCache;
        !            29:        cache_monitor.SetSize(82, 23);
        !            30:        // モニタ名も SetID() で決まるので、続きは向こうでやる
1.1       root       31: 
                     32:        // ログ表示用の名前
                     33:        sapr.name = "SAPR";
                     34:        uapr.name = "UAPR";
                     35: 
                     36:        // 暗黙 BATC を初期化
                     37:        SetBATC(8, 0xfff7ffb5); // $fff8xxxx,S,WT,CI,V
                     38:        SetBATC(9, 0xfffffff5); // $ffffxxxx,S,WT,CI,V
                     39: 
                     40:        // セットインデックスを初期化
                     41:        for (int i = 0; i < setarray.size(); i++) {
                     42:                auto& set = setarray[i];
                     43:                set.setidx = i;
                     44:        }
                     45: }
                     46: 
                     47: // m88200 デストラクタ
                     48: m88200::~m88200()
                     49: {
                     50: }
                     51: 
                     52: // 本当はコンストラクタ渡ししたかったもの
                     53: void
                     54: m88200::Ctor(m88kcpu *parent_)
                     55: {
                     56:        parent = parent_;
                     57: }
                     58: 
                     59: // リセット
                     60: void
                     61: m88200::Reset()
                     62: {
1.1.1.3   root       63:        const uint32 Undefined = 0xcccccccc;
                     64: 
1.1       root       65:        // レジスタ (p6-4, Table6-3)
1.1.1.3   root       66:        // ID, version は別途 Set される。
1.1       root       67:        command = 0;
                     68:        ssr = 0;
1.1.1.3   root       69:        sar = Undefined;
1.1       root       70:        sctr = 0;
                     71:        fault_code = 0;
1.1.1.3   root       72:        fault_addr = Undefined;
1.1       root       73:        sapr.enable = false;
                     74:        sapr.stat = APR_CI;
                     75:        uapr.enable = false;
                     76:        uapr.stat = APR_CI;
                     77: }
                     78: 
1.1.1.7 ! root       79: // モニター更新 (CMMU レジスタ)
1.1.1.2   root       80: void
1.1.1.7 ! root       81: m88200::MonitorUpdateReg(Monitor *, TextScreen& screen)
1.1       root       82: {
1.1.1.3   root       83:        uint32 baseaddr;
1.1       root       84:        uint32 reg;
                     85:        int x;
                     86:        int y;
                     87: 
1.1.1.3   root       88:        baseaddr = 0xfff00000 + (id << 12);
                     89: 
1.1.1.7 ! root       90:        screen.Clear();
1.1.1.3   root       91:        x = 24;
1.1       root       92: 
                     93:        y = 0;
1.1.1.7 ! root       94:        screen.Print(0, y++, "$%08x  IDR:%08x ID=$%02x Type=5(88200) Ver=$%x",
1.1.1.3   root       95:                baseaddr + 0, GetIDR(), id, version);
1.1       root       96: 
                     97:        reg = GetSSR();
1.1.1.7 ! root       98:        screen.Print(0, y, "$%08x  SSR:%08x", baseaddr + 0x008, reg);
        !            99:        screen.Puts(x,      y, TA::OnOff(reg & SSR_CE), "CE");
        !           100:        screen.Puts(x + 3,  y, TA::OnOff(reg & SSR_BE), "BE");
        !           101:        screen.Puts(x + 6,  y, TA::OnOff(reg & SSR_WT), "WT");
        !           102:        screen.Puts(x + 9,  y, TA::OnOff(reg & SSR_SP), "SP");
        !           103:        screen.Puts(x + 12, y, TA::OnOff(reg & SSR_G),  "G");
        !           104:        screen.Puts(x + 14, y, TA::OnOff(reg & SSR_CI), "CI");
        !           105:        screen.Puts(x + 17, y, TA::OnOff(reg & SSR_M),  "M");
        !           106:        screen.Puts(x + 19, y, TA::OnOff(reg & SSR_U),  "U");
        !           107:        screen.Puts(x + 21, y, TA::OnOff(reg & SSR_WP), "WP");
        !           108:        screen.Puts(x + 24, y, TA::OnOff(reg & SSR_BH), "BH");
        !           109:        screen.Puts(x + 27, y, TA::OnOff(reg & SSR_V),  "V");
1.1       root      110:        y++;
                    111: 
1.1.1.7 ! root      112:        screen.Print(0, y++, "$%08x  SAR:%08x", baseaddr + 0x00c, GetSAR());
1.1       root      113: 
                    114:        reg = GetSCTR();
1.1.1.7 ! root      115:        screen.Print(0, y, "$%08x SCTR:%08x", baseaddr + 0x104, GetSCTR());
        !           116:        screen.Puts(x,      y, TA::OnOff(reg & SCTR_PE), "PE");
        !           117:        screen.Puts(x + 3,  y, TA::OnOff(reg & SCTR_SE), "SE");
        !           118:        screen.Puts(x + 6,  y, TA::OnOff(reg & SCTR_PR), "PR");
1.1       root      119:        y++;
                    120: 
                    121:        reg = GetPFSR();
                    122:        static const char * const codestr[] = {
                    123:                "Success",
                    124:                "1?",
                    125:                "2?",
                    126:                "Bus Error",
                    127:                "Segment Fault",
                    128:                "Page Fault",
                    129:                "Supervisor Violation",
                    130:                "Write Violation",
                    131:        };
1.1.1.7 ! root      132:        screen.Print(0, y++, "$%08x PFSR:%08x %s", baseaddr + 0x108,
1.1.1.3   root      133:                reg, codestr[fault_code]);
1.1       root      134: 
1.1.1.7 ! root      135:        screen.Print(0, y++, "$%08x PFAR:%08x", baseaddr + 0x10c, GetPFAR());
1.1       root      136: 
                    137:        for (int i = 0; i < 2; i++) {
                    138:                int s = 1 - i;
                    139:                reg = GetAPR(s);
1.1.1.7 ! root      140:                screen.Print(0, y, "$%08x %cAPR:%08x", baseaddr + 0x200 + i * 4,
1.1.1.3   root      141:                        s ? 'S' : 'U', reg);
1.1.1.7 ! root      142:                screen.Print(x, y, "STBA=%05x'000 %c%c%c%c",
1.1       root      143:                        reg >> 12,
                    144:                        (reg & APR_WT) ? 'T' : '-',
                    145:                        (reg & APR_G)  ? 'G' : '-',
                    146:                        (reg & APR_CI) ? 'C' : '-',
                    147:                        (reg & APR_TE) ? 'E' : '-');
                    148:                y++;
                    149:        }
                    150: }
                    151: 
1.1.1.7 ! root      152: // モニター更新 (ATC)
        !           153: void
        !           154: m88200::MonitorUpdateATC(Monitor *, TextScreen& screen)
        !           155: {
        !           156:        int x;
        !           157:        int y;
        !           158: 
        !           159:        screen.Clear();
        !           160: 
        !           161:        screen.Print(0, 0,  "SAPR  %05x'000 TE=%d      %c%c%c",
        !           162:                (sapr.addr >> 12) & 0xfffff,
        !           163:                 sapr.enable ? 1 : 0,
        !           164:                (sapr.stat & m88200::APR_WT) ? 'T' : '-',
        !           165:                (sapr.stat & m88200::APR_G)  ? 'G' : '-',
        !           166:                (sapr.stat & m88200::APR_CI) ? 'C' : '-');
        !           167: 
        !           168:        screen.Print(34, 0, "UAPR  %05x'000 TE=%d      %c%c%c",
        !           169:                (uapr.addr >> 12) & 0xfffff,
        !           170:                 uapr.enable ? 1 : 0,
        !           171:                (uapr.stat & m88200::APR_WT) ? 'T' : '-',
        !           172:                (uapr.stat & m88200::APR_G)  ? 'G' : '-',
        !           173:                (uapr.stat & m88200::APR_CI) ? 'C' : '-');
        !           174: 
        !           175:        screen.Puts(0,  1, "<BATC>");
        !           176:        screen.Puts(0,  2, "No. LBA         PBA       Stat");
        !           177:        screen.Puts(34, 2, "No. LBA         PBA       Stat");
        !           178:        x = 0;
        !           179:        y = 3;
        !           180:        for (int i = 0; i < 10; i++) {
        !           181:                if (i == batc.size() / 2) {
        !           182:                        x = 34;
        !           183:                        y = 3;
        !           184:                }
        !           185:                if (i < 8) {
        !           186:                        screen.Print(x, y, " %d:", i);
        !           187:                } else {
        !           188:                        screen.Print(x, y, "(%d)", i);
        !           189:                }
        !           190: 
        !           191:                const m88200BATC& b = batc[i];
        !           192:                if ((b.lba & 1) == 0) {
        !           193:                        screen.Print(x + 4, y, "%c:%04x'0000 %04x'0000 %c%c%c%c",
        !           194:                                (b.lba & m88200::BATC_S)   ? 'S' : 'U',
        !           195:                                b.lba >> 16, b.pba >> 16,
        !           196:                                (b.stat & m88200::DESC_WT) ? 'T' : '-',
        !           197:                                (b.stat & m88200::DESC_G)  ? 'G' : '-',
        !           198:                                (b.stat & m88200::DESC_CI) ? 'C' : '-',
        !           199:                                (b.stat & m88200::DESC_WP) ? 'P' : '-');
        !           200:                }
        !           201:                y++;
        !           202:        }
        !           203: 
        !           204:        screen.Puts(0,  8, "<PATC>");
        !           205:        screen.Puts(0,  9, "No. LPA         PFA       Stat");
        !           206:        screen.Puts(34, 9, "No. LPA         PFA       Stat");
        !           207: 
        !           208:        x = 0;
        !           209:        y = 10;
        !           210:        for (int i = 0; i < patc.size(); i++) {
        !           211:                if (i == patc.size() / 2) {
        !           212:                        x = 34;
        !           213:                        y = 10;
        !           214:                }
        !           215:                screen.Print(x, y, "%2d:", i);
        !           216: 
        !           217:                const m88200PATC& p = patc[i];
        !           218:                if ((p.lpa & 1) == 0) {
        !           219:                        screen.Print(x + 4,  y, "%c:%05x'000 %05x'000 %c%c%c%c%c",
        !           220:                                (p.lpa & m88200::PATC_S)   ? 'S' : 'U',
        !           221:                                p.lpa >> 12, p.pfa >> 12,
        !           222:                                (p.stat & m88200::DESC_WT) ? 'T' : '-',
        !           223:                                (p.stat & m88200::DESC_G)  ? 'G' : '-',
        !           224:                                (p.stat & m88200::DESC_CI) ? 'C' : '-',
        !           225:                                (p.stat & m88200::DESC_WP) ? 'P' : '-',
        !           226:                                p.m                        ? 'M' : '-');
        !           227:                }
        !           228: 
        !           229:                y++;
        !           230:        }
        !           231: }
        !           232: 
        !           233: // モニター更新 (キャッシュ、概要と詳細の両方、GUI から呼ばれる)
        !           234: // screen.userdata は注目しているセット番号。
        !           235: void
        !           236: m88200::MonitorUpdateCache(Monitor *, TextScreen& screen)
        !           237: {
        !           238:        int setidx = screen.userdata;
        !           239: 
        !           240:        // 上半分(概要)
        !           241:        MonitorCacheOverview(screen, 0, setidx, true);
        !           242:        // 下半分(セット詳細)
        !           243:        MonitorCacheSet(screen, 18, setidx);
        !           244: }
        !           245: 
1.1       root      246: // データキャッシュの特定セットの詳細を TextScreen に出力する。
                    247: // y は開始オフセット。
                    248: // TextScreen は (70, 5) 必要。
                    249: void
                    250: m88200::MonitorCacheSet(TextScreen& s, int y, int setidx)
                    251: {
1.1.1.7 ! root      252:        assertmsg(0 <= setidx && setidx < setarray.size(), "setidx=%d", setidx);
1.1       root      253:        const m88200CacheSet& set = setarray[setidx];
                    254: 
                    255:        /*
                    256:        012345678901234567890123456789012345678901234567890123456789
                    257:        L Tag        Status
                    258:        0 $11223'344 VV     12345678 12345678 12345678 12345678
                    259:        */
                    260:        s.Puts(0, y, "L Tag        Status Word");
                    261:        s.Puts(58, y, "Order");
                    262:        y++;
                    263: 
                    264:        // ラインの古い順に評価して順序を0-3でつける
                    265:        int Lorder[4];
                    266:        int tmpL = set.L;
                    267:        for (int i = 0; i < 4; i++) {
                    268:                int line = m88200CacheSet::TryGetOldestLine(tmpL);
                    269:                Lorder[line] = 3 - i;
                    270:                tmpL = m88200CacheSet::TryUseLine(tmpL, line);
                    271:        }
                    272: 
                    273:        for (int line = 0; line < 4; line++, y++) {
                    274:                TA attr;
                    275:                // ステータスによって属性を選択
                    276:                switch (set.vv[line]) {
                    277:                 case m88200CacheSet::Status::IV:
                    278:                        attr = TA::Disable;
                    279:                        break;
                    280:                 case m88200CacheSet::Status::EU:
                    281:                 case m88200CacheSet::Status::SU:
                    282:                        attr = TA::Off;
                    283:                        break;
                    284:                 case m88200CacheSet::Status::EM:
                    285:                        attr = TA::Em;
                    286:                        break;
                    287:                }
                    288:                s.Print(0, y, attr, "%d", line);
1.1.1.3   root      289:                static const char statusstr[][4] = { "EU", "EM", "SU", "IV" };
1.1       root      290:                s.Print(2, y, attr, "$%05x'%03x %s",
                    291:                        (set.tag[line] >> 12),
                    292:                        (setidx << 4),
                    293:                        statusstr[set.vv[line]]);
                    294: 
                    295:                if (set.vv[line] == m88200CacheSet::Status::EM) {
                    296:                        // メモリに対してダーティならボールドにする
                    297:                        for (int w = 0; w < 4; w++) {
                    298:                                uint32 addr;
                    299:                                uint32 m;
                    300:                                addr = (set.tag[line] & 0xfffff000) | (setidx << 4) | (w << 2);
                    301:                                m = (vm_phys_peek_8(addr) << 24)
                    302:                                  | (vm_phys_peek_8(addr + 1) << 16)
                    303:                                  | (vm_phys_peek_8(addr + 2) <<  8)
                    304:                                  | (vm_phys_peek_8(addr + 3));
                    305:                                if (set.word[line * 4 + w] != m) {
                    306:                                        attr = TA::Em;
                    307:                                } else {
                    308:                                        attr = TA::Off;
                    309:                                }
                    310:                                s.Print(20 + w * 9, y, attr, "%08x", set.word[line * 4 + w]);
                    311:                        }
                    312:                } else {
                    313:                        // Unmodified (or Invalid) ならメモリとの比較は不要
                    314:                        for (int w = 0; w < 4; w++) {
                    315:                                s.Print(20 + w * 9, y, "%08x", set.word[line * 4 + w]);
                    316:                        }
                    317:                }
                    318: 
                    319:                // 順序
                    320:                s.Print(58, y, "%d", Lorder[line]);
                    321:        }
                    322: }
                    323: 
                    324: // データキャッシュの概要を指定の TextScreen に出力する。
                    325: // y は開始オフセット。CLI では単独コマンドとして、GUI ではページの一部と
                    326: // して描画するためこうなっている。
                    327: // cursor で指定された番号のセットは反転表示する。GUI でのカーソル用。
                    328: // 負数など範囲外の値を指定すればカーソルは表示されない。
                    329: // is_gui は GUI かどうか。CLI では80桁を微妙に越えるのは嫌だしどうせ表示
                    330: // だけなので間を詰めてあるが、GUI では 80桁制約はない代わりにマウス操作が
                    331: // あるので 1セットごとに間を空けて等間隔にしたい、という違いから。
                    332: // TextScreen は CLI なら (70, 17)、GUI なら (82, 17) 必要。
                    333: void
                    334: m88200::MonitorCacheOverview(TextScreen& s, int y, int cursor, bool is_gui)
                    335: {
                    336:        // X ガイド
                    337:        for (int i = 0; i < 16; i++) {
                    338:                int x;
                    339:                if (is_gui) {
                    340:                        x = 3 + i * 5;
                    341:                } else {
                    342:                        x = 3 + i * 4 + (i / 4);
                    343:                }
                    344:                s.Print(x, y, "+0%x", i);
                    345:        }
                    346:        y++;
                    347: 
                    348:        // Y ガイド
                    349:        for (int i = 0; i < 16; i++) {
                    350:                s.Print(0, y + i, "%02x", i * 16);
                    351:        }
                    352: 
                    353:        for (int i = 0; i < setarray.size(); i++) {
                    354:                const auto& set = setarray[i];
1.1.1.3   root      355:                const char str[] = "EMS-";
1.1       root      356:                int col = i % 16;
                    357:                int row = i / 16;
                    358:                int x;
                    359:                if (is_gui) {
                    360:                        x = 3 + col * 5;
                    361:                } else {
                    362:                        x = 3 + col * 4 + col / 4;
                    363:                }
                    364: 
                    365:                s.Print(x, y + row, TA::OnOff(i == cursor),
                    366:                        "%c%c%c%c",
                    367:                        str[set.vv[0]],
                    368:                        str[set.vv[1]],
                    369:                        str[set.vv[2]],
                    370:                        str[set.vv[3]]);
                    371:        }
                    372: }
                    373: 
                    374: // ID を設定する (IDR ではない)
                    375: void
                    376: m88200::SetID(uint id_)
                    377: {
                    378:        id = id_;
                    379: 
1.1.1.7 ! root      380:        SetName(string_format("CMMU#%u", id));
        !           381: 
        !           382:        reg_monitor.Regist(ID_MONITOR_CMMU(id));
        !           383:        atc_monitor.Regist(ID_MONITOR_ATC(id));
        !           384:        cache_monitor.Regist(ID_SUBWIN_CACHE(id));
1.1       root      385: }
                    386: 
                    387: // IDR の Version フィールドを設定する
                    388: void
                    389: m88200::SetVersion(uint version_)
                    390: {
                    391:        version = version_;
                    392: }
                    393: 
                    394: // コマンド名
                    395: // (0-15 は全部 No Operation なので、16以降のみ)
                    396: /*static*/ const char * const
                    397: m88200::commandname[] = {
                    398:        "No Operation",                                         // $10
                    399:        "No Operation",                                         // $11
                    400:        "No Operation",                                         // $12
                    401:        "No Operation",                                         // $13
                    402:        "DCache Invalidate, Line",                      // $14
                    403:        "DCache Invalidate, Page",                      // $15
                    404:        "DCache Invalidate, Segment",           // $16
                    405:        "DCache Invalidate, All",                       // $17
                    406: 
                    407:        "DCache Copyback, Line",                        // $18
                    408:        "DCache Copyback, Page",                        // $19
                    409:        "DCache Copyback, Segment",                     // $1a
                    410:        "DCache Copyback, All",                         // $1b
                    411:        "DCache Copy&Inv, Line",                        // $1c
                    412:        "DCache Copy&Inv, Page",                        // $1d
                    413:        "DCache Copy&Inv, Segment",                     // $1e
                    414:        "DCache Copy&Inv, All",                         // $1f
                    415: 
                    416:        "Probe User Address",                           // $20
                    417:        "Probe User Address",                           // $21
                    418:        "Probe User Address",                           // $22
                    419:        "Probe User Address",                           // $23
                    420:        "Probe Supervisor Address",                     // $24
                    421:        "Probe Supervisor Address",                     // $25
                    422:        "Probe Supervisor Address",                     // $26
                    423:        "Probe Supervisor Address",                     // $27
                    424: 
                    425:        "Probe User Address",                           // $28
                    426:        "Probe User Address",                           // $29
                    427:        "Probe User Address",                           // $2a
                    428:        "Probe User Address",                           // $2b
                    429:        "Probe Supervisor Address",                     // $2c
                    430:        "Probe Supervisor Address",                     // $2d
                    431:        "Probe Supervisor Address",                     // $2e
                    432:        "Probe Supervisor Address",                     // $2f
                    433: 
                    434:        "Invalidate U PATC, Line",                      // $30
                    435:        "Invalidate U PATC, Page",                      // $31
                    436:        "Invalidate U PATC, Segment",           // $32
                    437:        "Invalidate U PATC, All",                       // $33
                    438:        "Invalidate S PATC, Line",                      // $34
                    439:        "Invalidate S PATC, Page",                      // $35
                    440:        "Invalidate S PATC, Segment",           // $36
                    441:        "Invalidate S PATC, All",                       // $37
                    442: 
                    443:        "Invalidate U PATC, Line",                      // $38
                    444:        "Invalidate U PATC, Page",                      // $39
                    445:        "Invalidate U PATC, Segment",           // $3a
                    446:        "Invalidate U PATC, All",                       // $3b
                    447:        "Invalidate S PATC, Line",                      // $3c
                    448:        "Invalidate S PATC, Page",                      // $3d
                    449:        "Invalidate S PATC, Segment",           // $3e
                    450:        "Invalidate S PATC, All",                       // $3f
                    451: };
                    452: 
                    453: // SCR の読み出し
                    454: uint32
                    455: m88200::GetSCR() const
                    456: {
                    457:        // b31-b6 (reserved) の読み出し値は未定義らしい。
                    458:        // b5-b0 (Command Code) の読み出し値はマニュアルに記載がないけど
                    459:        // たぶんそのまま読めるのかな。
                    460:        return command;
                    461: }
                    462: 
                    463: // SCR への書き込み
                    464: void
                    465: m88200::SetSCR(uint32 data)
                    466: {
                    467:        command = data & 0x3f;
                    468: 
                    469:        // %00'XXXX No Operation
                    470:        // %01'00XX No Operation
                    471:        // %01'01gg Data Cache Invalidate
                    472:        // %01'10gg Data Cache Copyback to Memory
                    473:        // %01'11gg Data Cache Copyback and Invalidate
                    474:        // %10'X0XX Probe User Address
                    475:        // %10'X1XX Probe Supervisor Address
                    476:        // %11'X0gg Invalidate User PATC Descriptors
                    477:        // %11'X1gg Invalidate Supervisor PATC Descriptors
                    478: 
                    479:        const char *name;
                    480:        if (command < 0x10) {
                    481:                name = commandname[0];
                    482:        } else {
                    483:                name = commandname[command - 0x10];
                    484:        }
                    485:        putlog(1, "SCR  <- $%08x (%s)", data, name);
                    486: 
                    487:        switch (command) {
                    488:         case 0x00 ... 0x13:    // No Operation
                    489:                return;
                    490: 
                    491:         case 0x14 ... 0x1f:    // Flush Data Cache
                    492:                FlushCache();
                    493:                return;
                    494: 
                    495:         case 0x20 ... 0x23:    // Probe User Address
                    496:         case 0x28 ... 0x2b:
                    497:                putlog(0, "SCR Command: Probe User Address 未実装");
                    498:                return;
                    499: 
                    500:         case 0x24 ... 0x27:    // Probe Supervisor Address
                    501:         case 0x2c ... 0x2f:
                    502:                putlog(0, "SCR Command: Probe Supervisor Address 未実装");
                    503:                return;
                    504: 
                    505:         case 0x30 ... 0x3f:    // Invalidate {User,Supervisor} PATC Descriptors
                    506:                InvalidatePATC();
                    507:                return;
                    508:        }
                    509:        __unreachable();
                    510: }
                    511: 
                    512: // command に応じてデータキャッシュをフラッシュする。SetSCR() の下請け。
                    513: // command が $14..$1f でのみ呼ぶこと。
                    514: // p3-18, Section 3.7
                    515: void
                    516: m88200::FlushCache()
                    517: {
                    518:        uint32 op = command & 0x3c;
                    519:        uint32 gg = command & 0x03;
                    520:        uint32 addr = GetSAR();
                    521:        bool copyback;
                    522:        bool invalidate;
                    523: 
                    524:        // op       CopyBack Invalidate
                    525:        // %01'01gg false    true       | Data Cache Invalidate
                    526:        // %01'10gg true     false      | Data Cache Copyback to Memory
                    527:        // %01'11gg true     true       | Data Cache Copyback and invalidate
                    528: 
                    529:        // op によって書き戻しと無効化の組み合わせが異なる
                    530:        if (op == 0x14) {
                    531:                copyback   = false;
                    532:                invalidate = true;
                    533:        } else if (op == 0x18) {
                    534:                copyback   = true;
                    535:                invalidate = false;
                    536:        } else if (op == 0x1c) {
                    537:                copyback   = true;
                    538:                invalidate = true;
                    539:        } else {
                    540:                PANIC("unknown op = $%02x", op);
                    541:        }
                    542: 
                    543:        // 影響範囲
                    544:        switch (gg) {
                    545:         case GG_LINE:
                    546:                addr &= 0xfffffffc;
1.1.1.3   root      547:                parent->AddCycle(1);    // Table.6-1
1.1       root      548:                break;
                    549:         case GG_PAGE:
                    550:                addr &= 0xfffff000;
1.1.1.3   root      551:                parent->AddCycle(256);  // Table.6-1
1.1       root      552:                break;
                    553:         case GG_SEG:
                    554:                addr &= 0xffc00000;
1.1.1.3   root      555:                parent->AddCycle(1024); // Table.6-1
1.1       root      556:                break;
                    557:         case GG_ALL:
1.1.1.3   root      558:                parent->AddCycle(1024); // Table.6-1
1.1       root      559:                break;
                    560:         default:
                    561:                __unreachable();
                    562:        }
                    563: 
1.1.1.3   root      564:        // サイクル(基本部分) Table.6-1
                    565:        uint32 cycle = 0;
                    566:        if (invalidate) {
                    567:                switch (gg) {
                    568:                 case GG_LINE:  cycle = 1;              break;
                    569:                 case GG_PAGE:  cycle = 256;    break;
                    570:                 case GG_SEG:   cycle = 1024;   break;
                    571:                 case GG_ALL:   cycle = 256;    break;
                    572:                 default:       __unreachable();
                    573:                }
                    574:        }
                    575:        if (copyback) {
                    576:                switch (gg) {
                    577:                 case GG_LINE:  cycle = 1;              break;
                    578:                 case GG_PAGE:  cycle = 256;    break;
                    579:                 case GG_SEG:   cycle = 1024;   break;
                    580:                 case GG_ALL:   cycle = 1024;   break;
                    581:                 default:       __unreachable();
                    582:                }
                    583:        }
                    584:        // XXX ループ中のサイクル数は正しくないかも。よく分からん
                    585: 
1.1       root      586:        for (auto& set : setarray) {
                    587:                for (int line = 0; line < 4; line++) {
                    588:                        // 条件にマッチするか
                    589:                        bool match;
                    590:                        switch (gg) {
                    591:                         case GG_LINE:
                    592:                                match = (addr == (set.tag[line] | (set.setidx << 4)));
                    593:                                break;
                    594:                         case GG_PAGE:
                    595:                                match = (addr == set.tag[line]);
                    596:                                break;
                    597:                         case GG_SEG:
                    598:                                match = (addr == (set.tag[line] & 0xffc00001));
                    599:                                break;
                    600:                         case GG_ALL:
                    601:                                match = true;
                    602:                                break;
                    603:                         default:
                    604:                                __unreachable();
                    605:                        }
                    606:                        if (!match)
                    607:                                continue;
                    608: 
                    609:                        // Copyback ならまず EM なエントリを書き戻す。
                    610:                        if (copyback) {
                    611:                                if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3   root      612:                                        cycle += 7;     // Table.6-1
                    613:                                        CopyBackLine(set, line);
1.1       root      614:                                }
                    615:                        }
                    616: 
                    617:                        // Invalidate なら無効化する
                    618:                        if (invalidate) {
1.1.1.3   root      619:                                cycle += 1;     // Table.6-1
1.1       root      620:                                set.Update(line, m88200CacheSet::IV);
                    621:                        }
                    622:                }
                    623:        }
1.1.1.3   root      624: 
                    625:        parent->AddCycle(cycle);
1.1       root      626: }
                    627: 
                    628: // command に応じて PATC を無効化する。SetSCR() の下請け。
                    629: // command が $30..$3f で呼ぶこと。
                    630: // p2-9, Section 2.2.4
                    631: void
                    632: m88200::InvalidatePATC()
                    633: {
                    634:        uint32 gg = command & 0x03;
                    635:        uint32 addr = GetSAR();
                    636: 
                    637:        // ゲスト側が指定した端数部分は有効部分でマスクする。
                    638:        // 内部では下位ビットはフラグ扱いなのでマスクしないと誤動作する。
                    639:        if (gg == GG_SEG) {
                    640:                addr &= 0xffc00000;
                    641:        } else {
                    642:                addr &= 0xfffff000;
                    643:        }
                    644: 
                    645:        if ((command & 0x04)) {
                    646:                addr |= PATC_S;
                    647:        }
                    648: 
                    649:        for (auto& p : patc) {
                    650:                bool match;
                    651:                switch (command & 0x03) {
                    652:                 case GG_LINE:
                    653:                        match = false;          // XXX 書いてないけどどうなる?
                    654:                        break;
                    655:                 case GG_PAGE:
                    656:                        match = (addr == p.lpa);
                    657:                        break;
                    658:                 case GG_SEG:
                    659:                        match = (addr == (p.lpa & 0xffc00fff));
                    660:                        break;
                    661:                 case GG_ALL:
                    662:                        match = true;
                    663:                        break;
                    664:                 default:
                    665:                        __unreachable();
                    666:                }
                    667:                if (match) {
                    668:                        // 無効化
                    669:                        p.lpa |= 0x01;
                    670:                }
                    671:        }
                    672: }
                    673: 
                    674: // SCTR レジスタへの書き込み
                    675: void
                    676: m88200::SetSCTR(uint32 data)
                    677: {
                    678:        sctr = data & (SCTR_PE | SCTR_SE | SCTR_PR);
                    679: 
                    680:        std::string msg;
                    681:        if ((sctr & SCTR_PE))
                    682:                msg += ",PE";
                    683:        if ((sctr & SCTR_SE))
                    684:                msg += ",SE";
                    685:        if ((sctr & SCTR_PR))
                    686:                msg += ",PR";
                    687:        if (msg.length() > 0) {
                    688:                putlog(0, "SCTR <- $%08x (%s 書き込み未実装)", data, msg.c_str() + 1);
                    689:        }
                    690: }
                    691: 
                    692: // SAPR, UAPR レジスタ値の読み出し (S/U ビット指定)
                    693: uint32
                    694: m88200::GetAPR(uint issuper) const
                    695: {
                    696:        if (issuper) {
                    697:                return GetAPR(sapr);
                    698:        } else {
                    699:                return GetAPR(uapr);
                    700:        }
                    701: }
                    702: 
                    703: // SAPR, UAPR レジスタ値の読み出し (実体指定)
                    704: uint32
                    705: m88200::GetAPR(const m88200APR& xapr) const
                    706: {
                    707:        uint32 data;
                    708: 
                    709:        data  = xapr.addr & APR_ADDR_MASK;
                    710:        data |= xapr.stat & (APR_WT | APR_G | APR_CI);
                    711:        if (xapr.enable) {
                    712:                data |= APR_TE;
                    713:        }
                    714:        return data;
                    715: }
                    716: 
                    717: // SAPR, UAPR レジスタへの書き込み (S/U ビット指定)
                    718: void
                    719: m88200::SetAPR(uint issuper, uint32 data)
                    720: {
                    721:        if (issuper) {
                    722:                return SetAPR(sapr, data);
                    723:        } else {
                    724:                return SetAPR(uapr, data);
                    725:        }
                    726: }
                    727: 
                    728: // SAPR, UAPR レジスタへの書き込み (実体指定)
                    729: void
                    730: m88200::SetAPR(m88200APR& xapr, uint32 data)
                    731: {
                    732:        bool old_enable = xapr.enable;
                    733:        xapr.addr = data & APR_ADDR_MASK;
                    734:        xapr.stat = data & (APR_WT | APR_G | APR_CI);
                    735:        xapr.enable = data & APR_TE;
                    736: 
                    737:        if (old_enable == false && xapr.enable == true) {
                    738:                // 変換開始
                    739:                putlog(1, "%s <- $%08x (Translation Enabled)", xapr.name, data);
                    740:        } else if (old_enable == true && xapr.enable == false) {
                    741:                // 変換停止
                    742:                putlog(1, "%s <- $%08x (Translation Disabled)", xapr.name, data);
                    743:        } else {
                    744:                // 変化なし
                    745:                putlog(1, "%s <- $%08x", xapr.name, data);
                    746:        }
                    747: }
                    748: 
                    749: // BATC(BWP) #n の読み出し
                    750: uint32
                    751: m88200::GetBATC(uint n) const
                    752: {
                    753:        uint32 data;
                    754: 
                    755:        assert(n < 8);
                    756:        const m88200BATC& b = batc[n];
                    757: 
                    758:        //         9  8  7  6  5  4  3  2  1  0
                    759:        // BATC は             S  WT G  CI WP V
                    760:        // stat は WT SP G  CI 0  M  U  WP 0  V
                    761: 
                    762:        data = b.lba & (BATC_LBA_MASK | BATC_S);
                    763:        data |= (b.pba >> 13);
                    764:        if ((b.stat & DESC_WT))
                    765:                data |= BATC_WT;
                    766:        if ((b.stat & DESC_G))
                    767:                data |= BATC_G;
                    768:        if ((b.stat & DESC_CI))
                    769:                data |= BATC_CI;
                    770:        if (b.wp)
                    771:                data |= BATC_WP;
                    772:        if ((b.lba & 1) == 0)
                    773:                data |= BATC_V;
                    774:        return data;
                    775: }
                    776: 
                    777: // BATC (BWP) #n への書き込み
                    778: // (暗黙 BATC にも書き込めるよう n = 8,9 も受け付ける)
                    779: void
                    780: m88200::SetBATC(uint n, uint32 data)
                    781: {
                    782:        assert(n < 10);
                    783:        m88200BATC& b = batc[n];
                    784:        putlog(1, "BWP%u <- $%08x", n, data);
                    785: 
                    786:        memset(&b, 0, sizeof(b));
                    787:        b.lba   =  data & BATC_LBA_MASK;
                    788:        b.lba  |= (data & BATC_S);
                    789:        if ((data & BATC_V) == 0) {
                    790:                b.lba  |= 1;
                    791:        }
                    792:        b.pba   = (data & BATC_PBA_MASK) << 13;
                    793:        // BATC と stat はビット順が違うので注意。すぐ上の GetBATC() 参照。
                    794:        if ((data & BATC_WT))
                    795:                b.stat = DESC_WT;
                    796:        if ((data & BATC_G))
                    797:                b.stat = DESC_G;
                    798:        if ((data & BATC_CI))
                    799:                b.stat = DESC_CI;
                    800:        if ((data & BATC_WP)) {
                    801:                b.stat = DESC_WP;
                    802:                b.wp = true;
                    803:        }
                    804: }
                    805: 
                    806: // CSSP レジスタの読み出し
                    807: uint32
                    808: m88200::GetCSSP() const
                    809: {
                    810:        uint32 setidx = (GetSAR() >> 4) & 0xff;
                    811:        const m88200CacheSet& set = setarray[setidx];
                    812: 
                    813:        uint32 data = 0;
                    814:        // L5-L0
                    815:        data |= set.L << 24;
                    816: 
                    817:        // XXX D3-D0 未実装
                    818: 
                    819:        // VV3-VV0
                    820:        data |= set.vv[3] << CSSP_VV3_OFFSET;
                    821:        data |= set.vv[2] << CSSP_VV2_OFFSET;
                    822:        data |= set.vv[1] << CSSP_VV1_OFFSET;
                    823:        data |= set.vv[0] << CSSP_VV0_OFFSET;
                    824: 
                    825:        return data;
                    826: }
                    827: 
                    828: // CSSP レジスタへの書き込み
                    829: void
                    830: m88200::SetCSSP(uint32 data)
                    831: {
                    832:        uint32 setidx = (GetSAR() >> 4) & 0xff;
                    833:        m88200CacheSet& set = setarray[setidx];
                    834: 
                    835:        putlog(1, "CSSP <- $%08x (set=$%02x)", data,setidx);
                    836: 
                    837:        // L5-L0 書き込み
                    838:        set.L = (data >> 24) & 0x3f;
                    839: 
                    840:        // XXX D3-D0 未実装
                    841: 
                    842:        // VV3-VV0
                    843:        set.vv[3] = (m88200CacheSet::Status)((data >> CSSP_VV3_OFFSET) & 3);
                    844:        set.vv[2] = (m88200CacheSet::Status)((data >> CSSP_VV2_OFFSET) & 3);
                    845:        set.vv[1] = (m88200CacheSet::Status)((data >> CSSP_VV1_OFFSET) & 3);
                    846:        set.vv[0] = (m88200CacheSet::Status)((data >> CSSP_VV0_OFFSET) & 3);
                    847: }
                    848: 
                    849: 
                    850: //
                    851: // 物理バスアクセス
                    852: //
                    853: 
                    854: // MBus から読み込みを行う。
                    855: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
                    856: // 成功すれば読み込めた値を返す。
                    857: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
                    858: uint64
                    859: m88200::MBusRead(uint32 paddr, int size)
                    860: {
                    861:        uint64 data;
                    862: 
                    863:        if (size == 4) {
                    864:                data = vm_phys_read_32(paddr);
                    865:        } else if (size == 2) {
                    866:                data = vm_phys_read_16(paddr);
                    867:        } else {
                    868:                data = vm_phys_read_8(paddr);
                    869:        }
                    870:        if ((int64)data < 0) {
                    871:                fault_code = FAULT_CODE_BUSERR;
                    872:                fault_addr = paddr;
                    873:        }
                    874:        return data;
                    875: }
                    876: 
                    877: // MBus に書き込みを行う。
                    878: // paddr は size によって 1, 2, 4 バイト境界に整列していること。
                    879: // 成功すれば 0 を返す。
                    880: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
                    881: uint64
                    882: m88200::MBusWrite(uint32 paddr, uint32 data, int size)
                    883: {
                    884:        uint64 rv;
                    885: 
                    886:        if (size == 4) {
                    887:                rv = vm_phys_write_32(paddr, data);
                    888:        } else if (size == 2) {
                    889:                rv = vm_phys_write_16(paddr, data);
                    890:        } else {
                    891:                rv = vm_phys_write_8(paddr, data);
                    892:        }
                    893:        if ((int64)rv < 0) {
                    894:                fault_code = FAULT_CODE_BUSERR;
                    895:                fault_addr = paddr;
                    896:        }
                    897:        return rv;
                    898: }
                    899: 
                    900: // MBus に xmem トランザクションを行う。
1.1.1.6   root      901: // paddr は size によって 1, 4 バイト境界に整列していること (2バイトはない)。
1.1       root      902: // MBus Acquire された状態で呼び出すこと。
                    903: // 成功すれば読み込めた値を返す。
                    904: // バスエラーが起きれば fault_code、fault_addr をセットして (uint64)-1 を返す。
                    905: // read/write どちらでエラーが起きたかは acc_read で判別できる。
                    906: // p3-13, Figure3-7 の下半分のメインラインあたりに該当。
                    907: uint64
                    908: m88200::MBusXmem(uint32 paddr, uint32 data, int size)
                    909: {
                    910:        uint64 fetched;
                    911:        uint64 rv;
                    912: 
                    913:        // Read data with intent to modify
                    914:        acc_read = true;
                    915:        rv = MBusRead(paddr, size);
                    916:        if ((int64)rv < 0) {
                    917:                goto error;
                    918:        }
                    919:        fetched = (uint32)rv;
                    920: 
                    921:        // Supply data to PBus
                    922:        // Reply = Success
                    923: 
                    924:        // Write data to memory
                    925:        acc_read = false;
                    926:        rv = MBusWrite(paddr, data, size);
                    927:        if ((int64)rv < 0) {
                    928:                goto error;
                    929:        }
                    930: 
                    931:        rv = fetched;
                    932:  error:
                    933:        return rv;
                    934: }
                    935: 
                    936: //
                    937: // アクセス関数
                    938: //
                    939: 
                    940: template <int bits> uint64
                    941: m88200::load(uint32 addr)
                    942: {
                    943:        uint64 data;
                    944: 
                    945:        acc_laddr = addr;
                    946:        acc_read  = true;
                    947:        if (Translate() == false) {
1.1.1.4   root      948:                putlog(2, "Translation BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1.1       root      949:                return (uint64)-1;
                    950:        }
                    951:        if ((acc_stat & DESC_CI)) {
1.1.1.3   root      952:                parent->AddCycle(7);    // Table.6-2
1.1       root      953:                MBusAcquire();
                    954:                data = MBusRead(acc_paddrH + acc_paddrL, bits / 8);
                    955:                MBusRelease();
1.1.1.4   root      956:                if ((int64)data < 0) {
                    957:                        putlog(2, "MBus BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
                    958:                }
1.1       root      959:                return data;
                    960:        } else {
                    961:                data = CacheRead(acc_paddrH);
                    962:                if ((int64)data < 0) {
1.1.1.4   root      963:                        putlog(2, "Cache BusError %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
1.1       root      964:                        return data;
                    965:                }
                    966: 
                    967:                if (bits == 8) {
                    968:                        switch (acc_paddrL) {
                    969:                         case 0:
                    970:                                return (data >> 24);
                    971:                         case 1:
                    972:                                return (data >> 16) & 0xff;
                    973:                         case 2:
                    974:                                return (data >>  8) & 0xff;
                    975:                         case 3:
                    976:                                return data & 0xff;
                    977:                        }
                    978:                }
                    979:                if (bits == 16) {
                    980:                        if (acc_paddrL == 0) {
                    981:                                return data >> 16;
                    982:                        } else {
                    983:                                return data & 0xffff;
                    984:                        }
                    985:                }
                    986:                if (bits == 32) {
                    987:                        return data;
                    988:                }
                    989:                __unreachable();
                    990:        }
                    991: }
                    992: 
                    993: uint64
                    994: m88200::load_8(uint32 addr)
                    995: {
                    996:        return load<8>(addr);
                    997: }
                    998: 
                    999: uint64
                   1000: m88200::load_16(uint32 addr)
                   1001: {
                   1002:        return load<16>(addr);
                   1003: }
                   1004: 
                   1005: uint64
                   1006: m88200::load_32(uint32 addr)
                   1007: {
                   1008:        return load<32>(addr);
                   1009: }
                   1010: 
                   1011: #define DEBUG_WT 1
                   1012: 
                   1013: template <int bits> uint64
                   1014: m88200::store(uint32 addr, uint32 data)
                   1015: {
                   1016:        uint64 rv;
                   1017: 
                   1018:        acc_laddr = addr;
                   1019:        acc_read  = false;
                   1020:        if (Translate() == false) {
                   1021:                return (uint64)-1;
                   1022:        }
                   1023:        if ((acc_stat & DESC_CI)) {
1.1.1.3   root     1024:                parent->AddCycle(7);    // Table.6-2
1.1       root     1025:                MBusAcquire();
                   1026:                rv = MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8);
                   1027:                MBusRelease();
                   1028:                return rv;
                   1029:        } else {
1.1.1.3   root     1030:                if (DEBUG_WT) {
                   1031:                        MBusAcquire();
1.1       root     1032:                        MBusWrite(acc_paddrH + acc_paddrL, data, bits / 8);
1.1.1.3   root     1033:                        MBusRelease();
                   1034:                }
1.1       root     1035:                return CacheWrite(acc_paddrH + acc_paddrL, data, bits / 8);
                   1036:        }
                   1037: }
                   1038: 
                   1039: uint64
                   1040: m88200::store_8(uint32 addr, uint32 data)
                   1041: {
                   1042:        return store<8>(addr, data);
                   1043: }
                   1044: 
                   1045: uint64
                   1046: m88200::store_16(uint32 addr, uint32 data)
                   1047: {
                   1048:        return store<16>(addr, data);
                   1049: }
                   1050: 
                   1051: uint64
                   1052: m88200::store_32(uint32 addr, uint32 data)
                   1053: {
                   1054:        return store<32>(addr, data);
                   1055: }
                   1056: 
                   1057: template <int bits> uint64
                   1058: m88200::xmem(uint32 addr, uint32 data)
                   1059: {
                   1060:        uint64 rv;
                   1061: 
                   1062:        acc_laddr = addr;
                   1063:        acc_read  = false;
                   1064:        if (Translate() == false) {
                   1065:                return (uint64)-1;
                   1066:        }
                   1067:        if ((acc_stat & DESC_CI)) {
                   1068:                // XXX キャッシュ禁止領域だとどうなる?
                   1069:                MBusAcquire();
                   1070:                rv = MBusXmem(acc_paddrH + acc_paddrL, data, bits / 8);
                   1071:                MBusRelease();
                   1072:                return rv;
                   1073:        } else {
                   1074:                return CacheXmem(acc_paddrH + acc_paddrL, data, bits / 8);
                   1075:        }
                   1076: }
                   1077: 
                   1078: uint64
                   1079: m88200::xmem_8(uint32 addr, uint32 data)
                   1080: {
                   1081:        return xmem<8>(addr, data);
                   1082: }
                   1083: 
                   1084: uint64
                   1085: m88200::xmem_32(uint32 addr, uint32 data)
                   1086: {
                   1087:        return xmem<32>(addr, data);
                   1088: }
                   1089: 
                   1090: //
                   1091: // アドレス変換
                   1092: //
                   1093: 
                   1094: // デバッグ用
                   1095: /*static*/ std::string
                   1096: m88200::stat2str(uint32 stat)
                   1097: {
                   1098:        std::string buf;
                   1099: 
                   1100:        if ((stat & m88200::DESC_WT))
                   1101:                buf += ",WT";
                   1102:        if ((stat & m88200::DESC_G))
                   1103:                buf += ",G";
                   1104:        if ((stat & m88200::DESC_CI))
                   1105:                buf += ",CI";
                   1106:        if ((stat & m88200::DESC_M))
                   1107:                buf += ",M";
                   1108:        if ((stat & m88200::DESC_U))
                   1109:                buf += ",U";
                   1110:        if ((stat & m88200::DESC_WP))
                   1111:                buf += ",WP";
                   1112: 
                   1113:        if (buf.empty()) {
                   1114:                buf = ",0";
                   1115:        }
                   1116:        return buf.substr(1);
                   1117: }
                   1118: 
                   1119: // アドレス変換。
                   1120: // 事前に acc_laddr, acc_super, acc_read を設定しておくこと。
                   1121: // 成功すれば acc_paddrH, acc_paddrL をセットして true を返す。
                   1122: // 失敗ならいろいろセットして(?) false を返す。
                   1123: // p2-3, Figure2-1
                   1124: bool
                   1125: m88200::Translate()
                   1126: {
                   1127:        uint32 la;
                   1128: 
                   1129:        // Logical address(LA) presented on PBus
                   1130: 
                   1131:        putlog(3, "Translate %c:$%08x", (acc_super ? 'S' : 'U'), acc_laddr);
                   1132: 
                   1133:        // 下位2ビットは常にこうなる。
                   1134:        acc_paddrL = acc_laddr & 3;
                   1135: 
                   1136:        // 2回しかループしないはず
                   1137:        for (int loop = 0; loop < 3; loop++) {
                   1138:                // Select Area Descriptor
                   1139:                if (SelectAreaDesc() == false) {
1.1.1.3   root     1140:                        // XXX 図のこれはたぶん間違いだよなあ…
                   1141:                        // 誤: Physical Address <= LA[18-2] :: 00
                   1142:                        // 正: Physical Address <= LA[31-2] :: 00
1.1       root     1143:                        acc_paddrH = acc_laddr - acc_paddrL;
1.1.1.3   root     1144: 
                   1145:                        parent->AddCycle(1);
1.1       root     1146:                        return true;
                   1147:                }
                   1148: 
                   1149:                // type == Valid ここから
                   1150: 
                   1151:                // Search BATC first
                   1152:                la = acc_laddr & 0xfff80000;
                   1153:                la |= acc_super ? BATC_S : 0;
                   1154:                for (int i = 0; i < batc.size(); i++) {
                   1155:                        m88200BATC& b = batc[i];
                   1156:                        if (b.lba == la) {
                   1157:                                // BATC hit
                   1158:                                putlog(4, " BATC[%d] hit", i);
                   1159:                                if (acc_IsWrite() && b.wp) {
                   1160:                                        goto write_violation;
                   1161:                                }
                   1162: 
                   1163:                                // Physical Address <= PBA :: LA[18-2] :: 00
                   1164:                                acc_paddrH = b.pba | (acc_laddr & 0x0007fffc);
                   1165:                                acc_stat |= b.stat;
                   1166:                                putlog(4, " BATC hit acc=%s paddr=$%08x",
                   1167:                                        stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3   root     1168: 
                   1169:                                parent->AddCycle(1);
1.1       root     1170:                                return true;
                   1171:                        }
                   1172:                }
                   1173: 
                   1174:                // BATC miss, search PATC then
                   1175:                la = acc_laddr & 0xfffff000;
                   1176:                la |= acc_super ? PATC_S : 0;
                   1177:                acc_patc = NULL;
                   1178:                for (int i = 0; i < patc.size(); i++) {
                   1179:                        m88200PATC& p = patc[i];
                   1180:                        if (p.lpa == la) {
                   1181:                                // PATC hit
                   1182:                                if (acc_IsWrite() && p.wp) {
                   1183:                                        putlog(4, " PATC[%d] hit; stat=%s m=%d wp=%d", i,
                   1184:                                                stat2str(p.stat).c_str(), p.m, p.wp);
                   1185:                                        goto write_violation;
                   1186:                                }
                   1187:                                if (acc_IsWrite() && p.m == false) {
                   1188:                                        // Update M bit
                   1189:                                        // フローチャートでは PATC[M] はこの後のテーブルサーチ中
                   1190:                                        // の Update Page Descriptor 処理中で更新するように書いて
                   1191:                                        // あるように読めるのだが、その通りに実装すると、メモリ
                   1192:                                        // 上の Page Descriptor に最初から M ビットが立っていると
                   1193:                                        // (というか OpenBSD カーネルが用意した Page Descriptor
                   1194:                                        // には立っているので) PATC[M] の更新も行われず、PATC[M]
                   1195:                                        // が立っていないので再びここに来てしまい無限ループになる。
                   1196:                                        // 誰が間違ってるのか分からないけど、とりあえずここで
                   1197:                                        // PATC[M] を立てれば問題は起きない。
                   1198:                                        putlog(4, " PATC[%d] hit; Need to update M bit", i);
                   1199:                                        p.m = true;
                   1200: 
                   1201:                                        // この下の PATC miss に合流する
                   1202:                                        acc_patc = &p;
                   1203:                                        break;
                   1204:                                }
                   1205: 
                   1206:                                // Physical Address <= PFA :: LA[11-2] :: 00
                   1207:                                acc_paddrH = p.pfa | (acc_laddr & 0x00000ffc);
                   1208:                                acc_stat |= p.stat;
                   1209:                                putlog(4, " PATC[%d] hit acc=%s paddr=$%08x", i,
                   1210:                                        stat2str(acc_stat).c_str(), acc_paddrH);
1.1.1.3   root     1211: 
                   1212:                                parent->AddCycle(1);
1.1       root     1213:                                return true;
                   1214:                        }
                   1215:                }
1.1.1.2   root     1216:                putlog(4, " BATC/PATC miss");
1.1       root     1217: 
                   1218:                // PATC miss
                   1219: 
                   1220:                // フローチャートでは PATC miss というラベルが付いてるが、コード
                   1221:                // では acc_patc は PATC ループ前に NULL にしてあり(=miss)、
                   1222:                // ループで PATC エントリが見付かれば acc_patc に代入してから
                   1223:                // break してここに来るので、ちょっとだけ見た目と違うが意図してる
                   1224:                // 動作は同じはず。
                   1225: 
                   1226:                // Table search operation
                   1227:                if (TableSearch() == true) {
                   1228:                        continue;
                   1229:                }
                   1230: 
                   1231:                // Invalid
                   1232:                // Reply with fault (Figure2-10 だがここではすべて不要)
                   1233:                return false;
                   1234:        }
                   1235:        PANIC("loop detected");
                   1236: 
                   1237:  write_violation:
                   1238:        fault_code = FAULT_CODE_WRITE;
                   1239:        //fault_addr UNKNOWN?
                   1240:        // Reply with fault (Figure2-10 だがここではすべて不要)
                   1241:        return false;
                   1242: }
                   1243: 
                   1244: 
                   1245: // Select Area Descriptor.
                   1246: // 結果が Type=Valid なら true、Type=Untranslated なら false を返す。
                   1247: // Probe Command からも呼ばれる。
                   1248: // p2-21, Figure2-5
                   1249: bool
                   1250: m88200::SelectAreaDesc()
                   1251: {
                   1252:        const m88200APR *xapr;
                   1253: 
                   1254:        if (acc_super) {
                   1255:                xapr = &sapr;
                   1256:        } else {
                   1257:                xapr = &uapr;
                   1258:        }
                   1259: 
                   1260:        acc_stat = xapr->stat & ACC_STAT_MASK;
                   1261:        if (xapr->enable) {
                   1262:                // セグメントディスクリプタのアドレスはここで決まるが、
                   1263:                // 次に行う BATC、PATC サーチでは使わず、それらが全部ミスして
                   1264:                // テーブルサーチまで来た所で初めて使うので、ここでは表示しない。
                   1265:                acc_sdaddr = xapr->addr | ((acc_laddr >> 20) & ~3U);
                   1266:                putlog(4, " %s acc=%s", xapr->name, stat2str(acc_stat).c_str());
                   1267:                return true;
                   1268:        } else {
                   1269:                putlog(3, " %s acc=%s Untranslated",
                   1270:                        xapr->name, stat2str(acc_stat).c_str());
                   1271:                return false;
                   1272:        }
                   1273: }
                   1274: 
                   1275: // Table Search
                   1276: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
                   1277: // p2-20, Figure2-4
                   1278: bool
                   1279: m88200::TableSearch()
                   1280: {
                   1281:        putlog(4, " %s $%08x/%s acc=%s", __func__, acc_laddr,
                   1282:                (acc_read ? "Read" : "Write"), stat2str(acc_stat).c_str());
                   1283: 
                   1284:        // XXX フローチャートを厳密に追っかけると MBus の Acquire/Release が
                   1285:        // 対応していないので(orz)、ここでは
                   1286:        // TableSearch() に入ったところで Acquire、
                   1287:        // TableSearch() から出るところで Release だけに統一する。
                   1288: 
                   1289:        MBusAcquire();
                   1290: 
                   1291:        if (FetchSegmentDesc() == false) {
                   1292:                MBusRelease();
1.1.1.3   root     1293: 
                   1294:                parent->AddCycle(7);    // Table.6-2
1.1       root     1295:                return false;
                   1296:        }
                   1297: 
                   1298:        if (FetchPageDesc() == false) {
                   1299:                MBusRelease();
1.1.1.3   root     1300: 
                   1301:                parent->AddCycle(11);   // Table.6-2
1.1       root     1302:                return false;
                   1303:        }
                   1304: 
                   1305:        // 中央の TYPE = VALID のところ
                   1306:        //                       ( )
                   1307:        //            +----------+ +----------+
                   1308:        //            |                       |
                   1309:        //      DESC[U]=0 ||              Otherwise
                   1310:        //  DESC[M]=0 && WRITE                |
                   1311:        //            |                       |
                   1312:        //     UpdatePageDesc                 |
                   1313:        //            |                       |
                   1314:        // <- RETRY -( )-- INVALID ---------- | -->
                   1315:        //            |                       |
                   1316:        //          VALID                     |
                   1317:        //            |                       |
                   1318:        //           ( ) <--------------------+
                   1319:        //           | |
                   1320:        //       +---+ +------------+
                   1321:        //   Otherwise    TableSearch due to PATC miss
                   1322:        //       |                  |
                   1323:        //  (Only U/M bits     CreatePATCEntry
                   1324:        //   Updated)               |
                   1325:        //       |                  v
                   1326:        //       +---------------> ( )
                   1327: 
                   1328:        if ((tmp_desc & DESC_U) == 0 ||
                   1329:            ((tmp_desc & DESC_M) == 0 && acc_IsWrite()))
                   1330:        {
1.1.1.3   root     1331:                parent->AddCycle(15);   // Table.6-2
                   1332: 
1.1       root     1333:                if (UpdatePageDesc() == false) {
                   1334:                        MBusRelease();
                   1335:                        return false;
                   1336:                }
1.1.1.3   root     1337:        } else {
                   1338:                parent->AddCycle(11);   // Table.6-2
1.1       root     1339:        }
                   1340: 
                   1341:        if (acc_patc == NULL) {
                   1342:                // Table search due to PATC miss
                   1343:                CreatePATCEntry();
                   1344:        }
                   1345: 
                   1346:        MBusRelease();
                   1347:        return true;
                   1348: }
                   1349: 
                   1350: // Fetch Segment Descriptor
                   1351: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
                   1352: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
                   1353: // p2-22, Figure2-6
                   1354: bool
                   1355: m88200::FetchSegmentDesc()
                   1356: {
                   1357:        uint64 data;
                   1358: 
                   1359:        data = MBusRead(acc_sdaddr, 4);
                   1360:        if ((int64)data < 0) {
                   1361:                return false;
                   1362:        }
                   1363:        tmp_desc = (uint32)data;
                   1364:        tmp_desc &= (0xfffff000 |
                   1365:                DESC_WT | DESC_SP | DESC_G | DESC_CI | DESC_WP | DESC_V);
                   1366: 
                   1367:        if ((tmp_desc & DESC_V) == 0) {
                   1368:                fault_code = FAULT_CODE_SEGMENT;
                   1369:                fault_addr = acc_sdaddr;
                   1370:                putlog(4, "  SD $%08x desc=$%08x SegFault", acc_sdaddr, tmp_desc);
                   1371:                return false;
                   1372:        } else {
                   1373:                // Descriptor is valid
                   1374: 
                   1375:                if ((tmp_desc & DESC_SP) && acc_super == 0) {
                   1376:                        fault_code = FAULT_CODE_SUPERVISOR;
                   1377:                        fault_addr = acc_sdaddr;
                   1378:                        putlog(4, "  SD $%08x desc=$%08x SupervisorFault",
                   1379:                                acc_sdaddr, tmp_desc);
                   1380:                        return false;
                   1381:                }
                   1382: 
                   1383:                acc_pdaddr = (tmp_desc & 0xfffff000) | ((acc_laddr >> 10) & 0xffc);
                   1384:                acc_stat |= tmp_desc & ACC_STAT_MASK;
                   1385:                putlog(4, "  SD $%08x pdaddr=$%08x stat=%s acc=%s",
                   1386:                        acc_sdaddr, acc_pdaddr,
                   1387:                        stat2str(tmp_desc).c_str(),
                   1388:                        stat2str(acc_stat).c_str());
                   1389:                return true;
                   1390:        }
                   1391: }
                   1392: 
                   1393: // Fetch Page Descriptor
                   1394: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
                   1395: // 公式フローチャートと違って MBus Acquire された状態で呼び出すこと。
                   1396: // p2-23, Figure2-7
                   1397: bool
                   1398: m88200::FetchPageDesc()
                   1399: {
                   1400:        uint64 data;
                   1401: 
                   1402:        data = MBusRead(acc_pdaddr, 4);
                   1403:        if ((int64)data < 0) {
                   1404:                return false;
                   1405:        }
                   1406:        tmp_desc = (uint32)data;
                   1407:        tmp_desc &= (0xfffff000 | DESC_WT | DESC_SP | DESC_G | DESC_CI |
                   1408:                DESC_M | DESC_U | DESC_WP | DESC_V);
                   1409: 
                   1410:        if ((tmp_desc & DESC_V) == 0) {
                   1411:                fault_code = FAULT_CODE_PAGE;
                   1412:                fault_addr = acc_pdaddr;
                   1413:                putlog(4, "  PD $%08x desc=$%08x PageFault", acc_pdaddr, tmp_desc);
                   1414:                return false;
                   1415:        } else {
                   1416:                // Descriptor is valid
                   1417: 
                   1418:                if ((tmp_desc & DESC_SP) && acc_super == 0) {
                   1419:                        fault_code = FAULT_CODE_SUPERVISOR;
                   1420:                        fault_addr = acc_pdaddr;
                   1421:                        putlog(4, "  PD $%08x desc=$%08x SupervisorFault",
                   1422:                                acc_pdaddr, tmp_desc);
                   1423:                        return false;
                   1424:                }
                   1425: 
                   1426:                acc_stat |= tmp_desc & ACC_STAT_MASK;
                   1427: 
                   1428:                if ((acc_stat & DESC_WP) && acc_IsWrite()) {
                   1429:                        fault_code = FAULT_CODE_WRITE;
                   1430:                        // fault_addr は invalid data
                   1431:                        fault_addr = 0xdeadbeef;
                   1432:                        putlog(4, "  PD $%08x desc=$%08x WriteFault", acc_pdaddr, tmp_desc);
                   1433:                        return false;
                   1434:                } else {
                   1435:                        putlog(4, "  PD $%08x stat=%s acc=%s", acc_pdaddr,
                   1436:                                stat2str(tmp_desc).c_str(),
                   1437:                                stat2str(acc_stat).c_str());
                   1438:                        return true;
                   1439:                }
                   1440:        }
                   1441: }
                   1442: 
                   1443: // Update Page Descriptor
                   1444: // Type=Valid なら true、Type=Invalid なら false を返す。Type=Retry はない。
                   1445: // p2-24, Figure2-8
                   1446: bool
                   1447: m88200::UpdatePageDesc()
                   1448: {
                   1449:        uint64 rv;
                   1450: 
                   1451:        if ((tmp_desc & DESC_M) == 0 && acc_IsWrite()) {
                   1452:                // Update Modified bit and accrue status
                   1453: 
                   1454:                // XXX 図中 PATC[M] をセットするとあるが、ここでは遅い気がする。
                   1455:                // Translate() 中の Update M bit のところのコメントも参照。
                   1456: 
                   1457:                // XXX 図中 ACC_STATUS[M] は TEMP_DESCR[M] じゃないの?
                   1458:                tmp_desc |= DESC_M;
                   1459:        }
                   1460: 
                   1461:        // Update Used bit
                   1462:        tmp_desc |= DESC_U;
                   1463: 
                   1464:        rv = MBusWrite(acc_pdaddr, tmp_desc, 4);
                   1465:        if ((int64)rv < 0) {
                   1466:                return false;
                   1467:        }
                   1468:        putlog(4, "  Update PD $%08x desc=$%08x stat=%s",
                   1469:                acc_pdaddr, tmp_desc, stat2str(tmp_desc).c_str());
                   1470: 
                   1471:        return true;
                   1472: }
                   1473: 
                   1474: // Create PATC Entry
                   1475: // 公式フローチャートと違って MBus Acquire したまま戻ること。
                   1476: // p2-25, Figure2-9
                   1477: void
                   1478: m88200::CreatePATCEntry()
                   1479: {
                   1480:        // とりあえず線形探索で memcpy しとくべ
                   1481:        memmove(&patc[1], &patc[0], sizeof(patc[0]) * (patc.size() - 1));
                   1482:        // で、先頭に追加
                   1483:        m88200PATC& p = patc[0];
                   1484: 
                   1485:        memset(&p, 0, sizeof(p));
                   1486:        p.lpa = acc_laddr & 0xfffff000;
                   1487:        p.pfa = tmp_desc & 0xfffff000;
                   1488:        if (acc_super) {
                   1489:                p.lpa |= PATC_S;
                   1490:        }
                   1491:        p.stat = acc_stat;
                   1492:        putlog(4, "  %s %c:$%08x:$%08x stat=%s", __func__,
                   1493:                (p.lpa & PATC_S) ? 'S' : 'U', (p.lpa & 0xfffff000), p.pfa,
                   1494:                stat2str(p.stat).c_str());
                   1495: }
                   1496: 
                   1497: // アドレス変換 (デバッガ用)
                   1498: uint64
                   1499: m88200::TranslatePeek(uint32 laddr, bool issuper, bool do_search) const
                   1500: {
                   1501:        const m88200APR *xapr;
                   1502:        uint32 la;
                   1503: 
                   1504:        // Select Area Descriptor
                   1505:        if (issuper) {
                   1506:                xapr = &sapr;
                   1507:        } else {
                   1508:                xapr = &uapr;
                   1509:        }
                   1510:        if (xapr->enable == 0) {
                   1511:                return laddr;
                   1512:        }
                   1513: 
                   1514:        // Search BATC first
                   1515:        la = laddr & 0xfff80000;
                   1516:        la |= issuper ? BATC_S : 0;
                   1517:        for (const auto& b : batc) {
                   1518:                if (b.lba == la) {
                   1519:                        // BATC hit
                   1520:                        return b.pba | (laddr & 0x0007ffff);
                   1521:                }
                   1522:        }
                   1523: 
                   1524:        // BATC miss, search PATC then
                   1525:        la = laddr & 0xfffff000;
                   1526:        la |= issuper ? PATC_S : 0;
                   1527:        for (const auto& p : patc) {
                   1528:                if (p.lpa == la) {
                   1529:                        // PATC hit
                   1530:                        return p.pfa | (laddr & 0x00000fff);
                   1531:                }
                   1532:        }
                   1533: 
                   1534:        if (do_search == false) {
                   1535:                return (uint64)-1;
                   1536:        }
                   1537: 
                   1538:        // ここからテーブルサーチ
                   1539:        uint64 data;
                   1540:        uint32 desc_addr;
                   1541:        uint32 desc;
                   1542: 
                   1543:        // Peek Segment Descriptor
                   1544:        desc_addr = xapr->addr | ((laddr >> 20) & ~3U);
                   1545:        data = vm_phys_peek_32(desc_addr);
                   1546:        if ((int64)data < 0) {
                   1547:                return data;
                   1548:        }
                   1549:        desc = (uint32)data;
                   1550:        if ((desc & DESC_V) == 0) {
                   1551:                return (uint64)-1;
                   1552:        }
                   1553:        if ((desc & DESC_SP) && issuper == false) {
                   1554:                return (uint64)-1;
                   1555:        }
                   1556: 
                   1557:        // Peek Page Descriptor
                   1558:        desc_addr = (desc & 0xfffff000) | ((laddr >> 10) & 0xffc);
                   1559:        data = vm_phys_peek_32(desc_addr);
                   1560:        if ((int64)data < 0) {
                   1561:                return data;
                   1562:        }
                   1563:        desc = (uint32)data;
                   1564:        if ((desc & DESC_V) == 0) {
                   1565:                return (uint64)-1;
                   1566:        }
                   1567:        if ((desc & DESC_SP) && issuper == false) {
                   1568:                return (uint64)-1;
                   1569:        }
                   1570: 
                   1571:        return (desc & 0xfffff000) | (laddr & 0x00000fff);
                   1572: }
                   1573: 
                   1574: 
                   1575: //
                   1576: // キャッシュ
                   1577: //
                   1578: 
                   1579: // このラインの状態を更新
                   1580: void
                   1581: m88200CacheSet::Update(int line, m88200CacheSet::Status status)
                   1582: {
                   1583:        vv[line] = status;
                   1584:        if (status == IV) {
                   1585:                // 無効なら
                   1586:                tag[line] |= TAG_INVALID;
                   1587:                L = TryUnuseLine(L, line);
                   1588:        }
                   1589: }
                   1590: 
                   1591: // CSSP L5-L0 の処理。
                   1592: // 引数 tmpL の状態から line を最新にしたらどうなるか、を返す。
                   1593: // 表示処理で一時変数に対して処理が必要なため分離してある。
                   1594: int
                   1595: m88200CacheSet::TryUseLine(int tmpL, int line)
                   1596: {
                   1597:        // L フィールドは 3bit, 2bit, 1bit で構成され、
                   1598:        // 他のラインの対応ビットを落として、
                   1599:        // 自分のラインの対応ビットを全部立てれば、
                   1600:        // 他のラインの順序を保存した状態で、自分が最新になるように
                   1601:        // 順序をつけられる。
                   1602: 
                   1603:        if (line == 3) {
                   1604:                tmpL |= 0b111'00'0;
                   1605:        } else if (line == 2) {
                   1606:                tmpL &= 0b011'11'1;
                   1607:                tmpL |= 0b000'11'0;
                   1608:        } else if (line == 1) {
                   1609:                tmpL &= 0b101'01'1;
                   1610:                tmpL |= 0b000'00'1;
                   1611:        } else {
                   1612:                tmpL &= 0b110'10'0;
                   1613:        }
                   1614:        return tmpL;
                   1615: }
                   1616: 
                   1617: // CSSP L5-L0 の処理。
                   1618: // 引数 tmpL の状態から line を最古にしたらどうなるか、を返す。
                   1619: int
                   1620: m88200CacheSet::TryUnuseLine(int tmpL, int line)
                   1621: {
                   1622:        // Use のちょうど反転論理
                   1623:        if (line == 3) {
                   1624:                tmpL &= 0b000'11'1;
                   1625:        } else if (line == 2) {
                   1626:                tmpL |= 0b100'00'0;
                   1627:                tmpL &= 0b111'00'1;
                   1628:        } else if (line == 1) {
                   1629:                tmpL |= 0b010'10'0;
                   1630:                tmpL &= 0b111'11'0;
                   1631:        } else {
                   1632:                tmpL |= 0b001'01'1;
                   1633:        }
                   1634:        return tmpL;
                   1635: }
                   1636: 
                   1637: // CSSP L5-L0 の処理。
                   1638: // 引数 tmpL の状態で、最新の line を返す。
                   1639: // 表示処理で一時変数に対して処理が必要なため分離してある。
                   1640: int
                   1641: m88200CacheSet::TryGetOldestLine(int tmpL)
                   1642: {
                   1643:        if (tmpL < 8) {
                   1644:                return 3;
                   1645:        }
                   1646:        tmpL &= 7;
                   1647:        if (tmpL < 2) {
                   1648:                return 2;
                   1649:        }
                   1650:        tmpL &= 1;
                   1651:        if (tmpL == 0) {
                   1652:                return 1;
                   1653:        } else {
                   1654:                return 0;
                   1655:        }
                   1656: }
                   1657: 
                   1658: // 更新用に最も古いラインを選んで差し出す
                   1659: int
                   1660: m88200CacheSet::SelectOldestLine() const
                   1661: {
                   1662:        // なければ、最も古いラインを差し出す
                   1663:        return TryGetOldestLine(L);
                   1664: }
                   1665: 
                   1666: // キャッシュの指定の line, word に data を書き込む。
                   1667: // size は 1, 2, 4 バイト。
                   1668: void
                   1669: m88200CacheSet::Write(int line, uint32 paddr, uint32 data, int size)
                   1670: {
                   1671:        uint32 wordidx = (paddr >> 2) & 0x03;
                   1672:        uint32 data32;
                   1673: 
                   1674:        if (__predict_true(size == 4)) {
                   1675:                word[line * 4 + wordidx] = data;
                   1676:                return;
                   1677:        }
                   1678: 
                   1679:        data32 = word[line * 4 + wordidx];
                   1680:        if (size == 2) {
                   1681:                if ((paddr & 2) == 0) {
                   1682:                        data32 = (data32 & 0x0000ffff) | (data << 16);
                   1683:                } else {
                   1684:                        data32 = (data32 & 0xffff0000) | data;
                   1685:                }
                   1686:        } else {
                   1687:                switch (paddr & 3) {
                   1688:                 case 0:
                   1689:                        data32 = (data32 & 0x00ffffff) | (data << 24);
                   1690:                        break;
                   1691:                 case 1:
                   1692:                        data32 = (data32 & 0xff00ffff) | (data << 16);
                   1693:                        break;
                   1694:                 case 2:
                   1695:                        data32 = (data32 & 0xffff00ff) | (data << 8);
                   1696:                        break;
                   1697:                 case 3:
                   1698:                        data32 = (data32 & 0xffffff00) | data;
                   1699:                        break;
                   1700:                 default:
                   1701:                        __unreachable();
                   1702:                }
                   1703:        }
                   1704:        word[line * 4 + wordidx] = data32;
                   1705: }
                   1706: 
1.1.1.3   root     1707: // キャッシュを検索。
                   1708: // ヒットすれば line 番号(0..3) を返す。ヒットしなければ -1 を返す。
                   1709: int
                   1710: m88200CacheSet::Lookup(uint32 tagaddr) const
                   1711: {
                   1712:        for (int line = 0; line < 4; line++) {
                   1713:                if (tag[line] == tagaddr) {
                   1714:                        return line;
                   1715:                }
                   1716:        }
                   1717:        return -1;
                   1718: }
                   1719: 
                   1720: 
                   1721: // キャッシュの指定の set, line にメモリから 1 ライン(4word) 読み込む。
1.1       root     1722: // 成功すれば 0 を返す。
1.1.1.3   root     1723: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
1.1       root     1724: uint64
1.1.1.3   root     1725: m88200::ReadLine(m88200CacheSet& set, int line, uint32 tagaddr)
1.1       root     1726: {
                   1727:        uint32 addr;
1.1.1.3   root     1728:        uint64 data;
                   1729: 
                   1730:        // キャッシュラインの充填は実機では Burst Read されているらしいが
                   1731:        // nono では Burst Read 用のメソッドは用意しておらず通常の 32bit
                   1732:        // アクセスをしているため、このままでは所要ウェイト数が正しくない。
                   1733:        // そこでここで差を調整することにする。
                   1734:        // vm_phys_read_32() 4回なのでこれによって 12 wait が加算される。一方
                   1735:        // 実機の Burst Read は取扱説明書によると 320ns (8 サイクル) で完了
                   1736:        // するようなので、その差 4 をあらかじめ引いておく。
                   1737:        // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4   root     1738:        AddCycle(-4);
1.1.1.3   root     1739: 
                   1740:        // タグを更新
                   1741:        set.tag[line] = tagaddr;
1.1       root     1742: 
1.1.1.3   root     1743:        addr = set.tag[line] | (set.setidx << 4);
1.1       root     1744:        for (int i = 0; i < 4; i++) {
1.1.1.3   root     1745:                data = vm_phys_read_32(addr);
                   1746:                if ((int64)data < 0) {
                   1747:                        fault_code = FAULT_CODE_BUSERR;
                   1748:                        fault_addr = addr;
                   1749:                        return data;
1.1       root     1750:                }
1.1.1.3   root     1751:                set.word[line * 4 + i] = data;
1.1       root     1752:                addr += 4;
                   1753:        }
                   1754:        return 0;
                   1755: }
                   1756: 
1.1.1.3   root     1757: // キャッシュの指定の set, line を1ライン、メモリに書き出す(コピーバック)。
                   1758: // 成功すれば 0 を返す。
                   1759: // バスエラーなら fault_code, fault_addr をセットし (uint64)-1 を返す。
                   1760: uint64
                   1761: m88200::CopyBackLine(m88200CacheSet& set, int line)
1.1       root     1762: {
1.1.1.3   root     1763:        uint32 addr;
                   1764: 
                   1765:        // キャッシュラインの書き出しは実機では Burst Write されているらしいが
                   1766:        // nono では Burst Write 用のメソッドは用意しておらず通常の 32bit
                   1767:        // アクセスをしているため、このままでは所要ウェイト数が正しくない。
                   1768:        // そこでここで差を調整することにする。
                   1769:        // vm_phys_write_32() 4回なのでこれによって 8 wait が加算される。一方
                   1770:        // 実機の Burst Write は取扱説明書によると 280ns (7サイクル) で完了する
                   1771:        // ようなので、その差 1 をあらかじめて引いておく。
                   1772:        // 途中でバスエラーが起きたらとかそこまでは考慮しない。
1.1.1.4   root     1773:        AddCycle(-1);
1.1.1.3   root     1774: 
                   1775:        addr = set.tag[line] | (set.setidx << 4);
                   1776:        for (int i = 0; i < 4; i++) {
                   1777:                uint64 rv = vm_phys_write_32(addr, set.word[line * 4 + i]);
                   1778:                if ((int64)rv < 0) {
                   1779:                        fault_code = FAULT_CODE_BUSERR;
                   1780:                        fault_addr = addr;
                   1781:                        return rv;
1.1       root     1782:                }
1.1.1.3   root     1783:                addr += 4;
1.1       root     1784:        }
1.1.1.3   root     1785:        return 0;
1.1       root     1786: }
                   1787: 
                   1788: // キャッシュに対して paddr の読み込みを行う。
                   1789: // paddr は 32bit 境界のアドレスであること。
                   1790: // 読み込めれば該当の32bitワードを返す。
                   1791: // 何らかエラーが起きれば (uint64)-1 を返す。エラー要因は fault_code とか参照。
                   1792: // p.3-8 Figure 3-3
                   1793: uint64
                   1794: m88200::CacheRead(uint32 paddr)
                   1795: {
                   1796:        int line;
                   1797:        uint64 rv;
                   1798: 
                   1799:        assert((paddr & 3) == 0);
                   1800: 
                   1801:        // タグとセット番号
                   1802:        uint32 tagaddr = (paddr & 0xfffff000);
                   1803:        uint32 setidx  = (paddr >> 4) & 0xff;
                   1804:        uint32 wordidx = (paddr >> 2) & 0x03;
                   1805: 
                   1806:        m88200CacheSet& set = setarray[setidx];
                   1807:        putlog(3, "CacheRead paddr=$%08x (set=$%02x)", paddr, setidx);
                   1808: 
                   1809:        line = set.Lookup(tagaddr);
                   1810:        if (line >= 0) {
                   1811:                // Cache Hit
                   1812:                putlog(4, " CacheRead hit (line=%d,word=%d)", line, wordidx);
1.1.1.3   root     1813:                parent->AddCycle(1);
1.1       root     1814:                goto success;
                   1815:        }
                   1816: 
                   1817:        // Cache Miss
                   1818: 
1.1.1.3   root     1819:        parent->AddCycle(10);   // Table.6-2
                   1820: 
1.1       root     1821:        // reply <- Wait
                   1822:        MBusAcquire();
                   1823: 
                   1824:        // Select cache line for replacement
                   1825:        line = set.SelectOldestLine();
                   1826:        putlog(4, " CacheRead miss (replace line=%d)", line);
                   1827: 
                   1828:        if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3   root     1829:                parent->AddCycle(7);    // Table.6-2
                   1830:                rv = CopyBackLine(set, line);
1.1       root     1831:                if ((int64)rv < 0) {
                   1832:                        goto error;
                   1833:                }
                   1834:        }
                   1835: 
                   1836:        // Mark cache line invalid
                   1837:        set.Update(line, m88200CacheSet::IV);
                   1838: 
                   1839:        // Read line from memory
1.1.1.3   root     1840:        rv = ReadLine(set, line, tagaddr);
1.1       root     1841:        if ((int64)rv < 0) {
                   1842:                goto error;
                   1843:        }
                   1844: 
                   1845:        MBusRelease();
                   1846: 
                   1847:        // Update cache line
                   1848:        set.Update(line, m88200CacheSet::SU);
                   1849: 
                   1850:        putlog(4, " CacheRead updated (line=%d,word=%d)", line, wordidx);
                   1851:  success:
                   1852:        set.Use(line);
                   1853:        return set.word[line * 4 + wordidx];
                   1854: 
                   1855:  error:
                   1856:        MBusRelease();
                   1857:        return (uint64)-1;
                   1858: }
                   1859: 
                   1860: // キャッシュに対して paddr への data の書き込みを行う。size は 1, 2, 4 バイト。
                   1861: // paddr は size に応じた境界にあること。
                   1862: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
                   1863: // エラー要因は fault_code とか参照。
                   1864: // p.3-10 Figure 3-5
                   1865: uint64
                   1866: m88200::CacheWrite(uint32 paddr, uint32 data, int size)
                   1867: {
                   1868:        int line;
                   1869:        uint64 rv;
                   1870: 
                   1871:        assert((paddr & (size - 1)) == 0);
                   1872: 
                   1873:        // タグとセット番号
                   1874:        uint32 tagaddr = (paddr & 0xfffff000);
                   1875:        uint32 setidx  = (paddr >> 4) & 0xff;
                   1876: 
                   1877:        m88200CacheSet& set = setarray[setidx];
                   1878:        putlog(3, "CacheWrite paddr=$%08x (set=$%02x)", paddr, setidx);
                   1879: 
                   1880:        line = set.Lookup(tagaddr);
                   1881:        if (line >= 0) {
                   1882:                // Cache Hit
1.1.1.3   root     1883:                parent->AddCycle(1);
1.1       root     1884:                return CacheWriteHit(set, line, paddr, data, size);
                   1885:        }
                   1886: 
                   1887:        // Cache Miss
                   1888: 
1.1.1.3   root     1889:        parent->AddCycle(14);   // Table.6-2
                   1890: 
1.1       root     1891:        // reply <- Wait
                   1892:        MBusAcquire();
                   1893: 
                   1894:        // Select cache line for replacement
                   1895:        line = set.SelectOldestLine();
                   1896:        putlog(4, " CacheWrite miss (replace line=%d)", line);
                   1897: 
                   1898:        if (set.vv[line] == m88200CacheSet::EM) {
1.1.1.3   root     1899:                parent->AddCycle(7);    // Table.6-2
                   1900:                rv = CopyBackLine(set, line);
1.1       root     1901:                if ((int64)rv < 0) {
                   1902:                        goto error;
                   1903:                }
                   1904:        }
                   1905: 
                   1906:        // Mark line invalid
                   1907:        set.Update(line, m88200CacheSet::IV);
                   1908: 
                   1909:        // Read line with intent to modify
1.1.1.3   root     1910:        rv = ReadLine(set, line, tagaddr);
1.1       root     1911:        if ((int64)rv < 0) {
                   1912:                goto error;
                   1913:        }
                   1914: 
                   1915:        // Write data to memory
                   1916:        rv = MBusWrite(paddr, data, size);
                   1917:        if ((int64)rv < 0) {
1.1.1.3   root     1918:                goto error;
1.1       root     1919:        }
                   1920: 
                   1921:        // Write data into cache
                   1922:        set.Write(line, paddr, data, size);
                   1923: 
                   1924:        // Mark line exclusive unmodified
                   1925:        set.Update(line, m88200CacheSet::EU);
                   1926:        set.Use(line);
                   1927: 
                   1928:        MBusRelease();
                   1929:        return 0;
                   1930: 
                   1931:  error:
                   1932:        MBusRelease();
                   1933:        return (uint64)-1;
                   1934: }
                   1935: 
                   1936: // キャッシュがヒットした場合。
                   1937: // 書き込めれば 0、エラーが起きれば (uint64)-1 を返す。
                   1938: // p3-11 Figure 3-6
                   1939: uint64
                   1940: m88200::CacheWriteHit(m88200CacheSet& set, int line,
                   1941:        uint32 paddr, uint32 data, int size)
                   1942: {
                   1943:        uint64 rv;
                   1944: 
                   1945:        if (set.vv[line] == m88200CacheSet::SU) {
                   1946:                // Line Shared Unmodified の場合
                   1947: 
                   1948:                putlog(4, " CacheWrite hit shared unmodified (line=%d)", line);
                   1949: 
                   1950:                // WriteThrough と Global は最後の状態変化だけが違う
                   1951:                if ((acc_stat & (DESC_WT | DESC_G))) {
                   1952:                        // reply = Wait;
                   1953:                        MBusAcquire();
                   1954: 
                   1955:                        // Write data to cache
                   1956:                        set.Write(line, paddr, data, size);
                   1957: 
                   1958:                        // Write data to memory
                   1959:                        rv = MBusWrite(paddr, data, size);
                   1960:                        if ((int64)rv < 0) {
                   1961:                                MBusRelease();
                   1962:                                return rv;
                   1963:                        }
                   1964: 
                   1965:                        if ((acc_stat & DESC_WT)) {
                   1966:                                // Mark line shared unmodified
                   1967:                                set.Update(line, m88200CacheSet::SU);
                   1968:                        } else {
                   1969:                                // Mark line exclusive unmodified
                   1970:                                set.Update(line, m88200CacheSet::EU);
                   1971:                        }
                   1972:                        set.Use(line);
                   1973: 
                   1974:                        MBusRelease();
                   1975:                        return 0;
                   1976:                }
                   1977: 
                   1978:                // どちらでもない場合は Line Exclusive と同じ処理に落ちる
                   1979:        }
                   1980: 
                   1981:        // Line Exclusive の場合
                   1982: 
                   1983:        putlog(4, " CacheWrite hit exclusive (line=%d)", line);
                   1984: 
                   1985:        // Write data into cache
                   1986:        putlog(4, " CacheWrite line=%d $%08x sz=%d", line, paddr, size);
                   1987:        set.Write(line, paddr, data, size);
                   1988: 
                   1989:        // Mark line exclusive modified
                   1990:        set.Update(line, m88200CacheSet::EM);
                   1991:        set.Use(line);
                   1992:        return 0;
                   1993: }
                   1994: 
                   1995: // paddr への xmem を行う。size は 1, 2, 4 バイト。
                   1996: // 成功すれば読み出した値、エラーが起きれば (uint64)-1 を返す。
                   1997: // p3-13, Figure3-7
                   1998: uint64
                   1999: m88200::CacheXmem(uint32 paddr, uint32 data, int size)
                   2000: {
                   2001:        int line;
                   2002:        uint64 rv;
                   2003: 
                   2004:        assert((paddr & (size - 1)) == 0);
                   2005: 
                   2006:        // タグとセット番号
                   2007:        uint32 tagaddr = (paddr & 0xfffff000);
                   2008:        uint32 setidx  = (paddr >> 4) & 0xff;
                   2009: 
                   2010:        m88200CacheSet& set = setarray[setidx];
                   2011:        putlog(3, "CacheXmem paddr=$%08x (set=$%02x)", paddr, setidx);
                   2012: 
                   2013:        line = set.Lookup(tagaddr);
                   2014:        if (line >= 0 && set.vv[line] == m88200CacheSet::EM) {
                   2015:                // Cache Hit (and Line exclusive modified)
                   2016:                putlog(4, " CacheXmem hit and EM (line=%d)", line);
                   2017: 
                   2018:                MBusAcquire();
                   2019: 
1.1.1.3   root     2020:                parent->AddCycle(7);    // Table.6-2
                   2021:                rv = CopyBackLine(set, line);
1.1       root     2022:                if ((int64)rv < 0) {
                   2023:                        goto error;
                   2024:                }
                   2025: 
                   2026:                set.Update(line, m88200CacheSet::IV);
                   2027:        } else {
                   2028:                // Cache Miss or (Cache Hit but other than exclusive modified)
                   2029: 
                   2030:                if (line >= 0) {
                   2031:                        // Cache Hit and Otherwise (= !EM)
                   2032:                        putlog(4, " CacheXmem hit but !EM (line=%d)", line);
                   2033:                        set.Update(line, m88200CacheSet::IV);
                   2034:                } else {
                   2035:                        putlog(4, " CacheXmem miss");
                   2036:                }
                   2037: 
                   2038:                MBusAcquire();
                   2039:        }
                   2040: 
                   2041:        rv = MBusXmem(paddr, data, size);
                   2042:        MBusRelease();
                   2043:        return rv;
                   2044: 
                   2045:  error:
                   2046:        MBusRelease();
                   2047:        return rv;
                   2048: }
1.1.1.3   root     2049: 
                   2050: // サイクルを加算する (VM から使う)
                   2051: void
1.1.1.4   root     2052: m88200::AddCycle(int32 cycle)
1.1.1.3   root     2053: {
                   2054:        parent->AddCycle(cycle);
                   2055: }
                   2056: 
                   2057: // MBus 使用権を取得する
                   2058: void
                   2059: m88200::MBusAcquire()
                   2060: {
                   2061:        // アービトレーションのたびに1クロックかかる(?)
                   2062:        // よく分からんけど、とりあえず、CMMU は一度所有権を持ったら放さない、
                   2063:        // 別の CMMU がバスリクエストすると所有権はその CMMU に移る、とする。
                   2064:        if (mbus_master != this) {
                   2065:                mbus_master = this;
                   2066:                parent->AddCycle(1);
                   2067:        }
                   2068: }

unix.superglobalmegacorp.com

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