|
|
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.