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