--- nono/vm/fdd.cpp 2026/04/29 17:05:18 1.1.1.2 +++ nono/vm/fdd.cpp 2026/04/29 17:06:01 1.1.1.7 @@ -13,8 +13,12 @@ // トラックは 8~ 個のセクタで構成される。 // セクタは 128~ バイトで構成される。 +// 割り込み状態はこちらでは保持しておらず PEDEC 側で持っている。 +// PEDEC への割り込みは AssertINT() するだけで使っている。 + #include "fdd.h" #include "config.h" +#include "event.h" #include "fdc.h" #include "mainapp.h" #include "pedec.h" @@ -83,13 +87,13 @@ FDTrack::Clear() // // コンストラクタ -FDDDevice::FDDDevice(int unit_) +FDDDevice::FDDDevice(uint unit_) : inherited(OBJ_FDD(unit_)) { unit = unit_; - event.func = ToEventCallback(&FDDDevice::EventCallback); - event.Regist(GetName()); + // image はコンストラクタがないので、この辺りで設定。 + image.SetName(GetName()); } // デストラクタ @@ -101,51 +105,39 @@ FDDDevice::~FDDDevice() bool FDDDevice::Init() { - if (inherited::Init() == false) { - return false; - } - fdc = GetFDCDevice(); pedec = GetPEDECDevice(); - const std::string keybody = string_format("fd%d-", unit); + const std::string keybody = string_format("fd%u-", unit); const std::string imgkey = keybody + "image"; const std::string wikey = keybody + "writeignore"; - // デバイス種別(v[0])とパス(v[1])に分解。 - // デバイス種別はすでにチェックしてあるのでここでは不要。 const ConfigItem& itemimg = gConfig->Find(imgkey); const std::string& filename = itemimg.AsString(); // UI からの通知を受け取るイベントを用意 scheduler->ConnectMessage(MessageID::FDD_LOAD(unit), this, - ToMessageCallback(&FDDDevice::LoadCallback)); + ToMessageCallback(&FDDDevice::LoadMessage)); scheduler->ConnectMessage(MessageID::FDD_UNLOAD(unit), this, - ToMessageCallback(&FDDDevice::UnloadCallback)); + ToMessageCallback(&FDDDevice::UnloadMessage)); + + auto evman = GetEventManager(); + event = evman->Regist(this, + ToEventCallback(&FDDDevice::EventCallback), + GetName()); // オープン前に writeignore をチェック。 // この後パス名を処理するとすぐに UI に通知を出すため、それより前で // 行わないといけない。うーん。 - const ConfigItem& wi = gConfig->Find(wikey); - write_ignore = wi.AsInt(); + write_ignore = gConfig->Find(wikey).AsBool(); // 設定時点でファイルが指定されていればオープン if (filename.empty() == false) { - std::string path; - if (filename[0] == '/') { - path = filename; - } else { - // 相対パスなら VM ディレクトリから - path = gMainApp.GetVMDir() + filename; - } - + std::string path = gMainApp.NormalizePath(filename); if (LoadDisk(path) == false) { + itemimg.Err("Could not open %s", path.c_str()); return false; } - } else { - // メディアがロードされないままでも起動時は必ず通知を投げる。 - // ステータスパネルはこの UIMessage でのみ状態を更新するため。 - MediaChanged(); } return true; @@ -167,7 +159,7 @@ FDDDevice::ResetHard(bool poweron) // y = 11 以降が各ドライブの状態で、このうち x = 26 以降が FDD の担当。 // y = 16 以降は FDD のアクセスマップ。 void -FDDDevice::MonitorUpdateFDD(TextScreen& screen, int hd) +FDDDevice::MonitorScreenFDD(TextScreen& screen, uint hd) { /* 1 2 3 4 5 6 7 0123456789012345678901234567890123456789012345678901234567890123456789012345678 @@ -213,14 +205,14 @@ XX>01234567890123456 01234567890123456| if (medium_loaded) { // フォーマットと CHRN - screen.Print(ux + 20, uy, "%4s %2d %d %2d %d(%d)", + screen.Print(ux + 20, uy, "%4s %2u %u %2u %u(%u)", format_name.c_str(), ncyl, nhead, nsect, format_n, sectsize); } uy = 16 + (unit / 2) * 10; ux = (unit % 2) * 41; - screen.Print(ux, uy++, "Unit %d", unit); + screen.Print(ux, uy++, "Unit %u", unit); // 横ガイド for (int i = 0; i < 8; i++) { screen.Puts(ux + 2, uy + i, "|"); @@ -233,7 +225,7 @@ XX>01234567890123456 01234567890123456| } TA selattr = selected ? TA::Em : TA::Normal; - screen.Print(ux, uy - 1, selattr, "Unit %d: HD=%d cyl=%2d/%d pos=%5d/%d", + screen.Print(ux, uy - 1, selattr, "Unit %u: HD=%u cyl=%2u/%u pos=%5u/%u", unit, hd, cylinder, ncyl, pos, MFM_TRACK_RAW_SIZE); // ヘッドの現在位置。 @@ -253,10 +245,8 @@ XX>01234567890123456 01234567890123456| } // ヘッド位置 - screen.Print(ux, uy + heady, selattr, "%2d>", cylinder); + screen.Print(ux, uy + heady, selattr, "%2u>", cylinder); screen.Puts(ux + hd * 18 + 3 + headx, uy + heady, selattr, "#"); - // 裏のヘッド位置 - screen.Puts(ux + (1 - hd) * 18 + 3 + headx, uy + heady, selattr, "+"); } // READY 信号 @@ -309,7 +299,7 @@ FDDDevice::SetMotorOn(bool motor_on_) } void -FDDDevice::EventCallback(Event& ev) +FDDDevice::EventCallback(Event *ev) { // モータが回転している間は1バイトずつ進める pos++; @@ -324,31 +314,31 @@ FDDDevice::EventCallback(Event& ev) case SPIN_UP: // 増速中 - if (event.time == 16_usec) { + if (event->time == 16_usec) { motor_state = READY; // READY になったので FDC に通知 fdc->ReadyChanged(unit, true); } else { - if (event.time < 16_usec) { + if (event->time < 16_usec) { // オーバーシュート対応 - event.time = 16_usec; + event->time = 16_usec; } else { - event.time /= 2; + event->time /= 2; } - putlog(4, "SPIN_UP next=%uusec", (uint)(event.time / 1_usec)); + putlog(4, "SPIN_UP next=%uusec", (uint)tsec_to_usec(event->time)); } scheduler->StartEvent(ev); break; case SPIN_DOWN: - if (event.time >= 262144_usec) { + if (event->time >= 262144_usec) { motor_state = STOPPED; // イベント停止、ここでは time も 0 クリアしておく。 - event.time = 0; + event->time = 0; } else { - event.time *= 2; + event->time *= 2; scheduler->StartEvent(ev); - putlog(4, "SPIN_DOWN next=%uusec", (uint)(event.time / 1_usec)); + putlog(4, "SPIN_DOWN next=%uusec", (uint)tsec_to_usec(event->time)); } break; @@ -401,13 +391,13 @@ FDDDevice::DoMotorOn() // 仕様では 500msec で READY になるとあるが、ここでは 2 のべき乗を // 使っているので、約 524msec かかる。細かいことは気にしない。 motor_state = SPIN_UP; - event.time = 262144_usec; - putlog(4, "SPIN_UP next=%uusec", (uint)(event.time / 1_usec)); + event->time = 262144_usec; + putlog(4, "SPIN_UP next=%uusec", (uint)tsec_to_usec(event->time)); } else if (motor_state == SPIN_DOWN) { // 細かいことは無視して、増速に転じる motor_state = SPIN_UP; } else { - VMPANIC("DoMotorOn called on motor_state=%d", (int)motor_state); + VMPANIC("DoMotorOn called on motor_state=%u", (uint)motor_state); } scheduler->RestartEvent(event); @@ -434,7 +424,7 @@ FDDDevice::DoMotorOff() // 細かいことは無視して、減速に転じる。 motor_state = SPIN_DOWN; } else { - VMPANIC("DoMotorOff called on motor_state=%d", (int)motor_state); + VMPANIC("DoMotorOff called on motor_state=%u", (uint)motor_state); } scheduler->RestartEvent(event); @@ -653,7 +643,7 @@ FDDDevice::LoadDisk(const std::string& p { bool ejected; off_t size; - bool w_ok; + int w_ok; bool read_only; // すでにあればクローズ (ここでは通知は行わない) @@ -665,10 +655,29 @@ FDDDevice::LoadDisk(const std::string& p goto done; } - if (image.GetInfo(&size, &w_ok) == false) { + w_ok = image.IsWriteable(); + if (w_ok < 0) { + goto done; + } + + // 書き込みモードをここで確定 + if (w_ok) { + if (write_ignore) { + write_mode = RW::WriteIgnore; + } else { + write_mode = RW::Writeable; + } + } else { + write_mode = RW::WriteProtect; + } + + // ここでオープン + read_only = (GetWriteMode() != RW::Writeable); + if (image.Open(read_only, write_ignore) == false) { goto done; } + size = image.GetSize(); if (size == 1261568) { // Human68k 2HD フォーマットとみなす // 77track, 2side, 8sector, 1024bytes/sector @@ -698,23 +707,6 @@ FDDDevice::LoadDisk(const std::string& p gap4b = (MFM_TRACK_RAW_SIZE - MFM_TRACK_HEADER) - (sectsize + MFM_SECTOR_HEADER + gap3) * nsect; - // 書き込みモードをここで確定 - if (w_ok) { - if (write_ignore) { - write_mode = RW::WriteIgnore; - } else { - write_mode = RW::Writeable; - } - } else { - write_mode = RW::WriteProtect; - } - - // ここでオープン - read_only = (GetWriteMode() != RW::Writeable); - if (image.Open(read_only, write_ignore) == false) { - goto done; - } - // 書き込み無視なら一応ログ出力 if (GetWriteMode() == RW::WriteIgnore) { putmsg(0, "write is ignored"); @@ -796,7 +788,7 @@ FDDDevice::Clear() void FDDDevice::MediaChanged() const { - UIMessage::Post(UIMessage::FDD_MEDIA_CHANGE, unit); + gMainApp.GetUIMessage()->Post(UIMessage::FDD_MEDIA_CHANGE, unit); } // メディアを挿入する。 @@ -818,17 +810,17 @@ FDDDevice::UnloadDiskUI(bool force) // メディア挿入メッセージコールバック void -FDDDevice::LoadCallback(MessageID msgid, uint32 arg) +FDDDevice::LoadMessage(MessageID msgid, uint32 arg) { if (LoadDisk(new_pathname) == false) { // 失敗したら UI に通知 - UIMessage::Post(UIMessage::FDD_MEDIA_FAILED); + gMainApp.GetUIMessage()->Post(UIMessage::FDD_MEDIA_FAILED); } } // メディア排出メッセージコールバック void -FDDDevice::UnloadCallback(MessageID msgid, uint32 arg) +FDDDevice::UnloadMessage(MessageID msgid, uint32 arg) { bool force = arg; UnloadDisk(force);