Annotation of nono/vm/rtl8019as.cpp, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2023 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Nereid イーサネット (RTL8019AS)
                      9: //
                     10: 
                     11: // ローカル側のアドレス空間は以下の配置のようだ。
                     12: //
                     13: // 0000-3fff: PROM (32 バイトでミラー)
                     14: // 4000-7fff: バッファ RAM (16KB)
                     15: // 8000-bfff: バスか何かの都合で多少再現性のある不定データが読めるようだ
                     16: // c000-ffff: バッファ RAM (16KB) のミラーのようだ
                     17: 
                     18: // PROM 領域(32バイト)をバイトで読み出すと以下のように読める。
                     19: // 0000: 00 00 50 50 C2 C2 10 10  YY YY ZZ ZZ FF FF FF FF
                     20: // 0010: FF FF FF FF FF FF FF FF  FF FF FF FF 57 57 57 57
                     21: //
                     22: // 同領域をワードで読み出すと以下のように読める。
                     23: // 0000: 00FF 50FF C2FF 10FF YYFF ZZFF FFFF FFFF
                     24: // 0010: FFFF FFFF FFFF FFFF FFFF FFFF 57FF 57FF
                     25: //
                     26: // MAC アドレスは 00:50:C2:10:YY:ZZ。
                     27: // $001c あたりは 'B'($42) か 'W'($57) で、バイトかワードかを示すらしい。
                     28: 
                     29: // メモ。電源オン時のレジスタ値ダンプ:
                     30: // (1回目)
                     31: // Page0: 21 00 FF 9F 13 00 00 EF  FF FF 50 70 16 00 00 00
                     32: // Page1: 61 00 05 02 02 10 64 F7  01 B0 91 20 01 20 60 02
                     33: // Page2: A1 80 00 FF 00 FF FF FF  FF FF FF FF D1 E0 C6 80
                     34: // Page3: E1 30 00 00 90 00 10 FF  00 FE FF FD FF FE FF FF
                     35: // (2回目)
                     36: // Page0: 21 00 FF BF 13 00 00 EF  FF FF 50 70 16 00 00 00
                     37: // Page1: 61 00 01 00 02 00 44 F7  01 B0 91 20 00 20 20 02
                     38: // Page2: A1 80 00 FF 00 FF FF FF  FF FF FF FF D1 E0 86 80
                     39: // Page3: E1 30 00 00 90 00 10 FF  00 FE FF FD FF FE FF FF
                     40: 
                     41: #include "rtl8019as.h"
1.1.1.7   root       42: #include "event.h"
1.1       root       43: #include "interrupt.h"
1.1.1.4   root       44: #include "monitor.h"
1.1       root       45: #include "scheduler.h"
                     46: 
                     47: // コンストラクタ
1.1.1.3   root       48: RTL8019ASDevice::RTL8019ASDevice(uint n, int vector_)
1.1       root       49:        : inherited(OBJ_ETHERNET(n))
                     50: {
1.1.1.3   root       51:        SetName(string_format("RTL8019AS#%u", n));
1.1       root       52:        ClearAlias();
1.1.1.3   root       53:        AddAlias(string_format("RTL8019AS%u", n));
1.1.1.8 ! root       54:        AddAlias(string_format("Net%u", n));
1.1       root       55: 
                     56:        intr_vector = vector_;
                     57: 
1.1.1.4   root       58:        monitor = gMonitorManager->Regist(ID_MONITOR_RTL8019AS(n), this);
1.1.1.8 ! root       59:        monitor->SetCallback(&RTL8019ASDevice::MonitorScreen);
1.1.1.4   root       60:        monitor->SetSize(71, 19);
1.1       root       61: }
                     62: 
                     63: // デストラクタ
                     64: RTL8019ASDevice::~RTL8019ASDevice()
                     65: {
                     66: }
                     67: 
                     68: // 初期化
                     69: bool
                     70: RTL8019ASDevice::Init()
                     71: {
1.1.1.3   root       72:        uint n = GetId() - OBJ_ETHERNET0;
1.1       root       73: 
1.1.1.6   root       74:        hostnet->SetPortName(string_format("Nereid#%u", n));
                     75: 
1.1       root       76:        // MAC アドレスを取得
1.1.1.5   root       77:        MacAddr macaddr;
1.1       root       78:        if (inherited::GetConfigMacAddr(n, &macaddr, false) == false) {
                     79:                // エラーメッセージ表示済み
                     80:                return false;
                     81:        }
                     82:        // PROM 領域 (実質16バイト) を作成
                     83:        memset(&prom[0], 0xff, prom.size());
1.1.1.5   root       84:        macaddr.ExportTo(&prom[0]);
1.1       root       85:        prom[0xe] = 'W';
                     86:        prom[0xf] = 'W';
                     87: 
                     88:        interrupt = GetInterruptDevice();
                     89: 
                     90:        // ホストからの受信コールバックを登録
                     91:        scheduler->ConnectMessage(MessageID::HOSTNET_RX(n), this,
1.1.1.2   root       92:                ToMessageCallback(&RTL8019ASDevice::RxMessage));
1.1       root       93: 
1.1.1.7   root       94:        auto evman = GetEventManager();
                     95:        tx_event = evman->Regist(this,
                     96:                ToEventCallback(&RTL8019ASDevice::TXEvent),
                     97:                string_format("RTL8019AS%u TX", n));
                     98:        rx_event = evman->Regist(this,
                     99:                ToEventCallback(&RTL8019ASDevice::RXEvent),
                    100:                string_format("RTL8019AS%u RX", n));
                    101: 
                    102:        txled_event = evman->Regist(this,
                    103:                ToEventCallback(&RTL8019ASDevice::TXLedEvent),
                    104:                string_format("RTL8019AS%u TX LED", n));
                    105:        rxled_event = evman->Regist(this,
                    106:                ToEventCallback(&RTL8019ASDevice::RXLedEvent),
                    107:                string_format("RTL8019AS%u RX LED", n));
1.1.1.3   root      108: 
1.1       root      109:        return true;
                    110: }
                    111: 
                    112: // リセット
                    113: void
                    114: RTL8019ASDevice::ResetHard(bool poweron)
                    115: {
                    116:        if (poweron) {
                    117:                // 電源オン時の不定値は適当。ハードリセットの影響を受けない。
                    118:                // いずれにしても極力ゼロじゃない値にしておく。
                    119:                local_addr = 0xff00;
                    120:                boundary_addr = 0xcf00;
                    121:                current_page_addr = 0xfc00;
                    122:                remote_addr = 0xffff;
                    123: 
                    124:                // TSR/RSR は初回送信/受信時まで不定 (DP83901A.pdf)
                    125:                tsr = 0xcc;
                    126:                rsr = 0xcc;
                    127: 
                    128:                // PSTART は電源オンでだいたいこれが読める?
                    129:                // ハードリセットの影響を受けない。
                    130:                pstart_addr = 0x8000;
                    131: 
                    132:                // RCR は電源オン時だいたい $d1 な気がする
                    133:                monitor_mode = false;
                    134:                promisc_mode = true;
                    135:                accept_mcast = false;
                    136:                accept_bcast = false;
                    137:                accept_short = false;
                    138:                accept_error = true;
                    139: 
                    140:                // TCR は電源オン時だいたい $e0 な気がする
                    141:                tcr = 0x00;
                    142: 
                    143:                // DCR は電源オン時 $86 になることが多い気がする
                    144:                dcr = RTL8019::DCR_BOS;
                    145: 
                    146:                // XXX カウンタがリセットでどうなるかは未調査
                    147:                for (auto& c : error_counter) {
                    148:                        c = 0;
                    149:                }
                    150:        }
                    151: 
                    152:        // 処理中は全部破棄
                    153:        scheduler->StopEvent(tx_event);
                    154:        scheduler->StopEvent(rx_event);
                    155:        tx_in_progress = false;
                    156:        rx_packet.Clear();
                    157: 
                    158:        // LED は電源オンで点灯。リセットでも点灯に戻りそうな気はする。
                    159:        tx_led = true;
                    160:        rx_led = true;
                    161:        scheduler->StopEvent(txled_event);
                    162:        scheduler->StopEvent(rxled_event);
                    163: 
                    164:        // ハードリセットで、TPSR, RCR は変化しない。
                    165: 
                    166:        // CR は初期化される。
                    167:        pagesel = 0;
                    168:        dmamode = DMAMode::Complete;
                    169: 
                    170:        // PSTOP は 0 になるように見える。
                    171:        pstop_addr  = 0x0000;
                    172: 
                    173:        // TCR.LB は 0 (Normal Operation) になる。それ以外は変化しない。
                    174:        tcr &= ~RTL8019::TCR_LB_MASK;
                    175: 
                    176:        // DCR は LAS=1 になる。それ以外は変化しない。
                    177:        dcr |= RTL8019::DCR_LAS;
                    178: 
                    179:        // ISR は、電源オン後にクリアしろと書いてあるのでおそらく不定。
                    180:        // 実際 $ef が読めがち。
                    181:        intr_stat = 0xef;
                    182:        intr_mask = 0x00;
                    183:        ChangeState(State::Stop);
                    184: 
                    185:        // Page3 の RTL8019AS 部分はだいたいリセットされそう?
                    186:        config_write_enable = false;
                    187:        verid = 0;
                    188:        irq_enable = true;
                    189:        brom_force_disable = false;
                    190: 
                    191:        // XXX 初期値は?
                    192:        mediatype = RTL8019::MediaType_10BaseT_Auto;
                    193: 
                    194:        ChangeInterrupt();
                    195: }
                    196: 
                    197: // リセットポートによるソフトリセット
                    198: void
                    199: RTL8019ASDevice::Reset()
                    200: {
                    201:        // リセットといっても実質ほぼ Stop じゃないかと思う。
                    202:        // 実際ざっと試した限りレジスタの値は変化しなかった。
                    203:        ChangeState(State::Stop);
                    204: }
                    205: 
                    206: /*static*/ inline uint32
                    207: RTL8019ASDevice::Decoder(uint32 addr)
                    208: {
                    209:        return addr & 0x3f;
                    210: }
                    211: 
1.1.1.2   root      212: busdata
1.1.1.3   root      213: RTL8019ASDevice::Read(busaddr addr)
1.1       root      214: {
1.1.1.3   root      215:        busdata data;
                    216:        uint32 paddr = addr.Addr();
                    217:        uint32 reqsize = addr.GetSize();
                    218:        uint32 datasize = std::min(2 - (paddr & 1), reqsize);
                    219:        uint32 offset = Decoder(paddr) >> 1;
                    220: 
                    221:        if (offset < 0x10) {
                    222:                // レジスタ部は、上位にレジスタ、下位は $ff が読める。
                    223:                // ワードで読んでも上位にレジスタ、下位は $ff なので、
                    224:                // レジスタと $ff のバイト配置とも言えるかも。
                    225:                if ((paddr & 1) == 0) {
                    226:                        uint32 rn = pagesel + offset;
1.1       root      227:                        data = ReadReg(rn);
                    228:                } else {
                    229:                        data = 0xff;
                    230:                }
1.1.1.3   root      231:                data |= BusData::Size1;
                    232:        } else if (offset < 0x18) {
                    233:                // DMA 部。
                    234:                if (datasize == 1) {
                    235:                        data = ReadDMA8(paddr & 1);
                    236:                        data |= BusData::Size1;
                    237:                } else {
                    238:                        data = ReadDMA16();
                    239:                        data |= BusData::Size2;
                    240:                }
1.1       root      241:        } else {
1.1.1.3   root      242:                // リセットポート
1.1       root      243:                putlog(1, "Reset");
                    244:                Reset();
1.1.1.3   root      245:                data = 0xffff >> ((2 - datasize) * 8);
                    246:                data |= busdata::Size(datasize);
1.1       root      247:        }
                    248: 
                    249:        return data;
                    250: }
                    251: 
1.1.1.2   root      252: busdata
1.1.1.3   root      253: RTL8019ASDevice::Write(busaddr addr, uint32 data)
1.1       root      254: {
1.1.1.3   root      255:        busdata r;
                    256:        uint32 paddr = addr.Addr();
                    257:        uint32 reqsize = addr.GetSize();
                    258:        uint32 datasize = std::min(2 - (paddr & 1), reqsize);
                    259:        uint32 offset = Decoder(paddr) >> 1;
                    260: 
                    261:        data >>= (reqsize - datasize) * 8;
                    262: 
                    263:        if (offset < 0x10) {
                    264:                // レジスタ部は、上位がレジスタ、下位は無視される(バスエラーではない)。
                    265:                // ワードで書いても、上位がレジスタ、下位は無視されるので、
                    266:                // レジスタと N.C. のバイト配置とも言えるかも。
                    267:                if ((paddr & 1) == 0) {
                    268:                        uint32 rn = pagesel + offset;
                    269:                        WriteReg(rn, data);
1.1       root      270:                } else {
                    271:                }
1.1.1.3   root      272:                r |= BusData::Size1;
                    273:        } else if (offset < 0x18) {
                    274:                // DMA 部。
                    275:                if (datasize == 1) {
                    276:                        WriteDMA8(data);
                    277:                        r |= BusData::Size1;
                    278:                } else {
                    279:                        WriteDMA16(data);
                    280:                        r |= BusData::Size2;
                    281:                }
1.1       root      282:        } else {
                    283:                putlog(1, "Reset");
                    284:                Reset();
1.1.1.3   root      285:                r |= busdata::Size(datasize);
1.1       root      286:        }
                    287: 
1.1.1.3   root      288:        return r;
1.1       root      289: }
                    290: 
1.1.1.2   root      291: busdata
1.1.1.3   root      292: RTL8019ASDevice::Peek1(uint32 addr)
1.1       root      293: {
                    294:        uint32 offset = Decoder(addr);
                    295: 
                    296:        if (offset < 0x10 * 2) {
                    297:                if (offset % 2 == 0) {
                    298:                        uint32 n = pagesel + offset / 2;
                    299:                        return PeekReg(n);
                    300:                } else {
                    301:                        return 0xff;
                    302:                }
                    303:        } else if (offset < 0x18 * 2) {
                    304:                return PeekDMA(offset & 1);
                    305:        } else {
                    306:                // XXX ?
                    307:                return 0xff;
                    308:        }
                    309: }
                    310: 
                    311: void
1.1.1.8 ! root      312: RTL8019ASDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root      313: {
                    314:        uint32 val;
                    315:        const int x = 6;
                    316:        const int x2 = 59;
                    317:        int y;
                    318: 
                    319:        screen.Clear();
                    320:        y = 0;
                    321: 
                    322:        // 0         1         2         3         4         5
                    323:        // 012345678901234567890123456789012345678901234567890123456789
                    324:        // CFG0 $xx 12345 12345 12345 12345 12345 12345 12345 12345
                    325: 
                    326:        val = PeekCR();
                    327:        screen.Puts(0, y, "CR:");
                    328:        screen.Print(x, y, "$%02x", val);
                    329:        static const char * const cr_bits[] = {
                    330:                "", "", "", "", "", "TXP", "STA", "STP"
                    331:        };
                    332:        MonitorReg(screen, x + 4, y, val, cr_bits);
                    333:        screen.Print(x + 4, y, "PageSel=%x", val >> 6);
                    334:        uint rd = (val >> 3) & 7;
                    335:        screen.Print(x + 16, y, "RD=%x(%s)", rd, GetDMAName(rd));
                    336:        y++;
                    337: 
                    338:        val = PeekISR();
                    339:        screen.Puts(0, y, "ISR:");
                    340:        screen.Print(x, y, "$%02x", val);
                    341:        static const char * const isr_bits[] = {
                    342:                "RST", "RDC", "CNT", "OVW", "TXE", "RXE", "PTX", "PRX"
                    343:        };
                    344:        MonitorReg(screen, x + 4, y, val, isr_bits);
                    345:        y++;
                    346: 
                    347:        val = PeekIMR();
                    348:        screen.Puts(0, y, "IMR:");
                    349:        screen.Print(x, y, "$%02x", val);
                    350:        static const char * const imr_bits[] = {
                    351:                "-1", "RDCE", "CNTE", "OVWE", "TXEE", "RXEE", "PTXE", "PRXE"
                    352:        };
                    353:        MonitorReg(screen, x + 4, y, val, imr_bits);
                    354:        y++;
                    355: 
                    356:        val = PeekDCR();
                    357:        screen.Puts(0, y, "DCR:");
                    358:        screen.Print(x, y, "$%02x", val);
                    359:        static const char * const dcr_bits[] = {
                    360:                "-1", "FT1", "FT0", "ARM", "LS", "LAS", "(BOS)", "WTS"
                    361:        };
                    362:        MonitorReg(screen, x + 4, y, val, dcr_bits);
                    363:        y++;
                    364: 
                    365:        val = PeekTCR();
                    366:        screen.Puts(0, y, "TCR:");
                    367:        screen.Print(x, y, "$%02x", val);
                    368:        static const char * const tcr_bits[] = {
                    369:                "-1", "-1", "-1", "OFST", "ATD", "LB1", "LB0", "CRC"
                    370:        };
                    371:        MonitorReg(screen, x + 4, y, val, tcr_bits);
                    372:        y++;
                    373: 
                    374:        val = PeekTSR();
                    375:        screen.Puts(0, y, "TSR:");
                    376:        screen.Print(x, y, "$%02x", val);
                    377:        static const char * const tsr_bits[] = {
                    378:                "OWC", "CDH", "-0", "CRS", "ABT", "COL", "-1", "PTX"
                    379:        };
                    380:        MonitorReg(screen, x + 4, y, val, tsr_bits);
                    381:        y++;
                    382: 
                    383:        val = PeekRCR();
                    384:        screen.Puts(0, y, "RCR:");
                    385:        screen.Print(x, y, "$%02x", val);
                    386:        static const char * const rcr_bits[] = {
                    387:                "-1", "-1", "MON", "PRO", "AM", "AB", "AR", "SEP"
                    388:        };
                    389:        MonitorReg(screen, x + 4, y, val, rcr_bits);
                    390:        y++;
                    391: 
                    392:        val = PeekRSR();
                    393:        screen.Puts(0, y, "RSR:");
                    394:        screen.Print(x, y, "$%02x", val);
                    395:        static const char * const rsr_bits[] = {
                    396:                "DFR", "DIS", "PHY", "MPA", "-0", "FAE", "CRC", "PRX"
                    397:        };
                    398:        MonitorReg(screen, x + 4, y, val, rsr_bits);
                    399:        y++;
                    400: 
1.1.1.2   root      401:        // MAC アドレスは PAR0 が左側 (ビッグエンディアンぽい感じ)。
                    402:        screen.Print(0, y, "PAR0-5: %s", par.ToString(':').c_str());
1.1       root      403: 
1.1.1.2   root      404:        // マルチキャストフィルタは MAR0 が右側 (リトルエンディアンぽい感じ)。
                    405:        // MAR7-0: $00000000'00000000
1.1.1.5   root      406:        screen.Print(x + 23, y, "MAR7-0: $%08x'%08x",
                    407:                (uint32)(mar >> 32), (uint32)mar);
1.1       root      408:        y++;
                    409: 
                    410:        y++;
                    411: 
                    412:        val = Peek9346CR();
                    413:        screen.Puts(0, y, "9346:");
                    414:        screen.Print(x, y, "$%02x", val);
                    415:        static const char * const cr9346_bits[] = {
                    416:                "EEM1", "EEM0", "-1", "-1", "EECS", "EESK", "EEDI", "EEDO"
                    417:        };
                    418:        MonitorReg(screen, x + 4, y, val, cr9346_bits);
                    419:        uint eem = val >> 6;
                    420:        y++;
                    421: 
                    422:        val = PeekCONFIG0();
                    423:        screen.Puts(0, y, "CFG0:");
                    424:        screen.Print(x, y, "$%02x", val);
                    425:        static const char * const config0_bits[] = {
                    426:                "VID1", "VID0", "AUI", "PNPJP", "JP", "BNC", "-0", "-0"
                    427:        };
                    428:        MonitorReg(screen, x + 4, y, val, config0_bits);
                    429:        y++;
                    430: 
                    431:        val = PeekCONFIG1();
                    432:        screen.Puts(0, y, "CFG1:");
                    433:        screen.Print(x, y, "$%02x", val);
                    434:        static const char * const config1_bits[] = {
                    435:                "IRQEN", "IRQS2", "IRQS1", "IRQS0", "IOS3", "IOS2", "IOS1", "IOS0"
                    436:        };
                    437:        MonitorReg(screen, x + 4, y, val, config1_bits);
                    438:        y++;
                    439: 
                    440:        val = PeekCONFIG2();
                    441:        screen.Puts(0, y, "CFG2:");
                    442:        screen.Print(x, y, "$%02x", val);
                    443:        static const char * const config2_bits[] = {
                    444:                "PL1", "PL0", "BSELB", "BS4", "BS3", "BS2", "BS1", "BS0"
                    445:        };
                    446:        MonitorReg(screen, x + 4, y, val, config2_bits);
                    447:        y++;
                    448: 
                    449:        val = PeekCONFIG3();
                    450:        screen.Puts(0, y, "CFG3:");
                    451:        screen.Print(x, y, "$%02x", val);
                    452:        static const char * const config3_bits[] = {
                    453:                "PNP", "FUDUP", "LEDS1", "LEDS0", "-0", "SLEEP", "PWRDN", "ACTB"
                    454:        };
                    455:        MonitorReg(screen, x + 4, y, val, config3_bits);
                    456:        y++;
                    457: 
                    458:        val = PeekCONFIG4();
                    459:        screen.Puts(0, y, "CFG4:");
                    460:        screen.Print(x, y, "$%02x", val);
                    461:        static const char * const config4_bits[] = {
                    462:                "-1", "-1", "-1", "-1", "-1", "-1", "-1", "IOMS"
                    463:        };
                    464:        MonitorReg(screen, x + 4, y, val, config4_bits);
                    465:        y++;
                    466: 
                    467:        // x+        1         2         3         4
                    468:        // 01234567890123456789012345678901234567890123456789
                    469:        // EEM=0(AutoLoad) Ver=3(8019A/AS)  PL=0(10baseTAuto)
                    470:        static const char * const eem_str[] = {
                    471:                "Normal",
                    472:                "AutoLoad",
                    473:                "Program",
                    474:                "WriteEn",
                    475:        };
1.1.1.3   root      476:        screen.Print(x, y, "EEM=%u(%s)", eem, eem_str[eem]);
1.1       root      477: 
                    478:        static const char * const verid_str[] = {
                    479:                "8019A/AS",
                    480:                "?",
                    481:                "?",
                    482:                "8019",
                    483:        };
1.1.1.3   root      484:        screen.Print(x + 16, y, "VID=%u(%s)", verid, verid_str[verid]);
1.1       root      485: 
                    486:        static const char * const mediatype_str[] = {
                    487:                "10baseTAuto",
                    488:                "10baseT",
                    489:                "10base5",
                    490:                "10base2",
                    491:        };
1.1.1.3   root      492:        screen.Print(x + 33, y, "PL=%u(%s)", mediatype, mediatype_str[mediatype]);
1.1       root      493:        y++;
                    494: 
                    495:        // LED は、RTL8019AS の LED ピンではなく Nereid ボード上の LED で表す。
                    496:        // Nereid ボードを上 (実装面側) から見るとこのような位置関係と結線に
                    497:        // なっているため(素子は省略)、RTL8019AS の LED0,1,2 (LINK, RX, TX) と
                    498:        // Nereid 基板上の LE1,2,3 (LINK, TX, RX) は並び順が違うことに注意。
                    499:        //
                    500:        //       LINK              TX   RX
                    501:        //     (Orange)          (Red) (Green)
                    502:        //              +------+
                    503:        // +------[*]---| RJ45 |---[*]-[*]---------[USB]---+
                    504:        // |   LE1 |    +------+ LE2|   |LE3               |
                    505:        // |       |                |   |
                    506:        // |       +----------------|---|---+
                    507:        // |                        |   |   |
                    508:        // |                 +------+---+---+----+
                    509:        // |       RTL8019AS |     63  62  61    |
                    510:        // |                 |   LED2 LED1 LED0  |
                    511:        // |                 |  (TX) (RX) (LINK) |
                    512:        //
                    513:        y++;
                    514:        screen.Puts(0, y, "LED:");
1.1.1.4   root      515:        screen.Puts(x, y, TA::ReverseOrange, "LED1");
                    516:        screen.Puts(x + 4, y, "(LINK)");
                    517:        screen.Puts(x + 11, y, tx_led ? TA::ReverseRed   : TA::Off, "LED2");
                    518:        screen.Puts(x + 15, y, "(TX)");
                    519:        screen.Puts(x + 20, y, rx_led ? TA::ReverseGreen : TA::Off, "LED3");
                    520:        screen.Puts(x + 24, y, "(RX)");
1.1       root      521: 
                    522:        // 右カラム
                    523:        y = 0;
                    524:        screen.Puts(x2, y++, "RSAR");
                    525:        screen.Print(x2 - 1, y++, "(CRDA) =$%04x", PeekCRDA());
                    526:        screen.Print(x2, y++, "RBCR  =$%04x", remote_count);
                    527:        y++;
                    528:        //screen.Puts(x2 + 10, y, TA::Disable, "00");
                    529:        screen.Print(x2, y++, "TPSR  =$%02x", transmit_page_start_addr >> 8);
                    530:        screen.Print(x2, y++, "TBCR  =$%04x", transmit_byte_count);
                    531:        y++;
                    532:        //screen.Puts(x2 + 10, y, TA::Disable, "00");
                    533:        screen.Print(x2, y++, "PSTART=$%02x", PeekPSTART());
                    534:        //screen.Puts(x2 + 10, y, TA::Disable, "00");
                    535:        screen.Print(x2, y++, "PSTOP =$%02x", PeekPSTOP());
                    536:        //screen.Puts(x2 + 10, y, TA::Disable, "00");
                    537:        screen.Print(x2, y++, "BNRY  =$%02x", PeekBNRY());
                    538:        //screen.Puts(x2 + 10, y, TA::Disable, "00");
                    539:        screen.Print(x2, y++, "CURR  =$%02x", PeekCURR());
                    540:        y++;
                    541:        screen.Print(x2, y++, "CLDA  =$%04x", PeekCLDA());
                    542:        y++;
                    543:        screen.Print(x2, y++, "NCR   =  $%02x", PeekNCR());
                    544:        screen.Print(x2, y++, "CNTR0 =  $%02x", PeekCNTR(0));
                    545:        screen.Print(x2, y++, "CNTR1 =  $%02x", PeekCNTR(1));
                    546:        screen.Print(x2, y++, "CNTR2 =  $%02x", PeekCNTR(2));
                    547: }
                    548: 
1.1.1.8 ! root      549: // レジスタをビットごとに表示する。MonitorScreen の下請け。
1.1       root      550: // "-" で始まっていたら Disable 色にし、次の文字から表示。
                    551: void
                    552: RTL8019ASDevice::MonitorReg(TextScreen& screen,
                    553:        int x, int y, uint32 reg, const char * const *names)
                    554: {
                    555:        for (int i = 0; i < 8; i++) {
                    556:                if (names[i][0] == '-') {
                    557:                        screen.Puts(x + i * 6, y, TA::Disable, names[i] + 1);
                    558:                } else {
1.1.1.7   root      559:                        bool b = reg & (1U << (7 - i));
1.1       root      560:                        screen.Puts(x + i * 6, y, TA::OnOff(b), names[i]);
                    561:                }
                    562:        }
                    563: }
                    564: 
                    565: // レジスタ読み出し (rn はページ番号込み)
                    566: uint32
                    567: RTL8019ASDevice::ReadReg(uint32 rn)
                    568: {
                    569:        uint32 data;
                    570: 
                    571:        switch (rn) {
                    572:         case RTL8019::CR:              // CR は全ページで同じものが見える
                    573:         case RTL8019::CR_1:
                    574:         case RTL8019::CR_2:
                    575:         case RTL8019::CR_3:
                    576:                data = PeekCR();
                    577:                break;
                    578: 
                    579:         case RTL8019::CLDA0:
                    580:                data = PeekCLDA() & 0xff;
                    581:                break;
                    582:         case RTL8019::CLDA1:
                    583:                data = PeekCLDA() >> 8;
                    584:                break;
                    585: 
                    586:         case RTL8019::BNRY:
                    587:                data = PeekBNRY();
                    588:                break;
                    589: 
                    590:         case RTL8019::TSR:
                    591:                data = PeekTSR();
                    592:                break;
                    593: 
                    594:         case RTL8019::NCR:
                    595:                data = PeekNCR();
                    596:                break;
                    597: 
                    598:         case RTL8019::FIFO:
                    599:                // それっぽい値は返すけど未実装
                    600:                data = PeekFIFO();
                    601:                putlog(0, "Read %s -> $%02x (NOT IMPLEMENTED)",
                    602:                        RegNameR(rn).c_str(), data);
                    603:                return data;
                    604: 
                    605:         case RTL8019::ISR:
                    606:                data = PeekISR();
                    607:                break;
                    608: 
                    609:         case RTL8019::CRDA0:
                    610:                data = PeekCRDA() & 0xff;
                    611:                break;
                    612:         case RTL8019::CRDA1:
                    613:                data = PeekCRDA() >> 8;
                    614:                break;
                    615: 
                    616:         case RTL8019::ID0:
                    617:                data = Peek8019ID0();
                    618:                break;
                    619:         case RTL8019::ID1:
                    620:                data = Peek8019ID1();
                    621:                break;
                    622: 
                    623:         case RTL8019::RSR:
                    624:                data = PeekRSR();
                    625:                break;
                    626: 
                    627:         case RTL8019::CNTR0:
                    628:         case RTL8019::CNTR1:
                    629:         case RTL8019::CNTR2:
                    630:         {
                    631:                // 読み出しでリセットされる
1.1.1.3   root      632:                uint n = rn - RTL8019::CNTR0;
1.1       root      633:                data = PeekCNTR(n);
                    634:                error_counter[n] = 0;
                    635:                break;
                    636:        }
                    637: 
                    638:         case RTL8019::PAR0
                    639:          ... RTL8019::PAR5:
                    640:                data = PeekPAR(rn - RTL8019::PAR0);
                    641:                break;
                    642: 
                    643:         case RTL8019::CURR:
                    644:                data = PeekCURR();
                    645:                break;
                    646: 
                    647:         case RTL8019::MAR0
                    648:          ... RTL8019::MAR7:
                    649:                data = PeekMAR(rn - RTL8019::MAR0);
                    650:                break;
                    651: 
                    652:         case RTL8019::PSTART_2:
                    653:                data = PeekPSTART();
                    654:                break;
                    655: 
                    656:         case RTL8019::PSTOP_2:
                    657:                data = PeekPSTOP();
                    658:                break;
                    659: 
                    660:         case RTL8019::TPSR_2:
                    661:                data = PeekTPSR();
                    662:                break;
                    663: 
                    664:         case RTL8019::RCR_2:
                    665:                data = PeekRCR();
                    666:                break;
                    667: 
                    668:         case RTL8019::TCR_2:
                    669:                data = PeekTCR();
                    670:                break;
                    671: 
                    672:         case RTL8019::DCR_2:
                    673:                data = PeekDCR();
                    674:                break;
                    675: 
                    676:         case RTL8019::IMR_2:
                    677:                data = PeekIMR();
                    678:                break;
                    679: 
                    680:         case RTL8019::CR9346:
                    681:                data = Peek9346CR();
                    682:                break;
                    683: 
                    684:         case RTL8019::BPAGE:
                    685:                data = PeekBPAGE();
                    686:                break;
                    687: 
                    688:         case RTL8019::CONFIG0:
                    689:                data = PeekCONFIG0();
                    690:                break;
                    691: 
                    692:         case RTL8019::CONFIG1:
                    693:                data = PeekCONFIG1();
                    694:                break;
                    695: 
                    696:         case RTL8019::CONFIG2:
                    697:                data = PeekCONFIG2();
                    698:                break;
                    699: 
                    700:         case RTL8019::CONFIG3:
                    701:                data = PeekCONFIG3();
                    702:                break;
                    703: 
                    704:         case RTL8019::CSNSAV:
                    705:                data = PeekCSNSAV();
                    706:                break;
                    707: 
                    708:         case 0x39:
                    709:                data = PeekReg39();
                    710:                break;
                    711: 
                    712:         case RTL8019::INTR:
                    713:                data = PeekINTR();
                    714:                break;
                    715: 
                    716:         case RTL8019::CONFIG4:
                    717:                data = PeekCONFIG4();
                    718:                break;
                    719: 
                    720:         case 0x23:
                    721:         case 0x25 ... 0x2b:
                    722:         case 0x37:
                    723:         case 0x3a:
                    724:         case 0x3c:
                    725:         case 0x3e:
                    726:         case 0x3f:
                    727:                data = 0xff;
                    728:                break;
                    729: 
                    730:         default:
                    731:                putlog(0, "Read %s (NOT IMPLEMENTED)", RegNameR(rn).c_str());
                    732:                return 0xff;
                    733:        }
                    734: 
                    735:        putlog(2, "%s -> $%02x", RegNameR(rn).c_str(), data);
                    736:        return data;
                    737: }
                    738: 
                    739: // DMA ポートのバイト読み出し
                    740: uint32
                    741: RTL8019ASDevice::ReadDMA8(uint32 a0)
                    742: {
                    743:        uint32 data;
                    744: 
                    745:        // DMA モードが Read でない時に読み込むと、
                    746:        // 現在の CRDA が読める (がカウンタは変化しない) ような気がする。
                    747: 
                    748:        uint32 prev_addr = remote_addr;
                    749:        if (remote_addr < 0x4000) {
                    750:                // PROM 領域。
                    751:                // バイトアクセスだと偶数バイト、奇数バイトは同じものが見える。
                    752:                data = ReadPROM(remote_addr);
                    753:        } else if ((remote_addr & 0x4000)) {
                    754:                // RAM 領域。
                    755:                if (word_transfer || (remote_addr & 1) == 0) {
                    756:                        // WTS==1 か偶数番地なら普通に読み出せる。
                    757:                        // たぶんワードで読み出せてるがそのうち上位 (LE でいう下位)
                    758:                        // だけが見えてる状態だと思う。
                    759:                        uint16 addr = remote_addr & 0xfffe;
                    760:                        data = ReadRAM(addr);
                    761:                } else {
                    762:                        data = 0;
                    763:                }
                    764:        } else {
                    765:                // 未実装領域。実機ではバスの残像か何かが読めているようだが。
                    766:                data = 0xff;
                    767:        }
                    768:        PostDMA();
                    769: 
                    770:        if (__predict_false(loglevel >= 2)) {
                    771:                ReadDMAlog(prev_addr, data, 2);
                    772:        }
                    773: 
                    774:        return (uint8)data;
                    775: }
                    776: 
                    777: // DMA ポートのワード読み出し
                    778: uint32
                    779: RTL8019ASDevice::ReadDMA16()
                    780: {
                    781:        uint32 data;
                    782: 
                    783:        // DMA モードが Read でない時に読み込むと、
                    784:        // 現在の CRDA が読める (がカウンタは変化しない) ような気がする。
                    785: 
                    786:        // RTL8019AS は基本 LE で、Nereid 上でデータバスがクロスされてるはず
                    787:        //
                    788:        //         680x0                             RTL8019AS
                    789:        // +---------------------+       +----------------------------------+
                    790:        // レジスタ    データバス         データバス     (レジスタ)  内蔵メモリ
                    791:        //          +- D15-8: $86  <-  -  D15-8: $dd <-+             +00: $86
                    792:        //  $86dd <-+                ×                +- $dd86  <-  +01: $dd
                    793:        //          +- D7-0 : $dd  <-  -  D7-0 : $86 <-+
                    794: 
                    795:        uint32 prev_addr = remote_addr;
                    796:        if (remote_addr < 0x4000) {
                    797:                // PROM 領域。
                    798:                // ワードアクセスだと上位(偶数番地)にデータ、下位(奇数番地)は $ff。
                    799:                data  = ReadPROM(remote_addr) << 8;
                    800:                data |= 0xff;
                    801:        } else if ((remote_addr & 0x4000)) {
                    802:                // RAM 領域。
                    803:                // 偶数番地からのアクセスはワード値を返す。
                    804:                // WTS==1 なら、奇数番地でも A0 をマスクしたようにワード値を返す。
                    805:                // WTS==0 で奇数番地ならおかしなことになる (0000 とか ffff が読める?)
                    806:                // ようだ。
                    807:                if (word_transfer || (remote_addr & 1) == 0) {
                    808:                        uint16 addr = remote_addr & 0xfffe;
                    809:                        data  = ReadRAM(addr) << 8;
                    810:                        data |= ReadRAM(addr + 1);
                    811:                } else {
                    812:                        data = 0;
                    813:                }
                    814:        } else {
                    815:                // 未実装領域。実機ではバスの残像か何かが読めているようだが。
                    816:                data = 0xffff;
                    817:        }
                    818:        PostDMA();
                    819: 
                    820:        if (__predict_false(loglevel >= 2)) {
                    821:                ReadDMAlog(prev_addr, data, 4);
                    822:        }
                    823: 
                    824:        return (uint16)data;
                    825: }
                    826: 
                    827: // DMA 読み出しのログ。
                    828: // loglevel >= 3 なら、すべて表示。
                    829: // loglevel == 2 なら、受信ヘッダの読み出しと転送完了時のサマリーのみ表示。
                    830: // 受信ヘッダは、実際のバッファ上のデータが受信ヘッダかどうかではなく、
                    831: // ページ先頭から4バイトを読み出そうとしているものをヘッダの読み出しだと
                    832: // 思って表示する。ゲスト OS がヘッダだと思って読んだ(であろう)ところが
                    833: // どう読めたかが見たいので。
                    834: // この関数自体は loglevel >= 2 で呼ばれる。
                    835: void
                    836: RTL8019ASDevice::ReadDMAlog(uint32 prev_addr, uint32 data, int width)
                    837: {
                    838:        // ページ先頭から 4 バイトの転送ならヘッダ読み込みだと思ってみる
                    839:        bool header =
                    840:                ((remote_start_addr & 0x00ff) == 0) && (remote_start_count == 4);
                    841: 
                    842:        if (loglevel >= 3 || header) {
                    843:                std::string databuf = strhex(data, width);
                    844:                if ((int32)data < 0) {
                    845:                        putlogn("DMA[$%04x] -> $%s (No Data)", prev_addr, databuf.c_str());
                    846:                } else {
                    847:                        putlogn("DMA[$%04x] -> $%s", prev_addr, databuf.c_str());
                    848:                }
                    849:        }
                    850: 
                    851:        if (__predict_false(remote_count == 0)) {
1.1.1.3   root      852:                putlogn("DMA %u bytes transferred", remote_start_count);
1.1       root      853:        }
                    854: }
                    855: 
                    856: // レジスタ書き込み (rn はページ番号込み)
1.1.1.3   root      857: void
1.1       root      858: RTL8019ASDevice::WriteReg(uint32 rn, uint32 data)
                    859: {
                    860:        switch (rn) {
                    861:         case RTL8019::CR:              // CR は全ページで同じものが見える
                    862:         case RTL8019::CR_1:
                    863:         case RTL8019::CR_2:
                    864:         case RTL8019::CR_3:
                    865:                WriteCR(data);
1.1.1.3   root      866:                break;
1.1       root      867: 
                    868:         case RTL8019::PSTART:
                    869:                WritePSTART(data);
1.1.1.3   root      870:                break;
1.1       root      871: 
                    872:         case RTL8019::PSTOP:
                    873:                WritePSTOP(data);
1.1.1.3   root      874:                break;
1.1       root      875: 
                    876:         case RTL8019::BNRY:
                    877:                WriteBNRY(data);
1.1.1.3   root      878:                break;
1.1       root      879: 
                    880:         case RTL8019::TPSR:
                    881:                WriteTPSR(data);
1.1.1.3   root      882:                break;
1.1       root      883: 
                    884:         case RTL8019::TBCR0:
                    885:                WriteTBCR0(data);
1.1.1.3   root      886:                break;
1.1       root      887:         case RTL8019::TBCR1:
                    888:                WriteTBCR1(data);
1.1.1.3   root      889:                break;
1.1       root      890: 
                    891:         case RTL8019::ISR:
                    892:                WriteISR(data);
1.1.1.3   root      893:                break;
1.1       root      894: 
                    895:         case RTL8019::RSAR0:
                    896:                WriteRSAR0(data);
1.1.1.3   root      897:                break;
1.1       root      898:         case RTL8019::RSAR1:
                    899:                WriteRSAR1(data);
1.1.1.3   root      900:                break;
1.1       root      901: 
                    902:         case RTL8019::RBCR0:
                    903:                WriteRBCR0(data);
1.1.1.3   root      904:                break;
1.1       root      905:         case RTL8019::RBCR1:
                    906:                WriteRBCR1(data);
1.1.1.3   root      907:                break;
1.1       root      908: 
                    909:         case RTL8019::RCR:
                    910:                WriteRCR(data);
1.1.1.3   root      911:                break;
1.1       root      912: 
                    913:         case RTL8019::TCR:
                    914:                WriteTCR(data);
1.1.1.3   root      915:                break;
1.1       root      916: 
                    917:         case RTL8019::DCR:
                    918:                WriteDCR(data);
1.1.1.3   root      919:                break;
1.1       root      920: 
                    921:         case RTL8019::IMR:
                    922:                WriteIMR(data);
1.1.1.3   root      923:                break;
1.1       root      924: 
                    925:         case RTL8019::PAR0
                    926:          ... RTL8019::PAR5:
                    927:                WritePAR(rn - RTL8019::PAR0, data);
1.1.1.3   root      928:                break;
1.1       root      929: 
                    930:         case RTL8019::CURR:
                    931:                WriteCURR(data);
1.1.1.3   root      932:                break;
1.1       root      933: 
                    934:         case RTL8019::MAR0
                    935:          ... RTL8019::MAR7:
                    936:                WriteMAR(rn - RTL8019::MAR0, data);
1.1.1.3   root      937:                break;
1.1       root      938: 
                    939:         case RTL8019::CR9346:
                    940:                Write9346CR(data);
1.1.1.3   root      941:                break;
1.1       root      942: 
                    943:         case RTL8019::CONFIG0:
                    944:                WriteCONFIG0(data);
1.1.1.3   root      945:                break;
1.1       root      946: 
                    947:         case RTL8019::CONFIG1:
                    948:                WriteCONFIG1(data);
1.1.1.3   root      949:                break;
1.1       root      950: 
                    951:         case RTL8019::CONFIG2:
                    952:                WriteCONFIG2(data);
1.1.1.3   root      953:                break;
1.1       root      954: 
                    955:         case RTL8019::CONFIG3:
                    956:                WriteCONFIG3(data);
1.1.1.3   root      957:                break;
1.1       root      958: 
                    959:         default:
1.1.1.3   root      960:                putlog(0, "%s <- $%02x (NOT IMPLEMENTED)",
                    961:                        RegNameW(rn).c_str(), data);
1.1       root      962:                break;
                    963:        }
                    964: }
                    965: 
                    966: // CR レジスタ書き込み
                    967: void
                    968: RTL8019ASDevice::WriteCR(uint32 data)
                    969: {
                    970:        std::string msg;
                    971:        uint32 newpage;
                    972:        uint32 newmode;
                    973:        bool newstp;
                    974:        State newstate;
                    975: 
                    976:        // ページ
                    977:        newpage = (data >> 2) & 0x30;
                    978:        if (newpage != pagesel) {
                    979:                pagesel = newpage;
                    980:                if (loglevel >= 2) {
                    981:                        msg = string_format(" Page=%x", pagesel >> 4);
                    982:                }
                    983:        }
                    984: 
                    985:        // DMA モード
                    986:        newmode = (data >> 3) & 7;
                    987:        if ((DMAMode)newmode != dmamode) {
                    988:                dmamode = (DMAMode)newmode;
                    989:                if (loglevel >= 2) {
                    990:                        msg += " DMA=";
                    991:                        msg += GetDMAName(newmode);
                    992:                }
                    993:        }
                    994: 
                    995:        // TXP ビット
                    996:        if (loglevel >= 2) {
                    997:                if (tx_in_progress == false && (data & RTL8019::CR_TXP)) {
                    998:                        msg += " TXP";
                    999:                }
                   1000:        }
                   1001: 
                   1002:        // STP ビット
                   1003:        //
                   1004:        // 現行               STP書き込み
                   1005:        // Normal       0       : 何もしない
                   1006:        // InProg       0       : どうする?
                   1007:        // Stop         0       : -> Normal へ
                   1008:        // Normal       1       : -> InProg へ
                   1009:        // InProg       1       : 何もしない
                   1010:        // Stop         1       : 何もしない
                   1011:        newstp = (data & RTL8019::CR_STP);
                   1012:        newstate = state;
                   1013:        if (state == State::Normal) {
                   1014:                if (newstp) {
                   1015:                        // Normal 中に STP がセットされたらストップ状態へ移行。
                   1016:                        newstate = State::Stop;
                   1017:                }
                   1018:        } else {
                   1019:                if (newstp == false) {
                   1020:                        // Stop 中に STP がクリアされたら通常状態へ移行。
                   1021:                        // Progress もこっち?
                   1022:                        newstate = State::Normal;
                   1023:                }
                   1024:        }
                   1025:        if (loglevel >= 2) {
                   1026:                if (newstate != state) {
1.1.1.3   root     1027:                        msg += string_format(" STP=%u", newstp);
1.1       root     1028:                }
                   1029:        }
                   1030: 
                   1031:        // 表示内容が揃ったところでログ表示
                   1032:        if (loglevel >= 2) {
                   1033:                if (msg.empty()) {
                   1034:                        putlogn("CR <- $%02x", data);
                   1035:                } else {
                   1036:                        putlogn("CR <- $%02x (%s)", data, msg.c_str() + 1);
                   1037:                }
                   1038:        }
                   1039: 
                   1040:        if (dmamode == DMAMode::RemoteRead || dmamode == DMAMode::RemoteWrite) {
                   1041:                // ログ用に DMA 開始時の初期値を保存
                   1042:                remote_start_addr  = remote_addr;
                   1043:                remote_start_count = remote_count;
                   1044:        } else if (__predict_false(dmamode == DMAMode::SendPacket)) {
                   1045:                putlog(0, "CR: SendPacket Command (NOT IMPLEMENTED)");
                   1046:        }
                   1047: 
                   1048:        // RTL8019AS では STA ビットは何もせず状態を保持してるだけ?
                   1049:        cr_sta = (data & RTL8019::CR_STA);
                   1050: 
                   1051:        // XXX
                   1052:        // NetBSD の sys/dev/ic/ne2000.c::detect_ne2000() は CR.STP を下げて、
                   1053:        // ISR.RST が立つまで100回チェックしている。
                   1054:        // RTL8019AS.pdf (DP83901A.pdf も) には STP を下げると ISR.RST もクリア
                   1055:        // されると書いてあるので、このループは成立しないはず。
                   1056:        // そして 100回試しても RST が立たなかったら検出失敗に goto するところは
                   1057:        // (rev1.2 の時点から) if 0 されている (そりゃそれだと動かないからね…)。
                   1058:        // 他の互換チップのことは分からんけど、
                   1059:        // STP を下げて RST が下がるのを待つ、の間違いじゃないのかなあ。
                   1060: 
                   1061:        // XXX TXP と STP 同時にセットするとどうなる?
                   1062: 
                   1063:        // STP を立てられた時に送受信処理中でなければすぐにリセット。
                   1064:        // 処理中のものがあればそれが終わり次第そっちで変更するので
                   1065:        // ここでは対応不要。
                   1066:        if (newstate != state) {
                   1067:                ChangeState(newstate);
                   1068:        }
                   1069: 
                   1070:        // 送信開始
                   1071:        if ((data & RTL8019::CR_TXP)) {
                   1072:                Transmit();
                   1073:        }
                   1074: }
                   1075: 
                   1076: // PSTART レジスタ書き込み
                   1077: void
                   1078: RTL8019ASDevice::WritePSTART(uint32 data)
                   1079: {
                   1080:        putlog(2, "PSTART <- $%02x", data);
                   1081:        pstart_addr = data << 8;
                   1082: }
                   1083: 
                   1084: // PSTOP レジスタ書き込み
                   1085: void
                   1086: RTL8019ASDevice::WritePSTOP(uint32 data)
                   1087: {
                   1088:        putlog(2, "PSTOP  <- $%02x", data);
                   1089:        pstop_addr = data << 8;
                   1090: }
                   1091: 
                   1092: // BNRY レジスタ書き込み
                   1093: void
                   1094: RTL8019ASDevice::WriteBNRY(uint32 data)
                   1095: {
                   1096:        putlog(2, "BNRY <- $%02x", data);
                   1097:        boundary_addr = data << 8;
                   1098: }
                   1099: 
                   1100: // TPSR レジスタ書き込み
                   1101: void
                   1102: RTL8019ASDevice::WriteTPSR(uint32 data)
                   1103: {
                   1104:        putlog(2, "TPSR <- $%02x", data);
                   1105:        transmit_page_start_addr = data << 8;
                   1106: }
                   1107: 
                   1108: // TBCR0 レジスタ書き込み
                   1109: void
                   1110: RTL8019ASDevice::WriteTBCR0(uint32 data)
                   1111: {
                   1112:        transmit_byte_count &= 0xff00;
                   1113:        transmit_byte_count |= data;
                   1114: 
                   1115:        putlog(2, "TBCR0 <- $%02x (TBCR=$%04x)", data, transmit_byte_count);
                   1116: }
                   1117: 
                   1118: // TBCR1 レジスタ書き込み
                   1119: void
                   1120: RTL8019ASDevice::WriteTBCR1(uint32 data)
                   1121: {
                   1122:        transmit_byte_count &= 0x00ff;
                   1123:        transmit_byte_count |= data << 8;
                   1124: 
                   1125:        putlog(2, "TBCR1 <- $%02x (TBCR=$%04x)", data, transmit_byte_count);
                   1126: }
                   1127: 
                   1128: // ISR レジスタ書き込み
                   1129: void
                   1130: RTL8019ASDevice::WriteISR(uint32 data)
                   1131: {
                   1132:        // '1' が書き込まれたビットをクリア
                   1133:        intr_stat &= ~data;
                   1134:        // bit7 (RST) は関係ないので落としておく
                   1135:        intr_stat &= ~0x80;
                   1136: 
                   1137:        putlog(2, "ISR <- $%02x (ISR=$%02x)", data, intr_stat);
                   1138: 
                   1139:        ChangeInterrupt();
                   1140: }
                   1141: 
                   1142: // RSAR0 レジスタ書き込み
                   1143: void
                   1144: RTL8019ASDevice::WriteRSAR0(uint32 data)
                   1145: {
                   1146:        // RSAR への書き込みは実質 CRDA への書き込みで、両者は別のレジスタでは
                   1147:        // なく、よくあるリードとライトで名前が違うだけのように見える。
                   1148:        // 実際 RSAR=$4000 から $10 バイト転送後の CRDA は $4010 になっており
                   1149:        // ここから RSAR を書き込まずにもう一度 RBCR=$10 転送すると $4010 から
                   1150:        // の $10 バイトが読める。
                   1151: 
                   1152:        remote_addr &= 0xff00;
                   1153:        remote_addr |= data;
                   1154: 
                   1155:        putlog(2, "RSAR0 <- $%02x (CRDA=$%04x)", data, remote_addr);
                   1156: }
                   1157: 
                   1158: // RSAR1 レジスタ書き込み
                   1159: void
                   1160: RTL8019ASDevice::WriteRSAR1(uint32 data)
                   1161: {
                   1162:        remote_addr &= 0x00ff;
                   1163:        remote_addr |= data << 8;
                   1164: 
                   1165:        putlog(2, "RSAR1 <- $%02x (CRDA=$%04x)", data, remote_addr);
                   1166: }
                   1167: 
                   1168: // RBCR0 レジスタ書き込み
                   1169: void
                   1170: RTL8019ASDevice::WriteRBCR0(uint32 data)
                   1171: {
                   1172:        remote_count &= 0xff00;
                   1173:        remote_count |= data;
                   1174: 
                   1175:        putlog(2, "RBCR0 <- $%02x (RBCR=$%04x)", data, remote_count);
                   1176: }
                   1177: 
                   1178: // RBCR1 レジスタ書き込み
                   1179: void
                   1180: RTL8019ASDevice::WriteRBCR1(uint32 data)
                   1181: {
                   1182:        remote_count &= 0x00ff;
                   1183:        remote_count |= data << 8;
                   1184: 
                   1185:        putlog(2, "RBCR1 <- $%02x (RBCR=$%04x)", data, remote_count);
                   1186: }
                   1187: 
                   1188: // RCR レジスタ書き込み
                   1189: void
                   1190: RTL8019ASDevice::WriteRCR(uint32 data)
                   1191: {
                   1192:        putlog(2, "RCR <- $%02x", data);
                   1193:        monitor_mode = (data & RTL8019::RCR_MON);
                   1194:        promisc_mode = (data & RTL8019::RCR_PRO);
                   1195:        accept_mcast = (data & RTL8019::RCR_AM);
                   1196:        accept_bcast = (data & RTL8019::RCR_AB);
                   1197:        accept_short = (data & RTL8019::RCR_AR);
                   1198:        accept_error = (data & RTL8019::RCR_SEP);
                   1199: }
                   1200: 
                   1201: // TCR レジスタ書き込み
                   1202: void
                   1203: RTL8019ASDevice::WriteTCR(uint32 data)
                   1204: {
                   1205:        // OFST, ATD, LB1, CRC すべて未実装。
                   1206:        // ループバック(LB1:0)は 0(通常), 1(内部) のみ認めておく?
                   1207:        if ((data & 0x1d) != 0) {
                   1208:                putlog(0, "TCR <- $%02x (NOT IMPLEMENTED)", data);
                   1209:        } else {
                   1210:                putlog(2, "TCR <- $%02x", data);
                   1211:        }
                   1212:        tcr = data;
                   1213: }
                   1214: 
                   1215: // DCR レジスタ書き込み
                   1216: void
                   1217: RTL8019ASDevice::WriteDCR(uint32 data)
                   1218: {
                   1219:        // FT は NE2000 用なので不要らしい。
                   1220:        // LAS (ロングワード転送?) は RTL8019AS がサポートしてないらしい。
                   1221:        // BOS (バイトオーダ選択) は RTL8019AS がサポートしてない。
                   1222:        // ARM, LS(==0) はエミュレータ的未サポート。
                   1223:        std::string msg;
                   1224:        if ((data & RTL8019::DCR_ARM) != 0) {
                   1225:                msg += "ARM=1";
                   1226:        }
                   1227:        if ((data & RTL8019::DCR_LS) == 0) {
                   1228:                msg += "LS=0";
                   1229:        }
                   1230:        if (msg.empty() == false) {
                   1231:                putlog(0, "DCR <- $%02x (%s NOT IMPLEMENTED)", data, msg.c_str());
                   1232:        } else {
                   1233:                putlog(2, "DCR <- $%02x", data);
                   1234:        }
                   1235:        dcr = data & 0xfe;
                   1236:        // XXX WTS の設定と DMA ポートをアクセスする際のバス幅が一致してない
                   1237:        // ケースは未対応。
                   1238:        word_transfer = (data & RTL8019::DCR_WTS);
                   1239: }
                   1240: 
                   1241: // IMR レジスタ書き込み
                   1242: void
                   1243: RTL8019ASDevice::WriteIMR(uint32 data)
                   1244: {
                   1245:        putlog(2, "IMR <- $%02x", data);
                   1246:        intr_mask = data & ~0x80;
                   1247:        ChangeInterrupt();
                   1248: }
                   1249: 
                   1250: // PAR0..5 レジスタ書き込み
                   1251: void
1.1.1.3   root     1252: RTL8019ASDevice::WritePAR(uint n, uint32 data)
1.1       root     1253: {
                   1254:        par[n] = data;
                   1255: 
                   1256:        if (__predict_false(loglevel >= 3)) {
1.1.1.3   root     1257:                putlogn("PAR%u <- $%02x", n, data);
1.1       root     1258:        } else {
                   1259:                if (__predict_false(n == 5)) {
                   1260:                        putlog(2, "PAR <- %02x:%02x:%02x:%02x:%02x:%02x",
                   1261:                                par[0], par[1], par[2], par[3], par[4], par[5]);
                   1262:                }
                   1263:        }
                   1264: }
                   1265: 
                   1266: // CURR レジスタ書き込み
                   1267: void
                   1268: RTL8019ASDevice::WriteCURR(uint32 data)
                   1269: {
                   1270:        putlog(2, "CURR <- $%02x", data);
                   1271:        current_page_addr = data << 8;
                   1272:        local_addr = current_page_addr;
                   1273: }
                   1274: 
                   1275: // MAR0..7 レジスタ書き込み
                   1276: void
1.1.1.3   root     1277: RTL8019ASDevice::WriteMAR(uint n, uint32 data)
1.1       root     1278: {
1.1.1.5   root     1279:        mar &= ~(0xffULL << (n * 8));
                   1280:        mar |= (uint64)data << (n * 8);
1.1       root     1281: 
                   1282:        if (__predict_false(loglevel >= 3)) {
1.1.1.3   root     1283:                putlogn("MAR%u <- $%02x", n, data);
1.1       root     1284:        } else {
                   1285:                if (__predict_false(n == 7)) {
1.1.1.5   root     1286:                        putlog(2, "MAR <- $%08x'%08x", (uint32)(mar >> 32), (uint32)mar);
1.1       root     1287:                }
                   1288:        }
                   1289: }
                   1290: 
                   1291: // 9346CR レジスタ書き込み
                   1292: void
                   1293: RTL8019ASDevice::Write9346CR(uint32 data)
                   1294: {
                   1295:        uint32 eem = (data >> 6) & 3;
                   1296: 
                   1297:        if (eem == 3) {
                   1298:                // EEM = %11 で CONFIG1-3 への書き込みを許可。
                   1299:                config_write_enable = true;
                   1300:        } else {
                   1301:                config_write_enable = false;
                   1302:        }
                   1303: 
                   1304:        if (eem == 1 || eem == 2) {
1.1.1.3   root     1305:                putlog(0, "9346CR <- $%02x EEM=%u (NOT IMPLEMENTED)", data, eem);
1.1       root     1306:                return;
                   1307:        }
                   1308:        if ((data & 0x0f) != 0) {
                   1309:                putlog(0, "9346CR <- $%02x (NOT IMPLEMENTED)", data);
                   1310:                return;
                   1311:        }
                   1312:        putlog(2, "9346CR <- $%02x", data);
                   1313: }
                   1314: 
                   1315: void
                   1316: RTL8019ASDevice::WriteCONFIG0(uint32 data)
                   1317: {
                   1318:        if (config_write_enable == false) {
                   1319:                putlog(1, "CONFIG0 <- $%02x: Config write is disabled", data);
                   1320:                return;
                   1321:        }
                   1322: 
                   1323:        // CONFIG0 は元々読み出し専用レジスタで、このうち VERID (2bit) で
                   1324:        // RTL8019 のモデル情報が読み出せる構造だったっぽい。
                   1325:        //  %11 なら RTL8019
                   1326:        //  %00 なら RTL8019A
                   1327:        // で、RTL8019AS ではこの VERID フィールドだけ R/W に変えて、
                   1328:        // 設定によって RTL8019(無印) としても振る舞えるようにした(?)っぽい。
                   1329:        // ほんまかいな。
                   1330:        verid = data >> 6;
                   1331: 
                   1332:        if (verid != 0) {
                   1333:                putlog(2, "CONFIG0 <- $%02x VERID=%x (NOT IMPLEMENTED)", data, verid);
                   1334:        } else {
                   1335:                putlog(2, "CONFIG0 <- $%02x", data);
                   1336:        }
                   1337: }
                   1338: 
                   1339: void
                   1340: RTL8019ASDevice::WriteCONFIG1(uint32 data)
                   1341: {
                   1342:        if (config_write_enable == false) {
                   1343:                putlog(1, "CONFIG1 <- $%02x: Config write is disabled", data);
                   1344:                return;
                   1345:        }
                   1346: 
                   1347:        putlog(2, "CONFIG1 <- $%02x", data);
                   1348:        irq_enable = (data & RTL8019::CONFIG1_IRQEN);
                   1349:        ChangeInterrupt();
                   1350: }
                   1351: 
                   1352: void
                   1353: RTL8019ASDevice::WriteCONFIG2(uint32 data)
                   1354: {
                   1355:        if (config_write_enable == false) {
                   1356:                putlog(1, "CONFIG2 <- $%02x: Config write is disabled", data);
                   1357:                return;
                   1358:        }
                   1359: 
                   1360:        mediatype = (data >> 6);
                   1361:        // どのみち BS4-0 で BROM Disabled なので、BSELB の影響は受けない。
                   1362:        // 値だけ記憶しておく。
                   1363:        brom_force_disable = (data & RTL8019::CONFIG2_BSELB);
                   1364: }
                   1365: 
                   1366: void
                   1367: RTL8019ASDevice::WriteCONFIG3(uint32 data)
                   1368: {
                   1369:        if (config_write_enable == false) {
                   1370:                putlog(1, "CONFIG3 <- $%02x: Config write is disabled", data);
                   1371:                return;
                   1372:        }
                   1373: 
                   1374:        if ((data & 0x06) != 0) {
                   1375:                // SLEEP, PWRDN はサポートしていない
                   1376:                putlog(0, "CONFIG3 <- $%02x (NOT IMPLEMENTED)", data);
                   1377:        } else {
                   1378:                putlog(2, "CONFIG3 <- $%02x", data);
                   1379:        }
                   1380:        config3 = data;
                   1381: }
                   1382: 
                   1383: // DMA ポートへのバイト書き込み
                   1384: void
                   1385: RTL8019ASDevice::WriteDMA8(uint32 data)
                   1386: {
                   1387:        // DMA モードが Write でない時に書き込むとどうなる?
                   1388:        if (dmamode != DMAMode::RemoteWrite) {
                   1389:                putlog(0, "DMA <- $%02x but not RemoteWrite (NOT IMPLEMENTED)", data);
                   1390:                return;
                   1391:        }
                   1392: 
                   1393:        uint16 prev_addr = remote_addr;
                   1394:        bool written;
                   1395:        if ((remote_addr & 0x4000)) {
                   1396:                // RAM 領域。
                   1397:                if (word_transfer || (remote_addr & 1) == 0) {
                   1398:                        // WTS==1 か偶数番地なら書き込めそう。未確認。
                   1399:                        uint16 addr = remote_addr & 0xfffe;
                   1400:                        WriteRAM(addr, data);
                   1401:                } else {
                   1402:                        // 未確認。
                   1403:                }
                   1404:                written = true;
                   1405:        } else {
                   1406:                // 書き込み不可。たぶん何も起きない。
                   1407:                written = false;
                   1408:        }
                   1409:        PostDMA();
                   1410: 
                   1411:        if (__predict_false(loglevel >= 1)) {
                   1412:                if (written) {
                   1413:                        putlog(3, "DMA[$%04x] <- $%02x", prev_addr, data);
                   1414:                } else {
                   1415:                        putlogn("DMA[$%04x] <- $%02x (Not writable)", prev_addr, data);
                   1416:                }
                   1417: 
                   1418:                if (__predict_false(remote_count == 0)) {
1.1.1.3   root     1419:                        putlog(2, "DMA %u bytes transferred", remote_start_count);
1.1       root     1420:                }
                   1421:        }
                   1422: }
                   1423: 
                   1424: // DMA ポートへのワード書き込み
                   1425: void
                   1426: RTL8019ASDevice::WriteDMA16(uint32 data)
                   1427: {
                   1428:        // DMA モードが Write でない時に書き込むとどうなる?
                   1429:        if (dmamode != DMAMode::RemoteWrite) {
                   1430:                putlog(0, "DMA <- $%04x but not RemoteWrite (NOT IMPLEMENTED)", data);
                   1431:                return;
                   1432:        }
                   1433: 
                   1434:        // RTL8019AS は基本 LE で、Nereid 上でデータバスがクロスされてるはず
                   1435:        //
                   1436:        //         680x0                             RTL8019AS
                   1437:        // +---------------------+       +----------------------------------+
                   1438:        // レジスタ    データバス         データバス     (レジスタ)  内蔵メモリ
                   1439:        //         +-> D15-8: $86  -  ->  D15-8: $dd -+              +00: $86
                   1440:        //  $86dd -+                ×                +-> $dd86  ->  +01: $dd
                   1441:        //         +-> D7-0 : $dd  -  ->  D7-0 : $86 -+
                   1442: 
                   1443:        uint16 prev_addr = remote_addr;
                   1444:        bool written;
                   1445:        if ((remote_addr & 0x4000)) {
                   1446:                // RAM 領域。
                   1447:                // 書き込みは確認していないが Read 側からの推測で、
                   1448:                // 偶数番地からのアクセスは書き込めるはず。
                   1449:                // WTS==1 なら奇数番地でも A0 をマスクしたように振る舞うはず。
                   1450:                // WTS==0 で奇数番地ならおかしなことになりそう。
                   1451:                if (word_transfer || (remote_addr & 1) == 0) {
                   1452:                        uint16 addr = remote_addr & 0xfffe;
                   1453:                        WriteRAM(addr,     data >> 8);
                   1454:                        WriteRAM(addr + 1, data & 0xff);
                   1455:                } else {
                   1456:                        // XXX 何が書けるかは未調査。
                   1457:                }
                   1458:                written = true;
                   1459:        } else {
                   1460:                // 書き込み不可。たぶん何も起きない。
                   1461:                written = false;
                   1462:        }
                   1463:        PostDMA();
                   1464: 
                   1465:        if (__predict_false(loglevel >= 1)) {
                   1466:                if (written) {
                   1467:                        putlog(3, "DMA[$%04x] <- $%04x", prev_addr, data);
                   1468:                } else {
                   1469:                        putlogn("DMA[$%04x] <- $%04x (Not writable)", prev_addr, data);
                   1470:                }
                   1471: 
                   1472:                if (__predict_false(remote_count == 0)) {
1.1.1.3   root     1473:                        putlog(2, "DMA %u bytes transferred", remote_start_count);
1.1       root     1474:                }
                   1475:        }
                   1476: }
                   1477: 
                   1478: // DMA 転送後の共通処理。
                   1479: // アドレスをインクリメント、カウントをデクリメント。
                   1480: void
                   1481: RTL8019ASDevice::PostDMA()
                   1482: {
                   1483:        // DCR.WTS==0(バイト転送) なら1回、
                   1484:        // DCR.WTS==1(ワード転送) なら2回カウンタを進める。
                   1485:        // その都度 0 チェックは行う。
                   1486: 
                   1487:        // カウンタが 0 でも、1回今の remote_addr からの読み出しは出来て、
                   1488:        // ただしそれ以上は進まないので、ここにカウンタのチェックがあるっぽい。
                   1489:        //
                   1490:        // 実機でも、
                   1491:        // 1. RSAR=$4000、RBCR=$0008 をセットして CR <- RemoteDMA
                   1492:        //    -> $4000 から 8バイト読み出せて CRDA=$4008
                   1493:        // 2. CR <- RemoteDMA
                   1494:        //    -> $4008 から 1ワード(1回)読み出せて CRDA=$4008
                   1495:        // 3. RBCR=$0008 をセットして CR <- RemoteDMA
                   1496:        //    -> $4008 から 8バイト読み出せる。
                   1497:        // となる。
                   1498: 
                   1499:        int n;
                   1500: 
                   1501:        if (word_transfer) {
                   1502:                n = 2;
                   1503:        } else {
                   1504:                n = 1;
                   1505:        }
                   1506: 
                   1507:        for (int i = 0; remote_count > 0 && i < n; i++) {
                   1508:                remote_count--;
                   1509:                remote_addr++;
                   1510:                if (__predict_false(remote_addr == pstop_addr)) {
                   1511:                        remote_addr = pstart_addr;
                   1512:                }
                   1513:        }
                   1514: 
                   1515:        if (__predict_false(remote_count == 0)) {
                   1516:                dmamode = DMAMode::Complete;
                   1517:                intr_stat |= RTL8019::ISR_RDC;
                   1518:                ChangeInterrupt();
                   1519:        }
                   1520: }
                   1521: 
                   1522: uint32
                   1523: RTL8019ASDevice::PeekReg(uint32 rn) const
                   1524: {
                   1525:        switch (rn) {
                   1526:         case RTL8019::CR:              // CR は全ページで同じものが見える
                   1527:         case RTL8019::CR_1:
                   1528:         case RTL8019::CR_2:
                   1529:         case RTL8019::CR_3:
                   1530:                return PeekCR();
                   1531: 
                   1532:         case RTL8019::CLDA0:
                   1533:                return PeekCLDA() & 0xff;
                   1534:         case RTL8019::CLDA1:
                   1535:                return PeekCLDA() >> 8;
                   1536: 
                   1537:         case RTL8019::BNRY:
                   1538:                return PeekBNRY();
                   1539: 
                   1540:         case RTL8019::TSR:
                   1541:                return PeekTSR();
                   1542: 
                   1543:         case RTL8019::NCR:
                   1544:                return PeekNCR();
                   1545: 
                   1546:         case RTL8019::FIFO:
                   1547:                return PeekFIFO();
                   1548: 
                   1549:         case RTL8019::ISR:
                   1550:                return PeekISR();
                   1551: 
                   1552:         case RTL8019::CRDA0:
                   1553:                return PeekCRDA() & 0xff;
                   1554:         case RTL8019::CRDA1:
                   1555:                return PeekCRDA() >> 8;
                   1556: 
                   1557:         case RTL8019::ID0:
                   1558:                return Peek8019ID0();
                   1559:         case RTL8019::ID1:
                   1560:                return Peek8019ID1();
                   1561: 
                   1562:         case RTL8019::RSR:
                   1563:                return PeekRSR();
                   1564: 
                   1565:         case RTL8019::CNTR0:
                   1566:                return PeekCNTR(0);
                   1567:         case RTL8019::CNTR1:
                   1568:                return PeekCNTR(1);
                   1569:         case RTL8019::CNTR2:
                   1570:                return PeekCNTR(2);
                   1571: 
                   1572:         case RTL8019::PAR0
                   1573:          ... RTL8019::PAR5:
                   1574:                return PeekPAR(rn - RTL8019::PAR0);
                   1575: 
                   1576:         case RTL8019::CURR:
                   1577:                return PeekCURR();
                   1578: 
                   1579:         case RTL8019::MAR0
                   1580:          ... RTL8019::MAR7:
                   1581:                return PeekMAR(rn - RTL8019::MAR0);
                   1582: 
                   1583:         case RTL8019::PSTART_2:
                   1584:                return PeekPSTART();
                   1585: 
                   1586:         case RTL8019::PSTOP_2:
                   1587:                return PeekPSTOP();
                   1588: 
                   1589:         case RTL8019::TPSR_2:
                   1590:                return PeekTPSR();
                   1591: 
                   1592:         case RTL8019::RCR_2:
                   1593:                return PeekRCR();
                   1594: 
                   1595:         case RTL8019::TCR_2:
                   1596:                return PeekTCR();
                   1597: 
                   1598:         case RTL8019::DCR_2:
                   1599:                return PeekDCR();
                   1600: 
                   1601:         case RTL8019::IMR_2:
                   1602:                return PeekIMR();
                   1603: 
                   1604:         case RTL8019::CR9346:
                   1605:                return Peek9346CR();
                   1606: 
                   1607:         case RTL8019::BPAGE:
                   1608:                return PeekBPAGE();
                   1609: 
                   1610:         case RTL8019::CONFIG0:
                   1611:                return PeekCONFIG0();
                   1612: 
                   1613:         case RTL8019::CONFIG1:
                   1614:                return PeekCONFIG1();
                   1615: 
                   1616:         case RTL8019::CONFIG2:
                   1617:                return PeekCONFIG2();
                   1618: 
                   1619:         case RTL8019::CONFIG3:
                   1620:                return PeekCONFIG3();
                   1621: 
                   1622:         case RTL8019::CSNSAV:
                   1623:                return PeekCSNSAV();
                   1624: 
                   1625:         case 0x39:
                   1626:                return PeekReg39();
                   1627: 
                   1628:         case RTL8019::INTR:
                   1629:                return PeekINTR();
                   1630: 
                   1631:         case RTL8019::CONFIG4:
                   1632:                return PeekCONFIG4();
                   1633:        }
                   1634:        return 0xff;
                   1635: }
                   1636: 
                   1637: uint32
                   1638: RTL8019ASDevice::PeekCR() const
                   1639: {
                   1640:        uint32 data;
                   1641: 
                   1642:        // PS
                   1643:        data = pagesel << 2;
                   1644: 
                   1645:        // RD
                   1646:        switch (dmamode) {
                   1647:         case DMAMode::NotAllowed:
                   1648:                break;
                   1649:         case DMAMode::RemoteRead:
                   1650:                data |= RTL8019::CR_RD_READ;
                   1651:                break;
                   1652:         case DMAMode::RemoteWrite:
                   1653:                data |= RTL8019::CR_RD_WRITE;
                   1654:                break;
                   1655:         case DMAMode::SendPacket:
                   1656:                data |= RTL8019::CR_RD_SEND;
                   1657:                break;
                   1658:         case DMAMode::Complete:
                   1659:                data |= 0x20;
                   1660:                break;
                   1661:        }
                   1662: 
                   1663:        // TXP
                   1664:        if (tx_in_progress) {
                   1665:                data |= RTL8019::CR_TXP;
                   1666:        }
                   1667: 
                   1668:        // STA
                   1669:        data |= cr_sta;
                   1670: 
                   1671:        // STP
                   1672:        if (state == State::Stop) {
                   1673:                data |= RTL8019::CR_STP;
                   1674:        }
                   1675: 
                   1676:        return data;
                   1677: }
                   1678: 
                   1679: uint32
                   1680: RTL8019ASDevice::PeekCLDA() const
                   1681: {
                   1682:        return local_addr;
                   1683: }
                   1684: 
                   1685: uint32
                   1686: RTL8019ASDevice::PeekBNRY() const
                   1687: {
                   1688:        return boundary_addr >> 8;
                   1689: }
                   1690: 
                   1691: uint32
                   1692: RTL8019ASDevice::PeekTSR() const
                   1693: {
                   1694:        uint32 data = tsr;
                   1695: 
                   1696:        // bit5 は %0、bit1 は %1 らしい。
                   1697:        data &= ~0x20;
                   1698:        data |=  0x02;
                   1699: 
                   1700:        return data;
                   1701: }
                   1702: 
                   1703: uint32
                   1704: RTL8019ASDevice::PeekNCR() const
                   1705: {
                   1706:        // コリジョンカウンタは不要なので実装していない
                   1707:        return 0;
                   1708: }
                   1709: 
                   1710: uint32
                   1711: RTL8019ASDevice::PeekFIFO() const
                   1712: {
                   1713:        // 未実装だが $00 が読めているようだ
                   1714:        return 0;
                   1715: }
                   1716: 
                   1717: uint32
                   1718: RTL8019ASDevice::PeekISR() const
                   1719: {
                   1720:        uint32 data = intr_stat;
                   1721: 
                   1722:        // RST は、Stop 状態とバッファフルの論理和?
                   1723:        if (state == State::Stop || local_addr == boundary_addr) {
                   1724:                data |= RTL8019::ISR_RST;
                   1725:        }
                   1726: 
                   1727:        return data;
                   1728: }
                   1729: 
                   1730: uint32
                   1731: RTL8019ASDevice::PeekCRDA() const
                   1732: {
                   1733:        return remote_addr;
                   1734: }
                   1735: 
                   1736: uint32
                   1737: RTL8019ASDevice::Peek8019ID0() const
                   1738: {
                   1739:        return 0x50;
                   1740: }
                   1741: 
                   1742: uint32
                   1743: RTL8019ASDevice::Peek8019ID1() const
                   1744: {
                   1745:        return 0x70;
                   1746: }
                   1747: 
                   1748: uint32
                   1749: RTL8019ASDevice::PeekRSR() const
                   1750: {
                   1751:        uint32 data;
                   1752: 
                   1753:        data = rsr & ~0x48;
                   1754:        if (monitor_mode) {
                   1755:                data |= RTL8019::RSR_DIS;
                   1756:        }
                   1757: 
                   1758:        return data;
                   1759: }
                   1760: 
                   1761: uint32
                   1762: RTL8019ASDevice::PeekCNTR(int n) const
                   1763: {
                   1764:        return error_counter[n];
                   1765: }
                   1766: 
                   1767: uint32
                   1768: RTL8019ASDevice::PeekPAR(int n) const
                   1769: {
                   1770:        return par[n];
                   1771: }
                   1772: 
                   1773: uint32
                   1774: RTL8019ASDevice::PeekCURR() const
                   1775: {
                   1776:        return current_page_addr >> 8;
                   1777: }
                   1778: 
                   1779: uint32
                   1780: RTL8019ASDevice::PeekMAR(int n) const
                   1781: {
1.1.1.5   root     1782:        return (mar >> (n * 8)) & 0xff;
1.1       root     1783: }
                   1784: 
                   1785: uint32
                   1786: RTL8019ASDevice::PeekPSTART() const
                   1787: {
                   1788:        return pstart_addr >> 8;
                   1789: 
                   1790: }
                   1791: 
                   1792: uint32
                   1793: RTL8019ASDevice::PeekPSTOP() const
                   1794: {
                   1795:        return pstop_addr >> 8;
                   1796: }
                   1797: 
                   1798: uint32
                   1799: RTL8019ASDevice::PeekTPSR() const
                   1800: {
                   1801:        return transmit_page_start_addr >> 8;
                   1802: }
                   1803: 
                   1804: uint32
                   1805: RTL8019ASDevice::PeekRCR() const
                   1806: {
                   1807:        uint32 data = 0xc0;
                   1808: 
                   1809:        if (monitor_mode) data |= RTL8019::RCR_MON;
                   1810:        if (promisc_mode) data |= RTL8019::RCR_PRO;
                   1811:        if (accept_mcast) data |= RTL8019::RCR_AM;
                   1812:        if (accept_bcast) data |= RTL8019::RCR_AB;
                   1813:        if (accept_short) data |= RTL8019::RCR_AR;
                   1814:        if (accept_error) data |= RTL8019::RCR_SEP;
                   1815: 
                   1816:        return data;
                   1817: }
                   1818: 
                   1819: uint32
                   1820: RTL8019ASDevice::PeekTCR() const
                   1821: {
                   1822:        return 0xe0 | tcr;
                   1823: }
                   1824: 
                   1825: uint32
                   1826: RTL8019ASDevice::PeekDCR() const
                   1827: {
                   1828:        uint32 data;
                   1829: 
                   1830:        data = 0x80 | dcr;
                   1831:        if (word_transfer) data |= RTL8019::DCR_WTS;
                   1832: 
                   1833:        return data;
                   1834: }
                   1835: 
                   1836: uint32
                   1837: RTL8019ASDevice::PeekIMR() const
                   1838: {
                   1839:        return intr_mask | 0x80;
                   1840: }
                   1841: 
                   1842: uint32
                   1843: RTL8019ASDevice::Peek9346CR() const
                   1844: {
                   1845:        uint32 data = 0x30;
                   1846: 
                   1847:        // EEM は $0 か $3 のみサポート
                   1848:        if (config_write_enable) {
                   1849:                data |= 0xc0;
                   1850:        }
                   1851: 
                   1852:        return data;
                   1853: }
                   1854: 
                   1855: uint32
                   1856: RTL8019ASDevice::PeekBPAGE() const
                   1857: {
                   1858:        // 使わなそうだし、サポートもしていない
                   1859:        return 0;
                   1860: }
                   1861: 
                   1862: uint32
                   1863: RTL8019ASDevice::PeekCONFIG0() const
                   1864: {
                   1865:        // XXX 値確認
                   1866:        return (verid << 6);
                   1867: }
                   1868: 
                   1869: uint32
                   1870: RTL8019ASDevice::PeekCONFIG1() const
                   1871: {
                   1872:        uint32 data;
                   1873: 
                   1874:        // IRQS=INT1、IOS=300H
                   1875:        data = 0x10;
                   1876:        if (irq_enable) data |= RTL8019::CONFIG1_IRQEN;
                   1877: 
                   1878:        return data;
                   1879: }
                   1880: 
                   1881: uint32
                   1882: RTL8019ASDevice::PeekCONFIG2() const
                   1883: {
                   1884:        uint32 data;
                   1885: 
                   1886:        data = mediatype << 6;
                   1887:        if (brom_force_disable) {
                   1888:                data |= RTL8019::CONFIG2_BSELB;
                   1889:        }
                   1890:        // BS4-0 は 0
                   1891: 
                   1892:        return data;
                   1893: }
                   1894: 
                   1895: uint32
                   1896: RTL8019ASDevice::PeekCONFIG3() const
                   1897: {
                   1898:        uint32 data;
                   1899: 
                   1900:        data = (config3 & 0x06);
                   1901: 
                   1902:        // LEDS1=0, LEDS0=1
                   1903:        data |= 0x10;
                   1904: 
                   1905:        return data;
                   1906: }
                   1907: 
                   1908: uint32
                   1909: RTL8019ASDevice::PeekCSNSAV() const
                   1910: {
                   1911:        // サポートしていない
                   1912:        return 0;
                   1913: }
                   1914: 
                   1915: uint32
                   1916: RTL8019ASDevice::PeekReg39() const
                   1917: {
                   1918:        // データシートには何もないと書いてあるが $fe が読めるようだ
                   1919:        return 0xfe;
                   1920: }
                   1921: 
                   1922: uint32
                   1923: RTL8019ASDevice::PeekCONFIG4() const
                   1924: {
                   1925:        // IOMS=0
                   1926:        return 0xfe;
                   1927: }
                   1928: 
                   1929: uint32
                   1930: RTL8019ASDevice::PeekINTR() const
                   1931: {
                   1932:        // INT1 以外は pull up?
                   1933:        uint32 data = 0xfd;
                   1934: 
                   1935:        // 正論理でええんやろうか
                   1936:        if (interrupt->GetINT(this)) {
                   1937:                data |= 0x02;
                   1938:        }
                   1939: 
                   1940:        return data;
                   1941: }
                   1942: 
                   1943: uint32
                   1944: RTL8019ASDevice::PeekDMA(uint32 a0) const
                   1945: {
                   1946:        // DMA モードが Read でない時には何を見せる?
                   1947:        if (dmamode != DMAMode::RemoteRead) {
                   1948:                if (a0 == 0) {
                   1949:                        return 0xcc;
                   1950:                } else {
                   1951:                        return 0xdd;
                   1952:                }
                   1953:        }
                   1954: 
                   1955:        // このポートは実際にはバイトアクセスかワードアクセスかによって
                   1956:        // (か、もしくは DCR.WTS ビットによって?)、
                   1957:        // 読み出せる値が変わるが、実用上はワード転送がメインだろうと思うので、
                   1958:        // 正しくワードアクセスされたと仮定した時の値を表示しておく。
                   1959:        if (remote_addr < 0x4000) {
                   1960:                if (a0 == 0) {
                   1961:                        return ReadPROM(remote_addr);
                   1962:                } else {
                   1963:                        return 0xff;
                   1964:                }
                   1965:        } else if ((remote_addr & 0x4000)) {
                   1966:                uint32 addr = remote_addr & ~1;
                   1967:                return ReadRAM(addr + a0);
                   1968:        } else {
                   1969:                return 0xff;
                   1970:        }
                   1971: }
                   1972: 
                   1973: 
                   1974: // PROM 領域をバイトで読み出す。
                   1975: // addr は内蔵メモリ空間でのアドレス。
                   1976: uint32
                   1977: RTL8019ASDevice::ReadPROM(uint32 addr) const
                   1978: {
                   1979:        // PROM 領域は 32 バイト(16ワード) でミラー。
                   1980:        uint32 offset = (addr >> 1) & 0x0f;
                   1981:        assert(offset < prom.size());
                   1982:        return prom[offset];
                   1983: }
                   1984: 
                   1985: // 内蔵 RAM を (副作用なく) バイトで読み出す。
                   1986: // addr は内蔵メモリ空間でのアドレス。
                   1987: // 送信パケット用の読み出しにも使われる。
                   1988: inline uint32
                   1989: RTL8019ASDevice::ReadRAM(uint32 addr) const
                   1990: {
                   1991:        uint32 offset = addr & 0x3fff;
                   1992:        assert(offset < buffer.size());
                   1993:        return buffer[offset];
                   1994: }
                   1995: 
                   1996: // 内蔵 RAM に (副作用なく) バイトで書き込む。
                   1997: // addr は内蔵メモリ空間でのアドレス。
                   1998: // 受信パケットの書き込みにも使われる。
                   1999: inline void
                   2000: RTL8019ASDevice::WriteRAM(uint32 addr, uint32 data)
                   2001: {
                   2002:        uint32 offset = addr & 0x3fff;
                   2003:        assert(offset < buffer.size());
                   2004:        buffer[offset] = data;
                   2005: }
                   2006: 
                   2007: 
                   2008: // 動作状態が Stop か StopInProgress なら true を返す
                   2009: bool
                   2010: RTL8019ASDevice::IsStopOrInProgress() const
                   2011: {
                   2012:        return (state != State::Normal);
                   2013: }
                   2014: 
                   2015: // 動作状態を newstate に変更を試みる。
                   2016: // newstate には Normal か Stop を指定すること
                   2017: // (その結果 StopInProgress になるかも知れない)。
                   2018: void
                   2019: RTL8019ASDevice::ChangeState(State newstate)
                   2020: {
                   2021:        if (newstate == state) {
                   2022:                return;
                   2023:        }
                   2024: 
                   2025:        switch (newstate) {
                   2026:         case State::Normal:
                   2027:                hostnet->EnableRx(true);
                   2028:                break;
                   2029: 
                   2030:         case State::Stop:
1.1.1.8 ! root     2031:                if (tx_in_progress || rx_packet.Length() != 0) {
1.1       root     2032:                        // 処理中があれば、処理が終わるのを待つ。
                   2033:                        // (送信または受信処理完了時に Stop にする)
                   2034:                        newstate = State::StopInProgress;
                   2035:                } else {
                   2036:                        // ホストの受信を停止する
                   2037:                        hostnet->EnableRx(false);
                   2038:                }
                   2039:                break;
                   2040: 
                   2041:         default:
                   2042:                break;
                   2043:        }
                   2044:        state = newstate;
                   2045: }
                   2046: 
                   2047: // 送信開始。
                   2048: void
                   2049: RTL8019ASDevice::Transmit()
                   2050: {
                   2051:        // Stop なら送(受)信は不可。
                   2052:        // InProgress でも新たな送信は行わない
                   2053:        // (受信完了を待ってるところのかもしれないので)。
                   2054:        if (IsStopOrInProgress()) {
                   2055:                putlog(1, "Transmit not allowed due to CR.STP=1");
                   2056:                return;
                   2057:        }
                   2058: 
                   2059:        // 送信開始
                   2060:        putlog(2, "Transmit TPSR=$%02x TBCR=$%04x",
                   2061:                transmit_page_start_addr >> 8, transmit_byte_count);
                   2062: 
                   2063:        tx_packet.Clear();
                   2064:        tx_in_progress = true;
                   2065: 
                   2066:        // TSR は転送開始時にクリア (DP83901A.pdf)
                   2067:        tsr = 0;
                   2068: 
                   2069:        // 転送イベントを起こすだけ。
1.1.1.7   root     2070:        tx_event->time = 0;
1.1       root     2071:        scheduler->StartEvent(tx_event);
                   2072: 
                   2073:        // LED イベントは止まっていれば動かす。
1.1.1.7   root     2074:        if (txled_event->IsRunning() == false) {
                   2075:                txled_event->time = 0;
1.1       root     2076:                scheduler->StartEvent(txled_event);
                   2077:        }
                   2078: }
                   2079: 
                   2080: // 転送イベント。
                   2081: // TXP=1 で呼ばれて、ページごとにパケットにコピーする。
                   2082: // TBCR で指定された長さを全部コピーしたらホストに送信。
                   2083: void
1.1.1.7   root     2084: RTL8019ASDevice::TXEvent(Event *ev)
1.1       root     2085: {
                   2086:        // 今回処理する分
1.1.1.3   root     2087:        uint count = std::min((uint)transmit_byte_count, 256u);
1.1.1.8 ! root     2088:        if (count == 0 && tx_packet.Length() != 0) {
1.1       root     2089:                // 前回でコピーが完了していればここで送信。
1.1.1.8 ! root     2090:                putlog(3, "TXEvent Send %u bytes", tx_packet.Length());
1.1       root     2091:                hostnet->Tx(tx_packet);
                   2092: 
                   2093:                // 送信完了。
                   2094:                tx_in_progress = false;
                   2095:                tsr |= RTL8019::TSR_PTX;
                   2096:                intr_stat |= RTL8019::ISR_PTX;
                   2097:                ChangeInterrupt();
                   2098: 
                   2099:                // ストップ待ちなら、ストップ状態に移行を試みる
                   2100:                if (state == State::StopInProgress) {
                   2101:                        ChangeState(State::Stop);
                   2102:                }
                   2103:                return;
                   2104:        }
                   2105: 
                   2106:        // このページをパケットにコピー
                   2107:        uint32 addr = transmit_page_start_addr;
                   2108:        for (uint32 end = addr + count; addr < end; addr++) {
                   2109:                tx_packet.Append((uint8)ReadRAM(addr));
                   2110:        }
1.1.1.3   root     2111:        putlog(4, "TXEvent Copy %u bytes at page $%02x",
1.1       root     2112:                count, transmit_page_start_addr >> 8);
                   2113: 
                   2114:        // XXX TPSR, TBCR は更新されるのかどうか。
                   2115:        // とりあえず内部で必要なので使いまわしておく。
                   2116:        transmit_page_start_addr += 256;
                   2117:        transmit_byte_count -= count;
                   2118:        // XXX 折り返し
                   2119: 
                   2120:        // 転送にかかった時間を模しておく。
                   2121:        // 時間は適当。10Mbps なので 1バイトあたり 1usec とする。
1.1.1.8 ! root     2122:        tx_event->time = usec_to_tsec(count);
1.1       root     2123:        scheduler->StartEvent(tx_event);
                   2124: }
                   2125: 
1.1.1.2   root     2126: // パケット受信通知。HostNet から (EthernetDevice 経由で) 呼ばれる。
1.1       root     2127: void
1.1.1.2   root     2128: RTL8019ASDevice::RxMessage(MessageID msgid, uint32 arg)
1.1       root     2129: {
                   2130:        // 受信イベントが止まっていれば動かす。
                   2131:        // 受信イベントがすでに動いていれば、1パケット受信完了後に
                   2132:        // ホストキューを確認するので、ここでは何もしなくてよい。
1.1.1.7   root     2133:        if (rx_event->IsRunning() == false) {
                   2134:                rx_event->time = 0;
1.1       root     2135:                scheduler->StartEvent(rx_event);
                   2136:        }
                   2137: }
                   2138: 
                   2139: // 受信イベント。
                   2140: //
                   2141: // rx_packet の length, remain によって状態マシンになっている。
                   2142: //
                   2143: // len == 0                                    : 受信中でない。ホストキューから読み出せる
                   2144: // len != 0, remain == len     : 受信パケットのコピー (1ページ目)。ヘッダも出力
                   2145: // len != 0, remain < len      : 受信パケットのコピー (2ページ目以降)
                   2146: // len != 0, remain == 0       : 受信パケットのコピー完了直後。
                   2147: void
1.1.1.7   root     2148: RTL8019ASDevice::RXEvent(Event *ev)
1.1       root     2149: {
1.1.1.3   root     2150:        uint remain;
1.1       root     2151: 
1.1.1.8 ! root     2152:        if (rx_packet.Length() == 0) {
1.1       root     2153:                // パケットが空の時に呼ばれたら、
                   2154:                // ホストキューから1パケット取り出してみる。
                   2155:                if (hostnet->Rx(&rx_packet) == false) {
                   2156:                        // 取り出せなくなったら、ここでイベントを停止。
                   2157:                        rx_packet.Clear();
                   2158:                        return;
                   2159:                }
                   2160: 
                   2161:                // 取り出したらそのまま処理する。
                   2162:                // ここがパケット受信処理開始なので RSR をクリア。
                   2163:                rsr = 0;
                   2164: 
                   2165:                // 受信 LED イベントが止まっていれば動かす。
                   2166:                // 取り出して、破棄するかもしれないより前。
1.1.1.7   root     2167:                if (rxled_event->IsRunning() == false) {
                   2168:                        rxled_event->time = 0;
1.1       root     2169:                        scheduler->StartEvent(rxled_event);
                   2170:                }
                   2171: 
                   2172:                // 受信無効中ならカウンタを上げてから、パケットを破棄。
                   2173:                if (monitor_mode) {
                   2174:                        rsr |= RTL8019::RSR_MPA;
                   2175:                        rsr &= ~RTL8019::RSR_PRX;       // 念のため
                   2176:                        IncCounter(2);
                   2177: 
                   2178:                        intr_stat |= RTL8019::ISR_RXE;
                   2179:                        ChangeInterrupt();
                   2180: 
                   2181:                        goto discard;
                   2182:                }
                   2183:        }
                   2184: 
1.1.1.8 ! root     2185:        assert(rx_packet.Length() != 0);
1.1       root     2186:        remain = rx_packet.GetRemain();
                   2187:        if (remain != 0) {
                   2188:                // 実際に書き込む前に、これから書き込むページ(local_addr) が
                   2189:                // BNRY (ホストがまだ読んでない受信済みページ に追いついていたら、
                   2190:                // 受信バッファオーバーフロー。
                   2191:                if (local_addr == boundary_addr) {
                   2192:                        putlog(2, "Receive ring overflow: CURR=$%02x BNRY=$%02x",
                   2193:                                local_addr >> 8, boundary_addr >> 8);
                   2194: 
                   2195:                        rsr |= RTL8019::RSR_MPA;
                   2196:                        rsr &= ~RTL8019::RSR_PRX;       // 念のため
                   2197:                        IncCounter(2);
                   2198: 
                   2199:                        // RST は自動的にセットされる
                   2200:                        intr_stat |= RTL8019::ISR_OVW | RTL8019::ISR_RXE;
                   2201:                        ChangeInterrupt();
                   2202: 
                   2203:                        goto discard;
                   2204:                }
                   2205: 
1.1.1.8 ! root     2206:                if (remain == rx_packet.Length()) {
1.1       root     2207:                        // 初回処理
1.1.1.3   root     2208:                        RXHead();
1.1       root     2209:                }
1.1.1.2   root     2210:                RXCopy(ev, remain);
1.1       root     2211:        } else {
1.1.1.2   root     2212:                RXDone(ev);
1.1       root     2213:        }
                   2214:        return;
                   2215: 
                   2216:  discard:
                   2217:        // パケットを破棄する。
                   2218:        // この場合も、ホストキューから次のパケットを引き取る作業は必要。
                   2219:        // XXX 間隔は適当
                   2220:        rx_packet.Clear();
1.1.1.7   root     2221:        ev->time = 1_usec;
1.1.1.2   root     2222:        scheduler->RestartEvent(ev);
1.1       root     2223: }
                   2224: 
                   2225: // パケット受信の初回。
                   2226: // 4バイトの受信ヘッダをバッファに書き込む。
                   2227: void
1.1.1.3   root     2228: RTL8019ASDevice::RXHead()
1.1       root     2229: {
                   2230:        // 先に、このパケットの次のページ位置を求めて覚えておく。
1.1.1.8 ! root     2231:        next_page_addr = local_addr + 4 + rx_packet.Length();
1.1       root     2232:        next_page_addr = roundup(next_page_addr, 256);
                   2233:        if (next_page_addr >= pstop_addr) {
                   2234:                next_page_addr = pstart_addr + (next_page_addr - pstop_addr);
                   2235:        }
                   2236: 
                   2237:        // 受信ヘッダは転送完了後に書き込むため、空けておく。
                   2238:        // XXX ゼロクリアするかどうか
                   2239:        local_addr += 4;
                   2240: }
                   2241: 
                   2242: // 受信パケットをバッファにコピー。
                   2243: // 1ページ埋めるかパケットをコピーし終えたら次へ。
                   2244: // (初回もヘッダ書き込みに続いて呼ばれる)
                   2245: void
1.1.1.7   root     2246: RTL8019ASDevice::RXCopy(Event *ev, uint remain)
1.1       root     2247: {
                   2248:        // パケットをこのページにコピー。
                   2249:        // 今回処理する分はパケットの残りとページの残りの小さいほう。
1.1.1.3   root     2250:        uint count = std::min(remain, 0x100U - (local_addr & 0xff));
                   2251:        putlog(4, "RXEvent Copy %u bytes at page $%02x", count, local_addr >> 8);
1.1       root     2252:        for (uint32 end = local_addr + count; local_addr < end; ) {
                   2253:                WriteRAM(local_addr++, rx_packet.Read());
                   2254:        }
                   2255: 
                   2256:        // パケットの最後に到達したらポインタだけここで次ページへ。
                   2257:        // PSTOP 折り返し処理の前にやっておくため。
                   2258:        // (パケットの受信完了処理自体は次のループの先頭で行う)
                   2259:        if (rx_packet.GetRemain() == 0) {
                   2260:                local_addr = roundup(local_addr, 256);
                   2261:        }
                   2262: 
                   2263:        // PSTOP に到達したら PSTART に折り返す。
                   2264:        if (local_addr >= pstop_addr) {
                   2265:                local_addr = pstart_addr;
                   2266:        }
                   2267: 
                   2268:        // 転送にかかった時間を模しておく。
                   2269:        // 時間は適当。10Mbps なので 1バイトあたり 1usec とする。
1.1.1.8 ! root     2270:        ev->time = usec_to_tsec(count);
1.1.1.2   root     2271:        scheduler->RestartEvent(ev);
1.1       root     2272: }
                   2273: 
                   2274: // 受信パケットをバッファにコピーし終えた次のターンで呼ばれる。
                   2275: // 完了処理をして、ストップ待ちならストップ状態に移行。
                   2276: // ストップ待ちでなければ再び RXEvent() イベントを呼び、
                   2277: // 次パケットの処理を継続する。
                   2278: void
1.1.1.7   root     2279: RTL8019ASDevice::RXDone(Event *ev)
1.1       root     2280: {
                   2281:        // 前回でコピーが完了していればここで通知。
1.1.1.8 ! root     2282:        uint length = rx_packet.Length();
        !          2283:        putlog(3, "RXDone Received %u bytes", length);
1.1       root     2284: 
                   2285:        // 受信ヘッダに書き込む前に RSR を更新
                   2286:        rsr |= RTL8019::RSR_PRX;
1.1.1.8 ! root     2287:        if ((rx_packet.Peek(0) & 0x01)) {
1.1.1.5   root     2288:                rsr |= RTL8019::RSR_PHY;
                   2289:        }
1.1       root     2290:        // 念のためエラービットをクリア (DP83901A.pdf)
                   2291:        rsr &= ~(RTL8019::RSR_MPA |
                   2292:                 RTL8019::RSR_FAE |
                   2293:                 RTL8019::RSR_CRC);
                   2294: 
                   2295:        // XXX Receive Status には、正常受信時は RSR を書き込む。
                   2296:        // エラー時はまだ見てない (DP83901A.pdf)
                   2297: 
                   2298:        // 受信ヘッダを書き込む。
                   2299:        // このパケット受信中は CURR は更新しないので、これが使える。
                   2300:        //
                   2301:        // メモリ上のバイト順で次の通り。
                   2302:        // +0: Receive Status
                   2303:        // +1: 次の受信ページ
                   2304:        // +2: 受信バイト長(L)
                   2305:        // +3: 受信バイト長(H)
                   2306:        //
                   2307:        // ワード (Little Endian) 表記:
                   2308:        //     D15         D8   D7          D0
                   2309:        // +0: 次の受信ページ   Receive Status
                   2310:        // +2: 受信バイト長(H)  受信バイト長(L)
                   2311:        uint16 addr = current_page_addr;
                   2312:        WriteRAM(addr++, rsr);
                   2313:        WriteRAM(addr++, next_page_addr >> 8);
1.1.1.8 ! root     2314:        WriteRAM(addr++, length & 0xff);
        !          2315:        WriteRAM(addr++, length >> 8);
1.1       root     2316: 
                   2317:        // CURR を次受信ページに更新。残り転送バイトが 0 になった時点で
                   2318:        // local_addr は次ページ先頭に繰り上げてある。
                   2319:        current_page_addr = local_addr;
                   2320: 
                   2321:        rx_packet.Clear();
                   2322: 
                   2323:        // 受信完了。
                   2324:        intr_stat |= RTL8019::ISR_PRX;
                   2325:        ChangeInterrupt();
                   2326: 
                   2327:        if (state == State::StopInProgress) {
                   2328:                // ストップ待ちなら、ストップ状態に移行を試みる
                   2329:                ChangeState(State::Stop);
                   2330:        } else {
                   2331:                // そうでなければ、次の受信を試す。
1.1.1.8 ! root     2332:                // (rx_packet.Length() == 0 で RXEvent() を呼ぶとパケット受信となる)
1.1       root     2333: 
                   2334:                // どのくらいか待つ? 値は適当
1.1.1.7   root     2335:                ev->time = 100_usec;
1.1.1.2   root     2336:                scheduler->RestartEvent(ev);
1.1       root     2337:        }
                   2338: }
                   2339: 
1.1.1.5   root     2340: // この宛先アドレスを受信するかどうか。
                   2341: // これは HostNet スレッドで呼ばれる。
                   2342: int
                   2343: RTL8019ASDevice::HWAddrFilter(const MacAddr& dstaddr) const
                   2344: {
                   2345:        // RTL8019AS.pdf では詳細不明だが、
                   2346:        // DP83901A.pdf には、完全なプロミスキャスにするには AB, AM, PRO 全部
                   2347:        // 立ててさらにマルチキャストハッシュを全部 1 にしろ、と注釈があるので、
                   2348:        // - PRO は自分宛て以外のユニキャストを受け取るかどうか、
                   2349:        // - AM は、ハッシュで accept になったマルチキャストを受け取るか
                   2350:        //   マルチキャストを一切受け取らないか、
                   2351:        // - AB はブロードキャストを受け取るかどうか、
                   2352:        // の独立したビットのようだ。
                   2353: 
                   2354:        if (dstaddr.IsUnicast()) {
                   2355:                if (promisc_mode == false) {
                   2356:                        if (dstaddr != par) {
                   2357:                                return HPF_DROP_UNICAST;
                   2358:                        }
                   2359:                }
                   2360:        } else {
                   2361:                if (dstaddr.IsBroadcast()) {
                   2362:                        if (accept_bcast == false) {
                   2363:                                // XXX 選択肢がまだない
                   2364:                                return HPF_DROP_MULTICAST;
                   2365:                        }
                   2366:                } else {
                   2367:                        if (accept_mcast == false) {
                   2368:                                return HPF_DROP_MULTICAST;
                   2369:                        }
                   2370: 
                   2371:                        // マルチキャスト
                   2372:                        //
                   2373:                        // RTL8019AS のマルチキャストフィルタ(ハッシュ) は宛先 MAC
                   2374:                        // アドレスの CRC (32ビット) のうち上位6ビットを pos として、
                   2375:                        // MAR の下から pos ビット目が立っていれば受理する、というもの。
                   2376:                        //
                   2377:                        //                    31  30  29  28  27  26  25  24      0
                   2378:                        //                  +---+---+---+---+---+---+---+---+--   --+
                   2379:                        // CRC32(dstaddr) = | p5| p4| p3| p2| p1| p0| X   X |  ..   |
                   2380:                        //                  +---+---+---+---+---+---+---+---+--   --+
                   2381:                        //
                   2382:                        //                  +---+---+---+---+---+---+
                   2383:                        //           pos  = | p5| p4| p3| p2| p1| p0|
                   2384:                        //                  +---+---+---+---+---+---+
                   2385: 
                   2386:                        uint32 crc = EthernetDevice::CRC32(dstaddr);
                   2387:                        uint pos = crc >> 26;
                   2388:                        bool mcast_pass = (mar & (1ULL << pos));
                   2389:                        putmsg(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%u %s",
                   2390:                                dstaddr[0], dstaddr[1], dstaddr[2],
                   2391:                                dstaddr[3], dstaddr[4], dstaddr[5],
                   2392:                                pos, (mcast_pass ? "pass" : "drop"));
                   2393:                        if (mcast_pass == false) {
                   2394:                                return HPF_DROP_MULTICAST;
                   2395:                        }
                   2396:                }
                   2397:        }
                   2398: 
                   2399:        return HPF_PASS;
                   2400: }
                   2401: 
1.1       root     2402: // 送信 LED イベント
                   2403: void
1.1.1.7   root     2404: RTL8019ASDevice::TXLedEvent(Event *ev)
1.1       root     2405: {
                   2406:        if (tx_led == false) {
                   2407:                // 消灯中だったら、次は 6msec 点灯
                   2408:                tx_led = true;
1.1.1.7   root     2409:                ev->time = 6_msec;
1.1.1.2   root     2410:                scheduler->RestartEvent(ev);
1.1       root     2411:        } else {
                   2412:                // 点灯中だったら
                   2413:                // - 送信中なら次は 100msec 消灯
                   2414:                // - 送信中でなければここで終わり
                   2415:                if (tx_in_progress) {
                   2416:                        tx_led = false;
1.1.1.7   root     2417:                        ev->time = 100_msec;
1.1.1.2   root     2418:                        scheduler->RestartEvent(ev);
1.1       root     2419:                }
                   2420:        }
                   2421: }
                   2422: 
                   2423: // 受信 LED イベント
                   2424: void
1.1.1.7   root     2425: RTL8019ASDevice::RXLedEvent(Event *ev)
1.1       root     2426: {
                   2427:        if (rx_led == false) {
                   2428:                // 消灯中だったら、次は 6msec 点灯
                   2429:                rx_led = true;
1.1.1.7   root     2430:                ev->time = 6_msec;
1.1.1.2   root     2431:                scheduler->RestartEvent(ev);
1.1       root     2432:        } else {
                   2433:                // 点灯中だったら
                   2434:                // - 受信中なら次は 100msec 消灯
                   2435:                // - 受信中でなければここで終わり
1.1.1.8 ! root     2436:                if (rx_packet.Length() != 0) {
1.1       root     2437:                        rx_led = false;
1.1.1.7   root     2438:                        ev->time = 100_msec;
1.1.1.2   root     2439:                        scheduler->RestartEvent(ev);
1.1       root     2440:                }
                   2441:        }
                   2442: }
                   2443: 
                   2444: 
                   2445: // 実際のボードの割り込みは、SL811HS/T もいるので NereidBoard が一旦受けて
                   2446: // いると思うが、それを忠実に真似すると
                   2447: // RTL8019AS -> NereidBoard -> X68030Interrupt のようなカスケードになり、
                   2448: // それはちょっと手間なので、ここでは NereidBoard の DIPSW で決まる割り込み
                   2449: // ベクタの値だけ NereidBoard から事前に受け取っておいて、あとは
                   2450: // InterruptDevice と直接やりとりする。
                   2451: 
                   2452: // 割り込み信号線の状態を変える。
                   2453: // intr_stat、intr_mask、irq_enable が更新されたら呼ぶこと。
                   2454: void
                   2455: RTL8019ASDevice::ChangeInterrupt()
                   2456: {
                   2457:        if (irq_enable) {
1.1.1.2   root     2458:                bool irq = ((intr_stat & intr_mask) != 0);
                   2459:                interrupt->ChangeINT(this, irq);
1.1       root     2460:        } else {
                   2461:                // IRQEN が 0 だと出力がハイインピーダンスになる。
                   2462:                interrupt->AssertINT(this);
                   2463:        }
                   2464: }
                   2465: 
                   2466: // 割り込みアクノリッジ
1.1.1.2   root     2467: busdata
1.1       root     2468: RTL8019ASDevice::InterruptAcknowledge()
                   2469: {
                   2470:        return intr_vector;
                   2471: }
                   2472: 
                   2473: // エラーカウンタをインクリメントする。
                   2474: void
                   2475: RTL8019ASDevice::IncCounter(int n)
                   2476: {
                   2477:        error_counter[n]++;
                   2478: 
                   2479:        // XXX DP83901A はカウンタが $c0 になったらカウントとめるらしい。
                   2480:        // RTL8019AS/AX88196B には記述なし。要動作確認。
                   2481: 
                   2482:        // いずれかカウンタの MSB が立ったら割り込み
                   2483:        uint32 c = error_counter[0] | error_counter[1] | error_counter[2];
                   2484:        if ((c & 0x80) != 0) {
                   2485:                intr_stat |= RTL8019::ISR_CNT;
                   2486:        } else {
                   2487:                // 書いてはないけど、たぶん OR したのが繋がってるだけだとしたら
                   2488:                // 最上位ビットがいずれも立たなくなったら、CNT も勝手に下がるはず?
                   2489:                intr_stat &= ~RTL8019::ISR_CNT;
                   2490:        }
                   2491:        ChangeInterrupt();
                   2492: }
                   2493: 
                   2494: // 読み込み時のレジスタ名を返す (rn はページ番号込み)
                   2495: /*static*/ std::string
                   2496: RTL8019ASDevice::RegNameR(int rn)
                   2497: {
                   2498:        if (regnames[rn]) {
                   2499:                return std::string(regnames[rn]);
                   2500:        } else {
                   2501:                return string_format("(%02x)", rn);
                   2502:        }
                   2503: }
                   2504: 
                   2505: // 書き込み時のレジスタ名を返す (rn はページ番号込み)
                   2506: /*static*/ std::string
                   2507: RTL8019ASDevice::RegNameW(int rn)
                   2508: {
                   2509:        int page = rn >> 4;
                   2510:        int n    = rn & 0xf;
                   2511: 
                   2512:        // Page1 は R/W 共通
                   2513:        if (page == 1) {
                   2514:                return RegNameR(rn);
                   2515:        }
                   2516: 
                   2517:        // Page2 は ReadOnly レジスタなので名前はない。
                   2518:        if (page == 2) {
                   2519:                return string_format("%02x", rn);
                   2520:        }
                   2521: 
                   2522:        // Page0, Page3 のレジスタ名はオフセットしたところに置いてある。
                   2523:        int offset = (page == 0) ? 0x40 : 0x50;
                   2524:        if (regnames[offset + n]) {
                   2525:                return std::string(regnames[offset + n]);
                   2526:        } else {
                   2527:                return string_format("(%02x)", rn);
                   2528:        }
                   2529: }
                   2530: 
                   2531: /*static*/ const char * const
                   2532: RTL8019ASDevice::regnames[] = {
                   2533:        "CR",           // 0 Page0(Read側)
                   2534:        "CLDA0",        // 1
                   2535:        "CLDA1",        // 2
                   2536:        "BNRY",         // 3
                   2537:        "TSR",          // 4
                   2538:        "NCR",          // 5
                   2539:        "FIFO",         // 6
                   2540:        "ISR",          // 7
                   2541:        "CRDA0",        // 8
                   2542:        "CRDA1",        // 9
                   2543:        "8019ID0",      // a
                   2544:        "8019ID1",      // b
                   2545:        "RSR",          // c
                   2546:        "CNTR0",        // d
                   2547:        "CNTR1",        // e
                   2548:        "CNTR2",        // f
                   2549: 
                   2550:        "CR",           // 0 Page1(R/W共通)
                   2551:        "PAR0",         // 1
                   2552:        "PAR1",         // 2
                   2553:        "PAR2",         // 3
                   2554:        "PAR3",         // 4
                   2555:        "PAR4",         // 5
                   2556:        "PAR5",         // 6
                   2557:        "CURR",         // 7
                   2558:        "MAR0",         // 8
                   2559:        "MAR1",         // 9
                   2560:        "MAR2",         // a
                   2561:        "MAR3",         // b
                   2562:        "MAR4",         // c
                   2563:        "MAR5",         // d
                   2564:        "MAR6",         // e
                   2565:        "MAR7",         // f
                   2566: 
                   2567:        "CR",           // 0 Page2(Read Only)
                   2568:        "PSTART",       // 1
                   2569:        "PSTOP",        // 2
                   2570:        NULL,           // 3
                   2571:        "TPSR",         // 4
                   2572:        NULL,           // 5
                   2573:        NULL,           // 6
                   2574:        NULL,           // 7
                   2575:        NULL,           // 8
                   2576:        NULL,           // 9
                   2577:        NULL,           // a
                   2578:        NULL,           // b
                   2579:        "RCR",          // c
                   2580:        "TCR",          // d
                   2581:        "DCR",          // e
                   2582:        "IMR",          // f
                   2583: 
                   2584:        "CR",           // 0 Page3(Read側)
                   2585:        "9346CR",       // 1
                   2586:        "BPAGE",        // 2
                   2587:        "CONFIG0",      // 3
                   2588:        "CONFIG1",      // 4
                   2589:        "CONFIG2",      // 5
                   2590:        "CONFIG3",      // 6
                   2591:        NULL,           // 7
                   2592:        "CSNSAV",       // 8
                   2593:        NULL,           // 9
                   2594:        NULL,           // a
                   2595:        "INTR",         // b
                   2596:        NULL,           // c
                   2597:        "CONFIG4",      // d
                   2598:        NULL,           // e
                   2599:        NULL,           // f
                   2600: 
                   2601:        "CR",           // 0 Page0(Write側)
                   2602:        "PSTART",       // 1
                   2603:        "PSTOP",        // 2
                   2604:        "BNRY",         // 3
                   2605:        "TPSR",         // 4
                   2606:        "TBCR0",        // 5
                   2607:        "TBCR1",        // 6
                   2608:        "ISR",          // 7
                   2609:        "RSAR0",        // 8
                   2610:        "RSAR1",        // 9
                   2611:        "RBCR0",        // a
                   2612:        "RBCR1",        // b
                   2613:        "RCR",          // c
                   2614:        "TCR",          // d
                   2615:        "DCR",          // e
                   2616:        "IMR",          // f
                   2617: 
                   2618:        "CR",           // 0 Page3(Write側)
                   2619:        "9346CR",       // 1
                   2620:        "BPAGE",        // 2
                   2621:        "CONFIG0",      // 3
                   2622:        "CONFIG1",      // 4
                   2623:        "CONFIG2",      // 5
                   2624:        "CONFIG3",      // 6
                   2625:        "TEST",         // 7
                   2626:        NULL,           // 8
                   2627:        "HLTCLK",       // 9
                   2628:        NULL,           // a
                   2629:        NULL,           // b
                   2630:        "FMWP",         // c
                   2631:        NULL,           // d
                   2632:        NULL,           // e
                   2633:        NULL,           // f
                   2634: };
                   2635: 
                   2636: // CR_RD (DMAMode) の名前を返す
                   2637: /*static*/ const char *
                   2638: RTL8019ASDevice::GetDMAName(uint32 mode)
                   2639: {
                   2640:        static const char * const rd_str[] = {
                   2641:        //   01234567890
                   2642:                "NotAllowed",
                   2643:                "RemoteRead",
                   2644:                "RemoteWrite",
                   2645:                "SendPacket",
                   2646:                "Complt/Abrt",
                   2647:        };
                   2648: 
                   2649:        if (mode > 4) {
                   2650:                return rd_str[4];
                   2651:        } else {
                   2652:                return rd_str[mode];
                   2653:        }
                   2654: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.