--- nono/vm/dmac.cpp 2026/04/29 17:05:29 1.1.1.14 +++ nono/vm/dmac.cpp 2026/04/29 17:05:50 1.1.1.17 @@ -10,17 +10,20 @@ #include "dmac.h" #include "adpcm.h" +#include "event.h" #include "fdc.h" #include "interrupt.h" #include "mainbus.h" +#include "monitor.h" #include "mpu.h" #include "scheduler.h" +#include "syncer.h" // time 時間後に呼び出すコールバックをセットする。 // func の書式が面倒なのを省略して書きたいため。 #define CallAfter(func_, time_, wait_) do { \ - event.func = ToEventCallback(&DMACDevice::func_); \ - event.time = time_ * 80_nsec + wait_; \ + event->func = ToEventCallback(&DMACDevice::func_); \ + event->time = time_ * 80_nsec + wait_; \ scheduler->StartEvent(event); \ } while (0) @@ -52,9 +55,9 @@ DMACDevice::DMACDevice() channel[2].pcl_prev = true; // #3 は未対応 - monitor.func = ToMonitorCallback(&DMACDevice::MonitorUpdate); - monitor.SetSize(80, 34); - monitor.Regist(ID_MONITOR_DMAC); + monitor = gMonitorManager->Regist(ID_MONITOR_DMAC, this); + monitor->func = ToMonitorCallback(&DMACDevice::MonitorUpdate); + monitor->SetSize(80, 34); } // デストラクタ @@ -66,17 +69,14 @@ DMACDevice::~DMACDevice() bool DMACDevice::Init() { - if (inherited::Init() == false) { - return false; - } - adpcm = GetADPCMDevice(); fdc = GetFDCDevice(); interrupt = GetInterruptDevice(); mainbus = GetMainbusDevice(); + syncer = GetSyncer(); - event.SetName("DMAC"); - scheduler->RegistEvent(event); + auto evman = GetEventManager(); + event = evman->Regist(this, NULL, "DMAC"); return true; } @@ -120,10 +120,11 @@ DMACDevice::ResetHard(bool poweron) chan->priority = 0; } + syncer->RequestDMACActive(false); ChangeInterrupt(); // イベントを停止 - event.SetName("DMAC"); + event->SetName("DMAC"); scheduler->StopEvent(event); } @@ -874,7 +875,7 @@ DMACDevice::MonitorReg4(TextScreen& scre if (names[i][0] == '-') { screen.Puts(x + i * 4, y, TA::Disable, "---"); } else { - bool b = reg & (1 << (3 - i)); + bool b = reg & (1U << (3 - i)); screen.Puts(x + i * 4, y, TA::OnOff(b), names[i]); } } @@ -1044,6 +1045,22 @@ DMACDevice::WriteCCR(DMACChan *chan, uin ChangeInterrupt(); } +// CSR.ACT ビットの状態を変更。 +void +DMACDevice::ChangeACT(DMACChan *chan, bool active) +{ + chan->active = active; + + // チャンネルの ACT を変更した結果、 + // トータルでアクティブかどうかを Syncer に通知する。 + bool dmac_active = + channel[0].active || + channel[1].active || + channel[2].active || + channel[3].active; + syncer->RequestDMACActive(dmac_active); +} + // 転送開始 void DMACDevice::StartTransfer(DMACChan *chan) @@ -1056,7 +1073,7 @@ DMACDevice::StartTransfer(DMACChan *chan } // ACT を立てたら STR を下げる。 - chan->active = true; + ChangeACT(chan, true); chan->str = false; // XXX あとで移動する @@ -1131,7 +1148,7 @@ DMACDevice::StartTransfer(DMACChan *chan putlogn("#%u Start %s mtc=$%04x", chan->ch, msg.c_str(), chan->mtc); } - if (event.IsRunning() == false) { + if (event->IsRunning() == false) { CallAfter(StartCallback, 0, 0); } } @@ -1158,18 +1175,18 @@ DMACDevice::SelectChannel() } if (ch == -1) { // 転送チャンネルはもうないのでイベントは停止したままにする - event.SetName("DMAC"); + event->SetName("DMAC"); return NULL; } else { chan = &channel[ch]; - event.SetName(string_format("DMAC #%u", chan->ch)); + event->SetName(string_format("DMAC #%u", chan->ch)); return chan; } } // 転送開始 void -DMACDevice::StartCallback(Event& ev) +DMACDevice::StartCallback(Event *ev) { // チャンネルを決定 auto chan = SelectChannel(); @@ -1267,7 +1284,7 @@ DMACDevice::StartCallback(Event& ev) // 転送処理 void -DMACDevice::TransferCallback(Event& ev) +DMACDevice::TransferCallback(Event *ev) { // チャンネルを決定 auto chan = SelectChannel(); @@ -1480,7 +1497,7 @@ DMACDevice::TransferCallback(Event& ev) // すべての転送完了か if (__predict_false(chan->mtc == 0)) { chan->csr |= DMAC::CSR_COC; - chan->active = false; + ChangeACT(chan, false); ChangeInterrupt(); } @@ -1519,7 +1536,7 @@ DMACDevice::TransferError(DMACChan *chan } // 現在のイベントを再実行 - event.time = 1 * 80_nsec; + event->time = 1 * 80_nsec; scheduler->StartEvent(event); return; } else { @@ -1638,7 +1655,7 @@ DMACDevice::Error(DMACChan *chan, uint8 // データシート p.43 chan->cer = errcode; chan->csr |= DMAC::CSR_COC | DMAC::CSR_ERR; - chan->active = false; + ChangeACT(chan, false); chan->str = false; chan->cnt = false; ChangeInterrupt(); @@ -1699,7 +1716,7 @@ DMACDevice::AssertREQ(uint ch) chan->pcl_pin = true; } - if (event.IsRunning() == false) { + if (event->IsRunning() == false) { scheduler->StartEvent(event); } } @@ -1731,7 +1748,8 @@ DMACDevice::AbortTransfer(DMACChan *chan chan->str = false; chan->cnt = false; - chan->active = false; + ChangeACT(chan, false); + chan->cer = DMAC::CER_SOFT_ABORT; // ERR ビットが立つと SAB をクリアする chan->csr |= DMAC::CSR_ERR;