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