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