|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.