|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: // MPU (m680x0)
8:
9: #include "mpu680x0.h"
10: #include "config.h"
1.1.1.2 root 11: #include "m68030excep.h"
1.1 root 12: #include "mainapp.h"
13: #include "vm.h"
14: #include <math.h>
15:
16: std::unique_ptr<MPUATC> gMPUATC;
17:
18: // コンストラクタ
19: //
20: // reset_vector にはリセットベクタの番地を指定する。
21: // 本来の MPU の動作は、リセット例外時にメモリの $0, $4 番地 (もっと言えば
22: // FC がプログラム空間の) から SP, PC を読み込むのだが、そのためにメモリ空間
23: // を切り替える処理はリセット時にしか必要ないわりに結構手間である。そしてこの
24: // m68k 恒例のブートストラップ動作はソフトウェア的には一切観測する手段がない。
25: // であれば、リセット例外時にこのアドレスから SP, PC の値を直接読み込んだと
26: // しても動作にはまったく違いは出ない。そしてバス・メモリ空間の実装も簡略化
27: // できる。すごい楽。
28: MPU680x0Device::MPU680x0Device(uint32 reset_vector)
29: {
1.1.1.3 root 30: monitor_size = nnSize(79, 16);
1.1 root 31:
32: cpu = m68030_init(reset_vector);
33:
1.1.1.4 ! root 34: // リセット例外イベントコールバック設定
! 35: reset_event.func = (DeviceCallback_t)&MPU680x0Device::ResetCallback;
! 36:
1.1 root 37: // モニタ用の別オブジェクト
38: gMPUATC.reset(new MPUATC(cpu));
39: }
40:
41: // デストラクタ
42: MPU680x0Device::~MPU680x0Device()
43: {
44: }
45:
46: bool
47: MPU680x0Device::Init()
48: {
49: // FPU (6888x)
1.1.1.2 root 50: if (gMainApp.GetVMType() == VMTYPE_LUNA1) {
1.1 root 51: // LUNA は 68881 固定 (設定は見ない)
52: cpu->has_fpu = 1;
53: } else {
54: // X68k は設定による
1.1.1.2 root 55: const ConfigItem& item = gConfig->Find("mpu-has-fpu");
1.1 root 56: cpu->has_fpu = item.AsInt();
57: if (cpu->has_fpu < 0 || cpu->has_fpu > 2) {
58: item.Err();
59: return false;
60: }
61: }
62:
63: return true;
64: }
65:
1.1.1.4 ! root 66: // リセット例外イベントコールバック
1.1 root 67: void
1.1.1.4 ! root 68: MPU680x0Device::ResetCallback(Event& ev)
1.1 root 69: {
70: m68030_exception_reset(cpu);
71: }
72:
73: // MPU を request で指定されたクロックサイクルだけ実行する。
74: // 今回の実行サイクル数が request を越えた命令境界まで実行するので
75: // 実際には少しはみ出る。
76: // また実行中にデバイスアクセスなどによりスケジューラにイベントが
77: // 追加されるとその次の命令境界で処理を打ち切って戻ってくる。
78: // 戻り値は CPU の outer フラグ。
79: uint32
80: MPU680x0Device::Run(uint64 request)
81: {
82: return m68030_run(cpu, request);
83: }
84:
85: // 割り込み発生を MPU に通知 (オートベクタ)
86: void
1.1.1.2 root 87: MPU680x0Device::Interrupt(Object *src, int level)
1.1 root 88: {
89: int vector = M68K_EXCEP_LEVEL_BASE + level;
90: m68030_interrupt(cpu, level, vector);
91: }
92:
93: // 割り込み発生を MPU に通知 (ベクタ)
94: void
1.1.1.2 root 95: MPU680x0Device::Interrupt(Object *src, int level, int vector)
1.1 root 96: {
97: m68030_interrupt(cpu, level, vector);
98: }
99:
100: // A-Line 命令エミュレーションのコールバックを指定。
101: void
102: MPU680x0Device::SetALineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
103: {
104: cpu->aline_callback = callback;
105: cpu->aline_arg = arg;
106: }
107:
108: // F-Line 命令エミュレーションのコールバックを指定。
109: void
110: MPU680x0Device::SetFLineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
111: {
112: cpu->fline_callback = callback;
113: cpu->fline_arg = arg;
114: }
115:
1.1.1.2 root 116: // ダブルバスフォールトのコールバックを指定。
117: void
118: MPU680x0Device::SetHaltCallback(void (*callback)(void *), void *arg)
119: {
120: cpu->halt_callback = callback;
121: cpu->halt_arg = arg;
122: }
123:
1.1 root 124: // モニター更新 (レジスタウィンドウ)
1.1.1.3 root 125: void
126: MPU680x0Device::MonitorUpdate(TextScreen& monitor)
1.1 root 127: {
128: m68kreg reg;
129: uint32 ppc;
130: int x;
131: int y;
132:
133: monitor.Clear();
134:
135: // ローカルにコピー
136: // ただし PPC だけ reg 構造体ではなく cpu クラス側にある
137: reg = cpu->reg;
138: ppc = cpu->ppc;
139:
140: // データレジスタ、アドレスレジスタ
141: for (int i = 0; i < 4; i++) {
142: monitor.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x",
143: i + 0, reg.da[i],
144: i + 4, reg.da[i + 4],
145: i + 0, reg.da[i + 8],
146: i + 4, reg.da[i + 12]);
147: }
148:
149: // 5列目
150: x = 50;
151: // SR
152: monitor.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
153: (reg.sr_h() | reg.ccr.Get()),
154: (reg.ccr.IsX()) ? 'X' : '-',
155: (reg.ccr.IsN()) ? 'N' : '-',
156: (reg.ccr.IsZ()) ? 'Z' : '-',
157: (reg.ccr.IsV()) ? 'V' : '-',
158: (reg.ccr.IsC()) ? 'C' : '-');
159:
160: // VBR
161: monitor.Print(x, 1, "VBR:%08x", reg.vbr);
162:
163: // *SP
164: uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M
165: if (ms == 3) {
166: // Supervisor (Master) mode (A7=MSP, USP/ISP)
167: monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
168: monitor.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp);
169: } else if (ms == 2) {
170: // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
171: monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
172: monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
173: } else {
174: // User mode (A7=USP, ISP/MSP)
175: monitor.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp);
176: monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
177: }
178:
179: // 6列目
180: // PC: 01234567
181: // SFC:1 DFC:1
182: // CACR:01234567
183: // CAAR:01234567
184: x = 66;
185: monitor.Print(x, 0, "PC: %08x", ppc);
186: monitor.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc);
187: monitor.Print(x, 2, "CACR:%08x", reg.cacr);
188: monitor.Print(x, 3, "CAAR:%08x", reg.caar);
189:
190: // XXX どこに置くのがいいか
191: if (reg.state == 0) {
1.1.1.2 root 192: monitor.Puts(25, 4, "State: Running");
1.1 root 193: } else if (reg.state == CPU_REQ_STOP) {
1.1.1.2 root 194: monitor.Puts(25, 4, "State: STOP instruction");
1.1 root 195: } else if (reg.state == CPU_REQ_HALT) {
1.1.1.2 root 196: monitor.Puts(25, 4, TA::On, "State: Double Bus Fault");
1.1 root 197: }
198:
199: // MMU
200: x = 0;
201: y = 4;
1.1.1.2 root 202: monitor.Puts(x, y++, "<MMU>");
1.1 root 203: monitor.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l);
204: monitor.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l);
205: x += 23;
206: for (int i = 0; i < 2; i++) {
207: uint32 tt = reg.tt[i];
208: monitor.Print(x, y + i, "TT%d:%08x(%c%c%c)",
209: i, tt,
210: (tt & m68030TT::E) ? 'E' : '-',
211: (tt & m68030TT::CI) ? 'C' : '-',
212: (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W'));
213: }
214: x += 19;
215: monitor.Print(x, y, "TC:%08x(%c%c%c)",
216: reg.tc,
217: (reg.tc & m68030TC::TC_E) ? 'E' : '-',
218: (reg.tc & m68030TC::TC_SRE) ? 'S' : '-',
219: (reg.tc & m68030TC::TC_FCL) ? 'F' : '-');
220: monitor.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)",
221: reg.mmusr,
222: (reg.mmusr & m68030MMUSR::B) ? 'B' : '-',
223: (reg.mmusr & m68030MMUSR::L) ? 'L' : '-',
224: (reg.mmusr & m68030MMUSR::S) ? 'S' : '-',
225: (reg.mmusr & m68030MMUSR::W) ? 'W' : '-',
226: (reg.mmusr & m68030MMUSR::I) ? 'I' : '-',
227: (reg.mmusr & m68030MMUSR::M) ? 'M' : '-',
228: (reg.mmusr & m68030MMUSR::T) ? 'T' : '-',
229: (reg.mmusr & m68030MMUSR::N));
230:
231: // FPU
232: x = 0;
233: y = 7;
1.1.1.2 root 234: monitor.Puts(x, y++, "<FPU>");
1.1 root 235: for (int i = 0; i < 8; i++) {
236: monitor.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)",
237: i,
238: reg.fpframe.fpf_regs[i * 3 + 0] >> 16,
239: reg.fpframe.fpf_regs[i * 3 + 1],
240: reg.fpframe.fpf_regs[i * 3 + 2],
241: "not yet");
242: }
243:
244: x = 51;
245:
246: // FPCR
247: static const char * const rpstr[] = {
248: ".EXT",
249: ".SGL",
250: ".DBL",
251: ".???",
252: };
253: static const char * const rmstr[] = {
254: "Near",
255: "Zero",
256: "Minus",
257: "Plus",
258: };
259: uint32 fpcr = reg.fpframe.fpf_fpcr;
260: monitor.Print(x, y++, "FPCR:%04x", fpcr);
261: monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s",
262: (fpcr & 0x8000) ? "BS" : "--",
263: (fpcr & 0x4000) ? "SN" : "--",
264: (fpcr & 0x2000) ? "OP" : "--",
265: (fpcr & 0x1000) ? "OV" : "--",
266: (fpcr & 0x0800) ? "UF" : "--",
267: (fpcr & 0x0400) ? "DZ" : "--",
268: (fpcr & 0x0200) ? "I2" : "--",
269: (fpcr & 0x0100) ? "I1" : "--");
270: monitor.Print(x + 2, y++, "RP=%s RM=%s",
271: rpstr[(fpcr >> 6) & 3],
272: rmstr[(fpcr >> 4) & 3]);
273:
274: // FPSR
275: uint32 fpsr = reg.fpframe.fpf_fpsr;
276: uint32 cc = fpsr >> 24;
277: monitor.Print(x, y++, "FPSR:%08x", fpsr);
278: monitor.Print(x + 2, y++, "%c %c %s %s Q=$%02x",
279: (cc & 0x08) ? 'N' : '-',
280: (cc & 0x04) ? 'Z' : '-',
281: (cc & 0x02) ? "Inf" : "---",
282: (cc & 0x01) ? "NAN" : "---",
283: (fpsr >> 16) & 0xff);
284: monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s",
285: (fpsr & 0x8000) ? "BS" : "--",
286: (fpsr & 0x4000) ? "SN" : "--",
287: (fpsr & 0x2000) ? "OP" : "--",
288: (fpsr & 0x1000) ? "OV" : "--",
289: (fpsr & 0x0800) ? "UF" : "--",
290: (fpsr & 0x0400) ? "DZ" : "--",
291: (fpsr & 0x0200) ? "I2" : "--",
292: (fpsr & 0x0100) ? "I1" : "--");
293: monitor.Print(x + 2, y++, "%s %s %s %s %s",
294: (fpsr & 0x80) ? "IOP" : "---",
295: (fpsr & 0x40) ? "OVFL" : "----",
296: (fpsr & 0x20) ? "UNFL" : "----",
297: (fpsr & 0x10) ? "DZ" : "--",
298: (fpsr & 0x08) ? "INEX" : "----");
299:
300: // FPIAR
301: monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar);
302: }
303:
304: // CPU 側からのコールバック。RESET 命令ハンドラ
305: void
306: m68030_reset_inst(m68kcpu *cpu)
307: {
308: gVM->ResetSoft();
309: }
310:
311: //
312: // ATC モニタ
313: //
1.1.1.2 root 314: MPUATC::MPUATC(m68kcpu *cpu_)
1.1 root 315: {
1.1.1.2 root 316: cpu = cpu_;
1.1 root 317: #if !defined(ATC_SINGLE)
1.1.1.3 root 318: monitor_size = nnSize(131, m68030ATCTable::LINES + 3);
1.1 root 319: #else
1.1.1.3 root 320: monitor_size = nnSize(31, 24);
1.1 root 321: #endif
322: }
323:
1.1.1.3 root 324: void
325: MPUATC::MonitorUpdate(TextScreen& monitor)
1.1 root 326: {
327: m68030ATCTable *table;
328: #if !defined(ATC_SINGLE)
329: struct {
330: int fc;
331: const char *name;
332: } fclist[] = {
333: { 1, "User/Data" },
334: { 2, "User/Program" },
335: { 5, "Super/Data" },
336: { 6, "Super/Program" },
337: };
338:
339: monitor.Clear();
340:
341: // 行数は左端にだけ
342: for (int i = 0; i < m68030ATCTable::LINES; i++) {
343: monitor.Print(0, i + 2, "%02d:", i);
344: }
345:
346: for (int t = 0; t < countof(fclist); t++) {
347: int x = t * 32 + 4;
348: int fc = fclist[t].fc;
349: const char *name = fclist[t].name;
350: double r;
351: int i;
352:
353: table = &cpu->atc.tables[fc];
354: monitor.Print(x, 0, "FC=%d %s", fc, name);
1.1.1.2 root 355: monitor.Puts(x, 1, "LAddr PAddr Flag Hit% Age");
1.1 root 356: // 先に統計用の母数を計算
357: uint64 total = 0;
358: for (i = 0; i < countof(table->hit); i++) {
359: total += table->hit[i];
360: }
361: total += table->hit_head;
362:
363: // エントリ表示
364: for (i = 0; i < countof(table->line); i++) {
365: m68030ATCLine& a = table->line[i];
1.1.1.2 root 366: TA attr;
1.1 root 367: if (a.IsInvalid()) {
368: attr = TA::Disable;
369: } else if (table->head == &a) {
370: attr = TA::Em;
371: } else {
372: attr = TA::Normal;
373: }
374:
375: monitor.Print(x, i + 2, attr, "%08x %08x %c%c%c",
376: a.GetLAddr(),
377: a.GetPAddr(),
378: a.IsBusError() ? 'B' : '-',
379: a.IsWProtect() ? 'P' : '-',
380: a.IsModified() ? 'M' : '-');
381: }
382: // ヘッドのヒット率
1.1.1.2 root 383: monitor.Puts(x + 0, i + 2, "head");
1.1 root 384: r = (double)table->hit_head * 100 / total;
385: if (!isnan(r)) {
386: monitor.Print(x + 5, i + 2, "%4.1f%%", r);
387: }
388: // 配列のヒット率とミス率
1.1.1.2 root 389: monitor.Puts(x + 17, i + 2, "miss");
1.1 root 390: for (i = 0; i < countof(table->hit); i++) {
391: r = (double)(table->hit[i] * 100) / total;
392: if (!isnan(r)) {
393: monitor.Print(x + 22, i + 2, "%4.1f%%", r);
394: }
395: }
396: // カウンタ
397: // 分かりやすさのため最大値からの差(距離)を表示
398: for (i = 0; i < countof(table->line); i++) {
399: m68030ATCLine& a = table->line[i];
400: if (!a.IsInvalid()) {
401: monitor.Print(x + 27, i + 2, "%4d", table->head->age - a.age);
402: }
403: }
404: }
405: #else
406: m68030ATCLine *a;
407: int i;
408:
409: table = &cpu->atc.tables[0];
410: monitor.Clear();
411:
1.1.1.2 root 412: monitor.Puts(0, 0, "No. FC LAddr PAddr Flag");
1.1 root 413: for (a = table->head, i = 0; a; a = a->next, i++) {
414: monitor.Print(0, i + 1, "%02d:", i);
415: if (!a->IsInvalid()) {
416: char dp;
417: switch (a->fc & 3) {
418: case 1: dp = 'D'; break;
419: case 2: dp = 'P'; break;
420: default: dp = '?'; break;
421: }
422: monitor.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c",
423: a->fc,
424: (a->fc & 4) ? 'S' : 'U',
425: dp,
426: a->GetLAddr(), a->GetPAddr(),
427: a->IsBusError() ? 'B' : '-',
428: a->IsWProtect() ? 'W' : '-',
429: a->IsModified() ? 'M' : '-');
430: }
431: }
432: #endif
433: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.