--- nono/vm/dmac.h 2026/04/29 17:05:11 1.1.1.10 +++ nono/vm/dmac.h 2026/04/29 17:05:14 1.1.1.11 @@ -11,6 +11,7 @@ #pragma once #include "device.h" +#include "fixedqueue.h" #include "monitor.h" #include "event.h" #include @@ -36,21 +37,28 @@ struct DMAC 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 | --- | PCT | PCS | + // 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 - // CER + // 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_OPER_TIMING = 0x02; // Operation Timing 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 @@ -62,116 +70,175 @@ struct DMAC 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 | --- | PCL | - static const uint32 DCR_XRM_BURST = 0; // Burst Transfer - static const uint32 DCR_XRM_CYCLE_WO_HOLD = 2; // Cycle Steal without Hold - static const uint32 DCR_XRM_CYCLE_WITH_HOLD = 3;// Cycle Steal with Hold - static const uint32 DCR_DTYP_68000 = 0; // 68000 devices - static const uint32 DCR_DTYP_6800 = 1; // 6800 devices - static const uint32 DCR_DTYP_ACK = 2; // Devices with ACK - static const uint32 DCR_DTYP_ACK_REDY = 3; // Devices with ACK+READY - static const uint32 DCR_DPS_8BIT = 0; // 8bit port - static const uint32 DCR_DPS_16BIT = 1; // 16bit port - static const uint32 DCR_PCL_STATUS = 0; // Status Input - static const uint32 DCR_PCL_STATUS_INTR = 1; // Status Input with Interrupt - static const uint32 DCR_PCL_PULSE = 2; // Start Pulse - static const uint32 DCR_PCL_ABORT = 3; // Abort Input - - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | - // OCR | DIR | --- | SIZE | CHAIN | REQG | - // - static const uint32 OCR_DIR_MtoD = 0; // Memory to Device - static const uint32 OCR_DIR_DtoM = 1; // Device to Memory - static const uint32 OCR_SIZE_8BIT = 0; // 8bit - static const uint32 OCR_SIZE_16BIT = 1; // 16bit - static const uint32 OCR_SIZE_32BIT = 2; // 32bit - static const uint32 OCR_SIZE_8BIT_UP = 3; // 8bit (Non-Pack Operation) - static const uint32 OCR_CHAIN_NOCHAIN = 0; // Chain operation is disabled - static const uint32 OCR_CHAIN_ARRAY = 2; // Array Chaining - static const uint32 OCR_CHAIN_LINK = 3; // Linked Array Chaining - static const uint32 OCR_REQG_AUTO_LIM = 0; // Auto Request (Limited) - static const uint32 OCR_REQG_AUTO_MAX = 1; // AUto Request (Max) - static const uint32 OCR_REQG_EXTERNAL = 2; // External Request - static const uint32 OCR_REQG_AUTOFIRST = 3; // Auto first then ext. - - // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 | - // SCR | --- --- --- --- | MAC | DAC | + // 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 - // CCR + // 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 - // 各チャンネル - struct Channel { - // 二次変数など - int ch; // チャンネル番号 - const char *desc; // チャンネルの用途(モニタ表示用) - DMACDevice *parent; - uint8 priority; // 現在の実効プライオリティ - - // レジスタ - - // CSR - uint8 csr; // COC,BTC,NDT,ERR を保持 - bool active; // ACT - bool pcl; // PCL の状態 (High が true) - bool prev_pcl; // 前回の PCL の状態 (High が true) - bool IsINTR() const { // CSR の割り込み要因が立っていれば true - // XXX PCT は未対応 - return (csr & (CSR_COC | CSR_BTC | CSR_NDT | CSR_ERR)); - } - - uint8 cer; - uint8 dcr; - uint32 GetXRM() const { return (dcr >> 6); } - uint32 GetDTYP() const { return (dcr >> 4) & 3; } - uint32 GetDPS() const { return (dcr >> 3) & 1; } - uint32 GetPCL() const { return (dcr & 3); } - - uint8 ocr; - uint32 GetDIR() const { return (ocr >> 7); } - uint32 GetSIZE() const { return (ocr >> 4) & 3; } - uint32 GetCHAIN() const { return (ocr >> 2) & 3; } - uint32 GetREQG() const { return (ocr & 3); } - - // 転送種別 (DPS と SIZE から決まる) - uint32 xfertype; - - uint8 scr; - uint32 GetMAC() const { return (scr >> 2) & 3; } - uint32 GetDAC() const { return (scr & 3); } - - uint8 ccr; - - uint16 mtc; - uint32 mar; - uint32 dar; - uint16 btc; - uint32 bar; - uint8 niv; - uint8 eiv; - uint8 mfc; - uint8 cpr; - uint8 dfc; - uint8 bfc; - - uint8 PeekCSR() const; - void WriteCSR(uint32 data); - void WriteCCR(uint32 data); - - // 転送開始 - void StartTransfer(); - } chan[4]; + // 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 @@ -180,15 +247,34 @@ class DMACDevice : public 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() override; void ResetHard(bool poweron) override; - // 転送 - void StartTransfer(); - void AbortTransfer(DMAC::Channel *chan); + 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(); @@ -206,27 +292,37 @@ class DMACDevice : public IODevice 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); + // 割り込み信号線の状態を変更 void ChangeInterrupt(); + // 転送 + void StartTransfer(DMACChan *chan); + void AbortTransfer(DMACChan *chan); + DMACChan *SelectChannel(); + // 転送イベントコールバック void StartCallback(Event& ev); - void ReadCallback(Event& ev); - void WriteCallback(Event& ev); - void DoneCallback(Event& ev); + void TransferCallback(Event& ev); // 転送中エラー - void Error(uint64); + void TransferError(DMACChan *, int op, uint64); - struct DMAC dmac {}; + // エラー発生 + void Error(DMACChan *chan, uint8 errcode); - Event event { this }; + void AssertACK(DMACChan *); + void NegateACK(DMACChan *); - DMAC::Channel *xfer_chan {}; // 現在転送中のチャンネル - uint32 xfer_src; // 転送中ソースアドレス - uint32 xfer_dst; // 転送中ディスティネーションアドレス - uint32 xfer_data; // 転送中データ - int xfer_retry {}; // 転送リトライ + // レジスタ + std::array channel {}; + uint8 gcr; + + Event event { this }; Monitor monitor { this };