|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2018 [email protected] ! 4: // ! 5: ! 6: #include "upd7201.h" ! 7: ! 8: // コンストラクタ ! 9: uPD7201Device::uPD7201Device() ! 10: { ! 11: monitor.Init(48, 19); ! 12: cr.chan[0].id = 0; ! 13: cr.chan[0].name = "A"; ! 14: cr.chan[1].id = 1; ! 15: cr.chan[1].name = "B"; ! 16: ! 17: cr.chan[0].desc = NULL; ! 18: cr.chan[1].desc = NULL; ! 19: } ! 20: ! 21: // デストラクタ ! 22: uPD7201Device::~uPD7201Device() ! 23: { ! 24: } ! 25: ! 26: // リセット ! 27: // どのタイミングで呼ばれるかは上位による ! 28: void ! 29: uPD7201Device::Reset() ! 30: { ! 31: putlog(2, "リセット"); ! 32: ! 33: // CR2A はチップリセットで bit6 以外を '0' に ! 34: cr.cr2a &= ~0xbf; ! 35: ! 36: // チャンネルリセット ! 37: ResetChannel(&cr.chan[0]); ! 38: ResetChannel(&cr.chan[1]); ! 39: } ! 40: ! 41: // チャンネルリセット ! 42: void ! 43: uPD7201Device::ResetChannel(struct SIO::channel *chan) ! 44: { ! 45: putlog(2, "チャンネル %s リセット", chan->name); ! 46: ! 47: // CR0 b2-0 ! 48: chan->cr0 &= ~SIO::CR0_PTR; ! 49: chan->ptr = 0; ! 50: ! 51: // CR1 b0,1,3,4,7 ! 52: chan->cr1 &= ~(SIO::CR1_WAIT_EN | SIO::CR1_RXINT | ! 53: SIO::CR1_TXINT_EN | SIO::CR1_ESINT_EN); ! 54: ! 55: // CR3 b0-7 ! 56: chan->cr3 = 0; ! 57: ! 58: // CR5 b1,2,3,4,7 ! 59: chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN | ! 60: SIO::CR5_CRC16 | SIO::CR5_RTS); ! 61: ! 62: // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定 ! 63: chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL); ! 64: chan->sr0 |= (SIO::SR0_TXUNDER | SIO::SR0_TXEMPTY); ! 65: ! 66: // SR1 は b4-7 が '0' ! 67: chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR | ! 68: SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR); ! 69: ! 70: // E/S ラッチ解除 ! 71: chan->es_ratched = false; ! 72: ! 73: // 受信バッファをクリア ! 74: memset(chan->rxbuf, 0, sizeof(chan->rxbuf)); ! 75: chan->rxlen = 0; ! 76: } ! 77: ! 78: // 制御ポートの読み込み ! 79: uint8 ! 80: uPD7201Device::ReadCtrl(struct SIO::channel *chan) ! 81: { ! 82: uint8 data; ! 83: ! 84: switch (chan->ptr) { ! 85: case 0: // SR0 ! 86: // 送信バッファは常に空 ! 87: data = SIO::SR0_TXEMPTY; ! 88: // 受信データがあるか ! 89: if (chan->rxlen > 0) { ! 90: data |= SIO::SR0_RXAVAIL; ! 91: } ! 92: putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); ! 93: // アクセス後は SR0 へ戻す ! 94: chan->ptr = 0; ! 95: break; ! 96: ! 97: case 1: // SR1 ! 98: // エラーとか起きてないという状態だけ再現。 ! 99: data = SIO::SR1_ALL_SENT; ! 100: putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); ! 101: // アクセス後は SR0 へ戻す ! 102: chan->ptr = 0; ! 103: break; ! 104: ! 105: case 2: ! 106: // SR2B はベクタの読み出し ! 107: if (chan->id == 1) { ! 108: data = cr.vector; ! 109: putlog(2, "SR%d%s -> $%02x", chan->ptr, chan->name, data); ! 110: // アクセス後は SR0 へ戻す ! 111: chan->ptr = 0; ! 112: break; ! 113: } ! 114: ! 115: // SR2A はない ! 116: FALLTHROUGH; ! 117: ! 118: default: ! 119: putlog(0, "未実装レジスタ読み込み SR%d%s", ! 120: chan->ptr, chan->name); ! 121: // SR0 へ戻る? ! 122: chan->ptr = 0; ! 123: return 0xff; ! 124: } ! 125: return data; ! 126: } ! 127: ! 128: // 制御ポートの書き込み ! 129: void ! 130: uPD7201Device::WriteCtrl(struct SIO::channel *chan, uint32 data) ! 131: { ! 132: uint cmd; ! 133: ! 134: switch (chan->ptr) { ! 135: case 0: // CR0 ! 136: // XXX b7,b6 は未対応。 ! 137: // b5,b4,b3 がコマンド。 ! 138: // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。 ! 139: chan->cr0 = data; ! 140: chan->ptr = (chan->cr0 & SIO::CR0_PTR); ! 141: ! 142: cmd = (chan->cr0 & SIO::CR0_CMD) >> 3; ! 143: if (cmd == 0) { ! 144: // コマンド0 ならレジスタ切り替え ! 145: putlog(3, "CR0%s <- $%02x (ptr=%d)", chan->name, data, chan->ptr); ! 146: } else { ! 147: // 0 以外ならコマンド発行 ! 148: putlog(2, "CR0%s <- $%02x", chan->name, data); ! 149: } ! 150: switch (cmd) { ! 151: case 0: // No operation ! 152: break; ! 153: case 1: // Send Abort ! 154: if (chan->mode == SIO::Mode::HDLC) { ! 155: putlog(0, "CR0: Send Abort 未実装"); ! 156: } else { ! 157: // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて ! 158: // あるがそれ以外の時にどうなるか不明。 ! 159: putlog(0, "CR0: 未定義コマンド %d", cmd); ! 160: } ! 161: break; ! 162: case 2: // Reset External/Status Interrupt ! 163: putlog(3, "E/S ラッチ解除"); ! 164: chan->es_ratched = false; ! 165: break; ! 166: case 3: // Channel Reset ! 167: putlog(1, "チャンネル%sリセット", chan->name); ! 168: ResetChannel(chan); ! 169: break; ! 170: case 4: // Enable Interrupt On Next Receive Character ! 171: putlog(0, "CR0: 未実装コマンド %d", cmd); ! 172: break; ! 173: case 5: // Reset Transmitter Interrupt/DMA Pending ! 174: // 本来これは上がっている Tx 割り込みを落とすためのようだが、 ! 175: // SIO から MPU への割り込み通知はもう終わっていて下げる必要は ! 176: // ないので、何もすることはない。 ! 177: break; ! 178: case 6: // Error Reset ! 179: case 7: // End of Interrupt ! 180: putlog(0, "CR0: 未実装コマンド %d", cmd); ! 181: break; ! 182: default: ! 183: __unreachable(); ! 184: } ! 185: break; ! 186: ! 187: case 1: // CR1 ! 188: chan->cr1 = data; ! 189: putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); ! 190: // アクセス後は CR0 へ戻す ! 191: chan->ptr = 0; ! 192: break; ! 193: ! 194: case 2: ! 195: if (chan->id == 0) { // CR2A ! 196: putlog(2, "CR2A <- $%02x 書き込み(b7-2未実装)", data); ! 197: cr.cr2a = data; ! 198: } else { // CR2B ! 199: putlog(2, "CR2B <- $%02x ベクタ設定", data); ! 200: cr.vector = data; ! 201: } ! 202: // アクセス後は CR0 へ戻す ! 203: chan->ptr = 0; ! 204: break; ! 205: ! 206: case 3: // CR3 ! 207: chan->cr3 = data; ! 208: putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); ! 209: putlog(1, "チャンネル%s RX %s, %dbits", ! 210: chan->name, ! 211: (chan->cr3 & SIO::CR3_RX_EN) ? "Enable" : "Disable", ! 212: bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]); ! 213: // アクセス後は CR0 へ戻す ! 214: chan->ptr = 0; ! 215: break; ! 216: ! 217: case 4: // CR4 ! 218: { ! 219: chan->cr4 = data; ! 220: putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); ! 221: uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS); ! 222: uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE); ! 223: ! 224: // モード分け、優先順位は分からない ! 225: if (stopbits == SIO::SYNC_MODE) { ! 226: if (syncmode == SIO::SYNC_HDLC) { ! 227: chan->mode = SIO::Mode::HDLC; ! 228: putlog(2, "チャンネル%s HDLC モード", chan->name); ! 229: } else { ! 230: chan->mode = SIO::Mode::SYNC; ! 231: const char *sm[] = { "8bit", "16bit", "HDLC?", "Ext" }; ! 232: putlog(2, "チャンネル%s Sync (%s) モード", ! 233: chan->name, sm[syncmode >> 4]); ! 234: } ! 235: } else { ! 236: chan->mode = SIO::Mode::ASYNC; ! 237: const char *cm[] = { "x1", "x16", "x32", "x64" }; ! 238: const char *sm[] = { "?", "1", "1.5", "2" }; ! 239: putlog(2, "チャンネル%s Async (%s clock, stopbit %s) モード", ! 240: chan->name, ! 241: cm[(chan->cr4 & SIO::CR4_CLKRATE) >> 6], ! 242: sm[stopbits >> 2]); ! 243: } ! 244: ! 245: // アクセス後は CR0 へ戻す ! 246: chan->ptr = 0; ! 247: break; ! 248: } ! 249: ! 250: case 5: // CR5 ! 251: { ! 252: chan->cr5 = data; ! 253: putlog(2, "CR%d%s <- $%02x", chan->ptr, chan->name, data); ! 254: putlog(1, "チャンネル%s TX %s, %dbits", ! 255: chan->name, ! 256: (chan->cr5 & SIO::CR5_TX_EN) ? "Enable" : "Disable", ! 257: bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5]); ! 258: // アクセス後は CR0 へ戻す ! 259: chan->ptr = 0; ! 260: break; ! 261: } ! 262: ! 263: case 6: // CR6 ! 264: putlog(0, "CR6%s <- $%02x 書き込み(未実装)", chan->name, data); ! 265: chan->cr6 = data; ! 266: // アクセス後は CR0 へ戻す ! 267: chan->ptr = 0; ! 268: break; ! 269: ! 270: case 7: // CR7 ! 271: putlog(0, "CR7%s <- $%02x 書き込み(未実装)", chan->name, data); ! 272: chan->cr7 = data; ! 273: // アクセス後は CR0 へ戻す ! 274: chan->ptr = 0; ! 275: break; ! 276: ! 277: default: ! 278: putlog(0, "未実装レジスタ書き込み CR%d%s <- $%02x", ! 279: chan->ptr, chan->name, data); ! 280: break; ! 281: } ! 282: } ! 283: ! 284: // データポートの読み込み ! 285: uint8 ! 286: uPD7201Device::ReadData(int ch) ! 287: { ! 288: struct SIO::channel *chan = &cr.chan[ch]; ! 289: uint8 data; ! 290: ! 291: if (chan->rxlen > 0) { ! 292: data = chan->rxbuf[0]; ! 293: chan->rxlen--; ! 294: // 少ないので毎回前詰めしちゃえ ! 295: if (chan->rxlen > 0) { ! 296: memmove(chan->rxbuf + 1, chan->rxbuf, chan->rxlen); ! 297: } ! 298: } else { ! 299: // XXX 何が読めるか ! 300: data = 0xff; ! 301: } ! 302: ! 303: return data; ! 304: } ! 305: ! 306: // データポートの書き込み ! 307: void ! 308: uPD7201Device::WriteData(struct SIO::channel *chan, uint32 data) ! 309: { ! 310: char charbuf[4]; ! 311: ! 312: if (isprint((int)data)) { ! 313: snprintf(charbuf, sizeof(charbuf), "'%c'", data); ! 314: } else { ! 315: charbuf[0] = '\0'; ! 316: } ! 317: putlog(1, "Ch%s データレジスタ書き込み $%02x %s", ! 318: chan->name, data, charbuf); ! 319: ! 320: // 1文字送信 ! 321: ! 322: // 今のところ内部バッファがなく常に送信できるので ! 323: // 必ず Tx Buffer Empty が発生する。 ! 324: chan->sr0 |= SIO::SR0_TXEMPTY; ! 325: ! 326: // 割り込みをあげる ! 327: if ((chan->cr1 & SIO::CR1_TXINT_EN)) { ! 328: putlog(2, "割り込み (TX Empty)"); ! 329: Interrupt(); ! 330: } ! 331: } ! 332: ! 333: // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換します。 ! 334: /* static */ ! 335: const int ! 336: uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 }; ! 337: ! 338: // 1バイト受信する。 ! 339: // 受理されれば true を返す。 ! 340: bool ! 341: uPD7201Device::Rx(int ch, uint32 data) ! 342: { ! 343: struct SIO::channel *chan = &cr.chan[ch]; ! 344: ! 345: // Rx Enable でなければ受け取らない? ! 346: if ((chan->cr3 & SIO::CR3_RX_EN) == 0) { ! 347: return false; ! 348: } ! 349: ! 350: // バッファが一杯なら Rx Overrun Error ! 351: if (chan->rxlen == sizeof(chan->rxbuf)) { ! 352: putlog(2, "Rx Overrun"); ! 353: chan->sr1 |= SIO::SR1_RXOVERRUN; ! 354: return false; ! 355: } ! 356: ! 357: // 受信 ! 358: chan->rxbuf[chan->rxlen++] = data; ! 359: ! 360: // 必要なら割り込みを上げる ! 361: if ((chan->cr1 & SIO::CR1_RXINT) == SIO::RXINT_FIRSTCHAR) { ! 362: // First character interrupt モードなら最初の1バイトでだけ割り込み ! 363: if (chan->rxrecved == false) { ! 364: Interrupt(); ! 365: } ! 366: chan->rxrecved = true; ! 367: } else if ((chan->cr1 & SIO::CR1_RXINT) >= SIO::RXINT_ALL_INC_SPECIAL) { ! 368: // All character interrupt モード (Special のことはちょっと置いとく) ! 369: chan->rxrecved = true; ! 370: Interrupt(); ! 371: } ! 372: ! 373: return true; ! 374: } ! 375: ! 376: // モニター ! 377: bool ! 378: uPD7201Device::MonitorUpdate() ! 379: { ! 380: monitor.Clear(); ! 381: for (int i = 0; i < 2; i++) { ! 382: int x = 0; ! 383: int y = i * 10; ! 384: MonitorUpdateCh(i, x, y); ! 385: } ! 386: return true; ! 387: } ! 388: ! 389: // モニター (1チャンネル) ! 390: void ! 391: uPD7201Device::MonitorUpdateCh(int ch, int xbase, int ybase) ! 392: { ! 393: struct SIO::channel *chan = &cr.chan[ch]; ! 394: uint cr0; ! 395: uint cr1; ! 396: uint cr3; ! 397: uint cr4; ! 398: uint cr5; ! 399: uint sr0; ! 400: uint sr1; ! 401: uint rxlen; ! 402: int x; ! 403: int y; ! 404: ! 405: cr0 = chan->cr0; ! 406: cr1 = chan->cr1; ! 407: cr3 = chan->cr3; ! 408: cr4 = chan->cr4; ! 409: cr5 = chan->cr5; ! 410: sr0 = chan->sr0; ! 411: sr1 = chan->sr1; ! 412: rxlen = chan->rxlen; ! 413: ! 414: // 0 1 2 3 4 5 6 ! 415: // 012345678901234567890123456789012345678901234567890123456789012345 ! 416: // 0123 0123 0123 0123 0123 0123 0123 0123 ! 417: // CR0:$xx CRC=x CMD=x PTR=x ! 418: // CR1:$xx WE 0 WR RXInt=x 0 TXEn ESEn ! 419: ! 420: x = xbase; ! 421: y = ybase; ! 422: monitor.Print(x, y++, "Channel %s: %s", chan->name, chan->desc); ! 423: monitor.Print(x, y++, "CR0:$%02x", cr0); ! 424: monitor.Print(x, y++, "CR1:$%02x", cr1); ! 425: monitor.Print(x, y++, "CR3:$%02x", cr3); ! 426: monitor.Print(x, y++, "CR4:$%02x", cr4); ! 427: monitor.Print(x, y++, "CR5:$%02x", cr5); ! 428: monitor.Print(x, y++, "SR0:$%02x", sr0); ! 429: monitor.Print(x, y++, "SR1:$%02x", sr1); ! 430: monitor.Print(x, y, "RXbuf:%d", rxlen); ! 431: int i; ! 432: for (i = 0; i < rxlen; i++) { ! 433: monitor.Print(x + 8 + i * 4, y, "$%02x", chan->rxbuf[i]); ! 434: } ! 435: for (; i < sizeof(chan->rxbuf); i++) { ! 436: monitor.Print(x + 8 + i * 4, y, "---"); ! 437: } ! 438: ! 439: y = ybase + 1; ! 440: x = xbase; ! 441: // CR0 ! 442: monitor.Print(x + 9, y, "CRC=%d", (cr0 >> 6)); ! 443: static const char * const cmd_str[] = { ! 444: // 0123456789012345 ! 445: "No operation", ! 446: "Send Abort", ! 447: "Reset E/S Int", ! 448: "Channel Reset", ! 449: "Enable IntNextCh", ! 450: "Reset TxIntPend", ! 451: "Error Reset", ! 452: "End of Interrupt", ! 453: }; ! 454: uint cmd = (cr0 >> 3) & 7; ! 455: monitor.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]); ! 456: monitor.Print(x + 43, y, "PTR=%d", (cr0 & 7)); ! 457: y++; ! 458: ! 459: // CR1 ! 460: static const char * const cr1_str[] = { ! 461: "WaEn", "----", "WaRx", "", "", "----", "TxIE", "ESEn" ! 462: }; ! 463: MonitorReg(x + 9, y, cr1, cr1_str); ! 464: monitor.Print(x + 24, y, "RXInt=%d", (cr1 >> 3) & 3); ! 465: y++; ! 466: ! 467: // CR3 ! 468: static const char * const cr3_str[] = { ! 469: "", "", "AuEn", "----", "----", "----", "----", "RXEn" ! 470: }; ! 471: MonitorReg(x + 9, y, cr3, cr3_str); ! 472: monitor.Print(x + 9, y, "RXbits=%d", 5 + ((cr3 >> 6) & 3)); ! 473: y++; ! 474: ! 475: // CR4 ! 476: static const char * const cr4_str[] = { ! 477: "", "", "", "", "", "", "PaEv", "PaEn" ! 478: }; ! 479: MonitorReg(x + 9, y, cr4, cr4_str); ! 480: ! 481: static const char * const clkrate_str[] = { ! 482: "1", "16", "32", "64" ! 483: }; ! 484: monitor.Print(x + 9, y, "Rate=x%s", clkrate_str[(cr4 >> 6) & 3]); ! 485: static const char * const syncmode_str[] = { ! 486: "Mono", "Bi", "HDLC", "Ext" ! 487: }; ! 488: monitor.Print(x + 19, y, "Sync=%s", syncmode_str[(cr4 >> 4) & 3]); ! 489: static const char * const stopbit_str[] = { ! 490: "Sync", "1", "1.5", "2" ! 491: }; ! 492: monitor.Print(x + 29, y, "Stop=%s", stopbit_str[(cr4 >> 2) & 3]); ! 493: y++; ! 494: ! 495: // CR5 ! 496: static const char * const cr5_str[] = { ! 497: "DTR", "", "", "SBrk", "TXEn", "CRC", "!RTS", "TCEn" ! 498: }; ! 499: MonitorReg(x + 9, y, cr5, cr5_str); ! 500: monitor.Print(x + 14, y, "TXbits=%d", 5 + ((cr5 >> 5) & 3)); ! 501: y++; ! 502: ! 503: // SR0 ! 504: static const char * const sr0_str[] = { ! 505: "BrAb", "TxUn", "CTS", "SYNC", "DCD", "TxEm", "IntP", "RxAv" ! 506: }; ! 507: MonitorReg(x + 9, y, sr0, sr0_str); ! 508: y++; ! 509: ! 510: // SR1 ! 511: static const char * const sr1_str[] = { ! 512: "EOF", "CRCE", "RxOv", "PaEr", "", "", "", "Sent" ! 513: }; ! 514: MonitorReg(x + 9, y, sr1, sr1_str); ! 515: monitor.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7); ! 516: y++; ! 517: } ! 518: ! 519: // レジスタをビットごとに表示する。MonitorUpdate の下請け。 ! 520: void ! 521: uPD7201Device::MonitorReg(int x, int y, uint32 reg, const char * const *names) ! 522: { ! 523: for (int i = 0; i < 8; i++) { ! 524: if (strcmp(names[i], "----") == 0) { ! 525: monitor.Print(x + i * 5, y, TA::Disable, "%s", names[i]); ! 526: } else { ! 527: bool b = reg & (1 << (7 - i)); ! 528: uint attr = b ? TA::On : TA::Off; ! 529: monitor.Print(x + i * 5, y, attr, "%s", names[i]); ! 530: } ! 531: } ! 532: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.