|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ベクタテーブル (モニタ)
9: //
10:
11: #include "vectortable.h"
12: #include "mainapp.h"
1.1.1.3 root 13: #include "mainbus.h"
1.1.1.6 root 14: #include "monitor.h"
1.1 root 15: #include "mpu.h"
16:
17: // コンストラクタ
1.1.1.2 root 18: VectorTable::VectorTable(VMType vmtype)
1.1.1.3 root 19: : inherited(OBJ_VECTOR_TABLE)
1.1 root 20: {
21: // ログは不要
22: ClearAlias();
23:
1.1.1.8 root 24: monitor = gMonitorManager->Regist(ID_SUBWIN_VECTOR, this);
25:
1.1 root 26: // 表示名を作成。それぞれ微妙に処理が違う…
1.1.1.8 root 27: int w = 75;
1.1 root 28: switch (vmtype) {
1.1.1.2 root 29: case VMType::X68030:
30: case VMType::LUNA1:
1.1.1.3 root 31: case VMType::NEWS:
1.1.1.4 root 32: case VMType::VIRT68K:
1.1.1.6 root 33: InitTableM680x0(vmtype);
1.1.1.9 ! root 34: monitor->SetCallback(&VectorTable::MonitorScreenM680x0);
1.1 root 35: break;
1.1.1.2 root 36: case VMType::LUNA88K:
1.1 root 37: InitTableLuna88k();
1.1.1.9 ! root 38: monitor->SetCallback(&VectorTable::MonitorScreenM88xx0);
1.1.1.8 root 39: // ベクタが(16進数で)3桁必要。
40: w++;
1.1 root 41: break;
1.1.1.2 root 42: default:
43: PANIC("invalid vmtype %d", (int)vmtype);
1.1 root 44: }
45:
1.1.1.8 root 46: monitor->SetSize(w, 1 + 32); // ヘッダの1行と全エントリ数
1.1.1.6 root 47: monitor->SetMaxHeight(1 + Size());
1.1 root 48: }
49:
1.1.1.6 root 50: // m68k 機種の表示名テーブル初期化。コンストラクタの一部。
1.1 root 51: void
1.1.1.6 root 52: VectorTable::InitTableM680x0(VMType vmtype)
1.1 root 53: {
54: nametable.clear();
55: nametable.resize(256);
56:
1.1.1.6 root 57: // まず m680x0 標準の名称で埋める
1.1 root 58: for (int v = 0; v < 64; v++) {
1.1.1.6 root 59: if (name_m680x0[v]) {
60: nametable[v] = name_m680x0[v];
1.1 root 61: }
62: }
63:
1.1.1.3 root 64: // 機種ごとに必要なところだけ上書き
65: const std::map<int, const char * const> *names;
1.1.1.6 root 66: switch (vmtype) {
67: case VMType::X68030:
1.1.1.3 root 68: names = &name_x68030;
1.1.1.6 root 69: break;
70: case VMType::LUNA1:
1.1.1.3 root 71: names = &name_luna1;
1.1.1.6 root 72: break;
73: case VMType::NEWS:
1.1.1.3 root 74: names = &name_news;
1.1.1.6 root 75: break;
76: case VMType::VIRT68K:
77: names = &name_virt68k;
78: break;
79: default:
80: names = NULL;
81: break;
1.1.1.3 root 82: }
1.1.1.6 root 83: if (names) {
84: for (const auto& p : *names) {
85: int v = p.first;
86: const char *name = p.second;
87: nametable[v] = name;
88: }
1.1 root 89: }
90: }
91:
1.1.1.3 root 92: // LUNA-88K の表示名テーブルを初期化。コンストラクタの一部。
1.1 root 93: void
94: VectorTable::InitTableLuna88k()
95: {
96: nametable.clear();
97: nametable.resize(512);
98:
1.1.1.8 root 99: for (const auto& p : name_luna88k) {
100: int v = p.first;
101: const char *name = p.second;
102: nametable[v] = name;
1.1 root 103: }
104: }
105:
1.1.1.3 root 106: // デストラクタ
107: VectorTable::~VectorTable()
108: {
109: }
110:
111: // 初期化
112: bool
113: VectorTable::Init()
114: {
115: mainbus = GetMainbusDevice();
116: mpu = GetMPUDevice();
117:
118: return true;
119: }
120:
1.1 root 121: // 例外名を返す (例外履歴用)。
122: // 名前がなければ NULL を返す。
123: const char *
124: VectorTable::GetExceptionName(int vector) const
125: {
126: assertmsg(0 <= vector && vector < nametable.size(), "vector=%d", vector);
127:
128: if (__predict_false(vector < 2)) {
1.1.1.2 root 129: if (gMainApp.Has(VMCap::M68K)) {
1.1 root 130: // ベクタテーブル的には 0:"Reset(SP)"、1:"Reset(PC)" のほうが
131: // 分かりやすいが、例外の名前は 0 が "Reset Exception" で
132: // 1 は存在しない。
133: if (vector == 0) {
134: return "Reset Exception";
135: } else {
136: return "(vector 1?)";
137: }
138: }
139: }
140:
1.1.1.7 root 141: return nametable[vector];
1.1 root 142: }
143:
1.1.1.8 root 144: // モニタ更新 (M680x0)
1.1 root 145: void
1.1.1.9 ! root 146: VectorTable::MonitorScreenM680x0(Monitor *, TextScreen& screen)
1.1 root 147: {
1.1.1.5 root 148: // 0 1 2 3 4 5 6 7
149: // 012345678901234567890123456789012345678901234567890123456789012345678901234
150: // No. Offset Address Name >< Count
151: // $02( 2) $0008 $12345678 0123456789012345678901201234567890123456789012345
1.1 root 152:
1.1.1.3 root 153: uint32 vbr = mpu->GetVBR();
1.1 root 154:
155: // userdata が表示開始位置
156: int v = (int)screen.userdata;
157: int row = screen.GetRow();
158: int vend = v + row - 1;
159:
160: screen.Clear();
161:
162: // 最初の1行は常にヘッダ
163: screen.Print(0, 0, "No. Offset Address Name");
1.1.1.5 root 164: screen.Print(70, 0, "Count");
1.1 root 165:
166: for (int y = 1; v < vend; v++, y++) {
1.1.1.5 root 167: screen.Print(0, y, "$%02x(%3u) $%04x", v, v, v * 4);
168: busdata addr = mainbus->Peek4(vbr + v * 4);
1.1.1.4 root 169: if (__predict_false(addr.IsBusErr())) {
1.1 root 170: screen.Print(16, y, "BusErr");
171: } else {
1.1.1.4 root 172: screen.Print(16, y, "$%08x", addr.Data());
1.1 root 173: }
1.1.1.7 root 174: screen.Print(26, y, "%-23s", nametable[v] ?: "");
1.1.1.5 root 175: screen.Print(49, y, "%26s",
176: format_number(mpu->excep_counter[v]).c_str());
1.1 root 177: }
178: }
179:
1.1.1.8 root 180: // モニタ更新 (M88xx0)
181: void
1.1.1.9 ! root 182: VectorTable::MonitorScreenM88xx0(Monitor *, TextScreen& screen)
1.1.1.8 root 183: {
184: // 0 1 2 3 4 5 6 7
185: // 0123456789012345678901234567890123456789012345678901234567890123456789012346
186: // No. Offset Address Name >< Count
187: // $002( 2) $0010 @$12345678 0123456789012345678901201234567890123456789012345
188:
189: uint32 vbr = mpu->GetVBR();
190:
191: // userdata が表示開始位置
192: int v = (int)screen.userdata;
193: int row = screen.GetRow();
194: int vend = v + row - 1;
195:
196: screen.Clear();
197:
198: // 最初の1行は常にヘッダ
199: screen.Print(0, 0, "No. Offset Address Name");
200: screen.Print(71, 0, "Count");
201:
202: for (int y = 1; v < vend; v++, y++) {
203: screen.Print(0, y, "$%03x(%3u) $%04x", v, v, v * 8);
204:
205: // m88100 は各ベクタが2ワード分あり、ここに命令を書く。
206: // ただし1ワード目は実質使えなかったので or r0,r0,r0 (NOP) を置く
207: // ことになっており、実質2ワード目の1命令だけでジャンプしないと
208: // いけない (アドレス全域にジャンプ出来るには最低2命令必要なので
209: // 2命令分のスペースを取ったのだろうけど…どうして…)。
210: // そこで、1ワード目が $f4005800 (NOP) で 2ワード目が何らかの分岐
211: // 命令であれば、その分岐先をこのベクタのアドレスとして表示する。
212: // 命令列が条件を満たさない時は仕方ないのでアドレスの前に @ をつけて
213: // 現在位置 (1ワード目が置かれているアドレス) を表示するか。
214: uint32 vecaddr = vbr + v * 8;
215: busaddr addr = VectorToAddr(vecaddr);
216: if (__predict_false(addr.IsBusErr())) {
217: screen.Print(17, y, "BusErr");
218: } else if (__predict_false(addr.IsPhysical())) {
219: // ジャンプ先が拾えなかったら Physical ビットを立てて返してくる。
220: // 空いてるビットを使いまわしてるだけでそれ以上の意味はない。
221: screen.Print(16, y, "@$%08x", vecaddr);
222: } else {
223: screen.Print(17, y, "$%08x", addr.Addr());
224: }
225: screen.Print(27, y, "%-23s", nametable[v] ?: "");
226: screen.Print(50, y, "%26s",
227: format_number(mpu->excep_counter[v]).c_str());
228: }
229: }
230:
231: // m88100 の2ワードのベクタからこのベクタの再分岐先を調べて返す。
232: // このベクタのフェッチ自体がバスエラーなら BusErr を返す。
233: // 分岐先を特定出来なければ、Physical ビットを立てて返す。
234: busaddr
235: VectorTable::VectorToAddr(uint32 vecaddr)
236: {
237: busdata inst1 = mainbus->Peek4(vecaddr);
238: busdata inst2 = mainbus->Peek4(vecaddr + 4);
239: if (__predict_false(inst1.IsBusErr() || inst2.IsBusErr())) {
240: return BusAddr::BusErr;
241: }
242:
243: // 1命令目は or r0,r0,r0 の NOP 固定でお願いしたい…。
244: if (__predict_false(inst1.Data() != 0xf4005800)) {
245: return BusAddr::Physical;
246: }
247:
248: // 2命令目はさすがに br しか置く必要ないと思いたい…。
249: uint32 op = inst2.Data();
250: int32 offset = 0;
251: if (__predict_true((op & 0xfc00'0000) == 0xc000'0000)) { // br
252: offset = ((int32)(op << 6) >> 4);
253: } else {
254: return BusAddr::Physical;
255: }
256:
257: return busaddr(vecaddr + 4 + offset);
258: }
259:
1.1.1.6 root 260: // ベクタ名 (MC680x0)。
261: // とりあえず CPU の区別はないことにする。
262: /*static*/ std::array<const char * const, 64> VectorTable::name_m680x0 = {
1.1.1.7 root 263: // 01234567890123456789012
1.1 root 264: /* 0 */ "Reset (SP)",
265: /* 1 */ "Reset (PC)",
266: /* 2 */ "Bus Error",
267: /* 3 */ "Address Error",
268: /* 4 */ "Illegal Instruction",
269: /* 5 */ "Zero Divide",
1.1.1.7 root 270: /* 6 */ "CHK/CHK2 Instruction",
271: /* 7 */ "TRAP* Instruction",
1.1.1.6 root 272: /* 8 */ "Privilege Violation",
1.1 root 273: /* 9 */ "Trace",
1.1.1.6 root 274: /* 10 */ "Line A emulator",
275: /* 11 */ "Line F emulator",
1.1 root 276: /* 12 */ NULL,
1.1.1.7 root 277: /* 13 */ "Copro Proto Violation", // 68030 only
1.1 root 278: /* 14 */ "Format Error",
1.1.1.7 root 279: /* 15 */ "Uninitialized Interrupt",
1.1 root 280: /* 16 */ NULL, NULL, NULL, NULL,
281: /* 20 */ NULL, NULL, NULL, NULL,
282: /* 24 */ "Spurious Interrupt",
283: /* 25 */ "Level 1 Interrupt",
284: /* 26 */ "Level 2 Interrupt",
285: /* 27 */ "Level 3 Interrupt",
286: /* 28 */ "Level 4 Interrupt",
287: /* 29 */ "Level 5 Interrupt",
288: /* 30 */ "Level 6 Interrupt",
289: /* 31 */ "Level 7 Interrupt",
290: /* 32 */ "Trap #0",
291: /* 33 */ "Trap #1",
292: /* 34 */ "Trap #2",
293: /* 35 */ "Trap #3",
294: /* 36 */ "Trap #4",
295: /* 37 */ "Trap #5",
296: /* 38 */ "Trap #6",
297: /* 39 */ "Trap #7",
298: /* 40 */ "Trap #8",
299: /* 41 */ "Trap #9",
300: /* 42 */ "Trap #10",
301: /* 43 */ "Trap #11",
302: /* 44 */ "Trap #12",
303: /* 45 */ "Trap #13",
304: /* 46 */ "Trap #14",
305: /* 47 */ "Trap #15",
1.1.1.7 root 306: // 01234567890123456789012
1.1 root 307: /* 48 */ "FPCP Branch",
1.1.1.7 root 308: /* 49 */ "FPCP Inexcact Result",
1.1 root 309: /* 50 */ "FPCP Divide by Zero",
310: /* 51 */ "FPCP UnderFlow",
311: /* 52 */ "FPCP Operand Error",
312: /* 53 */ "FPCP OverFlow",
313: /* 54 */ "FPCP Signaling NAN",
1.1.1.7 root 314: /* 55 */ "FPCP Unsupp Data Type", // 68040 only
315: /* 56 */ "MMU Configuration Error", // 68030 only
1.1 root 316: /* 57 */ NULL,
317: /* 58 */ NULL,
318: /* 59 */ NULL,
319: /* 60 */ NULL,
320: /* 61 */ NULL,
321: /* 62 */ NULL,
322: /* 63 */ NULL,
323: };
324:
325: // ベクタ名 (X68030)
1.1.1.3 root 326: /*static*/ std::map<int, const char * const> VectorTable::name_x68030 = {
1.1.1.7 root 327: // 01234567890123456789012
1.1.1.3 root 328: { 0x40, "MFP Alarm" },
329: { 0x41, "MFP EXPON" },
330: { 0x42, "MFP POWSW" },
331: { 0x43, "MFP FM IRQ" },
332: { 0x44, "MFP Timer-D" },
333: { 0x45, "MFP Timer-C" },
334: { 0x46, "MFP V-Disp" },
335: { 0x47, "MFP GPIP5" },
336: { 0x48, "MFP Timer-B" },
337: { 0x49, "MFP TX Error" },
338: { 0x4a, "MFP TX Empty" },
339: { 0x4b, "MFP RX Error" },
340: { 0x4c, "MFP RX Full" },
341: { 0x4d, "MFP Timer-A" },
342: { 0x4e, "MFP CRTC IRQ" },
343: { 0x4f, "MFP H-Sync" },
344:
345: { 0x50, "SCC#B TX Empty" },
346: { 0x52, "SCC#B E/S" },
347: { 0x54, "SCC#B RX Intr" },
1.1.1.7 root 348: { 0x56, "SCC#B Special Condition" },
1.1.1.3 root 349: { 0x58, "SCC#A TX Empty" },
350: { 0x5a, "SCC#A E/S" },
351: { 0x5c, "SCC#A RX Intr" },
1.1.1.7 root 352: { 0x5e, "SCC#A Special Condition" },
1.1.1.3 root 353:
1.1.1.7 root 354: // 01234567890123456789012
355: { 0x60, "I/O FDC Interrupt" },
356: { 0x61, "I/O FDD Interrupt" },
357: { 0x62, "I/O HDC Interrupt" },
358: { 0x63, "I/O PRN Interrupt" },
1.1.1.3 root 359: { 0x64, "DMAC#0 Complete" },
360: { 0x65, "DMAC#0 Error" },
361: { 0x66, "DMAC#1 Complete" },
362: { 0x67, "DMAC#1 Error" },
363: { 0x68, "DMAC#2 Complete" },
364: { 0x69, "DMAC#2 Error" },
365: { 0x6a, "DMAC#3 Complete" },
366: { 0x6b, "DMAC#3 Error" },
367: { 0x6c, "SPC Interrupt" },
368:
1.1.1.7 root 369: // 01234567890123456789012
1.1.1.3 root 370: { 0xf0, "PSX16x50 Interrupt" },
371: { 0xf6, "ExSPC Interrupt" },
372: //0xf7, TS-6BSI
373: { 0xf8, "Nereid#1 Interrupt" },
374: { 0xf9, "Neptune-X Interrupt" },
375: { 0xfa, "Nereid#1 USB" },
376: { 0xfb, "Nereid#0 USB" },
377: };
1.1 root 378:
1.1.1.3 root 379: // LUNA-I
380: /*static*/ std::map<int, const char * const> VectorTable::name_luna1 = {
1.1.1.7 root 381: // 01234567890123456789012
1.1.1.3 root 382: { 0x19, "Lv1 Intr (XP Low)" },
383: { 0x1a, "Lv2 Intr (SPC)" },
384: { 0x1b, "Lv3 Intr (Lance)" },
385: { 0x1c, "Lv4 Intr (XP High)" },
1.1.1.7 root 386: { 0x1d, "Lv5 Intr (System Clock)" },
1.1.1.3 root 387: { 0x1e, "Lv6 Intr (SIO)" },
388: { 0x1f, "Lv7 Intr (NMI)" },
1.1 root 389: };
390:
1.1.1.3 root 391: // NEWS はレベル割り込みと、一部が vectored */
392: /*static*/ std::map<int, const char * const> VectorTable::name_news = {
1.1.1.7 root 393: // 01234567890123456789012
1.1.1.3 root 394: { 0x19, "Lv1 Intr (AST)" },
395: { 0x1a, "Lv2 Intr" },
396: { 0x1b, "Lv3 Intr" },
397: { 0x1c, "Lv4 Intr (SIC/LAN)" },
398: { 0x1d, "Lv5 Intr (SCC)" },
1.1.1.7 root 399: { 0x1e, "Lv6 Intr (System Timer)" },
1.1.1.3 root 400: { 0x1f, "Lv7 Intr" },
401:
402: { 0x40, "SCC" },
1.1 root 403: };
404:
1.1.1.6 root 405: // virt-m68k
406: /*static*/ std::map<int, const char * const> VectorTable::name_virt68k = {
1.1.1.7 root 407: // 01234567890123456789012
1.1.1.6 root 408: { 0x19, "Lv1 Intr (GFPIC1)" },
409: { 0x1a, "Lv2 Intr (GFPIC2)" },
410: { 0x1b, "Lv3 Intr (GFPIC3)" },
411: { 0x1c, "Lv4 Intr (GFPIC4)" },
412: { 0x1d, "Lv5 Intr (GFPIC5)" },
413: { 0x1e, "Lv6 Intr (GFPIC6)" },
414: { 0x1f, "Lv7 Intr" },
415: };
416:
1.1.1.8 root 417: // LUNA-88K
418: /*static*/ std::map<int, const char * const> VectorTable::name_luna88k = {
1.1.1.3 root 419: // 01234567890123456789012 <- 例外履歴欄の横幅
1.1.1.8 root 420: { 0x00, "Reset Exception" },
421: { 0x01, "Interrupt Exception" },
422: { 0x02, "Inst Access Exception" },
423: { 0x03, "Data Access Exception" },
424: { 0x04, "Misaligned Access Excep" },
425: { 0x05, "Unimplemented Opcode" },
426: { 0x06, "Priv. Violation Excep." },
427: { 0x07, "Bounds Check Violation" },
428: { 0x08, "Illegal Integer Divide" },
429: { 0x09, "Int Overflow Exception" },
430: { 0x0a, "Error Exception" },
431: // SFU1 (SFU2〜7 はなくていいか…)
432: { 0x72, "SFU1 Precise Exception" },
433: { 0x73, "SFU1 ImpreciseException" },
434:
435: // 0x80 は OpenBSD では sigsys、NetBSD/luna88k (非公式)ではシステムコール。
436: { 0x80, "NetBSD System Call" },
437: // XXX 本来は OpenBSD 稼働時に限定すべきだろうけど、そうする意味もない
438: { 0x81, "OpenBSD sigsys" },
439: { 0x82, "OpenBSD break" },
440: { 0x83, "OpenBSD trace" },
441: { 0x84, "OpenBSD entry" },
442: { 450, "OpenBSD System Call" },
443: { 451, "OpenBSD Cache Flush" },
444: { 503, "Division by Zero(GCC)" },
445: { 504, "OpenBSD stepbpt" },
446: { 511, "OpenBSD userbpt" },
1.1 root 447: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.