--- nono/vm/rtl8019as.cpp 2026/04/29 17:05:21 1.1.1.1 +++ nono/vm/rtl8019as.cpp 2026/04/29 17:05:29 1.1.1.3 @@ -43,26 +43,16 @@ #include "scheduler.h" // コンストラクタ -RTL8019ASDevice::RTL8019ASDevice(int n, int vector_) +RTL8019ASDevice::RTL8019ASDevice(uint n, int vector_) : inherited(OBJ_ETHERNET(n)) { - SetName(string_format("RTL8019AS#%d", n)); + SetName(string_format("RTL8019AS#%u", n)); ClearAlias(); - AddAlias(string_format("RTL8019AS%d", n)); - AddAlias(string_format("Eth%d", n)); + AddAlias(string_format("RTL8019AS%u", n)); + AddAlias(string_format("Eth%u", n)); intr_vector = vector_; - tx_event.func = ToEventCallback(&RTL8019ASDevice::TXEvent); - tx_event.Regist(string_format("RTL8019AS%d TX", n)); - rx_event.func = ToEventCallback(&RTL8019ASDevice::RXEvent); - rx_event.Regist(string_format("RTL8019AS%d RX", n)); - - txled_event.func = ToEventCallback(&RTL8019ASDevice::TXLedEvent); - txled_event.Regist(string_format("RTL8019AS%d TX LED", n)); - rxled_event.func = ToEventCallback(&RTL8019ASDevice::RXLedEvent); - rxled_event.Regist(string_format("RTL8019AS%d RX LED", n)); - monitor.func = ToMonitorCallback(&RTL8019ASDevice::MonitorUpdate); monitor.SetSize(71, 19); monitor.Regist(ID_MONITOR_RTL8019AS(n)); @@ -81,7 +71,7 @@ RTL8019ASDevice::Init() return false; } - int n = GetId() - OBJ_ETHERNET0; + uint n = GetId() - OBJ_ETHERNET0; // MAC アドレスを取得 macaddr_t macaddr; @@ -102,7 +92,21 @@ RTL8019ASDevice::Init() // ホストからの受信コールバックを登録 scheduler->ConnectMessage(MessageID::HOSTNET_RX(n), this, - ToMessageCallback(&RTL8019ASDevice::HostRxCallback)); + ToMessageCallback(&RTL8019ASDevice::RxMessage)); + + tx_event.func = ToEventCallback(&RTL8019ASDevice::TXEvent); + tx_event.SetName(string_format("RTL8019AS%u TX", n)); + rx_event.func = ToEventCallback(&RTL8019ASDevice::RXEvent); + rx_event.SetName(string_format("RTL8019AS%u RX", n)); + scheduler->RegistEvent(tx_event); + scheduler->RegistEvent(rx_event); + + txled_event.func = ToEventCallback(&RTL8019ASDevice::TXLedEvent); + txled_event.SetName(string_format("RTL8019AS%u TX LED", n)); + rxled_event.func = ToEventCallback(&RTL8019ASDevice::RXLedEvent); + rxled_event.SetName(string_format("RTL8019AS%u RX LED", n)); + scheduler->RegistEvent(txled_event); + scheduler->RegistEvent(rxled_event); return true; } @@ -207,97 +211,87 @@ RTL8019ASDevice::Decoder(uint32 addr) return addr & 0x3f; } -uint64 -RTL8019ASDevice::Read8(uint32 addr) +busdata +RTL8019ASDevice::Read(busaddr addr) { - uint32 offset = Decoder(addr); - uint32 data; - - if (offset < 0x10 * 2) { - if (offset % 2 == 0) { - uint32 rn = pagesel + offset / 2; + busdata data; + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (paddr & 1), reqsize); + uint32 offset = Decoder(paddr) >> 1; + + if (offset < 0x10) { + // レジスタ部は、上位にレジスタ、下位は $ff が読める。 + // ワードで読んでも上位にレジスタ、下位は $ff なので、 + // レジスタと $ff のバイト配置とも言えるかも。 + if ((paddr & 1) == 0) { + uint32 rn = pagesel + offset; data = ReadReg(rn); } else { - // 奇数番地はバスエラーではなく $ff が読める - putlog(4, "Reading $%06x", addr); data = 0xff; } - } else if (offset < 0x18 * 2) { - data = ReadDMA8(offset & 1); - } else { - putlog(1, "Reset"); - Reset(); - data = 0xff; - } - - return data; -} - -uint64 -RTL8019ASDevice::Read16(uint32 addr) -{ - uint32 offset = Decoder(addr); - uint32 data; - - if (offset < 0x10 * 2) { - uint32 rn = pagesel + offset / 2; - data = ReadReg(rn) << 8; - data |= 0xff; - } else if (offset < 0x18 * 2) { - data = ReadDMA16(); + data |= BusData::Size1; + } else if (offset < 0x18) { + // DMA 部。 + if (datasize == 1) { + data = ReadDMA8(paddr & 1); + data |= BusData::Size1; + } else { + data = ReadDMA16(); + data |= BusData::Size2; + } } else { + // リセットポート putlog(1, "Reset"); Reset(); - data = 0xffff; + data = 0xffff >> ((2 - datasize) * 8); + data |= busdata::Size(datasize); } return data; } -uint64 -RTL8019ASDevice::Write8(uint32 addr, uint32 data) +busdata +RTL8019ASDevice::Write(busaddr addr, uint32 data) { - uint32 offset = Decoder(addr); - - if (offset < 0x10 * 2) { - if (offset % 2 == 0) { - uint32 rn = pagesel + offset / 2; - return WriteReg(rn, data); + busdata r; + uint32 paddr = addr.Addr(); + uint32 reqsize = addr.GetSize(); + uint32 datasize = std::min(2 - (paddr & 1), reqsize); + uint32 offset = Decoder(paddr) >> 1; + + data >>= (reqsize - datasize) * 8; + + if (offset < 0x10) { + // レジスタ部は、上位がレジスタ、下位は無視される(バスエラーではない)。 + // ワードで書いても、上位がレジスタ、下位は無視されるので、 + // レジスタと N.C. のバイト配置とも言えるかも。 + if ((paddr & 1) == 0) { + uint32 rn = pagesel + offset; + WriteReg(rn, data); } else { - // 奇数番地はバスエラーにならない - putlog(4, "Writing $%06x <- $%02x", addr, data); - return 0; } - } else if (offset < 0x18 * 2) { - WriteDMA8(data); + r |= BusData::Size1; + } else if (offset < 0x18) { + // DMA 部。 + if (datasize == 1) { + WriteDMA8(data); + r |= BusData::Size1; + } else { + WriteDMA16(data); + r |= BusData::Size2; + } } else { putlog(1, "Reset"); Reset(); + r |= busdata::Size(datasize); } - return 0; -} - -uint64 -RTL8019ASDevice::Write16(uint32 addr, uint32 data) -{ - uint32 offset = Decoder(addr); - - if (offset < 0x10 * 2) { - uint32 rn = pagesel + offset / 2; - return WriteReg(rn, data >> 8); - } else if (offset < 0x18 * 2) { - WriteDMA16(data); - } else { - putlog(2, "Reset"); - Reset(); - } - - return 0; + return r; } -uint64 -RTL8019ASDevice::Peek8(uint32 addr) +busdata +RTL8019ASDevice::Peek1(uint32 addr) { uint32 offset = Decoder(addr); @@ -406,17 +400,14 @@ RTL8019ASDevice::MonitorUpdate(Monitor * MonitorReg(screen, x + 4, y, val, rsr_bits); y++; - screen.Puts(0, y, "PAR:"); - screen.Print(x, y, "%02x", par[0]); - for (int i = 1; i < 6; i++) { - screen.Print(x - 1 + i * 3, y, ":%02x", par[i]); - } + // MAC アドレスは PAR0 が左側 (ビッグエンディアンぽい感じ)。 + screen.Print(0, y, "PAR0-5: %s", par.ToString(':').c_str()); - screen.Puts(x + 21, y, "MAR:"); - screen.Print(x + 26, y, "%02x", mar[0]); - for (int i = 1; i < 8; i++) { - screen.Print(x + 25 + i * 3, y, ":%02x", mar[i]); - } + // マルチキャストフィルタは MAR0 が右側 (リトルエンディアンぽい感じ)。 + // MAR7-0: $00000000'00000000 + uint32 marH = (mar[7] << 24) | (mar[6] << 16) | (mar[5] << 8) | mar[4]; + uint32 marL = (mar[3] << 24) | (mar[2] << 16) | (mar[1] << 8) | mar[0]; + screen.Print(x + 23, y, "MAR7-0: $%08x'%08x", marH, marL); y++; y++; @@ -485,7 +476,7 @@ RTL8019ASDevice::MonitorUpdate(Monitor * "Program", "WriteEn", }; - screen.Print(x, y, "EEM=%d(%s)", eem, eem_str[eem]); + screen.Print(x, y, "EEM=%u(%s)", eem, eem_str[eem]); static const char * const verid_str[] = { "8019A/AS", @@ -493,7 +484,7 @@ RTL8019ASDevice::MonitorUpdate(Monitor * "?", "8019", }; - screen.Print(x + 16, y, "VID=%d(%s)", verid, verid_str[verid]); + screen.Print(x + 16, y, "VID=%u(%s)", verid, verid_str[verid]); static const char * const mediatype_str[] = { "10baseTAuto", @@ -501,7 +492,7 @@ RTL8019ASDevice::MonitorUpdate(Monitor * "10base5", "10base2", }; - screen.Print(x + 33, y, "PL=%d(%s)", mediatype, mediatype_str[mediatype]); + screen.Print(x + 33, y, "PL=%u(%s)", mediatype, mediatype_str[mediatype]); y++; // LED は、RTL8019AS の LED ピンではなく Nereid ボード上の LED で表す。 @@ -638,7 +629,7 @@ RTL8019ASDevice::ReadReg(uint32 rn) case RTL8019::CNTR2: { // 読み出しでリセットされる - int n = rn - RTL8019::CNTR0; + uint n = rn - RTL8019::CNTR0; data = PeekCNTR(n); error_counter[n] = 0; break; @@ -858,12 +849,12 @@ RTL8019ASDevice::ReadDMAlog(uint32 prev_ } if (__predict_false(remote_count == 0)) { - putlogn("DMA %d bytes transferred", remote_start_count); + putlogn("DMA %u bytes transferred", remote_start_count); } } // レジスタ書き込み (rn はページ番号込み) -uint32 +void RTL8019ASDevice::WriteReg(uint32 rn, uint32 data) { switch (rn) { @@ -872,106 +863,104 @@ RTL8019ASDevice::WriteReg(uint32 rn, uin case RTL8019::CR_2: case RTL8019::CR_3: WriteCR(data); - return 0; + break; case RTL8019::PSTART: WritePSTART(data); - return 0; + break; case RTL8019::PSTOP: WritePSTOP(data); - return 0; + break; case RTL8019::BNRY: WriteBNRY(data); - return 0; + break; case RTL8019::TPSR: WriteTPSR(data); - return 0; + break; case RTL8019::TBCR0: WriteTBCR0(data); - return 0; + break; case RTL8019::TBCR1: WriteTBCR1(data); - return 0; + break; case RTL8019::ISR: WriteISR(data); - return 0; + break; case RTL8019::RSAR0: WriteRSAR0(data); - return 0; + break; case RTL8019::RSAR1: WriteRSAR1(data); - return 0; + break; case RTL8019::RBCR0: WriteRBCR0(data); - return 0; + break; case RTL8019::RBCR1: WriteRBCR1(data); - return 0; + break; case RTL8019::RCR: WriteRCR(data); - return 0; + break; case RTL8019::TCR: WriteTCR(data); - return 0; + break; case RTL8019::DCR: WriteDCR(data); - return 0; + break; case RTL8019::IMR: WriteIMR(data); - return 0; + break; case RTL8019::PAR0 ... RTL8019::PAR5: WritePAR(rn - RTL8019::PAR0, data); - return 0; + break; case RTL8019::CURR: WriteCURR(data); - return 0; + break; case RTL8019::MAR0 ... RTL8019::MAR7: WriteMAR(rn - RTL8019::MAR0, data); - return 0; + break; case RTL8019::CR9346: Write9346CR(data); - return 0; + break; case RTL8019::CONFIG0: WriteCONFIG0(data); - return 0; + break; case RTL8019::CONFIG1: WriteCONFIG1(data); - return 0; + break; case RTL8019::CONFIG2: WriteCONFIG2(data); - return 0; + break; case RTL8019::CONFIG3: WriteCONFIG3(data); - return 0; + break; default: + putlog(0, "%s <- $%02x (NOT IMPLEMENTED)", + RegNameW(rn).c_str(), data); break; } - - putlog(0, "%s <- $%02x (NOT IMPLEMENTED)", - RegNameW(rn).c_str(), data); - return 0xff; } // CR レジスタ書き込み @@ -1035,7 +1024,7 @@ RTL8019ASDevice::WriteCR(uint32 data) } if (loglevel >= 2) { if (newstate != state) { - msg += string_format(" STP=%d", newstp); + msg += string_format(" STP=%u", newstp); } } @@ -1263,12 +1252,12 @@ RTL8019ASDevice::WriteIMR(uint32 data) // PAR0..5 レジスタ書き込み void -RTL8019ASDevice::WritePAR(int n, uint32 data) +RTL8019ASDevice::WritePAR(uint n, uint32 data) { par[n] = data; if (__predict_false(loglevel >= 3)) { - putlogn("PAR%d <- $%02x", n, data); + putlogn("PAR%u <- $%02x", n, data); } else { if (__predict_false(n == 5)) { putlog(2, "PAR <- %02x:%02x:%02x:%02x:%02x:%02x", @@ -1288,17 +1277,17 @@ RTL8019ASDevice::WriteCURR(uint32 data) // MAR0..7 レジスタ書き込み void -RTL8019ASDevice::WriteMAR(int n, uint32 data) +RTL8019ASDevice::WriteMAR(uint n, uint32 data) { mar[n] = data; if (__predict_false(loglevel >= 3)) { - putlogn("MAR%d <- $%02x", n, data); + putlogn("MAR%u <- $%02x", n, data); } else { if (__predict_false(n == 7)) { putlog(2, "MAR <- %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - mar[0], mar[1], mar[2], mar[3], - mar[4], mar[5], mar[6], mar[7]); + mar[7], mar[6], mar[5], mar[4], + mar[3], mar[2], mar[1], mar[0]); } } } @@ -1317,7 +1306,7 @@ RTL8019ASDevice::Write9346CR(uint32 data } if (eem == 1 || eem == 2) { - putlog(0, "9346CR <- $%02x EEM=%d (NOT IMPLEMENTED)", data, eem); + putlog(0, "9346CR <- $%02x EEM=%u (NOT IMPLEMENTED)", data, eem); return; } if ((data & 0x0f) != 0) { @@ -1431,7 +1420,7 @@ RTL8019ASDevice::WriteDMA8(uint32 data) } if (__predict_false(remote_count == 0)) { - putlog(2, "DMA %d bytes transferred", remote_start_count); + putlog(2, "DMA %u bytes transferred", remote_start_count); } } } @@ -1485,7 +1474,7 @@ RTL8019ASDevice::WriteDMA16(uint32 data) } if (__predict_false(remote_count == 0)) { - putlog(2, "DMA %d bytes transferred", remote_start_count); + putlog(2, "DMA %u bytes transferred", remote_start_count); } } } @@ -2039,9 +2028,21 @@ RTL8019ASDevice::ChangeState(State newst switch (newstate) { case State::Normal: + { + uint64 filter; + filter = ((uint64)mar[0] << 0) + | ((uint64)mar[1] << 8) + | ((uint64)mar[2] << 16) + | ((uint64)mar[3] << 24) + | ((uint64)mar[4] << 32) + | ((uint64)mar[5] << 40) + | ((uint64)mar[6] << 48) + | ((uint64)mar[7] << 56); hostnet->SetMyAddr(par); + hostnet->SetMCastFilter(filter); hostnet->EnableRx(true); break; + } case State::Stop: if (tx_in_progress || rx_packet.length != 0) { @@ -2097,13 +2098,13 @@ RTL8019ASDevice::Transmit() // TXP=1 で呼ばれて、ページごとにパケットにコピーする。 // TBCR で指定された長さを全部コピーしたらホストに送信。 void -RTL8019ASDevice::TXEvent(Event& event) +RTL8019ASDevice::TXEvent(Event& ev) { // 今回処理する分 - int count = std::min((uint)transmit_byte_count, 256u); + uint count = std::min((uint)transmit_byte_count, 256u); if (count == 0 && tx_packet.length != 0) { // 前回でコピーが完了していればここで送信。 - putlog(3, "TXEvent Send %d bytes", tx_packet.length); + putlog(3, "TXEvent Send %u bytes", tx_packet.length); hostnet->Tx(tx_packet); // 送信完了。 @@ -2124,7 +2125,7 @@ RTL8019ASDevice::TXEvent(Event& event) for (uint32 end = addr + count; addr < end; addr++) { tx_packet.Append((uint8)ReadRAM(addr)); } - putlog(4, "TXEvent Copy %d bytes at page $%02x", + putlog(4, "TXEvent Copy %u bytes at page $%02x", count, transmit_page_start_addr >> 8); // XXX TPSR, TBCR は更新されるのかどうか。 @@ -2139,9 +2140,9 @@ RTL8019ASDevice::TXEvent(Event& event) scheduler->StartEvent(tx_event); } -// パケット受信通知。HostNet から呼ばれる。 +// パケット受信通知。HostNet から (EthernetDevice 経由で) 呼ばれる。 void -RTL8019ASDevice::HostRxCallback(MessageID msgid, uint32 arg) +RTL8019ASDevice::RxMessage(MessageID msgid, uint32 arg) { // 受信イベントが止まっていれば動かす。 // 受信イベントがすでに動いていれば、1パケット受信完了後に @@ -2161,9 +2162,9 @@ RTL8019ASDevice::HostRxCallback(MessageI // len != 0, remain < len : 受信パケットのコピー (2ページ目以降) // len != 0, remain == 0 : 受信パケットのコピー完了直後。 void -RTL8019ASDevice::RXEvent(Event& event) +RTL8019ASDevice::RXEvent(Event& ev) { - int remain; + uint remain; if (rx_packet.length == 0) { // パケットが空の時に呼ばれたら、 @@ -2221,11 +2222,11 @@ RTL8019ASDevice::RXEvent(Event& event) if (remain == rx_packet.length) { // 初回処理 - RXHead(remain); + RXHead(); } - RXCopy(event, remain); + RXCopy(ev, remain); } else { - RXDone(event); + RXDone(ev); } return; @@ -2234,14 +2235,14 @@ RTL8019ASDevice::RXEvent(Event& event) // この場合も、ホストキューから次のパケットを引き取る作業は必要。 // XXX 間隔は適当 rx_packet.Clear(); - event.time = 1_usec; - scheduler->RestartEvent(event); + ev.time = 1_usec; + scheduler->RestartEvent(ev); } // パケット受信の初回。 // 4バイトの受信ヘッダをバッファに書き込む。 void -RTL8019ASDevice::RXHead(int remain) +RTL8019ASDevice::RXHead() { // 先に、このパケットの次のページ位置を求めて覚えておく。 next_page_addr = local_addr + 4 + rx_packet.length; @@ -2259,12 +2260,12 @@ RTL8019ASDevice::RXHead(int remain) // 1ページ埋めるかパケットをコピーし終えたら次へ。 // (初回もヘッダ書き込みに続いて呼ばれる) void -RTL8019ASDevice::RXCopy(Event& event, int remain) +RTL8019ASDevice::RXCopy(Event& ev, uint remain) { // パケットをこのページにコピー。 // 今回処理する分はパケットの残りとページの残りの小さいほう。 - int count = std::min(remain, 0x100 - (local_addr & 0xff)); - putlog(4, "RXEvent Copy %d bytes at page $%02x", count, local_addr >> 8); + uint count = std::min(remain, 0x100U - (local_addr & 0xff)); + putlog(4, "RXEvent Copy %u bytes at page $%02x", count, local_addr >> 8); for (uint32 end = local_addr + count; local_addr < end; ) { WriteRAM(local_addr++, rx_packet.Read()); } @@ -2283,8 +2284,8 @@ RTL8019ASDevice::RXCopy(Event& event, in // 転送にかかった時間を模しておく。 // 時間は適当。10Mbps なので 1バイトあたり 1usec とする。 - event.time = count * 1_usec; - scheduler->RestartEvent(event); + ev.time = count * 1_usec; + scheduler->RestartEvent(ev); } // 受信パケットをバッファにコピーし終えた次のターンで呼ばれる。 @@ -2292,10 +2293,10 @@ RTL8019ASDevice::RXCopy(Event& event, in // ストップ待ちでなければ再び RXEvent() イベントを呼び、 // 次パケットの処理を継続する。 void -RTL8019ASDevice::RXDone(Event& event) +RTL8019ASDevice::RXDone(Event& ev) { // 前回でコピーが完了していればここで通知。 - putlog(3, "RXDone Received %d bytes", rx_packet.length); + putlog(3, "RXDone Received %u bytes", rx_packet.length); // 受信ヘッダに書き込む前に RSR を更新 rsr |= RTL8019::RSR_PRX; @@ -2344,49 +2345,49 @@ RTL8019ASDevice::RXDone(Event& event) // (rx_packet.length == 0 で RXEvent() を呼ぶとパケット受信となる) // どのくらいか待つ? 値は適当 - event.time = 100_usec; - scheduler->RestartEvent(event); + ev.time = 100_usec; + scheduler->RestartEvent(ev); } } // 送信 LED イベント void -RTL8019ASDevice::TXLedEvent(Event& event) +RTL8019ASDevice::TXLedEvent(Event& ev) { if (tx_led == false) { // 消灯中だったら、次は 6msec 点灯 tx_led = true; - event.time = 6_msec; - scheduler->RestartEvent(event); + ev.time = 6_msec; + scheduler->RestartEvent(ev); } else { // 点灯中だったら // - 送信中なら次は 100msec 消灯 // - 送信中でなければここで終わり if (tx_in_progress) { tx_led = false; - event.time = 100_msec; - scheduler->RestartEvent(event); + ev.time = 100_msec; + scheduler->RestartEvent(ev); } } } // 受信 LED イベント void -RTL8019ASDevice::RXLedEvent(Event& event) +RTL8019ASDevice::RXLedEvent(Event& ev) { if (rx_led == false) { // 消灯中だったら、次は 6msec 点灯 rx_led = true; - event.time = 6_msec; - scheduler->RestartEvent(event); + ev.time = 6_msec; + scheduler->RestartEvent(ev); } else { // 点灯中だったら // - 受信中なら次は 100msec 消灯 // - 受信中でなければここで終わり if (rx_packet.length != 0) { rx_led = false; - event.time = 100_msec; - scheduler->RestartEvent(event); + ev.time = 100_msec; + scheduler->RestartEvent(ev); } } } @@ -2405,11 +2406,8 @@ void RTL8019ASDevice::ChangeInterrupt() { if (irq_enable) { - if ((intr_stat & intr_mask) != 0) { - interrupt->AssertINT(this); - } else { - interrupt->NegateINT(this); - } + bool irq = ((intr_stat & intr_mask) != 0); + interrupt->ChangeINT(this, irq); } else { // IRQEN が 0 だと出力がハイインピーダンスになる。 interrupt->AssertINT(this); @@ -2417,7 +2415,7 @@ RTL8019ASDevice::ChangeInterrupt() } // 割り込みアクノリッジ -int +busdata RTL8019ASDevice::InterruptAcknowledge() { return intr_vector;