--- nono/vm/spc.cpp 2026/04/29 17:05:41 1.1.1.19 +++ nono/vm/spc.cpp 2026/04/29 17:05:59 1.1.1.21 @@ -10,6 +10,7 @@ #include "spc.h" #include "config.h" +#include "event.h" #include "mainapp.h" #include "monitor.h" #include "pedec.h" @@ -20,21 +21,21 @@ // time 時間後に呼び出すコールバックをセットする。 // func の書式が面倒なのを省略して書きたいため。 #define CallAfter(func_, name_, time_) do { \ - phase_event.func = ToEventCallback(&SPCDevice::func_); \ - phase_event.time = time_; \ - phase_event.SetName(name_); \ + phase_event->SetCallback(&SPCDevice::func_); \ + phase_event->time = time_; \ + phase_event->SetName(name_); \ scheduler->RestartEvent(phase_event); \ } while (0) // コンストラクタ SPCDevice::SPCDevice() - : inherited(OBJ_SPC) + : inherited(OBJ_SPC0) { // 初期値は不定だが表示上困るのでとりあえず。 myid = 7; monitor = gMonitorManager->Regist(ID_MONITOR_SPC, this); - monitor->func = ToMonitorCallback(&SPCDevice::MonitorUpdate); + monitor->SetCallback(&SPCDevice::MonitorScreen); // サイズは Init で決まる } @@ -59,7 +60,7 @@ SPCDevice::Create() { // ドメイン。 try { - domain.reset(new SCSIDomain(this, "spc0")); + domain.reset(new SCSIDomain(this, "SPC0", "spc0")); } catch (...) { } if ((bool)domain == false) { warnx("Failed to initialize SCSIDomain at %s", __method__); @@ -98,8 +99,11 @@ SPCDevice::Init() // 入力クロックは機種によって異なる。 // X68k は 5MHz が入っている。 // LUNA-I はおそらく 6.144MHz だと思われる。LUNA-88K は未確認。 - const ConfigItem& item = gConfig->Find("!spc-tCLF"); - t_CLF = item.AsInt(); + if (vmtype == VMType::X68030) { + t_CLF = 200_nsec; + } else { + t_CLF = 163_nsec; + } // アクセスウェイト if (vmtype == VMType::X68030) { @@ -121,15 +125,9 @@ SPCDevice::Init() interrupt = GetInterruptDevice(); } - // 汎用イベント - // 名前とコールバック関数は都度セットする。 - phase_event.SetName("SPC Phase"); - scheduler->RegistEvent(phase_event); - - // TC カウンタイベント - timer_event.code = 0; - timer_event.SetName("SPC Timer"); - scheduler->RegistEvent(timer_event); + auto evman = GetEventManager(); + phase_event = evman->Regist(this, NULL, "SPC Phase"); + timer_event = evman->Regist(this, NULL, "SPC Timer"); // モニタに表示するアドレス if (vmtype == VMType::X68030) { @@ -189,7 +187,7 @@ SPCDevice::ReadPort(uint32 offset) switch (offset) { case SPC::BDID: - data = 1 << myid; + data = 1U << myid; putlog(3, "BDID -> $%02x", data.Data()); break; @@ -213,7 +211,7 @@ SPCDevice::ReadPort(uint32 offset) data = GetINTS(); if (loglevel >= 3) { uint32 new_ints = data.Data(); - if (timer_event.IsRunning()) { + if (timer_event->IsRunning()) { // イベント中は値が変わった時だけ表示 if (prev_ints != new_ints) { putlogn("INTS -> $%02x", new_ints); @@ -235,7 +233,7 @@ SPCDevice::ReadPort(uint32 offset) data = GetSSTS(); if (loglevel >= 3) { uint32 new_ssts = data.Data(); - if (timer_event.IsRunning()) { + if (timer_event->IsRunning()) { // イベント中は値が変わった時だけ表示 if (prev_ssts != new_ssts) { putlogn("SSTS -> $%02x", new_ssts); @@ -423,7 +421,7 @@ SPCDevice::PeekPort(uint32 offset) { switch (offset) { case SPC::BDID: - return 1 << myid; + return 1U << myid; case SPC::SCTL: return spc.sctl; @@ -493,7 +491,7 @@ SPCDevice::PokePort(uint32 offset, uint3 } void -SPCDevice::MonitorUpdate(Monitor *, TextScreen& screen) +SPCDevice::MonitorScreen(Monitor *, TextScreen& screen) { int x; int y; @@ -522,7 +520,7 @@ SPCDevice::MonitorUpdate(Monitor *, Text #define A(n) (baseaddr + (n) * regoffset) y = 0; - screen.Print(0, y++, "$%08x BDID: $%02x (ID=%u)", A(0), (1 << myid), myid); + screen.Print(0, y++, "$%08x BDID: $%02x (ID=%u)", A(0), (1U << myid), myid); screen.Print(0, y++, "$%08x SCTL: $%02x", A(1), sctl); screen.Print(0, y++, "$%08x SCMD: $%02x", A(2), scmd); screen.Print(0, y++, "$%08x INTS: $%02x", A(4), ints); @@ -656,14 +654,15 @@ SPCDevice::MonitorUpdate(Monitor *, Text y = 2; screen.Puts(x + 4, y++, "(________)"); screen.Puts(x + 4, y++, "(________)"); - screen.Puts(x + 4, y++, "+"); - screen.Puts(x + 4, y++, "|"); - screen.Puts(x + 4, y++, "+"); + // Shift-JIS は手動で置く必要がある。 + screen.Puts(x + 4, y++, "\x84\xa2"); // "┐" + screen.Puts(x + 4, y++, "\x84\xa0"); // "│" + screen.Puts(x + 4, y++, "\x84\xa3"); // "┘" // BSY, SEL の内訳。"(76543210)" の順。 y = 2; for (int i = 0; i < 8; i++) { - if ((bsy & (1 << i))) { + if ((bsy & (1U << i))) { screen.Print(x + 4 + 8 - i, y, "%u", i); } else { screen.Print(x + 4 + 8 - i, y, "_"); @@ -671,7 +670,7 @@ SPCDevice::MonitorUpdate(Monitor *, Text } y++; for (int i = 0; i < 8; i++) { - if ((sel & (1 << i))) { + if ((sel & (1U << i))) { screen.Print(x + 4 + 8 - i, y, "%u", i); } else { screen.Print(x + 4 + 8 - i, y, "_"); @@ -680,9 +679,9 @@ SPCDevice::MonitorUpdate(Monitor *, Text // 転送フェーズ中なら現在の XferPhase y += 2; - if (ph == SCSI::Phase::Transfer) { - screen.Puts(x + 5, y, SCSI::GetXferPhaseName(GetXfer())); - } + TA attrxfer = (ph == SCSI::Phase::Transfer) ? TA::Normal : TA::Disable; + screen.Puts(x + 6, y++, attrxfer, "XferPhase:"); + screen.Puts(x + 6, y, attrxfer, SCSI::GetXferPhaseName(GetXfer())); // デバイス一覧 // 0 1 @@ -738,7 +737,7 @@ SPCDevice::MonitorUpdate(Monitor *, Text } } -// レジスタをビットごとに表示する。MonitorUpdate の下請け。 +// レジスタをビットごとに表示する。MonitorScreen の下請け。 void SPCDevice::MonitorReg(TextScreen& screen, int x, int y, uint32 reg, const char * const *names) @@ -747,7 +746,7 @@ SPCDevice::MonitorReg(TextScreen& screen if (names[i][0] == '-') { screen.Puts(x + i * 5, y, TA::Disable, "----"); } else { - bool b = reg & (1 << (7 - i)); + bool b = reg & (1U << (7 - i)); screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]); } } @@ -895,9 +894,8 @@ SPCDevice::WriteINTS(uint32 data) if (spc.tc == 0) { BusFree(); } else { - timer_event.func = - ToEventCallback(&SPCDevice::SelectionTimeout); - timer_event.time = spc.tc * t_CLF * 2; + timer_event->SetCallback(&SPCDevice::SelectionTimeout); + timer_event->time = spc.tc * t_CLF * 2; scheduler->RestartEvent(timer_event); } } @@ -1198,12 +1196,12 @@ SPCDevice::SelectCommand() if (data == 0) { // ID が一切立ってない? idstr = "TEMP==0; No IDs?"; - } else if ((data & (1 << myid)) == 0) { + } else if ((data & (1U << myid)) == 0) { // 自 ID が立ってない? idstr = string_format("TEMP=$%02x; No BDID?", data); } else { // ここで少なくとも自 ID は立っている - data &= ~(1 << myid); + data &= ~(1U << myid); if (data == 0) { // ターゲット ID がない @@ -1269,8 +1267,8 @@ SPCDevice::SelectCommand() // N が 0 なら無限大なのでタイマーは動かさない。 uint32 N = (spc.tc >> 8) << 8; if (N != 0) { - timer_event.func = ToEventCallback(&SPCDevice::SelectionTimeout); - timer_event.time = (N + 15) * t_CLF * 2; + timer_event->SetCallback(&SPCDevice::SelectionTimeout); + timer_event->time = (N + 15) * t_CLF * 2; scheduler->RestartEvent(timer_event); } @@ -1282,21 +1280,21 @@ SPCDevice::SelectCommand() // 必ずバスの使用権を得る。 // バスフリーから規定時間後に SEL (と DB* と ATN) を上げる。 - uint64 t_ARB = 32 * t_CLF - 60; - uint64 t_AWSL = 40; // 適当に中間 + uint64 t_ARB = 32 * t_CLF - 60_nsec; + uint64 t_AWSL = 40_nsec; // 適当に中間 CallAfter(Arbitration1, "SPC Arbitration", wait + t_ARB + t_AWSL); } else { // アービトレーションなしの場合 // バスフリーから規定時間後に SEL (と DB*) を上げる。 - uint64 t_IDSL = 11 * t_CLF - 80; + uint64 t_IDSL = 11 * t_CLF - 80_nsec; CallAfter(Selection1, "SPC Selection", wait + t_IDSL); } } // アービトレーションフェーズ開始後、規定時間経過したので SEL を立てるところ。 void -SPCDevice::Arbitration1(Event& ev) +SPCDevice::Arbitration1(Event *ev) { putlog(3, "Arbitration1"); @@ -1316,15 +1314,15 @@ SPCDevice::Arbitration1(Event& ev) } AssertSEL(); - uint64 t_SIDA = 11 * t_CLF - 30; - uint64 t_IDBH = 2 * t_CLF - 80; + uint64 t_SIDA = 11 * t_CLF - 30_nsec; + uint64 t_IDBH = 2 * t_CLF - 80_nsec; CallAfter(Arbitration2, "SPC Arbitration2", t_SIDA + t_IDBH); } // アービトレーションフェーズ中、SEL を立ててから規定時間経過したので BSY を // 下げるところ。 void -SPCDevice::Arbitration2(Event& ev) +SPCDevice::Arbitration2(Event *ev) { putlog(3, "Arbitration2"); @@ -1334,7 +1332,7 @@ SPCDevice::Arbitration2(Event& ev) // アービトレーションフェーズを使わない場合のセレクションフェーズで、 // 規定時間経過したので SEL を立てるところ。 void -SPCDevice::Selection1(Event& ev) +SPCDevice::Selection1(Event *ev) { putlog(3, "Selection1"); @@ -1351,12 +1349,12 @@ SPCDevice::Selection1(Event& ev) // セレクションコマンドがタイムアウトした時に呼ばれるコールバック。 void -SPCDevice::SelectionTimeout(Event& ev) +SPCDevice::SelectionTimeout(Event *ev) { if (loglevel >= 3) { int tgtid; uint8 data = GetData(); - data &= ~(1 << myid); + data &= ~(1U << myid); tgtid = SCSIBus::DecodeID(data); if (tgtid == -1) { putlogn("Selection timeout"); @@ -1500,7 +1498,7 @@ SPCDevice::TransferReqCallback() // (1バイト送信するとターゲットが再び REQ を上げるなどしてくるので、 // OnTransferReq() か DREG 書き込みから再びここが呼ばれる) void -SPCDevice::HardwareTransfer(Event& ev) +SPCDevice::HardwareTransfer(Event *ev) { // SDGC_XFER_ENABLE は転送要求ごとに割り込みを上げる。 // (SPC から見て) 入力操作時は読み込めるデータがある場合、出力操作時は