|
|
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_m88xx0.h"
10: #include "m88100disasm.h"
1.1.1.2 root 11: #include "m88100acc.h"
1.1 root 12: #include "mystring.h"
13:
14: // newval が oldval から変化していれば太字属性にするマクロ
15: #define TSBOLD(newval, oldval) (((newval) != (oldval)) ? TA::Em : TA::Off)
16:
17: // cpu->name が変化していれば太字属性にするマクロ
18: #define TSBOLDC(name) TSBOLD(cpu->name, prev.name)
19:
20: // name の mask で示される部分が変化していれば太字属性にする
21: #define TSBOLDM(name, mask) TSBOLD((cpu->name & (mask)), (prev.name & (mask)))
22:
1.1.1.2 root 23: // コンストラクタ
24: DebuggerMD_m88xx0::DebuggerMD_m88xx0(Debugger *parent_, m88kcpu *cpu_)
25: : inherited(parent_)
26: {
27: cpu = cpu_;
28:
1.1.1.3 root 29: // 機種依存変数
30: vector_max = 512;
1.1.1.4 ! root 31: inst_bytes = 4;
! 32: inst_bytes_fixed = 4;
1.1.1.3 root 33:
1.1.1.2 root 34: // 奇数にしておくことで初回に必ずアドレス変換を起こさせる。
35: last_lpage[0].addr = 0xffffffff;
36: last_lpage[1].addr = 0xffffffff;
37:
38: cmp_rd = -1;
39: }
40:
41: // デストラクタ
42: DebuggerMD_m88xx0::~DebuggerMD_m88xx0()
43: {
44: }
45:
46: bool
47: DebuggerMD_m88xx0::MMUEnabled() const
48: {
49: // XXX 命令/データの区別がまだないので、とりあえず命令のほうだけ見る
50: uint32 xapr = cpu->cmmu[0].GetAPR(IsSuper() ? 1 : 0);
51: return (xapr & m88200::APR_TE);
52: }
53:
54: // アドレス変換
55: uint64
56: DebuggerMD_m88xx0::TranslateAddr(saddr_t laddr)
57: {
58: uint64 paddr;
59: int isdata;
60: m88200 *cmmu;
61:
62: // XXX とりあえずね
63: isdata = (laddr.data) ? 1 : 0;
64: if (isdata == 0) {
65: cmmu = &cpu->cmmu[0];
66: } else {
67: cmmu = &cpu->cmmu[1];
68: }
69:
70: // ページ境界(と初回)でアドレス変換
71: saddr_t lpage;
72: lpage.addr = laddr.addr & 0xfffff000;
73: lpage.super = laddr.super;
74: if (lpage.GetSaddr() != last_lpage[isdata].GetSaddr()) {
75: last_lpage[isdata] = lpage;
76:
77: bool do_search = laddr.IsSearch();
78: paddr = cmmu->TranslatePeek(laddr.addr, laddr.super, do_search);
79: if ((int64)paddr < 0) {
80: last_lpage[isdata].addr = 0xffffffff;
81: }
82: last_ppage[isdata] = paddr & 0xfffff000;
83: } else {
84: paddr = last_ppage[isdata] | (laddr.addr & 0x00000fff);
85: }
86: return paddr;
87: }
88:
1.1.1.4 ! root 89: // op が bb0 命令なら true を返す
! 90: /*static*/ bool
! 91: DebuggerMD_m88xx0::IsBB0(uint32 op)
! 92: {
! 93: return ((op & 0xf8000000) == 0xd0000000); // bb0
! 94: }
! 95:
! 96: // op が tb0 命令なら true を返す
! 97: /*static*/ bool
! 98: DebuggerMD_m88xx0::IsTB0(uint32 op)
! 99: {
! 100: return ((op & 0xfc00fe00) == 0xf000d000); // tb0
! 101: }
! 102:
1.1.1.2 root 103: // op が bb0/tb0 命令なら true を返す
104: /*static*/ bool
105: DebuggerMD_m88xx0::IsBBTB0(uint32 op)
106: {
1.1.1.4 ! root 107: return IsBB0(op) || IsTB0(op);
1.1.1.2 root 108: }
109:
110: // op が bb1 命令なら true を返す
111: /*static*/ bool
112: DebuggerMD_m88xx0::IsBB1(uint32 op)
113: {
114: return ((op & 0xf8000000) == 0xd8000000); // bb1
115: }
116:
117: // op が tb1 命令なら true を返す
118: /*static*/ bool
119: DebuggerMD_m88xx0::IsTB1(uint32 op)
120: {
121: return ((op & 0xfc00fe00) == 0xf000d800); // tb1
122: }
123:
124: // op が bb1/tb1 命令なら true を返す
125: /*static*/ bool
126: DebuggerMD_m88xx0::IsBBTB1(uint32 op)
127: {
128: return IsBB1(op) || IsTB1(op);
129: }
130:
1.1 root 131: void
132: DebuggerMD_m88xx0::BackupRegs()
133: {
134: prev = (m88100reg)*cpu;
135: }
136:
1.1.1.2 root 137: void
138: DebuggerMD_m88xx0::SetStepOut()
139: {
140: so_r1 = cpu->r[1];
141: }
142:
143: bool
144: DebuggerMD_m88xx0::IsStepOut() const
145: {
146: return (cpu->xip == so_r1);
147: }
148:
1.1.1.4 ! root 149: // この命令がステップイン出来るなら true を返す
! 150: bool
! 151: DebuggerMD_m88xx0::IsOpStepIn(uint32 op)
! 152: {
! 153: if ((op & 0xf800'0000) == 0xc800'0000 // bsr
! 154: || IsTB0(op) // tb0
! 155: || (IsTB1(op) && ((op >> 16) & 0x1f) != 0) // tb1 (except r0)
! 156: || (op & 0xfc00'fe00) == 0xf000'e800 // tcnd
! 157: || (op & 0xfc00'fb00) == 0xf400'c800 // jsr
! 158: || (op & 0xfc00'0000) == 0xf800'0000 // tbnd imm
! 159: || (op & 0xfc00'ffe0) == 0xf400'f800 // tbnd rs2
! 160: ) {
! 161: return true;
! 162: }
! 163:
! 164: return false;
! 165: }
! 166:
1.1 root 167: // レジスタ名からそのレジスタ値を返す。
168: // メモリダンプのような用途なのでアドレスとして使えるアドレスのみ。
169: uint64
170: DebuggerMD_m88xx0::GetRegAddr(const char *name) const
171: {
172: char buf[8];
173:
174: if (strcmp(name, "xip") == 0) return cpu->xip;
175: if (strcmp(name, "nip") == 0) return cpu->nip;
176: if (strcmp(name, "fip") == 0) return cpu->fip;
177:
178: // 制御レジスタ
179: //if (strcmp(name, "pid") == 0) return cpu->pid;
180: //if (strcmp(name, "psr") == 0) return cpu->psr;
181: //if (strcmp(name, "epsr") == 0) return cpu->epsr;
182: //if (strcmp(name, "ssbr") == 0) return cpu->ssbr;
1.1.1.2 root 183: if (strcmp(name, "sxip") == 0) return cpu->sxip & m88100reg::SIP_MASK;
184: if (strcmp(name, "snip") == 0) return cpu->snip & m88100reg::SIP_MASK;
185: if (strcmp(name, "sfip") == 0) return cpu->sfip & m88100reg::SIP_MASK;
1.1 root 186: if (strcmp(name, "vbr") == 0) return cpu->vbr;
187: //if (strcmp(name, "dmt0") == 0) return cpu->dmt0;
188: if (strcmp(name, "dmd0") == 0) return cpu->dmd0;
189: if (strcmp(name, "dma0") == 0) return cpu->dma0;
190: //if (strcmp(name, "dmt1") == 0) return cpu->dmt1;
191: if (strcmp(name, "dmd1") == 0) return cpu->dmd1;
192: if (strcmp(name, "dma1") == 0) return cpu->dma1;
193: //if (strcmp(name, "dmt2") == 0) return cpu->dmt2;
194: if (strcmp(name, "dmd2") == 0) return cpu->dmd2;
195: if (strcmp(name, "dma2") == 0) return cpu->dma2;
196: if (strcmp(name, "sr0") == 0) return cpu->sr[0];
197: if (strcmp(name, "sr1") == 0) return cpu->sr[1];
198: if (strcmp(name, "sr2") == 0) return cpu->sr[2];
199: if (strcmp(name, "sr3") == 0) return cpu->sr[3];
200:
201: for (int i = 0; i < countof(cpu->cr); i++) {
202: snprintf(buf, sizeof(buf), "cr%d", i);
203: if (strcmp(name, buf) == 0) {
204: return cpu->cr[i];
205: }
206: }
207:
208: // FPU レジスタ
209: // XXX not implement
210:
211: // 通常レジスタ
212: for (int i = 0; i < countof(cpu->r); i++) {
213: snprintf(buf, sizeof(buf), "r%d", i);
214: if (strcmp(name, buf) == 0) {
215: return cpu->r[i];
216: }
217: }
218:
219: return (uint64)-1;
220: }
221:
1.1.1.2 root 222: // レジスタ表示系コマンドのヘルプ
223: /*static*/ const HelpMessages
224: DebuggerMD_m88xx0::HelpMsgRegister = {
1.1.1.4 ! root 225: { "r", "Show general registers" },
! 226: { "rc", "Show (integer) control registers" },
! 227: { "rf", "Show floating point control registers" },
! 228: { "ro", "Show other (shadow) registers" },
! 229: { "ra<id>", "Show ATC on CMMU<id>" },
! 230: { "rd<id>", "Show data cache on CMMU<id>" },
! 231: { "rm<id>", "Show CMMU<id> registers" },
1.1.1.2 root 232: };
233:
234: const HelpMessages&
235: DebuggerMD_m88xx0::GetRegisterHelp() const
236: {
237: return HelpMsgRegister;
238: }
239:
240: // レジスタ表示系コマンド
241: bool
242: DebuggerMD_m88xx0::ShowRegister(Console *cons,
243: const std::vector<std::string>& args)
244: {
245: int cmmu_id;
246:
247: // 余分な引数は無視する?
248:
249: if (args[0] == "r") {
250: ShowRegMain(cons);
251: return true;
252: }
253: if (args[0] == "rc") {
254: ShowRegCtrl(cons);
255: return true;
256: }
257: if (args[0] == "rf") {
258: ShowRegFPU(cons);
259: return true;
260: }
261: if (args[0] == "ro") {
262: ShowRegOther(cons);
263: return true;
264: }
265:
266: if (MatchCMMUCmd(args[0], "ra", &cmmu_id)) {
267: parent->ShowMonitor(*gMPU88200ATC[7 - cmmu_id]);
268: return true;
269: }
270: if (MatchCMMUCmd(args[0], "rd", &cmmu_id)) {
271: ShowRegCache(cons, args, cmmu_id);
272: return true;
273: }
274: if (MatchCMMUCmd(args[0], "rm", &cmmu_id)) {
275: ShowRegMMU(cons, cmmu_id);
276: return true;
277: }
278:
279: // 該当なし
280: return false;
281: }
282:
283: // CMMU ID 入りコマンド名を照合する。
284: // cmdname が basename + <id> の時、*idp に id を格納して true を返す。
285: // 一致しないか id が不正なら false を返す。
286: bool
287: DebuggerMD_m88xx0::MatchCMMUCmd(const std::string& cmdname,
288: const char *basename, int *idp)
289: {
290: int baselen = strlen(basename);
291:
292: if (strncmp(cmdname.c_str(), basename, baselen) != 0) {
293: return false;
294: }
295:
296: // 先頭が一致したら id を調べる
297: int id;
298: const char *start = cmdname.c_str() + baselen;
299: char *end;
300: errno = 0;
301: id = strtoul(start, &end, 10);
302: if (*start == '\0' || *end != '\0' || errno == ERANGE) {
303: return false;
304: }
305:
306: *idp = id;
307: return true;
308: }
309:
1.1 root 310: void
311: DebuggerMD_m88xx0::ShowRegMain(Console *cons)
312: {
313: TextScreen s(80, 8);
314:
1.1.1.2 root 315: /*
316: r0 :00000000 r8 :00000000 r16:00000000 r24:00000000 b:bs=1 a:lo=1 8:ls=0
317: r1 :00700000 r9 :00000000 r17:00000000 r25:00000000
318: r2 :0070e1a0 r10:00000000 r18:00000000 r26:00000000
319: */
320:
1.1 root 321: for (int i = 0; i < countof(cpu->r); i++) {
322: s.Print((i / 8) * 14, i % 8, TSBOLDC(r[i]), "r%-2d:%08x", i, cpu->r[i]);
323: }
324:
1.1.1.2 root 325: // cmp 以降最初の分岐命令で結果レジスタの条件ビットマップを表示する。
326: // 分岐命令は bb1 #3 みたいな形式なのでそれだけでは条件演算子が分からない
327: // のと、bb1 #n 自体は cmp 以外に対しても使えるので、cmp 命令以降最初の
328: // 分岐命令でのみ表示してみる。
329: if (cmp_rd >= 0 && (IsBBTB0(cpu->opX) || IsBBTB1(cpu->opX))) {
330: static const char * const cmpstr[] = {
331: NULL, NULL, "eq", "ne", "gt", "le", "lt", "ge",
332: "hi", "ls", "lo", "hs",
333: };
334: int x = 0;
335: int y = 0;
336: uint32 res = cpu->r[cmp_rd];
337: for (int b = 11; b >= 2; b--) {
338: s.Print(57 + x * 7, y, "%x:%s=%d", b, cmpstr[b],
339: (res & (1 << b)) ? 1 : 0);
340: x++;
341: if (x > 2) {
342: x = 0;
343: y++;
344: }
345: }
346: }
347:
348: parent->ShowTextScreen(s);
1.1 root 349: }
350:
351: void
352: DebuggerMD_m88xx0::ShowRegCtrl(Console *cons)
353: {
354: TextScreen s(80, 6);
355: int x;
356: int y;
357:
358: /*
359: 0 1 2 3 4 5 6 7
360: 0123456789012345678901234567890123456789012345678901234567890123456789012345678
1.1.1.4 ! root 361: pid (cr0):12345678(Arch=$00 Ver=$00 M/C=Checker) sr0(cr17):00000000
! 362: psr (cr1):12345678(S,LE,SER,Cy SFD1,MXM,IND,SFRZ) sr1(cr18):00000000
! 363: epsr(cr2):12345678(S,LE,SER,Cy SFD1,MXM,IND,SFRZ) sr2(cr19):00000000
! 364: xip:00000000 opX:00000000(--) sxip(cr4):00000000:VE sr3(cr20):00000000
! 365: nip:00000000 opF:00000000(--) snip(cr5):00000000:-- ssbr(cr3):00000000
! 366: fip:00000000 sfip(cr6):00000000:VE vbr (cr7):00000000
1.1 root 367: */
368:
369: #define PRINT_B(x, y, reg, mask, fmt, arg) do { \
370: uint32 _new = cpu->reg & (mask); \
371: uint32 _old = prev.reg & (mask); \
372: s.Print((x), (y), TSBOLD(_new, _old), fmt, (arg)); \
373: } while (0)
374:
375: // pid(cr0)
376: x = 0;
377: y = 0;
1.1.1.2 root 378: s.Print(x, y, TSBOLDC(pid), "pid (cr0):%08x(", cpu->pid);
379: PRINT_B(x + 19, y, pid, m88100reg::PID_REV_MASK, "Arch=$%02x",
380: (_new >> 8) & 0xff);
381: PRINT_B(x + 28, y, pid, m88100reg::PID_VER_MASK, "Ver=$%02x",
382: (_new >> 1) & 0x7f);
383: PRINT_B(x + 36, y, pid, m88100reg::PID_MASTER, "M/C=%s)",
384: (_new & m88100reg::PID_MASTER) ? "Master" : "Checker");
1.1 root 385:
386: // psr(cr1)
387: y++;
388: s.Print(x, y, TSBOLDC(psr), "psr (cr1):%08x", cpu->psr);
389: s.Print(x + 18, y, "(s,le,ser,cy sfd1,mxm,ind,sfrz)");
390: PRINT_B(x + 19, y, psr, m88100reg::PSR_SUPER, "%c", _new ? 'S' : '-');
391: PRINT_B(x + 21, y, psr, m88100reg::PSR_BO_LE, "%s", _new ? "LE" : "BE");
392: PRINT_B(x + 24, y, psr, m88100reg::PSR_SER, "%s", _new ? "CON" : "SER");
393: PRINT_B(x + 28, y, psr, m88100reg::PSR_C, "%s", _new ? "Cy" : "--");
394: PRINT_B(x + 31, y, psr, m88100reg::PSR_SFD1, "%s", _new ? "SFD1" : "----");
395: PRINT_B(x + 36, y, psr, m88100reg::PSR_MXM, "%s", _new ? "MXM" : "---");
396: PRINT_B(x + 40, y, psr, m88100reg::PSR_IND, "%s", _new ? "IND" : "---");
397: PRINT_B(x + 44, y, psr, m88100reg::PSR_SFRZ, "%s", _new ? "SFRZ" : "----");
398:
399: // epsr(cr2)
400: y++;
1.1.1.4 ! root 401: s.Print(x, y, TSBOLDC(epsr), "epsr(cr2):%08x", cpu->epsr);
1.1 root 402: s.Print(x + 18, y, "(s,le,ser,cy sfd1,mxm,ind,sfrz)");
403: PRINT_B(x + 19, y, epsr, m88100reg::PSR_SUPER, "%c", _new ? 'S' : '-');
404: PRINT_B(x + 21, y, epsr, m88100reg::PSR_BO_LE, "%s", _new ? "LE" : "BE");
405: PRINT_B(x + 24, y, epsr, m88100reg::PSR_SER, "%s", _new ? "CON" : "SER");
406: PRINT_B(x + 28, y, epsr, m88100reg::PSR_C, "%s", _new ? "Cy" : "--");
407: PRINT_B(x + 31, y, epsr, m88100reg::PSR_SFD1, "%s", _new ? "SFD1":"----");
408: PRINT_B(x + 36, y, epsr, m88100reg::PSR_MXM, "%s", _new ? "MXM" : "---");
409: PRINT_B(x + 40, y, epsr, m88100reg::PSR_IND, "%s", _new ? "IND" : "---");
410: PRINT_B(x + 44, y, epsr, m88100reg::PSR_SFRZ, "%s", _new ? "SFRZ":"----");
411:
412: // *IP
413: x = 0;
414: y = 3;
415: s.Print(x, y, "xip:%08x opX:%08x(%c%c)",
416: cpu->xip, (uint32)cpu->opX,
417: cpu->OpIsBusErr(cpu->opX) ? 'B' : '-',
418: cpu->OpIsDelay(cpu->opX) ? 'D' : '-');
419: s.Print(x, y + 1, "nip:%08x opF:%08x(%c%c)",
420: cpu->nip, (uint32)cpu->opF,
421: cpu->OpIsBusErr(cpu->opF) ? 'B' : '-',
422: cpu->OpIsDelay(cpu->opX) ? 'D' : '-');
423: s.Print(x, y + 2, "fip:%08x", cpu->fip);
424:
425: // S*IP
426: x = 32;
427: for (int i = 0; i < 3; i++) {
428: s.Print(x, y + i, TSBOLDC(cr[4 + i]), "%s(cr%d):%08x:%c%c",
429: m88100reg::sipname[i], 4 + i,
430: (cpu->cr[4 + i] & m88100reg::SIP_MASK),
431: (cpu->cr[4 + i] & m88100reg::SIP_V) ? 'V' : '-',
432: (cpu->cr[4 + i] & m88100reg::SIP_E) ? 'E' : '-');
433: }
434:
435: x = 55;
436: y = 0;
437: // SR*
438: for (int i = 0; i < 4; i++) {
439: int rn = 17 + i;
1.1.1.4 ! root 440: s.Print(x, y++, TSBOLDC(cr[rn]), "sr%d(cr%d):%08x",
1.1 root 441: i, rn, cpu->cr[rn]);
442: }
1.1.1.4 ! root 443: // ssbr(cr3)
! 444: s.Print(x, y++, TSBOLDC(ssbr), "ssbr(cr3):%08x", cpu->ssbr);
! 445: // vbr(cr7)
! 446: s.Print(x, y++, TSBOLDC(vbr), "vbr (cr7):%08x", cpu->vbr);
1.1 root 447:
1.1.1.2 root 448: parent->ShowTextScreen(s);
449: }
450:
451: // CMMU のデータキャッシュを表示
452: // rd<N> なら概要表示。
453: // rd<N> <set> なら個別セットの詳細表示。
454: void
455: DebuggerMD_m88xx0::ShowRegCache(Console *cons,
456: const std::vector<std::string>& args, int id)
457: {
458: if (args.size() < 2) {
459: ShowRegCacheOverview(cons, id);
460: } else {
461: int set;
462: char *end;
463: errno = 0;
464: set = strtol(args[1].c_str(), &end, 16);
465: if (end == &args[1][0] || *end != '\0' || errno == ERANGE) {
466: cons->Print("<set> must be a number\n");
467: return;
468: }
469: if (set < 0 || set > 256) {
470: cons->Print("<set> must be in 00..ff\n");
471: return;
472: }
473: ShowRegCacheSet(cons, id, set);
474: }
475: }
476:
477: // CMMU データキャッシュの概要表示
478: void
479: DebuggerMD_m88xx0::ShowRegCacheOverview(Console *cons, int id)
480: {
481: TextScreen s(70, 17);
482: m88200 *cmmu;
483:
484: // まだ今の所決め打ち
485: if (id == 7) {
486: cmmu = &cpu->cmmu[0];
487: } else {
488: cmmu = &cpu->cmmu[1];
489: }
490: cmmu->MonitorCacheOverview(s, 0, false);
491: parent->ShowTextScreen(s);
492: }
493:
494: // CMMU データキャッシュの指定セットの詳細表示
495: void
496: DebuggerMD_m88xx0::ShowRegCacheSet(Console *cons, int id, int setidx)
497: {
498: TextScreen s(70, 5);
499: m88200 *cmmu;
500:
501: // まだ今の所決め打ち
502: if (id == 7) {
503: cmmu = &cpu->cmmu[0];
504: } else {
505: cmmu = &cpu->cmmu[1];
506: }
507: cmmu->MonitorCacheSet(s, 0, setidx);
508: parent->ShowTextScreen(s);
1.1 root 509: }
510:
511: void
512: DebuggerMD_m88xx0::ShowRegFPU(Console *cons)
513: {
514: static const char * const fcrname[] = {
515: "fpecr",
516: "fphs1",
517: "fpls1",
518: "fphs2",
519: "fpls2",
520: "fppt",
521: "fprh",
522: "fprl",
523: "fpit",
524: "fpsr", // [9] 62
525: "fpcr", // [10] 63
526: };
527: TextScreen s(80, 4);
528:
529: for (int i = 0; i < 9; i++) {
530: s.Print((i / 4) * 22, i % 4, TSBOLDC(fcr[i]),
531: "%-5s(fcr%d):%08x", fcrname[i], i, cpu->fcr[i]);
532: }
533:
534: s.Print(44, 2, TSBOLDC(fpsr), "fpsr(fcr62):%08x", cpu->fpsr);
535: s.Print(44, 3, TSBOLDC(fpcr), "fpcr(fcr63):%08x", cpu->fpcr);
536:
1.1.1.2 root 537: parent->ShowTextScreen(s);
1.1 root 538: }
539:
540: void
1.1.1.2 root 541: DebuggerMD_m88xx0::ShowRegMMU(Console *cons, int id)
542: {
543: m88200 *cmmu;
544:
545: // まだ今の所決め打ち
546: if (id == 7) {
547: cmmu = &cpu->cmmu[0];
548: } else {
549: cmmu = &cpu->cmmu[1];
550: }
551: parent->ShowMonitor(*cmmu);
552: }
553:
554: void
555: DebuggerMD_m88xx0::ShowRegOther(Console *cons)
1.1 root 556: {
557: TextScreen s(80, 3);
558: /*
559: 0 1 2 3 4 5 6 7
560: 0123456789012345678901234567890123456789012345678901234567890123456789012345678
1.1.1.2 root 561: dmt0(cr8) :0000(B,S,D,L,Rxx,S,---B,W,V) dmd0(cr9) :00000000 dma0(cr10):00000000
562: dmt0(cr11):0000(B,U,D,L,Rxx,S,HH--,W,V) dmd0(cr9) :00000000 dma0(cr10):00000000
563: dmt0(cr14):0000(B, ,D,L,Rxx,S,LLLL,W,V) dmd0(cr9) :00000000 dma0(cr10):00000000
1.1 root 564: */
565: for (int i = 0; i <= 2; i++) {
566: int dt = 8 + i * 3;
567: int dd = 9 + i * 3;
568: int da = 10 + i * 3;
569:
570: s.Print(0, i, TSBOLDC(cr[dt]), "dmt%d(cr%-2d):%04x",
571: i, dt, (cpu->cr[dt] & 0xffff));
1.1.1.2 root 572: s.Print(15, i, "(b,s,d,l,rx, s,en ,w,v)");
1.1 root 573: PRINT_B(16, i, cr[dt], m88100reg::DM_BO, "%c", _new ? 'B' : '-');
1.1.1.2 root 574: PRINT_B(18, i, cr[dt], m88100reg::DM_DAS, "%c", _new ? 'S' : 'U');
575: PRINT_B(20, i, cr[dt], m88100reg::DM_DOUB1, "%c", _new ? 'D' : '-');
576: PRINT_B(22, i, cr[dt], m88100reg::DM_LOCK, "%c", _new ? 'L' : '-');
577: // カンマを前詰め。かつ DREG がボールドでもカンマはボールドにしない
578: PRINT_B(24, i, cr[dt], m88100reg::DM_DREG_MASK, "r%d", _new >> 7);
579: s.Puts(",");
580: PRINT_B(28, i, cr[dt], m88100reg::DM_SIGNED, "%c", _new ? 'S' : '-');
581: PRINT_B(30, i, cr[dt], m88100reg::DM_EN_MASK,"%s",
582: m88100reg::dmt_en_str[(_new >> 2) & 0xf]);
583: PRINT_B(35, i, cr[dt], m88100reg::DM_WRITE, "%c", _new ? 'W' : '-');
584: PRINT_B(37, i, cr[dt], m88100reg::DM_VALID, "%c", _new ? 'V' : '-');
1.1 root 585:
1.1.1.2 root 586: s.Print(40, i, TSBOLDC(cr[dd]), "dmd%d(cr%-2d):%08x",
1.1 root 587: i, dd, cpu->cr[dd]);
1.1.1.2 root 588: s.Print(60, i, TSBOLDC(cr[dd]), "dma%d(cr%2d):%08x",
1.1 root 589: i, da, cpu->cr[da]);
590: }
591:
1.1.1.2 root 592: parent->ShowTextScreen(s);
1.1 root 593: }
594:
595: // 逆アセンブル
596: bool
597: DebuggerMD_m88xx0::Disassemble(saddr_t laddr,
598: std::string& mnemonic, std::vector<uint8>& bin)
599: {
600: m88100disasm dis(this);
601: if (dis.Exec(laddr) == false) {
602: return false;
603: }
604: mnemonic = dis.text;
605: bin = dis.bin;
606: return true;
607: }
608:
609: // 逆アセンブルをフォーマット (オフライン版)
610: std::string
611: DebuggerMD_m88xx0::FormatDisasm(const std::string& mnemonic,
612: const std::vector<uint8>& bin)
613: {
614: // 命令はすべて32ビット固定長
615: uint32 op = (bin[0] << 24) | (bin[1] << 16) | (bin[2] << 8) | bin[3];
616: return string_format("%08x %s", op, mnemonic.c_str());
617: }
618:
619: // 逆アセンブルをフォーマット (オンライン版)
620: std::string
621: DebuggerMD_m88xx0::FormatDisasmLive(const std::string& mnemonic,
622: const std::vector<uint8>& bin)
623: {
624: // 命令はすべて32ビット固定長
625: uint32 op = (bin[0] << 24) | (bin[1] << 16) | (bin[2] << 8) | bin[3];
626:
627: // 遅延スロットは分かりやすく表示したい
628: std::string delay;
629: if (cpu->OpIsDelay(cpu->opX)) {
630: delay = "(delayed) ";
631: }
632:
1.1.1.2 root 633: const char *cond = CondStr(op);
634: return string_format("%08x %s%s%s",
635: op, delay.c_str(), mnemonic.c_str(), cond);
636: }
637:
1.1.1.4 ! root 638: // 例外のベクタ番号から名前を取得。
! 639: const char *
! 640: DebuggerMD_m88xx0::GetExceptionName(int vector) const
! 641: {
! 642: return m88kcpu::GetExceptionName(vector);
! 643: }
! 644:
1.1.1.2 root 645: #define TAKE_IF(expr) do { \
646: if ((expr)) \
647: return " (will take)"; \
648: else \
649: return " (will not take)"; \
650: } while (0)
651:
652: // 条件命令なら、成立可否などの文字列を返す。
653: const char *
654: DebuggerMD_m88xx0::CondStr(uint32 op)
655: {
656: uint32 s = m88100opf_S1(op);
657:
658: if (IsBBTB0(op)) {
659: // 11010N BBBBB SSSSS dddddd dd dddddddd bb0
660: // 111100 BBBBB SSSSS 110100 0V VVVVVVVV tb0
661: // rS の bit B が %0 ならブランチ/トラップ
662: cmp_rd = -1;
663: uint32 b = m88100opf_B5(op);
664: TAKE_IF((cpu->r[s] & (1 << b)) == 0);
665: }
666: if (IsBB1(op)) {
667: // 11011N BBBBB SSSSS dddddd dd dddddddd bb1
668: // rS の bit B が %1 ならブランチ
669: cmp_rd = -1;
670: // 対 r0 なら絶対成立しないので nop
671: if (s == 0) {
672: return " (nop)";
673: }
674: uint32 b = m88100opf_B5(op);
675: TAKE_IF((cpu->r[s] & (1 << b)) != 0);
676: }
677: if (IsTB1(op)) {
678: // 111100 BBBBB SSSSS 110110 0V VVVVVVVV tb1
679: // rS の bit B が %1 ならトラップ
680: cmp_rd = -1;
681: // 対 r0 なら sync として使っており逆アセンブラ側で表示を加工してある
682: // のでこちら側では対処不要。
683: if (s == 0) {
684: return "";
685: }
686: uint32 b = m88100opf_B5(op);
687: TAKE_IF((cpu->r[s] & (1 << b)) != 0);
688: }
689: if ((op & 0xf8000000) == 0xe8000000 || // bcnd
690: (op & 0xfc00fe00) == 0xf000e800) // tcnd
691: {
692: // 11101N MMMMM SSSSS dddddd dd dddddddd bcnd
693: // rS が M5 で示される条件にマッチすればブランチ/トラップ
694: cmp_rd = -1;
695: uint32 m5 = m88100opf_M5(op);
696: TAKE_IF(
697: (m5 == 0x2 && cpu->r[s] == 0) || // eq0
698: (m5 == 0xd && cpu->r[s] != 0) || // ne0
699: (m5 == 0x1 && (int32)cpu->r[s] > 0) || // gt0
700: (m5 == 0xc && (int32)cpu->r[s] < 0) || // lt0
701: (m5 == 0x3 && (int32)cpu->r[s] >= 0) || // ge0
702: (m5 == 0xe && (int32)cpu->r[s] <= 0) // le0
703: );
704: }
705:
706: if ((op & 0xfc00fce0) == 0xf4007c00 || // cmp rD,rS1,rS2
707: (op & 0xfc000000) == 0x7c000000 ) // cmp rD,rS1,imm16
708: {
709: // 次の条件分岐命令で結果レジスタを表示するため、rD だけ覚えておく
710: cmp_rd = m88100opf_D(op);
711: }
712:
713: return "";
1.1 root 714: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.