|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #include "upd7201.h"
1.1.1.5 root 8: #include "interrupt.h"
1.1 root 9:
10: // コンストラクタ
1.1.1.7 root 11: uPD7201Device::uPD7201Device(const std::string& objname_)
12: : inherited(objname_)
1.1 root 13: {
14: cr.chan[0].id = 0;
15: cr.chan[0].name = "A";
16: cr.chan[1].id = 1;
17: cr.chan[1].name = "B";
18:
19: cr.chan[0].desc = NULL;
20: cr.chan[1].desc = NULL;
1.1.1.7 root 21:
1.1.1.9 ! root 22: for (int ch = 0; ch < txevent.size(); ch++) {
! 23: // time は SetTXPeriod() でセット
! 24: txevent[ch].dev = this;
! 25: txevent[ch].func = (DeviceCallback_t)&uPD7201Device::TXCallback;
! 26: txevent[ch].code = ch;
! 27: // 名前は継承先でセットする。機種ごとに名前を使い分けているため。
! 28: }
! 29:
1.1.1.7 root 30: monitor.func = (MonitorCallback_t)&uPD7201Device::MonitorUpdate;
31: monitor.SetSize(48, 22);
32: // 登録は継承先で行う。機種ごとに通りのいい名前を使い分けているため。
1.1 root 33: }
34:
35: // デストラクタ
36: uPD7201Device::~uPD7201Device()
37: {
38: }
39:
40: // リセット
41: void
1.1.1.6 root 42: uPD7201Device::ResetHard()
1.1 root 43: {
44: putlog(2, "リセット");
45:
46: // CR2A はチップリセットで bit6 以外を '0' に
47: cr.cr2a &= ~0xbf;
48:
49: // チャンネルリセット
50: ResetChannel(&cr.chan[0]);
51: ResetChannel(&cr.chan[1]);
52: }
53:
54: // チャンネルリセット
55: void
1.1.1.9 ! root 56: uPD7201Device::ResetChannel(SIO::channel *chan)
1.1 root 57: {
1.1.1.5 root 58: putlog(2, "Channel %s Reset", chan->name);
1.1 root 59:
1.1.1.5 root 60: // CR0 b2-0 (PTR)
1.1 root 61: chan->ptr = 0;
62:
63: // CR1 b0,1,3,4,7
64: chan->cr1 &= ~(SIO::CR1_WAIT_EN | SIO::CR1_RXINT |
65: SIO::CR1_TXINT_EN | SIO::CR1_ESINT_EN);
1.1.1.5 root 66: chan->all_or_first = false;
1.1 root 67:
68: // CR3 b0-7
69: chan->cr3 = 0;
70:
71: // CR5 b1,2,3,4,7
72: chan->cr5 &= ~(SIO::CR5_DTR | SIO::CR5_SENDBREAK | SIO::CR5_TX_EN |
73: SIO::CR5_CRC16 | SIO::CR5_RTS);
1.1.1.9 ! root 74: SetTXPeriod(chan);
1.1 root 75:
76: // SR0 は b0,1 が '0'、b2,6 が '1'、残りは不定
77: chan->sr0 &= ~(SIO::SR0_INTPEND | SIO::SR0_RXAVAIL);
78: chan->sr0 |= (SIO::SR0_TXUNDER | SIO::SR0_TXEMPTY);
79:
80: // SR1 は b4-7 が '0'
81: chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
82: SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
83:
1.1.1.5 root 84: // 内部状態をリセット
1.1 root 85: chan->es_ratched = false;
1.1.1.9 ! root 86: chan->txint = false;
1.1 root 87:
88: // 受信バッファをクリア
89: memset(chan->rxbuf, 0, sizeof(chan->rxbuf));
90: chan->rxlen = 0;
1.1.1.9 ! root 91:
! 92: chan->txbuf = 0;
! 93: chan->txlen = 0;
! 94: chan->tx_shiftreg = 0;
! 95: // 送信の停止
! 96: // XXX 送信途中のデータをぶちきることはサポートしない
! 97: txevent[chan->id].Stop();
! 98:
! 99: ChangeInterrupt();
! 100: }
! 101:
! 102: // CR(WR) レジスタ名を返す。uPD7201 では CRn のほうが通りがいい。
! 103: const char *
! 104: uPD7201Device::CRName(const SIO::channel *chan, int ptr_) const
! 105: {
! 106: assert(ptr_ < 8);
! 107: int idx = ptr_ * 2 + chan->id;
! 108: assert(idx < countof(crnames));
! 109: return crnames[idx];
! 110: }
! 111:
! 112: // SR(RR) レジスタ名を返す。uPD7201 では SRn のほうが通りがいい。
! 113: const char *
! 114: uPD7201Device::SRName(const SIO::channel *chan, int ptr_) const
! 115: {
! 116: assert(ptr_ < 8);
! 117: int idx = ptr_ * 2 + chan->id;
! 118: assert(idx < countof(srnames));
! 119: return srnames[idx];
1.1 root 120: }
121:
122: // 制御ポートの読み込み
123: uint8
1.1.1.9 ! root 124: uPD7201Device::ReadCtrl(SIO::channel *chan)
1.1 root 125: {
126: uint8 data;
127:
128: switch (chan->ptr) {
129: case 0: // SR0
1.1.1.5 root 130: data = chan->sr0;
1.1.1.9 ! root 131: putlog(2, "%s -> $%02x", SRName(chan), data);
1.1 root 132: // アクセス後は SR0 へ戻す
133: chan->ptr = 0;
134: break;
135:
136: case 1: // SR1
1.1.1.5 root 137: data = chan->sr1;
1.1.1.9 ! root 138: putlog(2, "%s -> $%02x", SRName(chan), data);
1.1 root 139: // アクセス後は SR0 へ戻す
140: chan->ptr = 0;
141: break;
142:
143: case 2:
144: // SR2B はベクタの読み出し
145: if (chan->id == 1) {
146: data = cr.vector;
1.1.1.9 ! root 147: putlog(2, "%s -> $%02x", SRName(chan), data);
1.1 root 148: // アクセス後は SR0 へ戻す
149: chan->ptr = 0;
150: break;
151: }
152:
153: // SR2A はない
154: FALLTHROUGH;
155:
156: default:
1.1.1.9 ! root 157: putlog(0, "未実装レジスタ読み込み %s", SRName(chan));
1.1 root 158: // SR0 へ戻る?
159: chan->ptr = 0;
160: return 0xff;
161: }
162: return data;
163: }
164:
165: // 制御ポートの書き込み
166: void
1.1.1.9 ! root 167: uPD7201Device::WriteCtrl(SIO::channel *chan, uint32 data)
1.1 root 168: {
1.1.1.5 root 169: // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。
170: // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。
1.1 root 171:
1.1.1.5 root 172: if (chan->ptr == 0) {
173: WriteCR0(chan, data);
174: } else {
175: switch (chan->ptr) {
176: case 1:
177: WriteCR1(chan, data);
1.1 root 178: break;
1.1.1.5 root 179: case 2:
180: WriteCR2(chan, data);
1.1 root 181: break;
1.1.1.5 root 182: case 3:
183: WriteCR3(chan, data);
1.1 root 184: break;
1.1.1.5 root 185: case 4:
186: WriteCR4(chan, data);
1.1 root 187: break;
1.1.1.5 root 188: case 5:
189: WriteCR5(chan, data);
1.1 root 190: break;
1.1.1.5 root 191: case 6:
192: WriteCR6(chan, data);
1.1 root 193: break;
1.1.1.5 root 194: case 7:
195: WriteCR7(chan, data);
1.1 root 196: break;
197: default:
1.1.1.9 ! root 198: __unreachable();
1.1 root 199: }
200: // アクセス後は CR0 へ戻す
201: chan->ptr = 0;
202: }
203: }
204:
1.1.1.2 root 205: // 制御ポートの Peek
206: uint8
1.1.1.9 ! root 207: uPD7201Device::PeekCtrl(const SIO::channel *chan) const
1.1.1.2 root 208: {
209: switch (chan->ptr) {
210: case 0: // SR0
1.1.1.5 root 211: return chan->sr0;
1.1.1.2 root 212:
213: case 1: // SR1
1.1.1.5 root 214: return chan->sr1;
1.1.1.2 root 215:
216: case 2: // SR2
217: // SR2A はない。SR2B はベクタの読み出し
218: if (chan->id == 1) {
219: return cr.vector;
220: }
221: FALLTHROUGH;
222:
223: default:
224: // 未調査
225: return 0xff;
226: }
227: }
228:
1.1.1.5 root 229: // CR0 への書き込み
1.1.1.9 ! root 230: // Z8530 の WR0 とは微妙に互換性がなく、scc.cpp に似た別物があるので注意。
1.1.1.5 root 231: void
1.1.1.9 ! root 232: uPD7201Device::WriteCR0(SIO::channel *chan, uint32 data)
1.1.1.2 root 233: {
1.1.1.5 root 234: uint cmd;
1.1.1.2 root 235:
1.1.1.5 root 236: // XXX b7,b6 は未対応。
237: // b5,b4,b3 がコマンド。
238: // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
239: chan->cr0 = data;
240: chan->ptr = (chan->cr0 & SIO::CR0_PTR);
241:
242: cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
243: if (cmd == 0) {
244: // コマンド0 ならレジスタ切り替え
1.1.1.9 ! root 245: putlog(3, "%s <- $%02x (ptr=%d)", CRName(chan, 0), data, chan->ptr);
1.1.1.5 root 246: } else {
247: // 0 以外ならコマンド発行
1.1.1.9 ! root 248: putlog(2, "%s <- $%02x", CRName(chan, 0), data);
1.1.1.5 root 249: }
250: switch (cmd) {
251: case 0: // No operation
252: break;
253: case 1: // Send Abort
1.1.1.9 ! root 254: SendAbort(chan);
1.1.1.5 root 255: break;
256: case 2: // Reset External/Status Interrupt
1.1.1.9 ! root 257: ResetESIntr(chan);
1.1.1.5 root 258: break;
259: case 3: // Channel Reset
260: ResetChannel(chan);
261: break;
262: case 4: // Enable Interrupt On Next Receive Character
1.1.1.9 ! root 263: EnableIntrOnNextRx(chan);
1.1.1.5 root 264: break;
265: case 5: // Reset Transmitter Interrupt/DMA Pending
1.1.1.9 ! root 266: ResetTxIntrPending(chan);
1.1.1.5 root 267: break;
268: case 6: // Error Reset
1.1.1.9 ! root 269: ErrorReset(chan);
! 270: break;
1.1.1.5 root 271: case 7: // End of Interrupt
1.1.1.9 ! root 272: // uPD7201 ではチャンネル A のみ有効。
! 273: // (チャンネル B でどうなるかは書いてない)
! 274: if (chan->id == 0) {
! 275: ResetHighestIUS(chan);
! 276: } else {
! 277: putlog(0, "%s: End of Intterupt 未定義", CRName(chan, 0));
! 278: }
1.1.1.5 root 279: break;
280: default:
281: __unreachable();
1.1.1.2 root 282: }
283: }
284:
1.1.1.9 ! root 285: // CR0(WR0) Send Abort コマンド
! 286: void
! 287: uPD7201Device::SendAbort(SIO::channel *chan)
! 288: {
! 289: if (chan->mode == SIO::Mode::HDLC) {
! 290: putlog(0, "%s: Send Abort 未実装", CRName(chan, 0));
! 291: } else {
! 292: // XXX Send Abort コマンドは「HDLC モードのみ有効」と書いて
! 293: // あるがそれ以外の時にどうなるか不明。
! 294: uint cmd = (chan->cr0 & SIO::CR0_CMD) >> 3;
! 295: putlog(0, "%s: 未定義コマンド %d", CRName(chan, 0), cmd);
! 296: }
! 297: }
! 298:
! 299: // CR0(WR0) Reset External/Status Interrupt コマンド
! 300: void
! 301: uPD7201Device::ResetESIntr(SIO::channel *chan)
! 302: {
! 303: putlog(3, "%s: Reset E/S Interrupt", CRName(chan, 0));
! 304: chan->es_ratched = false;
! 305: }
! 306:
! 307: // CR0(WR0) Enable Interrupt on Next Rx Character コマンド
! 308: void
! 309: uPD7201Device::EnableIntrOnNextRx(SIO::channel *chan)
! 310: {
! 311: putlog(0, "%s: Enable Intr on Next Rx Character 未実装", CRName(chan, 0));
! 312: }
! 313:
! 314: // CR0(WR0) Reset Tx Interrupt/DMA Pending コマンド
! 315: void
! 316: uPD7201Device::ResetTxIntrPending(SIO::channel *chan)
! 317: {
! 318: putlog(1, "%s: Reset Tx Intr/DMA Pending", CRName(chan, 0));
! 319: chan->txint = false;
! 320: ChangeInterrupt();
! 321: }
! 322:
! 323: // CR0(WR0) Error Reset コマンド
! 324: void
! 325: uPD7201Device::ErrorReset(SIO::channel *chan)
! 326: {
! 327: putlog(1, "%s: Error Reset", CRName(chan, 0));
! 328: chan->sr1 &= ~(SIO::SR1_ENDOFFRAME | SIO::SR1_CRCERROR |
! 329: SIO::SR1_RXOVERRUN | SIO::SR1_PARITYERROR);
! 330: // XXX Special Rx Condition は未実装
! 331: }
! 332:
! 333: // CR0 End of Interrupt コマンド
! 334: // WR0 Reset Highest IUS コマンド
! 335: // たぶん名前が違うだけで同じ。後者のほうが分かりやすいのでこっちを使う
! 336: void
! 337: uPD7201Device::ResetHighestIUS(SIO::channel *chan)
! 338: {
! 339: putlog(0, "%s: Reset Highest IUS 未実装", CRName(chan, 0));
! 340: }
! 341:
1.1.1.5 root 342: // CR1 への書き込み
343: void
1.1.1.9 ! root 344: uPD7201Device::WriteCR1(SIO::channel *chan, uint32 data)
1.1.1.2 root 345: {
1.1.1.9 ! root 346: putlog(2, "%s <- $%02x", CRName(chan), data);
1.1.1.5 root 347:
348: chan->cr1 = data;
349:
350: // RXINT モードで all_or_first の値(初期値)を用意。
351: // DISABLE なら(使わないのでどっちでもいいはずだけど一応) false にしとく。
352: // FIRSTCHAR なら初期状態が true。ALL_* なら常時 true。
353: chan->all_or_first = ((chan->cr1 & SIO::CR1_RXINT) != SIO::RXINT_DISABLE);
1.1.1.2 root 354: }
355:
1.1.1.5 root 356: // CR2 への書き込み
357: void
1.1.1.9 ! root 358: uPD7201Device::WriteCR2(SIO::channel *chan, uint32 data)
1.1.1.5 root 359: {
360: if (chan->id == 0) { // CR2A
1.1.1.9 ! root 361: putlog(2, "%s <- $%02x 書き込み(b7,b2-0未実装)", CRName(chan), data);
1.1.1.5 root 362: cr.cr2a = data;
363: } else { // CR2B
1.1.1.9 ! root 364: putlog(2, "%s <- $%02x (Set vector)", CRName(chan), data);
1.1.1.5 root 365: cr.vector = data;
366: }
367: }
368:
369: // CR3 への書き込み
370: void
1.1.1.9 ! root 371: uPD7201Device::WriteCR3(SIO::channel *chan, uint32 data)
1.1.1.5 root 372: {
1.1.1.9 ! root 373: uint8 oldcr3;
! 374:
! 375: oldcr3 = chan->cr3;
1.1.1.5 root 376: chan->cr3 = data;
377:
1.1.1.9 ! root 378: putlog(2, "%s <- $%02x", CRName(chan), data);
! 379:
! 380: // Disable は Disable に変化した時だけ表示
! 381: if ((oldcr3 & SIO::CR3_RX_EN) != 0 && (chan->cr3 & SIO::CR3_RX_EN) == 0) {
! 382: putlog(1, "Channel %s RX Disable", chan->name);
! 383: }
! 384: // Enable はパラメータ変更があるかもなので常に表示
! 385: if ((chan->cr3 & SIO::CR3_RX_EN)) {
! 386: putlog(1, "Channel %s RX Enable, %d bits/frame",
! 387: chan->name,
! 388: bits_per_char[(chan->cr3 & SIO::CR3_RXBITS) >> 6]);
! 389: }
1.1.1.5 root 390: }
391:
392: // CR4 への書き込み
393: void
1.1.1.9 ! root 394: uPD7201Device::WriteCR4(SIO::channel *chan, uint32 data)
1.1.1.5 root 395: {
396: chan->cr4 = data;
1.1.1.9 ! root 397: putlog(2, "%s <- $%02x", CRName(chan), data);
1.1.1.5 root 398: uint8 stopbits = (chan->cr4 & SIO::CR4_STOPBITS);
399: uint8 syncmode = (chan->cr4 & SIO::CR4_SYNCMODE);
400:
1.1.1.9 ! root 401: // TODO: 優先順位逆じゃない?
! 402:
1.1.1.5 root 403: // モード分け、優先順位は分からない
404: if (stopbits == SIO::SYNC_MODE) {
405: if (syncmode == SIO::SYNC_HDLC) {
406: chan->mode = SIO::Mode::HDLC;
407: putlog(2, "Channel %s HDLC Mode", chan->name);
408: } else {
409: chan->mode = SIO::Mode::SYNC;
410: const char *sm[] = { "8bit", "16bit", "HDLC?", "Ext" };
411: putlog(2, "Channel %s Sync (%s) Mode",
412: chan->name, sm[syncmode >> 4]);
413: }
414: } else {
415: chan->mode = SIO::Mode::ASYNC;
416: const char *sm[] = { "?", "1", "1.5", "2" };
1.1.1.9 ! root 417: putlog(2, "Channel %s Async (x%d clock, stopbit %s) Mode",
1.1.1.5 root 418: chan->name,
1.1.1.9 ! root 419: clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6],
1.1.1.5 root 420: sm[stopbits >> 2]);
421: }
1.1.1.9 ! root 422:
! 423: SetTXPeriod(chan);
1.1.1.5 root 424: }
425:
426: // CR5 への書き込み
427: void
1.1.1.9 ! root 428: uPD7201Device::WriteCR5(SIO::channel *chan, uint32 data)
1.1.1.5 root 429: {
1.1.1.9 ! root 430: uint8 oldcr5;
! 431:
! 432: oldcr5 = chan->cr5;
1.1.1.5 root 433: chan->cr5 = data;
434:
1.1.1.9 ! root 435: putlog(2, "%s <- $%02x", CRName(chan), data);
! 436:
! 437: // Disable は Disable に変化した時だけ表示
! 438: // (Enable は SetTXPeriod() 内で表示)
! 439: if ((oldcr5 & SIO::CR5_TX_EN) != 0 && (chan->cr5 & SIO::CR5_TX_EN) == 0) {
! 440: putlog(1, "Channel %s TX Disable", chan->name);
! 441: }
! 442:
! 443: SetTXPeriod(chan);
! 444: TrySend(chan);
1.1.1.5 root 445: }
446:
447: // CR6 への書き込み
448: void
1.1.1.9 ! root 449: uPD7201Device::WriteCR6(SIO::channel *chan, uint32 data)
1.1.1.5 root 450: {
451: chan->cr6 = data;
452:
1.1.1.9 ! root 453: putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data);
1.1.1.5 root 454: }
455:
456: // CR7 への書き込み
457: void
1.1.1.9 ! root 458: uPD7201Device::WriteCR7(SIO::channel *chan, uint32 data)
1.1.1.5 root 459: {
460: chan->cr7 = data;
461:
1.1.1.9 ! root 462: putlog(0, "%s <- $%02x 書き込み(未実装)", CRName(chan), data);
1.1.1.5 root 463: }
1.1.1.2 root 464:
1.1 root 465: // データポートの読み込み
466: uint8
1.1.1.9 ! root 467: uPD7201Device::ReadData(SIO::channel *chan)
1.1 root 468: {
469: uint8 data;
470:
471: if (chan->rxlen > 0) {
472: data = chan->rxbuf[0];
1.1.1.5 root 473: putlog(3, "Ch%s Data -> $%02x", chan->name, data);
1.1 root 474: chan->rxlen--;
1.1.1.5 root 475: if (chan->rxlen == 0) {
476: // 取り出して空になった
477: chan->sr0 &= ~SIO::SR0_RXAVAIL;
478: ChangeInterrupt();
479: } else {
1.1.1.6 root 480: chan->rxbuf[0] = chan->rxbuf[1];
481: chan->rxbuf[1] = chan->rxbuf[2];
1.1 root 482: }
483: } else {
484: // XXX 何が読めるか
485: data = 0xff;
1.1.1.5 root 486: putlog(3, "Ch%s Data -> $%02x (Empty)", chan->name, data);
1.1 root 487: }
488:
489: return data;
490: }
491:
492: // データポートの書き込み
493: void
1.1.1.9 ! root 494: uPD7201Device::WriteData(SIO::channel *chan, uint32 data)
1.1 root 495: {
496: char charbuf[4];
497:
498: if (isprint((int)data)) {
499: snprintf(charbuf, sizeof(charbuf), "'%c'", data);
500: } else {
501: charbuf[0] = '\0';
502: }
1.1.1.5 root 503: putlog(3, "Ch%s Data <- $%02x %s", chan->name, data, charbuf);
1.1 root 504:
1.1.1.9 ! root 505: // XXX: EMPTY でないときにデータを書いたらどうなるかは未定義
1.1 root 506:
1.1.1.9 ! root 507: // 1byte の TX Buffer
! 508: chan->txlen = 1;
! 509: chan->txbuf = data;
! 510: chan->sr0 &= ~SIO::SR0_TXEMPTY;
! 511:
! 512: // TX 割り込みのクリア
! 513: chan->txint = false;
! 514: ChangeInterrupt();
! 515:
! 516: TrySend(chan);
! 517: }
! 518:
! 519: // 送信できるか調べて送信する
! 520: void
! 521: uPD7201Device::TrySend(SIO::channel *chan)
! 522: {
! 523: if ((chan->cr5 & SIO::CR5_TX_EN) == false) {
! 524: // 送信可でなければなにもしない
! 525: return;
! 526: }
! 527: if (chan->txlen == 0) {
! 528: // 送信バッファが空なら何もしない
! 529: return;
! 530: }
! 531: if (txevent[chan->id].IsRunning()) {
! 532: // 送信中なので何もしない
! 533: return;
! 534: }
! 535:
! 536: // 送信する
! 537: chan->tx_shiftreg = chan->txbuf;
! 538: txevent[chan->id].Start();
! 539: putlog(2, "Ch%s sending $%02x", chan->name, chan->tx_shiftreg);
! 540: chan->txlen = 0;
1.1 root 541:
1.1.1.9 ! root 542: // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず
! 543:
! 544: // 送信割り込み
! 545: chan->sr0 |= SIO::SR0_TXEMPTY;
! 546: chan->txint = true;
1.1.1.5 root 547: ChangeInterrupt();
1.1 root 548: }
549:
1.1.1.9 ! root 550: // 送信のイベントコールバック
! 551: void
! 552: uPD7201Device::TXCallback(Event& event)
! 553: {
! 554: int ch = event.code;
! 555: SIO::channel *chan = &cr.chan[ch];
! 556:
! 557: // 接続デバイスの呼び出し
! 558: Tx(ch, chan->tx_shiftreg);
! 559:
! 560: // 次の送信データが来てたら送信
! 561: TrySend(chan);
! 562: }
! 563:
1.1.1.2 root 564: // データポートの Peek
565: uint8
1.1.1.9 ! root 566: uPD7201Device::PeekData(const SIO::channel *chan) const
1.1.1.2 root 567: {
568: if (chan->rxlen > 0) {
569: // 受信バッファにデータがあれば先頭バイトが見える
570: return chan->rxbuf[0];
571: } else {
572: // 空の時は?
573: return 0xff;
574: }
575: }
576:
1.1.1.3 root 577: // TX/RX の bits/char のレジスタ値を実際の bits/char の値に変換する。
1.1.1.9 ! root 578: /*static*/ const int
1.1 root 579: uPD7201Device::bits_per_char[] = { 5, 7, 6, 8 };
580:
1.1.1.9 ! root 581: // CR4 CLKRATE のレジスタ値を実際の倍率に変換する。
! 582: /*static*/ const int
! 583: uPD7201Device::clkrate[] = { 1, 16, 32, 64 };
! 584:
1.1 root 585: // 1バイト受信する。
586: // 受理されれば true を返す。
587: bool
588: uPD7201Device::Rx(int ch, uint32 data)
589: {
1.1.1.9 ! root 590: SIO::channel *chan = &cr.chan[ch];
1.1 root 591:
592: // Rx Enable でなければ受け取らない?
593: if ((chan->cr3 & SIO::CR3_RX_EN) == 0) {
594: return false;
595: }
596:
1.1.1.5 root 597: // 1バイトでもあれば有効
598: chan->sr0 |= SIO::SR0_RXAVAIL;
599:
1.1 root 600: // バッファが一杯なら Rx Overrun Error
601: if (chan->rxlen == sizeof(chan->rxbuf)) {
602: putlog(2, "Rx Overrun");
603: chan->sr1 |= SIO::SR1_RXOVERRUN;
1.1.1.5 root 604: // XXX special Rx condition interrupt occurs
1.1 root 605: return false;
606: }
607:
608: // 受信
609: chan->rxbuf[chan->rxlen++] = data;
610:
1.1.1.5 root 611: // 割り込み状態を変更
612: ChangeInterrupt();
613:
614: return true;
615: }
616:
1.1.1.9 ! root 617: static double
! 618: to_freq(uint64 nsec)
! 619: {
! 620: return (double)1.0 / nsec * 1e9;
! 621: }
! 622:
! 623: // 送信イベントの時間を設定する (CR4, CR5 の変更で呼ぶ)
! 624: void
! 625: uPD7201Device::SetTXPeriod(SIO::channel *chan)
! 626: {
! 627: uint64 bit12_ns;
! 628: int bit;
! 629:
! 630: // 誤差を減らすため 12bit 単位が基準
! 631: // 12bit 時間
! 632: bit12_ns = txc12_ns * clkrate[(chan->cr4 & SIO::CR4_CLKRATE) >> 6];
! 633:
! 634: // start bit
! 635: bit = 1;
! 636:
! 637: // data bit
! 638: bit += bits_per_char[(chan->cr5 & SIO::CR5_TXBITS) >> 5];
! 639:
! 640: // parity bit
! 641: bit += (chan->cr4 & SIO::CR4_PARITY_EN) ? 1 : 0;
! 642:
! 643: switch (chan->cr4 & SIO::CR4_STOPBITS) {
! 644: case 0:
! 645: // 非同期モードでの STOPBITS 0 は未定義 (Enable ならログ表示)
! 646: if ((chan->cr5 & SIO::CR5_TX_EN)) {
! 647: putlog(0, "%s 未定義ストップビット長 0", CRName(chan, 4));
! 648: }
! 649: break;
! 650: case SIO::STOP_BITS_1:
! 651: bit += 1;
! 652: break;
! 653: case SIO::STOP_BITS_1_5:
! 654: // サポートしない (Enable ならログ表示)
! 655: if ((chan->cr5 & SIO::CR5_TX_EN)) {
! 656: putlog(0, "%s 未実装ストップビット長 1.5", CRName(chan, 4));
! 657: }
! 658: break;
! 659: case SIO::STOP_BITS_2:
! 660: bit += 2;
! 661: break;
! 662: }
! 663:
! 664: txevent[chan->id].time = bit * bit12_ns / 12;
! 665:
! 666: // TX Enable (CR5) ならパラメータを含めて表示
! 667: if ((chan->cr5 & SIO::CR5_TX_EN)) {
! 668: std::string nsstr;
! 669: if (loglevel >= 2) {
! 670: nsstr = string_format(" (%" PRIu64 ")", bit12_ns);
! 671: }
! 672: putlog(1, "Channel %s TX Enable, %.1f baud%s, %d bits/frame",
! 673: chan->name,
! 674: (double)to_freq(bit12_ns) * 12,
! 675: nsstr.c_str(),
! 676: bit);
! 677: }
! 678: }
! 679:
1.1.1.5 root 680: // 割り込み状態を変更
681: void
682: uPD7201Device::ChangeInterrupt()
683: {
684: uint int_asserted = 0;
685:
686: for (int ch = 0; ch < 2; ch++) {
1.1.1.9 ! root 687: SIO::channel *chan = &cr.chan[ch];
1.1.1.5 root 688:
689: // Rx
690: bool rx_avail = (chan->rxlen > 0) && chan->all_or_first;
691: // Special Rx
692: bool special = false; // XXX not yet
693:
694: bool rx_enable = (chan->cr3 & SIO::CR3_RX_EN);
695: bool rx_int = (rx_enable && (rx_avail || special));
696:
697: // FirstChar モードなら1文字受信割り込み後にフラグを下ろす
698: // (Rx 割り込み用の変数 rx_int が確定したここで行う)
699: if ((chan->cr1 & SIO::CR1_RXINT) == SIO::RXINT_FIRSTCHAR) {
700: chan->all_or_first = false;
1.1 root 701: }
1.1.1.5 root 702:
703: // XXX E/S not yet
704:
705: // Tx
706: bool tx_enable = (chan->cr1 & SIO::CR1_TXINT_EN);
1.1.1.9 ! root 707: bool tx_int = tx_enable && chan->txint;
1.1.1.5 root 708:
709: // 4つの要因の合成
710: chan->int_asserted = 0;
711: chan->int_asserted |= tx_int ? SIO::INTR_TX : 0;
712: chan->int_asserted |= rx_int ? SIO::INTR_RX : 0;
713:
714: // 両方のチャンネル分を合成
715: int_asserted |= chan->int_asserted;
1.1 root 716: }
717:
1.1.1.5 root 718: gInterrupt->ChangeINT(this, int_asserted);
1.1 root 719: }
720:
721: // モニター
1.1.1.4 root 722: void
1.1.1.7 root 723: uPD7201Device::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 724: {
1.1.1.5 root 725: int y;
726:
1.1.1.7 root 727: screen.Clear();
1.1 root 728: for (int i = 0; i < 2; i++) {
729: int x = 0;
1.1.1.5 root 730: y = i * 10;
1.1.1.7 root 731: MonitorUpdateCh(screen, i, x, y);
1.1 root 732: }
1.1.1.5 root 733:
734: // CR2A
735: uint cr2a = cr.cr2a;
736: y = 20;
1.1.1.7 root 737: screen.Print(0, y, "CR2A:$%02x", cr2a);
1.1.1.5 root 738: if ((cr2a & 0x80)) {
1.1.1.7 root 739: screen.Print(9, y, TA::On, "SYNC");
1.1.1.5 root 740: } else {
1.1.1.7 root 741: screen.Print(9, y, "RTSB");
1.1.1.5 root 742: }
1.1.1.8 root 743: screen.Print(14, y, TA::Disable, "----");
1.1.1.7 root 744: screen.Print(19, y, TA::OnOff((cr2a & 0x20)), "Vect");
1.1.1.5 root 745: if ((cr2a & 0x18) == 0x10) {
1.1.1.7 root 746: screen.Print(24, y, "IM=V4-V2");
1.1.1.5 root 747: } else {
1.1.1.7 root 748: screen.Print(24, y, "IM=V2-V0");
1.1.1.5 root 749: }
750: // bit2 (Priority Select) は bit0 が 0 の時だけ意味があるようだ
751: if ((cr2a & 0x01) == 0) {
752: if ((cr2a & 0x04)) {
1.1.1.7 root 753: screen.Print(34, y, "RxTx");
1.1.1.5 root 754: } else {
1.1.1.7 root 755: screen.Print(34, y, "A->B");
1.1.1.5 root 756: }
757: }
758: // bit1,0 はよく分からん
1.1.1.7 root 759: screen.Print(39, y, "INT/DMA=%d", (cr2a & 0x3));
1.1.1.5 root 760: y++;
761:
762: // CR2B
1.1.1.7 root 763: screen.Print(0, y, "CR2B:$%02x", cr.vector);
1.1 root 764: }
765:
766: // モニター (1チャンネル)
767: void
1.1.1.7 root 768: uPD7201Device::MonitorUpdateCh(TextScreen& screen,
1.1.1.4 root 769: int ch, int xbase, int ybase)
1.1 root 770: {
1.1.1.9 ! root 771: SIO::channel *chan = &cr.chan[ch];
1.1 root 772: uint cr0;
773: uint cr1;
774: uint cr3;
775: uint cr4;
776: uint cr5;
777: uint sr0;
778: uint sr1;
779: uint rxlen;
780: int x;
781: int y;
782:
1.1.1.5 root 783: cr0 = (chan->cr0 & ~SIO::CR0_PTR) | chan->ptr;
1.1 root 784: cr1 = chan->cr1;
785: cr3 = chan->cr3;
786: cr4 = chan->cr4;
787: cr5 = chan->cr5;
788: sr0 = chan->sr0;
789: sr1 = chan->sr1;
790: rxlen = chan->rxlen;
791:
792: // 0 1 2 3 4 5 6
793: // 012345678901234567890123456789012345678901234567890123456789012345
794: // 0123 0123 0123 0123 0123 0123 0123 0123
1.1.1.5 root 795: // CR0: $xx CRC=x CMD=x PTR=x
796: // CR1: $xx WE 0 WR RXInt=x 0 TXEn ESEn
797: // RXBuf: 0 --- --- --- Intr: Rx Sp Tx ES
1.1 root 798:
799: x = xbase;
800: y = ybase;
1.1.1.7 root 801: screen.Print(x, y++, "Channel %s: %s", chan->name, chan->desc);
802: screen.Print(x, y++, "CR0: $%02x", cr0);
803: screen.Print(x, y++, "CR1: $%02x", cr1);
804: screen.Print(x, y++, "CR3: $%02x", cr3);
805: screen.Print(x, y++, "CR4: $%02x", cr4);
806: screen.Print(x, y++, "CR5: $%02x", cr5);
807: screen.Print(x, y++, "SR0: $%02x", sr0);
808: screen.Print(x, y++, "SR1: $%02x", sr1);
809: screen.Print(x, y, "RXbuf: %d", rxlen);
1.1 root 810: int i;
811: for (i = 0; i < rxlen; i++) {
1.1.1.7 root 812: screen.Print(x + 9 + i * 4, y, "$%02x", chan->rxbuf[i]);
1.1 root 813: }
814: for (; i < sizeof(chan->rxbuf); i++) {
1.1.1.7 root 815: screen.Print(x + 9 + i * 4, y, "---");
1.1 root 816: }
1.1.1.5 root 817: // 内部割り込み状態
1.1.1.7 root 818: screen.Print(31, y, "Intr:");
819: screen.Print(37, y, TA::OnOff(chan->int_asserted & SIO::INTR_RX), "Rx");
820: screen.Print(40, y, TA::OnOff(chan->int_asserted & SIO::INTR_SP), "SP");
821: screen.Print(43, y, TA::OnOff(chan->int_asserted & SIO::INTR_TX), "Tx");
822: screen.Print(46, y, TA::OnOff(chan->int_asserted & SIO::INTR_ES), "ES");
1.1 root 823:
824: y = ybase + 1;
825: x = xbase;
826: // CR0
1.1.1.7 root 827: screen.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
1.1 root 828: static const char * const cmd_str[] = {
829: // 0123456789012345
830: "No operation",
831: "Send Abort",
832: "Reset E/S Int",
833: "Channel Reset",
834: "Enable IntNextCh",
835: "Reset TxIntPend",
836: "Error Reset",
837: "End of Interrupt",
838: };
839: uint cmd = (cr0 >> 3) & 7;
1.1.1.7 root 840: screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
841: screen.Print(x + 43, y, "PTR=%d", (cr0 & 7));
1.1 root 842: y++;
843:
844: // CR1
845: static const char * const cr1_str[] = {
1.1.1.9 ! root 846: "Wait", "-", "", "", "", "VMod", "TxIE", "ESIE"
1.1 root 847: };
1.1.1.7 root 848: MonitorReg(screen, x + 9, y, cr1, cr1_str);
1.1.1.9 ! root 849: if ((cr1 & SIO::CR1_WAIT_EN)) {
! 850: screen.Puts(x + 19, y, ((cr1 & SIO::CR1_WAIT_RX) ? "OnRx" : "OnTx"));
! 851: } else {
! 852: screen.Puts(x + 19, y, TA::Disable, "TxRx");
! 853: }
! 854: screen.Print(x + 24, y, "RxIntMod%d", (cr1 >> 3) & 3);
! 855: // CR1 の bit2 (Modified Vector) は CR1B のみ。
! 856: if (ch == 0) {
! 857: screen.Puts(x + 34, y, TA::Disable, "----");
! 858: }
1.1 root 859: y++;
860:
861: // CR3
862: static const char * const cr3_str[] = {
1.1.1.9 ! root 863: "", "", "Auto", "-", "-", "-", "-", "RxEn"
1.1 root 864: };
1.1.1.7 root 865: MonitorReg(screen, x + 9, y, cr3, cr3_str);
1.1.1.9 ! root 866: screen.Print(x + 9, y, "RxBits=%d", 5 + ((cr3 >> 6) & 3));
1.1 root 867: y++;
868:
869: // CR4
870: static const char * const cr4_str[] = {
871: "", "", "", "", "", "", "PaEv", "PaEn"
872: };
1.1.1.7 root 873: MonitorReg(screen, x + 9, y, cr4, cr4_str);
1.1 root 874:
875: static const char * const clkrate_str[] = {
876: "1", "16", "32", "64"
877: };
1.1.1.7 root 878: screen.Print(x + 9, y, "Rate=x%s", clkrate_str[(cr4 >> 6) & 3]);
1.1 root 879: static const char * const syncmode_str[] = {
880: "Mono", "Bi", "HDLC", "Ext"
881: };
1.1.1.9 ! root 882: uint stopbit = (cr4 >> 2) & 3;
! 883: screen.Print(x + 19, y, (stopbit == 0 ? TA::Normal : TA::Disable),
! 884: "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
1.1 root 885: static const char * const stopbit_str[] = {
1.1.1.9 ! root 886: "SyncMode",
! 887: "StopBit=1",
! 888: "Stop=1.5",
! 889: "StopBit=2"
1.1 root 890: };
1.1.1.9 ! root 891: screen.Puts(x + 29, y, stopbit_str[stopbit]);
1.1 root 892: y++;
893:
894: // CR5
895: static const char * const cr5_str[] = {
1.1.1.9 ! root 896: "!DTR", "", "", "SBrk", "TxEn", "CRC", "!RTS", "TCEn"
1.1 root 897: };
1.1.1.7 root 898: MonitorReg(screen, x + 9, y, cr5, cr5_str);
1.1.1.9 ! root 899: screen.Print(x + 14, y, "TxBits=%d", 5 + ((cr5 >> 5) & 3));
1.1 root 900: y++;
901:
902: // SR0
903: static const char * const sr0_str[] = {
1.1.1.9 ! root 904: "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "IntP", "RxAv"
1.1 root 905: };
1.1.1.7 root 906: MonitorReg(screen, x + 9, y, sr0, sr0_str);
1.1.1.5 root 907: // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。
908: if (ch == 1) {
1.1.1.8 root 909: screen.Print(39, y, TA::Disable, "----");
1.1.1.5 root 910: }
1.1 root 911: y++;
912:
913: // SR1
914: static const char * const sr1_str[] = {
1.1.1.9 ! root 915: "EOF", "FrEr", "RxOv", "PaEr", "", "", "", "Sent"
1.1 root 916: };
1.1.1.7 root 917: MonitorReg(screen, x + 9, y, sr1, sr1_str);
918: screen.Print(x + 29, y, "ResidueCode=%d", (sr1 >> 1) & 7);
1.1 root 919: y++;
920: }
921:
922: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
923: void
1.1.1.7 root 924: uPD7201Device::MonitorReg(TextScreen& screen,
1.1.1.4 root 925: int x, int y, uint32 reg, const char * const *names)
1.1 root 926: {
927: for (int i = 0; i < 8; i++) {
1.1.1.8 root 928: if (names[i][0] == '-') {
929: screen.Puts(x + i * 5, y, TA::Disable, "----");
1.1 root 930: } else {
931: bool b = reg & (1 << (7 - i));
1.1.1.7 root 932: screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1.1 root 933: }
934: }
935: }
1.1.1.9 ! root 936:
! 937: // ログ表示用のレジスタ名
! 938: /*static*/ const char * const
! 939: uPD7201Device::crnames[16] = {
! 940: "CR0A", "CR0B",
! 941: "CR1A", "CR1B",
! 942: "CR2A", "CR2B",
! 943: "CR3A", "CR3B",
! 944: "CR4A", "CR4B",
! 945: "CR5A", "CR5B",
! 946: "CR6A", "CR6B",
! 947: "CR7A", "CR7B",
! 948: };
! 949: /*static*/ const char * const
! 950: uPD7201Device::srnames[16] = {
! 951: "SR0A", "SR0B",
! 952: "SR1A", "SR1B",
! 953: "SR2A?", "SR2B",
! 954: "SR3A?", "SR3B?",
! 955: "SR4A?", "SR4B?",
! 956: "SR5A?", "SR5B?",
! 957: "SR6A?", "SR6B?",
! 958: "SR7A?", "SR7B?",
! 959: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.