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

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

//
// Nereid イーサネット (RTL8019AS)
//

#pragma once

#include "ethernet.h"
#include "hostnet.h"
#include "message.h"

class InterruptDevice;

struct RTL8019
{
	// レジスタアドレスは $0-$f までの16個 x Page 0-3 の4ページなので、
	// ここでのレジスタ番号は全部リニアに並べて表現する。
	// Page0 はほとんどが Read/Write でレジスタが異なるが、
	// それについてはここでは区別せず、Read/Write のコード中で使い分ける。

	// Page0 R(/W)
	static const uint32 CR		= 0x00;	// RW: Command Register
	static const uint32 CLDA0	= 0x01;	// R-: Current Local DMA Address Regs
	static const uint32 CLDA1	= 0x02;	// R-: Current Local DMA Address Regs
	static const uint32 BNRY	= 0x03;	// RW: Boundary Register
	static const uint32 TSR		= 0x04;	// R-: Transmit Status Register
	static const uint32 NCR		= 0x05;	// R-: Number of Collisions Register
	static const uint32 FIFO	= 0x06;	// R-: First In First Out Register
	static const uint32 ISR		= 0x07;	// RW: Interrupt Status Register
	static const uint32 CRDA0	= 0x08;	// R-: Current Remote DMA Address Regs
	static const uint32 CRDA1	= 0x09;	// R-: Current Remote DMA Address Regs
	static const uint32 ID0		= 0x0a;	// R-: 8019ID0
	static const uint32 ID1		= 0x0b;	// R-: 8019ID1
	static const uint32 RSR		= 0x0c;	// R-: Receive Configuration Register
	static const uint32 CNTR0	= 0x0d;	// R-: Frame Align.Error Tally Counter
	static const uint32 CNTR1	= 0x0e;	// R-: CRC Error Tally Counter Reg.
	static const uint32 CNTR2	= 0x0f;	// R-: Missed Pakcet Tally Counter Reg.

	// Page0 W
	static const uint32 PSTART	= 0x01;	// -W: Page Start Register
	static const uint32 PSTOP	= 0x02;	// -W: Page Stop Register
	static const uint32 TPSR	= 0x04;	// -W: Transmit Page Start Register
	static const uint32 TBCR0	= 0x05;	// -W: Transmit Byte Counter Registers
	static const uint32 TBCR1	= 0x06;	// -W: Transmit Byte Counter Registers
	static const uint32 RSAR0	= 0x08;	// -W: Remote Start Address Regs
	static const uint32 RSAR1	= 0x09;	// -W: Remote Start Address Regs
	static const uint32 RBCR0	= 0x0a;	// -W: Remote Byte Count Registers
	static const uint32 RBCR1	= 0x0b;	// -W: Remote Byte Count Registers
	static const uint32 RCR		= 0x0c;	// -W: Receive Configuration Register
	static const uint32 TCR		= 0x0d;	// -W: Transmit Configuration Register
	static const uint32 DCR		= 0x0e;	// -W: Data Configuration Register
	static const uint32 IMR		= 0x0f;	// -W: Interrupt Mask Register

	// Page 1 R/W
	static const uint32 CR_1	= 0x10;
	static const uint32 PAR0	= 0x11;	// RW: Physical Address Registers
	static const uint32 PAR1	= 0x12;	// RW: Physical Address Registers
	static const uint32 PAR2	= 0x13;	// RW: Physical Address Registers
	static const uint32 PAR3	= 0x14;	// RW: Physical Address Registers
	static const uint32 PAR4	= 0x15;	// RW: Physical Address Registers
	static const uint32 PAR5	= 0x16;	// RW: Physical Address Registers
	static const uint32 CURR	= 0x17;	// RW: Current Page Register
	static const uint32 MAR0	= 0x18;	// RW: Multicast Address Registers
	static const uint32 MAR1	= 0x19;	// RW: Multicast Address Registers
	static const uint32 MAR2	= 0x1a;	// RW: Multicast Address Registers
	static const uint32 MAR3	= 0x1b;	// RW: Multicast Address Registers
	static const uint32 MAR4	= 0x1c;	// RW: Multicast Address Registers
	static const uint32 MAR5	= 0x1d;	// RW: Multicast Address Registers
	static const uint32 MAR6	= 0x1e;	// RW: Multicast Address Registers
	static const uint32 MAR7	= 0x1f;	// RW: Multicast Address Registers

	// Page2 R
	static const uint32 CR_2	= 0x20;
	static const uint32 PSTART_2= 0x21;
	static const uint32 PSTOP_2	= 0x22;
	static const uint32 TPSR_2	= 0x24;
	static const uint32 RCR_2	= 0x2c;
	static const uint32 TCR_2	= 0x2d;
	static const uint32 DCR_2	= 0x2e;
	static const uint32 IMR_2	= 0x2f;

	// Page3 R/W
	static const uint32 CR_3	= 0x30;
	static const uint32 CR9346	= 0x31;	// RW: 9346 Command Register
	static const uint32 BPAGE	= 0x32;	// RW: BROM Page Register
	static const uint32 CONFIG0	= 0x33;	// R-: RTL8019AS Config. Register 0
	static const uint32 CONFIG1	= 0x34;	// RW: RTL8019AS Config. Register 1
	static const uint32 CONFIG2	= 0x35;	// RW: RTL8019AS Config. Register 2
	static const uint32 CONFIG3	= 0x36;	// RW: RTL8019AS Config. Register 3
	static const uint32 TEST	= 0x37;	// -W:
	static const uint32 CSNSAV	= 0x38;	// R-: CSN Save Register (For PnP)
	static const uint32 HLTCLK	= 0x39;	// -W: Halt Clock Register
	static const uint32 INTR	= 0x3b;	// R-: Interrupt Register
	static const uint32 FMWP	= 0x3c;	// -W: Flush Memory Write Protect Reg.
	static const uint32 CONFIG4	= 0x3d;	// R-: RTL8019AS Config. Register 4

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// CR   |    PS     |       RD        | TXP | STA | STP |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CR_RD_READ	= 0x08;
	static const uint32 CR_RD_WRITE	= 0x10;
	static const uint32 CR_RD_SEND	= 0x18;
	static const uint32 CR_TXP		= 0x04;
	static const uint32 CR_STA		= 0x02;
	static const uint32 CR_STP		= 0x01;

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// TSR  | OWC | CDH |  0  | CRS | ABT | COL |  1  | PTX |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 TSR_OWC		= 0x80;	// Out of Window Collision
	static const uint32 TSR_CDH		= 0x40;	// CD Heartbeat
	static const uint32 TSR_CRS		= 0x10;	// Carrier Sense lost bit
	static const uint32 TSR_ABT		= 0x08;	// Abort TX due to excessive coll.
	static const uint32 TSR_COL		= 0x04;	// TX collied with other station
	static const uint32 TSR_PTX		= 0x01;	// TX completes with no errors

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// ISR  | RST | RDC | CNT | OVW | TXE | RXE | PTX | PRX |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 ISR_RST		= 0x80;	// Enter reset state
	static const uint32 ISR_RDC		= 0x40;	// Remote DMA operation completed
	static const uint32 ISR_CNT		= 0x20;	//
	static const uint32 ISR_OVW		= 0x10;	// RX buffer overflow
	static const uint32 ISR_TXE		= 0x08;	// TX Error
	static const uint32 ISR_RXE		= 0x04;	// RX Error
	static const uint32 ISR_PTX		= 0x02;	// Packet transmitted with no errors
	static const uint32 ISR_PRX		= 0x01;	// Packet received with no errors

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// RSR  | DFR | DIS | PHY | MPA |  0  | FAE | CRC | PRX |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 RSR_DFR		= 0x80;	// Deffering
	static const uint32 RSR_DIS		= 0x40;	// Receiver Disabled
	static const uint32 RSR_PHY		= 0x20;	// Recv'd packet is multi/broadcast
	static const uint32 RSR_MPA		= 0x10;	// Missed Packet
	static const uint32 RSR_FAE		= 0x04;	// Frame Alignment Error
	static const uint32 RSR_CRC		= 0x02;	// CRC Error
	static const uint32 RSR_PRX		= 0x01;	// Packet received with no errors

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// RCR  |  1  |  1  | MON | PRO | AM  | AB  | AR  | SEP |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 RCR_MON		= 0x20;	// Monitor mode
	static const uint32 RCR_PRO		= 0x10;	// Promisc.
	static const uint32 RCR_AM		= 0x08;	// Accept multicast dest address
	static const uint32 RCR_AB		= 0x04;	// Accept broadcast dest address
	static const uint32 RCR_AR		= 0x02;	// Accept <64bytes
	static const uint32 RCR_SEP		= 0x01;	// Accept packet with recv errors

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// TCR  |  1  |  1  |  1  |OFST | ATD |     LB    | CRC |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 TCR_OFST	= 0x10;	// Collision Offset Enable
	static const uint32 TCR_ATD		= 0x08;	// Auto Transmit Disable
	static const uint32 TCR_LB_MASK	= 0x06;	// Loopback mode
	static const uint32 TCR_CRC		= 0x01;	// Don't append CRC

	//         7     6     5     4     3     2     1     0
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	// DCR  |  1  |    FT     | ARM | LS  | LAS | BOS | WTS |
	//      +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 DCR_FT_MASK	= 0x60;	// FIFO threshold
	static const uint32 DCR_ARM		= 0x10;	// Auto initialize Remote
	static const uint32 DCR_LS		= 0x08;	// Loopback Select
	static const uint32 DCR_LAS		= 0x04;	// (32bit DMA not supported by NIC)
	static const uint32 DCR_BOS		= 0x02;	// Byte Order Select (Not Impl?)
	static const uint32 DCR_WTS		= 0x01;	// Word Transfer Select

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// 9346CR  |    EEM    |  not used |EECS |EESK |EEDI |EEDO |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CR9346_EEM_MASK	= 0xc0;	// RTL8019AS operating mode

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// CONFIG0 |   VERID   | AUI |PNPJP| JP  | BNC |  0  |  0  |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CONFIG0_VERID_MASK	= 0xc0;
	static const uint32 CONFIG0_AUI			= 0x20;
	static const uint32 CONFIG0_PNPJP		= 0x10;
	static const uint32 CONFIG0_JP			= 0x08;
	static const uint32 CONFIG0_BNC			= 0x04;

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// CONFIG1 |IRQEN|      IRQS       |          IOS          |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CONFIG1_IRQEN		= 0x80;
	static const uint32 CONFIG1_IRQS_MASK	= 0x70;
	static const uint32 CONFIG1_IOS_MASK	= 0x0f;

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// CONFIG2 |    PL     |BSELB|             BS              |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CONFIG2_PL_MASK		= 0xc0;
	static const uint32 CONFIG2_BSELB		= 0x20;
	static const uint32 CONFIG2_BS			= 0x1f;

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// CONFIG3 | PNP |FUDUP|LEDS1|LEDS0|  0  |SLEEP|PWRDN|ACTB |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CONFIG3_PNP			= 0x80;
	static const uint32 CONFIG3_FUDUP		= 0x40;
	static const uint32 CONFIG3_LEDS1		= 0x20;
	static const uint32 CONFIG3_LEDS0		= 0x10;
	static const uint32 CONFIG3_SLEEP		= 0x04;
	static const uint32 CONFIG3_PWRDN		= 0x02;
	static const uint32 CONFIG3_ACTB		= 0x01;

	//            7     6     5     4     3     2     1     0
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	// CONFIG4 |  -  |  -  |  -  |  -  |  -  |  -  |  -  |IOMS |
	//         +-----+-----+-----+-----+-----+-----+-----+-----+
	static const uint32 CONFIG4_IOMS		= 0x01;

	// メディアタイプ (CONFIG2)
	enum {
		MediaType_10BaseT_Auto	= 0,
		MediaType_10BaseT	= 1,
		MediaType_10Base5	= 2,
		MediaType_10Base2	= 3,
	};
};

class RTL8019ASDevice : public EthernetDevice, public IHWAddrFilter
{
	using inherited = EthernetDevice;

	// 動作状態 (数値比較も行うことに注意)
	enum class State {
		Normal = 0,			// 送受信可能
		Stop = 1,			// STP
		StopInProgress = 2,	// STP へ移行中 (処理中の送受信のみ継続)
	};

	// DMA 状態?
	enum class DMAMode {
		NotAllowed	= 0,
		RemoteRead	= 1,
		RemoteWrite	= 2,
		SendPacket	= 3,
		Complete	= 4,
	};

 public:
	RTL8019ASDevice(uint n_, int vector_);
	~RTL8019ASDevice() 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;

	busdata InterruptAcknowledge();

	int HWAddrFilter(const MacAddr& dstaddr) const override;

 private:
	static inline uint32 Decoder(uint32 addr);

	uint32 ReadReg(uint32 rn);
	uint32 ReadDMA8(uint32 a0);
	uint32 ReadDMA16();
	void WriteReg(uint32 rn, uint32 data);
	void WriteCR(uint32 data);
	void WritePSTART(uint32 data);
	void WritePSTOP(uint32 data);
	void WriteBNRY(uint32 data);
	void WriteTPSR(uint32 data);
	void WriteTBCR0(uint32 data);
	void WriteTBCR1(uint32 data);
	void WriteISR(uint32 data);
	void WriteRSAR0(uint32 data);
	void WriteRSAR1(uint32 data);
	void WriteRBCR0(uint32 data);
	void WriteRBCR1(uint32 data);
	void WriteRCR(uint32 data);
	void WriteTCR(uint32 data);
	void WriteDCR(uint32 data);
	void WriteIMR(uint32 data);
	void WritePAR(uint n, uint32 data);
	void WriteCURR(uint32 data);
	void WriteMAR(uint n, uint32 data);
	void Write9346CR(uint32 data);
	void WriteCONFIG0(uint32 data);
	void WriteCONFIG1(uint32 data);
	void WriteCONFIG2(uint32 data);
	void WriteCONFIG3(uint32 data);
	void WriteDMA8(uint32 data);
	void WriteDMA16(uint32 data);
	uint32 PeekReg(uint32 rn) const;
	uint32 PeekCR() const;
	uint32 PeekCLDA() const;
	uint32 PeekBNRY() const;
	uint32 PeekTSR() const;
	uint32 PeekNCR() const;
	uint32 PeekFIFO() const;
	uint32 PeekISR() const;
	uint32 PeekCRDA() const;
	uint32 Peek8019ID0() const;
	uint32 Peek8019ID1() const;
	uint32 PeekRSR() const;
	uint32 PeekCNTR(int n) const;
	uint32 PeekPAR(int n) const;
	uint32 PeekCURR() const;
	uint32 PeekMAR(int n) const;
	uint32 PeekPSTART() const;
	uint32 PeekPSTOP() const;
	uint32 PeekTPSR() const;
	uint32 PeekRCR() const;
	uint32 PeekTCR() const;
	uint32 PeekDCR() const;
	uint32 PeekIMR() const;
	uint32 Peek9346CR() const;
	uint32 PeekBPAGE() const;
	uint32 PeekCONFIG0() const;
	uint32 PeekCONFIG1() const;
	uint32 PeekCONFIG2() const;
	uint32 PeekCONFIG3() const;
	uint32 PeekCONFIG4() const;
	uint32 PeekCSNSAV() const;
	uint32 PeekReg39() const;
	uint32 PeekINTR() const;
	uint32 PeekDMA(uint32 a0) const;

	DECLARE_MONITOR_SCREEN(MonitorScreen);
	void MonitorReg(TextScreen&, int, int, uint32, const char * const *names);

	void Reset();
	void ChangeInterrupt();

	// DMA 処理の下請け
	void ReadDMAlog(uint32 addr, uint32 data, int width);
	void PostDMA();

	// 内蔵空間アクセス
	inline uint32 ReadPROM(uint32 addr) const;
	inline uint32 ReadRAM(uint32 addr) const;
	inline void WriteRAM(uint32 addr, uint32 data);

	// 状態
	bool IsStopOrInProgress() const;
	void ChangeState(State newstate);

	// 送信
	void Transmit();
	void TXEvent(Event *);
	// 受信
	void RxMessage(MessageID msgid, uint32 arg);
	void RXEvent(Event *);
	void RXHead();
	void RXCopy(Event *, uint remain);
	void RXDone(Event *);

	void TXLedEvent(Event *);
	void RXLedEvent(Event *);

	void IncCounter(int n);

	// レジスタ名を返す
	static std::string RegNameR(int rn);
	static std::string RegNameW(int rn);
	static const char *GetDMAName(uint32);

	// 動作状態
	// ハードウェアリセット(解除?)後、STA が発行されるまではリセット状態。
	// STP が発行されたら、仕掛りの送受信を終えたところでリセット状態に入る。
	// リセット状態に入ると ISR:RST が立つ。
	// このリセット状態をここでは Stop 状態と呼ぶ。
	State state {};
	// 送信処理中なら true
	// (受信処理中の方は rx_packet.length != 0 で判定する)
	bool tx_in_progress {};

	// CR: ページ番号 (をあらかじめオフセットしたもの)
	uint32 pagesel {};

	// CR_RD: DMA 状態?
	DMAMode dmamode {};

	bool cr_sta {};

	// 割り込みフラグ (bit7 は 0 にすること)
	uint32 intr_stat {};
	// 割り込みマスク (bit7 は 0 にすること)
	uint32 intr_mask {};
	// 割り込みベクタ (NereidBoardDevice から渡される)
	uint32 intr_vector {};

	uint32 tsr {};
	uint32 rsr {};		// DIS 以外のビットを保持

	// RCR: モニタモード
	bool monitor_mode {};
	bool promisc_mode {};
	bool accept_mcast {};
	bool accept_bcast {};
	bool accept_short {};
	bool accept_error {};

	// TCR
	uint32 tcr {};

	// DCR
	bool word_transfer {};
	uint32 dcr {};		// それ以外のビット

	// 折り返しを計算しなくて済むように uint16 にしておく。
	// またレジスタイメージがバイト単位かページ単位かに関わらず、
	// すべてバイト単位で統一。

	uint16 remote_addr {};			// RSAR/CRDA: 現在のアクセス位置
	uint16 remote_count {};			// RBCR: 残り転送バイト数
	uint16 remote_start_addr {};	// DMA 開始時の位置 (ログ用)
	uint16 remote_start_count {};	// DMA 開始時の残り転送バイト数 (ログ用)

	uint16 transmit_page_start_addr {};	// TPSR
	uint16 transmit_byte_count {};		// TBCR

	uint16 pstart_addr {};			// PSTART
	uint16 pstop_addr {};			// PSTOP
	uint16 boundary_addr {};		// BNRY
	uint16 current_page_addr {};	// CURR: 受信開始位置
	uint16 local_addr {};			// CLDA: 書き込み位置
	uint16 next_page_addr {};		// 次パケットの受信開始位置

	MacAddr par {};
	uint64 mar {};
	std::array<uint8, 3> error_counter {};

	// 9346CR
	bool config_write_enable {};

	// CONFIG
	uint32 verid {};
	bool irq_enable {};
	uint32 mediatype {};
	bool brom_force_disable {};
	uint32 config3 {};

	// バッファ (16KB 固定)
	std::array<uint8, 16384> buffer {};

	// PROM (実質 16 バイト)
	std::array<uint8, 16> prom {};

	NetPacket tx_packet {};
	NetPacket rx_packet {};

	// LED (true で点灯)
	bool tx_led {};
	bool rx_led {};

	Monitor *monitor {};

	Event *tx_event {};
	Event *rx_event {};
	Event *txled_event {};
	Event *rxled_event {};

	InterruptDevice *interrupt {};

	static const char * const regnames[];
};

inline RTL8019ASDevice *GetRTL8019ASDevice(int n) {
	return Object::GetObject<RTL8019ASDevice>(OBJ_ETHERNET(n));
}

unix.superglobalmegacorp.com

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