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