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

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.9 ! root       34:                monitor->SetCallback(&VectorTable::MonitorScreenM680x0);
1.1       root       35:                break;
1.1.1.2   root       36:         case VMType::LUNA88K:
1.1       root       37:                InitTableLuna88k();
1.1.1.9 ! root       38:                monitor->SetCallback(&VectorTable::MonitorScreenM88xx0);
1.1.1.8   root       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.9 ! root      146: VectorTable::MonitorScreenM680x0(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
1.1.1.9 ! root      182: VectorTable::MonitorScreenM88xx0(Monitor *, TextScreen& screen)
1.1.1.8   root      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.