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