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