--- nono/vm/lance.cpp 2026/04/29 17:05:32 1.1.1.17 +++ nono/vm/lance.cpp 2026/04/29 17:05:50 1.1.1.20 @@ -10,6 +10,7 @@ #include "lance.h" #include "bitops.h" +#include "event.h" #include "interrupt.h" #include "mainbus.h" #include "monitor.h" @@ -39,22 +40,18 @@ 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)); - // func, time は都度設定する - rx_event.SetName("Lance RX"); - tx_event.SetName("Lance TX"); - scheduler->RegistEvent(rx_event); - scheduler->RegistEvent(tx_event); + auto evman = GetEventManager(); + rx_event = evman->Regist(this, NULL, "Lance RX"); + tx_event = evman->Regist(this, NULL, "Lance TX"); return true; } @@ -370,7 +367,7 @@ LanceDevice::MonitorReg(TextScreen& scre int x, int y, uint32 data, const char * const *names) { for (int i = 0; i < 8; i++) { - bool b = data & (1 << (7 - i)); + bool b = data & (1U << (7 - i)); screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]); } } @@ -604,35 +601,32 @@ LanceDevice::ChipInit() uint32 rdrp = initblock[8] | (initblock[9] << 16); rmd_base = rdrp & 0xfffffc; int rlen = rdrp >> 29; - rmd_num = (1 << rlen); + rmd_num = (1U << rlen); uint32 tdrp = initblock[10] | (initblock[11] << 16); tmd_base = tdrp & 0xfffffc; int tlen = tdrp >> 29; - tmd_num = (1 << tlen); + tmd_num = (1U << 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 本当はいろいろ時間がかかりそうなはずだが // 初期化完了 @@ -728,7 +722,7 @@ LanceDevice::ChangeInterrupt() // - 所有できない場合、TDMD オンなら即、 // オフなら 1.6ms 待ってから再び TXIDLE へ。 void -LanceDevice::TXIdle(Event& ev) +LanceDevice::TXIdle(Event *ev) { tx_phase = TXPhase::IDLE; @@ -877,7 +871,7 @@ LanceDevice::TXCopy() // ただし ENP でなければアンダーフローによるパケット送信なのでフラグ処理。 // その後 TXNEXT フェーズへ。 void -LanceDevice::TXSend(Event& ev) +LanceDevice::TXSend(Event *ev) { tx_phase = TXPhase::SEND; @@ -914,7 +908,7 @@ LanceDevice::TXSend(Event& ev) // TXNEXT フェーズ。次のディスクリプタを指して TXIDLE へ。 void -LanceDevice::TXNext(Event& ev) +LanceDevice::TXNext(Event *ev) { tx_phase = TXPhase::NEXT; @@ -935,19 +929,19 @@ LanceDevice::TXNext(Event& ev) void LanceDevice::ChangePhase(TXPhase new_phase, uint64 time) { - tx_event.time = time; + tx_event->time = time; switch (new_phase) { case TXPhase::STOP: scheduler->StopEvent(tx_event); return; case TXPhase::IDLE: - tx_event.func = ToEventCallback(&LanceDevice::TXIdle); + tx_event->func = ToEventCallback(&LanceDevice::TXIdle); break; case TXPhase::SEND: - tx_event.func = ToEventCallback(&LanceDevice::TXSend); + tx_event->func = ToEventCallback(&LanceDevice::TXSend); break; case TXPhase::NEXT: - tx_event.func = ToEventCallback(&LanceDevice::TXNext); + tx_event->func = ToEventCallback(&LanceDevice::TXNext); break; default: assertmsg(false, "phase %u", (uint)new_phase); @@ -993,7 +987,7 @@ LanceDevice::RxMessage(MessageID msgid, // RXIDLE 受信アイドルフェーズ。 // (最初の)ディスクリプタを所有できるかポーリングする。 void -LanceDevice::RXIdle(Event& ev) +LanceDevice::RXIdle(Event *ev) { rx_phase = RXPhase::IDLE; @@ -1137,7 +1131,7 @@ LanceDevice::RXCopy() // - 次のディスクリプタが所有できれば引き続き書き出すため RXCOPY へ。 // - 次のディスクリプタが所有できなければエラーにして RXIDLE へ。 void -LanceDevice::RXNext(Event& ev) +LanceDevice::RXNext(Event *ev) { rx_phase = RXPhase::NEXT; @@ -1207,6 +1201,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 への遷移も必ず起こす必要がある。 @@ -1214,16 +1256,16 @@ LanceDevice::RXMiss() void LanceDevice::ChangePhase(RXPhase new_phase, uint64 time) { - rx_event.time = time; + rx_event->time = time; switch (new_phase) { case RXPhase::STOP: scheduler->StopEvent(rx_event); return; case RXPhase::IDLE: - rx_event.func = ToEventCallback(&LanceDevice::RXIdle); + rx_event->func = ToEventCallback(&LanceDevice::RXIdle); break; case RXPhase::NEXT: - rx_event.func = ToEventCallback(&LanceDevice::RXNext); + rx_event->func = ToEventCallback(&LanceDevice::RXNext); break; default: assertmsg(false, "phase %u", (uint)new_phase);