--- nono/vm/fdc.cpp 2026/04/29 17:04:35 1.1.1.4 +++ nono/vm/fdc.cpp 2026/04/29 17:05:11 1.1.1.9 @@ -4,39 +4,56 @@ // Licensed under nono-license.txt // +// +// FDC (uPD72065B) +// + #include "fdc.h" -#include "ioctlr.h" +#include "mpu.h" +#include "pedec.h" #include "scheduler.h" +// グローバル参照用 +FDCDevice *gFDC; + // コンストラクタ FDCDevice::FDCDevice() + : inherited("FDC") { - logname = "fdc"; - devname = "FDC"; devaddr = baseaddr; devlen = 0x2000; - event.dev = this; - 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 他には + gScheduler->StopEvent(event); idle_phase(); } uint64 -FDCDevice::Read(uint32 addr) +FDCDevice::Read(uint32 offset) { - switch (addr) { + gMPU->AddCycle(19); // InsideOut p.135 + + switch (offset) { case 0: return ReadStatus(); case 1: @@ -50,10 +67,13 @@ FDCDevice::Read(uint32 addr) } uint64 -FDCDevice::Write(uint32 addr, uint32 data) +FDCDevice::Write(uint32 offset, uint32 data) { - switch (addr) { + gMPU->AddCycle(19); // InsideOut p.135 + + switch (offset) { case 0: + putlog(0, "未実装コマンドレジスタ書き込み $%02x", data); return 0; case 1: @@ -70,7 +90,8 @@ FDCDevice::Write(uint32 addr, uint32 dat (fdc.drivesel & 8) ? " #3" : ""); } if ((data & 0xe0) != 0) { - putlog(0, "未実装ビット書き込み $%06x <- $%02x", addr, data); + putlog(0, "未実装ビット書き込み $%06x <- $%02x", + gMPU->GetPaddr(), data); } return 0; @@ -92,7 +113,7 @@ FDCDevice::Write(uint32 addr, uint32 dat } uint64 -FDCDevice::Peek(uint32 addr) +FDCDevice::Peek(uint32 offset) { // XXX 未実装 return 0xff; @@ -244,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; @@ -253,11 +278,25 @@ FDCDevice::exec_phase() case FDC::CMD_SENSE_INTERRUPT_STATUS: { putlog(1, "Exec フェーズ: SENSE INTERRUPT STATUS"); + // XXX とりあえずここで割り込みを下げる。 + // 実際には割り込み状態をラッチして信号線に出すというコマンドで + // 割り込み要因がオフになっていればそれによってネゲートされる + // ということのようだ。 + 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 @@ -274,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: @@ -305,12 +344,12 @@ FDCDevice::result_phase() // イベントコールバック void -FDCDevice::Callback(int arg) +FDCDevice::Callback(Event& ev) { - switch (arg) { + switch (ev.code) { case FDC::CMD_RECALIBRATE: fdd[fdc.accdrive].seek = false; - fdc.DIO = DIOtoHost; + fdc.DIO = DIOtoFDC; Interrupt(); break; } @@ -320,7 +359,15 @@ FDCDevice::Callback(int arg) void FDCDevice::Interrupt() { - gIOCtlr->IntFDC(); + gPEDEC->AssertINT(this); + interrupt = true; +} + +// 強制レディ信号の設定 +void +FDCDevice::SetForceReady(bool force_ready_) +{ + force_ready = force_ready_; } // コマンド名