--- nono/vm/dmac.h 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/dmac.h 2026/04/29 17:05:18 1.1.1.12 @@ -1,76 +1,345 @@ // // nono -// Copyright (C) 2017 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// DMAC (HD63450) // #pragma once #include "device.h" +#include "fixedqueue.h" +#include "monitor.h" +#include "event.h" +#include + +class ADPCMDevice; +class FDCDevice; +class InterruptDevice; +class MainbusDevice; struct DMAC { - static const int CSR = 0x00; // .B - static const int CER = 0x01; // .B - static const int DCR = 0x04; // .B - static const int OCR = 0x05; // .B - static const int SCR = 0x06; // .B - static const int CCR = 0x07; // .B - static const int MTC = 0x0a; // .W - static const int MAR = 0x0c; // .L - static const int DAR = 0x14; // .L - static const int BTC = 0x1a; // .W - static const int BAR = 0x1c; // .L - static const int NIV = 0x25; // .B - static const int EIV = 0x27; // .B - static const int MFC = 0x29; // .B - static const int CPR = 0x2d; // .B - static const int DFC = 0x31; // .B - static const int BFC = 0x39; // .B - static const int GCR = 0x3f; // .B (ch#3のみ) - - // 各チャンネル - struct channel { - uint8 csr; - uint8 cer; - uint8 dcr; - uint8 ocr; - uint8 scr; - uint8 ccr; - uint16 mtc; - uint32 mar; - uint32 dar; - uint16 btc; - uint32 bar; - uint8 niv; - uint8 eiv; - uint8 mfc; - uint8 cpr; - uint8 dfc; - uint8 bfc; - } chan[4]; + static const uint32 CSR = 0x00; // .B + static const uint32 CER = 0x01; // .B + static const uint32 DCR = 0x04; // .B + static const uint32 OCR = 0x05; // .B + static const uint32 SCR = 0x06; // .B + static const uint32 CCR = 0x07; // .B + static const uint32 MTC = 0x0a; // .W + static const uint32 MAR = 0x0c; // .L + static const uint32 DAR = 0x14; // .L + static const uint32 BTC = 0x1a; // .W + static const uint32 BAR = 0x1c; // .L + static const uint32 NIV = 0x25; // .B + static const uint32 EIV = 0x27; // .B + static const uint32 MFC = 0x29; // .B + static const uint32 CPR = 0x2d; // .B + static const uint32 DFC = 0x31; // .B + static const uint32 BFC = 0x39; // .B + static const uint32 GCR = 0x3f; // .B (ch#3のみ) + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // CSR | COC | BTC | NDT | ERR | ACT | DIT | PCT | PCS | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 CSR_COC = 0x80; // Channel Operation Complete + static const uint32 CSR_BTC = 0x40; // Block Transfer Complete + static const uint32 CSR_NDT = 0x20; // Normal Device Termination + static const uint32 CSR_ERR = 0x10; // Error Bit + static const uint32 CSR_ACT = 0x08; // Channel Active + static const uint32 CSR_DIT = 0x04; // DONE Input Transition + static const uint32 CSR_PCT = 0x02; // PCL Transition + static const uint32 CSR_PCS = 0x01; // PCL Input Line State + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // CER | 0 | Error Code | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 CER_NO_ERROR = 0x00; // No Error + static const uint32 CER_CONFIG = 0x01; // Configuration Error + static const uint32 CER_TIMING = 0x02; // Operation Timing Error + static const uint32 CER_ADDR_MAR = 0x05; // Address error in MAR + static const uint32 CER_ADDR_DAR = 0x06; // Address error in DAR + static const uint32 CER_ADDR_BAR = 0x07; // Address error in BAR + static const uint32 CER_BUS_MAR = 0x09; // Bus error in MAR + static const uint32 CER_BUS_DAR = 0x0a; // Bus error in DAR + static const uint32 CER_BUS_BAR = 0x0b; // Bus error in BAR + static const uint32 CER_COUNT_MTC = 0x0d; // Count error in MTC + static const uint32 CER_COUNT_BTC = 0x0f; // Count error in BTC + static const uint32 CER_EXT_ABORT = 0x10; // External Abort + static const uint32 CER_SOFT_ABORT = 0x11; // Software Abort + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // DCR | XRM | DTYP | DPS | 0 | PCL | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 XRM_BURST = 0; // Burst Transfer + static const uint32 XRM_CYCLE_WO_HOLD = 2; // Cycle Steal without Hold + static const uint32 XRM_CYCLE_WITH_HOLD = 3;// Cycle Steal with Hold + static const uint32 DTYP_68000 = 0; // 68000 devices + static const uint32 DTYP_6800 = 1; // 6800 devices + static const uint32 DTYP_ACK = 2; // Devices with ACK + static const uint32 DTYP_ACK_REDY = 3; // Devices with ACK+READY + static const uint32 DPS_8BIT = 0; // 8bit port + static const uint32 DPS_16BIT = 1; // 16bit port + static const uint32 PCL_STATUS = 0; // Status Input + static const uint32 PCL_STATUS_INTR = 1; // Status Input with Interrupt + static const uint32 PCL_PULSE = 2; // Start Pulse + static const uint32 PCL_ABORT = 3; // Abort Input + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // OCR | DIR | 0 | SIZE | CHAIN | REQG | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 DIR_MtoD = 0; // Memory to Device + static const uint32 DIR_DtoM = 1; // Device to Memory + static const uint32 SIZE_8BIT_PACK = 0; // 8bit (Packed) + static const uint32 SIZE_16BIT = 1; // 16bit + static const uint32 SIZE_32BIT = 2; // 32bit + static const uint32 SIZE_8BIT_UNPK = 3; // 8bit UnPacked + static const uint32 CHAIN_NOCHAIN = 0; // Chain operation is disabled + static const uint32 CHAIN_ARRAY = 2; // Array Chaining + static const uint32 CHAIN_LINK = 3; // Linked Array Chaining + static const uint32 REQG_AUTO_LIM = 0; // Auto Request (Limited) + static const uint32 REQG_AUTO_MAX = 1; // AUto Request (Max) + static const uint32 REQG_EXTERNAL = 2; // External Request + static const uint32 REQG_AUTOFIRST = 3; // Auto first then ext. + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // SCR | 0 | MAC | DAC | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 SCR_NO_COUNT = 0; // Does not count + static const uint32 SCR_COUNT_UP = 1; // Count up + static const uint32 SCR_COUNT_DOWN = 2; // Count down + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // CCR | STR | CNT | HLT | SAB | INT | 0 | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // + static const uint32 CCR_STR = 0x80; // Start Operation + static const uint32 CCR_CNT = 0x40; // Continue Operation + static const uint32 CCR_HLT = 0x20; // Halt Operation + static const uint32 CCR_SAB = 0x10; // Software Abort + static const uint32 CCR_INT = 0x08; // Interrupt Enable + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // CPR | 0 | CP | + // +-----+-----+-----+-----+-----+-----+-----+-----+ + + // b7 b6 b5 b4 b3 b2 b1 b0 + // +-----+-----+-----+-----+-----+-----+-----+-----+ + // GCR | 0 | BT | BR | + // +-----+-----+-----+-----+-----+-----+-----+-----+ +}; - // 全体 - uint8 gcr; +// 各チャンネル +class DMACChan +{ + public: + // 二次変数など + int ch; // チャンネル番号 + const char *desc; // チャンネルの用途(モニタ表示用) + uint8 priority; // 現在の実効プライオリティ + bool req; // REQ#n 信号 + + // レジスタ + + // CSR + uint8 csr; // COC,BTC,NDT,ERR を保持 + bool active; // ACT + bool pcl_pin; // PCL 信号線の状態 (High が true) + bool pcl_prev; // 前回の PCL の状態 (High が true) + uint8 GetCSR() const; + bool IsINTR() const { // CSR の割り込み要因が立っていれば true + // XXX PCT は未対応 + return csr; + } + + uint8 cer; + + // DCR + uint xrm; + uint dtyp; + uint dps; + uint dcr_pcl; + uint8 GetDCR() const; + void SetDCR(uint8); + uint GetXRM() const { return xrm; } + uint GetDTYP() const { return dtyp; } + uint GetDPS() const { return dps; } + uint GetPCL() const { return dcr_pcl; } + + // OCR + uint dir; + uint size; + uint chain; + uint reqg; + uint8 GetOCR() const; + void SetOCR(uint8); + uint32 GetDIR() const { return dir; } + uint32 GetSIZE() const { return size; } + uint32 GetCHAIN() const { return chain; } + uint32 GetREQG() const { return reqg; } + bool IsChain() const { return GetCHAIN() & 0x02; } + bool IsSingleAddress() const { return GetREQG() & 0x02; } + + // SCR + // XXX 名前が衝突してるのは後からなんとかする + uint scr_mac; + uint scr_dac; + uint8 GetSCR() const; + void SetSCR(uint8); + uint32 GetMAC() const { return scr_mac; } + uint32 GetDAC() const { return scr_dac; } + int mac; + int dac; + + // CCR + bool str; + bool cnt; + bool hlt; + bool sab; + bool int_enable; + uint8 GetCCR() const; + void SetCCR(uint8); + + uint16 mtc; + uint32 mar; + uint32 dar; + uint16 btc; + uint32 bar; + uint8 niv; + uint8 eiv; + uint8 mfc; + uint8 cpr; + uint8 dfc; + uint8 bfc; + void SetNIV(uint8); + void SetEIV(uint8); + void SetMFC(uint8); + void SetCPR(uint8); + void SetDFC(uint8); + void SetBFC(uint8); + + // 転送シーケンス + std::vector seq {}; + int seq_index {}; + + // 転送リトライカウンタ。 + // 実際には (SPC からの) DTACK を待つのだが、 + // 待つのは大変なのでこちらでポーリングしている。 + int retry {}; + + // 転送中データ + FixedQueue data; }; -class DMACDevice - : public IODevice +class DMACDevice : public IODevice { - typedef IODevice inherited; + using inherited = IODevice; static const int baseaddr = 0xe84000; + // 転送シーケンス + enum { + NOP = 0, + RD_M8, + RD_M16, + RD_D8, + RD_D16, + WR_M8, + WR_M16, + WR_D8, + WR_D16, + }; + public: DMACDevice(); - virtual ~DMACDevice(); + virtual ~DMACDevice() override; - virtual uint64 Read8(uint32 addr); - virtual uint64 Write8(uint32 addr, uint32 data); - virtual uint64 Peek8(uint32 addr); + bool Init() override; + void ResetHard(bool poweron) override; + + uint64 Read8(uint32 addr) override; + uint64 Read16(uint32 addr) override; + uint64 Write8(uint32 addr, uint32 data) override; + uint64 Write16(uint32 addr, uint32 data) override; + uint64 Peek8(uint32 addr) override; + + // 外部デバイスが REQ 信号を操作する + void AssertREQ(int ch); + void NegateREQ(int ch); + + // 割り込みアクノリッジ + int InterruptAcknowledge(); + + protected: + // BusIO インタフェース + static const uint NPORT = 256; + uint64 Read(uint32 offset); + uint64 Write(uint32 offset, uint32 data); + uint64 Peek(uint32 offset); private: - void write_csr(int ch, uint32 data); - void write_ccr(int ch, uint32 data); + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + void MonitorReg4(TextScreen&, + int x, int y, uint32 reg, const char * const *names); + + // チャンネル操作 + void WriteCSR(DMACChan *chan, uint32 data); + void WriteCCR(DMACChan *chan, uint32 data, uint8 up); + void WriteGCR(uint8 data); - struct DMAC dmac {}; + // 割り込み信号線の状態を変更 + void ChangeInterrupt(); + + // 転送 + void StartTransfer(DMACChan *chan); + void AbortTransfer(DMACChan *chan); + DMACChan *SelectChannel(); + + // 転送イベントコールバック + void StartCallback(Event& ev); + void TransferCallback(Event& ev); + + // 転送中エラー + void TransferError(DMACChan *, int op, uint64); + + // エラー発生 + void Error(DMACChan *chan, uint8 errcode); + + void AssertACK(DMACChan *); + void NegateACK(DMACChan *); + + // レジスタ + std::array channel {}; + uint8 gcr; + + ADPCMDevice *adpcm {}; + FDCDevice *fdc {}; + InterruptDevice *interrupt {}; + MainbusDevice *mainbus {}; + + Event event { this }; + + Monitor monitor { this }; + + static const char * const errnames[]; }; + +static inline DMACDevice *GetDMACDevice() { + return Object::GetObject(OBJ_DMAC); +}