--- nono/vm/mfp.cpp 2026/04/29 17:04:59 1.1.1.11 +++ nono/vm/mfp.cpp 2026/04/29 17:05:10 1.1.1.12 @@ -4,13 +4,19 @@ // Licensed under nono-license.txt // +// +// MFP (MC68901) +// + #include "mfp.h" #include "interrupt.h" #include "keyboard.h" -#include "mpu680x0.h" +#include "mpu.h" +#include "scheduler.h" #include "x68kkbd.h" -std::unique_ptr gMFP; +// グローバル参照用 +MFPDevice *gMFP; // コンストラクタ MFPDevice::MFPDevice() @@ -21,17 +27,17 @@ MFPDevice::MFPDevice() for (int ch = 0; ch < event.size(); ch++) { event[ch].dev = this; - event[ch].func = (DeviceCallback_t)&MFPDevice::TimerCallback; + event[ch].func = ToEventCallback(&MFPDevice::TimerCallback); event[ch].code = ch; - event[ch].SetName(string_format("MFP Timer-%c", ch + 'A')); + event[ch].Regist(string_format("MFP Timer-%c", ch + 'A')); } // キーボード周りは x68kkbd.cpp のコメント参照 - key_event.func = (DeviceCallback_t)&MFPDevice::KeyCallback; + key_event.func = ToEventCallback(&MFPDevice::KeyCallback); key_event.time = 3750_usec; - key_event.SetName("MFP USART"); + key_event.Regist("MFP USART"); - monitor.func = (MonitorCallback_t)&MFPDevice::MonitorUpdate; + monitor.func = ToMonitorCallback(&MFPDevice::MonitorUpdate); monitor.SetSize(77, 26); monitor.Regist(ID_MONITOR_MFP); } @@ -39,11 +45,12 @@ MFPDevice::MFPDevice() // デストラクタ MFPDevice::~MFPDevice() { + gMFP = NULL; } -// デバイスリセット +// リセット void -MFPDevice::ResetHard() +MFPDevice::ResetHard(bool poweron) { // All internal registers are cleared expect the TxDR, UDR, and TSR. mfp.aer = 0; @@ -64,9 +71,9 @@ MFPDevice::ResetHard() // All timers are stopped. for (auto& ev : event) { - ev.Stop(); + gScheduler->StopEvent(ev); } - key_event.Stop(); + gScheduler->StopEvent(key_event); // USART RX and TX are disabled. // SO line is placed in HighZ. @@ -180,7 +187,7 @@ MFPDevice::Write(uint32 offset, uint32 d mfp.gpip = data; break; case MFP::AER: - putlog(0, "AER <- $%02x 未実装書き込み", data); + putlog(2, "AER <- $%02x", data); mfp.aer = data; break; case MFP::DDR: @@ -573,11 +580,11 @@ MFPDevice::SetTCR(int ch, uint32 data) // していたが、イベントを停止すると求められなくなるので、イベント // 停止前に求めておく。 uint64 period = prescale_ns[prev]; - uint64 now = gMPU->GetVirtTime(); + uint64 now = gScheduler->GetVirtTime(); mfp.tdr[ch] = ((event[ch].vtime - now) + period - 1) / period; // でイベント停止 - event[ch].Stop(); + gScheduler->StopEvent(event[ch]); return; } else if (prev == 8) { // イベントカウントモードから停止しても何も起きないはず @@ -594,7 +601,7 @@ MFPDevice::SetTCR(int ch, uint32 data) // タイマースタート uint64 period = prescale_ns[mfp.tcr[ch]]; event[ch].time = period * (mfp.tdr[ch] ?: 256); - event[ch].Start(); + gScheduler->RestartEvent(event[ch]); putlog(1, "Timer-%c ディレイモード開始(%u x %u.%uusec)", ch + 'A', @@ -634,7 +641,7 @@ MFPDevice::GetTDR(int ch) const // プリスケーラと終了時刻から算出。 uint64 period = prescale_ns[tcr]; - uint64 now = gMPU->GetVirtTime(); + uint64 now = gScheduler->GetVirtTime(); return ((event[ch].vtime - now) + period - 1) / period; } else { @@ -656,7 +663,7 @@ MFPDevice::SetTDR(int ch, uint32 data) mfp.initial_tdr[ch] = data; } else if (tcr < 8) { - // ディレイモード動作中の書き込み + // ディレイモード動作中の書き込み。 // メインカウンタは影響を受けず、次回値を更新するだけ。 mfp.initial_tdr[ch] = data; @@ -685,12 +692,15 @@ MFPDevice::TimerCallback(Event& ev) // period が1メインパルス期間 // time が1タイムアウトパルス期間 uint64 period = prescale_ns[mfp.tcr[ch]]; - uint64 time = period * (mfp.tdr[ch] ?: 256); - // 次のタイムアウトパルスは、今回のタイムアウト時刻から数える - // (現在時刻はそれを通り過ぎた任意の時刻なので) - uint64 now = gMPU->GetVirtTime(); - ev.time = ev.vtime + time - now; - ev.Start(); + ev.time = period * (mfp.tdr[ch] ?: 256); + gScheduler->RestartEvent(ev); +} + +// HSync 入力 +void +MFPDevice::SetHSync(bool hsync) +{ + SetGPIP(MFP::GPIP_HSYNC, hsync); } // VDisp 入力 @@ -799,7 +809,7 @@ MFPDevice::ClearBF() // 実際のハードウェアでは、キーボードが本体 MFP が Ready になるのを待って // いるが、それに相当。 // システムポートの KEYCTRL はキーボード側で処理している。 - X68030Keyboard *x68kkbd = dynamic_cast(gKeyboard.get()); + X68030Keyboard *x68kkbd = dynamic_cast(gKeyboard); x68kkbd->Ready(); } @@ -857,7 +867,7 @@ MFPDevice::Rx(uint32 data) // ので、まだ Buffer Full は立てない。 key_event.code = data; - key_event.Start(); + gScheduler->RestartEvent(key_event); } // キーボードからのデータが受信し終わった頃に呼ばれるイベント。