Annotation of nono/debugger/vectortable.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2022 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // ベクタテーブル (モニタ)
                      9: //
                     10: 
                     11: #include "vectortable.h"
                     12: #include "mainapp.h"
1.1.1.3   root       13: #include "mainbus.h"
1.1.1.6   root       14: #include "monitor.h"
1.1       root       15: #include "mpu.h"
                     16: 
                     17: // コンストラクタ
1.1.1.2   root       18: VectorTable::VectorTable(VMType vmtype)
1.1.1.3   root       19:        : inherited(OBJ_VECTOR_TABLE)
1.1       root       20: {
                     21:        // ログは不要
                     22:        ClearAlias();
                     23: 
1.1.1.8 ! root       24:        monitor = gMonitorManager->Regist(ID_SUBWIN_VECTOR, this);
        !            25: 
1.1       root       26:        // 表示名を作成。それぞれ微妙に処理が違う…
1.1.1.8 ! root       27:        int w = 75;
1.1       root       28:        switch (vmtype) {
1.1.1.2   root       29:         case VMType::X68030:
                     30:         case VMType::LUNA1:
1.1.1.3   root       31:         case VMType::NEWS:
1.1.1.4   root       32:         case VMType::VIRT68K:
1.1.1.6   root       33:                InitTableM680x0(vmtype);
1.1.1.8 ! root       34:                monitor->func = ToMonitorCallback(&VectorTable::MonitorUpdateM680x0);
1.1       root       35:                break;
1.1.1.2   root       36:         case VMType::LUNA88K:
1.1       root       37:                InitTableLuna88k();
1.1.1.8 ! root       38:                monitor->func = ToMonitorCallback(&VectorTable::MonitorUpdateM88xx0);
        !            39:                // ベクタが(16進数で)3桁必要。
        !            40:                w++;
1.1       root       41:                break;
1.1.1.2   root       42:         default:
                     43:                PANIC("invalid vmtype %d", (int)vmtype);
1.1       root       44:        }
                     45: 
1.1.1.8 ! root       46:        monitor->SetSize(w, 1 + 32);    // ヘッダの1行と全エントリ数
1.1.1.6   root       47:        monitor->SetMaxHeight(1 + Size());
1.1       root       48: }
                     49: 
1.1.1.6   root       50: // m68k 機種の表示名テーブル初期化。コンストラクタの一部。
1.1       root       51: void
1.1.1.6   root       52: VectorTable::InitTableM680x0(VMType vmtype)
1.1       root       53: {
                     54:        nametable.clear();
                     55:        nametable.resize(256);
                     56: 
1.1.1.6   root       57:        // まず m680x0 標準の名称で埋める
1.1       root       58:        for (int v = 0; v < 64; v++) {
1.1.1.6   root       59:                if (name_m680x0[v]) {
                     60:                        nametable[v] = name_m680x0[v];
1.1       root       61:                }
                     62:        }
                     63: 
1.1.1.3   root       64:        // 機種ごとに必要なところだけ上書き
                     65:        const std::map<int, const char * const> *names;
1.1.1.6   root       66:        switch (vmtype) {
                     67:         case VMType::X68030:
1.1.1.3   root       68:                names = &name_x68030;
1.1.1.6   root       69:                break;
                     70:         case VMType::LUNA1:
1.1.1.3   root       71:                names = &name_luna1;
1.1.1.6   root       72:                break;
                     73:         case VMType::NEWS:
1.1.1.3   root       74:                names = &name_news;
1.1.1.6   root       75:                break;
                     76:         case VMType::VIRT68K:
                     77:                names = &name_virt68k;
                     78:                break;
                     79:         default:
                     80:                names = NULL;
                     81:                break;
1.1.1.3   root       82:        }
1.1.1.6   root       83:        if (names) {
                     84:                for (const auto& p : *names) {
                     85:                        int v = p.first;
                     86:                        const char *name = p.second;
                     87:                        nametable[v] = name;
                     88:                }
1.1       root       89:        }
                     90: }
                     91: 
1.1.1.3   root       92: // LUNA-88K の表示名テーブルを初期化。コンストラクタの一部。
1.1       root       93: void
                     94: VectorTable::InitTableLuna88k()
                     95: {
                     96:        nametable.clear();
                     97:        nametable.resize(512);
                     98: 
1.1.1.8 ! root       99:        for (const auto& p : name_luna88k) {
        !           100:                int v = p.first;
        !           101:                const char *name = p.second;
        !           102:                nametable[v] = name;
1.1       root      103:        }
                    104: }
                    105: 
1.1.1.3   root      106: // デストラクタ
                    107: VectorTable::~VectorTable()
                    108: {
                    109: }
                    110: 
                    111: // 初期化
                    112: bool
                    113: VectorTable::Init()
                    114: {
                    115:        mainbus = GetMainbusDevice();
                    116:        mpu = GetMPUDevice();
                    117: 
                    118:        return true;
                    119: }
                    120: 
1.1       root      121: // 例外名を返す (例外履歴用)。
                    122: // 名前がなければ NULL を返す。
                    123: const char *
                    124: VectorTable::GetExceptionName(int vector) const
                    125: {
                    126:        assertmsg(0 <= vector && vector < nametable.size(), "vector=%d", vector);
                    127: 
                    128:        if (__predict_false(vector < 2)) {
1.1.1.2   root      129:                if (gMainApp.Has(VMCap::M68K)) {
1.1       root      130:                        // ベクタテーブル的には 0:"Reset(SP)"、1:"Reset(PC)" のほうが
                    131:                        // 分かりやすいが、例外の名前は 0 が "Reset Exception" で
                    132:                        // 1 は存在しない。
                    133:                        if (vector == 0) {
                    134:                                return "Reset Exception";
                    135:                        } else {
                    136:                                return "(vector 1?)";
                    137:                        }
                    138:                }
                    139:        }
                    140: 
1.1.1.7   root      141:        return nametable[vector];
1.1       root      142: }
                    143: 
1.1.1.8 ! root      144: // モニタ更新 (M680x0)
1.1       root      145: void
1.1.1.8 ! root      146: VectorTable::MonitorUpdateM680x0(Monitor *, TextScreen& screen)
1.1       root      147: {
1.1.1.5   root      148: // 0         1         2         3         4         5         6         7
                    149: // 012345678901234567890123456789012345678901234567890123456789012345678901234
                    150: // No.      Offset Address   Name                  ><                    Count
                    151: // $02(  2) $0008  $12345678 0123456789012345678901201234567890123456789012345
1.1       root      152: 
1.1.1.3   root      153:        uint32 vbr = mpu->GetVBR();
1.1       root      154: 
                    155:        // userdata が表示開始位置
                    156:        int v = (int)screen.userdata;
                    157:        int row = screen.GetRow();
                    158:        int vend = v + row - 1;
                    159: 
                    160:        screen.Clear();
                    161: 
                    162:        // 最初の1行は常にヘッダ
                    163:        screen.Print(0, 0, "No.      Offset Address   Name");
1.1.1.5   root      164:        screen.Print(70, 0, "Count");
1.1       root      165: 
                    166:        for (int y = 1; v < vend; v++, y++) {
1.1.1.5   root      167:                screen.Print(0, y, "$%02x(%3u) $%04x", v, v, v * 4);
                    168:                busdata addr = mainbus->Peek4(vbr + v * 4);
1.1.1.4   root      169:                if (__predict_false(addr.IsBusErr())) {
1.1       root      170:                        screen.Print(16, y, "BusErr");
                    171:                } else {
1.1.1.4   root      172:                        screen.Print(16, y, "$%08x", addr.Data());
1.1       root      173:                }
1.1.1.7   root      174:                screen.Print(26, y, "%-23s", nametable[v] ?: "");
1.1.1.5   root      175:                screen.Print(49, y, "%26s",
                    176:                        format_number(mpu->excep_counter[v]).c_str());
1.1       root      177:        }
                    178: }
                    179: 
1.1.1.8 ! root      180: // モニタ更新 (M88xx0)
        !           181: void
        !           182: VectorTable::MonitorUpdateM88xx0(Monitor *, TextScreen& screen)
        !           183: {
        !           184: // 0         1         2         3         4         5         6         7
        !           185: // 0123456789012345678901234567890123456789012345678901234567890123456789012346
        !           186: // No.       Offset Address   Name                  ><                    Count
        !           187: // $002(  2) $0010 @$12345678 0123456789012345678901201234567890123456789012345
        !           188: 
        !           189:        uint32 vbr = mpu->GetVBR();
        !           190: 
        !           191:        // userdata が表示開始位置
        !           192:        int v = (int)screen.userdata;
        !           193:        int row = screen.GetRow();
        !           194:        int vend = v + row - 1;
        !           195: 
        !           196:        screen.Clear();
        !           197: 
        !           198:        // 最初の1行は常にヘッダ
        !           199:        screen.Print(0, 0, "No.       Offset Address   Name");
        !           200:        screen.Print(71, 0, "Count");
        !           201: 
        !           202:        for (int y = 1; v < vend; v++, y++) {
        !           203:                screen.Print(0, y, "$%03x(%3u) $%04x", v, v, v * 8);
        !           204: 
        !           205:                // m88100 は各ベクタが2ワード分あり、ここに命令を書く。
        !           206:                // ただし1ワード目は実質使えなかったので or r0,r0,r0 (NOP) を置く
        !           207:                // ことになっており、実質2ワード目の1命令だけでジャンプしないと
        !           208:                // いけない (アドレス全域にジャンプ出来るには最低2命令必要なので
        !           209:                // 2命令分のスペースを取ったのだろうけど…どうして…)。
        !           210:                // そこで、1ワード目が $f4005800 (NOP) で 2ワード目が何らかの分岐
        !           211:                // 命令であれば、その分岐先をこのベクタのアドレスとして表示する。
        !           212:                // 命令列が条件を満たさない時は仕方ないのでアドレスの前に @ をつけて
        !           213:                // 現在位置 (1ワード目が置かれているアドレス) を表示するか。
        !           214:                uint32 vecaddr = vbr + v * 8;
        !           215:                busaddr addr = VectorToAddr(vecaddr);
        !           216:                if (__predict_false(addr.IsBusErr())) {
        !           217:                        screen.Print(17, y, "BusErr");
        !           218:                } else if (__predict_false(addr.IsPhysical())) {
        !           219:                        // ジャンプ先が拾えなかったら Physical ビットを立てて返してくる。
        !           220:                        // 空いてるビットを使いまわしてるだけでそれ以上の意味はない。
        !           221:                        screen.Print(16, y, "@$%08x", vecaddr);
        !           222:                } else {
        !           223:                        screen.Print(17, y, "$%08x", addr.Addr());
        !           224:                }
        !           225:                screen.Print(27, y, "%-23s", nametable[v] ?: "");
        !           226:                screen.Print(50, y, "%26s",
        !           227:                        format_number(mpu->excep_counter[v]).c_str());
        !           228:        }
        !           229: }
        !           230: 
        !           231: // m88100 の2ワードのベクタからこのベクタの再分岐先を調べて返す。
        !           232: // このベクタのフェッチ自体がバスエラーなら BusErr を返す。
        !           233: // 分岐先を特定出来なければ、Physical ビットを立てて返す。
        !           234: busaddr
        !           235: VectorTable::VectorToAddr(uint32 vecaddr)
        !           236: {
        !           237:        busdata inst1 = mainbus->Peek4(vecaddr);
        !           238:        busdata inst2 = mainbus->Peek4(vecaddr + 4);
        !           239:        if (__predict_false(inst1.IsBusErr() || inst2.IsBusErr())) {
        !           240:                return BusAddr::BusErr;
        !           241:        }
        !           242: 
        !           243:        // 1命令目は or r0,r0,r0 の NOP 固定でお願いしたい…。
        !           244:        if (__predict_false(inst1.Data() != 0xf4005800)) {
        !           245:                return BusAddr::Physical;
        !           246:        }
        !           247: 
        !           248:        // 2命令目はさすがに br しか置く必要ないと思いたい…。
        !           249:        uint32 op = inst2.Data();
        !           250:        int32 offset = 0;
        !           251:        if (__predict_true((op & 0xfc00'0000) == 0xc000'0000)) {        // br
        !           252:                offset = ((int32)(op << 6) >> 4);
        !           253:        } else {
        !           254:                return BusAddr::Physical;
        !           255:        }
        !           256: 
        !           257:        return busaddr(vecaddr + 4 + offset);
        !           258: }
        !           259: 
1.1.1.6   root      260: // ベクタ名 (MC680x0)。
                    261: // とりあえず CPU の区別はないことにする。
                    262: /*static*/ std::array<const char * const, 64> VectorTable::name_m680x0 = {
1.1.1.7   root      263:        //           01234567890123456789012
1.1       root      264:        /*  0 */        "Reset (SP)",
                    265:        /*  1 */        "Reset (PC)",
                    266:        /*  2 */        "Bus Error",
                    267:        /*  3 */        "Address Error",
                    268:        /*  4 */        "Illegal Instruction",
                    269:        /*  5 */        "Zero Divide",
1.1.1.7   root      270:        /*  6 */        "CHK/CHK2 Instruction",
                    271:        /*  7 */        "TRAP* Instruction",
1.1.1.6   root      272:        /*  8 */        "Privilege Violation",
1.1       root      273:        /*  9 */        "Trace",
1.1.1.6   root      274:        /* 10 */        "Line A emulator",
                    275:        /* 11 */        "Line F emulator",
1.1       root      276:        /* 12 */        NULL,
1.1.1.7   root      277:        /* 13 */        "Copro Proto Violation",        // 68030 only
1.1       root      278:        /* 14 */        "Format Error",
1.1.1.7   root      279:        /* 15 */        "Uninitialized Interrupt",
1.1       root      280:        /* 16 */        NULL, NULL, NULL, NULL,
                    281:        /* 20 */        NULL, NULL, NULL, NULL,
                    282:        /* 24 */        "Spurious Interrupt",
                    283:        /* 25 */        "Level 1 Interrupt",
                    284:        /* 26 */        "Level 2 Interrupt",
                    285:        /* 27 */        "Level 3 Interrupt",
                    286:        /* 28 */        "Level 4 Interrupt",
                    287:        /* 29 */        "Level 5 Interrupt",
                    288:        /* 30 */        "Level 6 Interrupt",
                    289:        /* 31 */        "Level 7 Interrupt",
                    290:        /* 32 */        "Trap #0",
                    291:        /* 33 */        "Trap #1",
                    292:        /* 34 */        "Trap #2",
                    293:        /* 35 */        "Trap #3",
                    294:        /* 36 */        "Trap #4",
                    295:        /* 37 */        "Trap #5",
                    296:        /* 38 */        "Trap #6",
                    297:        /* 39 */        "Trap #7",
                    298:        /* 40 */        "Trap #8",
                    299:        /* 41 */        "Trap #9",
                    300:        /* 42 */        "Trap #10",
                    301:        /* 43 */        "Trap #11",
                    302:        /* 44 */        "Trap #12",
                    303:        /* 45 */        "Trap #13",
                    304:        /* 46 */        "Trap #14",
                    305:        /* 47 */        "Trap #15",
1.1.1.7   root      306:        //           01234567890123456789012
1.1       root      307:        /* 48 */        "FPCP Branch",
1.1.1.7   root      308:        /* 49 */        "FPCP Inexcact Result",
1.1       root      309:        /* 50 */        "FPCP Divide by Zero",
                    310:        /* 51 */        "FPCP UnderFlow",
                    311:        /* 52 */        "FPCP Operand Error",
                    312:        /* 53 */        "FPCP OverFlow",
                    313:        /* 54 */        "FPCP Signaling NAN",
1.1.1.7   root      314:        /* 55 */        "FPCP Unsupp Data Type",        // 68040 only
                    315:        /* 56 */        "MMU Configuration Error",      // 68030 only
1.1       root      316:        /* 57 */        NULL,
                    317:        /* 58 */        NULL,
                    318:        /* 59 */        NULL,
                    319:        /* 60 */        NULL,
                    320:        /* 61 */        NULL,
                    321:        /* 62 */        NULL,
                    322:        /* 63 */        NULL,
                    323: };
                    324: 
                    325: // ベクタ名 (X68030)
1.1.1.3   root      326: /*static*/ std::map<int, const char * const> VectorTable::name_x68030 = {
1.1.1.7   root      327:        //           01234567890123456789012
1.1.1.3   root      328:        { 0x40,         "MFP Alarm" },
                    329:        { 0x41,         "MFP EXPON" },
                    330:        { 0x42,         "MFP POWSW" },
                    331:        { 0x43,         "MFP FM IRQ" },
                    332:        { 0x44,         "MFP Timer-D" },
                    333:        { 0x45,         "MFP Timer-C" },
                    334:        { 0x46,         "MFP V-Disp" },
                    335:        { 0x47,         "MFP GPIP5" },
                    336:        { 0x48,         "MFP Timer-B" },
                    337:        { 0x49,         "MFP TX Error" },
                    338:        { 0x4a,         "MFP TX Empty" },
                    339:        { 0x4b,         "MFP RX Error" },
                    340:        { 0x4c,         "MFP RX Full" },
                    341:        { 0x4d,         "MFP Timer-A" },
                    342:        { 0x4e,         "MFP CRTC IRQ" },
                    343:        { 0x4f,         "MFP H-Sync" },
                    344: 
                    345:        { 0x50,         "SCC#B TX Empty" },
                    346:        { 0x52,         "SCC#B E/S" },
                    347:        { 0x54,         "SCC#B RX Intr" },
1.1.1.7   root      348:        { 0x56,         "SCC#B Special Condition" },
1.1.1.3   root      349:        { 0x58,         "SCC#A TX Empty" },
                    350:        { 0x5a,         "SCC#A E/S" },
                    351:        { 0x5c,         "SCC#A RX Intr" },
1.1.1.7   root      352:        { 0x5e,         "SCC#A Special Condition" },
1.1.1.3   root      353: 
1.1.1.7   root      354:        //           01234567890123456789012
                    355:        { 0x60,         "I/O FDC Interrupt" },
                    356:        { 0x61,         "I/O FDD Interrupt" },
                    357:        { 0x62,         "I/O HDC Interrupt" },
                    358:        { 0x63,         "I/O PRN Interrupt" },
1.1.1.3   root      359:        { 0x64,         "DMAC#0 Complete" },
                    360:        { 0x65,         "DMAC#0 Error" },
                    361:        { 0x66,         "DMAC#1 Complete" },
                    362:        { 0x67,         "DMAC#1 Error" },
                    363:        { 0x68,         "DMAC#2 Complete" },
                    364:        { 0x69,         "DMAC#2 Error" },
                    365:        { 0x6a,         "DMAC#3 Complete" },
                    366:        { 0x6b,         "DMAC#3 Error" },
                    367:        { 0x6c,         "SPC Interrupt" },
                    368: 
1.1.1.7   root      369:        //           01234567890123456789012
1.1.1.3   root      370:        { 0xf0,         "PSX16x50 Interrupt" },
                    371:        { 0xf6,         "ExSPC Interrupt" },
                    372:        //0xf7,         TS-6BSI
                    373:        { 0xf8,         "Nereid#1 Interrupt" },
                    374:        { 0xf9,         "Neptune-X Interrupt" },
                    375:        { 0xfa,         "Nereid#1 USB" },
                    376:        { 0xfb,         "Nereid#0 USB" },
                    377: };
1.1       root      378: 
1.1.1.3   root      379: // LUNA-I
                    380: /*static*/ std::map<int, const char * const> VectorTable::name_luna1 = {
1.1.1.7   root      381:        //           01234567890123456789012
1.1.1.3   root      382:        { 0x19,         "Lv1 Intr (XP Low)" },
                    383:        { 0x1a,         "Lv2 Intr (SPC)" },
                    384:        { 0x1b,         "Lv3 Intr (Lance)" },
                    385:        { 0x1c,         "Lv4 Intr (XP High)" },
1.1.1.7   root      386:        { 0x1d,         "Lv5 Intr (System Clock)" },
1.1.1.3   root      387:        { 0x1e,         "Lv6 Intr (SIO)" },
                    388:        { 0x1f,         "Lv7 Intr (NMI)" },
1.1       root      389: };
                    390: 
1.1.1.3   root      391: // NEWS はレベル割り込みと、一部が vectored */
                    392: /*static*/ std::map<int, const char * const> VectorTable::name_news = {
1.1.1.7   root      393:        //           01234567890123456789012
1.1.1.3   root      394:        { 0x19,         "Lv1 Intr (AST)" },
                    395:        { 0x1a,         "Lv2 Intr" },
                    396:        { 0x1b,         "Lv3 Intr" },
                    397:        { 0x1c,         "Lv4 Intr (SIC/LAN)" },
                    398:        { 0x1d,         "Lv5 Intr (SCC)" },
1.1.1.7   root      399:        { 0x1e,         "Lv6 Intr (System Timer)" },
1.1.1.3   root      400:        { 0x1f,         "Lv7 Intr" },
                    401: 
                    402:        { 0x40,         "SCC" },
1.1       root      403: };
                    404: 
1.1.1.6   root      405: // virt-m68k
                    406: /*static*/ std::map<int, const char * const> VectorTable::name_virt68k = {
1.1.1.7   root      407:        //           01234567890123456789012
1.1.1.6   root      408:        { 0x19,         "Lv1 Intr (GFPIC1)" },
                    409:        { 0x1a,         "Lv2 Intr (GFPIC2)" },
                    410:        { 0x1b,         "Lv3 Intr (GFPIC3)" },
                    411:        { 0x1c,         "Lv4 Intr (GFPIC4)" },
                    412:        { 0x1d,         "Lv5 Intr (GFPIC5)" },
                    413:        { 0x1e,         "Lv6 Intr (GFPIC6)" },
                    414:        { 0x1f,         "Lv7 Intr" },
                    415: };
                    416: 
1.1.1.8 ! root      417: // LUNA-88K
        !           418: /*static*/ std::map<int, const char * const> VectorTable::name_luna88k = {
1.1.1.3   root      419:        //           01234567890123456789012 <- 例外履歴欄の横幅
1.1.1.8 ! root      420:        { 0x00,         "Reset Exception" },
        !           421:        { 0x01,         "Interrupt Exception" },
        !           422:        { 0x02,         "Inst Access Exception" },
        !           423:        { 0x03,         "Data Access Exception" },
        !           424:        { 0x04,         "Misaligned Access Excep" },
        !           425:        { 0x05,         "Unimplemented Opcode" },
        !           426:        { 0x06,         "Priv. Violation Excep." },
        !           427:        { 0x07,         "Bounds Check Violation" },
        !           428:        { 0x08,         "Illegal Integer Divide" },
        !           429:        { 0x09,         "Int Overflow Exception" },
        !           430:        { 0x0a,         "Error Exception" },
        !           431:        // SFU1 (SFU2〜7 はなくていいか…)
        !           432:        { 0x72,         "SFU1 Precise Exception" },
        !           433:        { 0x73,         "SFU1 ImpreciseException" },
        !           434: 
        !           435:        // 0x80 は OpenBSD では sigsys、NetBSD/luna88k (非公式)ではシステムコール。
        !           436:        { 0x80,         "NetBSD System Call" },
        !           437:        // XXX 本来は OpenBSD 稼働時に限定すべきだろうけど、そうする意味もない
        !           438:        { 0x81,         "OpenBSD sigsys" },
        !           439:        { 0x82,         "OpenBSD break" },
        !           440:        { 0x83,         "OpenBSD trace" },
        !           441:        { 0x84,         "OpenBSD entry" },
        !           442:        { 450,          "OpenBSD System Call" },
        !           443:        { 451,          "OpenBSD Cache Flush" },
        !           444:        { 503,          "Division by Zero(GCC)" },
        !           445:        { 504,          "OpenBSD stepbpt" },
        !           446:        { 511,          "OpenBSD userbpt" },
1.1       root      447: };

unix.superglobalmegacorp.com

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