|
|
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.