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