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