|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.11 root 7: //
8: // Lance (AM7990)
9: //
10:
1.1 root 11: #include "lance.h"
1.1.1.11 root 12: #include "bitops.h"
1.1.1.7 root 13: #include "interrupt.h"
1.1.1.13 root 14: #include "mainbus.h"
1.1.1.17 root 15: #include "monitor.h"
1.1.1.11 root 16: #include "scheduler.h"
1.1.1.13 root 17: #include "subram.h"
1.1 root 18:
1.1.1.11 root 19: // コンストラクタ
1.1 root 20: LanceDevice::LanceDevice()
1.1.1.14 root 21: : inherited(OBJ_ETHERNET(0))
1.1 root 22: {
1.1.1.13 root 23: SetName("Lance");
24: ClearAlias();
25: AddAlias("Lance");
1.1.1.9 root 26: AddAlias("Ethernet");
1.1 root 27:
1.1.1.17 root 28: monitor = gMonitorManager->Regist(ID_MONITOR_LANCE, this);
29: monitor->func = ToMonitorCallback(&LanceDevice::MonitorUpdate);
30: monitor->SetSize(80, 34);
1.1 root 31: }
32:
1.1.1.11 root 33: // デストラクタ
1.1 root 34: LanceDevice::~LanceDevice()
35: {
36: }
37:
1.1.1.13 root 38: // 初期化
1.1 root 39: bool
40: LanceDevice::Init()
41: {
1.1.1.13 root 42: interrupt = GetInterruptDevice();
43: subram = GetSubRAMDevice();
1.1 root 44:
1.1.1.19! root 45: hostnet->SetPortName("Lance");
! 46:
1.1.1.13 root 47: // ホストからの受信コールバックを登録
1.1.1.14 root 48: scheduler->ConnectMessage(MessageID::HOSTNET_RX(0), this,
1.1.1.15 root 49: ToMessageCallback(&LanceDevice::RxMessage));
1.1 root 50:
1.1.1.16 root 51: // func, time は都度設定する
52: rx_event.SetName("Lance RX");
53: tx_event.SetName("Lance TX");
54: scheduler->RegistEvent(rx_event);
55: scheduler->RegistEvent(tx_event);
56:
1.1 root 57: return true;
58: }
59:
1.1.1.11 root 60: // リセット
1.1 root 61: void
1.1.1.11 root 62: LanceDevice::ResetHard(bool poweron)
1.1 root 63: {
64: reg.rap = 0;
65: ChipStop();
66: }
67:
1.1.1.15 root 68: busdata
1.1.1.16 root 69: LanceDevice::ReadPort(uint32 offset)
1.1 root 70: {
1.1.1.15 root 71: busdata data;
1.1 root 72:
1.1.1.8 root 73: switch (offset) {
1.1 root 74: case 0: // RDP
75: data = ReadData();
1.1.1.15 root 76: break;
1.1.1.3 root 77: case 1: // RAP
1.1 root 78: data = reg.rap;
1.1.1.16 root 79: putlog(2, "RAP -> %u", reg.rap);
1.1.1.15 root 80: break;
1.1.1.11 root 81: default:
1.1.1.16 root 82: VMPANIC("corrupted offset=%u", offset);
1.1.1.15 root 83: data = 0xffff;
84: break;
1.1 root 85: }
1.1.1.15 root 86:
87: // XXX wait?
1.1.1.16 root 88: data |= BusData::Size2;
1.1.1.15 root 89: return data;
1.1 root 90: }
91:
1.1.1.15 root 92: busdata
1.1.1.16 root 93: LanceDevice::WritePort(uint32 offset, uint32 data)
1.1 root 94: {
1.1.1.8 root 95: switch (offset) {
1.1 root 96: case 0: // RDP
97: WriteData(data);
1.1.1.15 root 98: break;
1.1.1.3 root 99: case 1: // RAP
1.1 root 100: reg.rap = data & 3;
1.1.1.15 root 101: break;
1.1.1.11 root 102: default:
1.1.1.16 root 103: VMPANIC("corrupted offset=%u", offset);
1.1.1.15 root 104: break;
1.1 root 105: }
1.1.1.15 root 106:
1.1.1.16 root 107: busdata r = BusData::Size2;
1.1.1.15 root 108: // XXX wait?
1.1.1.16 root 109: return r;
1.1 root 110: }
111:
1.1.1.15 root 112: busdata
1.1.1.16 root 113: LanceDevice::PeekPort(uint32 offset)
1.1 root 114: {
1.1.1.8 root 115: switch (offset) {
1.1.1.3 root 116: case 0: // RDP
117: // 今読めるはずのデータ。
118: // CSR[123] は STOP 中でなければ不定だがとりあえずそれは無視。
119: switch (reg.rap) {
120: case 0:
121: return reg.GetCSR0();
122: case 1:
123: return reg.iadr & 0xffff;
124: case 2:
125: return reg.iadr >> 16;
126: case 3:
127: return reg.csr3;
1.1.1.11 root 128: default:
1.1.1.13 root 129: break;
1.1.1.3 root 130: }
131: break;
132: case 1: // RAP
133: return reg.rap;
1.1.1.11 root 134: default:
1.1.1.13 root 135: break;
1.1.1.3 root 136: }
1.1.1.13 root 137: return 0xff;
1.1 root 138: }
139:
1.1.1.5 root 140: void
1.1.1.9 root 141: LanceDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 142: {
143: /*
144: CSR0: $1111 ERR BABL CERR MISS MERR RINT TINT IDON IADR:$123456
145: CSR3:$0004 BSWP ACON BCON
146:
147: MODE: $0000 PROM INTL DRTY COLL DTCR LOOP DTX DRX
1.1.1.15 root 148: PADR: 00:11:22:33:44:55 RDRP: $12345678 (RDRA=$123456 entries=32)
149: LADRF:$fedcba98'76543210 TDRP:
1.1 root 150:
151: <RMD> Current 00 OWN ERR OFLO CRC BUFF STP ENP BCNT=$123 MCNT=$123 buf=$123456
152: 01234567890123456789012345678901234567890 00
153: 00 OVCBSE $12345 $123/$123 00 OVCBSE $12345 $123/$123
154: <TMD> Current 00 OWN ERR STP ENP BUFF UFLO BCNT=$123 buf=$123456
155: 00 OSEBU $12345 $123
156: */
157:
158: // name を表示。(var & bit) ならオン(反転)表示。
159: // bitpos は 0..15 で [0] が MSB にあたる。
160: #define MonitorBit(var, bit, name) do { \
1.1.1.9 root 161: screen.Puts(x, y, TA::OnOff((var) & (bit)), name); \
1.1 root 162: x += strlen(name) + 1; \
163: } while (0)
164:
165: int x;
166: int y;
167: int i;
168:
1.1.1.9 root 169: screen.Clear();
1.1 root 170:
171: y = 0;
172: // CSR
173: uint16 csr0 = reg.GetCSR0();
1.1.1.9 root 174: screen.Print(0, y, "CSR0:$%04x", csr0);
175: MonitorReg(screen, 11, y, csr0 >> 8, csr0names);
176: MonitorReg(screen, 11, y + 1, csr0, csr0names + 8);
1.1 root 177:
1.1.1.9 root 178: screen.Print(54, y++, "IADR:$%06x", reg.iadr);
179: screen.Print(54, y, "CSR3:$%04x", reg.csr3);
1.1 root 180: // CSR3 は下位3ビットだけなので手動で配置
181: x = 65;
182: MonitorBit(reg.csr3, AM7990::CSR3_BSWP, csr3names[13]);
183: MonitorBit(reg.csr3, AM7990::CSR3_ACON, csr3names[14]);
184: MonitorBit(reg.csr3, AM7990::CSR3_BCON, csr3names[15]);
185: y++;
186:
1.1.1.9 root 187: screen.Puts(0, y, "<Initial Block>");
1.1 root 188: y++;
189: // MODE は bit15 と bit6-0 の8ビットだけ使われてるので
190: // 途中を省略して 8ビットとして表示する
1.1.1.9 root 191: screen.Print(0, y, "MODE:$%04x", initblock[0]);
1.1 root 192: x = 11;
193: MonitorBit(initblock[0], AM7990::IBMODE_PROM, ib_mode_names[0]);
194: MonitorBit(initblock[0], AM7990::IBMODE_INTL, ib_mode_names[1]);
195: MonitorBit(initblock[0], AM7990::IBMODE_DRTY, ib_mode_names[2]);
196: MonitorBit(initblock[0], AM7990::IBMODE_COLL, ib_mode_names[3]);
197: MonitorBit(initblock[0], AM7990::IBMODE_DTCR, ib_mode_names[4]);
198: MonitorBit(initblock[0], AM7990::IBMODE_LOOP, ib_mode_names[5]);
199: MonitorBit(initblock[0], AM7990::IBMODE_DTX, ib_mode_names[6]);
200: MonitorBit(initblock[0], AM7990::IBMODE_DRX, ib_mode_names[7]);
201: y++;
202:
1.1.1.9 root 203: screen.Print(0, y, "PADR: %02x:%02x:%02x:%02x:%02x:%02x",
1.1 root 204: initblock[1] & 0xff, initblock[1] >> 8,
205: initblock[2] & 0xff, initblock[2] >> 8,
206: initblock[3] & 0xff, initblock[3] >> 8);
1.1.1.15 root 207: screen.Print(0, y + 1, "LADRF:$%04x%04x'%04x%04x",
1.1 root 208: initblock[7],
209: initblock[6],
210: initblock[5],
211: initblock[4]);
212:
213: // RDRP
214: uint32 rdrp = initblock[8] | (initblock[9] << 16);
1.1.1.16 root 215: screen.Print(31, y, "RDRP:$%08x (RDRA=$%06x entries=%u)",
1.1 root 216: rdrp, rmd_base, rmd_num);
217: y++;
218:
219: // TDRP
220: uint32 tdrp = initblock[10] | (initblock[11] << 16);
1.1.1.16 root 221: screen.Print(31, y, "TDRP:$%08x (TDRA=$%06x entries=%u)",
1.1 root 222: tdrp, tmd_base, tmd_num);
223: y++;
224: y++;
225:
226: // RMD
1.1.1.9 root 227: screen.Puts(0, y, "<RMD>");
1.1 root 228:
229: uint16 rmd[4];
230: uint32 rmd_addr;
231: // 現行ディスクリプタは詳細表示
232: if (rmd_num > 0) {
233: rmd_addr = rmd_base + rmd_cur * 8;
234: for (int j = 0; j < countof(rmd); j++) {
235: rmd[j] = PeekMem(rmd_addr + j * 2);
236: }
237: x = 6;
1.1.1.16 root 238: screen.Print(x, y, "Current %02x", rmd_cur);
239: x += 11;
1.1 root 240: MonitorBit(rmd[1], AM7990::RMD1_OWN, rmd1_names[0]);
241: MonitorBit(rmd[1], AM7990::RMD1_ERR, rmd1_names[1]);
242: // 発生し得ないので省略 RMD1_FRAM rmd1_names[2]
243: MonitorBit(rmd[1], AM7990::RMD1_OFLO, rmd1_names[3]);
244: MonitorBit(rmd[1], AM7990::RMD1_CRC, rmd1_names[4]);
245: MonitorBit(rmd[1], AM7990::RMD1_BUFF, rmd1_names[5]);
246: MonitorBit(rmd[1], AM7990::RMD1_STP, rmd1_names[6]);
247: MonitorBit(rmd[1], AM7990::RMD1_ENP, rmd1_names[7]);
248: // BCNT は負数(2の補数)でエンコードされているので正数にデコード
1.1.1.9 root 249: screen.Print(x, y, "MCNT=$%03x BCNT=$%03x",
1.1 root 250: rmd[3] & 0xfff,
251: (-(int16)rmd[2]) & 0xfff);
252: x += 20;
1.1.1.9 root 253: screen.Print(x, y, "buf=$%06x", ((rmd[1] & 0xff) << 16) | rmd[0]);
1.1 root 254: }
255: y++;
256:
257: // 他は一覧表示
258: int rs;
259: if (rmd_num > 48) {
260: // 画面内に収まらないので仕方ないのでカーソルのある16個ブロックが
261: // 常に中央にくるようにローテートするのはどうか。
262: rs = (((rmd_cur - 16 + rmd_num) % rmd_num) / 16) * 16;
263: } else {
264: // 画面内に収まるので最初から書いていくだけ
265: rs = 0;
266: }
267: for (x = 0; x < 3; x++) {
268: for (i = 0; i < 16 && rs < rmd_num; i++) {
269: rmd_addr = rmd_base + rs * 8;
270: for (int j = 0; j < countof(rmd); j++) {
271: rmd[j] = PeekMem(rmd_addr + j * 2);
272: }
1.1.1.9 root 273: screen.Print(x * 27, y + i,
1.1 root 274: (rs == rmd_cur) ? TA::Em : TA::Normal,
275: "%02x %c%c%c%c%c%c $%05x $%03x/$%03x",
276: rs,
277: (rmd[1] & AM7990::RMD1_OWN) ? 'O' : '-',
278: (rmd[1] & AM7990::RMD1_OFLO) ? 'F' : '-',
279: (rmd[1] & AM7990::RMD1_CRC) ? 'C' : '-',
280: (rmd[1] & AM7990::RMD1_BUFF) ? 'B' : '-',
281: (rmd[1] & AM7990::RMD1_STP) ? 'S' : '-',
282: (rmd[1] & AM7990::RMD1_ENP) ? 'E' : '-',
283: ((rmd[1] & 0xff) << 16 | rmd[0]),
284: rmd[3] & 0xfff,
285: (-(int16)rmd[2]) & 0xfff);
286:
287: // 画面内に収まらない場合は折り返し。
288: // 収まる場合はこのまま rmd_num を超えればループを抜ける。
289: rs++;
290: if (rmd_num > 48 && rs >= rmd_num) {
291: rs = 0;
292: }
293: }
294: }
295: y += 17;
296:
297: // TMD
1.1.1.9 root 298: screen.Puts(0, y, "<TMD>");
1.1 root 299:
300: uint16 tmd[4];
301: uint32 tmd_addr;
302: // 現行ディスクリプタは詳細表示
303: if (tmd_num > 0) {
304: tmd_addr = tmd_base + tmd_cur * 8;
305: for (int j = 0; j < countof(tmd); j++) {
306: tmd[j] = PeekMem(tmd_addr + j * 2);
307: }
308: // MORE, ONE, DEF と LCOL, LCAR, RTRY, TDR は発生し得ないので省略
309: x = 6;
1.1.1.16 root 310: screen.Print(x, y, "Current %02x ", tmd_cur);
311: x += 11;
1.1 root 312: MonitorBit(tmd[1], AM7990::TMD1_OWN, tmd1_names[0]);
313: MonitorBit(tmd[1], AM7990::TMD1_ERR, tmd1_names[1]);
314: MonitorBit(tmd[1], AM7990::TMD1_STP, tmd1_names[6]);
315: MonitorBit(tmd[1], AM7990::TMD1_ENP, tmd1_names[7]);
316: x += 1;
317: MonitorBit(tmd[3], AM7990::TMD3_BUFF, tmd3_names[0]);
318: MonitorBit(tmd[3], AM7990::TMD3_UFLO, tmd3_names[1]);
319: // BCNT は負数(2の補数)でエンコードされているので正数にデコード
1.1.1.9 root 320: screen.Print(x, y, "BCNT=$%03x", (-(int16)tmd[2]) & 0xfff);
1.1 root 321: x += 10;
1.1.1.9 root 322: screen.Print(x, y, "buf=$%06x", ((tmd[1] & 0xff) << 16) | tmd[0]);
1.1 root 323: }
324: y++;
325:
326: // 他は一覧表示
327: int ts;
328: if (tmd_num > 24) {
329: // 画面内に収まらないので仕方ないのでカーソルのある16個ブロックが
330: // 常に中央にくるようにローテートするのはどうか。
331: ts = (((tmd_cur - 16 + tmd_num) % tmd_num) / 16) * 16;
332: } else {
333: // 画面内に収まるので最初から書いていくだけ
334: ts = 0;
335: }
336: for (x = 0; x < 3; x++) {
337: for (i = 0; i < 8 && ts < tmd_num; i++) {
338: tmd_addr = tmd_base + ts * 8;
339: for (int j = 0; j < countof(tmd); j++) {
340: tmd[j] = PeekMem(tmd_addr + j * 2);
341: }
1.1.1.9 root 342: screen.Print(x * 27, y + i,
1.1 root 343: (ts == tmd_cur) ? TA::Em : TA::Normal,
344: "%02x %c%c%c%c%c $%05x $%03x",
345: ts,
346: (tmd[1] & AM7990::TMD1_OWN) ? 'O' : '-',
347: (tmd[1] & AM7990::TMD1_STP) ? 'S' : '-',
348: (tmd[1] & AM7990::TMD1_ENP) ? 'E' : '-',
349: (tmd[3] & AM7990::TMD3_BUFF) ? 'B' : '-',
350: (tmd[3] & AM7990::TMD3_UFLO) ? 'U' : '-',
351: ((tmd[1] & 0xff) << 16 | tmd[0]),
352: (-(int16)tmd[2]) & 0xfff);
353:
354: // 画面内に収まらない場合は折り返し。
1.1.1.16 root 355: // 収まる場合はこのまま tmd_num を超えればループを抜ける。
1.1 root 356: ts++;
357: if (tmd_num > 24 && ts >= tmd_num) {
358: ts = 0;
359: }
360: }
361: }
362: }
363:
364: // レジスタをビットごとに表示する。
365: // data は下位8ビットのみ使用し、上位は無視する。
366: void
1.1.1.9 root 367: LanceDevice::MonitorReg(TextScreen& screen,
1.1.1.5 root 368: int x, int y, uint32 data, const char * const *names)
1.1 root 369: {
370: for (int i = 0; i < 8; i++) {
371: bool b = data & (1 << (7 - i));
1.1.1.9 root 372: screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1.1 root 373: }
374: }
375:
376:
377: // 現在選択されているレジスタを読み出す
378: uint32
379: LanceDevice::ReadData()
380: {
381: uint32 data;
382:
383: // XXX CSR[123] は STOP 中だけ読める。そうでない時は未定義値になる。
384: switch (reg.rap) {
385: case 0:
386: {
387: data = reg.GetCSR0();
388: const std::string name = CSR0ToString(data);
1.1.1.11 root 389: putlog(3, "CSR0 -> $%04x<%s>", data, name.c_str());
1.1 root 390: break;
391: }
392: case 1:
393: if (reg.IsSTOP()) {
394: data = reg.iadr & 0xffff;
1.1.1.16 root 395: putlog(2, "CSR%u -> $%04x", reg.rap, data);
1.1 root 396: } else {
397: data = 0xcccc & AM7990::CSR1_MASK;
1.1.1.16 root 398: putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data);
1.1 root 399: }
400: break;
401: case 2:
402: if (reg.IsSTOP()) {
403: data = reg.iadr >> 16;
1.1.1.16 root 404: putlog(2, "CSR%u -> $%04x", reg.rap, data);
1.1 root 405: } else {
406: data = 0xcccc & AM7990::CSR2_MASK;
1.1.1.16 root 407: putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data);
1.1 root 408: }
409: break;
410: case 3:
411: if (reg.IsSTOP()) {
412: data = reg.csr3;
413: const std::string name = CSR3ToString(data);
1.1.1.16 root 414: putlog(2, "CSR%u -> $%04x<%s>", reg.rap, data, name.c_str());
1.1 root 415: } else {
416: data = 0xcccc & AM7990::CSR3_MASK;
1.1.1.16 root 417: putlog(2, "CSR%u -> $%04x (indefinate read)", reg.rap, data);
1.1 root 418: }
419: break;
420: default:
1.1.1.16 root 421: VMPANIC("corrupted reg.rap=%u", reg.rap);
1.1.1.15 root 422: data = 0xffff;
1.1.1.13 root 423: break;
1.1 root 424: }
425: return data;
426: }
427:
428: // 現在選択されてるレジスタに data を書き込む
429: void
430: LanceDevice::WriteData(uint32 data)
431: {
432: switch (reg.rap) {
433: case 0:
434: {
435: // CSR0 は STOP ビットによらず書き込み可能
436: const std::string name = CSR0ToString(data);
437: putlog(2, "CSR0 <- $%04x<%s>", data, name.c_str());
438:
439: // STOP,STRT,INIT 全部立てると STOP のみ有効 (AM7990.pdf, p17)。
440: // STOP は実質リセットなので、これ立ってたらもうそれで終わりだろう。
441: if ((data & AM7990::CSR0_STOP)) {
442: ChipStop();
443: break;
444: }
445:
1.1.1.11 root 446: // INIT, STRT は立ち上がりで実行にしてみる。
447: // OpenBSD が割り込みクリアするために読んだ CSR0 をそのまま書いて
448: // くるようなので、毎回 INIT と STRT が走ってしまう。
449: // とりあえず立ち上がりでやってみる。
450: // XXX 要実機調査
451:
452: if (bit_rising(reg.csr0, data, AM7990::CSR0_INIT)) {
1.1 root 453: ChipInit();
454: }
1.1.1.11 root 455: if (bit_rising(reg.csr0, data, AM7990::CSR0_STRT)) {
1.1 root 456: ChipStart();
457: }
458:
459: // TDMD はセットオンリー (チップがクリアする)
460: if ((data & AM7990::CSR0_TDMD)) {
461: reg.csr0 |= AM7990::CSR0_TDMD;
1.1.1.9 root 462: // TX ポーリングの待ち時間ならこのあとすぐ起動
463: if (tx_phase == TXPhase::IDLE) {
464: ChangePhase(TXPhase::IDLE);
465: }
1.1 root 466: }
467:
468: // 書き込みがビットクリアになる人たち
469: if ((data & AM7990::CSR0_IDON)) {
470: reg.csr0 &= ~AM7990::CSR0_IDON;
471: }
472: if ((data & AM7990::CSR0_TINT)) {
473: reg.csr0 &= ~AM7990::CSR0_TINT;
474: }
475: if ((data & AM7990::CSR0_RINT)) {
476: reg.csr0 &= ~AM7990::CSR0_RINT;
477: }
478: if ((data & AM7990::CSR0_MERR)) {
479: reg.csr0 &= ~AM7990::CSR0_MERR;
480: }
481: if ((data & AM7990::CSR0_MISS)) {
482: reg.csr0 &= ~AM7990::CSR0_MISS;
483: }
484: if ((data & AM7990::CSR0_CERR)) {
485: reg.csr0 &= ~AM7990::CSR0_CERR;
486: }
487: if ((data & AM7990::CSR0_BABL)) {
488: reg.csr0 &= ~AM7990::CSR0_BABL;
489: }
490:
491: // INEA は %0 も %1 も書き込める
492: // INEA は STOP 中は設定できない
493: if (!reg.IsSTOP()) {
494: reg.csr0 &= ~AM7990::CSR0_INEA;
1.1.1.7 root 495: reg.csr0 |= data & AM7990::CSR0_INEA;
1.1 root 496: }
1.1.1.7 root 497:
498: ChangeInterrupt();
1.1 root 499: break;
500: }
501:
502: case 1:
503: // STOP 中のみ書き込み可能。そうでない時は無視する。
504: if (reg.IsSTOP()) {
505: reg.iadr = (reg.iadr & 0xff0000) | (data & AM7990::IADR_L_MASK);
506: putlog(2, "IDAR(L)=$%06x", reg.iadr);
1.1.1.11 root 507:
508: #if 0
509: // IADR 設定時にパフォーマンス測定用実時間表示
1.1.1.13 root 510: scheduler->PutlogRealtime();
1.1.1.11 root 511: #endif
1.1 root 512: }
513: break;
514:
515: case 2:
516: // STOP 中のみ書き込み可能。そうでない時は無視する。
517: if (reg.IsSTOP()) {
518: reg.iadr = ((data & AM7990::IADR_H_MASK) << 16)
519: | (reg.iadr & 0xffff);
520: putlog(2, "IDAR(H)=$%06x", reg.iadr);
521: }
522: break;
523:
524: case 3:
525: // STOP 中のみ書き込み可能。そうでない時は無視する。
526: if (reg.IsSTOP()) {
527: reg.csr3 = data & AM7990::CSR3_MASK;
528: const std::string name = CSR3ToString(reg.csr3);
529: putlog(2, "CSR3 <- $%04x<%s>", reg.csr3, name.c_str());
530: }
531: break;
532:
533: default:
1.1.1.16 root 534: VMPANIC("corrupted reg.rap=%u", reg.rap);
1.1 root 535: }
536: }
537:
538: // メモリアクセスについて。
1.1.1.11 root 539: // LANCE(AM7990) から見たメモリは、メインメモリではなく 3ポートSRAM
1.1.1.13 root 540: // (ここでは SubRAM デバイス)。
541: // LANCE のメモリバスは 16bit で、DAL15..8 が SubRAM の偶数アドレス、
542: // DAL7..0 が SubRAM の奇数アドレスに接続されている。
1.1.1.11 root 543: //
1.1.1.13 root 544: // LANCE | DAL15..DAL8 | DAL7..DAL0
545: // -------+-------------+------------
546: // SubRAM | +0 byte | +1 byte
547: // | +2 byte | +3 byte
1.1 root 548: //
1.1.1.11 root 549: // メモリアクセスは常にこの構成で、CSR3.BSWP はこの1ワードを SILO(FIFO) に
550: // 書き込む/から読み出す順序を入れ替えるもの。
1.1 root 551:
1.1.1.16 root 552: // メモリから1ワード読み込む。addr はワードアラインしていること。
553: uint32
554: LanceDevice::ReadMem(uint32 addr)
1.1 root 555: {
1.1.1.16 root 556: assertmsg((addr & 1) == 0, "addr=$%x", addr);
1.1 root 557:
558: // XXX 所要クロックを考察すること
1.1.1.16 root 559: busdata data = subram->Read2(addr);
560: return data.Data();
1.1 root 561: }
562:
1.1.1.16 root 563: // メモリに1ワード書き込む。addr はワードアラインしていること。
564: void
565: LanceDevice::WriteMem(uint32 addr, uint32 data)
1.1 root 566: {
1.1.1.16 root 567: assertmsg((addr & 1) == 0, "addr=$%x", addr);
1.1 root 568:
569: // XXX 所要クロックを考察すること
1.1.1.16 root 570: subram->Write2(addr, data);
1.1 root 571: }
572:
573: // メモリ (3ポートSRAM) から1ワードピークする。バスエラーは起きない。
1.1.1.16 root 574: uint32
575: LanceDevice::PeekMem(uint32 addr) const
1.1 root 576: {
1.1.1.16 root 577: busdata data = subram->Peek2(addr);
578: return data.Data();
1.1 root 579: }
580:
581: // INIT ビットによるチップ初期化。
582: void
583: LanceDevice::ChipInit()
584: {
1.1.1.11 root 585: putlog(1, "ChipInit");
586:
1.1 root 587: // INIT をセットすると STOP ビットはクリア
588: reg.csr0 |= AM7990::CSR0_INIT;
589: reg.csr0 &= ~AM7990::CSR0_STOP;
590:
591: // Initialization Block を読み込む
592: for (int i = 0; i < countof(initblock); i++) {
593: initblock[i] = ReadMem(reg.iadr + i * 2);
594: }
595: if (0) {
596: for (int i = 0; i < countof(initblock); i++) {
1.1.1.16 root 597: putlog(2, "initblock[%u] = $%04x", i, initblock[i]);
1.1 root 598: }
599: }
600:
601: // 送受信ディスクリプタ用の内部変数を設定
602: uint32 rdrp = initblock[8] | (initblock[9] << 16);
603: rmd_base = rdrp & 0xfffffc;
604: int rlen = rdrp >> 29;
605: rmd_num = (1 << rlen);
606:
607: uint32 tdrp = initblock[10] | (initblock[11] << 16);
608: tmd_base = tdrp & 0xfffffc;
609: int tlen = tdrp >> 29;
610: tmd_num = (1 << tlen);
611:
1.1.1.18 root 612: padr = MacAddr(
613: initblock[1] & 0xff,
614: initblock[1] >> 8,
615: initblock[2] & 0xff,
616: initblock[2] >> 8,
617: initblock[3] & 0xff,
618: initblock[3] >> 8);
1.1.1.11 root 619:
1.1.1.15 root 620: // LADRF は以下のように格納されていて、そのまま LADRF(63:00) に対応する。
621: // IADR+$08 LADRF(15:00)
622: // IADR+$0a LADRF(31:16)
623: // IADR+$0c LADRF(47:32)
624: // IADR+$0e LADRF(63:48)
1.1.1.18 root 625: ladrf = ((uint64)initblock[4] << 0)
626: | ((uint64)initblock[5] << 16)
627: | ((uint64)initblock[6] << 32)
628: | ((uint64)initblock[7] << 48);
629:
630: promisc = (initblock[0] & AM7990::IBMODE_PROM);
1.1.1.9 root 631:
1.1 root 632: // XXX 本当はいろいろ時間がかかりそうなはずだが
633: // 初期化完了
634: SetInterrupt(AM7990::CSR0_IDON);
635: }
636:
637: // STRT ビットによるスタート。
638: void
639: LanceDevice::ChipStart()
640: {
1.1.1.12 root 641: putlog(1, "Start");
1.1 root 642:
643: // STRT を書き込むと STOP はクリア
644: reg.csr0 |= AM7990::CSR0_STRT;
645: reg.csr0 &= ~AM7990::CSR0_STOP;
646:
647: // MODE の DTX がクリアなら TXON をセット?
648: // XXX 実際はタイミング違う気がする
649: // INIT で DTX==%0 ならトランスミッタがオンになり、
650: // トランスミッタがオンで STRT すると TXON がオンになる、ように読めるが
651: // トランスミッタは省略してみる。
652: // RX 側も同様。
653: if ((initblock[0] & AM7990::IBMODE_DTX) == 0) {
654: reg.csr0 |= AM7990::CSR0_TXON;
655: }
656: if ((initblock[0] & AM7990::IBMODE_DRX) == 0) {
657: reg.csr0 |= AM7990::CSR0_RXON;
658: }
659:
660: // 初回読み込みに備えて RMD1/TMD1 の先読みバッファを無効化する
661: rmd1_ahead = (uint32)-1;
662: tmd1_ahead = (uint32)-1;
663:
1.1.1.11 root 664: // バッファクリア
665: tx_packet.Clear();
666:
1.1.1.9 root 667: ChangePhase(TXPhase::IDLE, 0_nsec);
668: ChangePhase(RXPhase::IDLE, 0_nsec);
1.1.1.11 root 669:
670: // ホストの受信を開始する
671: hostnet->EnableRx(true);
1.1 root 672: }
673:
674: // STOP ビットによるチップリセット。
675: // ハードリセットもここに来る。
676: void
677: LanceDevice::ChipStop()
678: {
1.1.1.12 root 679: putlog(1, "Reset");
1.1 root 680:
681: // STOPセットで CSR0 は STOP セット、他は全クリア
682: reg.csr0 = AM7990::CSR0_STOP;
1.1.1.15 root 683: ChangeInterrupt();
1.1 root 684: // CSR1, 2 は不定
685: // CSR3 はクリア
686: reg.csr3 = 0;
687:
688: // 内部ポインタも戻す
689: tmd_cur = 0;
690: rmd_cur = 0;
691:
692: // イベントを(あれば)停止。
1.1.1.11 root 693: ChangePhase(RXPhase::STOP);
694: ChangePhase(TXPhase::STOP);
1.1 root 695:
1.1.1.11 root 696: // バッファクリア
697: rx_packet.Clear();
698: tx_packet.Clear();
1.1.1.9 root 699:
1.1.1.11 root 700: // ホストの受信を停止する
701: hostnet->EnableRx(false);
1.1 root 702: }
703:
1.1.1.7 root 704: // 割り込み要因を CSR0 にセットし、必要なら割り込みを上げる。
1.1 root 705: void
706: LanceDevice::SetInterrupt(uint32 bit)
707: {
708: reg.csr0 |= bit;
1.1.1.7 root 709: ChangeInterrupt();
1.1 root 710: }
711:
1.1.1.7 root 712: // 現状に合わせて割り込み信号線の状態を変える。
1.1 root 713: void
1.1.1.7 root 714: LanceDevice::ChangeInterrupt()
1.1 root 715: {
1.1.1.15 root 716: bool irq = (reg.IsINTR() && (reg.csr0 & AM7990::CSR0_INEA));
717: interrupt->ChangeINT(this, irq);
1.1 root 718: }
719:
720: // TXIDLE 送信アイドルフェーズ。
721: // ディスクリプタを所有できるかポーリングする。
1.1.1.9 root 722: // - 所有できれば TXCOPY フェーズへ。
723: // - 所有できない場合、TDMD オンなら即、
724: // オフなら 1.6ms 待ってから再び TXIDLE へ。
1.1 root 725: void
1.1.1.15 root 726: LanceDevice::TXIdle(Event& ev)
1.1 root 727: {
1.1.1.9 root 728: tx_phase = TXPhase::IDLE;
729:
730: // TDMD クリア
731: reg.csr0 &= ~AM7990::CSR0_TDMD;
732:
1.1 root 733: // TMD1 を読み込む
734: if ((int32)tmd1_ahead >= 0) {
735: // すでに先読みしてあればそれを使う
736: tmd1 = tmd1_ahead;
737: } else {
738: // 読み込む
739: uint32 tmd_addr = tmd_base + tmd_cur * 8;
740: tmd1 = ReadMem(tmd_addr + 2);
741: }
742: // どちらにしても先読みバッファは無効に戻す
743: tmd1_ahead = (uint32)-1;
744:
745: // その TMD1 に OWN と STP が立っているか
746: if ((tmd1 & AM7990::TMD1_OWN) && (tmd1 & AM7990::TMD1_STP)) {
747: // 取り込みへ
1.1.1.11 root 748: TXCopy();
1.1 root 749: return;
750: }
751:
1.1.1.9 root 752: // 立っていなければ次回は 1.6ms 後
753: ChangePhase(TXPhase::IDLE, 1.6_msec);
1.1 root 754: }
755:
756: // TXCOPY バッファ処理フェーズ。
757: // 現ディスクリプタのバッファの内容をメモリから読み込み、
758: // それにかかる時間相当分をウェイトする。
1.1.1.9 root 759: // - ENP ならウェイトした後 TXSEND フェーズへ。
760: // - 次 TMD が OWN できればウェイトした後 TXNEXT フェーズへ。
761: // - 次 TMD が OWN 出来なければウェイトした後 TXSEND フェーズ。
1.1 root 762: void
1.1.1.11 root 763: LanceDevice::TXCopy()
1.1 root 764: {
1.1.1.9 root 765: tx_phase = TXPhase::COPY;
766:
1.1 root 767: // TMD0, TMD2 は送信することが確定してから読み出す
768: uint32 tmd_addr = tmd_base + tmd_cur * 8;
769: uint16 tmd0 = ReadMem(tmd_addr);
770: uint16 tmd2 = ReadMem(tmd_addr + 4);
771:
1.1.1.11 root 772: // アドレスと送信バイト数。
773: // tmd2 には 2 の補数で送信バイト数が入っているので符号反転する。
774: uint32 src = ((tmd1 & 0x00ff) << 16) | tmd0;
775: int32 bcnt = -(int32)(int16)tmd2;
776:
777: // copycnt は bcnt のうち実際にコピーするバイト数
778: int32 copycnt;
779: if (tx_packet.length + bcnt > tx_packet.size()) {
780: // コピーするとバッファが溢れてしまう計算なら、溢れないように打ち切る。
781: copycnt = tx_packet.size() - tx_packet.length;
782: } else {
783: // 全部コピーできる。
784: copycnt = bcnt;
785: }
786:
787: // 送信パケットキュー上の書き込み中バッファに追記する
788: uint8 *dst = &tx_packet[tx_packet.length];
789: tx_packet.length += copycnt;
790:
1.1.1.13 root 791: // ここから、SubRAM からローカルの送信バッファにコピー
1.1.1.11 root 792: // XXX バーストコピー未対応
793: const uint32 srcend = src + bcnt;
794: const uint8 *dstend = dst + copycnt;
795:
796: // src が奇数アドレスから始まっている(そしてコピー可能な)場合
797: // (バッファを奇数アドレスから始めたりする奇特な人はいないと思うが)
798: if (__predict_false((src & 1) != 0) && dst < dstend) {
799: uint16 data = ReadMem(src & ~1);
800: if (reg.IsBSWP() == false) {
801: *dst++ = data >> 8;
802: } else {
803: *dst++ = data & 0xff;
804: }
805: src++;
806: }
1.1 root 807:
1.1.1.11 root 808: // 残り2バイト以上コピー可能な間 (ここで src はワード境界になっている)
809: const uint8 *dstend_even;
810: dstend_even = (const uint8 *)((uintptr_t)dstend & ~(uintptr_t)1);
811: while (dst < dstend_even) {
812: uint16 data = ReadMem(src);
813: if (reg.IsBSWP() == false) {
814: *dst++ = data & 0xff;
815: *dst++ = data >> 8;
816: } else {
817: *dst++ = data >> 8;
818: *dst++ = data & 0xff;
819: }
820: src += 2;
821: }
1.1 root 822:
1.1.1.11 root 823: // src が奇数アドレスで終わっている(そしてコピー可能な)場合
824: if (__predict_false(dst < dstend)) {
825: uint16 data = ReadMem(src);
826: if (reg.IsBSWP() == false) {
827: *dst++ = data & 0xff;
1.1 root 828: } else {
1.1.1.11 root 829: *dst++ = data >> 8;
1.1 root 830: }
1.1.1.11 root 831: src += 2;
832: }
833:
1.1.1.13 root 834: // tx_packet が一杯になったら後はディスクリプタが終わるまで SubRAM から
1.1.1.11 root 835: // 読み捨てる。tx_packet の長さに上限があるのはこっち(エミュレータ)の
836: // 都合であって LANCE はディスクリプタが終わるまで延々読み込んでは出力を
837: // 続けるようだ。ここでは同じだけ読み込むところ、それにかかる時間を求める
838: // ところを再現する。tx_packet がイーサネットフレーム長を超過していると
839: // この後 SEND フェーズで BABBLE ビットを立てるところも再現する。
840: // 正確には 1519バイト目の送信で立てるのだが、通常は起きない上に面倒
841: // なので省略。1519バイト以上のパケットをホストに流すこともしない。
842: while (src < srcend) {
843: ReadMem(src);
844: src += 2;
1.1 root 845: }
846:
1.1.1.9 root 847: // メモリからの転送にかかった時間をざっくり計算 XXX まだ適当
848: // そのウェイト後に指定のフェーズへ。
1.1.1.11 root 849: uint64 t = 700 * bcnt / 16;
1.1.1.9 root 850:
1.1 root 851: // ここが ENP なら、送信のため TXSEND フェーズへ
852: if ((tmd1 & AM7990::TMD1_ENP)) {
1.1.1.9 root 853: ChangePhase(TXPhase::SEND, t);
1.1 root 854: } else {
855: // 次のディスクリプタを先読み
856: tmd_addr = tmd_base + ((tmd_cur + 1) % tmd_num) * 8;
857: tmd1_ahead = ReadMem(tmd_addr + 2);
858:
859: if ((tmd1_ahead & AM7990::TMD1_OWN)) {
860: // 次ディスクリプタが所有できれば TXNEXT フェーズへ
1.1.1.9 root 861: ChangePhase(TXPhase::NEXT, t);
1.1 root 862: } else {
863: // この時点で所有できなければアンダーフロー。
864: // ここまでのバッファでパケットを送信するため TXSEND へ。
865: // エラーフラグの処理は TXSEND 側で行う。
1.1.1.9 root 866: ChangePhase(TXPhase::SEND, t);
1.1 root 867: }
868: }
869: }
870:
871: // TXSEND フェーズ。パケットを送信。
872: // ただし ENP でなければアンダーフローによるパケット送信なのでフラグ処理。
873: // その後 TXNEXT フェーズへ。
874: void
1.1.1.15 root 875: LanceDevice::TXSend(Event& ev)
1.1 root 876: {
1.1.1.9 root 877: tx_phase = TXPhase::SEND;
878:
1.1.1.11 root 879: if (__predict_false(tx_packet.length > 1518)) {
880: // 本当は 1519バイト目を送ったところで BABL を立てるのだが
881: // まず起きない上に面倒なので、ここで行う。
882: SetInterrupt(AM7990::CSR0_BABL);
883:
884: // 1519バイト以上のパケットはホストにも投げない。
885: } else {
886: // 送信
887: hostnet->Tx(tx_packet);
888: }
889: tx_packet.Clear();
1.1 root 890:
891: // ENP でなければアンダーフローによるものだった
892: if ((tmd1 & AM7990::TMD1_ENP) == 0) {
893: // TMD3 はここで書き出す
894: // XXX 読まずに書くだけもいいはず?
895: uint32 tmd_addr = tmd_base + tmd_cur * 8;
896: uint16 tmd3 = ReadMem(tmd_addr + 6);
897: tmd3 |= AM7990::TMD3_BUFF | AM7990::TMD3_UFLO;
898: WriteMem(tmd_addr + 6, tmd3);
899:
1.1.1.9 root 900: // TMD1 は TXNEXT フェーズで書き戻す
1.1 root 901: tmd1 |= AM7990::TMD1_ERR;
902: }
903:
904: // どちらにしても送信割り込み
905: SetInterrupt(AM7990::CSR0_TINT);
906:
1.1.1.9 root 907: ChangePhase(TXPhase::NEXT);
1.1 root 908: }
909:
910: // TXNEXT フェーズ。次のディスクリプタを指して TXIDLE へ。
911: void
1.1.1.15 root 912: LanceDevice::TXNext(Event& ev)
1.1 root 913: {
1.1.1.9 root 914: tx_phase = TXPhase::NEXT;
915:
1.1 root 916: // このディスクリプタの所有権を放棄
917: tmd1 &= ~AM7990::TMD1_OWN;
918: uint32 tmd_addr = tmd_base + tmd_cur * 8;
919: WriteMem(tmd_addr + 2, tmd1);
920:
1.1.1.9 root 921: // 即、次のディスクリプタの所有を試みる
1.1 root 922: tmd_cur = (tmd_cur + 1) % tmd_num;
1.1.1.9 root 923: ChangePhase(TXPhase::IDLE);
1.1 root 924: }
925:
1.1.1.9 root 926: // 指定時間後に TX フェーズを遷移する。
927: // (変化があれば)変更するではないことに注意。名前がアレだが IDLE フェーズは
928: // ポーリングしているので IDLE から IDLE への遷移も必ず起こす必要がある。
929: // TX か RX かは関数オーバーロードで区別している。
930: void
931: LanceDevice::ChangePhase(TXPhase new_phase, uint64 time)
1.1 root 932: {
1.1.1.9 root 933: tx_event.time = time;
934: switch (new_phase) {
1.1.1.11 root 935: case TXPhase::STOP:
1.1.1.13 root 936: scheduler->StopEvent(tx_event);
1.1.1.11 root 937: return;
1.1.1.9 root 938: case TXPhase::IDLE:
1.1.1.11 root 939: tx_event.func = ToEventCallback(&LanceDevice::TXIdle);
1.1.1.9 root 940: break;
941: case TXPhase::SEND:
1.1.1.11 root 942: tx_event.func = ToEventCallback(&LanceDevice::TXSend);
1.1.1.9 root 943: break;
944: case TXPhase::NEXT:
1.1.1.11 root 945: tx_event.func = ToEventCallback(&LanceDevice::TXNext);
1.1.1.9 root 946: break;
947: default:
1.1.1.16 root 948: assertmsg(false, "phase %u", (uint)new_phase);
1.1 root 949: }
1.1.1.13 root 950: scheduler->RestartEvent(tx_event);
1.1.1.9 root 951: }
1.1 root 952:
1.1.1.11 root 953: // 受信フェーズ遷移図
954: //
955: // +--------+
956: // | RXSTOP |<- - - (CSR0.STOP 書き込み / リセット)
957: // +--------+
958: // :
1.1.1.15 root 959: // : +‥‥‥+ <‥‥ RxMessage (パケット受信)
1.1.1.11 root 960: // v v :
961: // +-------------+ :
962: // +‥‥‥>| RXIDLE |‥‥+ Idle
963: // : +-------------+
964: // : | | ^
965: // : | | :
966: // : v | :
967: // : +--------+ | +--------+
968: // +‥| RXMISS | | | RXNEXT |
969: // +--------+ | +--------+
970: // | ^ |
971: // | : |
972: // v : v
973: // +-----------+
974: // | RXCOPY | 関数呼び出し ---->
975: // +-----------+ イベントによる遷移 ‥‥>
976:
1.1.1.15 root 977: // パケット受信通知。HostNet から (EthernetDevice 経由で) 呼ばれる。
1.1.1.9 root 978: void
1.1.1.15 root 979: LanceDevice::RxMessage(MessageID msgid, uint32 arg)
1.1.1.9 root 980: {
981: // RXIDLE ポーリングのウェイト中ならすぐに始める。
982: // そうでないときは RXIDLE に戻ったところで処理される。
983: if (rx_phase == RXPhase::IDLE) {
984: ChangePhase(RXPhase::IDLE);
985: }
1.1 root 986: }
987:
988: // RXIDLE 受信アイドルフェーズ。
989: // (最初の)ディスクリプタを所有できるかポーリングする。
990: void
1.1.1.15 root 991: LanceDevice::RXIdle(Event& ev)
1.1 root 992: {
1.1.1.9 root 993: rx_phase = RXPhase::IDLE;
994:
1.1.1.16 root 995: putlog(3, "%s[%u]", __func__, rmd_cur);
1.1.1.9 root 996:
1.1 root 997: // RMD1 を読み込む
998: if ((int32)rmd1_ahead >= 0) {
999: // すでにあればそれを使う
1000: rmd1 = rmd1_ahead;
1001: } else {
1002: // 読み込む
1003: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1004: rmd1 = ReadMem(rmd_addr + 2);
1005: }
1006: // どちらにしても先読みバッファは無効に戻す
1007: rmd1_ahead = (uint32)-1;
1008:
1.1.1.9 root 1009: // 受信しているか
1.1.1.11 root 1010: if (hostnet->Rx(&rx_packet)) {
1.1.1.9 root 1011: // その RMD1 に OWN が立っているか
1012: if ((rmd1 & AM7990::RMD1_OWN)) {
1013: // ここが STP になる
1014: rmd1 |= AM7990::RMD1_STP;
1.1.1.11 root 1015: // RXCOPY へ直接移行する。
1016: RXCopy();
1.1.1.9 root 1017: } else {
1.1.1.11 root 1018: // バッファが無いので MISS へ直接移行する。
1.1.1.9 root 1019: // MISS までの時間は受信処理によって表現されているはず
1.1.1.11 root 1020: RXMiss();
1.1.1.9 root 1021: }
1.1 root 1022: } else {
1.1.1.9 root 1023: if ((rmd1 & AM7990::RMD1_OWN)) {
1024: // ここが STP になる
1025: rmd1 |= AM7990::RMD1_STP;
1026: }
1027: // 1.6ms 待って再度 RXIDLE へ。
1028: ChangePhase(RXPhase::IDLE, 1.6_msec);
1.1 root 1029: }
1030: }
1031:
1032: // RXCOPY バッファ処理フェーズ。
1033: // 受信バッファからディスクリプタのバッファに書き込み、
1034: // 書き込みにかかる時間相当分をウェイトする。
1035: void
1.1.1.11 root 1036: LanceDevice::RXCopy()
1.1 root 1037: {
1.1.1.9 root 1038: rx_phase = RXPhase::COPY;
1039:
1.1.1.16 root 1040: putlog(1, "%s[%u]", __func__, rmd_cur);
1.1.1.9 root 1041:
1.1 root 1042: // RMD0, RMD2 は受信することが確定してから読み出す
1043: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1044: uint16 rmd0 = ReadMem(rmd_addr);
1045: uint16 rmd2 = ReadMem(rmd_addr + 4);
1046:
1.1.1.11 root 1047: // アドレスと受信バッファのバイト数。
1.1 root 1048: uint32 bufdst = ((rmd1 & 0x00ff) << 16) | rmd0;
1049: uint32 dst = bufdst;
1.1.1.11 root 1050: // rmd2 は 2 の補数
1051: int32 bcnt = -(int32)(int16)rmd2;
1.1 root 1052:
1.1.1.11 root 1053: if (bcnt < rx_packet.length) {
1.1.1.16 root 1054: putlog(1, "will be remain: %d < %u", bcnt, rx_packet.length);
1.1.1.9 root 1055: }
1056:
1.1.1.11 root 1057: uint8 *src = &rx_packet[0];
1.1.1.16 root 1058: uint remsize = rx_packet.length;
1.1.1.11 root 1059:
1060: if (bcnt > remsize) {
1061: bcnt = remsize;
1062: }
1.1 root 1063:
1.1.1.11 root 1064: // コピー後の残りサイズにしておく
1065: remsize -= bcnt;
1066:
1067: // ローカルの受信バッファからディスクリプタバッファにコピー
1068: for (; bcnt > 0; ) {
1.1 root 1069: // XXX バーストコピー未対応
1070: uint16 data;
1.1.1.11 root 1071: if (bcnt >= 2 && (dst & 1) == 0) {
1.1 root 1072: // 2バイト以上残っててワード境界ならワードアクセス
1.1.1.11 root 1073: if (reg.IsBSWP() == false) {
1074: data = *src++;
1075: data |= (*src++) << 8;
1076: } else {
1077: data = (*src++) << 8;
1078: data |= *src++;
1079: }
1.1 root 1080: WriteMem(dst, data);
1081: dst += 2;
1.1.1.11 root 1082: bcnt -= 2;
1.1 root 1083: } else if ((dst & 1) == 0) {
1084: // 偶数アドレスへ1バイト
1085: // 奇数バイトには不定データが出るらしいがここでは 0 にする
1.1.1.11 root 1086: if (reg.IsBSWP() == false) {
1087: data = *src++;
1088: } else {
1089: data = (*src++) << 8;
1090: }
1.1 root 1091: WriteMem(dst, data);
1092: dst += 1;
1.1.1.11 root 1093: bcnt -= 1;
1.1 root 1094: } else {
1095: // 奇数アドレスへ1バイト
1096: // 偶数バイトには不定データが出るらしいがここでは 0 にする
1.1.1.11 root 1097: if (reg.IsBSWP() == false) {
1098: data = (*src++) << 8;
1099: } else {
1100: data = *src++;
1101: }
1.1 root 1102: WriteMem(dst & ~1, data);
1103: dst += 1;
1.1.1.11 root 1104: bcnt -= 1;
1.1 root 1105: }
1106: }
1107:
1108: // 全部書き出せたらここが ENP
1.1.1.11 root 1109: if (remsize == 0) {
1.1 root 1110: rmd1 |= AM7990::RMD1_ENP;
1111:
1112: // ENP なら MCNT を更新
1113: WriteMem(rmd_addr + 6, (dst - bufdst) & 0xfff);
1.1.1.9 root 1114: } else {
1115: rmd1 &= ~AM7990::RMD1_ENP;
1.1.1.16 root 1116: putlog(1, "copy remain %u", remsize);
1.1.1.11 root 1117:
1118: // 前詰めにコピーする
1119: memmove(&rx_packet[0], src, remsize);
1120: rx_packet.length = remsize;
1.1 root 1121: }
1122:
1123: // メモリへの転送にかかった時間をざっくり計算 XXX まだ適当
1124: // そのウェイト後に RXNEXT フェーズへ。
1.1.1.10 root 1125: uint64 t = 700 * (dst - bufdst) / 16;
1.1.1.9 root 1126: ChangePhase(RXPhase::NEXT, t);
1.1 root 1127: }
1128:
1129: // RXNEXT フェーズ。
1130: // ここが ENP なら、次のディスクリプタを指して RXIDLE へ。
1131: // ENP でなければ、
1132: // - 次のディスクリプタが所有できれば引き続き書き出すため RXCOPY へ。
1133: // - 次のディスクリプタが所有できなければエラーにして RXIDLE へ。
1134: void
1.1.1.15 root 1135: LanceDevice::RXNext(Event& ev)
1.1 root 1136: {
1.1.1.9 root 1137: rx_phase = RXPhase::NEXT;
1138:
1.1.1.16 root 1139: putlog(1, "%s[%u]", __func__, rmd_cur);
1.1 root 1140:
1.1.1.9 root 1141: bool is_chained = false;
1.1 root 1142:
1143: if ((rmd1 & AM7990::RMD1_ENP)) {
1144: // ENP なら、RXIDLE へ。
1.1.1.11 root 1145: rx_packet.Clear();
1.1.1.9 root 1146: ChangePhase(RXPhase::IDLE);
1.1 root 1147: } else {
1148: // 次のディスクリプタを先読み
1149: uint32 rmd_addr = rmd_base + ((rmd_cur + 1) % rmd_num) * 8;
1150: rmd1_ahead = ReadMem(rmd_addr + 2);
1151:
1152: if ((rmd1_ahead & AM7990::RMD1_OWN)) {
1153: // 次ディスクリプタが所有できれば RXCOPY へ。
1.1.1.9 root 1154: is_chained = true;
1.1 root 1155: } else {
1156: // この時点で所有できなければオーバーフロー。
1157: // XXX BUFF と OFLO の違いがよくわからん
1158: rmd1 |= AM7990::RMD1_BUFF | AM7990::RMD1_OFLO;
1159:
1.1.1.11 root 1160: // 書き込み先が無いのでこのパケットは打ち切ってみる
1161: rx_packet.Clear();
1162:
1.1 root 1163: // 次のディスクリプタをポールするため RXIDLE へ。
1.1.1.9 root 1164: ChangePhase(RXPhase::IDLE);
1.1 root 1165: }
1166: }
1167:
1168: // このディスクリプタの所有権を放棄
1169: rmd1 &= ~AM7990::RMD1_OWN;
1170: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1171: WriteMem(rmd_addr + 2, rmd1);
1172:
1173: // 次のディスクリプタへ
1174: rmd_cur = (rmd_cur + 1) % rmd_num;
1175:
1.1.1.11 root 1176: // どちらにしても受信割り込み
1177: SetInterrupt(AM7990::CSR0_RINT);
1178:
1.1.1.9 root 1179: if (is_chained) {
1.1.1.11 root 1180: // 次のディスクリプタがある場合は RXCopy に直接遷移する。
1.1.1.9 root 1181: rmd1 = rmd1_ahead;
1182: rmd1_ahead = -1;
1.1.1.11 root 1183: RXCopy();
1.1.1.9 root 1184: }
1.1 root 1185: }
1186:
1187: // RXMISS 受信失敗処理。
1188: void
1.1.1.11 root 1189: LanceDevice::RXMiss()
1.1 root 1190: {
1.1.1.9 root 1191: rx_phase = RXPhase::MISS;
1192:
1193: putlog(1, "%s", __func__);
1.1 root 1194:
1195: // 受信データがあるのにディスクリプタを所有してなければエラー
1196: SetInterrupt(AM7990::CSR0_MISS | AM7990::CSR0_RINT);
1197:
1198: // 受信データを破棄。
1.1.1.11 root 1199: rx_packet.Clear();
1.1 root 1200:
1201: // そのまますぐにアイドルフェーズに戻るんだろうか
1.1.1.9 root 1202: ChangePhase(RXPhase::IDLE);
1.1 root 1203: }
1204:
1.1.1.18 root 1205: // この宛先アドレスを受信するかどうか。
1206: // これは HostNet スレッドで呼ばれる。
1207: int
1208: LanceDevice::HWAddrFilter(const MacAddr& dstaddr) const
1209: {
1210: if (promisc) {
1211: return HPF_PASS;
1212: }
1213:
1214: if (dstaddr.IsUnicast()) {
1215: if (dstaddr != padr) {
1216: return HPF_DROP_UNICAST;
1217: }
1218: } else {
1219: if (dstaddr.IsBroadcast()) {
1220: return HPF_PASS;
1221: }
1222:
1223: // マルチキャスト。
1224: //
1225: // AM7990 のマルチキャストフィルタ(ハッシュ) は宛先 MAC アドレスの
1226: // CRC (32ビット) のうち、下位6ビット *のビット順を逆順にしたもの*
1227: // を pos として、LADRF の下から pos ビット目が立っていれば受理する
1228: // というもの。
1229: // 31 7 6 5 4 3 2 1 0
1230: // +--- -+---+---+---+---+---+---+---+---+
1231: // CRC32(dstaddr) = | .. | X X | p0| p1| p2| p3| p4| p5|
1232: // +--- -+---+---+---+---+---+---+---+---+
1233: //
1234: // +---+---+---+---+---+---+
1235: // pos = | p5| p4| p3| p2| p1| p0|
1236: // +---+---+---+---+---+---+
1237:
1238: uint32 crc = EthernetDevice::CRC32(dstaddr);
1239: uint pos = bitrev8(crc) >> 2;
1240: bool mcast_pass = (ladrf & (1ULL << pos));
1241: putmsg(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%u %s",
1242: dstaddr[0], dstaddr[1], dstaddr[2],
1243: dstaddr[3], dstaddr[4], dstaddr[5],
1244: pos, (mcast_pass ? "pass" : "drop"));
1245: if (mcast_pass == false) {
1246: return HPF_DROP_MULTICAST;
1247: }
1248: }
1249:
1250: return HPF_PASS;
1251: }
1252:
1.1.1.9 root 1253: // 指定時間後に RX フェーズを遷移する。
1254: // (変化があれば)変更するではないことに注意。名前がアレだが IDLE フェーズは
1255: // ポーリングしているので IDLE から IDLE への遷移も必ず起こす必要がある。
1256: // TX か RX かは関数オーバーロードで区別している。
1.1 root 1257: void
1.1.1.9 root 1258: LanceDevice::ChangePhase(RXPhase new_phase, uint64 time)
1.1 root 1259: {
1.1.1.9 root 1260: rx_event.time = time;
1261: switch (new_phase) {
1.1.1.11 root 1262: case RXPhase::STOP:
1.1.1.13 root 1263: scheduler->StopEvent(rx_event);
1.1.1.11 root 1264: return;
1.1.1.9 root 1265: case RXPhase::IDLE:
1.1.1.11 root 1266: rx_event.func = ToEventCallback(&LanceDevice::RXIdle);
1.1.1.9 root 1267: break;
1268: case RXPhase::NEXT:
1.1.1.11 root 1269: rx_event.func = ToEventCallback(&LanceDevice::RXNext);
1.1.1.9 root 1270: break;
1271: default:
1.1.1.16 root 1272: assertmsg(false, "phase %u", (uint)new_phase);
1.1.1.9 root 1273: }
1.1.1.13 root 1274: scheduler->RestartEvent(rx_event);
1.1 root 1275: }
1276:
1.1.1.9 root 1277:
1.1 root 1278: // ビット名文字列配列は [0] が MSB 側の順で並べる
1279:
1280: /*static*/ const char * const LanceDevice::csr0names[] = {
1281: "ERR", "BABL", "CERR", "MISS", "MERR", "RINT", "TINT", "IDON",
1282: "INTR", "INEA", "RXON", "TXON", "TDMD", "STOP", "STRT", "INIT",
1283: };
1284:
1285: /*static*/ const char * const LanceDevice::csr3names[] = {
1.1.1.8 root 1286: "", "", "", "", "", "", "", "",
1.1 root 1287: "", "", "", "", "", "BSWP", "ACON", "BCON",
1288: };
1289:
1290: /*static*/ const char * const LanceDevice::ib_mode_names[] = {
1291: "PROM", "INTL", "DRTY", "COLL", "DTCR", "LOOP", "DTX", "DRX",
1292: };
1293:
1294: /*static*/ const char * const LanceDevice::rmd1_names[] = {
1295: "OWN", "ERR", "FRAM", "OFLO", "CRC", "BUFF", "STP", "ENP",
1296: };
1297:
1298: /*static*/ const char * const LanceDevice::tmd1_names[] = {
1299: "OWN", "ERR", "----", "MORE", "ONE", "DEF", "STP", "ENP",
1300: };
1301:
1302: /*static*/ const char * const LanceDevice::tmd3_names[] = {
1303: "BUFF", "UFLO", "----", "LCOL", "LCAR", "BTRY", "", "",
1304: };
1305:
1306: // bits の立っているビット名を左から MSB->LSB の順で並べて返す
1307: const std::string
1308: LanceDevice::BitToString(const char * const name[], uint16 bits)
1309: {
1310: std::string str;
1311:
1312: while (bits) {
1313: int clz = __builtin_clz(bits) - 16;
1314: if (!str.empty()) {
1315: str += ",";
1316: }
1317: str += name[clz];
1318: bits ^= 1 << (15 - clz);
1319: }
1320: return str;
1321: }
1322:
1323: // CSR0 のビット名を返す
1324: const std::string
1325: LanceDevice::CSR0ToString(uint16 bits)
1326: {
1327: return BitToString(csr0names, bits);
1328: }
1329:
1330: // CSR3 のビット名を返す
1331: const std::string
1332: LanceDevice::CSR3ToString(uint16 bits)
1333: {
1334: return BitToString(csr3names, bits);
1335: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.