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