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