--- nono/vm/fdc.cpp 2026/04/29 17:04:32 1.1.1.3 +++ nono/vm/fdc.cpp 2026/04/29 17:05:11 1.1.1.9 @@ -1,69 +1,86 @@ // // nono -// Copyright (C) 2017 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// FDC (uPD72065B) // #include "fdc.h" -#include "iocon.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::Read8(uint32 addr) +FDCDevice::Read(uint32 offset) { - uint32 offset = addr - baseaddr; + gMPU->AddCycle(19); // InsideOut p.135 + switch (offset) { - case 1: + case 0: return ReadStatus(); - case 3: + case 1: return ReadData(); - case 5: + case 2: return ReadDriveStatus(); - default: - break; + case 3: + return 0xff; } - PANIC("not impl"); + __unreachable(); } uint64 -FDCDevice::Read16(uint32 addr) +FDCDevice::Write(uint32 offset, uint32 data) { - return 0xff00 | Read8(addr + 1); -} + gMPU->AddCycle(19); // InsideOut p.135 -uint64 -FDCDevice::Write8(uint32 addr, uint32 data) -{ - uint32 offset = addr - baseaddr; switch (offset) { - case 3: + case 0: + putlog(0, "未実装コマンドレジスタ書き込み $%02x", data); + return 0; + + case 1: WriteCmd(data); return 0; - case 5: + + case 2: if ((data & 0x0f) != 0) { fdc.drivesel = data & 0x0f; putlog(1, "ドライブ選択%s%s%s%s", @@ -73,11 +90,12 @@ FDCDevice::Write8(uint32 addr, uint32 da (fdc.drivesel & 8) ? " #3" : ""); } if ((data & 0xe0) != 0) { - putlog(0, "未実装ビット書き込み $%06x <- $%02x", addr, data); + putlog(0, "未実装ビット書き込み $%06x <- $%02x", + gMPU->GetPaddr(), data); } return 0; - case 7: + case 3: fdc.is2DD = ((data & 0x10) != 0); fdc.accdrive = data & 3; putlog(1, "アクセスドライブ %s #%d", @@ -90,23 +108,14 @@ FDCDevice::Write8(uint32 addr, uint32 da putlog(1, "ドライブ #%d モーターオフ", fdc.accdrive); } return 0; - - default: - break; } - PANIC("FDC 未実装書き込み $%06x <- $%02x", addr, data); - return 0; -} - -uint64 -FDCDevice::Write16(uint32 addr, uint32 data) -{ - return Write8(addr + 1, data); + __unreachable(); } uint64 -FDCDevice::Peek8(uint32 addr) +FDCDevice::Peek(uint32 offset) { + // XXX 未実装 return 0xff; } @@ -256,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; @@ -265,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 @@ -286,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: @@ -317,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; } @@ -332,7 +359,15 @@ FDCDevice::Callback(int arg) void FDCDevice::Interrupt() { - gIOCon->IntFDC(); + gPEDEC->AssertINT(this); + interrupt = true; +} + +// 強制レディ信号の設定 +void +FDCDevice::SetForceReady(bool force_ready_) +{ + force_ready = force_ready_; } // コマンド名