--- nono/vm/lance.cpp 2026/04/29 17:05:10 1.1.1.11 +++ nono/vm/lance.cpp 2026/04/29 17:05:32 1.1.1.17 @@ -10,27 +10,24 @@ #include "lance.h" #include "bitops.h" -#include "bus.h" -#include "config.h" #include "interrupt.h" +#include "mainbus.h" +#include "monitor.h" #include "scheduler.h" -#include "zram.h" +#include "subram.h" // コンストラクタ LanceDevice::LanceDevice() - : inherited("Lance") + : inherited(OBJ_ETHERNET(0)) { + SetName("Lance"); + ClearAlias(); + AddAlias("Lance"); AddAlias("Ethernet"); - devaddr = 0xf1000000; - - // 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->func = ToMonitorCallback(&LanceDevice::MonitorUpdate); + monitor->SetSize(80, 34); } // デストラクタ @@ -38,35 +35,26 @@ LanceDevice::~LanceDevice() { } +// 初期化 bool LanceDevice::Init() { - // ホストからの受信コールバックを登録 - gScheduler->ConnectMessage(MessageID::HOSTNET_RX, this, - ToMessageCallback(&LanceDevice::HostRxCallback)); + if (inherited::Init() == false) { + return false; + } - const ConfigItem& item = gConfig->Find("ethernet-macaddr"); - const std::string& config_macaddr = item.AsString(); - if (config_macaddr == "rom") { - // ROM に書いてあるのを使うので、ここでは何もしなくていい - } else { - if (config_macaddr == "auto") { - // 自動生成 - // すでに記録されていれば使う。なければ生成して記録したい - if (0) { - } else { - macaddr.Generate(); - } - } else { - // ユーザ指定 - if (macaddr.FromString(config_macaddr) == false) { - item.Err("invalid MAC address"); - return false; - } - } + interrupt = GetInterruptDevice(); + subram = GetSubRAMDevice(); - putmsg(1, "macaddr=%s", macaddr.ToString(':').c_str()); - } + // ホストからの受信コールバックを登録 + 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); return true; } @@ -79,41 +67,52 @@ LanceDevice::ResetHard(bool poweron) ChipStop(); } -uint64 -LanceDevice::Read(uint32 offset) +busdata +LanceDevice::ReadPort(uint32 offset) { - uint32 data; + busdata data; switch (offset) { case 0: // RDP data = ReadData(); - return data; + break; case 1: // RAP data = reg.rap; - putlog(2, "RAP -> %d", reg.rap); - return data; + putlog(2, "RAP -> %u", reg.rap); + break; default: - __unreachable(); + VMPANIC("corrupted offset=%u", offset); + data = 0xffff; + break; } + + // XXX wait? + data |= BusData::Size2; + return data; } -uint64 -LanceDevice::Write(uint32 offset, uint32 data) +busdata +LanceDevice::WritePort(uint32 offset, uint32 data) { switch (offset) { case 0: // RDP WriteData(data); - return 0; + break; case 1: // RAP reg.rap = data & 3; - return 0; + break; default: - __unreachable(); + VMPANIC("corrupted offset=%u", offset); + break; } + + busdata r = BusData::Size2; + // XXX wait? + return r; } -uint64 -LanceDevice::Peek(uint32 offset) +busdata +LanceDevice::PeekPort(uint32 offset) { switch (offset) { case 0: // RDP @@ -129,14 +128,15 @@ LanceDevice::Peek(uint32 offset) case 3: return reg.csr3; default: - __unreachable(); + break; } break; case 1: // RAP return reg.rap; default: - __unreachable(); + break; } + return 0xff; } void @@ -147,8 +147,8 @@ CSR0: $1111 ERR BABL CERR MISS MERR RIN CSR3:$0004 BSWP ACON BCON MODE: $0000 PROM INTL DRTY COLL DTCR LOOP DTX DRX -PADR: 00:11:22:33:44:55 RDRP: $12345678 (RDRA=$123456 entries=32) -LADRF:$12345678_12345678 TDRP: +PADR: 00:11:22:33:44:55 RDRP: $12345678 (RDRA=$123456 entries=32) +LADRF:$fedcba98'76543210 TDRP: Current 00 OWN ERR OFLO CRC BUFF STP ENP BCNT=$123 MCNT=$123 buf=$123456 01234567890123456789012345678901234567890 00 @@ -206,8 +206,7 @@ LADRF:$12345678_12345678 TDRP: initblock[1] & 0xff, initblock[1] >> 8, initblock[2] & 0xff, initblock[2] >> 8, initblock[3] & 0xff, initblock[3] >> 8); - // XXX LADRF のバイト順未検証 - screen.Print(0, y + 1, "LADRF:$%04x%04x_%04x%04x", + screen.Print(0, y + 1, "LADRF:$%04x%04x'%04x%04x", initblock[7], initblock[6], initblock[5], @@ -215,13 +214,13 @@ LADRF:$12345678_12345678 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++; @@ -238,7 +237,8 @@ LADRF:$12345678_12345678 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] @@ -309,7 +309,8 @@ LADRF:$12345678_12345678 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]); @@ -353,7 +354,7 @@ LADRF:$12345678_12345678 TDRP: (-(int16)tmd[2]) & 0xfff); // 画面内に収まらない場合は折り返し。 - // 収まる場合はこのまま rmd_num を超えればループを抜ける。 + // 収まる場合はこのまま tmd_num を超えればループを抜ける。 ts++; if (tmd_num > 24 && ts >= tmd_num) { ts = 0; @@ -393,33 +394,35 @@ 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 (不定読み出し)", 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 (不定読み出し)", 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 (不定読み出し)", reg.rap, data); + putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data); } break; default: - __unreachable(); + VMPANIC("corrupted reg.rap=%u", reg.rap); + data = 0xffff; + break; } return data; } @@ -506,7 +509,7 @@ LanceDevice::WriteData(uint32 data) #if 0 // IADR 設定時にパフォーマンス測定用実時間表示 - gScheduler->PutlogRealtime(); + scheduler->PutlogRealtime(); #endif } break; @@ -530,66 +533,54 @@ LanceDevice::WriteData(uint32 data) break; default: - __unreachable(); + VMPANIC("corrupted reg.rap=%u", reg.rap); } } // メモリアクセスについて。 // LANCE(AM7990) から見たメモリは、メインメモリではなく 3ポートSRAM -// (ここでは ZRAM デバイス)。 -// LANCE のメモリバスは 16bit で、DAL15..8 が ZRAM の偶数アドレス、 -// DAL7..0 が ZRAM の奇数アドレスに接続されている。 +// (ここでは SubRAM デバイス)。 +// LANCE のメモリバスは 16bit で、DAL15..8 が SubRAM の偶数アドレス、 +// DAL7..0 が SubRAM の奇数アドレスに接続されている。 // -// LANCE | DAL15..DAL8 | DAL7..DAL0 -// ------+-------------+------------ -// ZRAM | +0 byte | +1 byte -// | +2 byte | +3 byte +// LANCE | DAL15..DAL8 | DAL7..DAL0 +// -------+-------------+------------ +// SubRAM | +0 byte | +1 byte +// | +2 byte | +3 byte // // メモリアクセスは常にこの構成で、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 = gZRAM->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 所要クロックを考察すること - gZRAM->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; - - // XXX なんでここ gZRAM->Peek() じゃないんだっけ? - - paddr &= 0x1ffff; - paddr += 0x71000000; // XXX 定数にしたほうがいい - - data = vm_phys_peek_8(paddr) << 8; - data |= vm_phys_peek_8(paddr + 1); - return data; + busdata data = subram->Peek2(addr); + return data.Data(); } // INIT ビットによるチップ初期化。 -// ロック状態で呼ばれる。 void LanceDevice::ChipInit() { @@ -605,7 +596,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]); } } @@ -627,8 +618,20 @@ LanceDevice::ChipInit() padr[4] = initblock[3] & 0xff; padr[5] = 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)); // XXX 本当はいろいろ時間がかかりそうなはずだが @@ -637,11 +640,10 @@ LanceDevice::ChipInit() } // STRT ビットによるスタート。 -// ロック状態で呼ばれる。 void LanceDevice::ChipStart() { - putlog(1, "スタート"); + putlog(1, "Start"); // STRT を書き込むと STOP はクリア reg.csr0 |= AM7990::CSR0_STRT; @@ -676,14 +678,14 @@ LanceDevice::ChipStart() // STOP ビットによるチップリセット。 // ハードリセットもここに来る。 -// ロック状態で呼ばれる。 void LanceDevice::ChipStop() { - putlog(1, "リセット"); + putlog(1, "Reset"); // STOPセットで CSR0 は STOP セット、他は全クリア reg.csr0 = AM7990::CSR0_STOP; + ChangeInterrupt(); // CSR1, 2 は不定 // CSR3 はクリア reg.csr3 = 0; @@ -716,11 +718,8 @@ LanceDevice::SetInterrupt(uint32 bit) void LanceDevice::ChangeInterrupt() { - if (reg.IsINTR() && (reg.csr0 & AM7990::CSR0_INEA)) { - gInterrupt->AssertINT(this); - } else { - gInterrupt->NegateINT(this); - } + bool irq = (reg.IsINTR() && (reg.csr0 & AM7990::CSR0_INEA)); + interrupt->ChangeINT(this, irq); } // TXIDLE 送信アイドルフェーズ。 @@ -729,7 +728,7 @@ LanceDevice::ChangeInterrupt() // - 所有できない場合、TDMD オンなら即、 // オフなら 1.6ms 待ってから再び TXIDLE へ。 void -LanceDevice::TXIdle(Event& event) +LanceDevice::TXIdle(Event& ev) { tx_phase = TXPhase::IDLE; @@ -794,7 +793,7 @@ LanceDevice::TXCopy() uint8 *dst = &tx_packet[tx_packet.length]; tx_packet.length += copycnt; - // ここから、ZRAM からローカルの送信バッファにコピー + // ここから、SubRAM からローカルの送信バッファにコピー // XXX バーストコピー未対応 const uint32 srcend = src + bcnt; const uint8 *dstend = dst + copycnt; @@ -837,7 +836,7 @@ LanceDevice::TXCopy() src += 2; } - // tx_packet が一杯になったら後はディスクリプタが終わるまで ZRAM から + // tx_packet が一杯になったら後はディスクリプタが終わるまで SubRAM から // 読み捨てる。tx_packet の長さに上限があるのはこっち(エミュレータ)の // 都合であって LANCE はディスクリプタが終わるまで延々読み込んでは出力を // 続けるようだ。ここでは同じだけ読み込むところ、それにかかる時間を求める @@ -878,7 +877,7 @@ LanceDevice::TXCopy() // ただし ENP でなければアンダーフローによるパケット送信なのでフラグ処理。 // その後 TXNEXT フェーズへ。 void -LanceDevice::TXSend(Event& event) +LanceDevice::TXSend(Event& ev) { tx_phase = TXPhase::SEND; @@ -915,7 +914,7 @@ LanceDevice::TXSend(Event& event) // TXNEXT フェーズ。次のディスクリプタを指して TXIDLE へ。 void -LanceDevice::TXNext(Event& event) +LanceDevice::TXNext(Event& ev) { tx_phase = TXPhase::NEXT; @@ -939,7 +938,7 @@ LanceDevice::ChangePhase(TXPhase new_pha tx_event.time = time; switch (new_phase) { case TXPhase::STOP: - gScheduler->StopEvent(tx_event); + scheduler->StopEvent(tx_event); return; case TXPhase::IDLE: tx_event.func = ToEventCallback(&LanceDevice::TXIdle); @@ -951,9 +950,9 @@ LanceDevice::ChangePhase(TXPhase new_pha tx_event.func = ToEventCallback(&LanceDevice::TXNext); break; default: - assertmsg(false, "phase %d", (int)new_phase); + assertmsg(false, "phase %u", (uint)new_phase); } - gScheduler->RestartEvent(tx_event); + scheduler->RestartEvent(tx_event); } // 受信フェーズ遷移図 @@ -962,7 +961,7 @@ LanceDevice::ChangePhase(TXPhase new_pha // | RXSTOP |<- - - (CSR0.STOP 書き込み / リセット) // +--------+ // : -// : +‥‥‥+ <‥‥ HostRxCallback (パケット受信) +// : +‥‥‥+ <‥‥ RxMessage (パケット受信) // v v : // +-------------+ : // +‥‥‥>| RXIDLE |‥‥+ Idle @@ -980,9 +979,9 @@ LanceDevice::ChangePhase(TXPhase new_pha // | RXCOPY | 関数呼び出し ----> // +-----------+ イベントによる遷移 ‥‥> -// パケット受信通知。HostNet から呼ばれる。 +// パケット受信通知。HostNet から (EthernetDevice 経由で) 呼ばれる。 void -LanceDevice::HostRxCallback(MessageID msgid, uint32 arg) +LanceDevice::RxMessage(MessageID msgid, uint32 arg) { // RXIDLE ポーリングのウェイト中ならすぐに始める。 // そうでないときは RXIDLE に戻ったところで処理される。 @@ -994,11 +993,11 @@ LanceDevice::HostRxCallback(MessageID ms // RXIDLE 受信アイドルフェーズ。 // (最初の)ディスクリプタを所有できるかポーリングする。 void -LanceDevice::RXIdle(Event& event) +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) { @@ -1043,7 +1042,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; @@ -1057,11 +1056,11 @@ LanceDevice::RXCopy() int32 bcnt = -(int32)(int16)rmd2; if (bcnt < rx_packet.length) { - putlog(1, "will be remain: %d < %d", bcnt, rx_packet.length); + putlog(1, "will be remain: %d < %u", bcnt, rx_packet.length); } uint8 *src = &rx_packet[0]; - int remsize = rx_packet.length; + uint remsize = rx_packet.length; if (bcnt > remsize) { bcnt = remsize; @@ -1119,7 +1118,7 @@ LanceDevice::RXCopy() WriteMem(rmd_addr + 6, (dst - bufdst) & 0xfff); } else { rmd1 &= ~AM7990::RMD1_ENP; - putlog(1, "copy remain %d", remsize); + putlog(1, "copy remain %u", remsize); // 前詰めにコピーする memmove(&rx_packet[0], src, remsize); @@ -1138,11 +1137,11 @@ LanceDevice::RXCopy() // - 次のディスクリプタが所有できれば引き続き書き出すため RXCOPY へ。 // - 次のディスクリプタが所有できなければエラーにして RXIDLE へ。 void -LanceDevice::RXNext(Event& event) +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; @@ -1218,7 +1217,7 @@ LanceDevice::ChangePhase(RXPhase new_pha rx_event.time = time; switch (new_phase) { case RXPhase::STOP: - gScheduler->StopEvent(rx_event); + scheduler->StopEvent(rx_event); return; case RXPhase::IDLE: rx_event.func = ToEventCallback(&LanceDevice::RXIdle); @@ -1227,9 +1226,9 @@ LanceDevice::ChangePhase(RXPhase new_pha rx_event.func = ToEventCallback(&LanceDevice::RXNext); break; default: - assertmsg(false, "phase %d", (int)new_phase); + assertmsg(false, "phase %u", (uint)new_phase); } - gScheduler->RestartEvent(rx_event); + scheduler->RestartEvent(rx_event); }