--- nono/vm/scsibus.cpp 2026/04/29 17:04:50 1.1.1.6 +++ nono/vm/scsibus.cpp 2026/04/29 17:05:17 1.1.1.11 @@ -4,29 +4,28 @@ // Licensed under nono-license.txt // +// // SCSI バス +// #include "scsibus.h" #include "scsidev.h" +#include "scheduler.h" // time 時間後に呼び出すコールバックをセットする。 // func の書式が面倒なのを省略して書きたいため。 #define CallAfter(func_, name_, time_) do { \ - event.func = (DeviceCallback_t)&SCSIBus::func_; \ - event.SetName(name_); \ - event.code = 0; \ + event.func = ToEventCallback(&SCSIBus::func_); \ event.time = time_; \ - event.Start(); \ + event.SetName(name_); \ + scheduler->RestartEvent(event); \ } while (0) // コンストラクタ SCSIBus::SCSIBus() + : inherited(OBJ_SCSIBUS) { - logname = "scsibus"; - devname = "SCSIBus"; - - event.dev = this; - event.SetName("SCSIBus"); // 複数出来たら名前どうするべか + event.Regist("SCSIBus"); // 複数出来たら名前どうするべか } // デストラクタ @@ -34,10 +33,27 @@ SCSIBus::~SCSIBus() { } -// リセット +// 電源オン/リセット void -SCSIBus::ResetHard() +SCSIBus::ResetHard(bool poweron) { + if (poweron) { + phase = SCSI::Phase::BusFree; + rst = false; + req = false; + ack = false; + atn = false; + sel = 0; + bsy = 0; + xfer = 0; + data = 0; + + last_req_time = 0; + req_wait = 0; + init_id = -1; + target_id = -1; + } + // ここでのイベントは実際にはイニシエータかターゲットのどちらかが // 時間を伴う処理をしている最中であることを示しているものなので、 // イニシエータがリセットされたこととバスの動作とは本来関係ないのだが @@ -45,7 +61,7 @@ SCSIBus::ResetHard() // タイマーイベントが使われており、本体をリセットしたのに入れ違いで // イニシエータの転送処理が呼び出されてしまうというような事故を // 防ぐためにもここでタイマーを停止する。 - event.Stop(); + scheduler->StopEvent(event); } // このバスにデバイスを接続する (初期化時に使う) @@ -173,7 +189,10 @@ SCSIBus::AssertSEL(uint id) // だろうか。賢くないターゲットデバイスは検出せずにそのまま (そして // デッドロック) になるだろうか。 - // XXX とりあえず +#if 1 + // XXX とりあえず LUNA で SCSI がなんか刺さった時に本体リセットでも + // 直らない状況を真似するため、ターゲットは何もしないでおく。 +#else // ターゲットデバイスは賢いので、全員イニシエータ様に忖度して // 即座にバスフリーへ移行するというのはどうか。 for (uint i = 0; i < 8; i++) { @@ -181,6 +200,7 @@ SCSIBus::AssertSEL(uint id) NegateBSY(i); } } +#endif } } @@ -223,7 +243,7 @@ SCSIBus::NegateSEL(uint id) } } else { // 下げる分には無視してもいいはずだけど、どうする? - PANIC("NegateSEL in %s phase\n", GetPhaseName()); + VMPANIC("NegateSEL in %s phase", GetPhaseName()); } } @@ -259,7 +279,7 @@ SCSIBus::AssertBSY(uint id) } else if (GetPhase() == SCSI::Phase::Arbitration) { // アービトレーションフェーズだったら、アービトレーションに参加。 // 今は起きない。 - PANIC("AssertBSY(#%d) in arbitration", id); + VMPANIC("AssertBSY(#%d) in arbitration", id); } else if (GetPhase() == SCSI::Phase::Selection) { // セレクションフェーズだったら、転送フェーズに移行中。 @@ -269,7 +289,7 @@ SCSIBus::AssertBSY(uint id) CallAfter(SelectionAck, "SCSIBus Selection Ack", 90_nsec); } else { // どうする? - PANIC("AssertBSY(#%d) in %s phase\n", id, GetPhaseName()); + VMPANIC("AssertBSY(#%d) in %s phase", id, GetPhaseName()); } } @@ -303,7 +323,7 @@ SCSIBus::NegateBSY(uint id) } else { // どうする? - PANIC("NegateBSY(#%d) in %s phase\n", id, GetPhaseName()); + VMPANIC("NegateBSY(#%d) in %s phase", id, GetPhaseName()); } } @@ -335,7 +355,7 @@ SCSIBus::AssertREQ() // 通知はイベントにしないといけないので。 uint64 after = 0; - uint64 now = gMPU->GetVirtTime(); + uint64 now = scheduler->GetVirtTime(); if (now < last_req_time + 1_usec) { after = (last_req_time + 1_usec) - now; } @@ -344,6 +364,7 @@ SCSIBus::AssertREQ() after += req_wait; req_wait = 0; } + last_req_time = now + after; CallAfter(TransferReq, "SCSIBus AssertREQ", after); } else { // 転送フェーズでないのに上げることはないと思うけど