Annotation of nono/debugger/branchhistory.cpp, revision 1.1.1.7

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.5   root        7: //
1.1       root        8: // ブランチ履歴
1.1.1.5   root        9: //
1.1       root       10: 
                     11: #include "branchhistory.h"
                     12: #include "m88100.h"
1.1.1.7 ! root       13: #include "mpu64180.h"
1.1.1.5   root       14: #include "vectortable.h"
1.1       root       15: 
                     16: // コンストラクタ
1.1.1.7 ! root       17: BranchHistory::BranchHistory(int objid_)
        !            18:        : inherited(objid_)
1.1       root       19: {
1.1.1.7 ! root       20:        int monitor_id;
        !            21: 
        !            22:        switch (GetId()) {
        !            23:         case OBJ_MPU_BRHIST:
        !            24:                is_exhist = false;
        !            25:                monitor_id = ID_SUBWIN_BRHIST;
        !            26:                break;
        !            27:         case OBJ_MPU_EXHIST:
        !            28:                is_exhist = true;
        !            29:                monitor_id = ID_SUBWIN_EXHIST;
        !            30:                break;
        !            31:         case OBJ_XP_BRHIST:
        !            32:                is_exhist = false;
        !            33:                monitor_id = ID_SUBWIN_XPBRHIST;
        !            34:                break;
        !            35:         case OBJ_XP_EXHIST:
        !            36:                is_exhist = true;
        !            37:                monitor_id = ID_SUBWIN_XPEXHIST;
        !            38:                break;
        !            39:         default:
        !            40:                PANIC("unknown id %s", GetIdStr());
        !            41:        }
1.1.1.4   root       42: 
1.1.1.5   root       43:        // ログは不要
                     44:        ClearAlias();
                     45: 
1.1.1.7 ! root       46:        vectortable = GetVectorTable();
        !            47: 
1.1.1.5   root       48:        monitor.func = ToMonitorCallback(&BranchHistory::MonitorUpdate);
1.1.1.6   root       49:        monitor.SetSize(55, 1 + 32); // ヘッダ1行とエントリ数
                     50:        monitor.SetMaxHeight(1 + 256);
1.1.1.7 ! root       51:        monitor.Regist(monitor_id);
        !            52: 
        !            53:        // hd64180 はこれを上書きする
        !            54:        x_count = 45;
1.1       root       55: }
                     56: 
                     57: // デストラクタ
                     58: BranchHistory::~BranchHistory()
                     59: {
                     60: }
                     61: 
                     62: // 初期化
                     63: void
                     64: BranchHistory::Clear()
                     65: {
                     66:        top = 0;
                     67:        for (int i = 0; i < countof(entry); i++) {
                     68:                BranchEntry& e = entry[i];
                     69:                e.count = 0;
                     70:                e.from  = 0xffffffff;
                     71:                e.to    = 0xffffffff;
                     72:                e.inst  = 0;
                     73:        }
                     74: }
                     75: 
                     76: // 使用中のエントリ数を取得する
                     77: int
                     78: BranchHistory::GetUsed() const
                     79: {
                     80:        int i = 0;
                     81: 
                     82:        // top の位置から一巡するまで。有効エントリは count > 0。
                     83:        for (; i < 256; i++) {
                     84:                if (entry[(256 + top - i) % 256].count == 0) {
                     85:                        break;
                     86:                }
                     87:        }
                     88:        return i;
                     89: }
                     90: 
                     91: // モニタ更新
                     92: void
1.1.1.4   root       93: BranchHistory::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root       94: {
                     95:        uint8 t;
                     96:        int y;
                     97:        int ydelta;
                     98:        int row;
                     99: 
                    100:        // userdata は表示開始位置と各種フラグ。
                    101:        // 下位 32bit が表示開始位置で、0 なら先頭のエントリから、1 なら先頭の
1.1.1.4   root      102:        // 一つ次のエントリから、…を表す (表示行数は screen の高さ分)。
1.1       root      103:        // BottomToTop が %1 なら並び順を下から上に変える (コンソール用)。
1.1.1.4   root      104:        bool bottom_to_top = (screen.userdata & BottomToTop);
                    105:        int pos = (int)screen.userdata;
1.1       root      106: 
                    107:        // 0         1         2         3         4         5         6
                    108:        // 0123456789012345678901234567890123456789012345678901234567890123456789
                    109:        // No. FromAddr  Instruction          ToAddr    Iteration
                    110:        // 001 U:01234567(01234567:bcnd.n) -> $01234567 x123456789
                    111:        // 001 U:01234567(0123:trap )      -> $01234567 x123456789
                    112:        // 002 S:01234567<  2> Bus Error
                    113:        // 002 S:01234567< 69> MFP Timer-C
                    114:        //                     01234567890123456789012
                    115: 
1.1.1.4   root      116:        screen.Clear();
                    117:        row = screen.GetRow();
1.1       root      118: 
                    119:        // 最初の1行は常にヘッダ
1.1.1.7 ! root      120:        std::string header = FormatHeader();
        !           121:        screen.Puts(0, 0, header.c_str());
1.1       root      122: 
                    123:        // pos は最新を 0 とした通し番号。(スクロールしてたら開始が 0 とは限らない)
                    124:        // t が entry[] 上の現在位置。
                    125:        // y は表示座標。(上から表示か下から表示かが変わる)
                    126:        t = top - pos;
                    127:        int pos_end = pos + row - 1;
                    128:        if (bottom_to_top == false) {
                    129:                y = 1;
                    130:                ydelta = 1;
                    131:        } else {
                    132:                y = row - 1;
                    133:                ydelta = -1;
                    134:        }
                    135:        for (; pos < pos_end; pos++, y += ydelta) {
                    136:                BranchEntry& e = entry[t--];
                    137:                if (e.count == 0) {
                    138:                        continue;
                    139:                }
                    140:                std::string str = FormatEntry(e);
1.1.1.4   root      141:                screen.Print(0, y, "%3d %s", pos, str.c_str());
1.1       root      142:                if (e.count > 1) {
1.1.1.7 ! root      143:                        screen.Print(x_count, y, "x%9u", e.count);
1.1       root      144:                }
                    145:        }
                    146: }
                    147: 
1.1.1.7 ! root      148: // ヘッダ文字列を返す。(m68k, m88k 共通)
        !           149: std::string
        !           150: BranchHistory::FormatHeader() const
        !           151: {
        !           152:        if (is_exhist) {
        !           153:                //      012345678901234567890123456789012345678901234567890123456789
        !           154:                return "No. FromAddr   Vec. Exception                Iteration";
        !           155:        } else {
        !           156:                //      012345678901234567890123456789012345678901234567890123456789
        !           157:                return "No. FromAddr  Instruction          ToAddr    Iteration";
        !           158:        }
        !           159: }
1.1       root      160: 
                    161: 
                    162: //
                    163: // m680x0 ブランチ履歴 (どこに置くのがよいか)
                    164: //
                    165: 
                    166: // m680x0 ブランチ履歴では、通常ブランチ、例外発生、例外ベクタによる
                    167: // ジャンプの3つを区別する。
                    168: //
                    169: // 通常の分岐:
1.1.1.3   root      170: //     from は上位31ビットが分岐元 PC、最下位ビットが S/U、
                    171: //     to   は32ビット全体が分岐先 PC、
                    172: //     inst の上位16ビットに命令の1ワード目。
1.1       root      173: //     inst の $8000 が立っていないことで区別する。
                    174: //
                    175: // 例外発生:
1.1.1.3   root      176: //     from は上位31ビットが例外発生時の PC、最下位ビットが S/U、
                    177: //     to   は不問(通常 0 をセットすること)、
1.1       root      178: //     inst は $00008LVV で $8000 が例外フラグ、VV がベクタ番号である。
                    179: //     ベクタ番号が $00 だと次項(ベクタによる分岐)と区別つかなくなってしまう
                    180: //     ため、リセット例外 (ベクタ番号0) は V=$01 で記録する。
                    181: //     L は割り込みなら割り込みレベル。
                    182: //     inst に $8000 が立っていて、かつ $8000 と一致しないことで区別する。
                    183: //
                    184: // 例外ベクタによる分岐 (例外処理の最後に起きる):
1.1.1.3   root      185: //     from はベクタアドレス、
                    186: //     to   は分岐先 (0 も起こりえる)、
                    187: //     inst は $00008000。
1.1       root      188: //     inst が $00008000 と一致することで区別する (ビットが立っているではない)。
                    189: 
                    190: // コンストラクタ
1.1.1.7 ! root      191: BranchHistory_m680x0::BranchHistory_m680x0(int objid_)
        !           192:        : inherited(objid_)
1.1       root      193: {
                    194: }
                    195: 
                    196: // デストラクタ
                    197: BranchHistory_m680x0::~BranchHistory_m680x0()
                    198: {
                    199: }
                    200: 
                    201: // 1エントリ分の表示内容作成
                    202: std::string
                    203: BranchHistory_m680x0::FormatEntry(const BranchEntry& e)
                    204: {
                    205:        // m68k では from の最下位1ビットを S/U として使う
                    206:        std::string desc = string_format("%c:%08x",
                    207:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    208: 
                    209:        if ((e.inst & 0x8000)) {
                    210:                if ((e.inst & 0x7fff) != 0) {
                    211:                        // 例外発生記録
                    212:                        // 発生アドレスとベクタ(と割り込みレベル)を表示
                    213:                        uint32 vector = e.inst & 0xff;
                    214:                        if (vector == 1) {
                    215:                                vector = 0;
                    216:                        }
                    217:                        // とりあえず
1.1.1.7 ! root      218:                        const char *name = vectortable->GetExceptionName(vector);
1.1.1.5   root      219:                        desc += string_format("<%3d> %s", vector, name ?: "");
1.1       root      220:                        // XXX TODO 割り込みレベル
                    221:                } else {
                    222:                        // 例外ベクタフェッチしてジャンプ
                    223:                        desc += string_format("(vector fetch)    -> $%08x", e.to);
                    224:                }
                    225:        } else {
                    226:                // ブランチ
                    227:                const char *mnemonic;
                    228:                uint32 inst = e.inst >> 16;
                    229:                if (inst == 0x4e73) {
                    230:                        mnemonic = ":rte";
                    231:                } else if (inst == 0x4e75) {
                    232:                        mnemonic = ":rts";
                    233:                } else if (inst == 0x4e77) {
                    234:                        mnemonic = ":rtr";
                    235:                } else if ((inst & 0xffc0) == 0x4e80) {
                    236:                        mnemonic = ":jsr";
                    237:                } else if ((inst & 0xffc0) == 0x4ec0) {
                    238:                        mnemonic = ":jmp";
                    239:                } else if ((inst & 0xfff8) == 0x51c8) {
                    240:                        mnemonic = ":dbra";
                    241:                } else if ((inst & 0xf0f8) == 0x50c8) {
                    242:                        mnemonic = ":dbcc";
                    243:                } else if ((inst & 0xff00) == 0x6000) {
                    244:                        mnemonic = ":bra";
                    245:                } else if ((inst & 0xff00) == 0x6100) {
                    246:                        mnemonic = ":bsr";
                    247:                } else if ((inst & 0xf000) == 0x6000) {
                    248:                        mnemonic = ":bcc";
                    249:                } else if ((inst & 0xfff8) == 0xf248) {
                    250:                        mnemonic = ":fdbcc";
                    251:                } else if ((inst & 0xff80) == 0xf280) {
                    252:                        mnemonic = ":fbcc";
                    253:                } else {
                    254:                        mnemonic = "";
                    255:                }
                    256:                desc += string_format("(%04x%-6s)      -> $%08x", inst, mnemonic, e.to);
                    257:        }
                    258:        return desc;
                    259: }
                    260: 
                    261: 
                    262: //
                    263: // m88xx0 ブランチ履歴 (どこに置くのがよいか)
                    264: //
                    265: 
                    266: // m88xx0 ブランチ履歴では、通常ブランチ、例外発生の2つを区別する。
                    267: // m68k は例外ベクタに書いてあるアドレスに飛ぶのでもう1種類分けてあったが、
                    268: // m88k は例外ベクタを直接実行するのでそれは不要。
                    269: //
                    270: // 通常の分岐:
1.1.1.3   root      271: //     from は上位30ビットが分岐元 XIP、最下位ビットが S/U、
                    272: //     to   は32ビット全体が分岐先アドレス、
                    273: //     inst は命令ワード。
1.1       root      274: //
                    275: // 例外発生:
1.1.1.3   root      276: //     from は上位30ビットが例外発生時の XIP、最下位ビットが S/U、
                    277: //     to   は 0。
                    278: //     inst は $fc000VVV で VVV (9ビット)がベクタ番号。
                    279: //     命令ワードとは衝突しない (instruction.txt 参照)。
1.1       root      280: 
                    281: // コンストラクタ
1.1.1.7 ! root      282: BranchHistory_m88xx0::BranchHistory_m88xx0(int objid_)
        !           283:        : inherited(objid_)
1.1       root      284: {
                    285: }
                    286: 
                    287: // デストラクタ
                    288: BranchHistory_m88xx0::~BranchHistory_m88xx0()
                    289: {
                    290: }
                    291: 
                    292: // 1エントリ分の表示内容作成
                    293: std::string
                    294: BranchHistory_m88xx0::FormatEntry(const BranchEntry& e)
                    295: {
                    296:        // m88k では from の最下位1ビットを S/U として使う
                    297:        std::string desc = string_format("%c:%08x",
                    298:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    299: 
                    300:        if (e.inst >= 0xfc000000 && e.to == 0) {
                    301:                // 例外発生記録
                    302:                // 発生アドレスとベクタを表示
                    303:                uint32 vector = e.inst & 0x1ff;
1.1.1.7 ! root      304:                const char *name = vectortable->GetExceptionName(vector);
1.1       root      305:                desc += string_format("<%3d> %s", vector, name ?: "");
1.1.1.7 ! root      306:                if (vector == 128 || vector == 450) {
        !           307:                        // 450 なら OpenBSD のシステムコール番号を追加。
        !           308:                        // 非公式 NetBSD/luna88k は(今の所?) 128 を使ってるようだ。
1.1       root      309:                        desc += string_format("(%d)", (e.inst >> 12) & 0xfff);
                    310:                }
                    311:        } else if (e.inst >= 0xc0000000) {
                    312:                // ブランチ
                    313:                const char *mnemonic = "";
                    314:                uint32 up4 = (e.inst >> 26) & 0xf;
                    315:                switch (up4) {
                    316:                 case 0:        mnemonic = ":br";               break;
                    317:                 case 1:        mnemonic = ":br.n";             break;
                    318:                 case 2:        mnemonic = ":bsr";              break;
                    319:                 case 3:        mnemonic = ":bsr.n";    break;
                    320:                 case 4:        mnemonic = ":bb0";              break;
                    321:                 case 5:        mnemonic = ":bb0.n";    break;
1.1.1.2   root      322:                 case 6:        mnemonic = ":bb1";              break;
1.1       root      323:                 case 7:        mnemonic = ":bb1.n";    break;
                    324: 
                    325:                 case 0xa:      mnemonic = ":bcnd";             break;
                    326:                 case 0xb:      mnemonic = ":bcnd.n";   break;
                    327:                 case 0xc: {
                    328:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
                    329:                        if (lo6 == 0x34) {
                    330:                                mnemonic = ":tb0";
                    331:                        } else if (lo6 == 0x36) {
                    332:                                mnemonic = ":tb1";
                    333:                        } else if (lo6 == 0x3a) {
                    334:                                mnemonic = ":tcnd";
                    335:                        }
                    336:                        break;
                    337:                 }
                    338:                 case 0xd: {
                    339:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
                    340:                        if (lo6 == 0x30) {
                    341:                                if ((e.inst & 0x1f) == 1) {
                    342:                                        mnemonic = ":jmp r1";
                    343:                                } else {
                    344:                                        mnemonic = ":jmp";
                    345:                                }
                    346:                        } else if (lo6 == 0x31) {
                    347:                                mnemonic = ":jmp.n";
                    348:                        } else if (lo6 == 0x32) {
                    349:                                mnemonic = ":jsr";
                    350:                        } else if (lo6 == 0x33) {
                    351:                                mnemonic = ":jsr.n";
                    352:                        } else if (lo6 == 0x3f) {
                    353:                                mnemonic = ":rte";
                    354:                        }
                    355:                        break;
                    356:                 }
                    357:                 case 0xe:      mnemonic = ":tbnd";     break;
                    358:                 default:
                    359:                        break;
                    360:                }
                    361:                desc += string_format("(%08x%-7s) -> $%08x", e.inst, mnemonic, e.to);
                    362:        }
                    363:        return desc;
                    364: }
1.1.1.7 ! root      365: 
        !           366: 
        !           367: //
        !           368: // XP ブランチ履歴
        !           369: //
        !           370: 
        !           371: // XP ブランチ履歴では、通常ブランチ、例外発生、例外ベクタによるジャンプの
        !           372: // 3つを区別する。
        !           373: //
        !           374: // 通常の分岐
        !           375: //     from は下位 16 ビットが分岐元 PC
        !           376: //     to   は下位 16 ビットが分岐先 PC
        !           377: //     inst の最上位ビットが %0 で区別する。
        !           378: //     inst の下位 16 ビットに命令を上詰めで。例えば
        !           379: //     CALL (1バイト命令 CD nn nn) なら $0000'cd00、
        !           380: //     RETI (2バイト命令 ED 4D) なら $0000'ed4d。
        !           381: //
        !           382: // 例外発生
        !           383: //     from は下位 16 ビットが例外発生時の PC
        !           384: //     to   は $ffffffff ならこのエントリはベクタ方式の例外発生時側を示す、
        !           385: //             そうでなければダイレクト方式で下位 16 ビットが分岐先 PC
        !           386: //     inst の最上位ビットが %1 で inst が $ffffffff でなければ
        !           387: //     下位に優先度(0-15)。
        !           388: //
        !           389: // 例外ベクタジャンプの場合
        !           390: //     from はベクタアドレス
        !           391: //     to   は分岐先 PC、
        !           392: //     inst が $ffffffff で区別する。
        !           393: 
        !           394: // コンストラクタ
        !           395: BranchHistory_hd64180::BranchHistory_hd64180(int objid_)
        !           396:        : inherited(objid_)
        !           397: {
        !           398:        monitor.SetSize(48, 1 + 32); // ヘッダ1行とエントリ数
        !           399:        x_count = 38;
        !           400: }
        !           401: 
        !           402: // デストラクタ
        !           403: BranchHistory_hd64180::~BranchHistory_hd64180()
        !           404: {
        !           405: }
        !           406: 
        !           407: // ヘッダ文字列を返す。
        !           408: std::string
        !           409: BranchHistory_hd64180::FormatHeader() const
        !           410: {
        !           411:        if (is_exhist) {
        !           412:                //      01234567890123456789012345678901234567890123456789
        !           413:                return "No. From  Exception                   Iteration";
        !           414:        } else {
        !           415:                //      01234567890123456789012345678901234567890123456789
        !           416:                return "No. From Instruction           ToAddr Iteration";
        !           417:        }
        !           418: }
        !           419: 
        !           420: // 1エントリ分の表示内容作成
        !           421: std::string
        !           422: BranchHistory_hd64180::FormatEntry(const BranchEntry& e)
        !           423: {
        !           424:        // 0         1         2         3         4         5
        !           425:        // 012345678901234567890123456789012345678901234567890
        !           426:        // No. From Instruction           ToAddr Iteration
        !           427:        // 001 0123(0000:CALL NZ)      -> $0234 x123456899
        !           428:        // No. From Exception
        !           429:        // 002 0123<00> Timer Overflow
        !           430:        // 003 0038(vector fetch)      -> $0000
        !           431: 
        !           432:        std::string desc = strhex(e.from, 4);
        !           433: 
        !           434:        if (e.inst == 0xffffffff) {
        !           435:                // 例外ベクタフェッチしてジャンプ
        !           436:                desc += string_format("(vector fetch)      -> $%04x", e.to);
        !           437:        } else if ((int32)e.inst < 0) {
        !           438:                // 例外発生
        !           439:                uint32 vector = e.inst & 0xff;
        !           440:                desc += string_format("<%2d>%-15s",
        !           441:                        vector, MPU64180Device::InterruptName[vector]);
        !           442:                // 例外履歴には宛先は出さないほうに統一。
        !           443:                // ブランチ履歴でも、ベクタ方式なら宛先不要。
        !           444:                if (is_exhist == false && e.to != -1) {
        !           445:                        desc += string_format(" -> $%04x", e.to);
        !           446:                }
        !           447:        } else {
        !           448:                // ブランチ
        !           449:                std::string mnemonic;
        !           450:                uint32 inst = e.inst & 0xffff;
        !           451:                if (inst == 0x1000) {
        !           452:                        mnemonic = ":DJNZ";
        !           453:                } else if (inst == 0x1800) {
        !           454:                        mnemonic = ":JR";
        !           455:                } else if (inst == 0xc300) {
        !           456:                        mnemonic = ":JP";
        !           457:                } else if (inst == 0xc900) {
        !           458:                        mnemonic = ":RET";
        !           459:                } else if (inst == 0xcd00) {
        !           460:                        mnemonic = ":CALL";
        !           461:                } else if (inst == 0xe900) {
        !           462:                        mnemonic = ":JP (HL)";
        !           463:                } else if (inst == 0xed45) {
        !           464:                        mnemonic = ":RETN";
        !           465:                } else if (inst == 0xed4d) {
        !           466:                        mnemonic = ":RETI";
        !           467:                } else if (inst == 0xdde9) {
        !           468:                        mnemonic = ":JP (IX)";
        !           469:                } else if (inst == 0xfde9) {
        !           470:                        mnemonic = ":JP (IY)";
        !           471:                } else if ((inst & 0xe700) == 0x2000) {
        !           472:                        mnemonic = ":JR " + fstr((inst >> 11) & 3);
        !           473:                } else if ((inst & 0xc700) == 0xc000) {
        !           474:                        mnemonic = ":RET " + fstr((inst >> 11) & 7);
        !           475:                } else if ((inst & 0xc700) == 0xc200) {
        !           476:                        mnemonic = ":JP " + fstr((inst >> 11) & 7);
        !           477:                } else if ((inst & 0xc700) == 0xc400) {
        !           478:                        mnemonic = ":CALL " + fstr((inst >> 11) & 7);
        !           479:                } else if ((inst & 0xc700) == 0xc700) {
        !           480:                        mnemonic = string_format(":RST %02xH", (inst >> 8) & 0x38);
        !           481:                }
        !           482:                desc += string_format("(%04x%-8s)      -> $%04x",
        !           483:                        inst, mnemonic.c_str(), e.to);
        !           484:        }
        !           485:        return desc;
        !           486: }
        !           487: 
        !           488: /*static*/ std::string
        !           489: BranchHistory_hd64180::fstr(int f)
        !           490: {
        !           491:        static const char fff[] =
        !           492:                "NZ\0\0"
        !           493:                "Z\0\0\0"
        !           494:                "NC\0\0"
        !           495:                "C\0\0\0"
        !           496:                "PO\0\0"
        !           497:                "PE\0\0"
        !           498:                "P\0\0\0"
        !           499:                "M";
        !           500: 
        !           501:        return &fff[f * 4];
        !           502: }

unix.superglobalmegacorp.com

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