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