--- nono/vm/lance.cpp 2026/04/29 17:05:28 1.1.1.16 +++ nono/vm/lance.cpp 2026/04/29 17:05:46 1.1.1.19 @@ -12,6 +12,7 @@ #include "bitops.h" #include "interrupt.h" #include "mainbus.h" +#include "monitor.h" #include "scheduler.h" #include "subram.h" @@ -24,9 +25,9 @@ LanceDevice::LanceDevice() AddAlias("Lance"); AddAlias("Ethernet"); - monitor.func = ToMonitorCallback(&LanceDevice::MonitorUpdate); - monitor.SetSize(80, 34); - monitor.Regist(ID_MONITOR_LANCE); + monitor = gMonitorManager->Regist(ID_MONITOR_LANCE, this); + monitor->func = ToMonitorCallback(&LanceDevice::MonitorUpdate); + monitor->SetSize(80, 34); } // デストラクタ @@ -38,13 +39,11 @@ LanceDevice::~LanceDevice() bool LanceDevice::Init() { - if (inherited::Init() == false) { - return false; - } - interrupt = GetInterruptDevice(); subram = GetSubRAMDevice(); + hostnet->SetPortName("Lance"); + // ホストからの受信コールバックを登録 scheduler->ConnectMessage(MessageID::HOSTNET_RX(0), this, ToMessageCallback(&LanceDevice::RxMessage)); @@ -610,28 +609,25 @@ LanceDevice::ChipInit() int tlen = tdrp >> 29; tmd_num = (1 << tlen); - padr[0] = initblock[1] & 0xff; - padr[1] = initblock[1] >> 8; - padr[2] = initblock[2] & 0xff; - padr[3] = initblock[2] >> 8; - padr[4] = initblock[3] & 0xff; - padr[5] = initblock[3] >> 8; + padr = MacAddr( + initblock[1] & 0xff, + initblock[1] >> 8, + initblock[2] & 0xff, + initblock[2] >> 8, + initblock[3] & 0xff, + initblock[3] >> 8); // LADRF は以下のように格納されていて、そのまま LADRF(63:00) に対応する。 // IADR+$08 LADRF(15:00) // IADR+$0a LADRF(31:16) // IADR+$0c LADRF(47:32) // IADR+$0e LADRF(63:48) - uint64 filter; - filter = ((uint64)initblock[4] << 0) - | ((uint64)initblock[5] << 16) - | ((uint64)initblock[6] << 32) - | ((uint64)initblock[7] << 48); - - // ホストデバイスに設定 - hostnet->SetMyAddr(padr); - hostnet->SetMCastFilter(filter); - hostnet->SetPromisc((initblock[0] & AM7990::IBMODE_PROM)); + ladrf = ((uint64)initblock[4] << 0) + | ((uint64)initblock[5] << 16) + | ((uint64)initblock[6] << 32) + | ((uint64)initblock[7] << 48); + + promisc = (initblock[0] & AM7990::IBMODE_PROM); // XXX 本当はいろいろ時間がかかりそうなはずだが // 初期化完了 @@ -1206,6 +1202,54 @@ LanceDevice::RXMiss() ChangePhase(RXPhase::IDLE); } +// この宛先アドレスを受信するかどうか。 +// これは HostNet スレッドで呼ばれる。 +int +LanceDevice::HWAddrFilter(const MacAddr& dstaddr) const +{ + if (promisc) { + return HPF_PASS; + } + + if (dstaddr.IsUnicast()) { + if (dstaddr != padr) { + return HPF_DROP_UNICAST; + } + } else { + if (dstaddr.IsBroadcast()) { + return HPF_PASS; + } + + // マルチキャスト。 + // + // AM7990 のマルチキャストフィルタ(ハッシュ) は宛先 MAC アドレスの + // CRC (32ビット) のうち、下位6ビット *のビット順を逆順にしたもの* + // を pos として、LADRF の下から pos ビット目が立っていれば受理する + // というもの。 + // 31 7 6 5 4 3 2 1 0 + // +--- -+---+---+---+---+---+---+---+---+ + // CRC32(dstaddr) = | .. | X X | p0| p1| p2| p3| p4| p5| + // +--- -+---+---+---+---+---+---+---+---+ + // + // +---+---+---+---+---+---+ + // pos = | p5| p4| p3| p2| p1| p0| + // +---+---+---+---+---+---+ + + uint32 crc = EthernetDevice::CRC32(dstaddr); + uint pos = bitrev8(crc) >> 2; + bool mcast_pass = (ladrf & (1ULL << pos)); + putmsg(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%u %s", + dstaddr[0], dstaddr[1], dstaddr[2], + dstaddr[3], dstaddr[4], dstaddr[5], + pos, (mcast_pass ? "pass" : "drop")); + if (mcast_pass == false) { + return HPF_DROP_MULTICAST; + } + } + + return HPF_PASS; +} + // 指定時間後に RX フェーズを遷移する。 // (変化があれば)変更するではないことに注意。名前がアレだが IDLE フェーズは // ポーリングしているので IDLE から IDLE への遷移も必ず起こす必要がある。