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

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

unix.superglobalmegacorp.com

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