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