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