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