--- nono/vm/lance.cpp 2026/04/29 17:05:24 1.1.1.15 +++ nono/vm/lance.cpp 2026/04/29 17:05:59 1.1.1.21 @@ -10,8 +10,10 @@ #include "lance.h" #include "bitops.h" +#include "event.h" #include "interrupt.h" #include "mainbus.h" +#include "monitor.h" #include "scheduler.h" #include "subram.h" @@ -22,15 +24,10 @@ LanceDevice::LanceDevice() SetName("Lance"); ClearAlias(); AddAlias("Lance"); - AddAlias("Ethernet"); - // func, time は都度設定する - rx_event.Regist("Lance RX"); - tx_event.Regist("Lance TX"); - - monitor.func = ToMonitorCallback(&LanceDevice::MonitorUpdate); - monitor.SetSize(80, 34); - monitor.Regist(ID_MONITOR_LANCE); + monitor = gMonitorManager->Regist(ID_MONITOR_LANCE, this); + monitor->SetCallback(&LanceDevice::MonitorScreen); + monitor->SetSize(80, 34); } // デストラクタ @@ -42,17 +39,19 @@ 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)); + auto evman = GetEventManager(); + rx_event = evman->Regist(this, NULL, "Lance RX"); + tx_event = evman->Regist(this, NULL, "Lance TX"); + return true; } @@ -65,7 +64,7 @@ LanceDevice::ResetHard(bool poweron) } busdata -LanceDevice::Read(uint32 offset) +LanceDevice::ReadPort(uint32 offset) { busdata data; @@ -75,20 +74,21 @@ LanceDevice::Read(uint32 offset) break; case 1: // RAP data = reg.rap; - putlog(2, "RAP -> %d", reg.rap); + putlog(2, "RAP -> %u", reg.rap); break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); data = 0xffff; break; } // XXX wait? + data |= BusData::Size2; return data; } busdata -LanceDevice::Write(uint32 offset, uint32 data) +LanceDevice::WritePort(uint32 offset, uint32 data) { switch (offset) { case 0: // RDP @@ -98,16 +98,17 @@ LanceDevice::Write(uint32 offset, uint32 reg.rap = data & 3; break; default: - VMPANIC("corrupted offset=%d", offset); + VMPANIC("corrupted offset=%u", offset); break; } + busdata r = BusData::Size2; // XXX wait? - return 0; + return r; } busdata -LanceDevice::Peek(uint32 offset) +LanceDevice::PeekPort(uint32 offset) { switch (offset) { case 0: // RDP @@ -135,7 +136,7 @@ LanceDevice::Peek(uint32 offset) } void -LanceDevice::MonitorUpdate(Monitor *, TextScreen& screen) +LanceDevice::MonitorScreen(Monitor *, TextScreen& screen) { /* CSR0: $1111 ERR BABL CERR MISS MERR RINT TINT IDON IADR:$123456 @@ -209,13 +210,13 @@ LADRF:$fedcba98'76543210 TDRP: // RDRP uint32 rdrp = initblock[8] | (initblock[9] << 16); - screen.Print(31, y, "RDRP:$%08x (RDRA=$%06x entries=%d)", + screen.Print(31, y, "RDRP:$%08x (RDRA=$%06x entries=%u)", rdrp, rmd_base, rmd_num); y++; // TDRP uint32 tdrp = initblock[10] | (initblock[11] << 16); - screen.Print(31, y, "TDRP:$%08x (TDRA=$%06x entries=%d)", + screen.Print(31, y, "TDRP:$%08x (TDRA=$%06x entries=%u)", tdrp, tmd_base, tmd_num); y++; y++; @@ -232,7 +233,8 @@ LADRF:$fedcba98'76543210 TDRP: rmd[j] = PeekMem(rmd_addr + j * 2); } x = 6; - screen.Print(x, y, "Current %02x", rmd_cur); x += 11; + screen.Print(x, y, "Current %02x", rmd_cur); + x += 11; MonitorBit(rmd[1], AM7990::RMD1_OWN, rmd1_names[0]); MonitorBit(rmd[1], AM7990::RMD1_ERR, rmd1_names[1]); // 発生し得ないので省略 RMD1_FRAM rmd1_names[2] @@ -303,7 +305,8 @@ LADRF:$fedcba98'76543210 TDRP: } // MORE, ONE, DEF と LCOL, LCAR, RTRY, TDR は発生し得ないので省略 x = 6; - screen.Print(x, y, "Current %02x ", tmd_cur); x += 11; + screen.Print(x, y, "Current %02x ", tmd_cur); + x += 11; MonitorBit(tmd[1], AM7990::TMD1_OWN, tmd1_names[0]); MonitorBit(tmd[1], AM7990::TMD1_ERR, tmd1_names[1]); MonitorBit(tmd[1], AM7990::TMD1_STP, tmd1_names[6]); @@ -347,7 +350,7 @@ LADRF:$fedcba98'76543210 TDRP: (-(int16)tmd[2]) & 0xfff); // 画面内に収まらない場合は折り返し。 - // 収まる場合はこのまま rmd_num を超えればループを抜ける。 + // 収まる場合はこのまま tmd_num を超えればループを抜ける。 ts++; if (tmd_num > 24 && ts >= tmd_num) { ts = 0; @@ -363,7 +366,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]); } } @@ -387,33 +390,33 @@ LanceDevice::ReadData() case 1: if (reg.IsSTOP()) { data = reg.iadr & 0xffff; - putlog(2, "CSR%d -> $%04x", reg.rap, data); + putlog(2, "CSR%u -> $%04x", reg.rap, data); } else { data = 0xcccc & AM7990::CSR1_MASK; - putlog(2, "CSR%d -> $%04x (indefinate read)", reg.rap, data); + putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data); } break; case 2: if (reg.IsSTOP()) { data = reg.iadr >> 16; - putlog(2, "CSR%d -> $%04x", reg.rap, data); + putlog(2, "CSR%u -> $%04x", reg.rap, data); } else { data = 0xcccc & AM7990::CSR2_MASK; - putlog(2, "CSR%d -> $%04x (indefinate read)", reg.rap, data); + putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data); } break; case 3: if (reg.IsSTOP()) { data = reg.csr3; const std::string name = CSR3ToString(data); - putlog(2, "CSR%d -> $%04x<%s>", reg.rap, data, name.c_str()); + putlog(2, "CSR%u -> $%04x<%s>", reg.rap, data, name.c_str()); } else { data = 0xcccc & AM7990::CSR3_MASK; - putlog(2, "CSR%d -> $%04x (indefinate read)", reg.rap, data); + putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data); } break; default: - VMPANIC("corrupted reg.rap=%d", reg.rap); + VMPANIC("corrupted reg.rap=%u", reg.rap); data = 0xffff; break; } @@ -499,11 +502,6 @@ LanceDevice::WriteData(uint32 data) if (reg.IsSTOP()) { reg.iadr = (reg.iadr & 0xff0000) | (data & AM7990::IADR_L_MASK); putlog(2, "IDAR(L)=$%06x", reg.iadr); - -#if 0 - // IADR 設定時にパフォーマンス測定用実時間表示 - scheduler->PutlogRealtime(); -#endif } break; @@ -526,7 +524,7 @@ LanceDevice::WriteData(uint32 data) break; default: - VMPANIC("corrupted reg.rap=%d", reg.rap); + VMPANIC("corrupted reg.rap=%u", reg.rap); } } @@ -544,40 +542,33 @@ LanceDevice::WriteData(uint32 data) // メモリアクセスは常にこの構成で、CSR3.BSWP はこの1ワードを SILO(FIFO) に // 書き込む/から読み出す順序を入れ替えるもの。 -// メモリから1ワード読み込む。paddr はワードアラインしていること。 -uint64 -LanceDevice::ReadMem(uint32 paddr) +// メモリから1ワード読み込む。addr はワードアラインしていること。 +uint32 +LanceDevice::ReadMem(uint32 addr) { - uint64 data; - - assertmsg((paddr & 1) == 0, "paddr=$%x", paddr); + assertmsg((addr & 1) == 0, "addr=$%x", addr); // XXX 所要クロックを考察すること - data = subram->Read16(paddr); - return data; + busdata data = subram->Read2(addr); + return data.Data(); } -// メモリに1ワード書き込む。paddr はワードアラインしていること。 -uint64 -LanceDevice::WriteMem(uint32 paddr, uint32 data) +// メモリに1ワード書き込む。addr はワードアラインしていること。 +void +LanceDevice::WriteMem(uint32 addr, uint32 data) { - assertmsg((paddr & 1) == 0, "paddr=$%x", paddr); + assertmsg((addr & 1) == 0, "addr=$%x", addr); // XXX 所要クロックを考察すること - subram->Write16(paddr, data); - return 0; + subram->Write2(addr, data); } // メモリ (3ポートSRAM) から1ワードピークする。バスエラーは起きない。 -uint64 -LanceDevice::PeekMem(uint32 paddr) +uint32 +LanceDevice::PeekMem(uint32 addr) const { - uint64 data; - - data = subram->Peek8(paddr) << 8; - data |= subram->Peek8(paddr + 1); - - return data; + busdata data = subram->Peek2(addr); + return data.Data(); } // INIT ビットによるチップ初期化。 @@ -596,7 +587,7 @@ LanceDevice::ChipInit() } if (0) { for (int i = 0; i < countof(initblock); i++) { - putlog(2, "initblock[%d] = $%04x", i, initblock[i]); + putlog(2, "initblock[%u] = $%04x", i, initblock[i]); } } @@ -604,35 +595,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 +716,7 @@ LanceDevice::ChangeInterrupt() // - 所有できない場合、TDMD オンなら即、 // オフなら 1.6ms 待ってから再び TXIDLE へ。 void -LanceDevice::TXIdle(Event& ev) +LanceDevice::TXIdle(Event *ev) { tx_phase = TXPhase::IDLE; @@ -779,79 +767,48 @@ LanceDevice::TXCopy() uint32 src = ((tmd1 & 0x00ff) << 16) | tmd0; int32 bcnt = -(int32)(int16)tmd2; - // copycnt は bcnt のうち実際にコピーするバイト数 - int32 copycnt; - if (tx_packet.length + bcnt > tx_packet.size()) { - // コピーするとバッファが溢れてしまう計算なら、溢れないように打ち切る。 - copycnt = tx_packet.size() - tx_packet.length; - } else { - // 全部コピーできる。 - copycnt = bcnt; - } - - // 送信パケットキュー上の書き込み中バッファに追記する - uint8 *dst = &tx_packet[tx_packet.length]; - tx_packet.length += copycnt; - // ここから、SubRAM からローカルの送信バッファにコピー // XXX バーストコピー未対応 - const uint32 srcend = src + bcnt; - const uint8 *dstend = dst + copycnt; + uint32 srcend = src + bcnt; // src が奇数アドレスから始まっている(そしてコピー可能な)場合 // (バッファを奇数アドレスから始めたりする奇特な人はいないと思うが) - if (__predict_false((src & 1) != 0) && dst < dstend) { + if (__predict_false((src & 1) != 0) && src < srcend) { uint16 data = ReadMem(src & ~1); + src++; if (reg.IsBSWP() == false) { - *dst++ = data >> 8; + tx_packet.Append(data >> 8); } else { - *dst++ = data & 0xff; + tx_packet.Append(data & 0xff); } - src++; } // 残り2バイト以上コピー可能な間 (ここで src はワード境界になっている) - const uint8 *dstend_even; - dstend_even = (const uint8 *)((uintptr_t)dstend & ~(uintptr_t)1); - while (dst < dstend_even) { + for (; src + 1 < srcend; ) { uint16 data = ReadMem(src); + src += 2; if (reg.IsBSWP() == false) { - *dst++ = data & 0xff; - *dst++ = data >> 8; + tx_packet.Append(data & 0xff); + tx_packet.Append(data >> 8); } else { - *dst++ = data >> 8; - *dst++ = data & 0xff; + tx_packet.Append(data >> 8); + tx_packet.Append(data & 0xff); } - src += 2; } // src が奇数アドレスで終わっている(そしてコピー可能な)場合 - if (__predict_false(dst < dstend)) { + if (src < srcend) { uint16 data = ReadMem(src); if (reg.IsBSWP() == false) { - *dst++ = data & 0xff; + tx_packet.Append(data & 0xff); } else { - *dst++ = data >> 8; + tx_packet.Append(data >> 8); } - src += 2; - } - - // tx_packet が一杯になったら後はディスクリプタが終わるまで SubRAM から - // 読み捨てる。tx_packet の長さに上限があるのはこっち(エミュレータ)の - // 都合であって LANCE はディスクリプタが終わるまで延々読み込んでは出力を - // 続けるようだ。ここでは同じだけ読み込むところ、それにかかる時間を求める - // ところを再現する。tx_packet がイーサネットフレーム長を超過していると - // この後 SEND フェーズで BABBLE ビットを立てるところも再現する。 - // 正確には 1519バイト目の送信で立てるのだが、通常は起きない上に面倒 - // なので省略。1519バイト以上のパケットをホストに流すこともしない。 - while (src < srcend) { - ReadMem(src); - src += 2; } // メモリからの転送にかかった時間をざっくり計算 XXX まだ適当 // そのウェイト後に指定のフェーズへ。 - uint64 t = 700 * bcnt / 16; + uint64 t = nsec_to_tsec(700 * bcnt / 16); // ここが ENP なら、送信のため TXSEND フェーズへ if ((tmd1 & AM7990::TMD1_ENP)) { @@ -877,11 +834,11 @@ LanceDevice::TXCopy() // ただし ENP でなければアンダーフローによるパケット送信なのでフラグ処理。 // その後 TXNEXT フェーズへ。 void -LanceDevice::TXSend(Event& ev) +LanceDevice::TXSend(Event *ev) { tx_phase = TXPhase::SEND; - if (__predict_false(tx_packet.length > 1518)) { + if (__predict_false(tx_packet.Length() > 1518)) { // 本当は 1519バイト目を送ったところで BABL を立てるのだが // まず起きない上に面倒なので、ここで行う。 SetInterrupt(AM7990::CSR0_BABL); @@ -914,7 +871,7 @@ LanceDevice::TXSend(Event& ev) // TXNEXT フェーズ。次のディスクリプタを指して TXIDLE へ。 void -LanceDevice::TXNext(Event& ev) +LanceDevice::TXNext(Event *ev) { tx_phase = TXPhase::NEXT; @@ -935,22 +892,22 @@ 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->SetCallback(&LanceDevice::TXIdle); break; case TXPhase::SEND: - tx_event.func = ToEventCallback(&LanceDevice::TXSend); + tx_event->SetCallback(&LanceDevice::TXSend); break; case TXPhase::NEXT: - tx_event.func = ToEventCallback(&LanceDevice::TXNext); + tx_event->SetCallback(&LanceDevice::TXNext); break; default: - assertmsg(false, "phase %d", (int)new_phase); + assertmsg(false, "phase %u", (uint)new_phase); } scheduler->RestartEvent(tx_event); } @@ -993,11 +950,11 @@ LanceDevice::RxMessage(MessageID msgid, // RXIDLE 受信アイドルフェーズ。 // (最初の)ディスクリプタを所有できるかポーリングする。 void -LanceDevice::RXIdle(Event& ev) +LanceDevice::RXIdle(Event *ev) { rx_phase = RXPhase::IDLE; - putlog(3, "%s[%d]", __func__, rmd_cur); + putlog(3, "%s[%u]", __func__, rmd_cur); // RMD1 を読み込む if ((int32)rmd1_ahead >= 0) { @@ -1042,7 +999,7 @@ LanceDevice::RXCopy() { rx_phase = RXPhase::COPY; - putlog(1, "%s[%d]", __func__, rmd_cur); + putlog(1, "%s[%u]", __func__, rmd_cur); // RMD0, RMD2 は受信することが確定してから読み出す uint32 rmd_addr = rmd_base + rmd_cur * 8; @@ -1050,84 +1007,70 @@ LanceDevice::RXCopy() uint16 rmd2 = ReadMem(rmd_addr + 4); // アドレスと受信バッファのバイト数。 - uint32 bufdst = ((rmd1 & 0x00ff) << 16) | rmd0; - uint32 dst = bufdst; + uint32 dst = ((rmd1 & 0x00ff) << 16) | rmd0; // rmd2 は 2 の補数 int32 bcnt = -(int32)(int16)rmd2; - if (bcnt < rx_packet.length) { - putlog(1, "will be remain: %d < %d", bcnt, rx_packet.length); - } + // 今回のコピーバイト数。 + uint copycnt = std::min((uint)bcnt, rx_packet.GetRemain()); + uint32 dstend = dst + copycnt; - uint8 *src = &rx_packet[0]; - int remsize = rx_packet.length; + // ローカルの受信バッファからディスクリプタバッファにコピー。 + // XXX バーストコピー未対応 - if (bcnt > remsize) { - bcnt = remsize; + // dst が奇数アドレスから始まっている場合。 + // 奇数バイトには不定データが出るらしいがここでは 0 にする + if (__predict_false((dst & 1) != 0) && dst < dstend) { + uint16 data; + if (reg.IsBSWP() == false) { + data = rx_packet.Read() << 8; + } else { + data = rx_packet.Read(); + } + WriteMem(dst & ~1, data); + dst += 1; } - // コピー後の残りサイズにしておく - remsize -= bcnt; + // 残り2バイト以上コピー可能な間 (ここで dst はワード境界になっている)。 + for (; dst + 1 < dstend; ) { + uint16 data; + if (reg.IsBSWP() == false) { + data = rx_packet.Read(); + data |= rx_packet.Read() << 8; + } else { + data = rx_packet.Read() << 8; + data |= rx_packet.Read(); + } + WriteMem(dst, data); + dst += 2; + } - // ローカルの受信バッファからディスクリプタバッファにコピー - for (; bcnt > 0; ) { - // XXX バーストコピー未対応 + // dst が奇数アドレスで終わっている場合。 + // 奇数バイトには不定データが出るらしいがここでは 0 にする + if (dst < dstend) { uint16 data; - if (bcnt >= 2 && (dst & 1) == 0) { - // 2バイト以上残っててワード境界ならワードアクセス - if (reg.IsBSWP() == false) { - data = *src++; - data |= (*src++) << 8; - } else { - data = (*src++) << 8; - data |= *src++; - } - WriteMem(dst, data); - dst += 2; - bcnt -= 2; - } else if ((dst & 1) == 0) { - // 偶数アドレスへ1バイト - // 奇数バイトには不定データが出るらしいがここでは 0 にする - if (reg.IsBSWP() == false) { - data = *src++; - } else { - data = (*src++) << 8; - } - WriteMem(dst, data); - dst += 1; - bcnt -= 1; + if (reg.IsBSWP() == false) { + data = rx_packet.Read(); } else { - // 奇数アドレスへ1バイト - // 偶数バイトには不定データが出るらしいがここでは 0 にする - if (reg.IsBSWP() == false) { - data = (*src++) << 8; - } else { - data = *src++; - } - WriteMem(dst & ~1, data); - dst += 1; - bcnt -= 1; + data = rx_packet.Read() << 8; } + WriteMem(dst, data); } // 全部書き出せたらここが ENP - if (remsize == 0) { + if (rx_packet.GetRemain() == 0) { rmd1 |= AM7990::RMD1_ENP; // ENP なら MCNT を更新 - WriteMem(rmd_addr + 6, (dst - bufdst) & 0xfff); + WriteMem(rmd_addr + 6, copycnt & 0xfff); } else { rmd1 &= ~AM7990::RMD1_ENP; - putlog(1, "copy remain %d", remsize); - - // 前詰めにコピーする - memmove(&rx_packet[0], src, remsize); - rx_packet.length = remsize; + putlog(1, "copy remain %u", rx_packet.GetRemain()); } // メモリへの転送にかかった時間をざっくり計算 XXX まだ適当 // そのウェイト後に RXNEXT フェーズへ。 - uint64 t = 700 * (dst - bufdst) / 16; + uint64 t = nsec_to_tsec(700 * copycnt / 16); ChangePhase(RXPhase::NEXT, t); } @@ -1137,11 +1080,11 @@ LanceDevice::RXCopy() // - 次のディスクリプタが所有できれば引き続き書き出すため RXCOPY へ。 // - 次のディスクリプタが所有できなければエラーにして RXIDLE へ。 void -LanceDevice::RXNext(Event& ev) +LanceDevice::RXNext(Event *ev) { rx_phase = RXPhase::NEXT; - putlog(1, "%s[%d]", __func__, rmd_cur); + putlog(1, "%s[%u]", __func__, rmd_cur); bool is_chained = false; @@ -1207,6 +1150,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,19 +1205,19 @@ 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->SetCallback(&LanceDevice::RXIdle); break; case RXPhase::NEXT: - rx_event.func = ToEventCallback(&LanceDevice::RXNext); + rx_event->SetCallback(&LanceDevice::RXNext); break; default: - assertmsg(false, "phase %d", (int)new_phase); + assertmsg(false, "phase %u", (uint)new_phase); } scheduler->RestartEvent(rx_event); }