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