--- nono/vm/fdc.cpp 2026/04/29 17:04:55 1.1.1.8 +++ nono/vm/fdc.cpp 2026/04/29 17:05:11 1.1.1.9 @@ -4,11 +4,17 @@ // Licensed under nono-license.txt // +// +// FDC (uPD72065B) +// + #include "fdc.h" +#include "mpu.h" #include "pedec.h" #include "scheduler.h" -std::unique_ptr gFDC; +// グローバル参照用 +FDCDevice *gFDC; // コンストラクタ FDCDevice::FDCDevice() @@ -17,20 +23,28 @@ FDCDevice::FDCDevice() devaddr = baseaddr; devlen = 0x2000; - event.func = (DeviceCallback_t)&FDCDevice::Callback; - event.SetName("FDC"); + event.func = ToEventCallback(&FDCDevice::Callback); + event.Regist("FDC"); + + // XXX ハック。ちゃんと作ること + fdd[0].ready = true; + fdd[1].ready = true; + fdd[2].ready = false; + fdd[3].ready = false; } // デストラクタ FDCDevice::~FDCDevice() { + gFDC = NULL; } +// リセット void -FDCDevice::ResetHard() +FDCDevice::ResetHard(bool poweron) { // XXX 他には - event.Stop(); + gScheduler->StopEvent(event); idle_phase(); } @@ -59,6 +73,7 @@ FDCDevice::Write(uint32 offset, uint32 d switch (offset) { case 0: + putlog(0, "未実装コマンドレジスタ書き込み $%02x", data); return 0; case 1: @@ -250,8 +265,12 @@ FDCDevice::exec_phase() case FDC::CMD_SENSE_DEVICE_STATUS: putlog(1, "Exec フェーズ: SENSE DEVICE STATUS"); - fdc.resbuf[0] = fdc.cmdbuf[1] & 0x07; - fdc.resbuf[0] |= 0x00; + uint8 st3; + st3 = fdc.cmdbuf[1] & 0x07; + if ((force_ready || fdd[fdc.accdrive].ready) == true) { + st3 |= FDC::ST3_RY; + } + fdc.resbuf[0] = st3; fdc.reslen = 1; result_phase(); break; @@ -263,12 +282,21 @@ FDCDevice::exec_phase() // 実際には割り込み状態をラッチして信号線に出すというコマンドで // 割り込み要因がオフになっていればそれによってネゲートされる // ということのようだ。 + if (interrupt == false) { + // XXX 割り込みが起きていないときは INVALID と同じらしい + fdc.resbuf[0] = 0x80; + fdc.reslen = 1; + result_phase(); + break; + } gPEDEC->NegateINT(this); + interrupt = false; // XXX まだフロッピー挿入はない uint8 st0 = 0; st0 |= FDC::ST0_IC_NT; - st0 |= FDC::ST0_EC; - st0 |= FDC::ST0_NR; + if ((force_ready || fdd[fdc.accdrive].ready) == false) { + st0 |= FDC::ST0_NR; + } st0 |= fdc.accdrive; fdc.resbuf[0] = st0; fdc.resbuf[1] = 0; // XXX PCN @@ -285,8 +313,8 @@ FDCDevice::exec_phase() idle_phase(); // XXX ヘッドの位置という概念がまだない event.time = 0; - event.code = FDC::CMD_RECALIBRATE; // XXX コマンドをメンバ変数にするとか - event.Start(); + event.code = FDC::CMD_RECALIBRATE; // XXX コマンドをメンバ変数にするとか + gScheduler->RestartEvent(event); break; case FDC::CMD_SEEK: @@ -321,7 +349,7 @@ FDCDevice::Callback(Event& ev) switch (ev.code) { case FDC::CMD_RECALIBRATE: fdd[fdc.accdrive].seek = false; - fdc.DIO = DIOtoHost; + fdc.DIO = DIOtoFDC; Interrupt(); break; } @@ -332,6 +360,14 @@ void FDCDevice::Interrupt() { gPEDEC->AssertINT(this); + interrupt = true; +} + +// 強制レディ信号の設定 +void +FDCDevice::SetForceReady(bool force_ready_) +{ + force_ready = force_ready_; } // コマンド名