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