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

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

unix.superglobalmegacorp.com

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