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