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

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 "m68030core.h"
                     13: #include "m88100.h"
1.1.1.5   root       14: #include "vectortable.h"
1.1       root       15: 
                     16: // コンストラクタ
1.1.1.4   root       17: BranchHistory::BranchHistory(bool is_exhist_)
1.1.1.5   root       18:        : inherited(is_exhist_ ? "(ExceptionHistory)" : "(BranchHistory)")
1.1       root       19: {
1.1.1.4   root       20:        is_exhist = is_exhist_;
                     21: 
1.1.1.5   root       22:        // ログは不要
                     23:        ClearAlias();
                     24: 
                     25:        monitor.func = ToMonitorCallback(&BranchHistory::MonitorUpdate);
1.1.1.6 ! root       26:        monitor.SetSize(55, 1 + 32); // ヘッダ1行とエントリ数
        !            27:        monitor.SetMaxHeight(1 + 256);
1.1.1.4   root       28:        if (is_exhist) {
                     29:                monitor.Regist(ID_SUBWIN_EXHIST);
                     30:        } else {
                     31:                monitor.Regist(ID_SUBWIN_BRHIST);
                     32:        }
1.1       root       33: }
                     34: 
                     35: // デストラクタ
                     36: BranchHistory::~BranchHistory()
                     37: {
                     38: }
                     39: 
                     40: // 初期化
                     41: void
                     42: BranchHistory::Clear()
                     43: {
                     44:        top = 0;
                     45:        for (int i = 0; i < countof(entry); i++) {
                     46:                BranchEntry& e = entry[i];
                     47:                e.count = 0;
                     48:                e.from  = 0xffffffff;
                     49:                e.to    = 0xffffffff;
                     50:                e.inst  = 0;
                     51:        }
                     52: }
                     53: 
                     54: // 使用中のエントリ数を取得する
                     55: int
                     56: BranchHistory::GetUsed() const
                     57: {
                     58:        int i = 0;
                     59: 
                     60:        // top の位置から一巡するまで。有効エントリは count > 0。
                     61:        for (; i < 256; i++) {
                     62:                if (entry[(256 + top - i) % 256].count == 0) {
                     63:                        break;
                     64:                }
                     65:        }
                     66:        return i;
                     67: }
                     68: 
                     69: // モニタ更新
                     70: void
1.1.1.4   root       71: BranchHistory::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root       72: {
                     73:        uint8 t;
                     74:        int y;
                     75:        int ydelta;
                     76:        int row;
                     77: 
                     78:        // userdata は表示開始位置と各種フラグ。
                     79:        // 下位 32bit が表示開始位置で、0 なら先頭のエントリから、1 なら先頭の
1.1.1.4   root       80:        // 一つ次のエントリから、…を表す (表示行数は screen の高さ分)。
1.1       root       81:        // BottomToTop が %1 なら並び順を下から上に変える (コンソール用)。
1.1.1.4   root       82:        bool bottom_to_top = (screen.userdata & BottomToTop);
                     83:        int pos = (int)screen.userdata;
1.1       root       84: 
                     85:        // 0         1         2         3         4         5         6
                     86:        // 0123456789012345678901234567890123456789012345678901234567890123456789
                     87:        // No. FromAddr  Instruction          ToAddr    Iteration
                     88:        // 001 U:01234567(01234567:bcnd.n) -> $01234567 x123456789
                     89:        // 001 U:01234567(0123:trap )      -> $01234567 x123456789
                     90:        // 002 S:01234567<  2> Bus Error
                     91:        // 002 S:01234567< 69> MFP Timer-C
                     92:        //                     01234567890123456789012
                     93: 
1.1.1.4   root       94:        screen.Clear();
                     95:        row = screen.GetRow();
1.1       root       96: 
                     97:        // 最初の1行は常にヘッダ
                     98:        if (is_exhist) {
1.1.1.4   root       99:                screen.Print(0, 0, "No. FromAddr   Vec. Exception");
                    100:                screen.Print(45, 0, "Iteration");
1.1       root      101:        } else {
1.1.1.4   root      102:                screen.Print(0, 0, "No. FromAddr  Instruction");
                    103:                screen.Print(35, 0, "ToAddr    Iteration");
1.1       root      104:        }
                    105: 
                    106:        // pos は最新を 0 とした通し番号。(スクロールしてたら開始が 0 とは限らない)
                    107:        // t が entry[] 上の現在位置。
                    108:        // y は表示座標。(上から表示か下から表示かが変わる)
                    109:        t = top - pos;
                    110:        int pos_end = pos + row - 1;
                    111:        if (bottom_to_top == false) {
                    112:                y = 1;
                    113:                ydelta = 1;
                    114:        } else {
                    115:                y = row - 1;
                    116:                ydelta = -1;
                    117:        }
                    118:        for (; pos < pos_end; pos++, y += ydelta) {
                    119:                BranchEntry& e = entry[t--];
                    120:                if (e.count == 0) {
                    121:                        continue;
                    122:                }
                    123:                std::string str = FormatEntry(e);
1.1.1.4   root      124:                screen.Print(0, y, "%3d %s", pos, str.c_str());
1.1       root      125:                if (e.count > 1) {
1.1.1.4   root      126:                        screen.Print(45, y, "x%9u", e.count);
1.1       root      127:                }
                    128:        }
                    129: }
                    130: 
                    131: 
                    132: 
                    133: //
                    134: // m680x0 ブランチ履歴 (どこに置くのがよいか)
                    135: //
                    136: 
                    137: // m680x0 ブランチ履歴では、通常ブランチ、例外発生、例外ベクタによる
                    138: // ジャンプの3つを区別する。
                    139: //
                    140: // 通常の分岐:
1.1.1.3   root      141: //     from は上位31ビットが分岐元 PC、最下位ビットが S/U、
                    142: //     to   は32ビット全体が分岐先 PC、
                    143: //     inst の上位16ビットに命令の1ワード目。
1.1       root      144: //     inst の $8000 が立っていないことで区別する。
                    145: //
                    146: // 例外発生:
1.1.1.3   root      147: //     from は上位31ビットが例外発生時の PC、最下位ビットが S/U、
                    148: //     to   は不問(通常 0 をセットすること)、
1.1       root      149: //     inst は $00008LVV で $8000 が例外フラグ、VV がベクタ番号である。
                    150: //     ベクタ番号が $00 だと次項(ベクタによる分岐)と区別つかなくなってしまう
                    151: //     ため、リセット例外 (ベクタ番号0) は V=$01 で記録する。
                    152: //     L は割り込みなら割り込みレベル。
                    153: //     inst に $8000 が立っていて、かつ $8000 と一致しないことで区別する。
                    154: //
                    155: // 例外ベクタによる分岐 (例外処理の最後に起きる):
1.1.1.3   root      156: //     from はベクタアドレス、
                    157: //     to   は分岐先 (0 も起こりえる)、
                    158: //     inst は $00008000。
1.1       root      159: //     inst が $00008000 と一致することで区別する (ビットが立っているではない)。
                    160: 
                    161: // コンストラクタ
1.1.1.4   root      162: BranchHistory_m680x0::BranchHistory_m680x0(bool mode_)
                    163:        : inherited(mode_)
1.1       root      164: {
                    165: }
                    166: 
                    167: // デストラクタ
                    168: BranchHistory_m680x0::~BranchHistory_m680x0()
                    169: {
                    170: }
                    171: 
                    172: // 1エントリ分の表示内容作成
                    173: std::string
                    174: BranchHistory_m680x0::FormatEntry(const BranchEntry& e)
                    175: {
                    176:        // m68k では from の最下位1ビットを S/U として使う
                    177:        std::string desc = string_format("%c:%08x",
                    178:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    179: 
                    180:        if ((e.inst & 0x8000)) {
                    181:                if ((e.inst & 0x7fff) != 0) {
                    182:                        // 例外発生記録
                    183:                        // 発生アドレスとベクタ(と割り込みレベル)を表示
                    184:                        uint32 vector = e.inst & 0xff;
                    185:                        if (vector == 1) {
                    186:                                vector = 0;
                    187:                        }
                    188:                        // とりあえず
1.1.1.5   root      189:                        const char *name = gVectorTable->GetExceptionName(vector);
                    190:                        desc += string_format("<%3d> %s", vector, name ?: "");
1.1       root      191:                        // XXX TODO 割り込みレベル
                    192:                } else {
                    193:                        // 例外ベクタフェッチしてジャンプ
                    194:                        desc += string_format("(vector fetch)    -> $%08x", e.to);
                    195:                }
                    196:        } else {
                    197:                // ブランチ
                    198:                const char *mnemonic;
                    199:                uint32 inst = e.inst >> 16;
                    200:                if (inst == 0x4e73) {
                    201:                        mnemonic = ":rte";
                    202:                } else if (inst == 0x4e75) {
                    203:                        mnemonic = ":rts";
                    204:                } else if (inst == 0x4e77) {
                    205:                        mnemonic = ":rtr";
                    206:                } else if ((inst & 0xffc0) == 0x4e80) {
                    207:                        mnemonic = ":jsr";
                    208:                } else if ((inst & 0xffc0) == 0x4ec0) {
                    209:                        mnemonic = ":jmp";
                    210:                } else if ((inst & 0xfff8) == 0x51c8) {
                    211:                        mnemonic = ":dbra";
                    212:                } else if ((inst & 0xf0f8) == 0x50c8) {
                    213:                        mnemonic = ":dbcc";
                    214:                } else if ((inst & 0xff00) == 0x6000) {
                    215:                        mnemonic = ":bra";
                    216:                } else if ((inst & 0xff00) == 0x6100) {
                    217:                        mnemonic = ":bsr";
                    218:                } else if ((inst & 0xf000) == 0x6000) {
                    219:                        mnemonic = ":bcc";
                    220:                } else if ((inst & 0xfff8) == 0xf248) {
                    221:                        mnemonic = ":fdbcc";
                    222:                } else if ((inst & 0xff80) == 0xf280) {
                    223:                        mnemonic = ":fbcc";
                    224:                } else {
                    225:                        mnemonic = "";
                    226:                }
                    227:                desc += string_format("(%04x%-6s)      -> $%08x", inst, mnemonic, e.to);
                    228:        }
                    229:        return desc;
                    230: }
                    231: 
                    232: 
                    233: //
                    234: // m88xx0 ブランチ履歴 (どこに置くのがよいか)
                    235: //
                    236: 
                    237: // m88xx0 ブランチ履歴では、通常ブランチ、例外発生の2つを区別する。
                    238: // m68k は例外ベクタに書いてあるアドレスに飛ぶのでもう1種類分けてあったが、
                    239: // m88k は例外ベクタを直接実行するのでそれは不要。
                    240: //
                    241: // 通常の分岐:
1.1.1.3   root      242: //     from は上位30ビットが分岐元 XIP、最下位ビットが S/U、
                    243: //     to   は32ビット全体が分岐先アドレス、
                    244: //     inst は命令ワード。
1.1       root      245: //
                    246: // 例外発生:
1.1.1.3   root      247: //     from は上位30ビットが例外発生時の XIP、最下位ビットが S/U、
                    248: //     to   は 0。
                    249: //     inst は $fc000VVV で VVV (9ビット)がベクタ番号。
                    250: //     命令ワードとは衝突しない (instruction.txt 参照)。
1.1       root      251: 
                    252: // コンストラクタ
1.1.1.4   root      253: BranchHistory_m88xx0::BranchHistory_m88xx0(bool mode_)
                    254:        : inherited(mode_)
1.1       root      255: {
                    256: }
                    257: 
                    258: // デストラクタ
                    259: BranchHistory_m88xx0::~BranchHistory_m88xx0()
                    260: {
                    261: }
                    262: 
                    263: // 1エントリ分の表示内容作成
                    264: std::string
                    265: BranchHistory_m88xx0::FormatEntry(const BranchEntry& e)
                    266: {
                    267:        // m88k では from の最下位1ビットを S/U として使う
                    268:        std::string desc = string_format("%c:%08x",
                    269:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
                    270: 
                    271:        if (e.inst >= 0xfc000000 && e.to == 0) {
                    272:                // 例外発生記録
                    273:                // 発生アドレスとベクタを表示
                    274:                uint32 vector = e.inst & 0x1ff;
1.1.1.5   root      275:                const char *name = gVectorTable->GetExceptionName(vector);
1.1       root      276:                desc += string_format("<%3d> %s", vector, name ?: "");
                    277:                if (vector == 450) {
                    278:                        // OpenBSD のシステムコール番号
                    279:                        desc += string_format("(%d)", (e.inst >> 12) & 0xfff);
                    280:                }
                    281:        } else if (e.inst >= 0xc0000000) {
                    282:                // ブランチ
                    283:                const char *mnemonic = "";
                    284:                uint32 up4 = (e.inst >> 26) & 0xf;
                    285:                switch (up4) {
                    286:                 case 0:        mnemonic = ":br";               break;
                    287:                 case 1:        mnemonic = ":br.n";             break;
                    288:                 case 2:        mnemonic = ":bsr";              break;
                    289:                 case 3:        mnemonic = ":bsr.n";    break;
                    290:                 case 4:        mnemonic = ":bb0";              break;
                    291:                 case 5:        mnemonic = ":bb0.n";    break;
1.1.1.2   root      292:                 case 6:        mnemonic = ":bb1";              break;
1.1       root      293:                 case 7:        mnemonic = ":bb1.n";    break;
                    294: 
                    295:                 case 0xa:      mnemonic = ":bcnd";             break;
                    296:                 case 0xb:      mnemonic = ":bcnd.n";   break;
                    297:                 case 0xc: {
                    298:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
                    299:                        if (lo6 == 0x34) {
                    300:                                mnemonic = ":tb0";
                    301:                        } else if (lo6 == 0x36) {
                    302:                                mnemonic = ":tb1";
                    303:                        } else if (lo6 == 0x3a) {
                    304:                                mnemonic = ":tcnd";
                    305:                        }
                    306:                        break;
                    307:                 }
                    308:                 case 0xd: {
                    309:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
                    310:                        if (lo6 == 0x30) {
                    311:                                if ((e.inst & 0x1f) == 1) {
                    312:                                        mnemonic = ":jmp r1";
                    313:                                } else {
                    314:                                        mnemonic = ":jmp";
                    315:                                }
                    316:                        } else if (lo6 == 0x31) {
                    317:                                mnemonic = ":jmp.n";
                    318:                        } else if (lo6 == 0x32) {
                    319:                                mnemonic = ":jsr";
                    320:                        } else if (lo6 == 0x33) {
                    321:                                mnemonic = ":jsr.n";
                    322:                        } else if (lo6 == 0x3f) {
                    323:                                mnemonic = ":rte";
                    324:                        }
                    325:                        break;
                    326:                 }
                    327:                 case 0xe:      mnemonic = ":tbnd";     break;
                    328:                 default:
                    329:                        break;
                    330:                }
                    331:                desc += string_format("(%08x%-7s) -> $%08x", e.inst, mnemonic, e.to);
                    332:        }
                    333:        return desc;
                    334: }

unix.superglobalmegacorp.com

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