Annotation of nono/debugger/debugger.cpp, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.