--- nono/vm/spc.cpp 2026/04/29 17:05:13 1.1.1.13 +++ nono/vm/spc.cpp 2026/04/29 17:05:17 1.1.1.14 @@ -22,21 +22,13 @@ event.func = ToEventCallback(&SPCDevice::func_); \ event.time = time_; \ event.SetName(name_); \ - gScheduler->RestartEvent(event); \ + scheduler->RestartEvent(event); \ } while (0) -// グローバル参照用 -SPCDevice *gSPC; - // コンストラクタ SPCDevice::SPCDevice() - : inherited("SPC") + : inherited(OBJ_SPC) { - // これらは XIOSpace で必要なので、LUNA ではダミー。 - // もうちょっといい方法を考えたほうがいい。 - devaddr = 0xe96000; - devlen = 0x2000; - SetConfigName("spc0"); myid = -1; @@ -56,12 +48,14 @@ SPCDevice::SPCDevice() // デストラクタ SPCDevice::~SPCDevice() { - gSPC = NULL; } +// 初期化 bool SPCDevice::Init() { + // inherited::Init() は少し下で呼んでいる + // 実行中に別インスタンスを頻繁に参照しないようにここで vmtype を覚えておく vmtype = gMainApp.GetVMType(); @@ -85,7 +79,7 @@ SPCDevice::Init() // 入力クロックは機種によって異なる。 // X68k は 5MHz が入っている。 - // LUNA-I はおそらく 6.144MHz だと思われる。LUNA88K は未確認。 + // LUNA-I はおそらく 6.144MHz だと思われる。LUNA-88K は未確認。 const ConfigItem& item = gConfig->Find("!spc-tCLF"); t_CLF = item.AsInt(); @@ -104,9 +98,9 @@ SPCDevice::Init() // 割り込み信号線の接続先 if (vmtype == VMType::X68030) { // X68030 は PEDEC (I/O コントローラ) にカスケード - interrupt = gPEDEC; + interrupt = GetPEDECDevice(); } else { - interrupt = gInterrupt; + interrupt = GetInterruptDevice(); } monitor.SetSize(70, 15 + connected_devices.size()); @@ -140,8 +134,8 @@ SPCDevice::ResetHard(bool poweron) prev_ssts = (uint32)-1; set_atn_in_selection = false; transfer_command_running = false; - gScheduler->StopEvent(event); - gScheduler->StopEvent(event_tc); + scheduler->StopEvent(event); + scheduler->StopEvent(event_tc); last_busfree_time = 0; } @@ -151,7 +145,7 @@ SPCDevice::Read(uint32 offset) { uint8 data; - gMPU->AddCycle(read_wait); + mpu->AddCycle(read_wait); switch (offset) { case SPC::BDID: @@ -253,14 +247,14 @@ SPCDevice::Read(uint32 offset) return 0xff; default: - __unreachable(); + VMPANIC("corrupted offset=%d", offset); } } uint64 SPCDevice::Write(uint32 offset, uint32 data) { - gMPU->AddCycle(write_wait); + mpu->AddCycle(write_wait); switch (offset) { case SPC::BDID: @@ -360,7 +354,7 @@ SPCDevice::Write(uint32 offset, uint32 d return 0; default: - __unreachable(); + VMPANIC("corrupted offset=%d", offset); } } @@ -428,7 +422,7 @@ SPCDevice::Peek(uint32 offset) return 0xff; default: - __unreachable(); + return 0xff; } } @@ -849,7 +843,7 @@ SPCDevice::WriteINTS(uint32 data) } else { event_tc.func = ToEventCallback(&SPCDevice::SelectionTimeout); event_tc.time = spc.tc * t_CLF * 2; - gScheduler->RestartEvent(event_tc); + scheduler->RestartEvent(event_tc); } } } @@ -1076,7 +1070,14 @@ SPCDevice::WriteDREG(uint32 data) // DREG キューに入れて.. if (spc.dreg.Enqueue(data) == false) { - VMPANIC("DREG キューオーバーフロー"); + // XXX キューが一杯だったらどうなるのかは書いてないので分からない。 + // a) キューを押し出して先頭を破棄する + // b) キューの末尾を破棄して新着データで上書きする + // c) キューの内容は変わらず新着データを破棄する + // どれで実装しても「この時何かしら失われるデータがある」こと自体は + // 再現出来ているはずなので、ここではひとまず a) の動作にしておく。 + putlog(0, "DREG Queue overflow"); + spc.dreg.EnqueueForce(data); } // ハードウェア転送中で REQ が来てれば送信。 if (transfer_command_running && GetREQ()) { @@ -1193,7 +1194,7 @@ SPCDevice::SelectCommand() // t_FRID/t_BFBL はたぶん今からではなくバスフリーになった時点から起算。 // t_FRID と t_BFBL は同じ式なのでここでは t_BFBL で統一。 uint64 t_BFBL = (6 + spc.GetTCL()) * t_CLF; // Min - uint64 now = gScheduler->GetVirtTime(); + uint64 now = scheduler->GetVirtTime(); if ((last_busfree_time + t_BFBL) > now) { wait = (last_busfree_time + t_BFBL) - now; } else { @@ -1209,7 +1210,7 @@ SPCDevice::SelectCommand() if (N != 0) { event_tc.func = ToEventCallback(&SPCDevice::SelectionTimeout); event_tc.time = (N + 15) * t_CLF * 2; - gScheduler->RestartEvent(event_tc); + scheduler->RestartEvent(event_tc); } if ((spc.sctl & SPC::SCTL_ARBIT_EN)) { @@ -1375,7 +1376,7 @@ SPCDevice::BusFreeCB(int id) putlog(4, "BusFree Callback"); inherited::BusFreeCB(id); - last_busfree_time = gScheduler->GetVirtTime(); + last_busfree_time = scheduler->GetVirtTime(); transfer_command_running = false; spc.ssts &= ~(SPC::SSTS_CONN_INIT | SPC::SSTS_CONN_TARG); @@ -1403,7 +1404,7 @@ SPCDevice::SelectionAckCB() NegateSEL(); // タイムアウトイベントを停止 - gScheduler->StopEvent(event_tc); + scheduler->StopEvent(event_tc); spc.ssts &= ~SPC::SSTS_SPC_BUSY; spc.ssts |= SPC::SSTS_CONN_INIT;