Annotation of nono/debugger/debugger.cpp, revision 1.1.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.