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