|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2019 [email protected]
4: //
5:
6: #include "header.h"
7: #include "bus.h"
8: #include "consio.h"
9: #include "cvprompt.h"
10: #include "disasm.h"
11: #include "m68030core.h"
12: #include "memdump.h"
13: #include "mpu.h"
14: #include "mystring.h"
15: #include <csignal>
16:
17: class Debugger
18: {
19: private:
20: // 型
21: typedef void (Debugger::*cmdfunc_t)();
22: typedef struct {
23: const char *name;
24: cmdfunc_t func;
25: } cmddef_t;
26:
27: // ブレークポイント
28: typedef struct {
29: bool enable;
30: bool ismemory;
31: uint32 addr;
32: uint32 count;
33: } breakpoint_t;
34: static const int MAX_BREAKPOINTS = 8;
35:
36: public:
37: Debugger();
38: virtual ~Debugger() { }
39:
40: void Init();
41: void ThreadRun();
42: bool Check();
43:
44: private:
45: bool MainLoop();
46: cmddef_t *ParseCmd();
47: // コマンド名は大文字小文字を区別する関係でスネークスタイル。
48: void cmd_b();
49: void cmd_b_list();
50: void cmd_brhist();
51: void cmd_bx();
52: void cmd_c();
53: void cmd_d();
54: void cmd_dt();
55: void cmd_D();
56: void cmd_h();
57: void cmd_L();
58: void cmd_m();
59: void cmd_mt();
60: void cmd_M();
61: void cmd_minus();
62: void cmd_n();
63: void cmd_q();
64: void cmd_r();
65: void cmd_ra();
66: void cmd_rf();
67: void cmd_rm();
68: void cmd_ro();
69: void cmd_s();
70: void cmd_so();
71: void cmd_show();
72: void cmd_t();
73: void cmd_unknown();
74:
75: int AddBreakpoint(uint32 addr, bool ismemory);
76: void Continue();
77: bool GetAddr(uint32& addr, uint32& lastaddr);
78: void cmd_d_common(MemdumpMode mode);
79: void cmd_m_common(MemdumpMode mode);
80: bool ParseAddr(const char *arg, uint32_t *addrp);
81: const char *OPccCondStr(uint32);
82: bool IsOPcc(uint16);
83: bool IsDBcc(uint16);
84: bool IsCond(uint16);
85: bool SetNBreakpoint();
86:
87: void HelpMain();
88:
89: void ShowRegMain();
90: void ShowRegFPU();
91: void ShowRegMMU();
92: void ShowRegOther();
93: void ShowMonitor(TextScreen& monitor);
94:
95: m68kcpu *cpu = NULL; // CPU コア
96: m68kreg prev {}; // 前回のレジスタセットのコピー
97:
98: Consio *cons = NULL; // 入出力
99: char cmdbuf[256] {}; // 現在のコマンドライン
100: char last_cmdbuf[256] {}; // 直前のコマンドライン
101: int ac = 0;
102: char *av[10] {};
103:
104: uint32 pc = 0;
105: uint32 nextpc = 0;
106: breakpoint_t bpoint[MAX_BREAKPOINTS] {};
107: bool bc_enable = false;
108: uint32 bc_addr = 0;
109: uint32 d_last_addr = 0;
110: uint32 m_last_addr = 0;
111: bool n_enable = false;
112: bool n_breakenable = false;
113: uint32 n_breakaddr = 0;
114: uint32 n_count = 0;
115: bool s_enable = false;
116: uint32 s_count = 0;
117: bool so_enable = false;
118: uint32 so_a7 = 0;
119: uint16 so_sr = 0;
120: bool t_enable = false;
121: uint32 t_count = 0;
122:
123: // 一度VMを実行して再びプロンプトに来たら true
124: bool is_continued = false;
125:
126: static cmddef_t cmdtable[];
127: static cmddef_t cmdtable_unknown;
128: };
129:
130: Debugger *gDebugger;
131: CVPrompt *gCVPrompt;
132:
133: // コマンドラインオプション
134: bool debug_on_start;
135: uint32 debug_breakaddr;
136:
137: static void *debugger_run(void *);
138:
139: // 初期化。
140: // この時点で VM が初期化されていること。
141: void
142: debugger_init()
143: {
144: gDebugger = new Debugger();
145: gDebugger->Init();
146:
147: gCVPrompt = new CVPrompt();
148:
149: // デバッガスレッド起動
150: pthread_t th;
151: pthread_create(&th, NULL, debugger_run, NULL);
152: }
153:
154: // デバッガスレッドのエントリポイント
155: static void *
156: debugger_run(void *dummy)
157: {
158: pthread_setname_np("Debugger");
159: pthread_detach(pthread_self());
160:
161: gDebugger->ThreadRun();
162: return NULL;
163: }
164:
165: // コンストラクタ
166: Debugger::Debugger()
167: {
168: cpu = gMPU->GetCPU();
169: }
170:
171: // コマンドライン引数によって動作を決めるところ。
172: // 名前がこれでいいのかはあるけど。
173: void
174: Debugger::Init()
175: {
176: // -d なら CPU 起動時点で停止してプロンプトを待つ
177: if (debug_on_start) {
178: cpu->atomic_reqflag |= CPU_REQ_PROMPT;
179: }
180:
181: // -b <addr> ならブレークポイント設定
182: if (debug_breakaddr != 0xffffffff) {
183: cpu->atomic_reqflag |= CPU_REQ_TRACE;
184: AddBreakpoint(debug_breakaddr, false);
185: }
186:
187: // どこでやるべか
188: signal(SIGPIPE, SIG_IGN);
189: }
190:
191: // デバッガスレッド
192: void
193: Debugger::ThreadRun()
194: {
195: // XXX どこかでコンソールの選択とパラメータの取得
196: cons = new ConsioTCP();
197: if (cons->Init() == false) {
198: return;
199: }
200:
201: for (;;) {
202: cons->Open();
203: cons->Print("This is debugger console\n");
204:
205: // 接続ごとに初期化する値
206: // XXX もうちょっときれいにしたい
207: d_last_addr = 0xffffffff;
208: m_last_addr = 0xffffffff;
209: n_enable = false;
210: s_enable = false;
211: t_enable = false;
212: is_continued = true;
213:
214: // コンソールが繋がっている間がトレースオン
215: // コンソールが繋がるとプロンプトになる
216: cpu->atomic_reqflag |= CPU_REQ_TRACE | CPU_REQ_PROMPT;
217: while (MainLoop() == true)
218: ;
219: // コンソールを抜ける時はCPUの停止を解除。
220: cpu->atomic_reqflag &= ~CPU_REQ_TRACE;
221: gCVPrompt->NotifyRelease();
222:
223: cons->Close();
224: }
225:
226: delete cons;
227: }
228:
229: // プロンプト処理のメイン部分。
230: // false を返すとコンソールをクローズする。
231: bool
232: Debugger::MainLoop()
233: {
234: // プロンプトが取れるのを待つ
235: gCVPrompt->WaitAcquire(cons);
236:
237: // VM 実行からプロンプトに来たとき
238: if (is_continued) {
239: is_continued = false;
240:
241: pc = RegPC;
242: d_last_addr = pc;
243: // プロンプトに来た時に表示するいつものやつ
244: cmd_minus();
245: }
246:
247: cons->Print("> ");
248: cons->Flush();
249: if (cons->Gets(cmdbuf, sizeof(cmdbuf)) < 1) {
250: return false;
251: }
252:
253: // chomp
254: for (int i = 0; cmdbuf[i] != '\0'; i++) {
255: if (cmdbuf[i] == '\r' || cmdbuf[i] == '\n') {
256: cmdbuf[i] = '\0';
257: break;
258: }
259: }
260:
261: if (cmdbuf[0] != '\0') {
262: // コマンドが入力されれば次回のために保存
263: strcpy(last_cmdbuf, cmdbuf);
264: } else {
265: // 空行が入力されれば直前のコマンドをもう一度
266: // 前行がなければ何もせずもう一度プロンプトを表示するかね
267: if (last_cmdbuf[0] == '\0')
268: return true;
269: strcpy(cmdbuf, last_cmdbuf);
270: }
271:
272: // 行を cmd, ac, av に分解
273: cmddef_t *cmd = ParseCmd();
274: if (cmd == NULL) {
275: // NULL は知らないコマンドではなく終了コマンド
276: return false;
277: }
278:
279: // 前回の値が有効なのはコマンドが連続した時だけ
280:
281: // コマンド実行
282: (this->*(cmd->func))();
283: return true;
284: }
285:
286: // ブレークポイントとかを調べる。
287: // CPU_REQ_TRACE フラグが立っている間1命令ごとに呼び出される。
288: bool
289: debugger_check()
290: {
291: return gDebugger->Check();
292: }
293:
294: // デバッガ実行中なら命令開始前にメインルーチンから呼ばれる。
295: // プロンプトに降りるなら true を返す。
296: bool
297: Debugger::Check()
298: {
299: if (t_enable) {
300: t_count--;
301: if (t_count == 0) {
302: t_enable = false;
303: return true;
304: }
305: }
306:
307: if (s_enable) {
308: s_count--;
309: if (s_count == 0) {
310: s_enable = false;
311: return true;
312: }
313: }
314:
315: // n による1命令実行のブレークポイントか
316: if (n_enable && n_breakenable && n_breakaddr == RegPC) {
317: n_breakenable = false;
318: return true;
319: }
320:
321: // アドレス
322: for (int i = 0; i < countof(bpoint); i++) {
323: breakpoint_t *bp = &bpoint[i];
324: if (bp->enable) {
325: if (bp->addr == RegPC) {
326: bp->count++;
327: return true;
328: }
329: }
330: }
331:
332: // ステップアウト
333: if (so_enable) {
334: if (RegA(7) > so_a7 || (RegSR & 0x3000) != so_sr) {
335: so_enable = false;
336: return true;
337: }
338: }
339:
340: // アドレス指定付き continue
341: if (bc_enable) {
342: if (bc_addr == RegPC) {
343: bc_enable = false;
344: return true;
345: }
346: }
347:
348: return false;
349: }
350:
351: // コマンド一覧。
352: // quit コマンドは ParseCmd() 側で処理してある。
353: Debugger::cmddef_t Debugger::cmdtable[] = {
354: { "bx", &Debugger::cmd_bx, },
355: { "b", &Debugger::cmd_b, },
356: { "brhist", &Debugger::cmd_brhist },
357: { "c", &Debugger::cmd_c, },
358: { "d", &Debugger::cmd_d, },
359: { "dt", &Debugger::cmd_dt, },
360: { "D", &Debugger::cmd_D, },
361: { "h", &Debugger::cmd_h, },
362: { "L", &Debugger::cmd_L, },
363: { "m", &Debugger::cmd_m, },
364: { "mt", &Debugger::cmd_mt, },
365: { "M", &Debugger::cmd_M, },
366: { "n", &Debugger::cmd_n, },
367: { "r", &Debugger::cmd_r, },
368: { "ra", &Debugger::cmd_ra, },
369: { "rf", &Debugger::cmd_rf, },
370: { "rm", &Debugger::cmd_rm, },
371: { "ro", &Debugger::cmd_ro, },
372: { "s", &Debugger::cmd_s, },
373: { "so", &Debugger::cmd_so, },
374: { "show", &Debugger::cmd_show, },
375: { "t", &Debugger::cmd_t, },
376: { "-", &Debugger::cmd_minus },
377: };
378: Debugger::cmddef_t Debugger::cmdtable_unknown = {
379: .name = "",
380: .func = &Debugger::cmd_unknown,
381: };
382:
383: // ヘルプ
384: void
385: Debugger::cmd_h()
386: {
387: if (ac == 1) {
388: // 引数なし
389: HelpMain();
390: return;
391: } else {
392: // 引数あり(今の所対応していない)
393: HelpMain();
394: return;
395: }
396: }
397:
398: void
399: Debugger::HelpMain()
400: {
401: cons->Print(" b ブレークポイント一覧表示\n");
402: cons->Print(" b #n ブレークポイント n を削除\n");
403: cons->Print(" b $<addr> メモリブレークポイント設定\n");
404: cons->Print(" b <addr> ブレークポイント設定\n");
405: cons->Print(" bx ブレークポイント全削除\n");
406: cons->Print(" brhist ブランチ履歴表示\n");
407: cons->Print(" c [<addr>] 実行再開(continue)\n");
408: cons->Print(" d [<addr> [<lines>] 逆アセンブル(論理、テーブルサーチなし)\n");
409: cons->Print(" dt [<addr> [<lines>] 逆アセンブル(論理、テーブルサーチあり)\n");
410: cons->Print(" D [<addr> [<lines>] 逆アセンブル(物理)\n");
411: cons->Print(" h ヘルプ(help)\n");
412: cons->Print(" L <name>=<lv> ログレベル設定\n");
413: cons->Print(" m [<addr> [<lines>] メモリダンプ(論理、テーブルサーチなし)\n");
414: cons->Print(" mt [<addr> [<lines>] メモリダンプ(論理、テーブルサーチあり)\n");
415: cons->Print(" M [<addr> [<lines>] メモリダンプ(物理)\n");
416: cons->Print(" n <cnt?:1> ステップ実行 (サブルーチンを飛ばす)\n");
417: cons->Print(" q quit\n");
418: cons->Print(" r [a|f|m|o] レジスタ表示\n");
419: cons->Print(" so ステップアウト\n");
420: cons->Print(" show <monitor> モニター表示\n");
421: cons->Print(" t <cnt?:1> トレース実行\n");
422: }
423:
424: // 知らないコマンドを処理するというコマンド
425: void
426: Debugger::cmd_unknown()
427: {
428: cons->Print("%s: unknown command\n", av[0]);
429: }
430:
431: // cmdbuf を cmd, ac, av に分解する。
432: // cmdbuf は破壊されるので以後は cmd, ac, av で参照のこと。
433: // コマンド(の1ワード目)が一致しなければ cmd_unknown を返し、
434: // 終了コマンドと一致したら NULL を返す。
435: Debugger::cmddef_t *
436: Debugger::ParseCmd()
437: {
438: char *p;
439: cmddef_t *cmd;
440:
441: p = cmdbuf;
442: ac = 0;
443: memset(&av, 0, sizeof(av));
444:
445: // 引数を空白で分解
446: for (; ac < countof(av); ) {
447: // 先頭の空白は取り除く
448: while (isspace((int)*p))
449: p++;
450: if (*p == '\0')
451: break;
452:
453: av[ac++] = p;
454: // 次の空白まで進める
455: for (; *p != '\0'; p++) {
456: if (isspace((int)*p))
457: break;
458: }
459: if (*p != '\0')
460: *p++ = '\0';
461: }
462:
463: // コマンドを探す
464: for (int i = 0; i < countof(cmdtable); i++) {
465: cmd = &cmdtable[i];
466:
467: // デバッガから抜ける(終了する)コマンドだけここで処理
468: if (strcmp(av[0], "q") == 0 || strcmp(av[0], "quit") == 0)
469: return NULL;
470:
471: if (strcmp(av[0], cmd->name) == 0)
472: return cmd;
473: }
474:
475: // 見つからなければ cmd_unknown コマンドを実行。
476: return &cmdtable_unknown;
477: }
478:
479: //
480: // デバッガコマンド
481: //
482:
483: // ブレークポイント
484: void
485: Debugger::cmd_b()
486: {
487: // 引数なしなら一覧表示
488: if (ac < 2) {
489: return cmd_b_list();
490: }
491:
492: // 引数取得
493: if (av[1][0] == '#') {
494: // #<n> 形式なら、指定番号のブレークポイントを削除
495: int i = atoi(&av[1][1]);
496: if (i < 0 || i >= MAX_BREAKPOINTS) {
497: cons->Print("invaild break point number: #%d\n", i);
498: return;
499: }
500: breakpoint_t *bp = &bpoint[i];
501: if (bp->enable) {
502: cons->Print("%sbreakpoint #%d (%08x) removed\n",
503: bp->ismemory ? "memory " : "", i, bp->addr);
504: bp->enable = false;
505: } else {
506: cons->Print("breakpoint #%d not enabled\n", i);
507: }
508: return;
509: }
510:
511: bool ismemory;
512: uint32 addr;
513: if (av[1][0] == '$') {
514: // $<n> 形式ならメモリブレークポイント
515: ismemory = true;
516: addr = strtoul(&av[1][1], NULL, 16);
517: } else {
518: // そうでなければアドレス指定
519: ismemory = false;
520: addr = strtoul(av[1], NULL, 16);
521: }
522:
523: // すでにあればそのブレークポイントを削除
524: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
525: breakpoint_t *bp = &bpoint[i];
526: if (bp->enable && bp->ismemory == ismemory && bp->addr == addr) {
527: bp->enable = false;
528: cons->Print("%sbreakpoint #%d (%08x) removed\n",
529: bp->ismemory ? "memory " : "", i, bp->addr);
530: return;
531: }
532: }
533:
534: // 空いてるところにセット
535: int bi = AddBreakpoint(addr, ismemory);
536: if (bi == -1) {
537: cons->Print("no free breakpoints!\n");
538: } else {
539: breakpoint_t *bp = &bpoint[bi];
540: cons->Print("%sbreakpoint #%d (%08x) added\n",
541: bp->ismemory ? "memory " : "", bi, bp->addr);
542: }
543: }
544:
545: // ブレークポイント一覧表示
546: void
547: Debugger::cmd_b_list()
548: {
549: int found = 0;
550:
551: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
552: breakpoint_t *bp = &bpoint[i];
553: if (bp->enable) {
554: cons->Print(" #%d %s%08x %d\n",
555: i,
556: bp->ismemory ? "memory $" : "",
557: bp->addr, bp->count);
558: found = 1;
559: }
560: }
561: if (found == 0) {
562: cons->Print(" No breakpoints enabled\n");
563: }
564: }
565:
566: // ブレークポイント全削除
567: void
568: Debugger::cmd_bx()
569: {
570: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
571: breakpoint_t *bp = &bpoint[i];
572: bp->enable = false;
573: }
574: cons->Print(" All breakpoints disabled\n");
575: }
576:
577: // ブレークポイントを設定。
578: // 設定できればその番号、できなければ -1 を返す
579: // TODO 重複の処理とか
580: int
581: Debugger::AddBreakpoint(uint32 addr, bool ismemory)
582: {
583: for (int i = 0; i < countof(bpoint); i++) {
584: breakpoint_t *bp = &bpoint[i];
585: if (!bp->enable) {
586: bp->enable = true;
587: bp->addr = addr;
588: bp->ismemory = ismemory;
589: bp->count = 0;
590: return i;
591: }
592: }
593: return -1;
594: }
595:
596: // ブランチ履歴表示
597: void
598: Debugger::cmd_brhist()
599: {
600: gMPUBrHist->MonitorUpdate();
601: ShowMonitor(gMPUBrHist->monitor);
602: }
603:
604: // 実行再開(continue): c [<addr>]
605: // <addr> 指定があれば <addr> まで実行。
606: void
607: Debugger::cmd_c()
608: {
609: if (ac > 1) {
610: // 引数があれば
611: if (!ParseAddr(av[1], &bc_addr)) {
612: return;
613: }
614: // 偶数番地に丸める
615: bc_addr &= 0xfffffffe;
616:
617: bc_enable = true;
618: }
619: Continue();
620: }
621:
622: // 実行再開
623: void
624: Debugger::Continue()
625: {
626: is_continued = true;
627:
628: // 今のレジスタセットを次回との差分のためにバックアップしておく
629: prev = cpu->reg;
630:
631: gCVPrompt->NotifyRelease();
632: }
633:
634: // 引数などからアドレスを取得する共通ルーチン。
635: // 引数が1つ(以上)あれば av[1] をアドレスとしてパースする。
636: // なければ、lastaddr が指定されていればそれを使う。
637: // それもなければ、RegPC を使う。
638: bool
639: Debugger::GetAddr(uint32& addr, uint32& lastaddr)
640: {
641: if (ac > 1) {
642: // 1つ目の引数があれば、開始アドレス
643: if (ParseAddr(av[1], &addr) == false) {
644: return false;
645: }
646: // 偶数番地からに丸める
647: addr &= 0xfffffffe;
648: } else if (lastaddr != 0xffffffff) {
649: // 引数なしで前回値があれば前回の続き
650: addr = lastaddr;
651: } else {
652: // そうでなければ、今の PC
653: addr = RegPC;
654: }
655: return true;
656: }
657:
658: // 逆アセンブル: d [<addr> [<cnt>]] (論理、テーブルサーチなし)
659: void
660: Debugger::cmd_d()
661: {
662: cmd_d_common(MemdumpMode::Logical_atc);
663: }
664:
665: // 逆アセンブル: dt [<addr>] [<cnt>]] (論理、テーブルサーチあり)
666: void
667: Debugger::cmd_dt()
668: {
669: cmd_d_common(MemdumpMode::Logical_search);
670: }
671:
672: // 逆アセンブル: D [<addr> [<cnt>]] (物理)
673: void
674: Debugger::cmd_D()
675: {
676: cmd_d_common(MemdumpMode::Physical);
677: }
678:
679: // 逆アセンブル共通
680: void
681: Debugger::cmd_d_common(MemdumpMode mode)
682: {
683: uint32 addr;
684: int cnt;
685:
686: cnt = 10;
687:
688: // 開始アドレス
689: if (GetAddr(addr, d_last_addr) == false) {
690: return;
691: }
692: // 2つ目の引数があれば行数
693: if (ac > 2) {
694: cnt = strtol(av[2], NULL, 10);
695: }
696:
697: DisasmLine dis(cpu, addr, mode);
698: for (int i = 0; i < cnt; i++) {
699: std::string buf = dis.Output();
700: cons->Print("%s\n", buf.c_str());
701: // バスエラーならこの行で終了。
702: // XXX バスエラーかどうかを文字列判定してるのはさすがにどうかと
703: if (buf.find("BusErr") != std::string::npos) {
704: break;
705: }
706: }
707: d_last_addr = dis.GetNextAddr();
708: }
709:
710: // ログレベル設定: L <name> <level>
711: void
712: Debugger::cmd_L()
713: {
714: const char *name;
715: int level;
716:
717: if (ac < 3) {
718: cons->Print("L <name> <level>\n");
719: return;
720: }
721:
722: name = av[1];
723: level = atoi(av[2]);
724:
725: // 短縮形とかエイリアスとか
726: // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい
727: if (strcmp(name, "sch") == 0)
728: name = "scheduler";
729: if (strcmp(name, "pio") == 0)
730: name = "ppi";
731: if (strcmp(name, "scc") == 0)
732: name = "sio";
733:
734: // all はどうするか
735: std::string sname = name;
736: bool found = false;
737: for (auto& obj : gObjects) {
738: if (obj->logname == sname) {
739: obj->loglevel = level;
740: cons->Print("%s=%d\n", name, obj->loglevel);
741: found = true;
742: break;
743: }
744: }
745: // 見付からない場合はエラー
746: if (!found) {
747: cons->Print("%s: invalid logname\n", name);
748: }
749: }
750:
751: // メモリダンプ: m [<addr> [<cnt>]] (論理、テーブルサーチなし)
752: void
753: Debugger::cmd_m()
754: {
755: cmd_m_common(MemdumpMode::Logical_atc);
756: }
757:
758: // メモリダンプ: mt [<addr> [<cnt>]] (論理、テーブルサーチあり)
759: void
760: Debugger::cmd_mt()
761: {
762: cmd_m_common(MemdumpMode::Logical_search);
763: }
764:
765: // メモリダンプ: M [<addr> [<cnt>]] (物理)
766: void
767: Debugger::cmd_M()
768: {
769: cmd_m_common(MemdumpMode::Physical);
770: }
771:
772: // メモリダンプ共通
773: void
774: Debugger::cmd_m_common(MemdumpMode mode)
775: {
776: uint32 addr;
777: int cnt;
778:
779: cnt = 10;
780:
781: // 開始アドレス
782: if (GetAddr(addr, m_last_addr) == false) {
783: return;
784: }
785: // 2つ目の引数があれば行数
786: if (ac > 2) {
787: cnt = strtol(av[2], NULL, 10);
788: }
789:
790: MemdumpLine mem(cpu, addr, mode);
791: for (int i = 0; i < cnt; i++) {
792: cons->Print("%s\n", mem.Output().c_str());
793: }
794: m_last_addr = mem.GetNextAddr();
795: }
796:
797: // プロンプトに来た最初に表示するいつものやつを再表示する
798: void
799: Debugger::cmd_minus()
800: {
801: cmd_r();
802:
803: // 論理アクセス時、ATC ミスが分かったほうが便利だと思う
804: MemdumpMode mode = (cpu->mmu_enable)
805: ? MemdumpMode::Logical_atc
806: : MemdumpMode::Physical;
807: DisasmLine dis(cpu, pc, mode);
808: cons->Print("%s%s\n", dis.Output().c_str(), OPccCondStr(pc));
809: nextpc = dis.GetNextAddr();
810: }
811:
812: // ステップ実行: n[<count>?=1] (サブルーチンを飛ばす)
813: void
814: Debugger::cmd_n()
815: {
816: if (ac > 1) {
817: int count;
818: count = strtol(av[1], NULL, 10);
819: if (count < 1) {
820: cons->Print(" invalid step count: %d\n", count);
821: return;
822: }
823:
824: n_count = count;
825: } else {
826: n_count = 1;
827: }
828: n_enable = true;
829: SetNBreakpoint();
830: Continue();
831: }
832:
833: // n コマンド用のサブルーチンを飛ばすブレークポイントを設定。
834: // 戻り値は、プロンプトをスキップするなら true。
835: bool
836: Debugger::SetNBreakpoint()
837: {
838: // n コマンドは、通常はブレークポイントを次の命令に仕掛けながら
839: // 実行するが、いくつかの命令ではブレークポイントではなく、
840: // 命令トレース (t コマンド) のように動作させる。
841: // トレース動作する命令は以下の通り。
842: // Bcc, BRA
843: // JMP
844: // RTD, RTR, RTS
845: // RTE
846: // FBcc
847: // FDBcc (2ワード目無視)
848: // (RTM は 68020 専用なので対応しない)
849: #define IsBcc(x) ((((x) & 0xf000) == 0x6000) && (((x) & 0xff00) != 0x6100))
850: #define IsJMP(x) (((x) & 0xffc0) == 0x4ec0)
851: #define IsRTD(x) (((x) & 0xffff) == 0x4e74)
852: #define IsRTE(x) (((x) & 0xffff) == 0x4e73)
853: #define IsRTR(x) (((x) & 0xffff) == 0x4e77)
854: #define IsRTS(x) (((x) & 0xffff) == 0x4e75)
855: #define IsFBcc(x) (((x) & 0xf180) == 0xf080)
856: #define IsFDBcc(x) (((x) & 0xf1f8) == 0xf048)
857:
858: uint16 op;
859:
860: // XXX この辺統一的にしたほうがいい
861: // XXX logical peek のような気がする
862: op = (((uint16)m68030_phys_peek_8(pc)) << 8)
863: | m68030_phys_peek_8(pc + 1);
864:
865: if (IsBcc(op)
866: || IsJMP(op)
867: || IsRTD(op)
868: || IsRTE(op)
869: || IsRTR(op)
870: || IsRTS(op)
871: || IsFBcc(op)
872: || IsFDBcc(op)
873: ) {
874: n_breakenable = false;
875: s_enable = true;
876: s_count = 1;
877: return false;
878: } else {
879: n_breakenable = true;
880: n_breakaddr = nextpc;
881: return true;
882: }
883: }
884:
885: // レジスタ表示
886: // rf: FPU レジスタを表示
887: // rm: MMU レジスタを表示
888: // r<それ以外>: 通常レジスタを表示?
889: void
890: Debugger::cmd_r()
891: {
892: if (ac > 1) {
893: int arg = av[1][0];
894: switch (arg) {
895: case 'a':
896: ShowMonitor(gMPUATC->monitor);
897: return;
898: case 'f':
899: ShowRegFPU();
900: return;
901: case 'm':
902: ShowRegMMU();
903: return;
904: case 'o':
905: ShowRegOther();
906: return;
907: }
908: }
909: ShowRegMain();
910: }
911:
912: // ショートカット
913: void
914: Debugger::cmd_ra()
915: {
916: gMPUATC->MonitorUpdate();
917: ShowMonitor(gMPUATC->monitor);
918: }
919: void
920: Debugger::cmd_rf()
921: {
922: ShowRegFPU();
923: }
924: void
925: Debugger::cmd_rm()
926: {
927: ShowRegMMU();
928: }
929: void
930: Debugger::cmd_ro()
931: {
932: ShowRegOther();
933: }
934:
935: // モニター表示
936: void
937: Debugger::cmd_show()
938: {
939: if (ac != 2) {
940: cons->Print("usage: show <monitor>\n");
941: for (auto& d : gObjects) {
942: if (d->logname != "?") {
943: cons->Print(" %s\n", d->logname.c_str());
944: }
945: }
946: return;
947: }
948:
949: std::string name(av[1]);
950: for (auto& d : gObjects) {
951: if (d->logname == name) {
952: // ここで更新して..
953: if (d->MonitorUpdate()) {
954: // 表示
955: ShowMonitor(d->monitor);
956: } else {
957: // モニターがない場合
958: cons->Print("show: %s has no monitor\n", av[1]);
959: }
960: return;
961: }
962: }
963: // 一致しない
964: cons->Print("show: no such objects\n");
965: }
966:
967: // モニタースクリーンを表示。
968: void
969: Debugger::ShowMonitor(TextScreen& monitor)
970: {
971: char sbuf[1024]; // 適当
972:
973: // monitor 内部バッファから ShiftJIS バッファを作成。
974: // その際属性もエスケープシーケンスで再現する。
975: int col = monitor.GetCol();
976: int row = monitor.GetRow();
977: const uint16 *src = monitor.GetBuf();
978:
979: for (int y = 0; y < row; y++) {
980: int sy = y * col;
981: int sx;
982: uint attr;
983: char *d;
984:
985: memset(sbuf, 0, sizeof(sbuf));
986: d = sbuf;
987: attr = TA::Normal;
988: for (sx = 0; sx < col; sx++) {
989: uint a = src[sy + sx] & 0xff00;
990: uint ch = src[sy + sx] & 0x00ff;
991:
992: // 属性の変わり目
993: if (attr != a) {
994: switch (a) {
995: case TA::Normal:
996: case TA::Off:
997: *d++ = 0x1b;
998: *d++ = '[';
999: *d++ = 'm';
1000: break;
1001: case TA::On:
1002: *d++ = 0x1b;
1003: *d++ = '[';
1004: *d++ = '7';
1005: *d++ = 'm';
1006: break;
1007: case TA::Disable:
1008: *d++ = 0x1b;
1009: *d++ = '[';
1010: *d++ = '2';
1011: *d++ = 'm';
1012: break;
1013: case TA::Em:
1014: *d++ = 0x1b;
1015: *d++ = '[';
1016: *d++ = '1';
1017: *d++ = 'm';
1018: break;
1019: }
1020: attr = a;
1021: }
1022: *d++ = ch;
1023: }
1024: *d = '\0';
1025:
1026: // XXX 日本語が使われてれば UTF-8 にしないといけないはず
1027:
1028: cons->Print("%s\n", sbuf);
1029: }
1030: }
1031:
1032: // ステップ実行: s[<count>?:1]
1033: void
1034: Debugger::cmd_s()
1035: {
1036: if (ac > 1) {
1037: int count;
1038: count = strtol(av[1], NULL, 10);
1039: if (count < 1) {
1040: cons->Print(" invalid step count: %d\n", count);
1041: return;
1042: }
1043:
1044: s_count = count;
1045: } else {
1046: s_count = 1;
1047: }
1048: s_enable = true;
1049: Continue();
1050: }
1051:
1052: // ステップアウト
1053: void
1054: Debugger::cmd_so()
1055: {
1056: so_enable = true;
1057: so_a7 = RegA(7);
1058: so_sr = RegSR & 0x3000;
1059: Continue();
1060: }
1061:
1062: // トレース実行: t[<count>?:1]
1063: // レジスタを表示しながら実行する
1064: void
1065: Debugger::cmd_t()
1066: {
1067: if (ac > 1) {
1068: int count;
1069: count = strtol(av[1], NULL, 10);
1070: if (count < 1) {
1071: cons->Print(" invalid trace count: %d\n", count);
1072: return;
1073: }
1074: t_count = count;
1075: } else {
1076: t_count = 1;
1077: }
1078: t_enable = true;
1079: Continue();
1080: }
1081:
1082: // 引数で示されるアドレスを返す。
1083: // '%' で始まればレジスタ。
1084: // そうでなければ16進数値。
1085: // アドレスが正しく取得できればアドレスを addr に格納し真を返す。
1086: // そうでなければエラーメッセージを表示して偽を返す。
1087: bool
1088: Debugger::ParseAddr(const char *arg, uint32_t *addrp)
1089: {
1090: uint32_t addr;
1091: char *end;
1092:
1093: if (arg[0] == '%') {
1094: /* '%' から始まればレジスタ */
1095: const char *regname = &arg[1];
1096: if ((*regname | 0x20) == 'a') {
1097: addr = RegA(arg[2] - '0');
1098:
1099: } else if ((*regname | 0x20) == 'd') {
1100: addr = RegD(arg[2] - '0');
1101:
1102: } else if (strcmp(regname, "sp") == 0) {
1103: addr = RegA(7);
1104:
1105: #if 0
1106: } else if (strcmp(regname, "usp") == 0) {
1107: addr = RegUSP;
1108:
1109: } else if (strcmp(regname, "isp") == 0) {
1110: addr = RegISP;
1111:
1112: } else if (strcmp(regname, "msp") == 0) {
1113: addr = RegMSP;
1114: #endif
1115:
1116: } else if (strcmp(regname, "pc") == 0) {
1117: addr = RegPC;
1118:
1119: } else if (strcmp(regname, "vbr") == 0) {
1120: addr = RegVBR;
1121:
1122: } else if (strcmp(regname, "srp") == 0) {
1123: addr = cpu->GetSRPl();
1124:
1125: } else if (strcmp(regname, "crp") == 0) {
1126: addr = cpu->GetCRPl();
1127:
1128: } else {
1129: cons->Print("valid register name are: %s%s\n",
1130: "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc",
1131: ",%msp,%vbr,%srp,%crp");
1132: return false;
1133: }
1134: } else {
1135: /* そうでなければ番地指定 */
1136: errno = 0;
1137: addr = strtoul(arg, &end, 16);
1138: if (arg[0] == '\0' || end[0] != '\0') {
1139: cons->Print("invalid address: '%s'\n", arg);
1140: return false;
1141: }
1142: if (errno == ERANGE) {
1143: cons->Print("out of range: %s\n", arg);
1144: return false;
1145: }
1146: }
1147:
1148: *addrp = addr;
1149: return true;
1150: }
1151:
1152: //
1153: // レジスタ表示
1154: //
1155:
1156: #define NORM "\x1b[0m"
1157: #define BOLD "\x1b[1m"
1158: #define BOLDIF(n) ((n) ? BOLD : "")
1159:
1160: // 基本セット
1161: void
1162: Debugger::ShowRegMain()
1163: {
1164: /*
1165: D0:00000070 D4:CCCCCCCC A0:00FFAA32 A4:CCCCCCCC SR=F810(S I=0 X----)
1166: D1:0000FFFF D5:00000000 A1:00000A7A A5:00000A7A
1167: D2:00FF0000 D6:00000000 A2:CCCCCCCC A6:CCCCCCCC
1168: D3:CCCCCCCC D7:00000003 A3:CCCCCCCC A7:00001FD8
1169: */
1170: bool vr[16];
1171:
1172: for (int i = 0; i < 16; i++) {
1173: vr[i] = (cpu->reg.da[i] != prev.da[i]);
1174: }
1175:
1176: // 1行目
1177: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s ",
1178: BOLDIF(vr[ 0]), 0, RegR( 0), NORM,
1179: BOLDIF(vr[ 4]), 4, RegR( 4), NORM,
1180: BOLDIF(vr[ 8]), 0, RegR( 8), NORM,
1181: BOLDIF(vr[12]), 4, RegR(12), NORM);
1182:
1183: // 1行目 SR
1184: uint16 sr = RegSR;
1185: uint16 prevsr = prev.sr_h()
1186: | (prev.ccr.IsX() ? M68K_CCR_X : 0)
1187: | (prev.ccr.IsN() ? M68K_CCR_N : 0)
1188: | (prev.ccr.IsZ() ? M68K_CCR_Z : 0)
1189: | (prev.ccr.IsV() ? M68K_CCR_V : 0)
1190: | (prev.ccr.IsC() ? M68K_CCR_C : 0);
1191: // SR は上位バイトと下位バイトが変化したくらいでいいか?
1192: cons->Print(" SR:%s%02x%s%s%02x%s",
1193: BOLDIF((sr & 0xff00) != (prevsr & 0xff00)),
1194: sr >> 8,
1195: NORM,
1196: BOLDIF((sr & 0x00ff) != (prevsr & 0x00ff)),
1197: sr & 0xff,
1198: NORM);
1199: cons->Print("(%c I=%d %c%c%c%c%c)\n",
1200: (sr & 0x2000) ? 'S' : '-',
1201: (sr >> 8) & 7,
1202: (sr & M68K_CCR_X) ? 'X' : '-',
1203: (sr & M68K_CCR_N) ? 'N' : '-',
1204: (sr & M68K_CCR_Z) ? 'Z' : '-',
1205: (sr & M68K_CCR_V) ? 'V' : '-',
1206: (sr & M68K_CCR_C) ? 'C' : '-');
1207:
1208: // 2行目
1209: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
1210: BOLDIF(vr[ 1]), 1, RegR( 1), NORM,
1211: BOLDIF(vr[ 5]), 5, RegR( 5), NORM,
1212: BOLDIF(vr[ 9]), 1, RegR( 9), NORM,
1213: BOLDIF(vr[13]), 5, RegR(13), NORM);
1214:
1215: // 3行目
1216: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
1217: BOLDIF(vr[ 2]), 2, RegR( 2), NORM,
1218: BOLDIF(vr[ 6]), 6, RegR( 6), NORM,
1219: BOLDIF(vr[10]), 2, RegR(10), NORM,
1220: BOLDIF(vr[14]), 6, RegR(14), NORM);
1221:
1222: // 4行目
1223: cons->Print("%sD%d:%08x%s %sD%d:%08x%s %sA%d:%08x%s %sA%d:%08x%s\n",
1224: BOLDIF(vr[ 3]), 3, RegR( 3), NORM,
1225: BOLDIF(vr[ 7]), 7, RegR( 7), NORM,
1226: BOLDIF(vr[11]), 3, RegR(11), NORM,
1227: BOLDIF(vr[15]), 7, RegR(15), NORM);
1228: }
1229:
1230: // FPU レジスタ表示
1231: void
1232: Debugger::ShowRegFPU()
1233: {
1234: /*
1235: FP0:0000_12345678_12345678 (-0.1234567890123456789) FPCR:1234
1236: FP1: BS,SN,OP,OV,UF,DZ,I2,I1
1237: FP2: RP=xx RM=xx
1238: FP3: FPSR:12345678
1239: FP4: N,Z,Inf,NAN Q=$xx
1240: FP5: BS,SN,OP,OV,UF,DZ,I2,I1
1241: FP6: AXEC
1242: FP7: FPIAR:12345678
1243: */
1244:
1245: #define PUT_FP(n) do { \
1246: uint32 *c_ = cpu->reg.fpframe.fpf_regs + (n) * 3; \
1247: uint32 *p_ = prev.fpframe.fpf_regs + (n) * 3; \
1248: bool d = (c_[0] ^ p_[0]) | (c_[1] ^ p_[1]) | (c_[2] ^ p_[2]); \
1249: cons->Print("%sFP%d:%04xxxxx_%08x_%08x (%-20s)%s ", \
1250: BOLDIF(d), (n), c_[0] >> 16, c_[1], c_[2], "notyet", NORM); \
1251: } while (0)
1252:
1253: uint32 fpcr, fpsr, fpiar;
1254: uint32 ppcr, ppsr, ppiar;
1255: static const char * const rpstr[] = {
1256: ".EXT",
1257: ".SGL",
1258: ".DBL",
1259: ".???",
1260: };
1261: static const char * const rmstr[] = {
1262: "Near",
1263: "Zero",
1264: "Minus",
1265: "Plus",
1266: };
1267:
1268: fpcr = cpu->reg.fpframe.fpf_fpcr;
1269: fpsr = cpu->reg.fpframe.fpf_fpsr;
1270: fpiar = cpu->reg.fpframe.fpf_fpiar;
1271: ppcr = prev.fpframe.fpf_fpcr;
1272: ppsr = prev.fpframe.fpf_fpsr;
1273: ppiar = prev.fpframe.fpf_fpiar;
1274:
1275: PUT_FP(0);
1276: cons->Print("%sFPCR:%04x%s\n", BOLDIF(fpcr != ppcr), fpcr, NORM);
1277:
1278: PUT_FP(1);
1279: cons->Print(" %s %s %s %s %s %s %s %s\n",
1280: (fpcr & 0x8000) ? "BS" : "--",
1281: (fpcr & 0x4000) ? "SN" : "--",
1282: (fpcr & 0x2000) ? "OP" : "--",
1283: (fpcr & 0x1000) ? "OV" : "--",
1284: (fpcr & 0x0800) ? "UF" : "--",
1285: (fpcr & 0x0400) ? "DZ" : "--",
1286: (fpcr & 0x0200) ? "I2" : "--",
1287: (fpcr & 0x0100) ? "I1" : "--");
1288:
1289: PUT_FP(2);
1290: cons->Print(" RP=%s RM=%s\n",
1291: rpstr[(fpcr >> 6) & 3],
1292: rmstr[(fpcr >> 4) & 3]);
1293:
1294: PUT_FP(3);
1295: cons->Print("%sFPSR:%08x%s\n", BOLDIF(fpsr != ppsr), fpsr, NORM);
1296:
1297: PUT_FP(4);
1298: uint cc = fpsr >> 24;
1299: cons->Print(" %c %c %s %s Q=$%02x\n",
1300: (cc & 0x08) ? 'N' : '-',
1301: (cc & 0x04) ? 'Z' : '-',
1302: (cc & 0x02) ? "Inf" : "---",
1303: (cc & 0x01) ? "NAN" : "---",
1304: (fpsr >> 16) & 0xff);
1305:
1306: PUT_FP(5);
1307: cons->Print(" %s %s %s %s %s %s %s %s\n",
1308: (fpsr & 0x8000) ? "BS" : "--",
1309: (fpsr & 0x4000) ? "SN" : "--",
1310: (fpsr & 0x2000) ? "OP" : "--",
1311: (fpsr & 0x1000) ? "OV" : "--",
1312: (fpsr & 0x0800) ? "UF" : "--",
1313: (fpsr & 0x0400) ? "DZ" : "--",
1314: (fpsr & 0x0200) ? "I2" : "--",
1315: (fpsr & 0x0100) ? "I1" : "--");
1316:
1317: PUT_FP(6);
1318: cons->Print(" %s %s %s %s %s\n",
1319: (fpsr & 0x80) ? "IOP" : "---",
1320: (fpsr & 0x40) ? "OVFL" : "----",
1321: (fpsr & 0x20) ? "UNFL" : "----",
1322: (fpsr & 0x10) ? "DZ" : "--",
1323: (fpsr & 0x08) ? "INEX" : "----");
1324:
1325: PUT_FP(7);
1326: cons->Print("%sFPIAR:%08x%s\n", BOLDIF(fpiar != ppiar), fpiar, NORM);
1327: }
1328:
1329: void
1330: Debugger::ShowRegMMU()
1331: {
1332: /*
1333: SRP:00001111_22223333 TT0:00001111 TC:00001111 (---)
1334: CRP:00001111_22223333 TT1:00001111 MMUSR: 0011 (
1335: */
1336: uint64 srp, osrp;
1337: uint64 crp, ocrp;
1338: uint32 tt0, ott0;
1339: uint32 tt1, ott1;
1340: uint32 tc, otc;
1341: uint16 sr, osr;
1342: bool p;
1343: bool t;
1344: bool c;
1345:
1346: srp = cpu->GetSRP();
1347: crp = cpu->GetCRP();
1348: tt0 = cpu->GetTT(0);
1349: tt1 = cpu->GetTT(1);
1350: tc = cpu->GetTC();
1351: sr = cpu->GetMMUSR();
1352:
1353: osrp = prev.srp.q;
1354: ocrp = prev.crp.q;
1355: ott0 = prev.tt[0];
1356: ott1 = prev.tt[1];
1357: otc = prev.tc;
1358: osr = prev.mmusr;
1359:
1360: // 1行目
1361: p = (srp != osrp);
1362: t = (tt0 != ott0);
1363: c = (tc != otc);
1364: cons->Print("%sSRP:%08x_%08x%s %sTT0:%08x%s(%c%c%c)",
1365: BOLDIF(p), (uint32)(srp >> 32), (uint32)srp, NORM,
1366: BOLDIF(t), tt0, NORM,
1367: (tt0 & m68030TT::E) ? 'E' : '-',
1368: (tt0 & m68030TT::CI) ? 'C' : '-',
1369: (tt0 & m68030TT::RWM) ? '-' : ((tt0 & m68030TT::RW) ? 'R' : 'W'));
1370: cons->Print(" %sTC:%08x%s(%c%c%c)\n",
1371: BOLDIF(c), tc, NORM,
1372: (tc & m68030TC::TC_E) ? 'E' : '-',
1373: (tc & m68030TC::TC_SRE) ? 'S' : '-',
1374: (tc & m68030TC::TC_FCL) ? 'F' : '-');
1375:
1376: // 2行目
1377: p = (crp != ocrp);
1378: t = (tt1 != ott1);
1379: c = (sr != osr);
1380: cons->Print("%sCRP:%08x_%08x%s %sTT1:%08x%s(%c%c%c)",
1381: BOLDIF(p), uint32(crp >> 32), (uint32)crp, NORM,
1382: BOLDIF(t), tt1, NORM,
1383: (tt1 & m68030TT::E) ? 'E' : '-',
1384: (tt1 & m68030TT::CI) ? 'C' : '-',
1385: (tt1 & m68030TT::RWM) ? '-' : ((tt1 & m68030TT::RW) ? 'R' : 'W'));
1386: cons->Print(" %sMMUSR: %04x%s(%c%c%c%c%c%c%c N=%d)\n",
1387: BOLDIF(c), sr, NORM,
1388: (sr & m68030MMUSR::B) ? 'B' : '-',
1389: (sr & m68030MMUSR::L) ? 'L' : '-',
1390: (sr & m68030MMUSR::S) ? 'S' : '-',
1391: (sr & m68030MMUSR::W) ? 'W' : '-',
1392: (sr & m68030MMUSR::I) ? 'I' : '-',
1393: (sr & m68030MMUSR::M) ? 'M' : '-',
1394: (sr & m68030MMUSR::T) ? 'T' : '-',
1395: (sr & m68030MMUSR::N));
1396: }
1397:
1398: // その他のレジスタを表示
1399: void
1400: Debugger::ShowRegOther()
1401: {
1402: TextScreen s(80, 2);
1403:
1404: // 0 1 2 3 4 5 6
1405: // 012345678901234567890123456789012345678901234567890123456789012345
1406: // CACR:01234567 VBR:01234567 USP:01234567
1407: // CAAR:01234567 SFC:0 DFC:0 MSP:01234567
1408:
1409: #define EM(name) ((cpu->reg.name != prev.name) ? TA::Em : TA::Normal)
1410: s.Print(0, 0, EM(cacr), "CACR:%08x", cpu->reg.cacr);
1411: s.Print(0, 1, EM(caar), "CAAR:%08x", cpu->reg.caar);
1412:
1413: s.Print(15, 0, EM(vbr), "VBR:%08x", cpu->reg.vbr);
1414: s.Print(15, 1, EM(sfc), "SFC:%d", cpu->reg.sfc);
1415: s.Print(22, 1, EM(dfc), "DFC:%d", cpu->reg.dfc);
1416:
1417: // スタック欄はモードによって表示を変える。
1418: // ユーザ 割り込み マスタ
1419: // 1行目 ISP USP USP
1420: // 2行目 MSP MSP ISP
1421: if (!cpu->reg.s) {
1422: s.Print(29, 0, EM(isp), "ISP:%08x", cpu->reg.isp);
1423: } else {
1424: s.Print(29, 0, EM(usp), "USP:%08x", cpu->reg.usp);
1425: }
1426: if (!cpu->reg.m) {
1427: s.Print(29, 1, EM(msp), "MSP:%08x", cpu->reg.msp);
1428: } else {
1429: s.Print(29, 1, EM(isp), "ISP:%08x", cpu->reg.isp);
1430: }
1431:
1432: ShowMonitor(s);
1433: }
1434:
1435: // op が 68030 の条件命令 Bcc, Scc, TRAPcc, DBcc なら true を返す。
1436: bool
1437: Debugger::IsOPcc(uint16 op)
1438: {
1439: uint16 cc;
1440:
1441: if ((op & 0xf000) == 0x6000) {
1442: cc = (op >> 8) & 0xf;
1443: if (cc == 0 || cc == 1) { // BRA, BSR
1444: return false;
1445: } else {
1446: return true; // Bcc
1447: }
1448: }
1449:
1450: if ((op & 0xf0c0) == 0x50c0) { // Scc, TRAPcc, DBcc
1451: return true;
1452: }
1453:
1454: return false;
1455: }
1456:
1457: // op が DBcc 命令なら true を返す。
1458: bool
1459: Debugger::IsDBcc(uint16 op)
1460: {
1461: if ((op & 0xf0f8) == 0x50c8) { // DBcc
1462: return true;
1463: }
1464: return false;
1465: }
1466:
1467: // op の cccc 条件が現在の CCR で成立するなら true を返す。
1468: bool
1469: Debugger::IsCond(uint16 op)
1470: {
1471: bool N = RegIsN;
1472: bool Z = RegIsZ;
1473: bool V = RegIsV;
1474: bool C = RegIsC;
1475:
1476: switch ((op >> 8) & 0x0f) {
1477: case 0: // T
1478: return true;
1479: case 1: // F
1480: return false;
1481: case 2: // HI
1482: return (!C) && (!Z);
1483: case 3: // LS
1484: return C || Z;
1485: case 4: // CC
1486: return !C;
1487: case 5: // CS
1488: return C;
1489: case 6: // NE
1490: return !Z;
1491: case 7: // EQ
1492: return Z;
1493: case 8: // VC
1494: return !V;
1495: case 9: // VS
1496: return V;
1497: case 10: // PL
1498: return !N;
1499: case 11: // MI
1500: return N;
1501: case 12: // GE
1502: return (N && V) || ((!N) && (!V));
1503: case 13: // LT
1504: return (N && (!V)) || ((!N) && V);
1505: case 14: // GT
1506: return (N && V && (!Z)) || ((!N) && (!V) && (!Z));
1507: case 15: // LE
1508: return Z || (N && (!V)) || ((!N) && V);
1509: default:
1510: __unreachable();
1511: }
1512: }
1513:
1514: // addr 位置の命令が条件命令なら、成立可否などの文字列を返す。
1515: // Bcc, Scc, TRAPcc 命令なら、条件が成立するかどうか。
1516: // DBcc 命令ならブランチするかどうか。
1517: const char *
1518: Debugger::OPccCondStr(uint32 addr)
1519: {
1520: uint16 op;
1521:
1522: // XXX logical peek のような気がする
1523: op = (((uint16)m68030_phys_peek_8(addr)) << 8)
1524: | m68030_phys_peek_8(addr + 1);
1525:
1526: // DBcc 命令なら、ブランチするかどうか
1527: // IsOPcc() は DBcc も含んでいるため、IsDBcc() の判定のほうが先。
1528: // DBcc は内部でカウンタレジスタを減算してから比較するため、
1529: // 命令実行前のカウンタが 0 の時点でループ終了となることに注意。
1530: if (IsDBcc(op)) {
1531: // 成立したら何もしない
1532: if (IsCond(op)) {
1533: return " (will fall)";
1534: }
1535: // カウンタが -1 なら何もしない
1536: uint rr = op & 7;
1537: if ((RegD(rr) & 0xffff) == 0) {
1538: return " (will expire)";
1539: }
1540: // それ以外はブランチ
1541: return " (will take)";
1542: }
1543:
1544: // Bcc, Scc, TRAPcc 命令なら条件が成立するかどうか
1545: if (IsOPcc(op)) {
1546: if (IsCond(op)) {
1547: return " (will take)";
1548: } else {
1549: return " (will not take)";
1550: }
1551: }
1552:
1553: // (ここで知ってる)条件命令ではない
1554: return "";
1555: }
1556:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.