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