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