--- nono/debugger/debugger.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/debugger/debugger.cpp 2026/04/29 17:04:30 1.1.1.2 @@ -3,137 +3,18 @@ // Copyright (C) 2019 isaki@NetBSD.org // -#include "header.h" -#include "bus.h" -#include "consio.h" -#include "cvprompt.h" -#include "disasm.h" -#include "m68030core.h" -#include "memdump.h" +#include "console.h" +#include "debugger_private.h" +#include "debugger_m680x0.h" +#include "debugger_m88xx0.h" +#include "mainapp.h" #include "mpu.h" #include "mystring.h" #include -class Debugger -{ - private: - // 型 - typedef void (Debugger::*cmdfunc_t)(); - typedef struct { - const char *name; - cmdfunc_t func; - } cmddef_t; - - // ブレークポイント - typedef struct { - bool enable; - bool ismemory; - uint32 addr; - uint32 count; - } breakpoint_t; - static const int MAX_BREAKPOINTS = 8; - - public: - Debugger(); - virtual ~Debugger() { } - - void Init(); - void ThreadRun(); - bool Check(); - - private: - bool MainLoop(); - cmddef_t *ParseCmd(); - // コマンド名は大文字小文字を区別する関係でスネークスタイル。 - void cmd_b(); - void cmd_b_list(); - void cmd_brhist(); - void cmd_bx(); - void cmd_c(); - void cmd_d(); - void cmd_dt(); - void cmd_D(); - void cmd_h(); - void cmd_L(); - void cmd_m(); - void cmd_mt(); - void cmd_M(); - void cmd_minus(); - void cmd_n(); - void cmd_q(); - void cmd_r(); - void cmd_ra(); - void cmd_rf(); - void cmd_rm(); - void cmd_ro(); - void cmd_s(); - void cmd_so(); - void cmd_show(); - void cmd_t(); - void cmd_unknown(); - - int AddBreakpoint(uint32 addr, bool ismemory); - void Continue(); - bool GetAddr(uint32& addr, uint32& lastaddr); - void cmd_d_common(MemdumpMode mode); - void cmd_m_common(MemdumpMode mode); - bool ParseAddr(const char *arg, uint32_t *addrp); - const char *OPccCondStr(uint32); - bool IsOPcc(uint16); - bool IsDBcc(uint16); - bool IsCond(uint16); - bool SetNBreakpoint(); - - void HelpMain(); - - void ShowRegMain(); - void ShowRegFPU(); - void ShowRegMMU(); - void ShowRegOther(); - void ShowMonitor(TextScreen& monitor); - - m68kcpu *cpu = NULL; // CPU コア - m68kreg prev {}; // 前回のレジスタセットのコピー - - Consio *cons = NULL; // 入出力 - char cmdbuf[256] {}; // 現在のコマンドライン - char last_cmdbuf[256] {}; // 直前のコマンドライン - int ac = 0; - char *av[10] {}; - - uint32 pc = 0; - uint32 nextpc = 0; - breakpoint_t bpoint[MAX_BREAKPOINTS] {}; - bool bc_enable = false; - uint32 bc_addr = 0; - uint32 d_last_addr = 0; - uint32 m_last_addr = 0; - bool n_enable = false; - bool n_breakenable = false; - uint32 n_breakaddr = 0; - uint32 n_count = 0; - bool s_enable = false; - uint32 s_count = 0; - bool so_enable = false; - uint32 so_a7 = 0; - uint16 so_sr = 0; - bool t_enable = false; - uint32 t_count = 0; - - // 一度VMを実行して再びプロンプトに来たら true - bool is_continued = false; - - static cmddef_t cmdtable[]; - static cmddef_t cmdtable_unknown; -}; - Debugger *gDebugger; CVPrompt *gCVPrompt; -// コマンドラインオプション -bool debug_on_start; -uint32 debug_breakaddr; - static void *debugger_run(void *); // 初期化。 @@ -165,7 +46,13 @@ debugger_run(void *dummy) // コンストラクタ Debugger::Debugger() { - cpu = gMPU->GetCPU(); + if (gMPU680x0) { + md = new DebuggerMD_m680x0(this, gMPU680x0->GetCPU()); + } else if (gMPU88xx0) { + md = new DebuggerMD_m88xx0(this, gMPU88xx0->GetCPU()); + } else { + throw "unknown mpu"; + } } // コマンドライン引数によって動作を決めるところ。 @@ -174,14 +61,14 @@ void Debugger::Init() { // -d なら CPU 起動時点で停止してプロンプトを待つ - if (debug_on_start) { - cpu->atomic_reqflag |= CPU_REQ_PROMPT; + if (gMainApp.debug_on_start) { + md->ReqSet(CPU_REQ_PROMPT); } // -b ならブレークポイント設定 - if (debug_breakaddr != 0xffffffff) { - cpu->atomic_reqflag |= CPU_REQ_TRACE; - AddBreakpoint(debug_breakaddr, false); + if (gMainApp.debug_breakaddr != 0xffffffff) { + md->ReqSet(CPU_REQ_TRACE); + AddBreakpoint(gMainApp.debug_breakaddr, false); } // どこでやるべか @@ -193,13 +80,18 @@ void Debugger::ThreadRun() { // XXX どこかでコンソールの選択とパラメータの取得 - cons = new ConsioTCP(); + if (gMainApp.debug_on_console) { + cons = new ConsoleStdio(); + } else { + cons = new ConsoleTCP(); + } if (cons->Init() == false) { return; } for (;;) { cons->Open(); + cons->InitEditLine("> "); cons->Print("This is debugger console\n"); // 接続ごとに初期化する値 @@ -213,11 +105,11 @@ Debugger::ThreadRun() // コンソールが繋がっている間がトレースオン // コンソールが繋がるとプロンプトになる - cpu->atomic_reqflag |= CPU_REQ_TRACE | CPU_REQ_PROMPT; + md->ReqSet(CPU_REQ_TRACE | CPU_REQ_PROMPT); while (MainLoop() == true) ; // コンソールを抜ける時はCPUの停止を解除。 - cpu->atomic_reqflag &= ~CPU_REQ_TRACE; + md->ReqClr(CPU_REQ_TRACE); gCVPrompt->NotifyRelease(); cons->Close(); @@ -232,55 +124,62 @@ bool Debugger::MainLoop() { // プロンプトが取れるのを待つ - gCVPrompt->WaitAcquire(cons); + for (;;) { + bool is_prompt = gCVPrompt->WaitAcquire(200); + if (is_prompt) break; + + // コンソールを定期観測して、入力があればブレーク要求 + if (cons->Poll()) { + // この入力は drop してみる + if (cons->Gets(cmdbuf) == false) { + // EOF or Error + cmd_q(); + return false; + } + md->ReqSet(CPU_REQ_PROMPT); + } + } // VM 実行からプロンプトに来たとき if (is_continued) { is_continued = false; - pc = RegPC; + pc = md->GetPC(); d_last_addr = pc; // プロンプトに来た時に表示するいつものやつ cmd_minus(); } - cons->Print("> "); - cons->Flush(); - if (cons->Gets(cmdbuf, sizeof(cmdbuf)) < 1) { + cons->Prompt(); + if (cons->Gets(cmdbuf) == false) { + // EOF or Error + cmd_q(); return false; } - // chomp - for (int i = 0; cmdbuf[i] != '\0'; i++) { - if (cmdbuf[i] == '\r' || cmdbuf[i] == '\n') { - cmdbuf[i] = '\0'; - break; - } - } + string_rtrim(cmdbuf); - if (cmdbuf[0] != '\0') { + if (!cmdbuf.empty()) { // コマンドが入力されれば次回のために保存 - strcpy(last_cmdbuf, cmdbuf); + last_cmdbuf = cmdbuf; } else { // 空行が入力されれば直前のコマンドをもう一度 // 前行がなければ何もせずもう一度プロンプトを表示するかね - if (last_cmdbuf[0] == '\0') + if (last_cmdbuf.empty()) return true; - strcpy(cmdbuf, last_cmdbuf); + cmdbuf = last_cmdbuf; } // 行を cmd, ac, av に分解 cmddef_t *cmd = ParseCmd(); - if (cmd == NULL) { - // NULL は知らないコマンドではなく終了コマンド - return false; - } // 前回の値が有効なのはコマンドが連続した時だけ // コマンド実行 (this->*(cmd->func))(); - return true; + + // 終了コマンドによる終了処理 + return (cmd->func != &Debugger::cmd_q); } // ブレークポイントとかを調べる。 @@ -313,7 +212,7 @@ Debugger::Check() } // n による1命令実行のブレークポイントか - if (n_enable && n_breakenable && n_breakaddr == RegPC) { + if (n_enable && n_breakenable && n_breakaddr == md->GetPC()) { n_breakenable = false; return true; } @@ -322,16 +221,23 @@ Debugger::Check() for (int i = 0; i < countof(bpoint); i++) { breakpoint_t *bp = &bpoint[i]; if (bp->enable) { - if (bp->addr == RegPC) { - bp->count++; - return true; + if (bp->ismemory) { + if (md->CheckLEA(bp->addr)) { + bp->count++; + return true; + } + } else { + if (bp->addr == md->GetPC()) { + bp->count++; + return true; + } } } } // ステップアウト if (so_enable) { - if (RegA(7) > so_a7 || (RegSR & 0x3000) != so_sr) { + if (md->IsStepOut()) { so_enable = false; return true; } @@ -339,7 +245,7 @@ Debugger::Check() // アドレス指定付き continue if (bc_enable) { - if (bc_addr == RegPC) { + if (bc_addr == md->GetPC()) { bc_enable = false; return true; } @@ -349,7 +255,7 @@ Debugger::Check() } // コマンド一覧。 -// quit コマンドは ParseCmd() 側で処理してある。 +// quit コマンドによるメインループ終了は MainLoop() 側で処理してある。 Debugger::cmddef_t Debugger::cmdtable[] = { { "bx", &Debugger::cmd_bx, }, { "b", &Debugger::cmd_b, }, @@ -364,8 +270,11 @@ Debugger::cmddef_t Debugger::cmdtable[] { "mt", &Debugger::cmd_mt, }, { "M", &Debugger::cmd_M, }, { "n", &Debugger::cmd_n, }, + { "q", &Debugger::cmd_q, }, + { "quit", &Debugger::cmd_q, }, { "r", &Debugger::cmd_r, }, { "ra", &Debugger::cmd_ra, }, + { "rc", &Debugger::cmd_rc, }, { "rf", &Debugger::cmd_rf, }, { "rm", &Debugger::cmd_rm, }, { "ro", &Debugger::cmd_ro, }, @@ -415,7 +324,12 @@ Debugger::HelpMain() cons->Print(" M [ [] メモリダンプ(物理)\n"); cons->Print(" n ステップ実行 (サブルーチンを飛ばす)\n"); cons->Print(" q quit\n"); - cons->Print(" r [a|f|m|o] レジスタ表示\n"); + cons->Print(" r 通常レジスタを表示\n"); + cons->Print(" ra ATC を表示\n"); + cons->Print(" rc 制御レジスタを表示 (m88xx0)\n"); + cons->Print(" rf FPU レジスタを表示\n"); + cons->Print(" rm MMU レジスタを表示\n"); + cons->Print(" ro その他のレジスタを表示\n"); cons->Print(" so ステップアウト\n"); cons->Print(" show モニター表示\n"); cons->Print(" t トレース実行\n"); @@ -429,16 +343,17 @@ Debugger::cmd_unknown() } // cmdbuf を cmd, ac, av に分解する。 -// cmdbuf は破壊されるので以後は cmd, ac, av で参照のこと。 // コマンド(の1ワード目)が一致しなければ cmd_unknown を返し、 // 終了コマンドと一致したら NULL を返す。 Debugger::cmddef_t * Debugger::ParseCmd() { + char buf[cmdbuf.length() + 1]; char *p; cmddef_t *cmd; - p = cmdbuf; + strcpy(buf, cmdbuf.c_str()); + p = buf; ac = 0; memset(&av, 0, sizeof(av)); @@ -459,15 +374,23 @@ Debugger::ParseCmd() if (*p != '\0') *p++ = '\0'; } + // buf はスコープを抜けると無効なので、 + // コピーを取って挿げ替え + for (int i = 0; i < ac; i++) { + strav[i] = av[i]; + av[i] = strav[i].c_str(); + } + // デバッグ表示 + if (0) { + for (int i = 0; i < ac; i++) { + printf("av[%d]=|%s|\n", i, av[i]); + } + } // コマンドを探す for (int i = 0; i < countof(cmdtable); i++) { cmd = &cmdtable[i]; - // デバッガから抜ける(終了する)コマンドだけここで処理 - if (strcmp(av[0], "q") == 0 || strcmp(av[0], "quit") == 0) - return NULL; - if (strcmp(av[0], cmd->name) == 0) return cmd; } @@ -626,7 +549,7 @@ Debugger::Continue() is_continued = true; // 今のレジスタセットを次回との差分のためにバックアップしておく - prev = cpu->reg; + md->BackupRegs(); gCVPrompt->NotifyRelease(); } @@ -634,7 +557,7 @@ Debugger::Continue() // 引数などからアドレスを取得する共通ルーチン。 // 引数が1つ(以上)あれば av[1] をアドレスとしてパースする。 // なければ、lastaddr が指定されていればそれを使う。 -// それもなければ、RegPC を使う。 +// それもなければ現在の PC を使う。 bool Debugger::GetAddr(uint32& addr, uint32& lastaddr) { @@ -650,7 +573,7 @@ Debugger::GetAddr(uint32& addr, uint32& addr = lastaddr; } else { // そうでなければ、今の PC - addr = RegPC; + addr = md->GetPC(); } return true; } @@ -681,6 +604,7 @@ void Debugger::cmd_d_common(MemdumpMode mode) { uint32 addr; + saddr_t saddr; int cnt; cnt = 10; @@ -694,17 +618,38 @@ Debugger::cmd_d_common(MemdumpMode mode) cnt = strtol(av[2], NULL, 10); } - DisasmLine dis(cpu, addr, mode); + saddr.addr = addr; + saddr.super = md->IsSuper(); + + // XXX そのうちなんとかする + if (mode == MemdumpMode::Logical_search) { + saddr.logical = true; + saddr.search = true; + } else if (mode == MemdumpMode::Logical_atc) { + saddr.logical = true; + } + for (int i = 0; i < cnt; i++) { - std::string buf = dis.Output(); - cons->Print("%s\n", buf.c_str()); - // バスエラーならこの行で終了。 - // XXX バスエラーかどうかを文字列判定してるのはさすがにどうかと - if (buf.find("BusErr") != std::string::npos) { - break; + std::string addrbuf; + std::string mnemonic; + std::string mnembuf; + std::vector local_ir; + + if (FormatDumpAddr(saddr, addrbuf)) { + md->Disassemble(saddr, mnemonic, local_ir); + // オフライン用に整形 + mnembuf = md->FormatDisasm(mnemonic, local_ir); } + // アドレス変換でバスエラーが起きてもここは表示する + cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str()); + + // 変換できなければここで終了 + if (local_ir.size() == 0) + break; + saddr.addr += local_ir.size(); } - d_last_addr = dis.GetNextAddr(); + + d_last_addr = saddr.addr; } // ログレベル設定: L @@ -726,8 +671,6 @@ Debugger::cmd_L() // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい if (strcmp(name, "sch") == 0) name = "scheduler"; - if (strcmp(name, "pio") == 0) - name = "ppi"; if (strcmp(name, "scc") == 0) name = "sio"; @@ -774,6 +717,7 @@ void Debugger::cmd_m_common(MemdumpMode mode) { uint32 addr; + saddr_t saddr; int cnt; cnt = 10; @@ -787,11 +731,63 @@ Debugger::cmd_m_common(MemdumpMode mode) cnt = strtol(av[2], NULL, 10); } - MemdumpLine mem(cpu, addr, mode); + saddr.addr = addr; + saddr.super = md->IsSuper(); + // XXX + if (mode == MemdumpMode::Logical_search) { + saddr.logical = true; + saddr.search = true; + } else if (mode == MemdumpMode::Logical_atc) { + saddr.logical = true; + } + for (int i = 0; i < cnt; i++) { - cons->Print("%s\n", mem.Output().c_str()); + std::string addrbuf; + std::string dumpbuf; + std::string charbuf; + + if (FormatDumpAddr(saddr, addrbuf) == false) { + // アドレス変換でバスエラーならダンプもくそもない + cons->Print("%s\n", addrbuf.c_str()); + // ここで終わる? + // XXX 16バイト先を試してみるとか? + break; + } + + for (int j = 0; j < 8; j++) { + uint64 paddr; + // もう一回アドレス変換するのやや冗長だが仕方ない + if (saddr.IsLogical() && md->MMUEnabled()) { + // アドレス変換 + paddr = md->TranslateAddr(saddr); + if ((int64)paddr < 0) { + // バスエラーが起きたら改行して仕切り直し + break; + } + } else { + paddr = saddr.addr; + } + + for (int k = 0; k < 2; k++) { + uint64 b = vm_phys_peek_8(paddr + k); + + if ((int64)b < 0) { + dumpbuf += "--"; + charbuf += " "; + } else { + uint32 c = (uint32)b; + dumpbuf += string_format("%02x", c); + charbuf += string_format("%c", + (0x20 <= c && c <= 0x7e) ? c : '.'); + } + } + dumpbuf += " "; + saddr.addr += 2; + } + cons->Print("%-18s %-40s %s\n", + addrbuf.c_str(), dumpbuf.c_str(), charbuf.c_str()); } - m_last_addr = mem.GetNextAddr(); + m_last_addr = saddr.addr; } // プロンプトに来た最初に表示するいつものやつを再表示する @@ -801,12 +797,27 @@ Debugger::cmd_minus() cmd_r(); // 論理アクセス時、ATC ミスが分かったほうが便利だと思う - MemdumpMode mode = (cpu->mmu_enable) - ? MemdumpMode::Logical_atc - : MemdumpMode::Physical; - DisasmLine dis(cpu, pc, mode); - cons->Print("%s%s\n", dis.Output().c_str(), OPccCondStr(pc)); - nextpc = dis.GetNextAddr(); + saddr_t laddr; + laddr.addr = pc; + laddr.super = md->IsSuper(); + laddr.logical = true; + laddr.search = false; + + // 現在の PC の位置を逆アセンブル。ここで ir を更新。 + std::string addrbuf; + std::string mnemonic; + std::string mnembuf; + ir.clear(); + // アドレスを表示用に + if (FormatDumpAddr(laddr, addrbuf)) { + md->Disassemble(laddr, mnemonic, ir); + // ライブ表示用に整形 + mnembuf = md->FormatDisasmLive(mnemonic, ir); + } + cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str()); + + // XXX m88k? + nextpc = pc + ir.size(); } // ステップ実行: n[?=1] (サブルーチンを飛ばす) @@ -859,8 +870,8 @@ Debugger::SetNBreakpoint() // XXX この辺統一的にしたほうがいい // XXX logical peek のような気がする - op = (((uint16)m68030_phys_peek_8(pc)) << 8) - | m68030_phys_peek_8(pc + 1); + op = (((uint16)vm_phys_peek_8(pc)) << 8) + | vm_phys_peek_8(pc + 1); if (IsBcc(op) || IsJMP(op) @@ -882,6 +893,19 @@ Debugger::SetNBreakpoint() } } +// デバッガ終了コマンド +void +Debugger::cmd_q() +{ + cons->Print("quit debugger console.\n"); + + // XXX: このフラグでいいのかとか exit でいいのかとか + if (gMainApp.debug_on_console) { + // コンソールモードのときはプログラムも終了 + exit(0); + } +} + // レジスタ表示 // rf: FPU レジスタを表示 // rm: MMU レジスタを表示 @@ -895,41 +919,48 @@ Debugger::cmd_r() case 'a': ShowMonitor(gMPUATC->monitor); return; + case 'c': + md->ShowRegCtrl(cons); + return; case 'f': - ShowRegFPU(); + md->ShowRegFPU(cons); return; case 'm': - ShowRegMMU(); + md->ShowRegMMU(cons); return; case 'o': - ShowRegOther(); + md->ShowRegOther(cons); return; } } - ShowRegMain(); + md->ShowRegMain(cons); } // ショートカット void Debugger::cmd_ra() { - gMPUATC->MonitorUpdate(); - ShowMonitor(gMPUATC->monitor); + md->ShowRegATC(cons); +} +void +Debugger::cmd_rc() +{ + md->ShowRegCtrl(cons); } void Debugger::cmd_rf() { - ShowRegFPU(); + md->ShowRegFPU(cons); } void Debugger::cmd_rm() { - ShowRegMMU(); + md->ShowRegMMU(cons); } void Debugger::cmd_ro() { - ShowRegOther(); + md->ShowRegOther(cons); } // モニター表示 @@ -1054,8 +1085,7 @@ void Debugger::cmd_so() { so_enable = true; - so_a7 = RegA(7); - so_sr = RegSR & 0x3000; + md->SetStepOut(); Continue(); } @@ -1091,46 +1121,19 @@ Debugger::ParseAddr(const char *arg, uin char *end; if (arg[0] == '%') { - /* '%' から始まればレジスタ */ - const char *regname = &arg[1]; - if ((*regname | 0x20) == 'a') { - addr = RegA(arg[2] - '0'); - - } else if ((*regname | 0x20) == 'd') { - addr = RegD(arg[2] - '0'); - - } else if (strcmp(regname, "sp") == 0) { - addr = RegA(7); - -#if 0 - } else if (strcmp(regname, "usp") == 0) { - addr = RegUSP; - - } else if (strcmp(regname, "isp") == 0) { - addr = RegISP; - - } else if (strcmp(regname, "msp") == 0) { - addr = RegMSP; -#endif - - } else if (strcmp(regname, "pc") == 0) { - addr = RegPC; - - } else if (strcmp(regname, "vbr") == 0) { - addr = RegVBR; - - } else if (strcmp(regname, "srp") == 0) { - addr = cpu->GetSRPl(); - - } else if (strcmp(regname, "crp") == 0) { - addr = cpu->GetCRPl(); - - } else { + // '%' から始まればレジスタ + uint64 r; + r = md->GetRegAddr(arg + 1); + if ((int64)r < 0) { +#if 0 // not yet cons->Print("valid register name are: %s%s\n", "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc", ",%msp,%vbr,%srp,%crp"); +#endif + cons->Print("invalid register name\n"); return false; } + addr = (uint32)r; } else { /* そうでなければ番地指定 */ errno = 0; @@ -1149,408 +1152,38 @@ Debugger::ParseAddr(const char *arg, uin return true; } -// -// レジスタ表示 -// - -#define NORM "\x1b[0m" -#define BOLD "\x1b[1m" -#define BOLDIF(n) ((n) ? BOLD : "") - -// 基本セット -void -Debugger::ShowRegMain() -{ -/* -D0:00000070 D4:CCCCCCCC A0:00FFAA32 A4:CCCCCCCC SR=F810(S I=0 X----) -D1:0000FFFF D5:00000000 A1:00000A7A A5:00000A7A -D2:00FF0000 D6:00000000 A2:CCCCCCCC A6:CCCCCCCC -D3:CCCCCCCC D7:00000003 A3:CCCCCCCC A7:00001FD8 -*/ - bool vr[16]; - - for (int i = 0; i < 16; i++) { - vr[i] = (cpu->reg.da[i] != prev.da[i]); - } - - // 1行目 - cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s ", - BOLDIF(vr[ 0]), 0, RegR( 0), NORM, - BOLDIF(vr[ 4]), 4, RegR( 4), NORM, - BOLDIF(vr[ 8]), 0, RegR( 8), NORM, - BOLDIF(vr[12]), 4, RegR(12), NORM); - - // 1行目 SR - uint16 sr = RegSR; - uint16 prevsr = prev.sr_h() - | (prev.ccr.IsX() ? M68K_CCR_X : 0) - | (prev.ccr.IsN() ? M68K_CCR_N : 0) - | (prev.ccr.IsZ() ? M68K_CCR_Z : 0) - | (prev.ccr.IsV() ? M68K_CCR_V : 0) - | (prev.ccr.IsC() ? M68K_CCR_C : 0); - // SR は上位バイトと下位バイトが変化したくらいでいいか? - cons->Print(" SR:%s%02x%s%s%02x%s", - BOLDIF((sr & 0xff00) != (prevsr & 0xff00)), - sr >> 8, - NORM, - BOLDIF((sr & 0x00ff) != (prevsr & 0x00ff)), - sr & 0xff, - NORM); - cons->Print("(%c I=%d %c%c%c%c%c)\n", - (sr & 0x2000) ? 'S' : '-', - (sr >> 8) & 7, - (sr & M68K_CCR_X) ? 'X' : '-', - (sr & M68K_CCR_N) ? 'N' : '-', - (sr & M68K_CCR_Z) ? 'Z' : '-', - (sr & M68K_CCR_V) ? 'V' : '-', - (sr & M68K_CCR_C) ? 'C' : '-'); - - // 2行目 - cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n", - BOLDIF(vr[ 1]), 1, RegR( 1), NORM, - BOLDIF(vr[ 5]), 5, RegR( 5), NORM, - BOLDIF(vr[ 9]), 1, RegR( 9), NORM, - BOLDIF(vr[13]), 5, RegR(13), NORM); - - // 3行目 - cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n", - BOLDIF(vr[ 2]), 2, RegR( 2), NORM, - BOLDIF(vr[ 6]), 6, RegR( 6), NORM, - BOLDIF(vr[10]), 2, RegR(10), NORM, - BOLDIF(vr[14]), 6, RegR(14), NORM); - - // 4行目 - cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n", - BOLDIF(vr[ 3]), 3, RegR( 3), NORM, - BOLDIF(vr[ 7]), 7, RegR( 7), NORM, - BOLDIF(vr[11]), 3, RegR(11), NORM, - BOLDIF(vr[15]), 7, RegR(15), NORM); -} - -// FPU レジスタ表示 -void -Debugger::ShowRegFPU() -{ -/* -FP0:0000_12345678_12345678 (-0.1234567890123456789) FPCR:1234 -FP1: BS,SN,OP,OV,UF,DZ,I2,I1 -FP2: RP=xx RM=xx -FP3: FPSR:12345678 -FP4: N,Z,Inf,NAN Q=$xx -FP5: BS,SN,OP,OV,UF,DZ,I2,I1 -FP6: AXEC -FP7: FPIAR:12345678 -*/ - -#define PUT_FP(n) do { \ - uint32 *c_ = cpu->reg.fpframe.fpf_regs + (n) * 3; \ - uint32 *p_ = prev.fpframe.fpf_regs + (n) * 3; \ - bool d = (c_[0] ^ p_[0]) | (c_[1] ^ p_[1]) | (c_[2] ^ p_[2]); \ - cons->Print("%sFP%d:%04xxxxx_%08x_%08x (%-20s)%s ", \ - BOLDIF(d), (n), c_[0] >> 16, c_[1], c_[2], "notyet", NORM); \ -} while (0) - - uint32 fpcr, fpsr, fpiar; - uint32 ppcr, ppsr, ppiar; - static const char * const rpstr[] = { - ".EXT", - ".SGL", - ".DBL", - ".???", - }; - static const char * const rmstr[] = { - "Near", - "Zero", - "Minus", - "Plus", - }; - - fpcr = cpu->reg.fpframe.fpf_fpcr; - fpsr = cpu->reg.fpframe.fpf_fpsr; - fpiar = cpu->reg.fpframe.fpf_fpiar; - ppcr = prev.fpframe.fpf_fpcr; - ppsr = prev.fpframe.fpf_fpsr; - ppiar = prev.fpframe.fpf_fpiar; - - PUT_FP(0); - cons->Print("%sFPCR:%04x%s\n", BOLDIF(fpcr != ppcr), fpcr, NORM); - - PUT_FP(1); - cons->Print(" %s %s %s %s %s %s %s %s\n", - (fpcr & 0x8000) ? "BS" : "--", - (fpcr & 0x4000) ? "SN" : "--", - (fpcr & 0x2000) ? "OP" : "--", - (fpcr & 0x1000) ? "OV" : "--", - (fpcr & 0x0800) ? "UF" : "--", - (fpcr & 0x0400) ? "DZ" : "--", - (fpcr & 0x0200) ? "I2" : "--", - (fpcr & 0x0100) ? "I1" : "--"); - - PUT_FP(2); - cons->Print(" RP=%s RM=%s\n", - rpstr[(fpcr >> 6) & 3], - rmstr[(fpcr >> 4) & 3]); - - PUT_FP(3); - cons->Print("%sFPSR:%08x%s\n", BOLDIF(fpsr != ppsr), fpsr, NORM); - - PUT_FP(4); - uint cc = fpsr >> 24; - cons->Print(" %c %c %s %s Q=$%02x\n", - (cc & 0x08) ? 'N' : '-', - (cc & 0x04) ? 'Z' : '-', - (cc & 0x02) ? "Inf" : "---", - (cc & 0x01) ? "NAN" : "---", - (fpsr >> 16) & 0xff); - - PUT_FP(5); - cons->Print(" %s %s %s %s %s %s %s %s\n", - (fpsr & 0x8000) ? "BS" : "--", - (fpsr & 0x4000) ? "SN" : "--", - (fpsr & 0x2000) ? "OP" : "--", - (fpsr & 0x1000) ? "OV" : "--", - (fpsr & 0x0800) ? "UF" : "--", - (fpsr & 0x0400) ? "DZ" : "--", - (fpsr & 0x0200) ? "I2" : "--", - (fpsr & 0x0100) ? "I1" : "--"); - - PUT_FP(6); - cons->Print(" %s %s %s %s %s\n", - (fpsr & 0x80) ? "IOP" : "---", - (fpsr & 0x40) ? "OVFL" : "----", - (fpsr & 0x20) ? "UNFL" : "----", - (fpsr & 0x10) ? "DZ" : "--", - (fpsr & 0x08) ? "INEX" : "----"); - - PUT_FP(7); - cons->Print("%sFPIAR:%08x%s\n", BOLDIF(fpiar != ppiar), fpiar, NORM); -} - -void -Debugger::ShowRegMMU() -{ -/* -SRP:00001111_22223333 TT0:00001111 TC:00001111 (---) -CRP:00001111_22223333 TT1:00001111 MMUSR: 0011 ( -*/ - uint64 srp, osrp; - uint64 crp, ocrp; - uint32 tt0, ott0; - uint32 tt1, ott1; - uint32 tc, otc; - uint16 sr, osr; - bool p; - bool t; - bool c; - - srp = cpu->GetSRP(); - crp = cpu->GetCRP(); - tt0 = cpu->GetTT(0); - tt1 = cpu->GetTT(1); - tc = cpu->GetTC(); - sr = cpu->GetMMUSR(); - - osrp = prev.srp.q; - ocrp = prev.crp.q; - ott0 = prev.tt[0]; - ott1 = prev.tt[1]; - otc = prev.tc; - osr = prev.mmusr; - - // 1行目 - p = (srp != osrp); - t = (tt0 != ott0); - c = (tc != otc); - cons->Print("%sSRP:%08x_%08x%s %sTT0:%08x%s(%c%c%c)", - BOLDIF(p), (uint32)(srp >> 32), (uint32)srp, NORM, - BOLDIF(t), tt0, NORM, - (tt0 & m68030TT::E) ? 'E' : '-', - (tt0 & m68030TT::CI) ? 'C' : '-', - (tt0 & m68030TT::RWM) ? '-' : ((tt0 & m68030TT::RW) ? 'R' : 'W')); - cons->Print(" %sTC:%08x%s(%c%c%c)\n", - BOLDIF(c), tc, NORM, - (tc & m68030TC::TC_E) ? 'E' : '-', - (tc & m68030TC::TC_SRE) ? 'S' : '-', - (tc & m68030TC::TC_FCL) ? 'F' : '-'); - - // 2行目 - p = (crp != ocrp); - t = (tt1 != ott1); - c = (sr != osr); - cons->Print("%sCRP:%08x_%08x%s %sTT1:%08x%s(%c%c%c)", - BOLDIF(p), uint32(crp >> 32), (uint32)crp, NORM, - BOLDIF(t), tt1, NORM, - (tt1 & m68030TT::E) ? 'E' : '-', - (tt1 & m68030TT::CI) ? 'C' : '-', - (tt1 & m68030TT::RWM) ? '-' : ((tt1 & m68030TT::RW) ? 'R' : 'W')); - cons->Print(" %sMMUSR: %04x%s(%c%c%c%c%c%c%c N=%d)\n", - BOLDIF(c), sr, NORM, - (sr & m68030MMUSR::B) ? 'B' : '-', - (sr & m68030MMUSR::L) ? 'L' : '-', - (sr & m68030MMUSR::S) ? 'S' : '-', - (sr & m68030MMUSR::W) ? 'W' : '-', - (sr & m68030MMUSR::I) ? 'I' : '-', - (sr & m68030MMUSR::M) ? 'M' : '-', - (sr & m68030MMUSR::T) ? 'T' : '-', - (sr & m68030MMUSR::N)); -} - -// その他のレジスタを表示 -void -Debugger::ShowRegOther() -{ - TextScreen s(80, 2); - - // 0 1 2 3 4 5 6 - // 012345678901234567890123456789012345678901234567890123456789012345 - // CACR:01234567 VBR:01234567 USP:01234567 - // CAAR:01234567 SFC:0 DFC:0 MSP:01234567 - -#define EM(name) ((cpu->reg.name != prev.name) ? TA::Em : TA::Normal) - s.Print(0, 0, EM(cacr), "CACR:%08x", cpu->reg.cacr); - s.Print(0, 1, EM(caar), "CAAR:%08x", cpu->reg.caar); - - s.Print(15, 0, EM(vbr), "VBR:%08x", cpu->reg.vbr); - s.Print(15, 1, EM(sfc), "SFC:%d", cpu->reg.sfc); - s.Print(22, 1, EM(dfc), "DFC:%d", cpu->reg.dfc); - - // スタック欄はモードによって表示を変える。 - // ユーザ 割り込み マスタ - // 1行目 ISP USP USP - // 2行目 MSP MSP ISP - if (!cpu->reg.s) { - s.Print(29, 0, EM(isp), "ISP:%08x", cpu->reg.isp); - } else { - s.Print(29, 0, EM(usp), "USP:%08x", cpu->reg.usp); - } - if (!cpu->reg.m) { - s.Print(29, 1, EM(msp), "MSP:%08x", cpu->reg.msp); - } else { - s.Print(29, 1, EM(isp), "ISP:%08x", cpu->reg.isp); - } - - ShowMonitor(s); -} - -// op が 68030 の条件命令 Bcc, Scc, TRAPcc, DBcc なら true を返す。 +// (論理、物理)アドレスを表示用に整形。 +// 逆アセンブル表示、メモリダンプ表示等で共通。 +// アドレス変換でバスエラーが起きたら false を返す (この場合も str は有効)。 +// 末尾を空白パディングはしていないので必要なら "%-18s" 等して使うこと。 +// 123456789012345678 +// "00112233:44556677:" bool -Debugger::IsOPcc(uint16 op) +Debugger::FormatDumpAddr(saddr_t laddr, std::string& str) { - uint16 cc; + bool rv = true; - if ((op & 0xf000) == 0x6000) { - cc = (op >> 8) & 0xf; - if (cc == 0 || cc == 1) { // BRA, BSR - return false; - } else { - return true; // Bcc - } - } + // laddr は常に表示 + str = string_format("%08x", laddr.addr); - if ((op & 0xf0c0) == 0x50c0) { // Scc, TRAPcc, DBcc - return true; - } - - return false; -} - -// op が DBcc 命令なら true を返す。 -bool -Debugger::IsDBcc(uint16 op) -{ - if ((op & 0xf0f8) == 0x50c8) { // DBcc - return true; - } - return false; -} - -// op の cccc 条件が現在の CCR で成立するなら true を返す。 -bool -Debugger::IsCond(uint16 op) -{ - bool N = RegIsN; - bool Z = RegIsZ; - bool V = RegIsV; - bool C = RegIsC; - - switch ((op >> 8) & 0x0f) { - case 0: // T - return true; - case 1: // F - return false; - case 2: // HI - return (!C) && (!Z); - case 3: // LS - return C || Z; - case 4: // CC - return !C; - case 5: // CS - return C; - case 6: // NE - return !Z; - case 7: // EQ - return Z; - case 8: // VC - return !V; - case 9: // VS - return V; - case 10: // PL - return !N; - case 11: // MI - return N; - case 12: // GE - return (N && V) || ((!N) && (!V)); - case 13: // LT - return (N && (!V)) || ((!N) && V); - case 14: // GT - return (N && V && (!Z)) || ((!N) && (!V) && (!Z)); - case 15: // LE - return Z || (N && (!V)) || ((!N) && V); - default: - __unreachable(); - } -} - -// addr 位置の命令が条件命令なら、成立可否などの文字列を返す。 -// Bcc, Scc, TRAPcc 命令なら、条件が成立するかどうか。 -// DBcc 命令ならブランチするかどうか。 -const char * -Debugger::OPccCondStr(uint32 addr) -{ - uint16 op; - - // XXX logical peek のような気がする - op = (((uint16)m68030_phys_peek_8(addr)) << 8) - | m68030_phys_peek_8(addr + 1); - - // DBcc 命令なら、ブランチするかどうか - // IsOPcc() は DBcc も含んでいるため、IsDBcc() の判定のほうが先。 - // DBcc は内部でカウンタレジスタを減算してから比較するため、 - // 命令実行前のカウンタが 0 の時点でループ終了となることに注意。 - if (IsDBcc(op)) { - // 成立したら何もしない - if (IsCond(op)) { - return " (will fall)"; - } - // カウンタが -1 なら何もしない - uint rr = op & 7; - if ((RegD(rr) & 0xffff) == 0) { - return " (will expire)"; - } - // それ以外はブランチ - return " (will take)"; - } - - // Bcc, Scc, TRAPcc 命令なら条件が成立するかどうか - if (IsOPcc(op)) { - if (IsCond(op)) { - return " (will take)"; + if (laddr.IsLogical() && md->MMUEnabled()) { + // アドレス変換してみる + uint64 paddr = md->TranslateAddr(laddr); + if ((int64)paddr < 0) { + // MMU 時点でバスエラー + str += ":BusErr"; + rv = false; + } else if (paddr == laddr.addr) { + // PA==VA + str += "=PA"; } else { - return " (will not take)"; + // PA!=VA + str += string_format(":%08x:", (uint32)paddr); } + } else { + // 物理アクセス + str += ":"; } - // (ここで知ってる)条件命令ではない - return ""; + return rv; } -