File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / dmac.h
Revision 1.1.1.19 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (3 months ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// DMAC (HD63450)
//

#pragma once

#include "device.h"
#include "bus.h"
#include "fixedqueue.h"
#include <array>

class ADPCMDevice;
class FDCDevice;
class InterruptDevice;
class MainbusDevice;
class Syncer;

struct DMAC
{
	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_DISABLED = 0;		// Chain operation is disabled
	static const uint32 CHAIN_reserved = 1;		// (Undefined, reserved)
	static const uint32 CHAIN_ARRAY = 2;		// Array Chaining
	static const uint32 CHAIN_LINKARRAY = 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     |
	//     +-----+-----+-----+-----+-----+-----+-----+-----+
};

// 各チャンネル
class DMACChan : public Device
{
	using inherited = Device;
 public:
	DMACChan(int ch_, const char *desc_);
	~DMACChan() override;

	// 二次変数など
	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<uint> seq {};
	int seq_index {};

	// 転送リトライカウンタ。
	// 実際には (SPC からの) DTACK を待つのだが、
	// 待つのは大変なのでこちらでポーリングしている。
	uint retry {};

	// 転送中データ
	FixedQueue<uint8, 2> data;
};

class DMACDevice : public IODevice
{
	using inherited = IODevice;

	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();
	~DMACDevice() override;

	bool Init() override;
	void ResetHard(bool poweron) override;

	busdata Read(busaddr addr) override;
	busdata Write(busaddr addr, uint32 data) override;
	busdata Peek1(uint32 addr) override;

	// 外部デバイスが REQ 信号を操作する
	void AssertREQ(uint ch);
	void NegateREQ(uint ch);

	// 割り込みアクノリッジ
	busdata InterruptAcknowledge();

	// ユーザ空間制御
	void SetUdevice(uint32 start, uint32 end, bool accessible);

 private:
	DECLARE_MONITOR_SCREEN(MonitorScreen);

	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);

	// ACT ビットの状態を変更
	void ChangeACT(DMACChan *, bool);

	// 割り込み信号線の状態を変更
	void ChangeInterrupt();

	// 転送
	void StartTransfer(DMACChan *chan);
	void AbortTransfer(DMACChan *chan);
	std::string MakeStartLog(DMACChan *chan);
	bool LoadLinkArray(DMACChan *chan);
	DMACChan *SelectChannel();

	// 転送イベントコールバック
	void StartCallback(Event *);
	void TransferCallback(Event *);

	// ログ出力
	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 *);

	// メインメモリアクセス
	busdata ReadMem(busaddr addr);
	busdata ReadMem4(busaddr addr);
	busdata WriteMem(busaddr addr, uint32 data);

	// レジスタ
	std::array<std::unique_ptr<DMACChan>, 4> channels {};
	uint8 gcr;

	// ユーザ空間制御
	std::array<bool, 2048> useraccess {};

	ADPCMDevice *adpcm {};
	FDCDevice *fdc {};
	InterruptDevice *interrupt {};
	MainbusDevice *mainbus {};
	Syncer *syncer {};

	Event *event {};

	Monitor *monitor {};

	static const char * const errnames[];
	static const char * const regname1[0x40];
	static const char * const regname2[0x20];
	static const char * const seqname[SEQ_MAX];
};

inline DMACDevice *GetDMACDevice() {
	return Object::GetObject<DMACDevice>(OBJ_DMAC);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.