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