|
|
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:
1.1.1.13 root 7: //
8: // MPU (MC68030)
9: //
1.1 root 10:
11: #include "mpu680x0.h"
12: #include "config.h"
1.1.1.13 root 13: #include "debugger.h"
14: #include "debugger_private.h"
1.1.1.10 root 15: #include "m68030bus.h"
1.1.1.2 root 16: #include "m68030excep.h"
1.1 root 17: #include "mainapp.h"
1.1.1.13 root 18: #include "scheduler.h"
19: #include "sync.h"
1.1.1.10 root 20: #include "uimessage.h"
1.1 root 21: #include "vm.h"
1.1.1.13 root 22: #include <cmath>
23:
24: static void mpu680x0_reset_inst(void *);
25: static void mpu680x0_halt(void *);
1.1 root 26:
27: // コンストラクタ
1.1.1.8 root 28: MPU680x0Device::MPU680x0Device()
1.1.1.9 root 29: : inherited("MPU(68030)")
1.1 root 30: {
1.1.1.13 root 31: cpu = m68030_init(this);
1.1 root 32:
1.1.1.13 root 33: // 割り込みイベントコールバック設定
34: intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback);
35: intr_event.Regist("MPU Interrupt");
1.1.1.4 root 36:
1.1.1.9 root 37: // レジスタモニター
1.1.1.13 root 38: reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg);
1.1.1.9 root 39: reg_monitor.SetSize(79, 16);
40: reg_monitor.Regist(ID_MONITOR_MPUREG);
41:
42: // ATC モニター
1.1.1.13 root 43: atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC);
1.1.1.9 root 44: #if !defined(ATC_SINGLE)
45: atc_monitor.SetSize(131, m68030ATCTable::LINES + 3);
46: #else
47: atc_monitor.SetSize(31, 24);
48: #endif
49: atc_monitor.Regist(ID_MONITOR_MPUATC);
1.1.1.13 root 50:
51: SetTrace(false);
1.1 root 52: }
53:
54: // デストラクタ
55: MPU680x0Device::~MPU680x0Device()
56: {
57: }
58:
59: bool
60: MPU680x0Device::Init()
61: {
1.1.1.5 root 62: // 親クラス
63: if (inherited::Init() == false) {
64: return false;
65: }
1.1.1.13 root 66:
67: // 割り込み時のディレイ。
68: //
69: // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを
70: // 認識(確定)するのに 1 ~ 2 クロックかかる。
71: // その後レベルを比較するのは次のアップエッジ。
72: // その後 /IPEND をアサートするのはその次のアップエッジ。
73: // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは
74: // 2 ~ 3 クロックかかる。(Figure 8-4)
75: intr_event.time = 3 * clock_nsec;
1.1.1.5 root 76:
1.1 root 77: // FPU (6888x)
1.1.1.14! root 78: if (gMainApp.GetVMType() == VMType::LUNA1) {
1.1 root 79: // LUNA は 68881 固定 (設定は見ない)
80: cpu->has_fpu = 1;
81: } else {
82: // X68k は設定による
1.1.1.14! root 83: const ConfigItem& item = gConfig->Find("fpu-type");
! 84: std::string type = item.AsString();
! 85: if (type == "none" || type == "0") {
! 86: cpu->has_fpu = 0;
! 87: } else if (type == "68881" || type == "1") {
! 88: cpu->has_fpu = 1;
! 89: } else {
1.1 root 90: item.Err();
91: return false;
92: }
93: }
94:
1.1.1.13 root 95: cpu->resetop_callback = mpu680x0_reset_inst;
96: cpu->resetop_arg = NULL;
97: cpu->halt_callback = mpu680x0_halt;
98: cpu->halt_arg = this;
1.1.1.10 root 99:
1.1 root 100: return true;
101: }
102:
1.1.1.13 root 103: // リセット
104: void
105: MPU680x0Device::ResetHard(bool poweron)
1.1.1.8 root 106: {
1.1.1.13 root 107: if (poweron) {
108: m68030_power_on(cpu);
109: }
1.1.1.14! root 110: resetting = true;
1.1.1.13 root 111:
112: // リセット例外を 520 クロック後に起こす。
113: // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック
114: // の間アサートしなければならないという値であって、実際これだけかかる
115: // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の
116: // ResetHard() がブートページを用意した後で m68030_exception_reset() で
117: // SP, PC をフェッチするという順序にしないといけないため、リセット例外が
118: // 起動するまでに時間がかかるというところを都合よく真似ておく。
119:
120: exec_event.func = ToEventCallback(&MPU680x0Device::ResetCallback);
121: exec_event.time = 520 * clock_nsec;
122: exec_event.SetName("MPU Reset");
123: gScheduler->RestartEvent(exec_event);
1.1.1.8 root 124: }
125:
1.1.1.13 root 126: // リセット例外コールバック。
127: // MPU リセットから規定時間後に呼ばれる。
1.1.1.8 root 128: void
1.1.1.13 root 129: MPU680x0Device::ResetCallback(Event& ev)
1.1.1.8 root 130: {
1.1.1.14! root 131: resetting = false;
1.1.1.13 root 132: intr_pending = false;
133:
134: // リセット例外を実行
135: int cycle = m68030_exception_reset(cpu);
136:
137: // コールバックを ResetCallback から Exec* に差し替える前のここで
138: // トレース状態を初期化する。
139: SetTrace(gDebugger->IsTrace());
140:
141: // 以降は通常走行。
142: if (cpu->state == m68kcpu::CPU_STATE_NORMAL) {
143: exec_event.func = exec_short;
144: exec_event.time = cycle * clock_nsec;
145: exec_event.SetName("MPU Execute");
1.1.1.14! root 146: gScheduler->RestartEvent(exec_event);
1.1.1.13 root 147: } else {
148: // リセット例外でダブルバスフォールトならここで停止。
149: }
1.1.1.8 root 150: }
151:
1.1.1.13 root 152: // 通常の1命令実行のコールバック
153: // 割り込みチェックなどを省いたショート版。
1.1 root 154: void
1.1.1.13 root 155: MPU680x0Device::ExecShort(Event& ev)
1.1 root 156: {
1.1.1.13 root 157: int cycle = m68030_exec(cpu);
158:
159: ev.time = cycle * clock_nsec;
160: gScheduler->StartEvent(ev);
161: }
162:
163: // 割り込みチェック、STOP 処理を含んだ完全な実行サイクルのコールバック。
164: // SR の I2:I0 が変わった直後などに呼ばれる。
165: // ここでは割り込みをチェックし、必要なら割り込み処理を起動、
166: // そうでなければ通常の命令実行を行う。
167: void
168: MPU680x0Device::ExecFull(Event& ev)
169: {
1.1.1.14! root 170: intr_pending |= m68030_check_interrupt(cpu);
! 171:
1.1.1.13 root 172: if (intr_pending) {
173: // 割り込み処理を起動。
174:
175: intr_pending = false;
176:
177: // 前の命令実行後となるここで割り込みを起動
178: int cycle = m68030_exception_interrupt(cpu);
179:
180: ev.time = cycle * clock_nsec;
181: gScheduler->StartEvent(ev);
182: } else {
183: if (cpu->state == m68kcpu::CPU_STATE_NORMAL) {
184: // コールバックを通常処理に戻してから...
185: exec_event.func = exec_short;
186:
187: // この場で次の命令を実行。
188: ExecShort(ev);
189: } else {
190: // STOP ならここで停止。HALT はそもそも来ないはず。
191: }
192: }
1.1 root 193: }
194:
1.1.1.13 root 195: // トレース実行
196: void
197: MPU680x0Device::ExecTrace(Event& ev)
1.1 root 198: {
1.1.1.13 root 199: gDebugger->Exec();
200: ExecFull(ev);
1.1 root 201: }
202:
1.1.1.13 root 203: // トレース状態を設定する
204: void
205: MPU680x0Device::SetTrace(bool enable)
1.1 root 206: {
1.1.1.13 root 207: if (enable) {
208: exec_short = ToEventCallback(&MPU680x0Device::ExecTrace);
209: exec_full = ToEventCallback(&MPU680x0Device::ExecTrace);
210: } else {
211: exec_short = ToEventCallback(&MPU680x0Device::ExecShort);
212: exec_full = ToEventCallback(&MPU680x0Device::ExecFull);
213: }
214: exec_event.func = exec_full;
215:
216: // STOP 命令中にオンにするには、停止しているイベントを起こす。
217: // STOP 命令中にオフにする場合は、何もしなくていい。
218: if (enable && exec_event.IsRunning() == false) {
219: gScheduler->StartEvent(exec_event);
220: }
1.1 root 221: }
222:
1.1.1.5 root 223: // 割り込みレベルが変わったことを MPU に通知。
1.1 root 224: void
1.1.1.5 root 225: MPU680x0Device::Interrupt(int level)
1.1 root 226: {
1.1.1.5 root 227: assertmsg(0 <= level && level <= 7, "level=%d", level);
228:
1.1.1.13 root 229: intr_event.code = level;
230: if (intr_event.IsRunning() == false) {
231: gScheduler->StartEvent(intr_event);
1.1.1.5 root 232: }
1.1.1.13 root 233: }
234:
235: // 外部割り込みイベントコールバック。
236: // 割り込みレベルが変わったことをコアに通知する。
237: // ev.code 0-7 は新しい割り込みレベル。
238: void
239: MPU680x0Device::InterruptCallback(Event& ev)
240: {
241: int level = ev.code;
242:
243: if (m68030_interrupt(cpu, level)) {
244: // 通知した結果割り込みが受け付けられたので、
245: // この命令終了時のコールバックを割り込み処理起動に差し替える。
246: MakeNextFull();
247: intr_pending = true;
248:
249: // STOP 状態だったらここでイベントを開始する
250: if (cpu->state == m68kcpu::CPU_STATE_STOP) {
251: // STOP から抜ける時間?
252: exec_event.time = 1 * clock_nsec;
253: gScheduler->StartEvent(exec_event);
254: }
255: }
256: }
257:
258: // 次の命令境界で割り込みチェックを行う。
259: // (割り込みマスクを変更する命令の実行で呼ばれる)
260: void
261: MPU680x0Device::CheckIntr()
262: {
263: MakeNextFull();
264: }
265:
266: // 次の命令境界は Full にする。
267: void
268: MPU680x0Device::MakeNextFull()
269: {
270: exec_event.func = exec_full;
271: }
272:
273: // コアからの動作変更通知
274: /*static*/ void
275: MPU680x0Device::NotifyCPUMode(uint32 new_mode)
276: {
277: // new_mode (m68kcpu::CPU_STATE_*) と
278: // RequestCPUMode() の引数 Sync::SCHED_CPU_* は
279: // 実は同じ値なのでそのまま渡してよいことにする。
280: static_assert(m68kcpu::CPU_STATE_NORMAL == Sync::SCHED_CPU_NORMAL, "");
281: static_assert(m68kcpu::CPU_STATE_STOP == Sync::SCHED_CPU_STOP, "");
282: static_assert(m68kcpu::CPU_STATE_HALT == Sync::SCHED_CPU_HALT, "");
283:
284: // 通知 (同期のため)
285: gSync->RequestCPUMode(new_mode);
1.1 root 286: }
287:
288: // A-Line 命令エミュレーションのコールバックを指定。
289: void
290: MPU680x0Device::SetALineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
291: {
292: cpu->aline_callback = callback;
293: cpu->aline_arg = arg;
294: }
295:
296: // F-Line 命令エミュレーションのコールバックを指定。
297: void
298: MPU680x0Device::SetFLineCallback(bool (*callback)(m68kcpu *, void*), void *arg)
299: {
300: cpu->fline_callback = callback;
301: cpu->fline_arg = arg;
302: }
303:
1.1.1.13 root 304: // RESET 命令の CPU からのコールバック関数
305: static void
306: mpu680x0_reset_inst(void *arg)
1.1.1.10 root 307: {
1.1.1.13 root 308: gVM->ResetByMPU();
309: }
310:
311: // ホールト時の CPU からのコールバック関数
312: static void
313: mpu680x0_halt(void *arg)
314: {
315: ((MPU680x0Device *)arg)->Halt();
316: }
317:
318: // ホールト状態
319: void
320: MPU680x0Device::Halt()
321: {
322: // 動作停止
323: gScheduler->StopEvent(exec_event);
324:
325: // UI に通知 (メッセージボックス表示とか)
1.1.1.10 root 326: UIMessage::Post(UIMessage::HALT);
327: }
328:
329: // MPU からのアクセスをエミュレート
330: uint64
331: MPU680x0Device::Read8(uint32 addr)
332: {
333: try {
334: return m68030_read_8(cpu, addr);
335: } catch (...) {
336: return (uint64)-1;
337: }
338: }
339:
340: uint64
341: MPU680x0Device::Read16(uint32 addr)
342: {
343: try {
344: return m68030_read_16(cpu, addr);
345: } catch (...) {
346: return (uint64)-1;
347: }
348: }
349:
350: uint64
351: MPU680x0Device::Read32(uint32 addr)
1.1.1.2 root 352: {
1.1.1.10 root 353: try {
354: return m68030_read_32(cpu, addr);
355: } catch (...) {
356: return (uint64)-1;
357: }
358: }
359:
360: uint64
361: MPU680x0Device::Write8(uint32 addr, uint32 data)
362: {
363: try {
364: m68030_write_8(cpu, addr, data);
365: return 0;
366: } catch (...) {
367: return (uint64)-1;
368: }
369: }
370:
371: uint64
372: MPU680x0Device::Write16(uint32 addr, uint32 data)
373: {
374: try {
375: m68030_write_16(cpu, addr, data);
376: return 0;
377: } catch (...) {
378: return (uint64)-1;
379: }
380: }
381:
382: uint64
383: MPU680x0Device::Write32(uint32 addr, uint32 data)
384: {
385: try {
386: m68030_write_32(cpu, addr, data);
387: return 0;
388: } catch (...) {
389: return (uint64)-1;
390: }
1.1.1.2 root 391: }
392:
1.1 root 393: // モニター更新 (レジスタウィンドウ)
1.1.1.3 root 394: void
1.1.1.9 root 395: MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen)
1.1 root 396: {
397: m68kreg reg;
398: uint32 ppc;
1.1.1.13 root 399: uint32 state;
1.1 root 400: int x;
401: int y;
402:
1.1.1.9 root 403: screen.Clear();
1.1 root 404:
405: // ローカルにコピー
1.1.1.13 root 406: // ただし一部は reg ではなく cpu クラス本体にある
1.1 root 407: reg = cpu->reg;
408: ppc = cpu->ppc;
1.1.1.13 root 409: state = cpu->state;
1.1 root 410:
411: // データレジスタ、アドレスレジスタ
412: for (int i = 0; i < 4; i++) {
1.1.1.9 root 413: screen.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x",
1.1 root 414: i + 0, reg.da[i],
415: i + 4, reg.da[i + 4],
416: i + 0, reg.da[i + 8],
417: i + 4, reg.da[i + 12]);
418: }
419:
420: // 5列目
421: x = 50;
422: // SR
1.1.1.9 root 423: screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)",
1.1 root 424: (reg.sr_h() | reg.ccr.Get()),
425: (reg.ccr.IsX()) ? 'X' : '-',
426: (reg.ccr.IsN()) ? 'N' : '-',
427: (reg.ccr.IsZ()) ? 'Z' : '-',
428: (reg.ccr.IsV()) ? 'V' : '-',
429: (reg.ccr.IsC()) ? 'C' : '-');
430:
431: // VBR
1.1.1.9 root 432: screen.Print(x, 1, "VBR:%08x", reg.vbr);
1.1 root 433:
434: // *SP
435: uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M
436: if (ms == 3) {
437: // Supervisor (Master) mode (A7=MSP, USP/ISP)
1.1.1.9 root 438: screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
439: screen.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp);
1.1 root 440: } else if (ms == 2) {
441: // Supervisor (Interrupt) mode (A7=ISP, USP/MSP)
1.1.1.9 root 442: screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp);
443: screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
1.1 root 444: } else {
445: // User mode (A7=USP, ISP/MSP)
1.1.1.9 root 446: screen.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp);
447: screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp);
1.1 root 448: }
449:
450: // 6列目
451: // PC: 01234567
452: // SFC:1 DFC:1
453: // CACR:01234567
454: // CAAR:01234567
455: x = 66;
1.1.1.9 root 456: screen.Print(x, 0, "PC: %08x", ppc);
457: screen.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc);
458: screen.Print(x, 2, "CACR:%08x", reg.cacr);
459: screen.Print(x, 3, "CAAR:%08x", reg.caar);
1.1 root 460:
461: // XXX どこに置くのがいいか
1.1.1.13 root 462: switch (state) {
463: case m68kcpu::CPU_STATE_NORMAL:
1.1.1.9 root 464: screen.Puts(25, 4, "State: Running");
1.1.1.13 root 465: break;
466: case m68kcpu::CPU_STATE_STOP:
1.1.1.9 root 467: screen.Puts(25, 4, "State: STOP instruction");
1.1.1.13 root 468: break;
469: case m68kcpu::CPU_STATE_HALT:
1.1.1.9 root 470: screen.Puts(25, 4, TA::On, "State: Double Bus Fault");
1.1.1.13 root 471: break;
472: default:
473: __unreachable();
1.1 root 474: }
475:
476: // MMU
477: x = 0;
478: y = 4;
1.1.1.9 root 479: screen.Puts(x, y++, "<MMU>");
480: screen.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l);
481: screen.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l);
1.1 root 482: x += 23;
483: for (int i = 0; i < 2; i++) {
484: uint32 tt = reg.tt[i];
1.1.1.9 root 485: screen.Print(x, y + i, "TT%d:%08x(%c%c%c)",
1.1 root 486: i, tt,
487: (tt & m68030TT::E) ? 'E' : '-',
488: (tt & m68030TT::CI) ? 'C' : '-',
489: (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W'));
490: }
491: x += 19;
1.1.1.9 root 492: screen.Print(x, y, "TC:%08x(%c%c%c)",
1.1 root 493: reg.tc,
494: (reg.tc & m68030TC::TC_E) ? 'E' : '-',
495: (reg.tc & m68030TC::TC_SRE) ? 'S' : '-',
496: (reg.tc & m68030TC::TC_FCL) ? 'F' : '-');
1.1.1.9 root 497: screen.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)",
1.1 root 498: reg.mmusr,
499: (reg.mmusr & m68030MMUSR::B) ? 'B' : '-',
500: (reg.mmusr & m68030MMUSR::L) ? 'L' : '-',
501: (reg.mmusr & m68030MMUSR::S) ? 'S' : '-',
502: (reg.mmusr & m68030MMUSR::W) ? 'W' : '-',
503: (reg.mmusr & m68030MMUSR::I) ? 'I' : '-',
504: (reg.mmusr & m68030MMUSR::M) ? 'M' : '-',
505: (reg.mmusr & m68030MMUSR::T) ? 'T' : '-',
506: (reg.mmusr & m68030MMUSR::N));
507:
508: // FPU
509: x = 0;
510: y = 7;
1.1.1.9 root 511: screen.Puts(x, y++, "<FPU>");
1.1 root 512: for (int i = 0; i < 8; i++) {
1.1.1.9 root 513: screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)",
1.1 root 514: i,
515: reg.fpframe.fpf_regs[i * 3 + 0] >> 16,
516: reg.fpframe.fpf_regs[i * 3 + 1],
517: reg.fpframe.fpf_regs[i * 3 + 2],
518: "not yet");
519: }
520:
521: x = 51;
522:
523: // FPCR
524: static const char * const rpstr[] = {
525: ".EXT",
526: ".SGL",
527: ".DBL",
528: ".???",
529: };
530: uint32 fpcr = reg.fpframe.fpf_fpcr;
1.1.1.9 root 531: screen.Print(x, y++, "FPCR:%04x", fpcr);
1.1.1.11 root 532: screen.Puts(x + 2, y, TA::OnOff(fpcr & 0x8000), "BS");
533: screen.Puts(x + 5, y, TA::OnOff(fpcr & 0x4000), "SN");
534: screen.Puts(x + 8, y, TA::OnOff(fpcr & 0x2000), "OP");
535: screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV");
536: screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF");
537: screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ");
538: screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2");
539: screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1");
540: y++;
1.1.1.9 root 541: screen.Print(x + 2, y++, "RP=%s RM=%s",
1.1 root 542: rpstr[(fpcr >> 6) & 3],
543: rmstr[(fpcr >> 4) & 3]);
544:
545: // FPSR
546: uint32 fpsr = reg.fpframe.fpf_fpsr;
547: uint32 cc = fpsr >> 24;
1.1.1.9 root 548: screen.Print(x, y++, "FPSR:%08x", fpsr);
1.1.1.11 root 549: screen.Puts(x + 2, y, TA::OnOff(cc & 0x08), "N");
550: screen.Puts(x + 4, y, TA::OnOff(cc & 0x04), "Z");
551: screen.Puts(x + 6, y, TA::OnOff(cc & 0x02), "Inf");
552: screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN");
553: screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff);
554: y++;
555: screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x8000), "BS");
556: screen.Puts(x + 5, y, TA::OnOff(fpsr & 0x4000), "SN");
557: screen.Puts(x + 8, y, TA::OnOff(fpsr & 0x2000), "OP");
558: screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV");
559: screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF");
560: screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ");
561: screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2");
562: screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1");
563: y++;
564: screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x80), "IOP");
565: screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x80), "OVFL");
566: screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL");
567: screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ");
568: screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX");
569: y++;
1.1 root 570:
571: // FPIAR
1.1.1.9 root 572: screen.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar);
1.1 root 573: }
574:
1.1.1.9 root 575: // モニター更新 (ATC)
1.1.1.3 root 576: void
1.1.1.9 root 577: MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen)
1.1 root 578: {
579: m68030ATCTable *table;
580: #if !defined(ATC_SINGLE)
581: struct {
582: int fc;
583: const char *name;
584: } fclist[] = {
585: { 1, "User/Data" },
586: { 2, "User/Program" },
587: { 5, "Super/Data" },
588: { 6, "Super/Program" },
589: };
590:
1.1.1.9 root 591: screen.Clear();
1.1 root 592:
593: // 行数は左端にだけ
594: for (int i = 0; i < m68030ATCTable::LINES; i++) {
1.1.1.9 root 595: screen.Print(0, i + 2, "%02d:", i);
1.1 root 596: }
597:
598: for (int t = 0; t < countof(fclist); t++) {
599: int x = t * 32 + 4;
600: int fc = fclist[t].fc;
601: const char *name = fclist[t].name;
602: double r;
603: int i;
604:
605: table = &cpu->atc.tables[fc];
1.1.1.9 root 606: screen.Print(x, 0, "FC=%d %s", fc, name);
607: screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age");
1.1 root 608: // 先に統計用の母数を計算
609: uint64 total = 0;
610: for (i = 0; i < countof(table->hit); i++) {
611: total += table->hit[i];
612: }
613: total += table->hit_head;
614:
615: // エントリ表示
616: for (i = 0; i < countof(table->line); i++) {
617: m68030ATCLine& a = table->line[i];
1.1.1.2 root 618: TA attr;
1.1 root 619: if (a.IsInvalid()) {
620: attr = TA::Disable;
621: } else if (table->head == &a) {
622: attr = TA::Em;
623: } else {
624: attr = TA::Normal;
625: }
626:
1.1.1.9 root 627: screen.Print(x, i + 2, attr, "%08x %08x %c%c%c",
1.1 root 628: a.GetLAddr(),
629: a.GetPAddr(),
630: a.IsBusError() ? 'B' : '-',
631: a.IsWProtect() ? 'P' : '-',
632: a.IsModified() ? 'M' : '-');
633: }
634: // ヘッドのヒット率
1.1.1.9 root 635: screen.Puts(x + 0, i + 2, "head");
1.1 root 636: r = (double)table->hit_head * 100 / total;
1.1.1.13 root 637: if (!std::isnan(r)) {
1.1.1.9 root 638: screen.Print(x + 5, i + 2, "%4.1f%%", r);
1.1 root 639: }
640: // 配列のヒット率とミス率
1.1.1.9 root 641: screen.Puts(x + 17, i + 2, "miss");
1.1 root 642: for (i = 0; i < countof(table->hit); i++) {
643: r = (double)(table->hit[i] * 100) / total;
1.1.1.13 root 644: if (!std::isnan(r)) {
1.1.1.9 root 645: screen.Print(x + 22, i + 2, "%4.1f%%", r);
1.1 root 646: }
647: }
648: // カウンタ
649: // 分かりやすさのため最大値からの差(距離)を表示
650: for (i = 0; i < countof(table->line); i++) {
651: m68030ATCLine& a = table->line[i];
652: if (!a.IsInvalid()) {
1.1.1.9 root 653: screen.Print(x + 27, i + 2, "%4d", table->head->age - a.age);
1.1 root 654: }
655: }
656: }
657: #else
658: m68030ATCLine *a;
659: int i;
660:
661: table = &cpu->atc.tables[0];
1.1.1.9 root 662: screen.Clear();
1.1 root 663:
1.1.1.9 root 664: screen.Puts(0, 0, "No. FC LAddr PAddr Flag");
1.1 root 665: for (a = table->head, i = 0; a; a = a->next, i++) {
1.1.1.9 root 666: screen.Print(0, i + 1, "%02d:", i);
1.1 root 667: if (!a->IsInvalid()) {
668: char dp;
669: switch (a->fc & 3) {
670: case 1: dp = 'D'; break;
671: case 2: dp = 'P'; break;
672: default: dp = '?'; break;
673: }
1.1.1.9 root 674: screen.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c",
1.1 root 675: a->fc,
676: (a->fc & 4) ? 'S' : 'U',
677: dp,
678: a->GetLAddr(), a->GetPAddr(),
679: a->IsBusError() ? 'B' : '-',
680: a->IsWProtect() ? 'W' : '-',
681: a->IsModified() ? 'M' : '-');
682: }
683: }
684: #endif
685: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.