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

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

unix.superglobalmegacorp.com

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