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