--- nono/vm/dmac.h 2026/04/29 17:04:32 1.1.1.2 +++ nono/vm/dmac.h 2026/04/29 17:05:29 1.1.1.14 @@ -1,12 +1,26 @@ // // 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 "scheduler.h" +#include "bus.h" +#include "event.h" +#include "fixedqueue.h" +#include "monitor.h" +#include + +class ADPCMDevice; +class FDCDevice; +class InterruptDevice; +class MainbusDevice; struct DMAC { @@ -29,21 +43,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 @@ -55,147 +76,278 @@ 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; - - // レジスタ - - // CSR - uint8 csr; // COC,BTC,NDT,ERR を保持 - bool active; // ACT - bool pcl; // PCL の状態 (High が true) - bool prev_pcl; // 前回の PCL の状態 (High が true) - - 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; - bool int_enable; // INT: 割り込み許可なら true - - 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); - uint8 PeekCCR() const; - void WriteCCR(uint32 data); - - // 転送開始 - void StartTransfer(); - // 割り込み - void SetINT(uint32 val); - } 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 cpr; + busaddr mfc; + busaddr dfc; + busaddr 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 を待つのだが、 + // 待つのは大変なのでこちらでポーリングしている。 + uint retry {}; + + // 転送中データ + FixedQueue data; }; -class DMACDevice - : public IODevice +class DMACDevice : public IODevice { - typedef IODevice inherited; + using inherited = IODevice; - static const int baseaddr = 0xe84000; + static const uint32 baseaddr = 0xe84000; + + // 転送シーケンス + enum { + NOP = 0, + RD_M8, + RD_M16, + RD_D8, + RD_D16, + WR_M8, + WR_M16, + WR_D8, + WR_D16, + SEQ_MAX, + }; public: DMACDevice(); - virtual ~DMACDevice(); + ~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; - virtual bool MonitorUpdate(); + busdata Read(busaddr addr) override; + busdata Write(busaddr addr, uint32 data) override; + busdata Peek1(uint32 addr) override; - // 転送 - void AbortTransfer(DMAC::Channel *chan); - void Transfer(int arg); - int64 TransferM8toD8(DMAC::Channel *chan); - int64 TransferD8toM8(DMAC::Channel *chan); + // 外部デバイスが REQ 信号を操作する + void AssertREQ(uint ch); + void NegateREQ(uint ch); + + // 割り込みアクノリッジ + busdata InterruptAcknowledge(); + + // ユーザ空間制御 + void SetUdevice(uint32 start, uint32 end, bool accessible); private: - void MonitorReg4(int x, int y, uint32 reg, const char * const *names); + DECLARE_MONITOR_CALLBACK(MonitorUpdate); + + void MonitorReg4(TextScreen&, + int x, int y, uint32 reg, const char * const *names); + + busdata WriteByte(DMACChan *chan, uint32 n, uint32 data); + busdata WriteWord(DMACChan *chan, uint32 n, uint32 data); + + // チャンネル操作 + 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 TransferCallback(Event& ev); + + // ログ出力 + void TransferLog(DMACChan *, uint op, busaddr addr, busdata r, uint64 data); + + // 転送中エラー + void TransferError(DMACChan *, uint op, busdata r, uint32 data); + + // エラー発生 + void Error(DMACChan *chan, uint8 errcode); + + void AssertACK(DMACChan *); + void NegateACK(DMACChan *); + + // レジスタ + std::array channel {}; + uint8 gcr; + + // ユーザ空間制御 + std::array useraccess {}; + + ADPCMDevice *adpcm {}; + FDCDevice *fdc {}; + InterruptDevice *interrupt {}; + MainbusDevice *mainbus {}; + + Event event { this }; - struct DMAC dmac {}; - Event event[4] {}; + Monitor monitor { this }; static const char * const errnames[]; + static const char * const regname1[0x40]; + static const char * const regname2[0x20]; + static const char * const seqname[SEQ_MAX]; }; -extern std::unique_ptr gDMAC; +static inline DMACDevice *GetDMACDevice() { + return Object::GetObject(OBJ_DMAC); +}