|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2025 nono project ! 4: // Licensed under nono-license.txt ! 5: // ! 6: ! 7: // ! 8: // HD647180 ASCI (非同期シリアル) ! 9: // ! 10: ! 11: #include "hd647180asci.h" ! 12: #include "hostcom.h" ! 13: #include "monitor.h" ! 14: #include "mpu64180.h" ! 15: #include "scheduler.h" ! 16: ! 17: // コンストラクタ ! 18: HD647180ASCIDevice::HD647180ASCIDevice() ! 19: : inherited(OBJ_XP_ASCI) ! 20: { ! 21: // 入力クロックφ= 6.144MHz だが、設定に関わらず必ず 160 分周は ! 22: // されるので、それをした後の値を基本周波数(周期)とする。 ! 23: // 6.144MHz / 160 = 38400 [bps] = 26.04166... [usec/bit] ! 24: // 12倍すると 312.5 [usec] ! 25: xc12_ns = 312.5_usec; ! 26: ! 27: for (uint i = 0; i < channels.size(); i++) { ! 28: channels[i].id = i; ! 29: } ! 30: ! 31: monitor = gMonitorManager->Regist(ID_MONITOR_XPASCI, this); ! 32: monitor->func = ToMonitorCallback(&HD647180ASCIDevice::MonitorUpdate); ! 33: monitor->SetSize(63, 12); ! 34: } ! 35: ! 36: // デストラクタ ! 37: HD647180ASCIDevice::~HD647180ASCIDevice() ! 38: { ! 39: for (uint n = 0; n < channels.size(); n++) { ! 40: if ((bool)hostcom[n]) { ! 41: hostcom[n]->ResetRxCallback(); ! 42: } ! 43: } ! 44: } ! 45: ! 46: bool ! 47: HD647180ASCIDevice::Create() ! 48: { ! 49: static const char * const names[2] = { ! 50: "XP ASCI Ch.0", ! 51: "XP ASCI Ch.1", ! 52: }; ! 53: ! 54: // 対応するホストドライバを作成。 ! 55: for (auto& chan : channels) { ! 56: uint n = chan.id; ! 57: try { ! 58: hostcom[n].reset(new HostCOMDevice(this, n + 1, names[n])); ! 59: } catch (...) { } ! 60: if ((bool)hostcom[n] == false) { ! 61: warnx("Failed to initialize HostCOMDevice at %s", __method__); ! 62: return false; ! 63: } ! 64: auto func = ToDeviceCallback(&HD647180ASCIDevice::HostRxCallback); ! 65: hostcom[n]->SetRxCallback(func, n); ! 66: } ! 67: ! 68: return true; ! 69: } ! 70: ! 71: // 初期化 ! 72: bool ! 73: HD647180ASCIDevice::Init() ! 74: { ! 75: xp = GetMPU64180Device(); ! 76: ! 77: for (auto& chan : channels) { ! 78: uint n = chan.id; ! 79: ! 80: chan.tdr_empty = true; ! 81: chan.rdr_full = false; ! 82: ! 83: scheduler->ConnectMessage(MessageID::HOSTCOM_RX(n + 1), this, ! 84: ToMessageCallback(&HD647180ASCIDevice::RxMessage)); ! 85: ! 86: txevent[n].dev = this; ! 87: txevent[n].func = ToEventCallback(&HD647180ASCIDevice::TxCallback); ! 88: txevent[n].code = n; ! 89: txevent[n].SetName(string_format("XP ASCI Ch%c TX", n + '0')); ! 90: scheduler->RegistEvent(txevent[n]); ! 91: ! 92: rxevent[n].dev = this; ! 93: rxevent[n].func = ToEventCallback(&HD647180ASCIDevice::RxCallback); ! 94: rxevent[n].code = n; ! 95: rxevent[n].SetName(string_format("XP ASCI Ch%c RX", n + '0')); ! 96: scheduler->RegistEvent(rxevent[n]); ! 97: } ! 98: ! 99: return true; ! 100: } ! 101: ! 102: // リセット ! 103: void ! 104: HD647180ASCIDevice::ResetHard(bool poweron) ! 105: { ! 106: // TDR, RDR はリセットの影響を受けない。 ! 107: // リセットで転送は止まる (.. are stopped during RESET) とは書いてあるが ! 108: // TSR, RSR がどうなるかは不明。さすがにリセットされるか。 ! 109: ! 110: nRTS0 = true; ! 111: cka1_disable = true; ! 112: ! 113: for (auto& chan : channels) { ! 114: uint n = chan.id; ! 115: ! 116: chan.rx_enable = false; ! 117: chan.tx_enable = false; ! 118: chan.rx_intr_enable = false; ! 119: chan.tx_intr_enable = false; ! 120: chan.data8bit = false; ! 121: chan.parity_en = false; ! 122: chan.stop2bit = false; ! 123: chan.parity_odd = false; ! 124: chan.prescale = false; ! 125: chan.divratio = false; ! 126: chan.ss = 7; ! 127: chan.nCTS = false; // ? ! 128: chan.tsr = -1; ! 129: chan.rsr = -1; ! 130: ChangeBaudRate(chan.id); ! 131: ChangeInterrupt(chan.id); ! 132: ! 133: scheduler->StopEvent(txevent[n]); ! 134: scheduler->StopEvent(rxevent[n]); ! 135: } ! 136: } ! 137: ! 138: uint32 ! 139: HD647180ASCIDevice::ReadCNTLA(uint n) ! 140: { ! 141: uint32 data = PeekCNTLA(n); ! 142: putlog(3, "CNTLA%u -> $%02x", n, data); ! 143: return data; ! 144: } ! 145: ! 146: uint32 ! 147: HD647180ASCIDevice::ReadCNTLB(uint n) ! 148: { ! 149: uint32 data = PeekCNTLB(n); ! 150: putlog(3, "CNTLB%u -> $%02x", n, data); ! 151: return data; ! 152: } ! 153: ! 154: uint32 ! 155: HD647180ASCIDevice::ReadSTAT(uint n) ! 156: { ! 157: uint32 data = PeekSTAT(n); ! 158: putlog(3, "STAT%u -> $%02x", n, data); ! 159: return data; ! 160: } ! 161: ! 162: uint32 ! 163: HD647180ASCIDevice::ReadTDR(uint n) ! 164: { ! 165: // TDR は副作用なく読み出し可能。 ! 166: uint32 data = PeekTDR(n); ! 167: putlog(3, "TDR%u -> $%02x", n, data); ! 168: return data; ! 169: } ! 170: ! 171: uint32 ! 172: HD647180ASCIDevice::ReadRDR(uint n) ! 173: { ! 174: Channel& chan = channels[n]; ! 175: ! 176: uint32 data = PeekRDR(n); ! 177: if (chan.rsr >= 0) { ! 178: chan.rdr = chan.rsr; ! 179: chan.rsr = -1; ! 180: } else { ! 181: chan.rdr_full = false; ! 182: } ! 183: putlog(4, "RDR%u -> $%02x", n, data); ! 184: return data; ! 185: } ! 186: ! 187: uint32 ! 188: HD647180ASCIDevice::WriteCNTLA(uint n, uint32 data) ! 189: { ! 190: Channel& chan = channels[n]; ! 191: std::string msg; ! 192: ! 193: if ((data & CNTL_MPE)) { ! 194: putlog(0, "MPE=1 (NOT IMPLEMENTED)"); ! 195: } ! 196: ! 197: bool newrxe = (data & CNTL_RE); ! 198: if (chan.rx_enable != newrxe) { ! 199: chan.rx_enable = newrxe; ! 200: if (__predict_false(loglevel >= 1)) { ! 201: msg += string_format(" RX=%s", (newrxe ? "Enable" : "Disable")); ! 202: } ! 203: } ! 204: ! 205: bool newtxe = (data & CNTL_TE); ! 206: if (chan.tx_enable != newtxe) { ! 207: chan.tx_enable = newtxe; ! 208: if (__predict_false(loglevel >= 1)) { ! 209: msg += string_format(" TX=%s", (newtxe ? "Enable" : "Disable")); ! 210: } ! 211: } ! 212: ! 213: if (n == 0) { ! 214: nRTS0 = (data & CNTL_nRTS0); ! 215: } else { ! 216: cka1_disable = (data & CNTL_CKA1D); ! 217: if (cka1_disable == false) { ! 218: putlog(0, "CKA1D=0 (NOT IMPLEMENTED)"); ! 219: } ! 220: } ! 221: ! 222: if ((data & CNTL_EFR)) { ! 223: // OVRN, FE, PE をクリアする。 ! 224: chan.overrun = false; ! 225: ChangeInterrupt(n); ! 226: } ! 227: ! 228: bool new8bit = (data & CNTL_DATA8); ! 229: bool newpen = (data & CNTL_PAREN); ! 230: bool newstop = (data & CNTL_STOP2); ! 231: if (chan.data8bit != new8bit || ! 232: chan.parity_en != newpen || ! 233: chan.stop2bit != newstop) ! 234: { ! 235: chan.data8bit = new8bit; ! 236: chan.parity_en = newpen; ! 237: chan.stop2bit = newstop; ! 238: ChangeBaudRate(n); ! 239: if (__predict_false(loglevel >= 1)) { ! 240: msg += string_format(" data=%u,stop=%u,parity=%s", ! 241: (chan.data8bit ? 8 : 7), ! 242: (chan.stop2bit ? 2 : 1), ! 243: (chan.parity_en ? "on" : "off")); ! 244: } ! 245: } ! 246: ! 247: if (__predict_false(loglevel >= 1)) { ! 248: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。 ! 249: int req; ! 250: if (msg.empty()) { ! 251: // 状態が変わっていない。 ! 252: req = 2; ! 253: } else { ! 254: req = 1; ! 255: msg[0] = '('; ! 256: msg += ')'; ! 257: } ! 258: putlog(req, "CNTLA%u <- $%02x %s", n, data, msg.c_str()); ! 259: } ! 260: ! 261: return 0; ! 262: } ! 263: ! 264: uint32 ! 265: HD647180ASCIDevice::WriteCNTLB(uint n, uint32 data) ! 266: { ! 267: Channel& chan = channels[n]; ! 268: std::string msg; ! 269: ! 270: if ((data & (CNTL_MPBT | CNTL_MP))) { ! 271: putlog(0, "MPBT|MP=1 (NOT IMPLEMENTED)"); ! 272: } ! 273: ! 274: bool newpo = (data & CNTL_PEO); ! 275: if (chan.parity_odd != newpo) { ! 276: chan.parity_odd = newpo; ! 277: if (__predict_false(loglevel >= 1)) { ! 278: msg += string_format(" Parity=%s", (newpo ? "Odd" : "Even")); ! 279: } ! 280: } ! 281: ! 282: bool newps = (data & CNTL_PS); ! 283: bool newdr = (data & CNTL_DR); ! 284: uint32 newss = (data & CNTL_SS); ! 285: if (chan.prescale != newps || ! 286: chan.divratio != newdr || ! 287: chan.ss != newss) ! 288: { ! 289: chan.prescale = newps; ! 290: chan.divratio = newdr; ! 291: chan.ss = newss; ! 292: ChangeBaudRate(n); ! 293: if (__predict_false(loglevel >= 1)) { ! 294: msg += string_format(" PS=%u DR=%u SS=%u", ! 295: (uint)newps, (uint)newdr, newss); ! 296: if (chan.baudrate > 0) { ! 297: msg += string_format(", %u bps", chan.baudrate); ! 298: } ! 299: } ! 300: } ! 301: ! 302: if (__predict_false(loglevel >= 1)) { ! 303: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。 ! 304: int req; ! 305: if (msg.empty()) { ! 306: // 状態が変わっていない。 ! 307: req = 2; ! 308: } else { ! 309: req = 1; ! 310: msg[0] = '('; ! 311: msg += ')'; ! 312: } ! 313: putlog(req, "CNTLB%u <- $%02x %s", n, data, msg.c_str()); ! 314: } ! 315: ! 316: return 0; ! 317: } ! 318: ! 319: uint32 ! 320: HD647180ASCIDevice::WriteSTAT(uint n, uint32 data) ! 321: { ! 322: Channel& chan = channels[n]; ! 323: std::string msg; ! 324: ! 325: if (n == 1) { ! 326: cts1_enable = (data & STAT_CTS1E); ! 327: if (cts1_enable) { ! 328: putlog(0, "CTS1E=1 (NOT IMPLEMENTED)"); ! 329: } ! 330: } ! 331: ! 332: bool newrie = (data & STAT_RIE); ! 333: if (chan.rx_intr_enable != newrie) { ! 334: chan.rx_intr_enable = newrie; ! 335: ChangeInterrupt(n); ! 336: msg += string_format(" RIE=%s", newrie ? "Enable" : "Disable"); ! 337: } ! 338: ! 339: bool newtie = (data & STAT_TIE); ! 340: if (chan.tx_intr_enable != newtie) { ! 341: chan.tx_intr_enable = newtie; ! 342: ChangeInterrupt(n); ! 343: msg += string_format(" TIE=%s", newrie ? "Enable" : "Disable"); ! 344: } ! 345: ! 346: if (__predict_false(loglevel >= 1)) { ! 347: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。 ! 348: int req; ! 349: if (msg.empty()) { ! 350: // 状態が変わっていない。 ! 351: req = 2; ! 352: } else { ! 353: req = 1; ! 354: msg[0] = '('; ! 355: msg += ')'; ! 356: } ! 357: putlog(req, "STAT%u <- $%02x %s", n, data, msg.c_str()); ! 358: } ! 359: ! 360: return 0; ! 361: } ! 362: ! 363: uint32 ! 364: HD647180ASCIDevice::WriteTDR(uint n, uint32 data) ! 365: { ! 366: Channel& chan = channels[n]; ! 367: ! 368: // どちらにしても一旦 TDR には置く。 ! 369: chan.tdr = data; ! 370: putlog(4, "TDR%u <- $%02x", n, data); ! 371: ! 372: // TDR TSR TDR TSR ! 373: // --- --- --- --- ! 374: // なし なし -> なし data イベント始動 ! 375: // なし 有り -> data 有り (イベントは動いてるはず) ! 376: // 有り なし (すぐ1行上に遷移するのでこの状態にはならない) ! 377: // 有り 有り -> data 有り ! 378: ! 379: if (chan.tsr < 0) { ! 380: // TSR が空なら即コピーして、送信イベント開始。 ! 381: chan.tsr = chan.tdr; ! 382: chan.tdr_empty = true; ! 383: if (txevent[n].IsRunning() == false) { ! 384: scheduler->StartEvent(txevent[n]); ! 385: } ! 386: } else { ! 387: // TSR が埋まっていれば何もしない。(イベントは動いてるはず) ! 388: chan.tdr_empty = false; ! 389: } ! 390: ! 391: ChangeInterrupt(n); ! 392: return 0; ! 393: } ! 394: ! 395: uint32 ! 396: HD647180ASCIDevice::WriteRDR(uint n, uint32 data) ! 397: { ! 398: Channel& chan = channels[n]; ! 399: ! 400: // RDR が空の時に限り、書き込み出来る。(p.69) ! 401: if (chan.rdr_full) { ! 402: putlog(1, "RDR%u <- $%02x (Write Ignored)", n, data); ! 403: } else { ! 404: chan.rdr = data; ! 405: putlog(4, "RDR%u <- $%02x", n, data); ! 406: } ! 407: return 0; ! 408: } ! 409: ! 410: uint32 ! 411: HD647180ASCIDevice::PeekCNTLA(uint n) const ! 412: { ! 413: const Channel& chan = channels[n]; ! 414: uint32 data = 0; ! 415: ! 416: // MPE Not implemented ! 417: ! 418: if (chan.rx_enable) { ! 419: data |= CNTL_RE; ! 420: } ! 421: if (chan.tx_enable) { ! 422: data |= CNTL_TE; ! 423: } ! 424: if (n == 0) { ! 425: if (nRTS0) { ! 426: data |= CNTL_nRTS0; ! 427: } ! 428: } else { ! 429: if (cka1_disable) { ! 430: data |= CNTL_CKA1D; ! 431: } ! 432: } ! 433: if (chan.data8bit) { ! 434: data |= CNTL_DATA8; ! 435: } ! 436: if (chan.parity_en) { ! 437: data |= CNTL_PAREN; ! 438: } ! 439: if (chan.stop2bit) { ! 440: data |= CNTL_STOP2; ! 441: } ! 442: ! 443: return data; ! 444: } ! 445: ! 446: uint32 ! 447: HD647180ASCIDevice::PeekCNTLB(uint n) const ! 448: { ! 449: const Channel& chan = channels[n]; ! 450: uint32 data = 0; ! 451: ! 452: // MPBT, MP: Not implemented ! 453: ! 454: if (chan.nCTS) { ! 455: data |= CNTL_nCTS; ! 456: } ! 457: if (chan.parity_odd) { ! 458: data |= CNTL_PEO; ! 459: } ! 460: if (chan.divratio) { ! 461: data |= CNTL_DR; ! 462: } ! 463: data |= chan.ss; ! 464: ! 465: return data; ! 466: } ! 467: ! 468: uint32 ! 469: HD647180ASCIDevice::PeekSTAT(uint n) const ! 470: { ! 471: const Channel& chan = channels[n]; ! 472: uint32 data = 0; ! 473: ! 474: if (chan.rdr_full) { ! 475: data |= STAT_RDRF; ! 476: } ! 477: if (chan.overrun) { ! 478: data |= STAT_OVRN; ! 479: } ! 480: ! 481: // PE, FE は立たない。 ! 482: ! 483: if (chan.rx_intr_enable) { ! 484: data |= STAT_RIE; ! 485: } ! 486: if (n == 0) { ! 487: if (nDCD0) { ! 488: data |= STAT_nDCD0; ! 489: } ! 490: } else { ! 491: if (cts1_enable) { ! 492: data |= STAT_CTS1E; ! 493: } ! 494: } ! 495: if (chan.tdr_empty) { ! 496: data |= STAT_TDRE; ! 497: } ! 498: if (chan.tx_intr_enable) { ! 499: data |= STAT_TIE; ! 500: } ! 501: ! 502: return data; ! 503: } ! 504: ! 505: uint32 ! 506: HD647180ASCIDevice::PeekTDR(uint n) const ! 507: { ! 508: const Channel& chan = channels[n]; ! 509: ! 510: return chan.tdr; ! 511: } ! 512: ! 513: uint32 ! 514: HD647180ASCIDevice::PeekRDR(uint n) const ! 515: { ! 516: const Channel& chan = channels[n]; ! 517: ! 518: return chan.rdr; ! 519: } ! 520: ! 521: void ! 522: HD647180ASCIDevice::MonitorUpdate(Monitor *, TextScreen& screen) ! 523: { ! 524: screen.Clear(); ! 525: ! 526: MonitorUpdateChan(screen, 0, 0); ! 527: MonitorUpdateChan(screen, 6, 1); ! 528: } ! 529: ! 530: void ! 531: HD647180ASCIDevice::MonitorUpdateChan(TextScreen& screen, int y, int n) const ! 532: { ! 533: Channel tmp = channels[n]; ! 534: uint32 cntla = PeekCNTLA(n); ! 535: uint32 cntlb = PeekCNTLB(n); ! 536: uint32 stat = PeekSTAT(n); ! 537: int x; ! 538: ! 539: screen.Print(0, y++, "<Ch.%c>", n + '0'); ! 540: ! 541: x = 16; ! 542: screen.Print(0, y, "%02XH CNTLA%u=$%02x:", 0 + n, n, cntla); ! 543: screen.Puts(x + 0, y, TA::OnOff(cntla & 0x80), "MPE"); ! 544: screen.Puts(x + 6, y, TA::OnOff(cntla & 0x40), "RE"); ! 545: screen.Puts(x + 12, y, TA::OnOff(cntla & 0x20), "TE"); ! 546: screen.Puts(x + 18, y, TA::OnOff(cntla & 0x10), ! 547: (n == 0 ? "!RTS0" : "CKA1D")); ! 548: screen.Puts(x + 24, y, TA::OnOff(cntla & 0x08), "MPBR"); ! 549: screen.Puts(x + 30, y, TA::OnOff(cntla & 0x04), "8BIT"); ! 550: screen.Puts(x + 36, y, TA::OnOff(cntla & 0x02), "ParEn"); ! 551: screen.Puts(x + 42, y, TA::OnOff(cntla & 0x01), "STOP2"); ! 552: y++; ! 553: ! 554: screen.Print(0, y, "%02XH CNTLB%u=$%02x:", 2 + n, n, cntlb); ! 555: screen.Puts(x + 0, y, TA::OnOff(cntlb & 0x80), "MPBT"); ! 556: screen.Puts(x + 6, y, TA::OnOff(cntlb & 0x40), "MP"); ! 557: screen.Puts(x + 12, y, TA::OnOff(cntlb & 0x20), "!CTS"); ! 558: screen.Puts(x + 18, y, TA::OnOff(cntlb & 0x10), "PEO"); ! 559: screen.Print(x + 24, y, "DR=%u", tmp.divratio ? 1 : 0); ! 560: screen.Print(x + 30, y, "SS[210]=%u", (cntlb & 0x07)); ! 561: screen.Print(x + 42, y, "PS=%u", tmp.prescale ? 1 : 0); ! 562: y++; ! 563: ! 564: screen.Print(0, y, "%02XH STAT%u =$%02x:", 4 + n, n, stat); ! 565: screen.Puts(x + 0, y, TA::OnOff(stat & 0x80), "RDRF"); ! 566: screen.Puts(x + 6, y, TA::OnOff(stat & 0x40), "OVRN"); ! 567: screen.Puts(x + 12, y, TA::OnOff(stat & 0x20), "PE"); ! 568: screen.Puts(x + 18, y, TA::OnOff(stat & 0x10), "FE"); ! 569: screen.Puts(x + 24, y, TA::OnOff(stat & 0x08), "RIE"); ! 570: screen.Puts(x + 30, y, TA::OnOff(stat & 0x04), ! 571: (n == 0 ? "!DCD0" : "CTS1E")); ! 572: screen.Puts(x + 36, y, TA::OnOff(stat & 0x02), "TDRE"); ! 573: screen.Puts(x + 42, y, TA::OnOff(stat & 0x01), "TIE"); ! 574: y++; ! 575: ! 576: screen.Print(0, y, "%02XH TDR%u =", 6 + n, n); ! 577: screen.Print(11, y, (tmp.tdr_empty ? TA::Disable : TA::Normal), ! 578: "$%02x", tmp.tdr); ! 579: screen.Puts(x, y, "TSR:"); ! 580: if (__predict_true(tmp.tsr < 0)) { ! 581: screen.Puts(x + 4, y, TA::Disable, "---"); ! 582: } else { ! 583: screen.Print(x + 4, y, "$%02x", tmp.tsr); ! 584: } ! 585: y++; ! 586: ! 587: screen.Print(0, y, "%02XH RDR%u =", 8 + n, n); ! 588: screen.Print(11, y, (tmp.rdr_full ? TA::Normal : TA::Disable), ! 589: "$%02x", tmp.rdr); ! 590: screen.Puts(x, y, "RSR:"); ! 591: if (__predict_true(tmp.rsr < 0)) { ! 592: screen.Puts(x + 4, y, TA::Disable, "---"); ! 593: } else { ! 594: screen.Print(x + 4, y, "$%02x", tmp.rsr); ! 595: } ! 596: ! 597: // Param: 19200,N,8,2 ! 598: screen.Puts(x + 29, y, "Param:"); ! 599: if (tmp.baudrate == 0) { ! 600: screen.Puts(x + 36, y, "(ExtClock)"); ! 601: } else { ! 602: char p; ! 603: if (tmp.parity_en) { ! 604: p = tmp.parity_odd ? 'O' : 'E'; ! 605: } else { ! 606: p = 'N'; ! 607: } ! 608: screen.Print(x + 36, y, "%5u,%c,%u,%u", ! 609: tmp.baudrate, p, (tmp.data8bit ? 8 : 7), (tmp.stop2bit ? 2 : 1)); ! 610: } ! 611: } ! 612: ! 613: ! 614: // 割り込み状態を更新する。 ! 615: // RDFn, OVRNn, RIEn, TDREn, TIEn のいずれかでも変更したら呼ぶこと。 ! 616: void ! 617: HD647180ASCIDevice::ChangeInterrupt(uint n) ! 618: { ! 619: // p.77 Fig 2.10.3 より、片方のチャンネルの割り込み要求ロジック。 ! 620: // ____ ! 621: // DCD0(*) --|OR (*) Ch0 のみ ! 622: // RDRFn ----|OR ! 623: // OVRNn ----|OR-----|& : IEF1 ! 624: // PEn -----|OR |& : | ! 625: // FEn -----|OR |&-----|OR : | ! 626: // |& |OR : +--|& ! 627: // RIEn -----|& |OR : |&----> ASCIn Int ! 628: // |OR-----------|& ! 629: // TDREn ----|& |OR : ! 630: // |&-----|OR : ! 631: // TIEn -----|& : ! 632: // : ! 633: // この関数でやってるのはここまで : こっちは xp->ChangeASCIInt() ! 634: ! 635: const Channel& chan = channels[n]; ! 636: ! 637: // PE, FE (, !DCD0) はない。 ! 638: bool rcond = chan.rdr_full || chan.overrun; ! 639: bool rintr = rcond && chan.rx_intr_enable; ! 640: ! 641: bool tintr = chan.tdr_empty && chan.tx_intr_enable; ! 642: ! 643: bool intr = (rintr || tintr); ! 644: ! 645: // IEF1 は向こうで処理している。 ! 646: xp->ChangeASCIInt(n, intr); ! 647: } ! 648: ! 649: static double ! 650: to_freq(uint64 nsec) ! 651: { ! 652: return (double)1e9 / nsec; ! 653: } ! 654: ! 655: // 現在の Prescale, DivideRatio, SS からボーレートを再計算する。 ! 656: // ここで 1文字分の時間も計算するため、CNTLA の MOD が変わっても呼ぶこと。 ! 657: void ! 658: HD647180ASCIDevice::ChangeBaudRate(uint n) ! 659: { ! 660: Channel& chan = channels[n]; ! 661: ! 662: if (__predict_false(chan.ss == 7)) { ! 663: chan.baudrate = 0; ! 664: } else { ! 665: uint d = (1U << chan.ss); ! 666: ! 667: // PreScaler で 30 か 10 分周が指定出来るが、このうち 10 は計算済み。 ! 668: if (chan.prescale) { ! 669: d *= 3; ! 670: } ! 671: ! 672: // DivideRatio で 64 か 16 分周が指定できるが、このうち 16 は計算済み。 ! 673: if (chan.divratio) { ! 674: d *= 4; ! 675: } ! 676: ! 677: chan.bit12_ns = xc12_ns * d; ! 678: chan.baudrate = to_freq(chan.bit12_ns / 12); ! 679: ! 680: // 1文字の送受信にかかる時間。 ! 681: uint bits = 1/*start*/ + 7/*data*/ + 1/*stop*/; ! 682: if (chan.data8bit) { ! 683: bits++; ! 684: } ! 685: if (chan.parity_en) { ! 686: bits++; ! 687: } ! 688: if (chan.stop2bit) { ! 689: bits++; ! 690: } ! 691: uint64 time = chan.bit12_ns * bits / 12; ! 692: txevent[n].time = time; ! 693: rxevent[n].time = time; ! 694: } ! 695: } ! 696: ! 697: // 送信イベント。 ! 698: void ! 699: HD647180ASCIDevice::TxCallback(Event& ev) ! 700: { ! 701: uint n = ev.code; ! 702: Channel& chan = channels[n]; ! 703: ! 704: // 1文字分の時間が経過したので TSR の文字をホストに送信。 ! 705: hostcom[n]->Tx(chan.tsr); ! 706: ! 707: if (chan.tdr_empty) { ! 708: // 次がなければ終わり。 ! 709: chan.tsr = -1; ! 710: } else { ! 711: // 次の文字がある。 ! 712: chan.tsr = chan.tdr; ! 713: chan.tdr_empty = true; ! 714: ChangeInterrupt(n); ! 715: ! 716: scheduler->StartEvent(ev); ! 717: } ! 718: } ! 719: ! 720: // ホストスレッドからの受信通知。 ! 721: // (HostCOM スレッドで呼ばれる) ! 722: void ! 723: HD647180ASCIDevice::HostRxCallback(uint32 arg) ! 724: { ! 725: // XXX mpscc.cpp の同関数のコメント参照。 ! 726: ! 727: uint n = arg; ! 728: Event& ev = rxevent[n]; ! 729: ! 730: if (ev.IsRunning() == false) { ! 731: // スレッドを超えるためにメッセージを投げる。 ! 732: scheduler->SendMessage(MessageID::HOSTCOM_RX(n + 1)); ! 733: } ! 734: } ! 735: ! 736: // ホストシリアルからの1バイト受信メッセージ ! 737: // (VM スレッドで呼ばれる) ! 738: void ! 739: HD647180ASCIDevice::RxMessage(MessageID msgid, uint32 arg) ! 740: { ! 741: uint n = msgid - MessageID::HOSTCOM1_RX; ! 742: Event& ev = rxevent[n]; ! 743: ! 744: // 受信ループが止まっていれば開始。 ! 745: if (ev.IsRunning() == false) { ! 746: scheduler->StartEvent(ev); ! 747: } ! 748: } ! 749: ! 750: // 受信イベントコールバック。 ! 751: void ! 752: HD647180ASCIDevice::RxCallback(Event& ev) ! 753: { ! 754: uint n = ev.code; ! 755: int data; ! 756: ! 757: data = hostcom[n]->Rx(); ! 758: if (data >= 0) { ! 759: Rx(n, data); ! 760: ! 761: scheduler->StartEvent(ev); ! 762: } ! 763: } ! 764: ! 765: // 1バイト受信する。 ! 766: bool ! 767: HD647180ASCIDevice::Rx(uint n, uint32 data) ! 768: { ! 769: Channel& chan = channels[n]; ! 770: ! 771: // Rx Enable でなければ受け取らない? ! 772: if (chan.rx_enable == false) { ! 773: return false; ! 774: } ! 775: ! 776: // 受信前 受信後の状態 ! 777: // RDR RSR RDR RSR ! 778: // --- --- --- --- ! 779: // なし なし -> data なし ! 780: // なし 有り (すぐに1行下の状態に遷移するためこの状態はない) ! 781: // 有り なし -> 有り data ! 782: // 有り 有り -> 有り 有り (Overrun) ! 783: ! 784: // バッファが一杯なら Overrun。 ! 785: if (chan.rdr_full && chan.rsr >= 0) { ! 786: putlog(2, "Ch%u Rx Overrun", n); ! 787: chan.overrun = true; ! 788: ChangeInterrupt(n); ! 789: return false; ! 790: } ! 791: ! 792: // 受信。 ! 793: putlog(2, "Ch%u recv $%02x", n, data); ! 794: if (chan.rdr_full) { ! 795: chan.rsr = data; ! 796: } else { ! 797: chan.rdr = data; ! 798: chan.rdr_full = true; ! 799: chan.rsr = -1; ! 800: ChangeInterrupt(n); ! 801: } ! 802: ! 803: return true; ! 804: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.