--- nono/debugger/vectortable.cpp 2026/04/29 17:05:24 1.1.1.4 +++ nono/debugger/vectortable.cpp 2026/04/29 17:05:49 1.1.1.8 @@ -11,6 +11,7 @@ #include "vectortable.h" #include "mainapp.h" #include "mainbus.h" +#include "monitor.h" #include "mpu.h" // コンストラクタ @@ -20,54 +21,71 @@ VectorTable::VectorTable(VMType vmtype) // ログは不要 ClearAlias(); + monitor = gMonitorManager->Regist(ID_SUBWIN_VECTOR, this); + // 表示名を作成。それぞれ微妙に処理が違う… + int w = 75; switch (vmtype) { case VMType::X68030: case VMType::LUNA1: case VMType::NEWS: case VMType::VIRT68K: - InitTableM68030(vmtype); + InitTableM680x0(vmtype); + monitor->func = ToMonitorCallback(&VectorTable::MonitorUpdateM680x0); break; case VMType::LUNA88K: InitTableLuna88k(); + monitor->func = ToMonitorCallback(&VectorTable::MonitorUpdateM88xx0); + // ベクタが(16進数で)3桁必要。 + w++; break; default: PANIC("invalid vmtype %d", (int)vmtype); } - monitor.func = ToMonitorCallback(&VectorTable::MonitorUpdate); - monitor.SetSize(49, 1 + 32); // ヘッダの1行と全エントリ数 - monitor.SetMaxHeight(1 + Size()); - monitor.Regist(ID_SUBWIN_VECTOR); + monitor->SetSize(w, 1 + 32); // ヘッダの1行と全エントリ数 + monitor->SetMaxHeight(1 + Size()); } -// X68030、LUNA-I の表示名テーブル初期化。コンストラクタの一部。 +// m68k 機種の表示名テーブル初期化。コンストラクタの一部。 void -VectorTable::InitTableM68030(VMType vmtype) +VectorTable::InitTableM680x0(VMType vmtype) { nametable.clear(); nametable.resize(256); - // まず m68k 標準の名称で埋める + // まず m680x0 標準の名称で埋める for (int v = 0; v < 64; v++) { - if (name_m68030[v]) { - nametable[v] = name_m68030[v]; + if (name_m680x0[v]) { + nametable[v] = name_m680x0[v]; } } // 機種ごとに必要なところだけ上書き const std::map *names; - if (vmtype == VMType::X68030) { + switch (vmtype) { + case VMType::X68030: names = &name_x68030; - } else if (vmtype == VMType::LUNA1) { + break; + case VMType::LUNA1: names = &name_luna1; - } else { + break; + case VMType::NEWS: names = &name_news; + break; + case VMType::VIRT68K: + names = &name_virt68k; + break; + default: + names = NULL; + break; } - for (const auto& p : *names) { - int v = p.first; - const char *name = p.second; - nametable[v] = name; + if (names) { + for (const auto& p : *names) { + int v = p.first; + const char *name = p.second; + nametable[v] = name; + } } } @@ -78,30 +96,11 @@ VectorTable::InitTableLuna88k() nametable.clear(); nametable.resize(512); - // 先頭から10個くらいだけ連続しているのでテーブルからコピー - for (int i = 0; i < countof(name_luna88k); i++) { - nametable[i] = name_luna88k[i]; + for (const auto& p : name_luna88k) { + int v = p.first; + const char *name = p.second; + nametable[v] = name; } - - // 以降は不連続で、間が空きすぎているので、ここで代入 - - // SFU - // (SFU2〜7 はいいか…) - // 01234567890123456789012 <- 例外履歴欄の横幅 - nametable[114] = "SFU1 Precise Exception"; - nametable[115] = "SFU1 ImpreciseException"; - - // NetBSD/luna88k - nametable[128] = "NetBSD System Call"; - - // OpenBSD - // XXX 本来は OpenBSD 稼働時に限定すべきだろうけど、そうする意味もない - // 01234567890123456789012 - nametable[450] = "OpenBSD System Call"; - nametable[451] = "OpenBSD Cache Flush"; - nametable[503] = "Division by Zero(GCC)"; - nametable[504] = "OpenBSD stepbpt"; - nametable[511] = "OpenBSD userbpt"; } // デストラクタ @@ -113,26 +112,12 @@ VectorTable::~VectorTable() bool VectorTable::Init() { - if (inherited::Init() == false) { - return false; - } - mainbus = GetMainbusDevice(); mpu = GetMPUDevice(); return true; } -// 例外名を返す (ベクタテーブル用)。 -// 名前がなければ "" を返す。 -const char * -VectorTable::GetTableName(int vector) const -{ - assertmsg(0 <= vector && vector < nametable.size(), "vector=%d", vector); - - return nametable[vector] ?: ""; -} - // 例外名を返す (例外履歴用)。 // 名前がなければ NULL を返す。 const char * @@ -153,21 +138,17 @@ VectorTable::GetExceptionName(int vector } } - if (__predict_true(nametable[vector] != NULL)) { - return nametable[vector]; - } else { - return NULL; - } + return nametable[vector]; } -// モニタ更新 +// モニタ更新 (M680x0) void -VectorTable::MonitorUpdate(Monitor *, TextScreen& screen) +VectorTable::MonitorUpdateM680x0(Monitor *, TextScreen& screen) { - // 0 1 2 3 4 5 6 - // 0123456789012345678901234567890123456789012345678901234567890123456789 - // No. Offset Address Name Count - // $02( 2) $0008 $12345678 01234567890123456789012 0123456789 +// 0 1 2 3 4 5 6 7 +// 012345678901234567890123456789012345678901234567890123456789012345678901234 +// No. Offset Address Name >< Count +// $02( 2) $0008 $12345678 0123456789012345678901201234567890123456789012345 uint32 vbr = mpu->GetVBR(); @@ -180,39 +161,122 @@ VectorTable::MonitorUpdate(Monitor *, Te // 最初の1行は常にヘッダ screen.Print(0, 0, "No. Offset Address Name"); - //screen.Print(57, 0, "Count"); + screen.Print(70, 0, "Count"); for (int y = 1; v < vend; v++, y++) { - screen.Print(0, y, "$%02x(%3d) $%04x", v, v, v * 4); - busdata addr = mainbus->Peek32(vbr + v * 4); + screen.Print(0, y, "$%02x(%3u) $%04x", v, v, v * 4); + busdata addr = mainbus->Peek4(vbr + v * 4); if (__predict_false(addr.IsBusErr())) { screen.Print(16, y, "BusErr"); } else { screen.Print(16, y, "$%08x", addr.Data()); } - screen.Print(26, y, "%-23s", GetTableName(v)); + screen.Print(26, y, "%-23s", nametable[v] ?: ""); + screen.Print(49, y, "%26s", + format_number(mpu->excep_counter[v]).c_str()); } } -// ベクタ名 (MC68030 共通) -/*static*/ std::array VectorTable::name_m68030 = { - // 0123456789012345678 <- 例外履歴欄の横幅 +// モニタ更新 (M88xx0) +void +VectorTable::MonitorUpdateM88xx0(Monitor *, TextScreen& screen) +{ +// 0 1 2 3 4 5 6 7 +// 0123456789012345678901234567890123456789012345678901234567890123456789012346 +// No. Offset Address Name >< Count +// $002( 2) $0010 @$12345678 0123456789012345678901201234567890123456789012345 + + uint32 vbr = mpu->GetVBR(); + + // userdata が表示開始位置 + int v = (int)screen.userdata; + int row = screen.GetRow(); + int vend = v + row - 1; + + screen.Clear(); + + // 最初の1行は常にヘッダ + screen.Print(0, 0, "No. Offset Address Name"); + screen.Print(71, 0, "Count"); + + for (int y = 1; v < vend; v++, y++) { + screen.Print(0, y, "$%03x(%3u) $%04x", v, v, v * 8); + + // m88100 は各ベクタが2ワード分あり、ここに命令を書く。 + // ただし1ワード目は実質使えなかったので or r0,r0,r0 (NOP) を置く + // ことになっており、実質2ワード目の1命令だけでジャンプしないと + // いけない (アドレス全域にジャンプ出来るには最低2命令必要なので + // 2命令分のスペースを取ったのだろうけど…どうして…)。 + // そこで、1ワード目が $f4005800 (NOP) で 2ワード目が何らかの分岐 + // 命令であれば、その分岐先をこのベクタのアドレスとして表示する。 + // 命令列が条件を満たさない時は仕方ないのでアドレスの前に @ をつけて + // 現在位置 (1ワード目が置かれているアドレス) を表示するか。 + uint32 vecaddr = vbr + v * 8; + busaddr addr = VectorToAddr(vecaddr); + if (__predict_false(addr.IsBusErr())) { + screen.Print(17, y, "BusErr"); + } else if (__predict_false(addr.IsPhysical())) { + // ジャンプ先が拾えなかったら Physical ビットを立てて返してくる。 + // 空いてるビットを使いまわしてるだけでそれ以上の意味はない。 + screen.Print(16, y, "@$%08x", vecaddr); + } else { + screen.Print(17, y, "$%08x", addr.Addr()); + } + screen.Print(27, y, "%-23s", nametable[v] ?: ""); + screen.Print(50, y, "%26s", + format_number(mpu->excep_counter[v]).c_str()); + } +} + +// m88100 の2ワードのベクタからこのベクタの再分岐先を調べて返す。 +// このベクタのフェッチ自体がバスエラーなら BusErr を返す。 +// 分岐先を特定出来なければ、Physical ビットを立てて返す。 +busaddr +VectorTable::VectorToAddr(uint32 vecaddr) +{ + busdata inst1 = mainbus->Peek4(vecaddr); + busdata inst2 = mainbus->Peek4(vecaddr + 4); + if (__predict_false(inst1.IsBusErr() || inst2.IsBusErr())) { + return BusAddr::BusErr; + } + + // 1命令目は or r0,r0,r0 の NOP 固定でお願いしたい…。 + if (__predict_false(inst1.Data() != 0xf4005800)) { + return BusAddr::Physical; + } + + // 2命令目はさすがに br しか置く必要ないと思いたい…。 + uint32 op = inst2.Data(); + int32 offset = 0; + if (__predict_true((op & 0xfc00'0000) == 0xc000'0000)) { // br + offset = ((int32)(op << 6) >> 4); + } else { + return BusAddr::Physical; + } + + return busaddr(vecaddr + 4 + offset); +} + +// ベクタ名 (MC680x0)。 +// とりあえず CPU の区別はないことにする。 +/*static*/ std::array VectorTable::name_m680x0 = { + // 01234567890123456789012 /* 0 */ "Reset (SP)", /* 1 */ "Reset (PC)", /* 2 */ "Bus Error", /* 3 */ "Address Error", /* 4 */ "Illegal Instruction", /* 5 */ "Zero Divide", - /* 6 */ "CHK/CHK2 Insn", - /* 7 */ "TRAPV, *TRAPcc Insn", - /* 8 */ "PriviledgeViolation", + /* 6 */ "CHK/CHK2 Instruction", + /* 7 */ "TRAP* Instruction", + /* 8 */ "Privilege Violation", /* 9 */ "Trace", - /* 10 */ "Line 1010 emulator", - /* 11 */ "Line 1111 emulator", + /* 10 */ "Line A emulator", + /* 11 */ "Line F emulator", /* 12 */ NULL, - /* 13 */ "CoproProtoViolation", + /* 13 */ "Copro Proto Violation", // 68030 only /* 14 */ "Format Error", - /* 15 */ "Uninitialized Intr", + /* 15 */ "Uninitialized Interrupt", /* 16 */ NULL, NULL, NULL, NULL, /* 20 */ NULL, NULL, NULL, NULL, /* 24 */ "Spurious Interrupt", @@ -239,16 +303,16 @@ VectorTable::MonitorUpdate(Monitor *, Te /* 45 */ "Trap #13", /* 46 */ "Trap #14", /* 47 */ "Trap #15", - // 0123456789012345678 + // 01234567890123456789012 /* 48 */ "FPCP Branch", - /* 49 */ "FPCP InexcactResult", + /* 49 */ "FPCP Inexcact Result", /* 50 */ "FPCP Divide by Zero", /* 51 */ "FPCP UnderFlow", /* 52 */ "FPCP Operand Error", /* 53 */ "FPCP OverFlow", /* 54 */ "FPCP Signaling NAN", - /* 55 */ NULL, - /* 56 */ "MMU Config Error", + /* 55 */ "FPCP Unsupp Data Type", // 68040 only + /* 56 */ "MMU Configuration Error", // 68030 only /* 57 */ NULL, /* 58 */ NULL, /* 59 */ NULL, @@ -260,7 +324,7 @@ VectorTable::MonitorUpdate(Monitor *, Te // ベクタ名 (X68030) /*static*/ std::map VectorTable::name_x68030 = { - // 0123456789012345678 + // 01234567890123456789012 { 0x40, "MFP Alarm" }, { 0x41, "MFP EXPON" }, { 0x42, "MFP POWSW" }, @@ -281,17 +345,17 @@ VectorTable::MonitorUpdate(Monitor *, Te { 0x50, "SCC#B TX Empty" }, { 0x52, "SCC#B E/S" }, { 0x54, "SCC#B RX Intr" }, - { 0x56, "SCC#B SpCond" }, + { 0x56, "SCC#B Special Condition" }, { 0x58, "SCC#A TX Empty" }, { 0x5a, "SCC#A E/S" }, { 0x5c, "SCC#A RX Intr" }, - { 0x5e, "SCC#A SpCond" }, + { 0x5e, "SCC#A Special Condition" }, - // 0123456789012345678 - { 0x60, "I/O FDC Intr" }, - { 0x61, "I/O FDD Intr" }, - { 0x62, "I/O HDC Intr" }, - { 0x63, "I/O PRN Intr" }, + // 01234567890123456789012 + { 0x60, "I/O FDC Interrupt" }, + { 0x61, "I/O FDD Interrupt" }, + { 0x62, "I/O HDC Interrupt" }, + { 0x63, "I/O PRN Interrupt" }, { 0x64, "DMAC#0 Complete" }, { 0x65, "DMAC#0 Error" }, { 0x66, "DMAC#1 Complete" }, @@ -302,7 +366,7 @@ VectorTable::MonitorUpdate(Monitor *, Te { 0x6b, "DMAC#3 Error" }, { 0x6c, "SPC Interrupt" }, - // 0123456789012345678 + // 01234567890123456789012 { 0xf0, "PSX16x50 Interrupt" }, { 0xf6, "ExSPC Interrupt" }, //0xf7, TS-6BSI @@ -314,43 +378,70 @@ VectorTable::MonitorUpdate(Monitor *, Te // LUNA-I /*static*/ std::map VectorTable::name_luna1 = { - // 0123456789012345678 <- 例外履歴欄の横幅 + // 01234567890123456789012 { 0x19, "Lv1 Intr (XP Low)" }, { 0x1a, "Lv2 Intr (SPC)" }, { 0x1b, "Lv3 Intr (Lance)" }, { 0x1c, "Lv4 Intr (XP High)" }, - { 0x1d, "Lv5 Intr (SysClk)" }, + { 0x1d, "Lv5 Intr (System Clock)" }, { 0x1e, "Lv6 Intr (SIO)" }, { 0x1f, "Lv7 Intr (NMI)" }, }; // NEWS はレベル割り込みと、一部が vectored */ /*static*/ std::map VectorTable::name_news = { - // 0123456789012345678 <- 例外履歴欄の横幅 + // 01234567890123456789012 { 0x19, "Lv1 Intr (AST)" }, { 0x1a, "Lv2 Intr" }, { 0x1b, "Lv3 Intr" }, { 0x1c, "Lv4 Intr (SIC/LAN)" }, { 0x1d, "Lv5 Intr (SCC)" }, - { 0x1e, "Lv6 Intr (SysTimer)" }, + { 0x1e, "Lv6 Intr (System Timer)" }, { 0x1f, "Lv7 Intr" }, { 0x40, "SCC" }, }; -// LUNA-88K は先頭11個のみ (残りはコードで処理) -/*static*/ std::array VectorTable::name_luna88k = { - // 01234567890123456789012 <- 例外履歴欄の横幅 - /* 0 */ "Reset Exception", - /* 1 */ "Interrupt Exception", - /* 2 */ "Inst Access Exception", - /* 3 */ "Data Access Exception", - /* 4 */ "Misaligned Access Excep", - /* 5 */ "Unimplemented Opcode", - /* 6 */ "Priv. Violation Excep.", - /* 7 */ "Bounds Check Violation", - /* 8 */ "Illegal Integer Divide", - /* 9 */ "Int Overflow Exception", - /* 10 */ "Error Exception", +// virt-m68k +/*static*/ std::map VectorTable::name_virt68k = { // 01234567890123456789012 + { 0x19, "Lv1 Intr (GFPIC1)" }, + { 0x1a, "Lv2 Intr (GFPIC2)" }, + { 0x1b, "Lv3 Intr (GFPIC3)" }, + { 0x1c, "Lv4 Intr (GFPIC4)" }, + { 0x1d, "Lv5 Intr (GFPIC5)" }, + { 0x1e, "Lv6 Intr (GFPIC6)" }, + { 0x1f, "Lv7 Intr" }, +}; + +// LUNA-88K +/*static*/ std::map VectorTable::name_luna88k = { + // 01234567890123456789012 <- 例外履歴欄の横幅 + { 0x00, "Reset Exception" }, + { 0x01, "Interrupt Exception" }, + { 0x02, "Inst Access Exception" }, + { 0x03, "Data Access Exception" }, + { 0x04, "Misaligned Access Excep" }, + { 0x05, "Unimplemented Opcode" }, + { 0x06, "Priv. Violation Excep." }, + { 0x07, "Bounds Check Violation" }, + { 0x08, "Illegal Integer Divide" }, + { 0x09, "Int Overflow Exception" }, + { 0x0a, "Error Exception" }, + // SFU1 (SFU2〜7 はなくていいか…) + { 0x72, "SFU1 Precise Exception" }, + { 0x73, "SFU1 ImpreciseException" }, + + // 0x80 は OpenBSD では sigsys、NetBSD/luna88k (非公式)ではシステムコール。 + { 0x80, "NetBSD System Call" }, + // XXX 本来は OpenBSD 稼働時に限定すべきだろうけど、そうする意味もない + { 0x81, "OpenBSD sigsys" }, + { 0x82, "OpenBSD break" }, + { 0x83, "OpenBSD trace" }, + { 0x84, "OpenBSD entry" }, + { 450, "OpenBSD System Call" }, + { 451, "OpenBSD Cache Flush" }, + { 503, "Division by Zero(GCC)" }, + { 504, "OpenBSD stepbpt" }, + { 511, "OpenBSD userbpt" }, };