|
|
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:
1.1.1.10 root 7: //
8: // SCC (Z8530)
9: //
10:
1.1 root 11: #include "scc.h"
1.1.1.8 root 12: #include "bitops.h"
1.1.1.10 root 13: #include "hostcom.h"
1.1.1.8 root 14: #include "keyboard.h"
1.1.1.5 root 15: #include "mpu.h"
1.1 root 16:
1.1.1.10 root 17: // グローバル参照用
18: SCCDevice *gSCC;
1.1.1.2 root 19:
1.1.1.10 root 20: // コンストラクタ
1.1 root 21: SCCDevice::SCCDevice()
1.1.1.7 root 22: : inherited("SCC")
1.1 root 23: {
24: devaddr = baseaddr;
25: devlen = 0x2000;
1.1.1.2 root 26:
1.1.1.10 root 27: mpscc.chan[0].desc = "Serial Port";
28: mpscc.chan[1].desc = "Mouse";
29:
30: // ポートアドレス。
31: // デバイス自身は自分が配置されるアドレスを知らなくてよい構造になって
32: // いるが、直接アクセスしたりする場合などに毎回アドレスを確認するのが
33: // 面倒なので(全機種で向きと間隔が異なる)、モニタで表示されてほしい。
34: mpscc.chan[1].ctrladdr = 0xe98001;
35: mpscc.chan[1].dataaddr = 0xe98003;
36: mpscc.chan[0].ctrladdr = 0xe98005;
37: mpscc.chan[0].dataaddr = 0xe98007;
1.1.1.7 root 38:
39: // X680x0 では SCC と呼ぶほうが通りがいい。
1.1.1.10 root 40: // イベントの登録は親クラスで行ってある。
1.1.1.9 root 41: for (int ch = 0; ch < txevent.size(); ch++) {
1.1.1.10 root 42: auto& chan = mpscc.chan[ch];
43: txevent[ch].SetName(string_format("SCC Ch%c TX", chan.name));
44: rxevent[ch].SetName(string_format("SCC Ch%c RX", chan.name));
1.1.1.9 root 45: }
1.1.1.10 root 46:
47: monitor.func = ToMonitorCallback(&SCCDevice::MonitorUpdate);
48: monitor.SetSize(70, 35);
1.1.1.7 root 49: monitor.Regist(ID_MONITOR_SCC);
1.1 root 50: }
51:
1.1.1.10 root 52: // デストラクタ
1.1 root 53: SCCDevice::~SCCDevice()
54: {
1.1.1.10 root 55: gSCC = NULL;
56: }
57:
58: // リセット
59: void
60: SCCDevice::ResetHard(bool poweron)
61: {
62: // Z8530 は RD と WR を同時に Low にするとリセットがかかる。
63: // 回路図からは PEDEC から繋がってるという以上のことは分からないけど
64: // 普通に考えればハードリセットでリセットされるよな。
65:
66: // WR9 b2,3,4 = %0、b6,7 = %1
67: mpscc.disable_lower_chain = false;
68: mpscc.master_int_enable = false;
69: mpscc.status_high_low = false;
70: // XXX Reset
71:
72: for (auto& chan : mpscc.chan) {
1.1.1.11! root 73: // XC 設定は ResetChannel() の前に必要。
! 74: SetXC(chan);
1.1.1.10 root 75: ResetChannel(chan);
76:
77: // WR10 b5,6 = %0
78: chan.wr10 &= ~0x40;
79:
80: // WR11
81: chan.wr11 = 0x08;
82:
83: // WR14 b0-1 = %0
84: //
85: // b4 (Local Loopback) は p.2-15 ではチャンネルリセット時は %0、
86: // ハードリセット時は %1 に初期化されると書いてあるが、おそらく
87: // そんなことはないだろうし、p.5-20 の WR14 の説明には
88: // "This bit is reset by a channel or hardware reset." とあるので
89: // たぶんこっちのほうが正しい。
90: chan.wr14 &= ~0x03;
91: }
1.1 root 92: }
93:
1.1.1.10 root 94: // チャンネルリセット
95: void
96: SCCDevice::ResetChannel(MPSCCChan& chan)
97: {
1.1.1.11! root 98: uint8 val;
! 99:
1.1.1.10 root 100: // WR0 b0-7 = %0
101: chan.crc_cmd = 0;
102: chan.cmd = 0;
103: chan.ptr = 0;
104:
105: // WR1 b0,1,3,4,6,7 = %0
106: chan.esint_enable = false;
107: chan.txint_enable = false;
108: chan.rxint_mode = MPSCCChan::RXINT_DISABLE;
109: chan.wait_func = false;
110: chan.wait_enable = false;
111:
112: // WR3 b0 = %0
113: chan.rx_enable = false;
114:
115: // WR4 b2 = %1
116: // b2,3 が StopBits 設定だが b2 だけ %1 にするらしい…。
117: // 少なくとも非同期モードにしときたいということだろうか。
1.1.1.11! root 118: val = GetCR4(chan);
! 119: SetCR4(chan, val | 0x04);
1.1.1.10 root 120:
121: // WR5 b1,2,3,4,7 = %0
1.1.1.11! root 122: val = GetCR5(chan);
! 123: SetCR5(chan, val & 0x61);
1.1.1.10 root 124:
125: // WR9 b5 = %0 (未実装ビット)
126:
127: // WR10 b0-4,7 = %0
128: chan.wr10 &= 0x60;
129:
130: // WR14 b2-4 = %0、b5 = %1
131: chan.wr14 &= 0xe3;
132: chan.wr14 |= 0x20;
133:
134: // WR15
135: chan.wr15 = 0xf8;
136:
137: // RR0 b0,1=%0、b2,6=%1
138: chan.tx_underrun = true;
139:
140: // RR1 b1,2=%1、b3-7=%0
141: chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
142: MPSCC::SR1_FRAMEERROR |
143: MPSCC::SR1_RXOVERRUN |
144: MPSCC::SR1_PARITYERROR);
145: chan.sr1 &= 0x08;
146: chan.sr1 |= 0x60;
147:
148: // RR3
149: chan.intpend = 0;
150:
151: // RR10 b0-5,7 = %0
152: chan.rr10 &= 0x40;
153:
154: ResetChannelCommon(chan);
155: }
1.1 root 156:
157: uint64
1.1.1.6 root 158: SCCDevice::Read(uint32 offset)
1.1 root 159: {
1.1.1.10 root 160: uint64 data;
161:
1.1.1.4 root 162: gMPU->AddCycle(41); // InsideOut p.135
163:
1.1.1.6 root 164: switch (offset) {
1.1.1.3 root 165: case 0: // $E98001
1.1.1.10 root 166: data = ReadCtrl(mpscc.chan[1]);
167: break;
1.1.1.3 root 168: case 1: // $E98003
1.1.1.10 root 169: data = ReadData(mpscc.chan[1]);
170: break;
1.1.1.3 root 171: case 2: // $E98005
1.1.1.10 root 172: data = ReadCtrl(mpscc.chan[0]);
173: break;
1.1.1.3 root 174: case 3: // $E98007
1.1.1.11! root 175: putlog(0, "Read ChA Data Register (NOT IMPLEMENTED)");
1.1.1.10 root 176: data = ReadData(mpscc.chan[0]);
177: break;
178: default:
179: __unreachable();
1.1 root 180: }
1.1.1.10 root 181: return data;
1.1 root 182: }
183:
184: uint64
1.1.1.6 root 185: SCCDevice::Write(uint32 offset, uint32 data)
1.1 root 186: {
1.1.1.4 root 187: gMPU->AddCycle(49); // InsideOut p.135
188:
1.1.1.6 root 189: switch (offset) {
1.1.1.3 root 190: case 0: // $E98001
1.1.1.10 root 191: WriteCtrl(mpscc.chan[1], data);
192: break;
1.1.1.3 root 193: case 1: // $E98003
1.1.1.10 root 194: WriteData(mpscc.chan[1], data);
195: break;
1.1.1.3 root 196: case 2: // $E98005
1.1.1.10 root 197: WriteCtrl(mpscc.chan[0], data);
198: break;
1.1.1.3 root 199: case 3: // $E98007
1.1.1.10 root 200: WriteData(mpscc.chan[0], data);
201: break;
202: default:
203: __unreachable();
1.1 root 204: }
1.1.1.10 root 205: return 0;
1.1 root 206: }
207:
208: uint64
1.1.1.6 root 209: SCCDevice::Peek(uint32 offset)
1.1 root 210: {
1.1.1.10 root 211: uint64 data;
212:
1.1.1.6 root 213: switch (offset) {
1.1.1.3 root 214: case 0: // $E98001
1.1.1.10 root 215: data = PeekCtrl(mpscc.chan[1]);
216: break;
1.1.1.3 root 217: case 1: // $E98003
1.1.1.10 root 218: data = PeekData(mpscc.chan[1]);
219: break;
1.1.1.3 root 220: case 2: // $E98005
1.1.1.10 root 221: data = PeekCtrl(mpscc.chan[0]);
222: break;
1.1.1.3 root 223: case 3: // $E98007
1.1.1.10 root 224: data = PeekData(mpscc.chan[0]);
225: break;
226: default:
227: __unreachable();
1.1.1.2 root 228: }
1.1.1.10 root 229: return data;
1.1 root 230: }
231:
1.1.1.10 root 232: // 書き込みレジスタ名を返す。
1.1.1.9 root 233: const char *
1.1.1.10 root 234: SCCDevice::CRName(const MPSCCChan& chan, int ptr_) const
1.1.1.9 root 235: {
236: assert(ptr_ < 16);
1.1.1.10 root 237: int idx = ptr_ * 2 + chan.id;
1.1.1.9 root 238: assert(idx < countof(wrnames));
239: return wrnames[idx];
240: }
241:
1.1.1.10 root 242: // 読み込みレジスタ名を返す。
1.1.1.9 root 243: const char *
1.1.1.10 root 244: SCCDevice::SRName(const MPSCCChan& chan, int ptr_) const
1.1.1.9 root 245: {
246: assert(ptr_ < 16);
1.1.1.10 root 247: int idx = ptr_ * 2 + chan.id;
1.1.1.9 root 248: assert(idx < countof(rrnames));
249: return rrnames[idx];
250: }
251:
1.1 root 252: // Z8530 制御ポート読み込み
253: uint8
1.1.1.10 root 254: SCCDevice::ReadCtrl(MPSCCChan& chan)
1.1 root 255: {
1.1.1.10 root 256: uint8 data;
1.1 root 257:
1.1.1.10 root 258: // PTR とレジスタの対応 (Z8530 p.2-13)
259: //
260: // PTR Reg PTR Reg PTR Reg PTR Reg
261: // 0 = RR0 4 = (RR0) 8 = RR8 12 = RR12
262: // 1 = RR1 5 = (RR1) 9 = (RR13) 13 = RR13
263: // 2 = RR2 6 = (RR2) 10 = RR10 14 = RR14
264: // 3 = RR3 7 = (RR3) 11 = (RR15) 15 = RR15
1.1 root 265:
1.1.1.10 root 266: switch (chan.ptr) {
267: case 0: // RR0
268: case 4:
269: data = GetRR0(chan);
1.1 root 270: break;
271:
1.1.1.10 root 272: case 1: // RR1
1.1 root 273: case 5:
1.1.1.10 root 274: data = chan.sr1;
275: break;
276:
277: case 2:
1.1 root 278: case 6:
1.1.1.10 root 279: if (chan.id == 0) { // RR2A
280: data = mpscc.vector;
281: } else { // RR2B
282: // 割り込み要因で変化したベクタ
283: data = GetSR2B();
284: }
285: break;
286:
287: case 3:
1.1 root 288: case 7:
1.1.1.10 root 289: if (chan.id == 0) { // RR3A
290: data = GetRR3A();
291: } else { // RR3B
292: data = 0;
293: }
1.1 root 294: break;
295:
1.1.1.10 root 296: case 8:
297: case 10:
298: case 12:
299: case 13:
300: case 9:
301: case 14:
302: case 15:
303: case 11:
1.1.1.11! root 304: putlog(0, "ReadCtrl %d (NOT IMPLEMENTED)", chan.ptr);
1.1.1.10 root 305: data = 0xff;
1.1 root 306: break;
307:
1.1.1.10 root 308: default:
309: __unreachable();
310: }
1.1.1.11! root 311: chan.ptr = 0;
1.1.1.10 root 312: return data;
313: }
314:
315: // Z8530 制御ポート書き込み
316: void
317: SCCDevice::WriteCtrl(MPSCCChan& chan, uint32 data)
318: {
319: // WR0 はコマンドかまたは次にアクセスするレジスタを指定する。
320: // WR0 以外のレジスタをアクセスすると、次のアクセスは WR0 に戻る。
321:
322: if (chan.ptr == 0) {
323: WriteWR0(chan, data);
324: } else {
325: switch (chan.ptr) {
326: case 1:
327: WriteWR1(chan, data);
1.1 root 328: break;
1.1.1.10 root 329: case 2:
330: WriteWR2(data);
1.1 root 331: break;
1.1.1.10 root 332: case 3:
333: WriteCR3(chan, data);
1.1 root 334: break;
1.1.1.10 root 335: case 4:
336: WriteCR4(chan, data);
337: break;
338: case 5:
339: WriteWR5(chan, data);
340: break;
341: case 6:
342: WriteCR6(chan, data);
343: break;
344: case 7:
345: WriteCR7(chan, data);
346: break;
347:
348: case 8:
349: WriteData(chan, data);
350: break;
351: case 9:
352: WriteWR9(data);
353: break;
354: case 10:
355: WriteWR10(chan, data);
356: break;
357: case 11:
358: WriteWR11(chan, data);
359: break;
360: case 12:
361: WriteWR12(chan, data);
362: break;
363: case 13:
364: WriteWR13(chan, data);
365: break;
366: case 14:
367: WriteWR14(chan, data);
368: break;
369: case 15:
370: WriteWR15(chan, data);
1.1 root 371: break;
372: default:
373: __unreachable();
374: }
375: // アクセス後は WR0 へ戻す
1.1.1.10 root 376: chan.ptr = 0;
377: }
378: }
1.1 root 379:
1.1.1.10 root 380: // 制御ポートの Peek
381: uint8
382: SCCDevice::PeekCtrl(const MPSCCChan& chan) const
383: {
384: uint8 data;
385:
386: switch (chan.ptr) {
387: case 0: // RR0
388: case 4:
389: data = GetRR0(chan);
1.1.1.5 root 390: break;
391:
1.1.1.10 root 392: case 1: // RR1
393: case 5:
394: data = chan.sr1;
1.1 root 395: break;
396:
1.1.1.10 root 397: case 2:
398: case 6:
399: if (chan.id == 0) { // RR2A
400: data = mpscc.vector;
401: } else {
402: data = GetSR2B();
403: }
1.1 root 404: break;
405:
1.1.1.10 root 406: case 3:
407: case 7:
408: if (chan.id == 0) { // RR3A
409: data = GetRR3A();
410: } else { // RR3B
411: data = 0;
412: }
1.1 root 413: break;
414:
1.1.1.10 root 415: case 8:
416: data = PeekData(chan);
1.1 root 417: break;
418:
1.1.1.10 root 419: case 10:
420: case 12:
421: case 13:
422: case 9:
423: case 14:
424: case 15:
425: case 11:
426: data = 0xff;
1.1 root 427: break;
428:
429: default:
1.1.1.10 root 430: __unreachable();
431: }
432: return data;
433: }
434:
435: // WR1 レジスタの内容を取得
436: uint8
437: SCCDevice::GetWR1(const MPSCCChan& chan) const
438: {
439: uint8 data = 0;
440:
441: if (chan.wait_enable)
442: data |= MPSCC::WR1_WAIT_EN;
443: if (chan.wait_func)
444: data |= MPSCC::WR1_WAIT_FUNC;
445: if (chan.wait_on_rx)
446: data |= MPSCC::WR1_WAIT_RX;
447: switch (chan.rxint_mode) {
448: case MPSCCChan::RXINT_DISABLE:
449: break;
450: case MPSCCChan::RXINT_1STCHAR:
451: data |= MPSCC::WR1_RXINT_1STCHAR;
1.1.1.9 root 452: break;
1.1.1.10 root 453: case MPSCCChan::RXINT_ALLCHAR:
454: data |= MPSCC::WR1_RXINT_ALLCHAR;
455: break;
456: case MPSCCChan::RXINT_SPONLY:
457: data |= MPSCC::WR1_RXINT_SPONLY;
458: break;
459: default:
460: __unreachable();
1.1.1.9 root 461: }
1.1.1.10 root 462: if (chan.sp_parity)
463: data |= MPSCC::WR1_SP_INC_PE;
464: if (chan.txint_enable)
465: data |= MPSCC::WR1_TXINT_EN;
466: if (chan.esint_enable)
467: data |= MPSCC::WR1_ESINT_EN;
468:
469: return data;
1.1.1.9 root 470: }
471:
1.1.1.10 root 472: // WR9 レジスタの内容を取得
473: uint8
474: SCCDevice::GetWR9() const
1.1.1.9 root 475: {
1.1.1.10 root 476: uint8 data = 0;
477:
478: data |= mpscc.wr9_cmd << 6;
479: if (mpscc.status_high_low) data |= MPSCC::WR9_SHSL;
480: if (mpscc.master_int_enable) data |= MPSCC::WR9_MIE;
481: if (mpscc.disable_lower_chain) data |= MPSCC::WR9_DLC;
482: if (!mpscc.vectored_mode) data |= MPSCC::WR9_NV;
483: if (mpscc.sav_vis) data |= MPSCC::WR9_VIS;
484:
485: return data;
1.1.1.9 root 486: }
487:
1.1.1.10 root 488: // RR0 レジスタの内容を取得
489: uint8
490: SCCDevice::GetRR0(const MPSCCChan& chan) const
1.1.1.9 root 491: {
1.1.1.10 root 492: uint8 data = 0;
493:
494: if (chan.break_detected)data |= MPSCC::RR0_BREAK;
495: if (chan.tx_underrun) data |= MPSCC::RR0_TXUNDER;
496: if (chan.nCTS) data |= MPSCC::RR0_nCTS;
497: if (chan.nSYNC) data |= MPSCC::RR0_nSYNC;
498: if (chan.nDCD) data |= MPSCC::RR0_nDCD;
499: if (chan.txlen == 0) data |= MPSCC::RR0_TXEMPTY;
500: if (false) data |= MPSCC::RR0_ZEROCNT; // XXX TODO
501: if (chan.rxlen != 0) data |= MPSCC::RR0_RXAVAIL;
502:
503: return data;
504: }
505:
506: // RR3A の内容を取得
507: uint8
508: SCCDevice::GetRR3A() const
509: {
510: uint8 data = 0;
511:
512: if ((mpscc.chan[0].intpend & INTPEND_RX))
513: data |= MPSCC::RR3_RXA;
514: if ((mpscc.chan[0].intpend & INTPEND_TX))
515: data |= MPSCC::RR3_TXA;
516: if ((mpscc.chan[0].intpend & INTPEND_ES))
517: data |= MPSCC::RR3_ESA;
518:
519: if ((mpscc.chan[1].intpend & INTPEND_RX))
520: data |= MPSCC::RR3_RXB;
521: if ((mpscc.chan[1].intpend & INTPEND_TX))
522: data |= MPSCC::RR3_TXB;
523: if ((mpscc.chan[1].intpend & INTPEND_ES))
524: data |= MPSCC::RR3_ESB;
525:
526: return data;
527: }
1.1.1.9 root 528:
1.1.1.10 root 529: // WR0 への書き込み
530: void
531: SCCDevice::WriteWR0(MPSCCChan& chan, uint32 data)
532: {
1.1.1.9 root 533: // XXX b7,b6 (CRC Reset Command) は未対応。
534: // XXX コマンドが %001、%000 以外の時に PTR(レジスタセレクト) が同時に
535: // 指定されたらどうなるか。
1.1.1.10 root 536: chan.crc_cmd = (data & MPSCC::CR0_CRC) >> 6;;
537: chan.cmd = (data & MPSCC::CR0_CMD) >> 3;
1.1.1.9 root 538:
1.1.1.10 root 539: if (chan.crc_cmd != 0) {
540: // CRC は非同期モードでは不要のはず
1.1.1.11! root 541: putlog(3, "%s CRC Reset %d (NOT IMPLEMENTED)",
! 542: WRName(chan, 0), chan.crc_cmd);
1.1.1.9 root 543: }
544:
1.1.1.10 root 545: if (chan.cmd == 0 || chan.cmd == 1) {
1.1.1.9 root 546: // コマンド 0、1 がレジスタ切り替え
1.1.1.10 root 547: chan.ptr = data & MPSCC::WR0_PTR;
548: putlog(3, "%s <- $%02x (ptr=%d)", WRName(chan, 0), data, chan.ptr);
549: } else {
550: // それ以外ならコマンド発行
551: putlog(2, "%s <- $%02x", CRName(chan, 0), data);
552:
553: switch (chan.cmd) {
554: case 2: // Reset Ext/Status Interrupts
555: ResetESIntr(chan);
556: break;
557: case 3: // Send Abort
558: SendAbort(chan);
559: break;
560: case 4: // Enable Int on Next Rx Character
561: EnableIntrOnNextRx(chan);
562: break;
563: case 5: // Reset Tx Int Pending
564: ResetTxIntrPending(chan);
565: break;
566: case 6: // Error Reset
567: ErrorReset(chan);
568: break;
569: case 7: // Reset Highest IUS
570: ResetHighestIUS(chan);
571: break;
572: default:
573: __unreachable();
574: }
575: }
576: }
577:
578: // WR1[AB] への書き込み
579: void
580: SCCDevice::WriteWR1(MPSCCChan& chan, uint32 data)
581: {
582: putlog(2, "%s <- $%02x", WRName(chan), data);
583:
584: chan.wait_enable = (data & MPSCC::WR1_WAIT_EN);
585: chan.wait_func = (data & MPSCC::WR1_WAIT_FUNC);
586: chan.wait_on_rx = (data & MPSCC::WR1_WAIT_RX);
587: // SCC の RXINT は内部フォーマットと同じ値にしてあるのでそのまま代入可。
588: chan.rxint_mode = (data >> 3) & 3;
589: chan.all_or_first = (chan.rxint_mode != 0);
590: chan.sp_parity = (data & MPSCC::WR1_SP_INC_PE);
591: chan.txint_enable = (data & MPSCC::WR1_TXINT_EN);
592: chan.esint_enable = (data & MPSCC::WR1_ESINT_EN);
593: }
594:
595: // WR2 への書き込み
596: void
597: SCCDevice::WriteWR2(uint32 data)
598: {
599: // Z8530 の WR2 は A/B 共通でベクタ設定
600: putlog(2, "WR2 <- $%02x (Set Vector)", data);
601: mpscc.vector = data;
602: }
603:
604: void
605: SCCDevice::WriteWR5(MPSCCChan& chan, uint32 data)
606: {
1.1.1.11! root 607: // ~RTS 端子の立ち下がりでマウスに送信要求。
! 608: // ~RTS 端子の立ち下がりは nRTS ビットでは立ち上がりになる。
! 609: bool old_nRTS = chan.nRTS;
! 610: bool new_nRTS = (data & MPSCC::WR5_nRTS);
! 611: bool rts = (old_nRTS == false && new_nRTS);
1.1.1.10 root 612:
613: inherited::WriteCR5(chan, data);
614:
615: if (chan.id == 1 && rts) {
616: gKeyboard->MouseSendStart();
617: }
618: }
619:
620: void
621: SCCDevice::WriteWR9(uint32 data)
622: {
623: putlog(2, "WR9 <- $%02x", data);
624:
625: mpscc.wr9_cmd = (data >> 6);
626: switch (mpscc.wr9_cmd) {
627: case 0: // No Reset
1.1.1.9 root 628: break;
1.1.1.10 root 629: case 1: // Channel Reset B
630: putlog(1, "Channel B Reset");
631: ResetChannel(mpscc.chan[1]);
1.1.1.9 root 632: break;
1.1.1.10 root 633: case 2: // Channel Reset A
634: putlog(1, "Channel A Reset");
635: ResetChannel(mpscc.chan[0]);
1.1 root 636: break;
1.1.1.10 root 637: case 3: // Force Hardware Reset
638: ResetHard(false);
1.1.1.9 root 639: break;
640: default:
641: __unreachable();
1.1 root 642: }
1.1.1.10 root 643:
644: // これらはハードウェアリセットと同時に指定されたら、
645: // リセット後に処理のはず?
646: mpscc.status_high_low = (data & MPSCC::WR9_SHSL);
647: mpscc.master_int_enable = (data & MPSCC::WR9_MIE);
648: mpscc.disable_lower_chain = (data & MPSCC::WR9_DLC);
649: mpscc.vectored_mode = !(data & MPSCC::WR9_NV);
650: mpscc.sav_vis = (data & MPSCC::WR9_VIS);
651:
652: // SHSL と VIS によって vis モードを再設定
653: if (mpscc.sav_vis) {
654: if (mpscc.status_high_low) {
655: mpscc.vis = MPSCC::VIS_456;
656: } else {
657: mpscc.vis = MPSCC::VIS_321;
658: }
659: } else {
660: mpscc.vis = MPSCC::VIS_FIXED;
661: }
1.1 root 662: }
663:
1.1.1.8 root 664: void
1.1.1.10 root 665: SCCDevice::WriteWR10(MPSCCChan& chan, uint32 data)
1.1.1.8 root 666: {
1.1.1.11! root 667: putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data);
1.1.1.10 root 668: chan.wr10 = data;
669: }
1.1.1.8 root 670:
1.1.1.10 root 671: void
672: SCCDevice::WriteWR11(MPSCCChan& chan, uint32 data)
673: {
1.1.1.11! root 674: putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data);
1.1.1.10 root 675: chan.wr11 = data;
676: }
1.1.1.8 root 677:
1.1.1.10 root 678: void
679: SCCDevice::WriteWR12(MPSCCChan& chan, uint32 data)
680: {
681: chan.tc = (chan.tc & 0xff00) | data;
682: putlog(2, "%s TC(L)=%04x", WRName(chan), chan.tc);
683: SetXC(chan);
684: }
685:
686: void
687: SCCDevice::WriteWR13(MPSCCChan& chan, uint32 data)
688: {
689: chan.tc = (chan.tc & 0x00ff) | (data << 8);
690: putlog(2, "%s TC(H)=%04x", WRName(chan), chan.tc);
691: SetXC(chan);
692: }
693:
694: void
695: SCCDevice::WriteWR14(MPSCCChan& chan, uint32 data)
696: {
1.1.1.11! root 697: putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data);
1.1.1.10 root 698: chan.wr14 = data;
699: }
700:
701: void
702: SCCDevice::WriteWR15(MPSCCChan& chan, uint32 data)
703: {
1.1.1.11! root 704: putlog(2, "%s <- $%02x (NOT IMPLEMENTED)", WRName(chan), data);
1.1.1.10 root 705: chan.wr15 = data;
706: }
707:
708: // モニター
709: void
710: SCCDevice::MonitorUpdate(Monitor *, TextScreen& screen)
711: {
712: uint wr9;
713: uint rr3a;
714: int y;
715:
716: wr9 = GetWR9();
717: rr3a = GetRR3A();
718:
719: screen.Clear();
720: for (int i = 0; i < 2; i++) {
721: int x = 0;
722: y = i * 16;
723: MonitorUpdateCh(screen, i, x, y);
724: }
725:
726: y = 32;
727: // WR9
728: screen.Print(0, y, "WR9 :$%02x", wr9);
729: static const char * const wr9_str[] = {
730: "", "", "-", "SHSL", "MIE", "DLC", "NV", "VIS"
731: };
732: MonitorReg(screen, 9, y, wr9, wr9_str);
733: static const char * const resetcmd_str[] = {
734: // 012345678
735: "(NoReset)",
736: "(RstChB)",
737: "(RstChA)",
738: "(HardRst)",
739: };
740: screen.Puts(9, y, resetcmd_str[wr9 >> 6]);
741: y++;
742:
743: // RR2B / RR2B
744: screen.Print(0, y, "RR2A:$%02x / RR2B:$%02x", mpscc.vector, GetSR2B());
745: y++;
746:
747: // RR3A
748: static const char * const rr3a_str[] = {
749: "-", "-", "RxA", "TxA", "ESA", "RxB", "TxB", "ESB"
750: };
751: screen.Print(0, y, "RR3A:$%02x", rr3a);
752: MonitorReg(screen, 9, y, rr3a, rr3a_str);
753: y++;
754: }
755:
756: // モニター (1チャンネル)
757: void
758: SCCDevice::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase)
759: {
760: const MPSCCChan& chan = mpscc.chan[ch];
761: uint crc;
762: uint cmd;
763: uint ptr;
764: uint wr0;
765: uint wr1;
766: uint wr3;
767: uint wr4;
768: uint wr5;
1.1.1.11! root 769: uint wr6;
! 770: uint wr7;
1.1.1.10 root 771: uint wr10;
772: uint wr11;
773: uint wr14;
774: uint wr15;
775: uint rr0;
776: uint rr1;
777: uint rr10;
778: uint rxlen;
779: uint tc;
780: int x;
781: int y;
782:
783: wr0 = GetCR0(chan);
784: crc = chan.crc_cmd;
785: cmd = chan.cmd;
786: ptr = chan.ptr;
787: wr1 = GetWR1(chan);
788: wr3 = GetCR3(chan);
1.1.1.11! root 789: wr4 = GetCR4(chan);
1.1.1.10 root 790: wr5 = GetCR5(chan);
1.1.1.11! root 791: wr6 = chan.cr6;
! 792: wr7 = chan.cr7;
1.1.1.10 root 793: wr10 = chan.wr10;
794: wr11 = chan.wr11;
795: tc = chan.tc;
796: wr14 = chan.wr14;
797: wr15 = chan.wr15;
798: rr0 = GetRR0(chan);
799: rr1 = chan.sr1;
800: rr10 = chan.rr10;
801: rxlen = chan.rxlen;
802:
803: // 0 1 2 3 4 5 6
804: // 0123456789012345678901234567890123456789012345678901234567890123456789
805: // 0123 0123 0123 0123 0123 0123 0123 0123
806: // Channel A: Serial Console DataAddr $000000
807: // WR0: $xx CRC=x CMD=x PTR=x CtrlAddr $000000
808: // WR1: $xx WE 0 WR RXInt=x 0 TXEn ESEn
1.1.1.11! root 809: // WR13/WR12: $001f (196000bps) WR7/WR6:$1234
1.1.1.10 root 810:
811: x = xbase;
812: y = ybase;
813: screen.Print(x, y++, "Channel %c: %s", chan.name, chan.desc);
814: screen.Print(x, y++, "WR0: $%02x", wr0);
815: screen.Print(x, y++, "WR1: $%02x", wr1);
816: screen.Print(x, y++, "WR3: $%02x", wr3);
817: screen.Print(x, y++, "WR4: $%02x", wr4);
818: screen.Print(x, y++, "WR5: $%02x", wr5);
819: screen.Print(x, y++, "WR10:$%02x", wr10);
820: screen.Print(x, y++, "WR11:$%02x", wr11);
821: screen.Print(x, y++, "WR14:$%02x", wr14);
822: screen.Print(x, y++, "WR15:$%02x", wr15);
1.1.1.11! root 823: screen.Print(x, y, "WR13/WR12:$%04x (%.1fbps)", tc, chan.baudrate);
! 824: screen.Print(x + 35, y++, "WR7/WR6:$%02x%02x", wr7, wr6);
1.1.1.10 root 825: screen.Print(x, y++, "RR0: $%02x", rr0);
826: screen.Print(x, y++, "RR1: $%02x", rr1);
827: screen.Print(x, y++, "RR10:$%02x", rr10);
828: screen.Print(x, y, "RXbuf: %d", rxlen);
829: int i;
830: for (i = 0; i < rxlen; i++) {
831: screen.Print(x + 9 + i * 4, y, "$%02x", chan.rxbuf[i]);
1.1.1.8 root 832: }
1.1.1.10 root 833: for (; i < sizeof(chan.rxbuf); i++) {
834: screen.Print(x + 9 + i * 4, y, "---");
835: }
836:
837: y = ybase + 1;
838: x = xbase;
839: // WR0
840: screen.Print(x + 9, y, "CRC=%d", crc);
841: static const char * const cmd_str[] = {
842: // 012345678901234
843: "Null command",
844: "Point High",
845: "Reset E/S Int",
846: "Send Abort",
847: "EnableIntNextCh",
848: "Reset TxIntPend",
849: "Error Reset",
850: "ResetHighestIUS",
851: };
852: screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
853: screen.Print(x + 43 - (ptr > 9 ? 1 : 0), y, "PTR=%d", ptr);
854: y++;
855:
856: // WR1
857: static const char * const wr1_str[] = {
858: "Wait", "Func", "OnRx", "", "", "SpPE", "TxIE", "ESIE"
859: };
860: MonitorReg(screen, x + 9, y, wr1, wr1_str);
861: static const char * const rxint_str[] = {
862: // 012345678
863: "RxInt=Dis",
864: "RI=1stChr",
865: "RI=AllChr",
866: "RI=SPOnly",
867: };
868: screen.Puts(x + 24, y, rxint_str[(wr1 >> 3) & 3]);
869: y++;
870:
871: // WR3,WR4,WR5
872: y = MonitorUpdateCR345(screen, x, y, wr3, wr4, wr5);
873:
874: // WR10
875: screen.Puts(x + 9, y, TA::Disable, (wr10 & 0x80) ? "CRC1" : "CRC0");
876: static const char * const de_str[] = {
877: // 012345678
878: "Enc=NRZ",
879: "Enc=NRZI",
880: "Enc=FM(1)",
881: "Enc=FM(0)",
882: };
883: screen.Puts(x + 14, y, de_str[(wr10 >> 5) & 3]);
884: screen.Puts(x + 24, y, TA::Disable, (wr10 & 0x10) ? "1" : "0");
885: screen.Puts(x + 29, y, TA::Disable, (wr10 & 0x08) ? "1" : "0");
886: screen.Puts(x + 34, y, TA::Disable, (wr10 & 0x04) ? "1" : "0");
887: screen.Puts(x + 39, y, TA::Disable, (wr10 & 0x02) ? "1" : "0");
888: screen.Puts(x + 44, y, TA::Disable, (wr10 & 0x01) ? "1" : "0");
889: y++;
890:
891: // WR11
892: screen.Puts(x + 9, y, TA::OnOff(wr11 & 0x80), "XTAL");
893: static const char * const clksrc_str[] = {
894: // 45678
895: "!RTxC",
896: "!TRxC",
897: "BRG",
898: "DPLL",
899: };
900: screen.Print(x + 14, y, "RxC=%s", clksrc_str[(wr11 >> 5) & 3]);
901: screen.Print(x + 24, y, "TxC=%s", clksrc_str[(wr11 >> 3) & 3]);
902: screen.Puts(x + 34, y, TA::OnOff(wr11 & 0x04), "TOUT");
903: static const char * const clkout_str[] = {
904: // 012345678
905: "TRxC=DPLL",
906: "TRxC=BRG",
907: "TRxC=Clk",
908: "TRxC=Xtal",
909: };
910: screen.Puts(x + 39, y, clkout_str[(wr11 & 3)]);
911: y++;
912:
913: // WR14
914: static const char * const wr14_str[] = {
915: "", "", "", "LLB", "Echo", "DTRL", "BRGS", "BRGE",
916: };
917: MonitorReg(screen, x + 9, y, wr14, wr14_str);
918: static const char * const dpllcmd_str[] = {
919: // 01234567890123
920: "(DPLL nullcmd)",
921: "(EntSearchMod)",
922: "(ResetMissClk)",
923: "(Disable DPLL)",
924: "(Set SRC=BRG)",
925: "(Set SRC=RTxC)",
926: "(Set FM Mode)",
927: "(Set NRZIMode)",
928: };
929: screen.Puts(x + 9, y, dpllcmd_str[(wr14 >> 5)]);
930: y++;
931:
932: // WR15
933: static const char * const wr15_str[] = {
934: "BrIE", "TUIE", "CTIE", "SHIE", "DCIE", "-", "ZCIE", "-"
935: };
936: MonitorReg(screen, x + 9, y, wr15, wr15_str);
937: y++;
938:
939: // WR12/WR13
940: y++;
941:
942: // RR0
943: static const char * const rr0_str[] = {
944: "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "ZCnt", "RxAv"
945: };
946: MonitorReg(screen, x + 9, y, rr0, rr0_str);
947: y++;
948:
949: // RR1
950: MonitorUpdateSR1(screen, x, y, rr1);
951: y++;
952:
953: // RR10
954: static const char * const rr10_str[] = {
955: "1CM", "2CM", "-", "", "-", "-", "", "-"
956: };
957: MonitorReg(screen, x + 9, y, rr10, rr10_str);
958: screen.Puts(x + 24, y, TA::Disable, (rr10 & 0x10) ? "1" : "0");
959: screen.Puts(x + 39, y, TA::Disable, (rr10 & 0x02) ? "1" : "0");
960: y++;
961:
962: // 右列
1.1.1.11! root 963: y = ybase + 1;
1.1.1.10 root 964: x = xbase + 51;
1.1.1.11! root 965: screen.Print(x, y++, "DataAddr: $%06x", chan.dataaddr);
! 966: screen.Print(x, y++, "CtrlAddr: $%06x", chan.ctrladdr);
1.1.1.10 root 967: y++;
1.1.1.11! root 968: screen.Print(x, y++, "Param: %12s", GetParamStr(chan).c_str());
! 969: screen.Print(x, y++, "Rx Bits/Frame: %2d", chan.rxframebits);
! 970: screen.Print(x, y++, "Tx Bits/Frame: %2d", chan.txframebits);
1.1.1.8 root 971: }
972:
1.1.1.10 root 973: // 内部の送信データクロックの設定
1.1 root 974: void
1.1.1.10 root 975: SCCDevice::SetXC(MPSCCChan& chan)
1.1 root 976: {
1.1.1.10 root 977: // 5MHz = 200nsec
978: // 12bit = 2.4usec
1.1.1.11! root 979: chan.xc12_ns = (2 * (chan.tc + 2)) * 2.4_usec;
! 980: ChangeBaudrate(chan);
1.1.1.5 root 981: }
982:
983: // 割り込みアクノリッジ
984: int
985: SCCDevice::InterruptAcknowledge()
986: {
1.1.1.10 root 987: return GetSR2B();
988: }
989:
990: // ペンディングのうち最も優先度の高い割り込み要因を返す
991: uint
992: SCCDevice::GetHighestInt() const
993: {
994: // 上から RxA, TxA, ESA, RxB, TxB, ESB の順 (Z8530 p.2-16)。
995:
996: if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
997: if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
998: if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
999: if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
1000: if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
1001: if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
1002: if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
1003: if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
1004:
1005: return MPSCC::VS_none;
1.1 root 1006: }
1.1.1.9 root 1007:
1008: void
1009: SCCDevice::Tx(int ch, uint32 data)
1010: {
1.1.1.10 root 1011: switch (ch) {
1012: case 0:
1013: hostcom->Tx(data);
1014: break;
1015: case 1:
1016: // ChB はマウスだが TxD は接続されていない
1017: break;
1018: default:
1019: __unreachable();
1020: }
1.1.1.9 root 1021: }
1022:
1023: // ログ表示用のレジスタ名
1024: /*static*/ const char * const
1025: SCCDevice::wrnames[32] = {
1026: "WR0A", "WR0B",
1027: "WR1A", "WR1B",
1.1.1.10 root 1028: "WR2", "WR2",
1.1.1.9 root 1029: "WR3A", "WR3B",
1030: "WR4A", "WR4B",
1031: "WR5A", "WR5B",
1032: "WR6A", "WR6B",
1033: "WR7A", "WR7B",
1034: "WR8A", "WR8B",
1.1.1.10 root 1035: "WR9", "WR9",
1.1.1.9 root 1036: "WR10A", "WR10B",
1037: "WR11A", "WR11B",
1038: "WR12A", "WR12B",
1039: "WR13A", "WR13B",
1040: "WR14A", "WR14B",
1041: "WR15A", "WR15B",
1042: };
1043: /*static*/ const char * const
1044: SCCDevice::rrnames[32] = {
1045: "RR0A", "RR0B",
1046: "RR1A", "RR1B",
1047: "RR2A", "RR2B",
1048: "RR3A", "RR3B",
1.1.1.10 root 1049: "(RR0A)", "(RR0B)",
1050: "(RR1A)", "(RR1B)",
1051: "(RR2A)", "(RR2B)",
1052: "(RR3A)", "(RR3B)",
1.1.1.9 root 1053: "RR8A", "RR8B",
1.1.1.10 root 1054: "(RR13A)", "(RR13B)",
1.1.1.9 root 1055: "RR10A", "RR10B",
1.1.1.10 root 1056: "(RR15A)", "(RR15B)",
1.1.1.9 root 1057: "RR12A", "RR12B",
1058: "RR13A", "RR13B",
1.1.1.10 root 1059: "RR14A", "RR14B",
1.1.1.9 root 1060: "RR15A", "RR15B",
1061: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.