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

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"
        !            10: #include "m68030core.h"
        !            11: #include "m88100.h"
        !            12: #include "mystring.h"
        !            13: 
        !            14: // コンストラクタ
        !            15: BranchHistory::BranchHistory()
        !            16: {
        !            17:        monitor_size = nnSize(55, 33);
        !            18: }
        !            19: 
        !            20: // デストラクタ
        !            21: BranchHistory::~BranchHistory()
        !            22: {
        !            23: }
        !            24: 
        !            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: 
        !            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)
        !            57: {
        !            58:        uint8 t;
        !            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;
        !            72: 
        !            73:        // 0         1         2         3         4         5         6
        !            74:        // 0123456789012345678901234567890123456789012345678901234567890123456789
        !            75:        // No. FromAddr  Instruction          ToAddr    Iteration
        !            76:        // 001 U:01234567(01234567:bcnd.n) -> $01234567 x123456789
        !            77:        // 001 U:01234567(0123:trap )      -> $01234567 x123456789
        !            78:        // 002 S:01234567<  2> Bus Error
        !            79:        // 002 S:01234567< 69> MFP Timer-C
        !            80:        //                     01234567890123456789012
        !            81: 
        !            82:        monitor.Clear();
        !            83:        row = monitor.GetRow();
        !            84: 
        !            85:        // 最初の1行は常にヘッダ
        !            86:        if (is_exhist) {
        !            87:                monitor.Print(0, 0, "No. FromAddr   Vec. Exception");
        !            88:                monitor.Print(45, 0, "Iteration");
        !            89:        } else {
        !            90:                monitor.Print(0, 0, "No. FromAddr  Instruction");
        !            91:                monitor.Print(35, 0, "ToAddr    Iteration");
        !            92:        }
        !            93: 
        !            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) {
        !           107:                BranchEntry& e = entry[t--];
        !           108:                if (e.count == 0) {
        !           109:                        continue;
        !           110:                }
        !           111:                std::string str = FormatEntry(e);
        !           112:                monitor.Print(0, y, "%3d %s", pos, str.c_str());
        !           113:                if (e.count > 1) {
        !           114:                        monitor.Print(45, 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: // 例外発生:
        !           133: //     from は例外発生時の PC、to は不問(通常 0 をセットすること)、
        !           134: //     inst は $00008LVV で $8000 が例外フラグ、VV がベクタ番号である。
        !           135: //     ベクタ番号が $00 だと次項(ベクタによる分岐)と区別つかなくなってしまう
        !           136: //     ため、リセット例外 (ベクタ番号0) は V=$01 で記録する。
        !           137: //     L は割り込みなら割り込みレベル。
        !           138: //     inst に $8000 が立っていて、かつ $8000 と一致しないことで区別する。
        !           139: //
        !           140: // 例外ベクタによる分岐 (例外処理の最後に起きる):
        !           141: //     from はベクタアドレス、to は分岐先 (0 も起こりえる)、inst は $00008000。
        !           142: //     inst が $00008000 と一致することで区別する (ビットが立っているではない)。
        !           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:        // m68k では from の最下位1ビットを S/U として使う
        !           159:        std::string desc = string_format("%c:%08x",
        !           160:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
        !           161: 
        !           162:        if ((e.inst & 0x8000)) {
        !           163:                if ((e.inst & 0x7fff) != 0) {
        !           164:                        // 例外発生記録
        !           165:                        // 発生アドレスとベクタ(と割り込みレベル)を表示
        !           166:                        uint32 vector = e.inst & 0xff;
        !           167:                        if (vector == 1) {
        !           168:                                vector = 0;
        !           169:                        }
        !           170:                        // とりあえず
        !           171:                        desc += string_format("<%3d> %s", vector,
        !           172:                                m68030_get_exception_name(vector));
        !           173:                        // XXX TODO 割り込みレベル
        !           174:                } else {
        !           175:                        // 例外ベクタフェッチしてジャンプ
        !           176:                        desc += string_format("(vector fetch)    -> $%08x", e.to);
        !           177:                }
        !           178:        } else {
        !           179:                // ブランチ
        !           180:                const char *mnemonic;
        !           181:                uint32 inst = e.inst >> 16;
        !           182:                if (inst == 0x4e73) {
        !           183:                        mnemonic = ":rte";
        !           184:                } else if (inst == 0x4e75) {
        !           185:                        mnemonic = ":rts";
        !           186:                } else if (inst == 0x4e77) {
        !           187:                        mnemonic = ":rtr";
        !           188:                } else if ((inst & 0xffc0) == 0x4e80) {
        !           189:                        mnemonic = ":jsr";
        !           190:                } else if ((inst & 0xffc0) == 0x4ec0) {
        !           191:                        mnemonic = ":jmp";
        !           192:                } else if ((inst & 0xfff8) == 0x51c8) {
        !           193:                        mnemonic = ":dbra";
        !           194:                } else if ((inst & 0xf0f8) == 0x50c8) {
        !           195:                        mnemonic = ":dbcc";
        !           196:                } else if ((inst & 0xff00) == 0x6000) {
        !           197:                        mnemonic = ":bra";
        !           198:                } else if ((inst & 0xff00) == 0x6100) {
        !           199:                        mnemonic = ":bsr";
        !           200:                } else if ((inst & 0xf000) == 0x6000) {
        !           201:                        mnemonic = ":bcc";
        !           202:                } else if ((inst & 0xfff8) == 0xf248) {
        !           203:                        mnemonic = ":fdbcc";
        !           204:                } else if ((inst & 0xff80) == 0xf280) {
        !           205:                        mnemonic = ":fbcc";
        !           206:                } else {
        !           207:                        mnemonic = "";
        !           208:                }
        !           209:                desc += string_format("(%04x%-6s)      -> $%08x", inst, mnemonic, e.to);
        !           210:        }
        !           211:        return desc;
        !           212: }
        !           213: 
        !           214: 
        !           215: //
        !           216: // m88xx0 ブランチ履歴 (どこに置くのがよいか)
        !           217: //
        !           218: 
        !           219: // m88xx0 ブランチ履歴では、通常ブランチ、例外発生の2つを区別する。
        !           220: // m68k は例外ベクタに書いてあるアドレスに飛ぶのでもう1種類分けてあったが、
        !           221: // m88k は例外ベクタを直接実行するのでそれは不要。
        !           222: //
        !           223: // 通常の分岐:
        !           224: //     from は分岐元 XIP、to は分岐先アドレス、inst は命令ワード。
        !           225: //
        !           226: // 例外発生:
        !           227: //     from は例外発生時の XIP、to は 0。inst は $fc000VVV で VVV (9ビット)が
        !           228: //     ベクタ番号。命令ワードとは衝突しない (instruction.txt 参照)。
        !           229: 
        !           230: // コンストラクタ
        !           231: BranchHistory_m88xx0::BranchHistory_m88xx0()
        !           232: {
        !           233: }
        !           234: 
        !           235: // デストラクタ
        !           236: BranchHistory_m88xx0::~BranchHistory_m88xx0()
        !           237: {
        !           238: }
        !           239: 
        !           240: // 1エントリ分の表示内容作成
        !           241: std::string
        !           242: BranchHistory_m88xx0::FormatEntry(const BranchEntry& e)
        !           243: {
        !           244:        // m88k では from の最下位1ビットを S/U として使う
        !           245:        std::string desc = string_format("%c:%08x",
        !           246:                (e.from & 1) ? 'S' : 'U', (e.from & ~1));
        !           247: 
        !           248:        if (e.inst >= 0xfc000000 && e.to == 0) {
        !           249:                // 例外発生記録
        !           250:                // 発生アドレスとベクタを表示
        !           251:                uint32 vector = e.inst & 0x1ff;
        !           252:                const char *name = m88kcpu::GetExceptionName(vector);
        !           253:                desc += string_format("<%3d> %s", vector, name ?: "");
        !           254:                if (vector == 450) {
        !           255:                        // OpenBSD のシステムコール番号
        !           256:                        desc += string_format("(%d)", (e.inst >> 12) & 0xfff);
        !           257:                }
        !           258:        } else if (e.inst >= 0xc0000000) {
        !           259:                // ブランチ
        !           260:                const char *mnemonic = "";
        !           261:                uint32 up4 = (e.inst >> 26) & 0xf;
        !           262:                switch (up4) {
        !           263:                 case 0:        mnemonic = ":br";               break;
        !           264:                 case 1:        mnemonic = ":br.n";             break;
        !           265:                 case 2:        mnemonic = ":bsr";              break;
        !           266:                 case 3:        mnemonic = ":bsr.n";    break;
        !           267:                 case 4:        mnemonic = ":bb0";              break;
        !           268:                 case 5:        mnemonic = ":bb0.n";    break;
        !           269:                 case 6:        mnemonic = ":bb1";              break;
        !           270:                 case 7:        mnemonic = ":bb1.n";    break;
        !           271: 
        !           272:                 case 0xa:      mnemonic = ":bcnd";             break;
        !           273:                 case 0xb:      mnemonic = ":bcnd.n";   break;
        !           274:                 case 0xc: {
        !           275:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
        !           276:                        if (lo6 == 0x34) {
        !           277:                                mnemonic = ":tb0";
        !           278:                        } else if (lo6 == 0x36) {
        !           279:                                mnemonic = ":tb1";
        !           280:                        } else if (lo6 == 0x3a) {
        !           281:                                mnemonic = ":tcnd";
        !           282:                        }
        !           283:                        break;
        !           284:                 }
        !           285:                 case 0xd: {
        !           286:                        uint32 lo6 = (e.inst >> 10) & 0x3f;
        !           287:                        if (lo6 == 0x30) {
        !           288:                                if ((e.inst & 0x1f) == 1) {
        !           289:                                        mnemonic = ":jmp r1";
        !           290:                                } else {
        !           291:                                        mnemonic = ":jmp";
        !           292:                                }
        !           293:                        } else if (lo6 == 0x31) {
        !           294:                                mnemonic = ":jmp.n";
        !           295:                        } else if (lo6 == 0x32) {
        !           296:                                mnemonic = ":jsr";
        !           297:                        } else if (lo6 == 0x33) {
        !           298:                                mnemonic = ":jsr.n";
        !           299:                        } else if (lo6 == 0x3f) {
        !           300:                                mnemonic = ":rte";
        !           301:                        }
        !           302:                        break;
        !           303:                 }
        !           304:                 case 0xe:      mnemonic = ":tbnd";     break;
        !           305:                 default:
        !           306:                        break;
        !           307:                }
        !           308:                desc += string_format("(%08x%-7s) -> $%08x", e.inst, mnemonic, e.to);
        !           309:        }
        !           310:        return desc;
        !           311: }

unix.superglobalmegacorp.com

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