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