|
|
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.13 root 45: // ホストからの受信コールバックを登録
1.1.1.14 root 46: scheduler->ConnectMessage(MessageID::HOSTNET_RX(0), this,
1.1.1.15 root 47: ToMessageCallback(&LanceDevice::RxMessage));
1.1 root 48:
1.1.1.16 root 49: // func, time は都度設定する
50: rx_event.SetName("Lance RX");
51: tx_event.SetName("Lance TX");
52: scheduler->RegistEvent(rx_event);
53: scheduler->RegistEvent(tx_event);
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.9 root 139: LanceDevice::MonitorUpdate(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++) {
369: bool b = data & (1 << (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);
1.1.1.11 root 505:
506: #if 0
507: // IADR 設定時にパフォーマンス測定用実時間表示
1.1.1.13 root 508: scheduler->PutlogRealtime();
1.1.1.11 root 509: #endif
1.1 root 510: }
511: break;
512:
513: case 2:
514: // STOP 中のみ書き込み可能。そうでない時は無視する。
515: if (reg.IsSTOP()) {
516: reg.iadr = ((data & AM7990::IADR_H_MASK) << 16)
517: | (reg.iadr & 0xffff);
518: putlog(2, "IDAR(H)=$%06x", reg.iadr);
519: }
520: break;
521:
522: case 3:
523: // STOP 中のみ書き込み可能。そうでない時は無視する。
524: if (reg.IsSTOP()) {
525: reg.csr3 = data & AM7990::CSR3_MASK;
526: const std::string name = CSR3ToString(reg.csr3);
527: putlog(2, "CSR3 <- $%04x<%s>", reg.csr3, name.c_str());
528: }
529: break;
530:
531: default:
1.1.1.16 root 532: VMPANIC("corrupted reg.rap=%u", reg.rap);
1.1 root 533: }
534: }
535:
536: // メモリアクセスについて。
1.1.1.11 root 537: // LANCE(AM7990) から見たメモリは、メインメモリではなく 3ポートSRAM
1.1.1.13 root 538: // (ここでは SubRAM デバイス)。
539: // LANCE のメモリバスは 16bit で、DAL15..8 が SubRAM の偶数アドレス、
540: // DAL7..0 が SubRAM の奇数アドレスに接続されている。
1.1.1.11 root 541: //
1.1.1.13 root 542: // LANCE | DAL15..DAL8 | DAL7..DAL0
543: // -------+-------------+------------
544: // SubRAM | +0 byte | +1 byte
545: // | +2 byte | +3 byte
1.1 root 546: //
1.1.1.11 root 547: // メモリアクセスは常にこの構成で、CSR3.BSWP はこの1ワードを SILO(FIFO) に
548: // 書き込む/から読み出す順序を入れ替えるもの。
1.1 root 549:
1.1.1.16 root 550: // メモリから1ワード読み込む。addr はワードアラインしていること。
551: uint32
552: LanceDevice::ReadMem(uint32 addr)
1.1 root 553: {
1.1.1.16 root 554: assertmsg((addr & 1) == 0, "addr=$%x", addr);
1.1 root 555:
556: // XXX 所要クロックを考察すること
1.1.1.16 root 557: busdata data = subram->Read2(addr);
558: return data.Data();
1.1 root 559: }
560:
1.1.1.16 root 561: // メモリに1ワード書き込む。addr はワードアラインしていること。
562: void
563: LanceDevice::WriteMem(uint32 addr, uint32 data)
1.1 root 564: {
1.1.1.16 root 565: assertmsg((addr & 1) == 0, "addr=$%x", addr);
1.1 root 566:
567: // XXX 所要クロックを考察すること
1.1.1.16 root 568: subram->Write2(addr, data);
1.1 root 569: }
570:
571: // メモリ (3ポートSRAM) から1ワードピークする。バスエラーは起きない。
1.1.1.16 root 572: uint32
573: LanceDevice::PeekMem(uint32 addr) const
1.1 root 574: {
1.1.1.16 root 575: busdata data = subram->Peek2(addr);
576: return data.Data();
1.1 root 577: }
578:
579: // INIT ビットによるチップ初期化。
580: void
581: LanceDevice::ChipInit()
582: {
1.1.1.11 root 583: putlog(1, "ChipInit");
584:
1.1 root 585: // INIT をセットすると STOP ビットはクリア
586: reg.csr0 |= AM7990::CSR0_INIT;
587: reg.csr0 &= ~AM7990::CSR0_STOP;
588:
589: // Initialization Block を読み込む
590: for (int i = 0; i < countof(initblock); i++) {
591: initblock[i] = ReadMem(reg.iadr + i * 2);
592: }
593: if (0) {
594: for (int i = 0; i < countof(initblock); i++) {
1.1.1.16 root 595: putlog(2, "initblock[%u] = $%04x", i, initblock[i]);
1.1 root 596: }
597: }
598:
599: // 送受信ディスクリプタ用の内部変数を設定
600: uint32 rdrp = initblock[8] | (initblock[9] << 16);
601: rmd_base = rdrp & 0xfffffc;
602: int rlen = rdrp >> 29;
603: rmd_num = (1 << rlen);
604:
605: uint32 tdrp = initblock[10] | (initblock[11] << 16);
606: tmd_base = tdrp & 0xfffffc;
607: int tlen = tdrp >> 29;
608: tmd_num = (1 << tlen);
609:
1.1.1.18! root 610: padr = MacAddr(
! 611: initblock[1] & 0xff,
! 612: initblock[1] >> 8,
! 613: initblock[2] & 0xff,
! 614: initblock[2] >> 8,
! 615: initblock[3] & 0xff,
! 616: initblock[3] >> 8);
1.1.1.11 root 617:
1.1.1.15 root 618: // LADRF は以下のように格納されていて、そのまま LADRF(63:00) に対応する。
619: // IADR+$08 LADRF(15:00)
620: // IADR+$0a LADRF(31:16)
621: // IADR+$0c LADRF(47:32)
622: // IADR+$0e LADRF(63:48)
1.1.1.18! root 623: ladrf = ((uint64)initblock[4] << 0)
! 624: | ((uint64)initblock[5] << 16)
! 625: | ((uint64)initblock[6] << 32)
! 626: | ((uint64)initblock[7] << 48);
! 627:
! 628: promisc = (initblock[0] & AM7990::IBMODE_PROM);
1.1.1.9 root 629:
1.1 root 630: // XXX 本当はいろいろ時間がかかりそうなはずだが
631: // 初期化完了
632: SetInterrupt(AM7990::CSR0_IDON);
633: }
634:
635: // STRT ビットによるスタート。
636: void
637: LanceDevice::ChipStart()
638: {
1.1.1.12 root 639: putlog(1, "Start");
1.1 root 640:
641: // STRT を書き込むと STOP はクリア
642: reg.csr0 |= AM7990::CSR0_STRT;
643: reg.csr0 &= ~AM7990::CSR0_STOP;
644:
645: // MODE の DTX がクリアなら TXON をセット?
646: // XXX 実際はタイミング違う気がする
647: // INIT で DTX==%0 ならトランスミッタがオンになり、
648: // トランスミッタがオンで STRT すると TXON がオンになる、ように読めるが
649: // トランスミッタは省略してみる。
650: // RX 側も同様。
651: if ((initblock[0] & AM7990::IBMODE_DTX) == 0) {
652: reg.csr0 |= AM7990::CSR0_TXON;
653: }
654: if ((initblock[0] & AM7990::IBMODE_DRX) == 0) {
655: reg.csr0 |= AM7990::CSR0_RXON;
656: }
657:
658: // 初回読み込みに備えて RMD1/TMD1 の先読みバッファを無効化する
659: rmd1_ahead = (uint32)-1;
660: tmd1_ahead = (uint32)-1;
661:
1.1.1.11 root 662: // バッファクリア
663: tx_packet.Clear();
664:
1.1.1.9 root 665: ChangePhase(TXPhase::IDLE, 0_nsec);
666: ChangePhase(RXPhase::IDLE, 0_nsec);
1.1.1.11 root 667:
668: // ホストの受信を開始する
669: hostnet->EnableRx(true);
1.1 root 670: }
671:
672: // STOP ビットによるチップリセット。
673: // ハードリセットもここに来る。
674: void
675: LanceDevice::ChipStop()
676: {
1.1.1.12 root 677: putlog(1, "Reset");
1.1 root 678:
679: // STOPセットで CSR0 は STOP セット、他は全クリア
680: reg.csr0 = AM7990::CSR0_STOP;
1.1.1.15 root 681: ChangeInterrupt();
1.1 root 682: // CSR1, 2 は不定
683: // CSR3 はクリア
684: reg.csr3 = 0;
685:
686: // 内部ポインタも戻す
687: tmd_cur = 0;
688: rmd_cur = 0;
689:
690: // イベントを(あれば)停止。
1.1.1.11 root 691: ChangePhase(RXPhase::STOP);
692: ChangePhase(TXPhase::STOP);
1.1 root 693:
1.1.1.11 root 694: // バッファクリア
695: rx_packet.Clear();
696: tx_packet.Clear();
1.1.1.9 root 697:
1.1.1.11 root 698: // ホストの受信を停止する
699: hostnet->EnableRx(false);
1.1 root 700: }
701:
1.1.1.7 root 702: // 割り込み要因を CSR0 にセットし、必要なら割り込みを上げる。
1.1 root 703: void
704: LanceDevice::SetInterrupt(uint32 bit)
705: {
706: reg.csr0 |= bit;
1.1.1.7 root 707: ChangeInterrupt();
1.1 root 708: }
709:
1.1.1.7 root 710: // 現状に合わせて割り込み信号線の状態を変える。
1.1 root 711: void
1.1.1.7 root 712: LanceDevice::ChangeInterrupt()
1.1 root 713: {
1.1.1.15 root 714: bool irq = (reg.IsINTR() && (reg.csr0 & AM7990::CSR0_INEA));
715: interrupt->ChangeINT(this, irq);
1.1 root 716: }
717:
718: // TXIDLE 送信アイドルフェーズ。
719: // ディスクリプタを所有できるかポーリングする。
1.1.1.9 root 720: // - 所有できれば TXCOPY フェーズへ。
721: // - 所有できない場合、TDMD オンなら即、
722: // オフなら 1.6ms 待ってから再び TXIDLE へ。
1.1 root 723: void
1.1.1.15 root 724: LanceDevice::TXIdle(Event& ev)
1.1 root 725: {
1.1.1.9 root 726: tx_phase = TXPhase::IDLE;
727:
728: // TDMD クリア
729: reg.csr0 &= ~AM7990::CSR0_TDMD;
730:
1.1 root 731: // TMD1 を読み込む
732: if ((int32)tmd1_ahead >= 0) {
733: // すでに先読みしてあればそれを使う
734: tmd1 = tmd1_ahead;
735: } else {
736: // 読み込む
737: uint32 tmd_addr = tmd_base + tmd_cur * 8;
738: tmd1 = ReadMem(tmd_addr + 2);
739: }
740: // どちらにしても先読みバッファは無効に戻す
741: tmd1_ahead = (uint32)-1;
742:
743: // その TMD1 に OWN と STP が立っているか
744: if ((tmd1 & AM7990::TMD1_OWN) && (tmd1 & AM7990::TMD1_STP)) {
745: // 取り込みへ
1.1.1.11 root 746: TXCopy();
1.1 root 747: return;
748: }
749:
1.1.1.9 root 750: // 立っていなければ次回は 1.6ms 後
751: ChangePhase(TXPhase::IDLE, 1.6_msec);
1.1 root 752: }
753:
754: // TXCOPY バッファ処理フェーズ。
755: // 現ディスクリプタのバッファの内容をメモリから読み込み、
756: // それにかかる時間相当分をウェイトする。
1.1.1.9 root 757: // - ENP ならウェイトした後 TXSEND フェーズへ。
758: // - 次 TMD が OWN できればウェイトした後 TXNEXT フェーズへ。
759: // - 次 TMD が OWN 出来なければウェイトした後 TXSEND フェーズ。
1.1 root 760: void
1.1.1.11 root 761: LanceDevice::TXCopy()
1.1 root 762: {
1.1.1.9 root 763: tx_phase = TXPhase::COPY;
764:
1.1 root 765: // TMD0, TMD2 は送信することが確定してから読み出す
766: uint32 tmd_addr = tmd_base + tmd_cur * 8;
767: uint16 tmd0 = ReadMem(tmd_addr);
768: uint16 tmd2 = ReadMem(tmd_addr + 4);
769:
1.1.1.11 root 770: // アドレスと送信バイト数。
771: // tmd2 には 2 の補数で送信バイト数が入っているので符号反転する。
772: uint32 src = ((tmd1 & 0x00ff) << 16) | tmd0;
773: int32 bcnt = -(int32)(int16)tmd2;
774:
775: // copycnt は bcnt のうち実際にコピーするバイト数
776: int32 copycnt;
777: if (tx_packet.length + bcnt > tx_packet.size()) {
778: // コピーするとバッファが溢れてしまう計算なら、溢れないように打ち切る。
779: copycnt = tx_packet.size() - tx_packet.length;
780: } else {
781: // 全部コピーできる。
782: copycnt = bcnt;
783: }
784:
785: // 送信パケットキュー上の書き込み中バッファに追記する
786: uint8 *dst = &tx_packet[tx_packet.length];
787: tx_packet.length += copycnt;
788:
1.1.1.13 root 789: // ここから、SubRAM からローカルの送信バッファにコピー
1.1.1.11 root 790: // XXX バーストコピー未対応
791: const uint32 srcend = src + bcnt;
792: const uint8 *dstend = dst + copycnt;
793:
794: // src が奇数アドレスから始まっている(そしてコピー可能な)場合
795: // (バッファを奇数アドレスから始めたりする奇特な人はいないと思うが)
796: if (__predict_false((src & 1) != 0) && dst < dstend) {
797: uint16 data = ReadMem(src & ~1);
798: if (reg.IsBSWP() == false) {
799: *dst++ = data >> 8;
800: } else {
801: *dst++ = data & 0xff;
802: }
803: src++;
804: }
1.1 root 805:
1.1.1.11 root 806: // 残り2バイト以上コピー可能な間 (ここで src はワード境界になっている)
807: const uint8 *dstend_even;
808: dstend_even = (const uint8 *)((uintptr_t)dstend & ~(uintptr_t)1);
809: while (dst < dstend_even) {
810: uint16 data = ReadMem(src);
811: if (reg.IsBSWP() == false) {
812: *dst++ = data & 0xff;
813: *dst++ = data >> 8;
814: } else {
815: *dst++ = data >> 8;
816: *dst++ = data & 0xff;
817: }
818: src += 2;
819: }
1.1 root 820:
1.1.1.11 root 821: // src が奇数アドレスで終わっている(そしてコピー可能な)場合
822: if (__predict_false(dst < dstend)) {
823: uint16 data = ReadMem(src);
824: if (reg.IsBSWP() == false) {
825: *dst++ = data & 0xff;
1.1 root 826: } else {
1.1.1.11 root 827: *dst++ = data >> 8;
1.1 root 828: }
1.1.1.11 root 829: src += 2;
830: }
831:
1.1.1.13 root 832: // tx_packet が一杯になったら後はディスクリプタが終わるまで SubRAM から
1.1.1.11 root 833: // 読み捨てる。tx_packet の長さに上限があるのはこっち(エミュレータ)の
834: // 都合であって LANCE はディスクリプタが終わるまで延々読み込んでは出力を
835: // 続けるようだ。ここでは同じだけ読み込むところ、それにかかる時間を求める
836: // ところを再現する。tx_packet がイーサネットフレーム長を超過していると
837: // この後 SEND フェーズで BABBLE ビットを立てるところも再現する。
838: // 正確には 1519バイト目の送信で立てるのだが、通常は起きない上に面倒
839: // なので省略。1519バイト以上のパケットをホストに流すこともしない。
840: while (src < srcend) {
841: ReadMem(src);
842: src += 2;
1.1 root 843: }
844:
1.1.1.9 root 845: // メモリからの転送にかかった時間をざっくり計算 XXX まだ適当
846: // そのウェイト後に指定のフェーズへ。
1.1.1.11 root 847: uint64 t = 700 * bcnt / 16;
1.1.1.9 root 848:
1.1 root 849: // ここが ENP なら、送信のため TXSEND フェーズへ
850: if ((tmd1 & AM7990::TMD1_ENP)) {
1.1.1.9 root 851: ChangePhase(TXPhase::SEND, t);
1.1 root 852: } else {
853: // 次のディスクリプタを先読み
854: tmd_addr = tmd_base + ((tmd_cur + 1) % tmd_num) * 8;
855: tmd1_ahead = ReadMem(tmd_addr + 2);
856:
857: if ((tmd1_ahead & AM7990::TMD1_OWN)) {
858: // 次ディスクリプタが所有できれば TXNEXT フェーズへ
1.1.1.9 root 859: ChangePhase(TXPhase::NEXT, t);
1.1 root 860: } else {
861: // この時点で所有できなければアンダーフロー。
862: // ここまでのバッファでパケットを送信するため TXSEND へ。
863: // エラーフラグの処理は TXSEND 側で行う。
1.1.1.9 root 864: ChangePhase(TXPhase::SEND, t);
1.1 root 865: }
866: }
867: }
868:
869: // TXSEND フェーズ。パケットを送信。
870: // ただし ENP でなければアンダーフローによるパケット送信なのでフラグ処理。
871: // その後 TXNEXT フェーズへ。
872: void
1.1.1.15 root 873: LanceDevice::TXSend(Event& ev)
1.1 root 874: {
1.1.1.9 root 875: tx_phase = TXPhase::SEND;
876:
1.1.1.11 root 877: if (__predict_false(tx_packet.length > 1518)) {
878: // 本当は 1519バイト目を送ったところで BABL を立てるのだが
879: // まず起きない上に面倒なので、ここで行う。
880: SetInterrupt(AM7990::CSR0_BABL);
881:
882: // 1519バイト以上のパケットはホストにも投げない。
883: } else {
884: // 送信
885: hostnet->Tx(tx_packet);
886: }
887: tx_packet.Clear();
1.1 root 888:
889: // ENP でなければアンダーフローによるものだった
890: if ((tmd1 & AM7990::TMD1_ENP) == 0) {
891: // TMD3 はここで書き出す
892: // XXX 読まずに書くだけもいいはず?
893: uint32 tmd_addr = tmd_base + tmd_cur * 8;
894: uint16 tmd3 = ReadMem(tmd_addr + 6);
895: tmd3 |= AM7990::TMD3_BUFF | AM7990::TMD3_UFLO;
896: WriteMem(tmd_addr + 6, tmd3);
897:
1.1.1.9 root 898: // TMD1 は TXNEXT フェーズで書き戻す
1.1 root 899: tmd1 |= AM7990::TMD1_ERR;
900: }
901:
902: // どちらにしても送信割り込み
903: SetInterrupt(AM7990::CSR0_TINT);
904:
1.1.1.9 root 905: ChangePhase(TXPhase::NEXT);
1.1 root 906: }
907:
908: // TXNEXT フェーズ。次のディスクリプタを指して TXIDLE へ。
909: void
1.1.1.15 root 910: LanceDevice::TXNext(Event& ev)
1.1 root 911: {
1.1.1.9 root 912: tx_phase = TXPhase::NEXT;
913:
1.1 root 914: // このディスクリプタの所有権を放棄
915: tmd1 &= ~AM7990::TMD1_OWN;
916: uint32 tmd_addr = tmd_base + tmd_cur * 8;
917: WriteMem(tmd_addr + 2, tmd1);
918:
1.1.1.9 root 919: // 即、次のディスクリプタの所有を試みる
1.1 root 920: tmd_cur = (tmd_cur + 1) % tmd_num;
1.1.1.9 root 921: ChangePhase(TXPhase::IDLE);
1.1 root 922: }
923:
1.1.1.9 root 924: // 指定時間後に TX フェーズを遷移する。
925: // (変化があれば)変更するではないことに注意。名前がアレだが IDLE フェーズは
926: // ポーリングしているので IDLE から IDLE への遷移も必ず起こす必要がある。
927: // TX か RX かは関数オーバーロードで区別している。
928: void
929: LanceDevice::ChangePhase(TXPhase new_phase, uint64 time)
1.1 root 930: {
1.1.1.9 root 931: tx_event.time = time;
932: switch (new_phase) {
1.1.1.11 root 933: case TXPhase::STOP:
1.1.1.13 root 934: scheduler->StopEvent(tx_event);
1.1.1.11 root 935: return;
1.1.1.9 root 936: case TXPhase::IDLE:
1.1.1.11 root 937: tx_event.func = ToEventCallback(&LanceDevice::TXIdle);
1.1.1.9 root 938: break;
939: case TXPhase::SEND:
1.1.1.11 root 940: tx_event.func = ToEventCallback(&LanceDevice::TXSend);
1.1.1.9 root 941: break;
942: case TXPhase::NEXT:
1.1.1.11 root 943: tx_event.func = ToEventCallback(&LanceDevice::TXNext);
1.1.1.9 root 944: break;
945: default:
1.1.1.16 root 946: assertmsg(false, "phase %u", (uint)new_phase);
1.1 root 947: }
1.1.1.13 root 948: scheduler->RestartEvent(tx_event);
1.1.1.9 root 949: }
1.1 root 950:
1.1.1.11 root 951: // 受信フェーズ遷移図
952: //
953: // +--------+
954: // | RXSTOP |<- - - (CSR0.STOP 書き込み / リセット)
955: // +--------+
956: // :
1.1.1.15 root 957: // : +‥‥‥+ <‥‥ RxMessage (パケット受信)
1.1.1.11 root 958: // v v :
959: // +-------------+ :
960: // +‥‥‥>| RXIDLE |‥‥+ Idle
961: // : +-------------+
962: // : | | ^
963: // : | | :
964: // : v | :
965: // : +--------+ | +--------+
966: // +‥| RXMISS | | | RXNEXT |
967: // +--------+ | +--------+
968: // | ^ |
969: // | : |
970: // v : v
971: // +-----------+
972: // | RXCOPY | 関数呼び出し ---->
973: // +-----------+ イベントによる遷移 ‥‥>
974:
1.1.1.15 root 975: // パケット受信通知。HostNet から (EthernetDevice 経由で) 呼ばれる。
1.1.1.9 root 976: void
1.1.1.15 root 977: LanceDevice::RxMessage(MessageID msgid, uint32 arg)
1.1.1.9 root 978: {
979: // RXIDLE ポーリングのウェイト中ならすぐに始める。
980: // そうでないときは RXIDLE に戻ったところで処理される。
981: if (rx_phase == RXPhase::IDLE) {
982: ChangePhase(RXPhase::IDLE);
983: }
1.1 root 984: }
985:
986: // RXIDLE 受信アイドルフェーズ。
987: // (最初の)ディスクリプタを所有できるかポーリングする。
988: void
1.1.1.15 root 989: LanceDevice::RXIdle(Event& ev)
1.1 root 990: {
1.1.1.9 root 991: rx_phase = RXPhase::IDLE;
992:
1.1.1.16 root 993: putlog(3, "%s[%u]", __func__, rmd_cur);
1.1.1.9 root 994:
1.1 root 995: // RMD1 を読み込む
996: if ((int32)rmd1_ahead >= 0) {
997: // すでにあればそれを使う
998: rmd1 = rmd1_ahead;
999: } else {
1000: // 読み込む
1001: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1002: rmd1 = ReadMem(rmd_addr + 2);
1003: }
1004: // どちらにしても先読みバッファは無効に戻す
1005: rmd1_ahead = (uint32)-1;
1006:
1.1.1.9 root 1007: // 受信しているか
1.1.1.11 root 1008: if (hostnet->Rx(&rx_packet)) {
1.1.1.9 root 1009: // その RMD1 に OWN が立っているか
1010: if ((rmd1 & AM7990::RMD1_OWN)) {
1011: // ここが STP になる
1012: rmd1 |= AM7990::RMD1_STP;
1.1.1.11 root 1013: // RXCOPY へ直接移行する。
1014: RXCopy();
1.1.1.9 root 1015: } else {
1.1.1.11 root 1016: // バッファが無いので MISS へ直接移行する。
1.1.1.9 root 1017: // MISS までの時間は受信処理によって表現されているはず
1.1.1.11 root 1018: RXMiss();
1.1.1.9 root 1019: }
1.1 root 1020: } else {
1.1.1.9 root 1021: if ((rmd1 & AM7990::RMD1_OWN)) {
1022: // ここが STP になる
1023: rmd1 |= AM7990::RMD1_STP;
1024: }
1025: // 1.6ms 待って再度 RXIDLE へ。
1026: ChangePhase(RXPhase::IDLE, 1.6_msec);
1.1 root 1027: }
1028: }
1029:
1030: // RXCOPY バッファ処理フェーズ。
1031: // 受信バッファからディスクリプタのバッファに書き込み、
1032: // 書き込みにかかる時間相当分をウェイトする。
1033: void
1.1.1.11 root 1034: LanceDevice::RXCopy()
1.1 root 1035: {
1.1.1.9 root 1036: rx_phase = RXPhase::COPY;
1037:
1.1.1.16 root 1038: putlog(1, "%s[%u]", __func__, rmd_cur);
1.1.1.9 root 1039:
1.1 root 1040: // RMD0, RMD2 は受信することが確定してから読み出す
1041: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1042: uint16 rmd0 = ReadMem(rmd_addr);
1043: uint16 rmd2 = ReadMem(rmd_addr + 4);
1044:
1.1.1.11 root 1045: // アドレスと受信バッファのバイト数。
1.1 root 1046: uint32 bufdst = ((rmd1 & 0x00ff) << 16) | rmd0;
1047: uint32 dst = bufdst;
1.1.1.11 root 1048: // rmd2 は 2 の補数
1049: int32 bcnt = -(int32)(int16)rmd2;
1.1 root 1050:
1.1.1.11 root 1051: if (bcnt < rx_packet.length) {
1.1.1.16 root 1052: putlog(1, "will be remain: %d < %u", bcnt, rx_packet.length);
1.1.1.9 root 1053: }
1054:
1.1.1.11 root 1055: uint8 *src = &rx_packet[0];
1.1.1.16 root 1056: uint remsize = rx_packet.length;
1.1.1.11 root 1057:
1058: if (bcnt > remsize) {
1059: bcnt = remsize;
1060: }
1.1 root 1061:
1.1.1.11 root 1062: // コピー後の残りサイズにしておく
1063: remsize -= bcnt;
1064:
1065: // ローカルの受信バッファからディスクリプタバッファにコピー
1066: for (; bcnt > 0; ) {
1.1 root 1067: // XXX バーストコピー未対応
1068: uint16 data;
1.1.1.11 root 1069: if (bcnt >= 2 && (dst & 1) == 0) {
1.1 root 1070: // 2バイト以上残っててワード境界ならワードアクセス
1.1.1.11 root 1071: if (reg.IsBSWP() == false) {
1072: data = *src++;
1073: data |= (*src++) << 8;
1074: } else {
1075: data = (*src++) << 8;
1076: data |= *src++;
1077: }
1.1 root 1078: WriteMem(dst, data);
1079: dst += 2;
1.1.1.11 root 1080: bcnt -= 2;
1.1 root 1081: } else if ((dst & 1) == 0) {
1082: // 偶数アドレスへ1バイト
1083: // 奇数バイトには不定データが出るらしいがここでは 0 にする
1.1.1.11 root 1084: if (reg.IsBSWP() == false) {
1085: data = *src++;
1086: } else {
1087: data = (*src++) << 8;
1088: }
1.1 root 1089: WriteMem(dst, data);
1090: dst += 1;
1.1.1.11 root 1091: bcnt -= 1;
1.1 root 1092: } else {
1093: // 奇数アドレスへ1バイト
1094: // 偶数バイトには不定データが出るらしいがここでは 0 にする
1.1.1.11 root 1095: if (reg.IsBSWP() == false) {
1096: data = (*src++) << 8;
1097: } else {
1098: data = *src++;
1099: }
1.1 root 1100: WriteMem(dst & ~1, data);
1101: dst += 1;
1.1.1.11 root 1102: bcnt -= 1;
1.1 root 1103: }
1104: }
1105:
1106: // 全部書き出せたらここが ENP
1.1.1.11 root 1107: if (remsize == 0) {
1.1 root 1108: rmd1 |= AM7990::RMD1_ENP;
1109:
1110: // ENP なら MCNT を更新
1111: WriteMem(rmd_addr + 6, (dst - bufdst) & 0xfff);
1.1.1.9 root 1112: } else {
1113: rmd1 &= ~AM7990::RMD1_ENP;
1.1.1.16 root 1114: putlog(1, "copy remain %u", remsize);
1.1.1.11 root 1115:
1116: // 前詰めにコピーする
1117: memmove(&rx_packet[0], src, remsize);
1118: rx_packet.length = remsize;
1.1 root 1119: }
1120:
1121: // メモリへの転送にかかった時間をざっくり計算 XXX まだ適当
1122: // そのウェイト後に RXNEXT フェーズへ。
1.1.1.10 root 1123: uint64 t = 700 * (dst - bufdst) / 16;
1.1.1.9 root 1124: ChangePhase(RXPhase::NEXT, t);
1.1 root 1125: }
1126:
1127: // RXNEXT フェーズ。
1128: // ここが ENP なら、次のディスクリプタを指して RXIDLE へ。
1129: // ENP でなければ、
1130: // - 次のディスクリプタが所有できれば引き続き書き出すため RXCOPY へ。
1131: // - 次のディスクリプタが所有できなければエラーにして RXIDLE へ。
1132: void
1.1.1.15 root 1133: LanceDevice::RXNext(Event& ev)
1.1 root 1134: {
1.1.1.9 root 1135: rx_phase = RXPhase::NEXT;
1136:
1.1.1.16 root 1137: putlog(1, "%s[%u]", __func__, rmd_cur);
1.1 root 1138:
1.1.1.9 root 1139: bool is_chained = false;
1.1 root 1140:
1141: if ((rmd1 & AM7990::RMD1_ENP)) {
1142: // ENP なら、RXIDLE へ。
1.1.1.11 root 1143: rx_packet.Clear();
1.1.1.9 root 1144: ChangePhase(RXPhase::IDLE);
1.1 root 1145: } else {
1146: // 次のディスクリプタを先読み
1147: uint32 rmd_addr = rmd_base + ((rmd_cur + 1) % rmd_num) * 8;
1148: rmd1_ahead = ReadMem(rmd_addr + 2);
1149:
1150: if ((rmd1_ahead & AM7990::RMD1_OWN)) {
1151: // 次ディスクリプタが所有できれば RXCOPY へ。
1.1.1.9 root 1152: is_chained = true;
1.1 root 1153: } else {
1154: // この時点で所有できなければオーバーフロー。
1155: // XXX BUFF と OFLO の違いがよくわからん
1156: rmd1 |= AM7990::RMD1_BUFF | AM7990::RMD1_OFLO;
1157:
1.1.1.11 root 1158: // 書き込み先が無いのでこのパケットは打ち切ってみる
1159: rx_packet.Clear();
1160:
1.1 root 1161: // 次のディスクリプタをポールするため RXIDLE へ。
1.1.1.9 root 1162: ChangePhase(RXPhase::IDLE);
1.1 root 1163: }
1164: }
1165:
1166: // このディスクリプタの所有権を放棄
1167: rmd1 &= ~AM7990::RMD1_OWN;
1168: uint32 rmd_addr = rmd_base + rmd_cur * 8;
1169: WriteMem(rmd_addr + 2, rmd1);
1170:
1171: // 次のディスクリプタへ
1172: rmd_cur = (rmd_cur + 1) % rmd_num;
1173:
1.1.1.11 root 1174: // どちらにしても受信割り込み
1175: SetInterrupt(AM7990::CSR0_RINT);
1176:
1.1.1.9 root 1177: if (is_chained) {
1.1.1.11 root 1178: // 次のディスクリプタがある場合は RXCopy に直接遷移する。
1.1.1.9 root 1179: rmd1 = rmd1_ahead;
1180: rmd1_ahead = -1;
1.1.1.11 root 1181: RXCopy();
1.1.1.9 root 1182: }
1.1 root 1183: }
1184:
1185: // RXMISS 受信失敗処理。
1186: void
1.1.1.11 root 1187: LanceDevice::RXMiss()
1.1 root 1188: {
1.1.1.9 root 1189: rx_phase = RXPhase::MISS;
1190:
1191: putlog(1, "%s", __func__);
1.1 root 1192:
1193: // 受信データがあるのにディスクリプタを所有してなければエラー
1194: SetInterrupt(AM7990::CSR0_MISS | AM7990::CSR0_RINT);
1195:
1196: // 受信データを破棄。
1.1.1.11 root 1197: rx_packet.Clear();
1.1 root 1198:
1199: // そのまますぐにアイドルフェーズに戻るんだろうか
1.1.1.9 root 1200: ChangePhase(RXPhase::IDLE);
1.1 root 1201: }
1202:
1.1.1.18! root 1203: // この宛先アドレスを受信するかどうか。
! 1204: // これは HostNet スレッドで呼ばれる。
! 1205: int
! 1206: LanceDevice::HWAddrFilter(const MacAddr& dstaddr) const
! 1207: {
! 1208: if (promisc) {
! 1209: return HPF_PASS;
! 1210: }
! 1211:
! 1212: if (dstaddr.IsUnicast()) {
! 1213: if (dstaddr != padr) {
! 1214: return HPF_DROP_UNICAST;
! 1215: }
! 1216: } else {
! 1217: if (dstaddr.IsBroadcast()) {
! 1218: return HPF_PASS;
! 1219: }
! 1220:
! 1221: // マルチキャスト。
! 1222: //
! 1223: // AM7990 のマルチキャストフィルタ(ハッシュ) は宛先 MAC アドレスの
! 1224: // CRC (32ビット) のうち、下位6ビット *のビット順を逆順にしたもの*
! 1225: // を pos として、LADRF の下から pos ビット目が立っていれば受理する
! 1226: // というもの。
! 1227: // 31 7 6 5 4 3 2 1 0
! 1228: // +--- -+---+---+---+---+---+---+---+---+
! 1229: // CRC32(dstaddr) = | .. | X X | p0| p1| p2| p3| p4| p5|
! 1230: // +--- -+---+---+---+---+---+---+---+---+
! 1231: //
! 1232: // +---+---+---+---+---+---+
! 1233: // pos = | p5| p4| p3| p2| p1| p0|
! 1234: // +---+---+---+---+---+---+
! 1235:
! 1236: uint32 crc = EthernetDevice::CRC32(dstaddr);
! 1237: uint pos = bitrev8(crc) >> 2;
! 1238: bool mcast_pass = (ladrf & (1ULL << pos));
! 1239: putmsg(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%u %s",
! 1240: dstaddr[0], dstaddr[1], dstaddr[2],
! 1241: dstaddr[3], dstaddr[4], dstaddr[5],
! 1242: pos, (mcast_pass ? "pass" : "drop"));
! 1243: if (mcast_pass == false) {
! 1244: return HPF_DROP_MULTICAST;
! 1245: }
! 1246: }
! 1247:
! 1248: return HPF_PASS;
! 1249: }
! 1250:
1.1.1.9 root 1251: // 指定時間後に RX フェーズを遷移する。
1252: // (変化があれば)変更するではないことに注意。名前がアレだが IDLE フェーズは
1253: // ポーリングしているので IDLE から IDLE への遷移も必ず起こす必要がある。
1254: // TX か RX かは関数オーバーロードで区別している。
1.1 root 1255: void
1.1.1.9 root 1256: LanceDevice::ChangePhase(RXPhase new_phase, uint64 time)
1.1 root 1257: {
1.1.1.9 root 1258: rx_event.time = time;
1259: switch (new_phase) {
1.1.1.11 root 1260: case RXPhase::STOP:
1.1.1.13 root 1261: scheduler->StopEvent(rx_event);
1.1.1.11 root 1262: return;
1.1.1.9 root 1263: case RXPhase::IDLE:
1.1.1.11 root 1264: rx_event.func = ToEventCallback(&LanceDevice::RXIdle);
1.1.1.9 root 1265: break;
1266: case RXPhase::NEXT:
1.1.1.11 root 1267: rx_event.func = ToEventCallback(&LanceDevice::RXNext);
1.1.1.9 root 1268: break;
1269: default:
1.1.1.16 root 1270: assertmsg(false, "phase %u", (uint)new_phase);
1.1.1.9 root 1271: }
1.1.1.13 root 1272: scheduler->RestartEvent(rx_event);
1.1 root 1273: }
1274:
1.1.1.9 root 1275:
1.1 root 1276: // ビット名文字列配列は [0] が MSB 側の順で並べる
1277:
1278: /*static*/ const char * const LanceDevice::csr0names[] = {
1279: "ERR", "BABL", "CERR", "MISS", "MERR", "RINT", "TINT", "IDON",
1280: "INTR", "INEA", "RXON", "TXON", "TDMD", "STOP", "STRT", "INIT",
1281: };
1282:
1283: /*static*/ const char * const LanceDevice::csr3names[] = {
1.1.1.8 root 1284: "", "", "", "", "", "", "", "",
1.1 root 1285: "", "", "", "", "", "BSWP", "ACON", "BCON",
1286: };
1287:
1288: /*static*/ const char * const LanceDevice::ib_mode_names[] = {
1289: "PROM", "INTL", "DRTY", "COLL", "DTCR", "LOOP", "DTX", "DRX",
1290: };
1291:
1292: /*static*/ const char * const LanceDevice::rmd1_names[] = {
1293: "OWN", "ERR", "FRAM", "OFLO", "CRC", "BUFF", "STP", "ENP",
1294: };
1295:
1296: /*static*/ const char * const LanceDevice::tmd1_names[] = {
1297: "OWN", "ERR", "----", "MORE", "ONE", "DEF", "STP", "ENP",
1298: };
1299:
1300: /*static*/ const char * const LanceDevice::tmd3_names[] = {
1301: "BUFF", "UFLO", "----", "LCOL", "LCAR", "BTRY", "", "",
1302: };
1303:
1304: // bits の立っているビット名を左から MSB->LSB の順で並べて返す
1305: const std::string
1306: LanceDevice::BitToString(const char * const name[], uint16 bits)
1307: {
1308: std::string str;
1309:
1310: while (bits) {
1311: int clz = __builtin_clz(bits) - 16;
1312: if (!str.empty()) {
1313: str += ",";
1314: }
1315: str += name[clz];
1316: bits ^= 1 << (15 - clz);
1317: }
1318: return str;
1319: }
1320:
1321: // CSR0 のビット名を返す
1322: const std::string
1323: LanceDevice::CSR0ToString(uint16 bits)
1324: {
1325: return BitToString(csr0names, bits);
1326: }
1327:
1328: // CSR3 のビット名を返す
1329: const std::string
1330: LanceDevice::CSR3ToString(uint16 bits)
1331: {
1332: return BitToString(csr3names, bits);
1333: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.