File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / lance.h
Revision 1.1.1.17 (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
//

//
// Lance (AM7990)
//

#pragma once

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

class InterruptDevice;
class SubRAMDevice;

struct AM7990
{
	uint rap;			// レジスタアドレス (0..3)

	// CSR0
	static const uint16 CSR0_ERR	= 0x8000;
	static const uint16 CSR0_BABL	= 0x4000;
	static const uint16 CSR0_CERR	= 0x2000;
	static const uint16 CSR0_MISS	= 0x1000;
	static const uint16 CSR0_MERR	= 0x0800;
	static const uint16 CSR0_RINT	= 0x0400;
	static const uint16 CSR0_TINT	= 0x0200;
	static const uint16 CSR0_IDON	= 0x0100;
	static const uint16 CSR0_INTR	= 0x0080;
	static const uint16 CSR0_INEA	= 0x0040;
	static const uint16 CSR0_RXON	= 0x0020;
	static const uint16 CSR0_TXON	= 0x0010;
	static const uint16 CSR0_TDMD	= 0x0008;
	static const uint16 CSR0_STOP	= 0x0004;
	static const uint16 CSR0_STRT	= 0x0002;
	static const uint16 CSR0_INIT	= 0x0001;
	// CSR0_ERR はこれらの和
	static const uint16 CSR0_ERR_BITS =
		CSR0_BABL |
		CSR0_CERR |
		CSR0_MISS |
		CSR0_MERR;
	// CSR0_INTR はこれらの和
	static const uint16 CSR0_INTR_BITS =
		CSR0_BABL |
		CSR0_MISS |
		CSR0_MERR |
		CSR0_RINT |
		CSR0_TINT |
		CSR0_IDON;

	// CSR1
	static const uint16 CSR1_MASK	= 0xfffe;
	static const uint16 IADR_L_MASK	= 0xfffe;

	// CSR2
	static const uint16 CSR2_MASK	= 0x00ff;
	static const uint16 IADR_H_MASK	= 0x00ff;

	// CSR3
	static const uint16 CSR3_MASK	= 0x0007;
	static const uint16 CSR3_BSWP	= 0x0004;
	static const uint16 CSR3_ACON	= 0x0002;
	static const uint16 CSR3_BCON	= 0x0001;

	// IBMODE
	static const uint16 IBMODE_PROM	= 0x8000;
	static const uint16 IBMODE_INTL	= 0x0040;
	static const uint16 IBMODE_DRTY	= 0x0020;
	static const uint16 IBMODE_COLL	= 0x0010;
	static const uint16 IBMODE_DTCR	= 0x0008;
	static const uint16 IBMODE_LOOP	= 0x0004;
	static const uint16 IBMODE_DTX	= 0x0002;
	static const uint16 IBMODE_DRX	= 0x0001;
	// RMD1
	static const uint16 RMD1_OWN	= 0x8000;
	static const uint16 RMD1_ERR	= 0x4000;
	static const uint16 RMD1_FRAM	= 0x2000;
	static const uint16 RMD1_OFLO	= 0x1000;
	static const uint16 RMD1_CRC	= 0x0800;
	static const uint16 RMD1_BUFF	= 0x0400;
	static const uint16 RMD1_STP	= 0x0200;
	static const uint16 RMD1_ENP	= 0x0100;
	// TMD1
	static const uint16 TMD1_OWN	= 0x8000;
	static const uint16 TMD1_ERR	= 0x4000;
	static const uint16 TMD1_resv	= 0x2000;
	static const uint16 TMD1_MORE	= 0x1000;
	static const uint16 TMD1_ONE	= 0x0800;
	static const uint16 TMD1_DEF	= 0x0400;
	static const uint16 TMD1_STP	= 0x0200;
	static const uint16 TMD1_ENP	= 0x0100;
	// TMD3
	static const uint16 TMD3_BUFF	= 0x8000;
	static const uint16 TMD3_UFLO	= 0x4000;
	static const uint16 TMD3_resv	= 0x2000;
	static const uint16 TMD3_LCOL	= 0x1000;
	static const uint16 TMD3_LCAR	= 0x0800;
	static const uint16 TMD3_BTRY	= 0x0400;

	// CSR0 ビットごとに処理方法が異なる。
	//
	// b15 ERR :	値は計算で求める。csr0 の該当ビットは常時クリア。
	// b14 BABL:	csr0 で保持。
	// b13 CERR:	csr0 で保持。
	// b12 MISS:	csr0 で保持。
	// b11 ERR :	csr0 で保持。
	// b10 INT :	csr0 で保持。
	// b9  TINT:	csr0 で保持。
	// b8  IDON:	csr0 で保持。
	// b7  INTR:	値は計算で求める。csr0 の該当ビットは常時クリア。
	// b6  INEA:	csr0 で保持。
	// b5  RXON:	csr0 で保持。
	// b4  TXON:	csr0 で保持。
	// b2  STOP:	csr0 で保持。
	// b1  STRT:	csr0 で保持。
	// b0  INIT:	csr0 で保持。
	//
	// レジスタ値や状態を更新する際にはこれらに注意すること。
	// レジスタ値を読み出す時は GetCSR0() を使用すること。
	uint16 csr0;
	bool IsERR() const		{ return ((csr0 & CSR0_ERR_BITS) != 0); }
	bool IsINTR() const		{ return ((csr0 & CSR0_INTR_BITS) != 0); }
	bool IsSTOP() const		{ return ((csr0 & CSR0_STOP) != 0); }

	// CSR0 の読み出し値を返す
	uint16 GetCSR0() const	{
		// ERR, INTR ビットだけ計算による
		uint16 intr = IsINTR() ? CSR0_INTR : 0;
		uint16 errbit = IsERR() ? CSR0_ERR : 0;
		return (csr0 | intr | errbit);
	}

	// CSR1, CSR2 は IADR の状態で保持する
	uint32 iadr;

	// CSR3
	uint16 csr3;
	bool IsBSWP() const		{ return (csr3 & CSR3_BSWP); }
};

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

	// 受信フェーズ
	enum class RXPhase {
		STOP = 0,	// (動作していない)
		IDLE,		// ポーリング
		COPY,		// バッファ書き込み
		NEXT,		// RMD 更新
		MISS,		// 受信ミス
	};
	// 送信フェーズ
	enum class TXPhase {
		STOP = 0,	// (動作していない)
		IDLE,		// ポーリング
		COPY,		// バッファ読み込み
		SEND,		// 送信
		NEXT,		// TMD 更新
	};

 public:
	LanceDevice();
	~LanceDevice() override;

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

	int HWAddrFilter(const MacAddr& dstaddr) const override;

	// BusIO インタフェース
	// (内蔵 ROM からのアクセス用に特別に public にしてある)
	busdata WritePort(uint32 offset, uint32 data);
 protected:
	static const uint32 NPORT = 2;
	busdata ReadPort(uint32 offset);
	busdata PeekPort(uint32 offset);

 private:
	DECLARE_MONITOR_SCREEN(MonitorScreen);
	void MonitorReg(TextScreen&,
		int x, int y, uint32 data, const char * const * names);
	uint32 ReadData();
	void WriteData(uint32 data);

	// メモリアクセス
	uint32 ReadMem(uint32 paddr);
	void WriteMem(uint32 paddr, uint32 data);
	uint32 PeekMem(uint32 paddr) const;

	void ChipInit();
	void ChipStart();
	void ChipStop();

	// 割り込み要因をセットし、許可されていれば割り込みを上げる
	void SetInterrupt(uint32 bit);
	// 割り込み信号線の状態を変える
	void ChangeInterrupt();

	void TXIdle(Event *);
	void TXCopy();
	void TXSend(Event *);
	void TXNext(Event *);

	void RXIdle(Event *);
	void RXCopy();
	void RXNext(Event *);
	void RXMiss();

	// フェーズ遷移
	void ChangePhase(TXPhase new_phase, uint64 time = 100_nsec);
	void ChangePhase(RXPhase new_phase, uint64 time = 100_nsec);

	// パケット受信通知 (HostNet から EthernetDevice 経由で呼ばれる)
	void RxMessage(MessageID, uint32);

	const std::string BitToString(const char * const name[], uint16 bits);
	const std::string CSR0ToString(uint16 bits);
	const std::string CSR3ToString(uint16 bits);
	static const char * const csr0names[];
	static const char * const csr3names[];
	static const char * const ib_mode_names[];
	static const char * const rmd1_names[];
	static const char * const tmd1_names[];
	static const char * const tmd3_names[];

	struct AM7990 reg {};

	// Initialization Block
	uint16 initblock[12] {};

	MacAddr padr {};
	uint64 ladrf {};
	bool promisc {};

	uint32 rmd_base {};			// 受信ディスクリプタの(SubRAMでの)開始アドレス
	uint   rmd_num {};			// 受信ディスクリプタ数
	uint   rmd_cur {};			// RMD 内の現在の注目インデックス
	uint32 tmd_base {};			// 送信ディスクリプタの(SubRAMでの)開始アドレス
	uint   tmd_num {};			// 送信ディスクリプタ数
	uint   tmd_cur {};			// TMD 内の現在の注目インデックス

	uint16 rmd1 {};				// 現在の RMD1
	uint32 rmd1_ahead {};		// 次の RMD1 先読み (負なら先読みしてない状態)

	uint16 tmd1 {};				// 現在の TMD1
	uint32 tmd1_ahead {};		// 次の TMD1 先読み (負なら先読みしてない状態)

	NetPacket rx_packet {};		// 受信バッファ
	NetPacket tx_packet {};		// 送信バッファ

	RXPhase rx_phase {};		// 受信フェーズ
	TXPhase tx_phase {};		// 送信フェーズ

	// 前回の TMD 状態文字列 (デバッグ表示用)
	std::string last_tmdstr {};

	InterruptDevice *interrupt {};
	SubRAMDevice *subram {};

	// 待ち時間用イベント
	Event *rx_event {};
	Event *tx_event {};

	Monitor *monitor {};
};

inline LanceDevice *GetLanceDevice() {
	return Object::GetObject<LanceDevice>(OBJ_ETHERNET(0));
}

unix.superglobalmegacorp.com

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