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