--- nono/debugger/debugger_m680x0.cpp 2026/04/29 17:05:16 1.1.1.9 +++ nono/debugger/debugger_m680x0.cpp 2026/04/29 17:05:58 1.1.1.13 @@ -11,21 +11,22 @@ #include "debugger_m680x0.h" #include "debugger_memory.h" #include "debugger.h" -#include "m68030disasm.h" +#include "exttostr.h" +#include "m680x0disasm.h" #include "m68030mmu.h" #include "mainbus.h" +#include "vectortable.h" // コンストラクタ DebuggerMD_m680x0::DebuggerMD_m680x0(Debugger *parent_) : inherited(parent_, CPUArch::M680x0) { // この時点で Get*Device() は使える - cpu = GetMPU680x0Device(); + cpu = GetMPU680x0Device(parent->mpu); bus = GetMainbusDevice(); // 機種依存変数 inst_bytes = 2; - inst_bytes_fixed = 0; lasize = 32; pasize = 32; name = "mpu"; @@ -37,21 +38,14 @@ DebuggerMD_m680x0::~DebuggerMD_m680x0() } // アドレス変換 -uint64 -DebuggerMD_m680x0::TranslateAddr(saddr_t laddr, bool lookup) const +busaddr +DebuggerMD_m680x0::TranslateAddr(busaddr laddr) const { - uint fc; - - fc = laddr.IsData() ? M68K::FC_DATA : M68K::FC_PROG; - if (laddr.IsSuper()) { - fc |= M68K::FC_SUPER; - } - - return cpu->TranslatePeek((uint32)laddr, fc, lookup); + return cpu->TranslatePeek(laddr); } -// op が 68030 の条件命令 Bcc, Scc, TRAPcc, DBcc なら true を返す。 -bool +// op が 680x0 の条件命令 Bcc, Scc, TRAPcc, DBcc なら true を返す。 +/*static*/ bool DebuggerMD_m680x0::IsOPcc(uint16 op) { uint16 cc; @@ -73,7 +67,7 @@ DebuggerMD_m680x0::IsOPcc(uint16 op) } // op が DBcc 命令なら true を返す。 -bool +/*static*/ bool DebuggerMD_m680x0::IsDBcc(uint16 op) { if ((op & 0xf0f8) == 0x50c8) { // DBcc @@ -82,9 +76,37 @@ DebuggerMD_m680x0::IsDBcc(uint16 op) return false; } +// ir[] が FBcc, FScc, FDBcc, FTRAPcc 命令なら condition のあるワード位置を +// 返す。これらの条件命令でなければ (FNOP も含む)、-1 を返す。 +/*static*/ int +DebuggerMD_m680x0::IsFXcc(const std::vector& ir) +{ + if ((ir[0] & 0xfe00) != 0xf200) { + return -1; + } + if (ir.size() < 2) { + return -1; + } + + // FNOP は除く。 + if (ir[0] == 0xf280 && ir[1] == 0) { + return -1; + } + + uint type = (ir[0] >> 6) & 7; + if (type == 1) { // FScc/FDBcc/FTRAPcc + return 1; + } else if (type == 2) { // FBcc.W + return 0; + } else if (type == 3) { // FBcc.L + return 0; + } + return -1; +} + // op の cccc 条件が現在の CCR で成立するなら true を返す。 bool -DebuggerMD_m680x0::IsCond(uint16 op) +DebuggerMD_m680x0::IsCond(uint16 op) const { bool N = cpu->reg.ccr.IsN(); bool Z = cpu->reg.ccr.IsZ(); @@ -133,7 +155,7 @@ DebuggerMD_m680x0::IsCond(uint16 op) // Bcc, Scc, TRAPcc 命令なら、条件が成立するかどうか。 // DBcc 命令ならブランチするかどうか。 const char * -DebuggerMD_m680x0::CondStr(const std::vector& ir) +DebuggerMD_m680x0::CondStr(const std::vector& ir) const { uint16 op = ir[0]; @@ -164,6 +186,22 @@ DebuggerMD_m680x0::CondStr(const std::ve } } + // FXcc + int n = IsFXcc(ir); + if (n >= 0) { + struct fpemu fe0; + struct fpframe fpf0; + memset(&fe0, 0, sizeof(fe0)); + fe0.fe_fpframe = &fpf0; + fe0.fe_fpsr = cpu->reg.fpframe.fpf_fpsr; + int result = test_cc(&fe0, ir[n]); + if (result < 0) { + return " (will take)"; + } else if (result == 0) { + return " (will not take)"; + } + } + // (ここで知ってる)条件命令ではない return ""; } @@ -193,6 +231,7 @@ DebuggerMD_m680x0::IsOpStepIn(DebuggerMe || (op & 0xf0f8) == 0x50f8 // TRAPcc || (op & 0xff00) == 0x6100 // BSR || (op & 0xfff8) == 0xf278 // FTRAPcc + || (op & 0xfe00) == 0xfe00 // DOS($FFxx), FPACK($FExx) ) { return true; } @@ -217,24 +256,51 @@ DebuggerMD_m680x0::GetRegAddr(const char uint32 addr; if ((*name | 0x20) == 'a') { + if (name[1] < '0' || name[1] > '7') { + return (uint64)-1; + } addr = cpu->reg.A[name[1] - '0']; } else if ((*name | 0x20) == 'd') { + if (name[1] < '0' || name[1] > '7') { + return (uint64)-1; + } addr = cpu->reg.D[name[1] - '0']; } else if (strcmp(name, "sp") == 0) { addr = cpu->reg.A[7]; -#if 0 } else if (strcmp(name, "usp") == 0) { - addr = cpu->RegUSP; + if (cpu->reg.s == false) { + addr = cpu->reg.A[7]; + } else { + addr = cpu->reg.usp; + } } else if (strcmp(name, "isp") == 0) { - addr = cpu->RegISP; + if (cpu->reg.s && cpu->reg.m == false) { + addr = cpu->reg.A[7]; + } else { + addr = cpu->reg.isp; + } } else if (strcmp(name, "msp") == 0) { - addr = cpu->RegMSP; -#endif + if (cpu->reg.s && cpu->reg.m) { + addr = cpu->reg.A[7]; + } else { + addr = cpu->reg.msp; + } + + } else if (strcmp(name, "ssp") == 0) { + if (cpu->reg.s) { + addr = cpu->reg.A[7]; + } else { + if (cpu->reg.m) { + addr = cpu->reg.msp; + } else { + addr = cpu->reg.isp; + } + } } else if (strcmp(name, "pc") == 0) { addr = cpu->reg.pc; @@ -243,10 +309,29 @@ DebuggerMD_m680x0::GetRegAddr(const char addr = cpu->GetVBR(); } else if (strcmp(name, "srp") == 0) { - addr = cpu->GetSRPl(); + if (cpu->GetMPUType() == m680x0MPUType::M68030) { + auto cpu68030 = dynamic_cast(cpu); + addr = cpu68030->GetSRPl(); + } else { + auto cpu68040 = dynamic_cast(cpu); + addr = cpu68040->GetSRP(); + } } else if (strcmp(name, "crp") == 0) { - addr = cpu->GetCRPl(); + auto cpu68030 = dynamic_cast(cpu); + if (cpu68030) { + addr = cpu68030->GetCRPl(); + } else { + return (uint64)-1; + } + + } else if (strcmp(name, "urp") == 0) { + auto cpu68040 = dynamic_cast(cpu); + if (cpu68040) { + addr = cpu68040->GetURP(); + } else { + return (uint64)-1; + } } else { return (uint64)-1; @@ -336,7 +421,11 @@ DebuggerMD_m680x0::ShowRegister(FILE *co return true; } if (args[0] == "rm") { - ShowRegMMU(cons); + if (cpu->GetMPUType() == m680x0MPUType::M68030) { + ShowRegMMU30(cons); + } else { + ShowRegMMU40(cons); + } return true; } if (args[0] == "ro") { @@ -419,32 +508,14 @@ void DebuggerMD_m680x0::ShowRegFPU(FILE *cons) { /* -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 +FP0:0000_12345678_12345678 = -0.1234567890123456789) +FPCR: 1234 BS,SN,OE,OF,UF,DZ,X2,X1 RP=.X RM=Minus +FPSR: 12345678 N Z Inf NAN Q=$xx BS,SN,OE,OF,UF,DZ,X2,X1 AV AO AU AZ AX +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]); \ - fprintf(cons, "%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", @@ -459,39 +530,39 @@ FP7: ppsr = prev.fpframe.fpf_fpsr; ppiar = prev.fpframe.fpf_fpiar; - PUT_FP(0); - fprintf(cons, "%sFPCR:%04x%s\n", BOLDIF(fpcr != ppcr), fpcr, NORM); + for (uint n = 0; n < 8; n++) { + 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]); + fprintf(cons, "%sFP%u:%04x_%08x_%08x%s = %s\n", + BOLDIF(d), n, c_[0] >> 16, c_[1], c_[2], NORM, + ExtToStr(c_).c_str()); + } - PUT_FP(1); - fprintf(cons, " %s %s %s %s %s %s %s %s\n", + fprintf(cons, "%sFPCR: %04x%s%20s", + BOLDIF(fpcr != ppcr), fpcr, NORM, ""); + fprintf(cons, "%s %s %s %s %s %s %s %s ", (fpcr & 0x8000) ? "BS" : "--", (fpcr & 0x4000) ? "SN" : "--", - (fpcr & 0x2000) ? "OP" : "--", - (fpcr & 0x1000) ? "OV" : "--", + (fpcr & 0x2000) ? "OE" : "--", + (fpcr & 0x1000) ? "OF" : "--", (fpcr & 0x0800) ? "UF" : "--", (fpcr & 0x0400) ? "DZ" : "--", - (fpcr & 0x0200) ? "I2" : "--", - (fpcr & 0x0100) ? "I1" : "--"); - - PUT_FP(2); - fprintf(cons, " RP=%s RM=%s\n", - rpstr[(fpcr >> 6) & 3], + (fpcr & 0x0200) ? "X2" : "--", + (fpcr & 0x0100) ? "X1" : "--"); + fprintf(cons, "RP=.%c RM=%s\n", + "XSD?"[(fpcr >> 6) & 3], rmstr[(fpcr >> 4) & 3]); - PUT_FP(3); - fprintf(cons, "%sFPSR:%08x%s\n", BOLDIF(fpsr != ppsr), fpsr, NORM); - - PUT_FP(4); uint cc = fpsr >> 24; - fprintf(cons, " %c %c %s %s Q=$%02x\n", + fprintf(cons, "%sFPSR: %08x%s ", BOLDIF(fpsr != ppsr), fpsr, NORM); + fprintf(cons, "%c %c %s %s Q=$%02x ", (cc & 0x08) ? 'N' : '-', (cc & 0x04) ? 'Z' : '-', (cc & 0x02) ? "Inf" : "---", (cc & 0x01) ? "NAN" : "---", (fpsr >> 16) & 0xff); - - PUT_FP(5); - fprintf(cons, " %s %s %s %s %s %s %s %s\n", + fprintf(cons, "%s %s %s %s %s %s %s %s ", (fpsr & 0x8000) ? "BS" : "--", (fpsr & 0x4000) ? "SN" : "--", (fpsr & 0x2000) ? "OP" : "--", @@ -500,27 +571,25 @@ FP7: (fpsr & 0x0400) ? "DZ" : "--", (fpsr & 0x0200) ? "I2" : "--", (fpsr & 0x0100) ? "I1" : "--"); + fprintf(cons, "%s %s %s %s %s\n", + (fpsr & 0x80) ? "AV" : "--", + (fpsr & 0x40) ? "AO" : "--", + (fpsr & 0x20) ? "AU" : "--", + (fpsr & 0x10) ? "AZ" : "--", + (fpsr & 0x08) ? "AX" : "--"); - PUT_FP(6); - fprintf(cons, " %s %s %s %s %s\n", - (fpsr & 0x80) ? "IOP" : "---", - (fpsr & 0x40) ? "OVFL" : "----", - (fpsr & 0x20) ? "UNFL" : "----", - (fpsr & 0x10) ? "DZ" : "--", - (fpsr & 0x08) ? "INEX" : "----"); - - PUT_FP(7); fprintf(cons, "%sFPIAR:%08x%s\n", BOLDIF(fpiar != ppiar), fpiar, NORM); } -// MMU レジスタ表示 +// 68030 MMU レジスタ表示 void -DebuggerMD_m680x0::ShowRegMMU(FILE *cons) +DebuggerMD_m680x0::ShowRegMMU30(FILE *cons) { /* SRP:00001111_22223333 TT0:00001111 TC:00001111 (---) CRP:00001111_22223333 TT1:00001111 MMUSR: 0011 ( */ + auto cpu68030 = dynamic_cast(cpu); uint64 srp, osrp; uint64 crp, ocrp; uint32 tt0, ott0; @@ -531,12 +600,12 @@ CRP:00001111_22223333 TT1:00001111 MMUSR bool t; bool c; - srp = cpu->GetSRP(); - crp = cpu->GetCRP(); - tt0 = cpu->GetTT(0); - tt1 = cpu->GetTT(1); - tc = cpu->GetTC(); - sr = cpu->GetMMUSR(); + srp = cpu68030->GetSRP(); + crp = cpu68030->GetCRP(); + tt0 = cpu68030->GetTT(0); + tt1 = cpu68030->GetTT(1); + tc = cpu68030->GetTC(); + sr = cpu68030->GetMMUSR(); osrp = prev.srp.q; ocrp = prev.crp.q; @@ -583,6 +652,13 @@ CRP:00001111_22223333 TT1:00001111 MMUSR (sr & m68030MMUSR::N)); } +// 68040 MMU レジスタ表示 +void +DebuggerMD_m680x0::ShowRegMMU40(FILE *cons) +{ + fprintf(cons, "Not implemented\n"); +} + // ATC を表示 void DebuggerMD_m680x0::ShowRegATC() @@ -606,8 +682,8 @@ DebuggerMD_m680x0::ShowRegOther() 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); + s.Print(15, 1, EM(sfc), "SFC:%d", cpu->reg.GetSFC()); + s.Print(22, 1, EM(dfc), "DFC:%d", cpu->reg.GetDFC()); // スタック欄はモードによって表示を変える。 // ユーザ 割り込み マスタ @@ -657,3 +733,740 @@ DebuggerMD_m680x0::Disassemble(DebuggerM return str; } + +// 命令ニーモニックに対するバイナリを文字列形式で返す。 +// 対応しない場合は "" を返す。cmd_bi 用。 +std::string +DebuggerMD_m680x0::ParseInst(const std::string& inst) const +{ + if (inst == "frestore") return "f340:ffc0"; + if (inst == "fsave") return "f300:ffc0"; + if (inst == "nop") return "4e71"; + if (inst == "ptestr") return "f0008200:ffc0e200"; + if (inst == "ptestw") return "f0008000:ffc0e200"; + if (inst == "rte") return "4e73"; + + return ""; +} + +// 例外フレーム処理用の便利クラス。 +// 例外フレーム内は基本ワード単位なのに、仕様書のオフセットはバイト単位 +// なのでこういうヘルパーがないと事故が多発する。 +class StackData +{ + public: + StackData(DebuggerMemoryStream& mem_) + : mem(mem_) + { + } + + // 合計が words [ワード] になるまで追加で読み込む。 + void ReadWordUntil(size_t words); + // 合計が bytes (偶数) [バイト] になるまで追加で読み込む。 + void ReadByteUntil(size_t bytes); + + // 改行込みで出力。 + void Print(FILE *out, size_t byteoffset, uint bytes) const; + void Print(FILE *out, size_t byteoffset, uint bytes, + const char *, ...) const __printflike(5, 6); + + // 共通の表示用文字列を作成して返す。戻り値は改行なしの文字列。 + std::string Format(size_t byteoffset, uint bytes) const; + std::string Format(size_t byteoffset, uint bytes, + const char *, ...) const __printflike(4, 5); + + // byteoffset の位置のデータを表示用文字列にする。 + std::string FormatWord(size_t byteoffset) const; + std::string FormatLong(size_t byteoffset) const; + + // byteoffset の位置からのワードデータを返す。バスエラーなら -1。 + uint32 Word(size_t byteoffset) const; + // byteoffset の位置からのロングワードを返す。バスエラーなら (uint64)-1。 + uint64 Long(size_t byteoffset) const; + + // データサイズをバイト単位で返す。 + size_t bytesize() const noexcept { return framebuf.size() * 2; } + + private: + std::string FormatV(size_t byteoffset, uint bytes, + const char *, va_list) const __printflike(4, 0); + + DebuggerMemoryStream mem; + std::vector framebuf {}; +}; + +void +StackData::ReadWordUntil(size_t words) +{ + while (framebuf.size() < words) { + framebuf.push_back(mem.Read(2)); + } +} + +void +StackData::ReadByteUntil(size_t bytes) +{ + assert((bytes % 1) == 0); + size_t words = bytes / 2; + while (framebuf.size() < words) { + framebuf.push_back(mem.Read(2)); + } +} + +// 改行込みで表示する。bytes は 2, 4, 16 のみ。追加情報なし。 +void +StackData::Print(FILE *out, size_t byteoffset, uint bytes) const +{ + fprintf(out, "%s\n", Format(byteoffset, bytes).c_str()); +} + +// 改行込みで表示する。bytes は 2, 4, 16 のみ。 +void +StackData::Print(FILE *out, size_t byteoffset, uint bytes, + const char *fmt, ...) const +{ + va_list ap; + + assert(bytes == 2 || bytes == 4 || bytes == 16); + + va_start(ap, fmt); + fprintf(out, "%s\n", FormatV(byteoffset, bytes, fmt, ap).c_str()); + va_end(ap); +} + +// 共通の表示用文字列を作成して返す。戻り値は改行なしの文字列。 +std::string +StackData::Format(size_t byteoffset, uint bytes) const +{ + std::string s = string_format("+$%02x: ", (uint)byteoffset); + if (bytes == 2) { + s += FormatWord(byteoffset); + } else if (bytes == 4) { + s += FormatLong(byteoffset); + } else { + s += FormatLong(byteoffset); + s += ' '; + s += FormatLong(byteoffset + 4); + s += ' '; + s += FormatLong(byteoffset + 8); + s += ' '; + s += FormatLong(byteoffset + 12); + } + + return s; +} + +// 共通の表示用文字列を作成して返す。戻り値は改行なしの文字列。 +std::string +StackData::Format(size_t byteoffset, uint bytes, const char *fmt, ...) const +{ + std::string str; + va_list ap; + + va_start(ap, fmt); + str = FormatV(byteoffset, bytes, fmt, ap); + va_end(ap); + + return str; +} + +// 共通の表示用文字列を作成して返す。戻り値は改行なしの文字列。 +std::string +StackData::FormatV(size_t byteoffset, uint bytes, + const char *fmt, va_list ap) const +{ + std::string s = Format(byteoffset, bytes); + + char text[128]; + vsnprintf(text, sizeof(text), fmt, ap); + if (text[0]) { + if (bytes == 2) { + s += " "; + } + s += string_format(" : %s", text); + } + return s; +} + +// byteoffset の位置からのワードデータを表示用文字列にする。 +std::string +StackData::FormatWord(size_t byteoffset) const +{ + uint32 data = Word(byteoffset); + if ((int32)data < 0) { + return "----"; + } else { + char buf[16]; + snprintf(buf, sizeof(buf), "%04x", data); + return buf; + } +} + +// byteoffset の位置からのロングワードデータを表示用文字列にする。 +std::string +StackData::FormatLong(size_t byteoffset) const +{ + uint64 data = Long(byteoffset); + if ((int64)data < 0) { + return "--------"; + } else { + char buf[16]; + snprintf(buf, sizeof(buf), "%08x", (uint32)data); + return buf; + } +} + +uint32 +StackData::Word(size_t byteoffset) const +{ + size_t wordoffset = byteoffset / 2; + assert(wordoffset < framebuf.size()); + return framebuf[wordoffset]; +} + +uint64 +StackData::Long(size_t byteoffset) const +{ + uint32 hi = Word(byteoffset); + uint32 lo = Word(byteoffset + 2); + if ((int32)hi < 0 || (int32)lo < 0) { + return (uint64)-1; + } + return (hi << 16) | lo; +} + +// 例外フレームを表示する。 +void +DebuggerMD_m680x0::PrintExceptionFrame(FILE *out, busaddr addr) +{ + DebuggerMemoryStream mem(this, addr); + StackData frame(mem); + + fprintf(out, "Exception stack at $%08x\n", addr.Addr()); + + frame.ReadWordUntil(4); + + // ここからフレーム別。 + uint32 format = frame.Word(6) >> 12; + switch (format) { + case 0x0: // 034 Four word stack + PrintExceptionFrame0(out, frame); + break; + + case 0x1: // 034 Throwaway four word stack + PrintExceptionFrameCommon(out, frame, true); + break; + + case 0x2: // 034 Six word stack + PrintExceptionFrame2(out, frame); + break; + + case 0x3: // --4 Floating-point post-instruction stack + PrintExceptionFrame3(out, frame); + break; + + case 0x4: // --L Eight-word stack + PrintExceptionFrame4(out, frame); + break; + + case 0x7: // --4 Access error stack + PrintExceptionFrame7(out, frame); + break; + + case 0xb: // -3- Long bus cycle stack + PrintExceptionFrameB(out, frame); + break; + + case 9: // -3- Coprocessor mid-instruction Stack + case 0xa: // -3- Short bus cycle stack (nono は生成しない) + default: + fprintf(out, "Format $%x not supported\n", format); + break; + } +} + +// 共通の4ワード目までを表示する。 +bool +DebuggerMD_m680x0::PrintExceptionFrameCommon(FILE *out, + const StackData& frame, bool pc_is_next) +{ + // $06: Format|Vector + uint32 format_vector = frame.Word(6); + uint32 format = format_vector >> 12; + std::string s6; + if ((int32)format_vector < 0) { + s6 += "Format+Vector"; + } else { + uint32 vector = (format_vector >> 2) & 0xff; + s6 += string_format("Format=$%x Vector=$%02x", format, vector); + + // ベクタ番号からベクタ名を引いてみる。 + // Vector=$b は本来 Format=$0 で F ライン例外だが、 + // Format=$2 Vector=$b なら 68040 の未実装 FP 命令例外なので区別する。 + const char *exname = NULL; + if (format == 2 && vector == 0x0b) { + exname = "Unimplemented FP Instruction"; + } else { + auto vectortable = GetVectorTable(); + exname = vectortable->GetExceptionName(vector); + } + if (exname) { + s6 += " \""; + s6 += exname; + s6 += '\"'; + } + } + + frame.Print(out, 0, 2, "SR"); + frame.Print(out, 2, 4, "%sPC", pc_is_next ? "Next ": ""); + frame.Print(out, 6, 2, "%s", s6.c_str()); + + // ここがバスエラーならもう出来ることはない。 + if ((int32)format_vector < 0) { + return false; + } + return true; +} + +void +DebuggerMD_m680x0::PrintExceptionFrame0(FILE *out, StackData& frame) +{ + // Format$0 の PC は + // 種類 PC + // ---- + // ・割り込み 次の命令 + // ・TRAP#N 次の命令 + // ・フォーマットエラー 当該命令(RTE/FRESTORE) + // ・不当命令 当該命令 + // ・A/F ライン命令 当該命令 + // ・特権違反 当該命令 + + bool next; + uint vector = (frame.Word(0x06) & 0xfff) >> 2; + switch (vector) { + case M68K::EXCEP_FORMAT: + case M68K::EXCEP_ILLEGAL: + case M68K::EXCEP_ALINE: + case M68K::EXCEP_FLINE: + case M68K::EXCEP_PRIV: + next = false; + break; + default: + next = true; + break; + } + PrintExceptionFrameCommon(out, frame, next); +} + +void +DebuggerMD_m680x0::PrintExceptionFrame2(FILE *out, StackData& frame) +{ + // Format$2 の PC と Address は + // 種類 PC Address + // ---- -- ------- + // ・CHK/CHK2/TRAP*/ 次の命令 例外を起こした命令 + // FTRAPcc/Trace/ZeroDiv + // ・MMU 構成例外 次の命令 例外を起こした命令 + // ・040 未実装FP命令 次の命令 FPが計算したEA + // ・040 アドレスエラー 当該命令 参照アドレス-1 + + bool next; + const char *addr; + uint vector = (frame.Word(0x06) & 0xfff) >> 2; + switch (vector) { + case M68K::EXCEP_ZERODIV: + case M68K::EXCEP_CHK: + case M68K::EXCEP_TRAPV: + case M68K::EXCEP_TRACE: + case M68K::EXCEP_MMU_CONFIG: + next = true; + addr = "Caused instruction address"; + break; + + case M68K::EXCEP_FLINE: // これは 040 の EXCEP_FP_UNIMPL + next = true; + addr = "Calculated EA"; + break; + + case M68K::EXCEP_ADDRERR: + next = false; + addr = "Reference Address - 1"; + break; + + default: + next = false; + addr = "?"; + break; + } + + frame.ReadWordUntil(6); + if (PrintExceptionFrameCommon(out, frame, next) == false) { + return; + } + frame.Print(out, 0x08, 4, "%s", addr); +} + +void +DebuggerMD_m680x0::PrintExceptionFrame3(FILE *out, StackData& frame) +{ + frame.ReadWordUntil(6); + if (PrintExceptionFrameCommon(out, frame, true) == false) { + return; + } + frame.Print(out, 0x08, 4, "Effective Address"); +} + +void +DebuggerMD_m680x0::PrintExceptionFrame4(FILE *out, StackData& frame) +{ + frame.ReadWordUntil(8); + if (PrintExceptionFrameCommon(out, frame, true) == false) { + return; + } + frame.Print(out, 0x08, 4, "Effective Address"); + frame.Print(out, 0x0c, 4, "PC of Faulted Instruction"); +} + +void +DebuggerMD_m680x0::PrintExceptionFrame7(FILE *out, StackData& frame) +{ + static const char * const sizestr[] = { + ".L", + ".B", + ".W", + "Line", + }; + + frame.ReadWordUntil(30); + if (PrintExceptionFrameCommon(out, frame, true) == false) { + return; + } + frame.Print(out, 0x08, 4, "Effective Address"); + + // SSW + uint16 ssw = frame.Word(0x0c); + frame.Print(out, 0x0c, 2, + "SSW (%s %s %s %s %s %s %s RW=%c size=%s TT=%u TM=%u)", + ((ssw & M68040::SSW_CP) ? "CP" : "--"), + ((ssw & M68040::SSW_CU) ? "CU" : "--"), + ((ssw & M68040::SSW_CT) ? "CT" : "--"), + ((ssw & M68040::SSW_CM) ? "CM" : "--"), + ((ssw & M68040::SSW_MA) ? "MA" : "--"), + ((ssw & M68040::SSW_ATC) ? "ATC" : "---"), + ((ssw & M68040::SSW_LK) ? "LK" : "--"), + ((ssw & M68040::SSW_RW) ? 'R' : 'W'), + sizestr[(ssw >> 5) & 3], + ((ssw >> 3) & 3), + (ssw & 7)); + + // WB[321]S + for (uint i = 0; i < 3; i++) { + size_t off = 0x0e + i * 2; + uint16 wbs = frame.Word(off); + std::string stbuf; + if ((wbs & 0x80)) { + stbuf = "Valid"; + stbuf += string_format(" size=%s", sizestr[(wbs >> 5) & 3]); + stbuf += string_format(" TT=%u", (wbs >> 3) & 3); + stbuf += string_format(" TM=%u", wbs & 7); + } else { + stbuf = "no pending"; + } + frame.Print(out, off, 2, "WB%u Status (%s)", 3 - i, stbuf.c_str()); + } + + frame.Print(out, 0x14, 4, "Fault Address"); + frame.Print(out, 0x18, 4, "WB3 Address"); + frame.Print(out, 0x1c, 4, "WB3 Data"); + frame.Print(out, 0x20, 4, "WB2 Address"); + frame.Print(out, 0x24, 4, "WB2 Data"); + frame.Print(out, 0x28, 4, "WB1 Address"); + frame.Print(out, 0x2c, 4, "WB1 Data / PushData 0"); + frame.Print(out, 0x30, 4, "Push Data 1"); + frame.Print(out, 0x34, 4, "Push Data 2"); + frame.Print(out, 0x38, 4, "Push Data 3"); +} + +void +DebuggerMD_m680x0::PrintExceptionFrameB(FILE *out, StackData& frame) +{ + frame.ReadWordUntil(46); + if (PrintExceptionFrameCommon(out, frame, false) == false) { + return; + } + frame.Print(out, 0x08, 2); // internal + + // SSW + uint16 ssw = frame.Word(0x0a); + frame.Print(out, 0x0a, 2, + "SSW (%s %s %s %s %s %s RW=%c size=%c FC=%u)", + ((ssw & M68030::SSW_FC) ? "FC" : "--"), + ((ssw & M68030::SSW_FB) ? "FB" : "--"), + ((ssw & M68030::SSW_RC) ? "RC" : "--"), + ((ssw & M68030::SSW_RB) ? "RB" : "--"), + ((ssw & M68030::SSW_DF) ? "DF" : "--"), + ((ssw & M68030::SSW_RM) ? "RM" : "--"), + ((ssw & M68030::SSW_RW) ? 'R' : 'W'), + "LBW3"[(ssw >> 4) & 3], + (ssw & 7)); + + frame.Print(out, 0x0c, 2, "Instruction Pipe Stage C"); + frame.Print(out, 0x0e, 2, "Instruction Pipe Stage B"); + frame.Print(out, 0x10, 4, "Data Cycle Fault Address"); + frame.Print(out, 0x14, 4); + frame.Print(out, 0x18, 4, "Data Output Buffer"); + frame.Print(out, 0x1c, 4); + frame.Print(out, 0x20, 4); + frame.Print(out, 0x24, 4, "Stage B Address"); + frame.Print(out, 0x28, 4); + frame.Print(out, 0x2c, 4, "Data Input Buffer"); + + // 残りは内部データなのでまとめる。 + frame.Print(out, 0x30, 4, "(internal registers)"); + // +$36 にちょっと構造があるけどとりあえず無視。 + for (uint i = 0x34; i < frame.bytesize(); i += 4) { + if (i == 0x34 || i == 0x48) { + fprintf(out, "+$%02x:", i); + } + fprintf(out, " %s", frame.FormatLong(i).c_str()); + if (i == 0x44) { + fprintf(out, "\n"); + } + } + fprintf(out, "\n"); +} + +void +DebuggerMD_m680x0::PrintFPStateFrame(FILE *out, busaddr addr) +{ + DebuggerMemoryStream mem(this, addr); + StackData frame(mem); + + fprintf(out, "Floating-point state frame at $%08x\n", addr.Addr()); + + frame.ReadByteUntil(4); + + // 第1ワードはバージョンと後続の長さ。 + uint64 w00 = frame.Long(0x00); + uint32 ver = (w00 >> 24) & 0xff; + uint32 len = (w00 >> 16) & 0xff; + // VER LEN Name + // $00 ANY Null State Frame + // ver $18 68881 IDLE + // ver $38 68882 IDLE + // ver $B4 68881 BUSY + // ver $D4 68882 BUSY + // $41 $00 68040 IDLE + // $41 $30 68040 Unimplemented Instruction + // $41 $60 68040 BUSY + if (ver == 0x00) { + frame.Print(out, 0x00, 4, "Null State Frame"); + } else { + // NULL フレーム以外は残り len バイトある。 + frame.ReadByteUntil(len + 4); + + if (ver == 0x41) { + switch (len) { + case 0x00: + frame.Print(out, 0x00, 4, "68040 Idle State Frame"); + break; + case 0x30: + frame.Print(out, 0x00, 4, + "68040 Unimplemented Instruction State Frame"); + PrintFPFrame68040Unimpl(out, frame, 0); + break; + case 0x60: + frame.Print(out, 0x00, 4, "68040 Busy State Frame"); + PrintFPFrame68040Busy(out, frame); + break; + default: + frame.Print(out, 0x00, 4, "68040 Unknown State Frame?"); + break; + } + } else { + switch (len) { + case 0x18: + frame.Print(out, 0x00, 4, "68881 Idle State Frame"); + PrintFPFrame6888xIdle(out, frame, len); + break; + case 0x38: + frame.Print(out, 0x00, 4, "68882 Idle State Frame"); + PrintFPFrame6888xIdle(out, frame, len); + break; + case 0xb4: + frame.Print(out, 0x00, 4, "68881 Busy State Frame"); + PrintFPFrame6888xBusy(out, frame, len); + break; + case 0xd4: + frame.Print(out, 0x00, 4, "68882 Busy State Frame"); + PrintFPFrame6888xBusy(out, frame, len); + break; + default: + frame.Print(out, 0x00, 4, "Unknown State Frame?"); + break; + } + } + } +} + +void +DebuggerMD_m680x0::PrintFPFrame6888xIdle(FILE *out, StackData& frame, + uint32 len) +{ + bool is68882 = (len == 0x38); + + frame.Print(out, 0x04, 2, "Command/Condition Register"); + frame.Print(out, 0x06, 2); + uint32 pos = 0x08; + if (is68882) { + for (; pos < 0x28; pos += 16) { + frame.Print(out, pos, 16, "(internal register)"); + } + } + for (uint i = 0; i < 12; i += 4) { + frame.Print(out, pos, 4, "Exceptional Operand"); + pos += 4; + } + frame.Print(out, pos, 4, "Operand Register"); + pos += 4; + frame.Print(out, pos, 4, "BIU Flags"); +} + +void +DebuggerMD_m680x0::PrintFPFrame6888xBusy(FILE *out, StackData& frame, + uint32 len) +{ + uint pos = 4; + uint cnt = len / 16; + for (uint i = 0; i < cnt; i++) { + frame.Print(out, pos, 16, "(internal register)"); + pos += 16; + } + for (; pos < len + 4; pos += 4) { + frame.Print(out, pos, 4, "(internal register)"); + } +} + +// 68040 の未実装命令ステートフレーム。 +// 68040 のビジーフレームからも呼ばれる。base には Unimpl の原点を指定するが +// +$00 からの4バイト分の表示は呼び出し側の担当。 +void +DebuggerMD_m680x0::PrintFPFrame68040Unimpl(FILE *out, StackData& frame, + uint base) +{ + // +$04.L: CMDREG3B + uint32 reg3b = frame.Word(base + 0x04); + frame.Print(out, base + 0x04, 4, "CMDREG3B=$%03x", reg3b); + + // +$08.L: (reserved) + uint16 exc = frame.Word(base + 0x08); + frame.Print(out, base + 0x08, 4, + "(NMNEXC %s %s %s %s %s) (NMCEXC %s %s %s %s %s)", + ((exc & 0x0200) ? "UN" : "--"), + ((exc & 0x0100) ? "SN" : "--"), + ((exc & 0x0080) ? "OE" : "--"), + ((exc & 0x0040) ? "OF" : "--"), + ((exc & 0x0020) ? "UF" : "--"), + ((exc & 0x0010) ? "UN" : "--"), + ((exc & 0x0008) ? "SN" : "--"), + ((exc & 0x0004) ? "OE" : "--"), + ((exc & 0x0002) ? "OF" : "--"), + ((exc & 0x0001) ? "UF" : "--")); + + // +$0c.L: STAG... + uint32 w0c = frame.Word(base + 0x0c); + uint32 stag = (w0c >> 13) & 7; + frame.Print(out, base + 0x0c, 4, + "STAG=%u%s (E=%u) M66=%u M1=%u M0=%u SBIT=%u", + stag, MPU68040Device::GetFPUTagName(stag).c_str(), + ((w0c & 0x1000) ? 1 : 0), + ((w0c & 0x0400) ? 1 : 0), + ((w0c & 0x0200) ? 1 : 0), + ((w0c & 0x0100) ? 1 : 0), + ((w0c & 0x0080) ? 1 : 0)); + + // +$10.L: CMDREG1B + uint32 reg1b = frame.Word(base + 0x10); + uint32 opclass = reg1b >> 13; + uint32 rx = (reg1b >> 10) & 7; + uint32 ry = (reg1b >> 7) & 7; + uint32 cmd = reg1b & 0x7f; + std::string cmdname = MPU68040Device::GetReg1BName(opclass, rx, cmd); + frame.Print(out, base + 0x10, 4, + "CMDREG1B=$%04x: OPCLASS=%x Rs=%u Rd=%u CMD=$%02x(%s)", + reg1b, + opclass, rx, ry, + cmd, cmdname.c_str()); + + // +$14.L: DTAG... + uint32 w14 = frame.Word(base + 0x14); + uint32 dtag = (w14 >> 13) & 7; + frame.Print(out, base + 0x14, 4, + "DTAG=%u%s (FPTEMP15=%u) WBTEMP15=%u", + dtag, MPU68040Device::GetFPUTagName(dtag).c_str(), + ((w14 & 0x1000) ? 1 : 0), + ((w14 & 0x0010) ? 1 : 0)); + + // +$18.L: E1,E3,T + uint32 w18 = frame.Word(base + 0x18); + frame.Print(out, base + 0x18, 4, + "E1=%u E3=%u (S=%u X=%u U=%u) T=%u", + ((w18 & 0x0400) ? 1 : 0), + ((w18 & 0x0200) ? 1 : 0), + ((w18 & 0x0100) ? 1 : 0), + ((w18 & 0x0080) ? 1 : 0), + ((w18 & 0x0020) ? 1 : 0), + ((w18 & 0x0010) ? 1 : 0)); + + // +$1C.L: FPTS,FPTE + uint32 w1c = frame.Word(base + 0x1c); + frame.Print(out, base + 0x1c, 4, "FPTS=%u FPTE=$%04x", + ((w1c & 0x8000) ? 1 : 0), + (w1c & 0x7fff)); + + // +$20.L: FPTM + // +$24.L: FPTM + frame.Print(out, base + 0x20, 4, "FPTM[63:32]"); + frame.Print(out, base + 0x24, 4, "FPTM[31:00]"); + + // +$28.L: ETS,ETE + uint32 w28 = frame.Word(base + 0x28); + frame.Print(out, base + 0x28, 4, "ETS=%u ETE=$%04x", + ((w28 & 0x8000) ? 1 : 0), + (w28 & 0x7fff)); + + // +$2C.L: ETM + // +$30.L: ETM + frame.Print(out, base + 0x2c, 4, "ETM[63:32]"); + frame.Print(out, base + 0x30, 4, "ETM[31:00]"); +} + +void +DebuggerMD_m680x0::PrintFPFrame68040Busy(FILE *out, StackData& frame) +{ + frame.Print(out, 0x04, 4, "(reserved)"); + + // $08 CU_SAVEPC + uint32 w08 = frame.Word(0x08); + frame.Print(out, 0x08, 4, "CU_SAVEPC=$%02x", w08 >> 25); + + frame.Print(out, 0x0c, 4, "(reserved)"); + frame.Print(out, 0x10, 4, "(reserved)"); + frame.Print(out, 0x14, 4, "(reserved)"); + + // $18 WBT + uint32 w18 = frame.Word(0x18); + frame.Print(out, 0x18, 4, "WBT S=%u E=$%04x", + ((w18 & 0x8000) ? 1 : 0), + (w18 & 0x7fff)); + frame.Print(out, 0x1c, 4, "WBTM[63:32]"); + frame.Print(out, 0x20, 4, "WBTM[31:00]"); + + frame.Print(out, 0x24, 4, "(reserved)"); + frame.Print(out, 0x28, 4, "FPIARCU"); + frame.Print(out, 0x2c, 4, "(reserved)"); + frame.Print(out, 0x30, 4, "(reserved)"); + + // これ以降は Unimpl と同じ。 + PrintFPFrame68040Unimpl(out, frame, 0x30); +}