|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.