|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.