|
|
1.1 root 1: //
2: // nono
1.1.1.2 ! root 3: // Copyright (C) 2020 nono project
! 4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "console.h"
8: #include "debugger_private.h"
9: #include "debugger_m680x0.h"
10: #include "m68030disasm.h"
11: #include "mpu.h"
12: #include "mystring.h"
13:
1.1.1.2 ! root 14: // コンストラクタ
! 15: DebuggerMD_m680x0::DebuggerMD_m680x0(Debugger *parent_, m68kcpu *cpu_)
! 16: : inherited(parent_)
! 17: {
! 18: cpu = cpu_;
! 19:
! 20: // 奇数にしておくことで初回に必ずアドレス変換を起こさせる。
! 21: last_lpage.addr = 0xffffffff;
! 22: }
! 23:
! 24: // デストラクタ
! 25: DebuggerMD_m680x0::~DebuggerMD_m680x0()
! 26: {
! 27: }
! 28:
1.1 root 29: // アドレス変換
30: uint64
31: DebuggerMD_m680x0::TranslateAddr(saddr_t laddr)
32: {
33: uint64 paddr;
34:
35: // ページ境界(と初回)でアドレス変換
36: saddr_t lpage;
37: lpage.addr = laddr.addr & cpu->mmu_tc.lmask;
38: lpage.super = laddr.super;
39: if (lpage.GetSaddr() != last_lpage.GetSaddr()) {
40: last_lpage = lpage;
41: uint32 fc2 = (lpage.super ? FC_SUPER : 0) | FC_PROG; // DATAは?
42:
43: bool do_search = laddr.IsSearch();
44: paddr = m68030_mmu_translate_peek(cpu, laddr.addr, fc2, do_search);
45: if ((int64)paddr < 0) {
46: last_lpage.addr = 0xffffffff;
47: }
48: last_ppage = paddr & cpu->mmu_tc.lmask;
49: } else {
50: paddr = last_ppage | (laddr.addr & cpu->mmu_tc.pgmask);
51: }
52: return paddr;
53: }
54:
55: // op が 68030 の条件命令 Bcc, Scc, TRAPcc, DBcc なら true を返す。
56: bool
57: DebuggerMD_m680x0::IsOPcc(uint16 op)
58: {
59: uint16 cc;
60:
61: if ((op & 0xf000) == 0x6000) {
62: cc = (op >> 8) & 0xf;
63: if (cc == 0 || cc == 1) { // BRA, BSR
64: return false;
65: } else {
66: return true; // Bcc
67: }
68: }
69:
70: if ((op & 0xf0c0) == 0x50c0) { // Scc, TRAPcc, DBcc
71: return true;
72: }
73:
74: return false;
75: }
76:
77: // op が DBcc 命令なら true を返す。
78: bool
79: DebuggerMD_m680x0::IsDBcc(uint16 op)
80: {
81: if ((op & 0xf0f8) == 0x50c8) { // DBcc
82: return true;
83: }
84: return false;
85: }
86:
87: // op の cccc 条件が現在の CCR で成立するなら true を返す。
88: bool
89: DebuggerMD_m680x0::IsCond(uint16 op)
90: {
91: bool N = RegIsN;
92: bool Z = RegIsZ;
93: bool V = RegIsV;
94: bool C = RegIsC;
95:
96: switch ((op >> 8) & 0x0f) {
97: case 0: // T
98: return true;
99: case 1: // F
100: return false;
101: case 2: // HI
102: return (!C) && (!Z);
103: case 3: // LS
104: return C || Z;
105: case 4: // CC
106: return !C;
107: case 5: // CS
108: return C;
109: case 6: // NE
110: return !Z;
111: case 7: // EQ
112: return Z;
113: case 8: // VC
114: return !V;
115: case 9: // VS
116: return V;
117: case 10: // PL
118: return !N;
119: case 11: // MI
120: return N;
121: case 12: // GE
122: return (N && V) || ((!N) && (!V));
123: case 13: // LT
124: return (N && (!V)) || ((!N) && V);
125: case 14: // GT
126: return (N && V && (!Z)) || ((!N) && (!V) && (!Z));
127: case 15: // LE
128: return Z || (N && (!V)) || ((!N) && V);
129: default:
130: __unreachable();
131: }
132: }
133:
134: // addr 位置の命令が条件命令なら、成立可否などの文字列を返す。
135: // Bcc, Scc, TRAPcc 命令なら、条件が成立するかどうか。
136: // DBcc 命令ならブランチするかどうか。
137: const char *
138: DebuggerMD_m680x0::CondStr(const std::vector<uint16>& ir)
139: {
140: uint16 op = ir[0];
141:
142: // DBcc 命令なら、ブランチするかどうか
143: // IsOPcc() は DBcc も含んでいるため、IsDBcc() の判定のほうが先。
144: // DBcc は内部でカウンタレジスタを減算してから比較するため、
145: // 命令実行前のカウンタが 0 の時点でループ終了となることに注意。
146: if (IsDBcc(op)) {
147: // 成立したら何もしない
148: if (IsCond(op)) {
149: return " (will fall)";
150: }
151: // カウンタが -1 なら何もしない
152: uint rr = op & 7;
153: if ((RegD(rr) & 0xffff) == 0) {
154: return " (will expire)";
155: }
156: // それ以外はブランチ
157: return " (will take)";
158: }
159:
160: // Bcc, Scc, TRAPcc 命令なら条件が成立するかどうか
161: if (IsOPcc(op)) {
162: if (IsCond(op)) {
163: return " (will take)";
164: } else {
165: return " (will not take)";
166: }
167: }
168:
169: // (ここで知ってる)条件命令ではない
170: return "";
171: }
172:
173: void
174: DebuggerMD_m680x0::SetStepOut()
175: {
176: so_a7 = RegA(7);
177: so_sr = RegSR & 0x3000;
178: }
179:
180: bool
181: DebuggerMD_m680x0::IsStepOut() const
182: {
183: return (RegA(7) > so_a7 || (RegSR & 0x3000) != so_sr);
184: }
185:
186: // レジスタ名からそのレジスタ値を返す。
187: // メモリダンプのような用途なのでアドレスとして使えるアドレスのみ。
188: uint64
189: DebuggerMD_m680x0::GetRegAddr(const char *name) const
190: {
191: uint32 addr;
192:
193: if ((*name | 0x20) == 'a') {
194: addr = RegA(name[1] - '0');
195:
196: } else if ((*name | 0x20) == 'd') {
197: addr = RegD(name[1] - '0');
198:
199: } else if (strcmp(name, "sp") == 0) {
200: addr = RegA(7);
201:
202: #if 0
203: } else if (strcmp(name, "usp") == 0) {
204: addr = RegUSP;
205:
206: } else if (strcmp(name, "isp") == 0) {
207: addr = RegISP;
208:
209: } else if (strcmp(name, "msp") == 0) {
210: addr = RegMSP;
211: #endif
212:
213: } else if (strcmp(name, "pc") == 0) {
214: addr = RegPC;
215:
216: } else if (strcmp(name, "vbr") == 0) {
217: addr = RegVBR;
218:
219: } else if (strcmp(name, "srp") == 0) {
220: addr = cpu->GetSRPl();
221:
222: } else if (strcmp(name, "crp") == 0) {
223: addr = cpu->GetCRPl();
224:
225: } else {
226: return (uint64)-1;
227: }
228: return addr;
229: }
230:
1.1.1.2 ! root 231: // レジスタ表示系コマンドのヘルプ
! 232: /*static*/ const HelpMessages
! 233: DebuggerMD_m680x0::HelpMsgRegister = {
! 234: { "r", "通常レジスタを表示" },
! 235: { "ra", "ATC を表示" },
! 236: { "rf", "FPU レジスタを表示" },
! 237: { "rm", "MMU レジスタを表示" },
! 238: { "ro", "その他のレジスタを表示" },
! 239: };
! 240:
! 241: const HelpMessages&
! 242: DebuggerMD_m680x0::GetRegisterHelp() const
! 243: {
! 244: return HelpMsgRegister;
! 245: }
! 246:
! 247: // レジスタ表示系コマンド
! 248: bool
! 249: DebuggerMD_m680x0::ShowRegister(Console *cons,
! 250: const std::vector<std::string>& args)
! 251: {
! 252: // 余分な引数は無視する?
! 253:
! 254: if (args[0] == "r") {
! 255: ShowRegMain(cons);
! 256: return true;
! 257: }
! 258: if (args[0] == "ra") {
! 259: ShowRegATC(cons);
! 260: return true;
! 261: }
! 262: if (args[0] == "rf") {
! 263: ShowRegFPU(cons);
! 264: return true;
! 265: }
! 266: if (args[0] == "rm") {
! 267: ShowRegMMU(cons);
! 268: return true;
! 269: }
! 270: if (args[0] == "ro") {
! 271: ShowRegOther(cons);
! 272: return true;
! 273: }
! 274:
! 275: // 該当なし
! 276: return false;
! 277: }
! 278:
! 279:
1.1 root 280: // レジスタ表示 (基本セット)
281: void
282: DebuggerMD_m680x0::ShowRegMain(Console *cons)
283: {
284: /*
285: D0:00000070 D4:CCCCCCCC A0:00FFAA32 A4:CCCCCCCC SR=F810(S I=0 X----)
286: D1:0000FFFF D5:00000000 A1:00000A7A A5:00000A7A
287: D2:00FF0000 D6:00000000 A2:CCCCCCCC A6:CCCCCCCC
288: D3:CCCCCCCC D7:00000003 A3:CCCCCCCC A7:00001FD8
289: */
290: bool vr[16];
291:
292: for (int i = 0; i < 16; i++) {
293: vr[i] = (cpu->reg.da[i] != prev.da[i]);
294: }
295:
296: // 1行目
297: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s ",
298: BOLDIF(vr[ 0]), 0, RegR( 0), NORM,
299: BOLDIF(vr[ 4]), 4, RegR( 4), NORM,
300: BOLDIF(vr[ 8]), 0, RegR( 8), NORM,
301: BOLDIF(vr[12]), 4, RegR(12), NORM);
302:
303: // 1行目 SR
304: uint16 sr = RegSR;
305: uint16 prevsr = prev.sr_h()
306: | (prev.ccr.IsX() ? M68K_CCR_X : 0)
307: | (prev.ccr.IsN() ? M68K_CCR_N : 0)
308: | (prev.ccr.IsZ() ? M68K_CCR_Z : 0)
309: | (prev.ccr.IsV() ? M68K_CCR_V : 0)
310: | (prev.ccr.IsC() ? M68K_CCR_C : 0);
311: // SR は上位バイトと下位バイトが変化したくらいでいいか?
312: cons->Print(" SR:%s%02x%s%s%02x%s",
313: BOLDIF((sr & 0xff00) != (prevsr & 0xff00)),
314: sr >> 8,
315: NORM,
316: BOLDIF((sr & 0x00ff) != (prevsr & 0x00ff)),
317: sr & 0xff,
318: NORM);
319: cons->Print("(%c I=%d %c%c%c%c%c)\n",
320: (sr & 0x2000) ? 'S' : '-',
321: (sr >> 8) & 7,
322: (sr & M68K_CCR_X) ? 'X' : '-',
323: (sr & M68K_CCR_N) ? 'N' : '-',
324: (sr & M68K_CCR_Z) ? 'Z' : '-',
325: (sr & M68K_CCR_V) ? 'V' : '-',
326: (sr & M68K_CCR_C) ? 'C' : '-');
327:
328: // 2行目
329: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
330: BOLDIF(vr[ 1]), 1, RegR( 1), NORM,
331: BOLDIF(vr[ 5]), 5, RegR( 5), NORM,
332: BOLDIF(vr[ 9]), 1, RegR( 9), NORM,
333: BOLDIF(vr[13]), 5, RegR(13), NORM);
334:
335: // 3行目
336: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
337: BOLDIF(vr[ 2]), 2, RegR( 2), NORM,
338: BOLDIF(vr[ 6]), 6, RegR( 6), NORM,
339: BOLDIF(vr[10]), 2, RegR(10), NORM,
340: BOLDIF(vr[14]), 6, RegR(14), NORM);
341:
342: // 4行目
343: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
344: BOLDIF(vr[ 3]), 3, RegR( 3), NORM,
345: BOLDIF(vr[ 7]), 7, RegR( 7), NORM,
346: BOLDIF(vr[11]), 3, RegR(11), NORM,
347: BOLDIF(vr[15]), 7, RegR(15), NORM);
348: }
349:
350: // FPU レジスタ表示
351: void
352: DebuggerMD_m680x0::ShowRegFPU(Console *cons)
353: {
354: /*
355: FP0:0000_12345678_12345678 (-0.1234567890123456789) FPCR:1234
356: FP1: BS,SN,OP,OV,UF,DZ,I2,I1
357: FP2: RP=xx RM=xx
358: FP3: FPSR:12345678
359: FP4: N,Z,Inf,NAN Q=$xx
360: FP5: BS,SN,OP,OV,UF,DZ,I2,I1
361: FP6: AXEC
362: FP7: FPIAR:12345678
363: */
364:
365: #define PUT_FP(n) do { \
366: uint32 *c_ = cpu->reg.fpframe.fpf_regs + (n) * 3; \
367: uint32 *p_ = prev.fpframe.fpf_regs + (n) * 3; \
368: bool d = (c_[0] ^ p_[0]) | (c_[1] ^ p_[1]) | (c_[2] ^ p_[2]); \
369: cons->Print("%sFP%d:%04xxxxx_%08x_%08x (%-20s)%s ", \
370: BOLDIF(d), (n), c_[0] >> 16, c_[1], c_[2], "notyet", NORM); \
371: } while (0)
372:
373: uint32 fpcr, fpsr, fpiar;
374: uint32 ppcr, ppsr, ppiar;
375: static const char * const rpstr[] = {
376: ".EXT",
377: ".SGL",
378: ".DBL",
379: ".???",
380: };
381: static const char * const rmstr[] = {
382: "Near",
383: "Zero",
384: "Minus",
385: "Plus",
386: };
387:
388: fpcr = cpu->reg.fpframe.fpf_fpcr;
389: fpsr = cpu->reg.fpframe.fpf_fpsr;
390: fpiar = cpu->reg.fpframe.fpf_fpiar;
391: ppcr = prev.fpframe.fpf_fpcr;
392: ppsr = prev.fpframe.fpf_fpsr;
393: ppiar = prev.fpframe.fpf_fpiar;
394:
395: PUT_FP(0);
396: cons->Print("%sFPCR:%04x%s\n", BOLDIF(fpcr != ppcr), fpcr, NORM);
397:
398: PUT_FP(1);
399: cons->Print(" %s %s %s %s %s %s %s %s\n",
400: (fpcr & 0x8000) ? "BS" : "--",
401: (fpcr & 0x4000) ? "SN" : "--",
402: (fpcr & 0x2000) ? "OP" : "--",
403: (fpcr & 0x1000) ? "OV" : "--",
404: (fpcr & 0x0800) ? "UF" : "--",
405: (fpcr & 0x0400) ? "DZ" : "--",
406: (fpcr & 0x0200) ? "I2" : "--",
407: (fpcr & 0x0100) ? "I1" : "--");
408:
409: PUT_FP(2);
410: cons->Print(" RP=%s RM=%s\n",
411: rpstr[(fpcr >> 6) & 3],
412: rmstr[(fpcr >> 4) & 3]);
413:
414: PUT_FP(3);
415: cons->Print("%sFPSR:%08x%s\n", BOLDIF(fpsr != ppsr), fpsr, NORM);
416:
417: PUT_FP(4);
418: uint cc = fpsr >> 24;
419: cons->Print(" %c %c %s %s Q=$%02x\n",
420: (cc & 0x08) ? 'N' : '-',
421: (cc & 0x04) ? 'Z' : '-',
422: (cc & 0x02) ? "Inf" : "---",
423: (cc & 0x01) ? "NAN" : "---",
424: (fpsr >> 16) & 0xff);
425:
426: PUT_FP(5);
427: cons->Print(" %s %s %s %s %s %s %s %s\n",
428: (fpsr & 0x8000) ? "BS" : "--",
429: (fpsr & 0x4000) ? "SN" : "--",
430: (fpsr & 0x2000) ? "OP" : "--",
431: (fpsr & 0x1000) ? "OV" : "--",
432: (fpsr & 0x0800) ? "UF" : "--",
433: (fpsr & 0x0400) ? "DZ" : "--",
434: (fpsr & 0x0200) ? "I2" : "--",
435: (fpsr & 0x0100) ? "I1" : "--");
436:
437: PUT_FP(6);
438: cons->Print(" %s %s %s %s %s\n",
439: (fpsr & 0x80) ? "IOP" : "---",
440: (fpsr & 0x40) ? "OVFL" : "----",
441: (fpsr & 0x20) ? "UNFL" : "----",
442: (fpsr & 0x10) ? "DZ" : "--",
443: (fpsr & 0x08) ? "INEX" : "----");
444:
445: PUT_FP(7);
446: cons->Print("%sFPIAR:%08x%s\n", BOLDIF(fpiar != ppiar), fpiar, NORM);
447: }
448:
449: // MMU レジスタ表示
450: void
451: DebuggerMD_m680x0::ShowRegMMU(Console *cons)
452: {
453: /*
454: SRP:00001111_22223333 TT0:00001111 TC:00001111 (---)
455: CRP:00001111_22223333 TT1:00001111 MMUSR: 0011 (
456: */
457: uint64 srp, osrp;
458: uint64 crp, ocrp;
459: uint32 tt0, ott0;
460: uint32 tt1, ott1;
461: uint32 tc, otc;
462: uint16 sr, osr;
463: bool p;
464: bool t;
465: bool c;
466:
467: srp = cpu->GetSRP();
468: crp = cpu->GetCRP();
469: tt0 = cpu->GetTT(0);
470: tt1 = cpu->GetTT(1);
471: tc = cpu->GetTC();
472: sr = cpu->GetMMUSR();
473:
474: osrp = prev.srp.q;
475: ocrp = prev.crp.q;
476: ott0 = prev.tt[0];
477: ott1 = prev.tt[1];
478: otc = prev.tc;
479: osr = prev.mmusr;
480:
481: // 1行目
482: p = (srp != osrp);
483: t = (tt0 != ott0);
484: c = (tc != otc);
485: cons->Print("%sSRP:%08x_%08x%s %sTT0:%08x%s(%c%c%c)",
486: BOLDIF(p), (uint32)(srp >> 32), (uint32)srp, NORM,
487: BOLDIF(t), tt0, NORM,
488: (tt0 & m68030TT::E) ? 'E' : '-',
489: (tt0 & m68030TT::CI) ? 'C' : '-',
490: (tt0 & m68030TT::RWM) ? '-' : ((tt0 & m68030TT::RW) ? 'R' : 'W'));
491: cons->Print(" %sTC:%08x%s(%c%c%c)\n",
492: BOLDIF(c), tc, NORM,
493: (tc & m68030TC::TC_E) ? 'E' : '-',
494: (tc & m68030TC::TC_SRE) ? 'S' : '-',
495: (tc & m68030TC::TC_FCL) ? 'F' : '-');
496:
497: // 2行目
498: p = (crp != ocrp);
499: t = (tt1 != ott1);
500: c = (sr != osr);
501: cons->Print("%sCRP:%08x_%08x%s %sTT1:%08x%s(%c%c%c)",
502: BOLDIF(p), uint32(crp >> 32), (uint32)crp, NORM,
503: BOLDIF(t), tt1, NORM,
504: (tt1 & m68030TT::E) ? 'E' : '-',
505: (tt1 & m68030TT::CI) ? 'C' : '-',
506: (tt1 & m68030TT::RWM) ? '-' : ((tt1 & m68030TT::RW) ? 'R' : 'W'));
507: cons->Print(" %sMMUSR: %04x%s(%c%c%c%c%c%c%c N=%d)\n",
508: BOLDIF(c), sr, NORM,
509: (sr & m68030MMUSR::B) ? 'B' : '-',
510: (sr & m68030MMUSR::L) ? 'L' : '-',
511: (sr & m68030MMUSR::S) ? 'S' : '-',
512: (sr & m68030MMUSR::W) ? 'W' : '-',
513: (sr & m68030MMUSR::I) ? 'I' : '-',
514: (sr & m68030MMUSR::M) ? 'M' : '-',
515: (sr & m68030MMUSR::T) ? 'T' : '-',
516: (sr & m68030MMUSR::N));
517: }
518:
519: // ATC を表示
520: void
521: DebuggerMD_m680x0::ShowRegATC(Console *cons)
522: {
1.1.1.2 ! root 523: parent->ShowMonitor(*gMPUATC);
1.1 root 524: }
525:
526: // その他のレジスタを表示
527: void
528: DebuggerMD_m680x0::ShowRegOther(Console *cons)
529: {
530: TextScreen s(80, 2);
531:
532: // 0 1 2 3 4 5 6
533: // 012345678901234567890123456789012345678901234567890123456789012345
534: // CACR:01234567 VBR:01234567 USP:01234567
535: // CAAR:01234567 SFC:0 DFC:0 MSP:01234567
536:
537: #define EM(name) ((cpu->reg.name != prev.name) ? TA::Em : TA::Normal)
538: s.Print(0, 0, EM(cacr), "CACR:%08x", cpu->reg.cacr);
539: s.Print(0, 1, EM(caar), "CAAR:%08x", cpu->reg.caar);
540:
541: s.Print(15, 0, EM(vbr), "VBR:%08x", cpu->reg.vbr);
542: s.Print(15, 1, EM(sfc), "SFC:%d", cpu->reg.sfc);
543: s.Print(22, 1, EM(dfc), "DFC:%d", cpu->reg.dfc);
544:
545: // スタック欄はモードによって表示を変える。
546: // ユーザ 割り込み マスタ
547: // 1行目 ISP USP USP
548: // 2行目 MSP MSP ISP
549: if (!cpu->reg.s) {
550: s.Print(29, 0, EM(isp), "ISP:%08x", cpu->reg.isp);
551: } else {
552: s.Print(29, 0, EM(usp), "USP:%08x", cpu->reg.usp);
553: }
554: if (!cpu->reg.m) {
555: s.Print(29, 1, EM(msp), "MSP:%08x", cpu->reg.msp);
556: } else {
557: s.Print(29, 1, EM(isp), "ISP:%08x", cpu->reg.isp);
558: }
559:
1.1.1.2 ! root 560: parent->ShowTextScreen(s);
1.1 root 561: }
562:
563: // 逆アセンブル
564: bool
565: DebuggerMD_m680x0::Disassemble(saddr_t laddr,
566: std::string& mnemonic, std::vector<uint8>& bin)
567: {
568: m680x0disasm dis(this);
569: if (dis.Exec(laddr) == false) {
570: return false;
571: }
572: mnemonic = dis.text;
573: bin = dis.bin;
574: return true;
575: }
576:
577: // 逆アセンブルをフォーマット (オフライン版)
578: std::string
579: DebuggerMD_m680x0::FormatDisasm(const std::string& mnemonic,
580: const std::vector<uint8>& bin)
581: {
582: // 16進ダンプ
583: std::string dumpbuf;
584: for (int i = 0; i < bin.size(); i += 2) {
585: dumpbuf += string_format("%02x%02x ", bin[i], bin[i + 1]);
586: }
587:
588: // ダンプは5ワード分 (越えたら知らん)
589: return string_format("%-25s%s", dumpbuf.c_str(), mnemonic.c_str());
590: }
591:
592: // 逆アセンブルをフォーマット (オンライン版)
593: std::string
594: DebuggerMD_m680x0::FormatDisasmLive(const std::string& mnemonic,
595: const std::vector<uint8>& bin)
596: {
597: // オフライン文字列
598: std::string str = FormatDisasm(mnemonic, bin);
599:
600: // bin は uint8 列だが ir は uint16 列なので変換
601: std::vector<uint16> ir;
602: for (int i = 0; i < bin.size(); i += 2) {
603: ir.push_back((bin[i] << 8) | bin[i + 1]);
604: }
605:
606: // 条件判断をする
607: std::string condstr = CondStr(ir);
608:
609: return str + condstr;
610: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.