--- nono/vm/mpu680x0.cpp 2026/04/29 17:04:42 1.1.1.4 +++ nono/vm/mpu680x0.cpp 2026/04/29 17:05:09 1.1.1.13 @@ -4,38 +4,51 @@ // Licensed under nono-license.txt // -// MPU (m680x0) +// +// MPU (MC68030) +// #include "mpu680x0.h" #include "config.h" +#include "debugger.h" +#include "debugger_private.h" +#include "m68030bus.h" #include "m68030excep.h" #include "mainapp.h" +#include "scheduler.h" +#include "sync.h" +#include "uimessage.h" #include "vm.h" -#include +#include -std::unique_ptr gMPUATC; +static void mpu680x0_reset_inst(void *); +static void mpu680x0_halt(void *); // コンストラクタ -// -// reset_vector にはリセットベクタの番地を指定する。 -// 本来の MPU の動作は、リセット例外時にメモリの $0, $4 番地 (もっと言えば -// FC がプログラム空間の) から SP, PC を読み込むのだが、そのためにメモリ空間 -// を切り替える処理はリセット時にしか必要ないわりに結構手間である。そしてこの -// m68k 恒例のブートストラップ動作はソフトウェア的には一切観測する手段がない。 -// であれば、リセット例外時にこのアドレスから SP, PC の値を直接読み込んだと -// しても動作にはまったく違いは出ない。そしてバス・メモリ空間の実装も簡略化 -// できる。すごい楽。 -MPU680x0Device::MPU680x0Device(uint32 reset_vector) -{ - monitor_size = nnSize(79, 16); +MPU680x0Device::MPU680x0Device() + : inherited("MPU(68030)") +{ + cpu = m68030_init(this); - cpu = m68030_init(reset_vector); + // 割り込みイベントコールバック設定 + intr_event.func = ToEventCallback(&MPU680x0Device::InterruptCallback); + intr_event.Regist("MPU Interrupt"); + + // レジスタモニター + reg_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateReg); + reg_monitor.SetSize(79, 16); + reg_monitor.Regist(ID_MONITOR_MPUREG); - // リセット例外イベントコールバック設定 - reset_event.func = (DeviceCallback_t)&MPU680x0Device::ResetCallback; + // ATC モニター + atc_monitor.func = ToMonitorCallback(&MPU680x0Device::MonitorUpdateATC); +#if !defined(ATC_SINGLE) + atc_monitor.SetSize(131, m68030ATCTable::LINES + 3); +#else + atc_monitor.SetSize(31, 24); +#endif + atc_monitor.Regist(ID_MONITOR_MPUATC); - // モニタ用の別オブジェクト - gMPUATC.reset(new MPUATC(cpu)); + SetTrace(false); } // デストラクタ @@ -46,6 +59,21 @@ MPU680x0Device::~MPU680x0Device() bool MPU680x0Device::Init() { + // 親クラス + if (inherited::Init() == false) { + return false; + } + + // 割り込み時のディレイ。 + // + // 外部デバイスが 68030 の IPL0-2 をアサートしてから、68030 がそれを + // 認識(確定)するのに 1 ~ 2 クロックかかる。 + // その後レベルを比較するのは次のアップエッジ。 + // その後 /IPEND をアサートするのはその次のアップエッジ。 + // 合わせると、IPL0-2 が変化してから /IPEND がアサートされるまでは + // 2 ~ 3 クロックかかる。(Figure 8-4) + intr_event.time = 3 * clock_nsec; + // FPU (6888x) if (gMainApp.GetVMType() == VMTYPE_LUNA1) { // LUNA は 68881 固定 (設定は見ない) @@ -60,41 +88,194 @@ MPU680x0Device::Init() } } + cpu->resetop_callback = mpu680x0_reset_inst; + cpu->resetop_arg = NULL; + cpu->halt_callback = mpu680x0_halt; + cpu->halt_arg = this; + return true; } -// リセット例外イベントコールバック +// リセット +void +MPU680x0Device::ResetHard(bool poweron) +{ + if (poweron) { + m68030_power_on(cpu); + } + + // リセット例外を 520 クロック後に起こす。 + // 520 は、電源オン時、Vcc が最小動作規定値に達してから最低 520 クロック + // の間アサートしなければならないという値であって、実際これだけかかる + // とかいう値ではない。が、こちら側の都合で、この後実行される RAM の + // ResetHard() がブートページを用意した後で m68030_exception_reset() で + // SP, PC をフェッチするという順序にしないといけないため、リセット例外が + // 起動するまでに時間がかかるというところを都合よく真似ておく。 + + exec_event.func = ToEventCallback(&MPU680x0Device::ResetCallback); + exec_event.time = 520 * clock_nsec; + exec_event.SetName("MPU Reset"); + gScheduler->RestartEvent(exec_event); +} + +// リセット例外コールバック。 +// MPU リセットから規定時間後に呼ばれる。 void MPU680x0Device::ResetCallback(Event& ev) { - m68030_exception_reset(cpu); + intr_pending = false; + + // リセット例外を実行 + int cycle = m68030_exception_reset(cpu); + + // コールバックを ResetCallback から Exec* に差し替える前のここで + // トレース状態を初期化する。 + SetTrace(gDebugger->IsTrace()); + + // 以降は通常走行。 + if (cpu->state == m68kcpu::CPU_STATE_NORMAL) { + exec_event.func = exec_short; + exec_event.time = cycle * clock_nsec; + exec_event.SetName("MPU Execute"); + gScheduler->StartEvent(exec_event); + } else { + // リセット例外でダブルバスフォールトならここで停止。 + } +} + +// 通常の1命令実行のコールバック +// 割り込みチェックなどを省いたショート版。 +void +MPU680x0Device::ExecShort(Event& ev) +{ + int cycle = m68030_exec(cpu); + + ev.time = cycle * clock_nsec; + gScheduler->StartEvent(ev); +} + +// 割り込みチェック、STOP 処理を含んだ完全な実行サイクルのコールバック。 +// SR の I2:I0 が変わった直後などに呼ばれる。 +// ここでは割り込みをチェックし、必要なら割り込み処理を起動、 +// そうでなければ通常の命令実行を行う。 +void +MPU680x0Device::ExecFull(Event& ev) +{ + if (intr_pending) { + // 割り込み処理を起動。 + + intr_pending = false; + + // 前の命令実行後となるここで割り込みを起動 + int cycle = m68030_exception_interrupt(cpu); + + ev.time = cycle * clock_nsec; + gScheduler->StartEvent(ev); + } else { + if (cpu->state == m68kcpu::CPU_STATE_NORMAL) { + // コールバックを通常処理に戻してから... + exec_event.func = exec_short; + + // この場で次の命令を実行。 + ExecShort(ev); + } else { + // STOP ならここで停止。HALT はそもそも来ないはず。 + } + } +} + +// トレース実行 +void +MPU680x0Device::ExecTrace(Event& ev) +{ + gDebugger->Exec(); + ExecFull(ev); +} + +// トレース状態を設定する +void +MPU680x0Device::SetTrace(bool enable) +{ + if (enable) { + exec_short = ToEventCallback(&MPU680x0Device::ExecTrace); + exec_full = ToEventCallback(&MPU680x0Device::ExecTrace); + } else { + exec_short = ToEventCallback(&MPU680x0Device::ExecShort); + exec_full = ToEventCallback(&MPU680x0Device::ExecFull); + } + exec_event.func = exec_full; + + // STOP 命令中にオンにするには、停止しているイベントを起こす。 + // STOP 命令中にオフにする場合は、何もしなくていい。 + if (enable && exec_event.IsRunning() == false) { + gScheduler->StartEvent(exec_event); + } +} + +// 割り込みレベルが変わったことを MPU に通知。 +void +MPU680x0Device::Interrupt(int level) +{ + assertmsg(0 <= level && level <= 7, "level=%d", level); + + intr_event.code = level; + if (intr_event.IsRunning() == false) { + gScheduler->StartEvent(intr_event); + } } -// MPU を request で指定されたクロックサイクルだけ実行する。 -// 今回の実行サイクル数が request を越えた命令境界まで実行するので -// 実際には少しはみ出る。 -// また実行中にデバイスアクセスなどによりスケジューラにイベントが -// 追加されるとその次の命令境界で処理を打ち切って戻ってくる。 -// 戻り値は CPU の outer フラグ。 -uint32 -MPU680x0Device::Run(uint64 request) +// 外部割り込みイベントコールバック。 +// 割り込みレベルが変わったことをコアに通知する。 +// ev.code 0-7 は新しい割り込みレベル。 +void +MPU680x0Device::InterruptCallback(Event& ev) { - return m68030_run(cpu, request); + int level = ev.code; + + if (m68030_interrupt(cpu, level)) { + // 通知した結果割り込みが受け付けられたので、 + // この命令終了時のコールバックを割り込み処理起動に差し替える。 + MakeNextFull(); + intr_pending = true; + + // STOP 状態だったらここでイベントを開始する + if (cpu->state == m68kcpu::CPU_STATE_STOP) { + // STOP から抜ける時間? + exec_event.time = 1 * clock_nsec; + gScheduler->StartEvent(exec_event); + } + } } -// 割り込み発生を MPU に通知 (オートベクタ) +// 次の命令境界で割り込みチェックを行う。 +// (割り込みマスクを変更する命令の実行で呼ばれる) void -MPU680x0Device::Interrupt(Object *src, int level) +MPU680x0Device::CheckIntr() { - int vector = M68K_EXCEP_LEVEL_BASE + level; - m68030_interrupt(cpu, level, vector); + MakeNextFull(); + intr_pending |= m68030_check_interrupt(cpu); } -// 割り込み発生を MPU に通知 (ベクタ) +// 次の命令境界は Full にする。 void -MPU680x0Device::Interrupt(Object *src, int level, int vector) +MPU680x0Device::MakeNextFull() +{ + exec_event.func = exec_full; +} + +// コアからの動作変更通知 +/*static*/ void +MPU680x0Device::NotifyCPUMode(uint32 new_mode) { - m68030_interrupt(cpu, level, vector); + // new_mode (m68kcpu::CPU_STATE_*) と + // RequestCPUMode() の引数 Sync::SCHED_CPU_* は + // 実は同じ値なのでそのまま渡してよいことにする。 + static_assert(m68kcpu::CPU_STATE_NORMAL == Sync::SCHED_CPU_NORMAL, ""); + static_assert(m68kcpu::CPU_STATE_STOP == Sync::SCHED_CPU_STOP, ""); + static_assert(m68kcpu::CPU_STATE_HALT == Sync::SCHED_CPU_HALT, ""); + + // 通知 (同期のため) + gSync->RequestCPUMode(new_mode); } // A-Line 命令エミュレーションのコールバックを指定。 @@ -113,33 +294,116 @@ MPU680x0Device::SetFLineCallback(bool (* cpu->fline_arg = arg; } -// ダブルバスフォールトのコールバックを指定。 +// RESET 命令の CPU からのコールバック関数 +static void +mpu680x0_reset_inst(void *arg) +{ + gVM->ResetByMPU(); +} + +// ホールト時の CPU からのコールバック関数 +static void +mpu680x0_halt(void *arg) +{ + ((MPU680x0Device *)arg)->Halt(); +} + +// ホールト状態 void -MPU680x0Device::SetHaltCallback(void (*callback)(void *), void *arg) +MPU680x0Device::Halt() { - cpu->halt_callback = callback; - cpu->halt_arg = arg; + // 動作停止 + gScheduler->StopEvent(exec_event); + + // UI に通知 (メッセージボックス表示とか) + UIMessage::Post(UIMessage::HALT); +} + +// MPU からのアクセスをエミュレート +uint64 +MPU680x0Device::Read8(uint32 addr) +{ + try { + return m68030_read_8(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Read16(uint32 addr) +{ + try { + return m68030_read_16(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Read32(uint32 addr) +{ + try { + return m68030_read_32(cpu, addr); + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write8(uint32 addr, uint32 data) +{ + try { + m68030_write_8(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write16(uint32 addr, uint32 data) +{ + try { + m68030_write_16(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } +} + +uint64 +MPU680x0Device::Write32(uint32 addr, uint32 data) +{ + try { + m68030_write_32(cpu, addr, data); + return 0; + } catch (...) { + return (uint64)-1; + } } // モニター更新 (レジスタウィンドウ) void -MPU680x0Device::MonitorUpdate(TextScreen& monitor) +MPU680x0Device::MonitorUpdateReg(Monitor *, TextScreen& screen) { m68kreg reg; uint32 ppc; + uint32 state; int x; int y; - monitor.Clear(); + screen.Clear(); // ローカルにコピー - // ただし PPC だけ reg 構造体ではなく cpu クラス側にある + // ただし一部は reg ではなく cpu クラス本体にある reg = cpu->reg; ppc = cpu->ppc; + state = cpu->state; // データレジスタ、アドレスレジスタ for (int i = 0; i < 4; i++) { - monitor.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x", + screen.Print(0, i, "D%d:%08x D%d:%08x A%d:%08x A%d:%08x", i + 0, reg.da[i], i + 4, reg.da[i + 4], i + 0, reg.da[i + 8], @@ -149,7 +413,7 @@ MPU680x0Device::MonitorUpdate(TextScreen // 5列目 x = 50; // SR - monitor.Print(x, 0, "SR:%04x(%c%c%c%c%c)", + screen.Print(x, 0, "SR:%04x(%c%c%c%c%c)", (reg.sr_h() | reg.ccr.Get()), (reg.ccr.IsX()) ? 'X' : '-', (reg.ccr.IsN()) ? 'N' : '-', @@ -158,22 +422,22 @@ MPU680x0Device::MonitorUpdate(TextScreen (reg.ccr.IsC()) ? 'C' : '-'); // VBR - monitor.Print(x, 1, "VBR:%08x", reg.vbr); + screen.Print(x, 1, "VBR:%08x", reg.vbr); // *SP uint ms = (reg.s ? 2 : 0) | (reg.m ? 1 : 0); // T1 T0 S M if (ms == 3) { // Supervisor (Master) mode (A7=MSP, USP/ISP) - monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); - monitor.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp); + screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); + screen.Print(x, 3, TA::Disable, "ISP:%08x", reg.isp); } else if (ms == 2) { // Supervisor (Interrupt) mode (A7=ISP, USP/MSP) - monitor.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); - monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); + screen.Print(x, 2, TA::Disable, "USP:%08x", reg.usp); + screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); } else { // User mode (A7=USP, ISP/MSP) - monitor.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp); - monitor.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); + screen.Print(x, 2, TA::Disable, "ISP:%08x", reg.isp); + screen.Print(x, 3, TA::Disable, "MSP:%08x", reg.msp); } // 6列目 @@ -182,42 +446,48 @@ MPU680x0Device::MonitorUpdate(TextScreen // CACR:01234567 // CAAR:01234567 x = 66; - monitor.Print(x, 0, "PC: %08x", ppc); - monitor.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc); - monitor.Print(x, 2, "CACR:%08x", reg.cacr); - monitor.Print(x, 3, "CAAR:%08x", reg.caar); + screen.Print(x, 0, "PC: %08x", ppc); + screen.Print(x, 1, "SFC:%d DFC:%d", reg.sfc, reg.dfc); + screen.Print(x, 2, "CACR:%08x", reg.cacr); + screen.Print(x, 3, "CAAR:%08x", reg.caar); // XXX どこに置くのがいいか - if (reg.state == 0) { - monitor.Puts(25, 4, "State: Running"); - } else if (reg.state == CPU_REQ_STOP) { - monitor.Puts(25, 4, "State: STOP instruction"); - } else if (reg.state == CPU_REQ_HALT) { - monitor.Puts(25, 4, TA::On, "State: Double Bus Fault"); + switch (state) { + case m68kcpu::CPU_STATE_NORMAL: + screen.Puts(25, 4, "State: Running"); + break; + case m68kcpu::CPU_STATE_STOP: + screen.Puts(25, 4, "State: STOP instruction"); + break; + case m68kcpu::CPU_STATE_HALT: + screen.Puts(25, 4, TA::On, "State: Double Bus Fault"); + break; + default: + __unreachable(); } // MMU x = 0; y = 4; - monitor.Puts(x, y++, ""); - monitor.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l); - monitor.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l); + screen.Puts(x, y++, ""); + screen.Print(x, y, "SRP:%08x_%08x", reg.srp.h, reg.srp.l); + screen.Print(x, y + 1, "CRP:%08x_%08x", reg.crp.h, reg.crp.l); x += 23; for (int i = 0; i < 2; i++) { uint32 tt = reg.tt[i]; - monitor.Print(x, y + i, "TT%d:%08x(%c%c%c)", + screen.Print(x, y + i, "TT%d:%08x(%c%c%c)", i, tt, (tt & m68030TT::E) ? 'E' : '-', (tt & m68030TT::CI) ? 'C' : '-', (tt & m68030TT::RWM) ? '-' : ((tt & m68030TT::RW) ? 'R' : 'W')); } x += 19; - monitor.Print(x, y, "TC:%08x(%c%c%c)", + screen.Print(x, y, "TC:%08x(%c%c%c)", reg.tc, (reg.tc & m68030TC::TC_E) ? 'E' : '-', (reg.tc & m68030TC::TC_SRE) ? 'S' : '-', (reg.tc & m68030TC::TC_FCL) ? 'F' : '-'); - monitor.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)", + screen.Print(x, y + 1, "MMUSR: %04x(%c%c%c%c%c%c%c N=%d)", reg.mmusr, (reg.mmusr & m68030MMUSR::B) ? 'B' : '-', (reg.mmusr & m68030MMUSR::L) ? 'L' : '-', @@ -231,9 +501,9 @@ MPU680x0Device::MonitorUpdate(TextScreen // FPU x = 0; y = 7; - monitor.Puts(x, y++, ""); + screen.Puts(x, y++, ""); for (int i = 0; i < 8; i++) { - monitor.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", + screen.Print(x, y + i, "FP%d:%04x_%08x_%08x (%-20s)", i, reg.fpframe.fpf_regs[i * 3 + 0] >> 16, reg.fpframe.fpf_regs[i * 3 + 1], @@ -250,79 +520,54 @@ MPU680x0Device::MonitorUpdate(TextScreen ".DBL", ".???", }; - static const char * const rmstr[] = { - "Near", - "Zero", - "Minus", - "Plus", - }; uint32 fpcr = reg.fpframe.fpf_fpcr; - monitor.Print(x, y++, "FPCR:%04x", fpcr); - monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", - (fpcr & 0x8000) ? "BS" : "--", - (fpcr & 0x4000) ? "SN" : "--", - (fpcr & 0x2000) ? "OP" : "--", - (fpcr & 0x1000) ? "OV" : "--", - (fpcr & 0x0800) ? "UF" : "--", - (fpcr & 0x0400) ? "DZ" : "--", - (fpcr & 0x0200) ? "I2" : "--", - (fpcr & 0x0100) ? "I1" : "--"); - monitor.Print(x + 2, y++, "RP=%s RM=%s", + screen.Print(x, y++, "FPCR:%04x", fpcr); + screen.Puts(x + 2, y, TA::OnOff(fpcr & 0x8000), "BS"); + screen.Puts(x + 5, y, TA::OnOff(fpcr & 0x4000), "SN"); + screen.Puts(x + 8, y, TA::OnOff(fpcr & 0x2000), "OP"); + screen.Puts(x + 11, y, TA::OnOff(fpcr & 0x1000), "OV"); + screen.Puts(x + 14, y, TA::OnOff(fpcr & 0x0800), "UF"); + screen.Puts(x + 17, y, TA::OnOff(fpcr & 0x0400), "DZ"); + screen.Puts(x + 20, y, TA::OnOff(fpcr & 0x0200), "I2"); + screen.Puts(x + 23, y, TA::OnOff(fpcr & 0x0100), "I1"); + y++; + screen.Print(x + 2, y++, "RP=%s RM=%s", rpstr[(fpcr >> 6) & 3], rmstr[(fpcr >> 4) & 3]); // FPSR uint32 fpsr = reg.fpframe.fpf_fpsr; uint32 cc = fpsr >> 24; - monitor.Print(x, y++, "FPSR:%08x", fpsr); - monitor.Print(x + 2, y++, "%c %c %s %s Q=$%02x", - (cc & 0x08) ? 'N' : '-', - (cc & 0x04) ? 'Z' : '-', - (cc & 0x02) ? "Inf" : "---", - (cc & 0x01) ? "NAN" : "---", - (fpsr >> 16) & 0xff); - monitor.Print(x + 2, y++, "%s %s %s %s %s %s %s %s", - (fpsr & 0x8000) ? "BS" : "--", - (fpsr & 0x4000) ? "SN" : "--", - (fpsr & 0x2000) ? "OP" : "--", - (fpsr & 0x1000) ? "OV" : "--", - (fpsr & 0x0800) ? "UF" : "--", - (fpsr & 0x0400) ? "DZ" : "--", - (fpsr & 0x0200) ? "I2" : "--", - (fpsr & 0x0100) ? "I1" : "--"); - monitor.Print(x + 2, y++, "%s %s %s %s %s", - (fpsr & 0x80) ? "IOP" : "---", - (fpsr & 0x40) ? "OVFL" : "----", - (fpsr & 0x20) ? "UNFL" : "----", - (fpsr & 0x10) ? "DZ" : "--", - (fpsr & 0x08) ? "INEX" : "----"); + screen.Print(x, y++, "FPSR:%08x", fpsr); + screen.Puts(x + 2, y, TA::OnOff(cc & 0x08), "N"); + screen.Puts(x + 4, y, TA::OnOff(cc & 0x04), "Z"); + screen.Puts(x + 6, y, TA::OnOff(cc & 0x02), "Inf"); + screen.Puts(x + 10, y, TA::OnOff(cc & 0x01), "NAN"); + screen.Print(x + 14, y, "Q=$%02x", (fpsr >> 16) & 0xff); + y++; + screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x8000), "BS"); + screen.Puts(x + 5, y, TA::OnOff(fpsr & 0x4000), "SN"); + screen.Puts(x + 8, y, TA::OnOff(fpsr & 0x2000), "OP"); + screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x1000), "OV"); + screen.Puts(x + 14, y, TA::OnOff(fpsr & 0x0800), "UF"); + screen.Puts(x + 17, y, TA::OnOff(fpsr & 0x0400), "DZ"); + screen.Puts(x + 20, y, TA::OnOff(fpsr & 0x0200), "I2"); + screen.Puts(x + 23, y, TA::OnOff(fpsr & 0x0100), "I1"); + y++; + screen.Puts(x + 2, y, TA::OnOff(fpsr & 0x80), "IOP"); + screen.Puts(x + 6, y, TA::OnOff(fpsr & 0x80), "OVFL"); + screen.Puts(x + 11, y, TA::OnOff(fpsr & 0x80), "UNFL"); + screen.Puts(x + 16, y, TA::OnOff(fpsr & 0x80), "DZ"); + screen.Puts(x + 19, y, TA::OnOff(fpsr & 0x80), "INEX"); + y++; // FPIAR - monitor.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); -} - -// CPU 側からのコールバック。RESET 命令ハンドラ -void -m68030_reset_inst(m68kcpu *cpu) -{ - gVM->ResetSoft(); -} - -// -// ATC モニタ -// -MPUATC::MPUATC(m68kcpu *cpu_) -{ - cpu = cpu_; -#if !defined(ATC_SINGLE) - monitor_size = nnSize(131, m68030ATCTable::LINES + 3); -#else - monitor_size = nnSize(31, 24); -#endif + screen.Print(x, y++, "FPIAR:%08x", reg.fpframe.fpf_fpiar); } +// モニター更新 (ATC) void -MPUATC::MonitorUpdate(TextScreen& monitor) +MPU680x0Device::MonitorUpdateATC(Monitor *, TextScreen& screen) { m68030ATCTable *table; #if !defined(ATC_SINGLE) @@ -336,11 +581,11 @@ MPUATC::MonitorUpdate(TextScreen& monito { 6, "Super/Program" }, }; - monitor.Clear(); + screen.Clear(); // 行数は左端にだけ for (int i = 0; i < m68030ATCTable::LINES; i++) { - monitor.Print(0, i + 2, "%02d:", i); + screen.Print(0, i + 2, "%02d:", i); } for (int t = 0; t < countof(fclist); t++) { @@ -351,8 +596,8 @@ MPUATC::MonitorUpdate(TextScreen& monito int i; table = &cpu->atc.tables[fc]; - monitor.Print(x, 0, "FC=%d %s", fc, name); - monitor.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); + screen.Print(x, 0, "FC=%d %s", fc, name); + screen.Puts(x, 1, "LAddr PAddr Flag Hit% Age"); // 先に統計用の母数を計算 uint64 total = 0; for (i = 0; i < countof(table->hit); i++) { @@ -372,7 +617,7 @@ MPUATC::MonitorUpdate(TextScreen& monito attr = TA::Normal; } - monitor.Print(x, i + 2, attr, "%08x %08x %c%c%c", + screen.Print(x, i + 2, attr, "%08x %08x %c%c%c", a.GetLAddr(), a.GetPAddr(), a.IsBusError() ? 'B' : '-', @@ -380,17 +625,17 @@ MPUATC::MonitorUpdate(TextScreen& monito a.IsModified() ? 'M' : '-'); } // ヘッドのヒット率 - monitor.Puts(x + 0, i + 2, "head"); + screen.Puts(x + 0, i + 2, "head"); r = (double)table->hit_head * 100 / total; - if (!isnan(r)) { - monitor.Print(x + 5, i + 2, "%4.1f%%", r); + if (!std::isnan(r)) { + screen.Print(x + 5, i + 2, "%4.1f%%", r); } // 配列のヒット率とミス率 - monitor.Puts(x + 17, i + 2, "miss"); + screen.Puts(x + 17, i + 2, "miss"); for (i = 0; i < countof(table->hit); i++) { r = (double)(table->hit[i] * 100) / total; - if (!isnan(r)) { - monitor.Print(x + 22, i + 2, "%4.1f%%", r); + if (!std::isnan(r)) { + screen.Print(x + 22, i + 2, "%4.1f%%", r); } } // カウンタ @@ -398,7 +643,7 @@ MPUATC::MonitorUpdate(TextScreen& monito for (i = 0; i < countof(table->line); i++) { m68030ATCLine& a = table->line[i]; if (!a.IsInvalid()) { - monitor.Print(x + 27, i + 2, "%4d", table->head->age - a.age); + screen.Print(x + 27, i + 2, "%4d", table->head->age - a.age); } } } @@ -407,11 +652,11 @@ MPUATC::MonitorUpdate(TextScreen& monito int i; table = &cpu->atc.tables[0]; - monitor.Clear(); + screen.Clear(); - monitor.Puts(0, 0, "No. FC LAddr PAddr Flag"); + screen.Puts(0, 0, "No. FC LAddr PAddr Flag"); for (a = table->head, i = 0; a; a = a->next, i++) { - monitor.Print(0, i + 1, "%02d:", i); + screen.Print(0, i + 1, "%02d:", i); if (!a->IsInvalid()) { char dp; switch (a->fc & 3) { @@ -419,7 +664,7 @@ MPUATC::MonitorUpdate(TextScreen& monito case 2: dp = 'P'; break; default: dp = '?'; break; } - monitor.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c", + screen.Print(4, i + 1, "%d(%c%c):%08x %08x %c%c%c", a->fc, (a->fc & 4) ? 'S' : 'U', dp,