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