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