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