|
|
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.