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