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

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

unix.superglobalmegacorp.com

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