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