Annotation of nono/lib/branchhistory.cpp, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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