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