|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.9 ! root 7: //
! 8: // SIO (uPD7201)
! 9: //
! 10:
! 11: #define MPSCC_SIO_LOG_HACK
1.1 root 12: #include "sio.h"
1.1.1.9 ! root 13: #include "hostcom.h"
1.1.1.8 root 14: #include "keyboard.h"
1.1.1.9 ! root 15: #include "mainapp.h"
1.1 root 16:
1.1.1.9 ! root 17: // グローバル参照用
! 18: SIODevice *gSIO;
1.1 root 19:
1.1.1.9 ! root 20: // コンストラクタ
1.1 root 21: SIODevice::SIODevice()
1.1.1.7 root 22: : inherited("SIO")
1.1 root 23: {
24: devaddr = 0x51000000;
25:
1.1.1.9 ! root 26: mpscc.chan[0].desc = "Serial Console";
! 27: mpscc.chan[1].desc = "Keyboard";
! 28:
! 29: // ポートアドレス。
! 30: // デバイス自身は自分が配置されるアドレスを知らなくてよい構造になって
! 31: // いるが、直接アクセスしたりする場合などに毎回アドレスを確認するのが
! 32: // 面倒なので(全機種で向きと間隔が異なる)、モニタで表示されてほしい。
! 33: if (gMainApp.GetVMType() == VMTYPE_LUNA1) {
! 34: mpscc.chan[0].dataaddr = 0x51000000;
! 35: mpscc.chan[0].ctrladdr = 0x51000002;
! 36: mpscc.chan[1].dataaddr = 0x51000004;
! 37: mpscc.chan[1].ctrladdr = 0x51000006;
! 38: } else {
! 39: mpscc.chan[0].dataaddr = 0x51000000;
! 40: mpscc.chan[0].ctrladdr = 0x51000004;
! 41: mpscc.chan[1].dataaddr = 0x51000008;
! 42: mpscc.chan[1].ctrladdr = 0x5100000c;
! 43: }
1.1.1.7 root 44:
1.1.1.8 root 45: // 153.6kHz = 6.510416...usec / bit;
46: // 12bit = 78.125usec
1.1.1.9 ! root 47: xc12_ns = 78.125_usec;
1.1.1.8 root 48:
1.1.1.7 root 49: // LUNA では SIO と呼ぶほうが通りがいい。
1.1.1.9 ! root 50: // イベントの登録は親クラスで行ってある。
1.1.1.8 root 51: for (int ch = 0; ch < txevent.size(); ch++) {
1.1.1.9 ! root 52: auto& chan = mpscc.chan[ch];
! 53: txevent[ch].SetName(string_format("SIO Ch%c TX", chan.name));
! 54: rxevent[ch].SetName(string_format("SIO Ch%c RX", chan.name));
1.1.1.8 root 55: }
1.1.1.9 ! root 56:
! 57: monitor.func = ToMonitorCallback(&SIODevice::MonitorUpdate);
! 58: monitor.SetSize(70, 22);
1.1.1.7 root 59: monitor.Regist(ID_MONITOR_SIO);
1.1 root 60: }
61:
1.1.1.9 ! root 62: // デストラクタ
1.1 root 63: SIODevice::~SIODevice()
64: {
1.1.1.9 ! root 65: gSIO = NULL;
! 66: }
! 67:
! 68: // リセット
! 69: void
! 70: SIODevice::ResetHard(bool poweron)
! 71: {
! 72: // master_int_enable は uPD7201 にはなく常に true と等価
! 73: mpscc.master_int_enable = true;
! 74:
! 75: // CR2 b0-5,7 = %0
! 76: mpscc.intdma_mode = 0;
! 77: mpscc.priority_select = false;
! 78: mpscc.int_mode = 0;
! 79: mpscc.vectored_mode = false;
! 80: mpscc.syncb = false;
! 81:
! 82: for (auto& chan : mpscc.chan) {
! 83: ResetChannel(chan);
! 84: }
! 85:
! 86: // ログ省略ステートをリセット
! 87: sr0_logphase = 0;
! 88: }
! 89:
! 90: // チャンネルリセット
! 91: void
! 92: SIODevice::ResetChannel(MPSCCChan& chan)
! 93: {
! 94: // CR0 b0-2 = %0
! 95: chan.ptr = 0;
! 96:
! 97: // CR1 b0,1,3,4,7 = %0
! 98: chan.esint_enable = false;
! 99: chan.txint_enable = false;
! 100: chan.rxint_mode = 0;
! 101: chan.wait_enable = false;
! 102:
! 103: // CR3 b0-7 = %0
! 104: chan.cr3 = 0;
! 105: chan.rx_enable = false;
! 106:
! 107: // CR5 b1,2,3,4,7 = %0
! 108: chan.cr5 &= 0x61;
! 109: chan.tx_enable = false;
! 110:
! 111: // SR0 b0,1 = %0、b2,6 = %1
! 112: chan.rxlen = 0;
! 113: chan.intpend = 0;
! 114: chan.txlen = 0;
! 115: chan.tx_underrun = true;
! 116:
! 117: // SR1 b4-7 = %0
! 118: chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
! 119: MPSCC::SR1_FRAMEERROR |
! 120: MPSCC::SR1_RXOVERRUN |
! 121: MPSCC::SR1_PARITYERROR);
! 122:
! 123: ResetChannelCommon(chan);
1.1 root 124: }
125:
126: uint64
1.1.1.6 root 127: SIODevice::Read(uint32 offset)
1.1 root 128: {
1.1.1.9 ! root 129: uint64 data;
1.1 root 130:
1.1.1.6 root 131: switch (offset) {
1.1 root 132: case 0:
1.1.1.9 ! root 133: data = ReadData(mpscc.chan[0]);
1.1 root 134: break;
135: case 1:
1.1.1.9 ! root 136: data = ReadCtrl(mpscc.chan[0]);
1.1 root 137: break;
138: case 2:
1.1.1.9 ! root 139: data = ReadData(mpscc.chan[1]);
1.1 root 140: break;
141: case 3:
1.1.1.9 ! root 142: data = ReadCtrl(mpscc.chan[1]);
1.1 root 143: break;
144: default:
145: __unreachable();
146: }
147: return data;
148: }
149:
150: uint64
1.1.1.6 root 151: SIODevice::Write(uint32 offset, uint32 data)
1.1 root 152: {
1.1.1.6 root 153: switch (offset) {
1.1 root 154: case 0:
1.1.1.9 ! root 155: WriteData(mpscc.chan[0], data);
! 156: break;
1.1 root 157: case 1:
1.1.1.9 ! root 158: WriteCtrl(mpscc.chan[0], data);
! 159: break;
1.1 root 160: case 2:
1.1.1.9 ! root 161: WriteData(mpscc.chan[1], data);
! 162: break;
1.1 root 163: case 3:
1.1.1.9 ! root 164: WriteCtrl(mpscc.chan[1], data);
! 165: break;
! 166: default:
! 167: __unreachable();
1.1 root 168: }
1.1.1.9 ! root 169: return 0;
1.1 root 170: }
171:
172: uint64
1.1.1.6 root 173: SIODevice::Peek(uint32 offset)
1.1 root 174: {
1.1.1.9 ! root 175: uint64 data;
! 176:
1.1.1.6 root 177: switch (offset) {
1.1.1.3 root 178: case 0:
1.1.1.9 ! root 179: data = PeekData(mpscc.chan[0]);
! 180: break;
1.1.1.3 root 181: case 1:
1.1.1.9 ! root 182: data = PeekCtrl(mpscc.chan[0]);
! 183: break;
! 184: case 2:
! 185: data = PeekData(mpscc.chan[1]);
! 186: break;
! 187: case 3:
! 188: data = PeekCtrl(mpscc.chan[1]);
! 189: break;
! 190: default:
! 191: __unreachable();
! 192: }
! 193: return data;
! 194: }
! 195:
! 196: // 書き込みレジスタ名を返す
! 197: const char *
! 198: SIODevice::CRName(const MPSCCChan& chan, int ptr_) const
! 199: {
! 200: assert(ptr_ < 8);
! 201: int idx = ptr_ * 2 + chan.id;
! 202: assert(idx < countof(crnames));
! 203: return crnames[idx];
! 204: }
! 205:
! 206: // 読み込みレジスタ名を返す
! 207: const char *
! 208: SIODevice::SRName(const MPSCCChan& chan, int ptr_) const
! 209: {
! 210: assert(ptr_ < 8);
! 211: int idx = ptr_ * 2 + chan.id;
! 212: assert(idx < countof(srnames));
! 213: return srnames[idx];
! 214: }
! 215:
! 216: // 制御ポートの読み込み
! 217: uint8
! 218: SIODevice::ReadCtrl(MPSCCChan& chan)
! 219: {
! 220: uint8 data;
! 221:
! 222: switch (chan.ptr) {
! 223: case 0: // SR0
! 224: data = GetSR0(chan);
! 225: break;
! 226:
! 227: case 1: // SR1
! 228: data = chan.sr1;
! 229: break;
1.1.1.3 root 230:
231: case 2:
1.1.1.9 ! root 232: // SR2B はベクタの読み出し
! 233: if (chan.id == 1) {
! 234: data = GetSR2B();
! 235: break;
! 236: }
! 237:
! 238: // SR2A はない
! 239: // XXX どうなる?
! 240: FALLTHROUGH;
! 241:
! 242: default:
! 243: // XXX どうなる?
! 244: putlog(0, "%s 未実装レジスタ読み込み", SRName(chan));
! 245: // SR0 へ戻る?
! 246: chan.ptr = 0;
! 247: return 0xff;
! 248: }
! 249:
! 250: // PROM が SR0 を高速でポーリングするのでログを細工する。
! 251: //
! 252: // SR0 SRn
! 253: // loglevel<=1 非表示 非表示
! 254: // loglevel 2 * 常に表示
! 255: // loglevel 3 常に表示 常に表示
! 256: //
! 257: // *: 同じ値の読み込みログが連続したら省略。
! 258: if (__predict_true(loglevel <= 1)) {
! 259: // nop
! 260: } else if (__predict_false(loglevel >= 3 || chan.ptr > 0)) {
! 261: putlog(2, "%s -> $%02x", SRName(chan), data);
! 262: } else {
! 263: // ここは loglevel==2 && SR0
! 264:
! 265: switch (sr0_logphase) {
! 266: case 0: // 表示する
! 267: first:
! 268: sr0_logphase = 1;
! 269: sr0_lastread = data;
! 270: disp:
! 271: putlogn("%s -> $%02x", SRName(chan, 0), data);
! 272: break;
! 273: case 1: // 連続(1回目)
! 274: if (__predict_true(data == sr0_lastread)) {
! 275: sr0_logphase++;
! 276: goto disp;
! 277: } else {
! 278: goto first;
! 279: }
! 280: break;
! 281: case 2: // 連続(2回目)
! 282: if (__predict_true(data == sr0_lastread)) {
! 283: sr0_logphase++;
! 284: putlogn("%s -> $%02x (omit the following)",
! 285: SRName(chan, 0), data);
! 286: } else {
! 287: goto first;
! 288: }
! 289: break;
! 290: default: // 連続(3回目以降)
! 291: if (__predict_true(data == sr0_lastread)) {
! 292: // 連続したので表示省略
! 293: } else {
! 294: goto first;
! 295: }
! 296: break;
! 297: }
! 298: }
! 299: // アクセス後は SR0 へ戻す
! 300: chan.ptr = 0;
! 301:
! 302: return data;
! 303: }
! 304:
! 305: // 制御ポートの書き込み
! 306: void
! 307: SIODevice::WriteCtrl(MPSCCChan& chan, uint32 data)
! 308: {
! 309: // CR0 はコマンドかまたは次にアクセスするレジスタを指定する。
! 310: // CR0 以外のレジスタをアクセスすると、次のアクセスは CR0 に戻る。
! 311:
! 312: if (chan.ptr == 0) {
! 313: WriteCR0(chan, data);
! 314: } else {
! 315: switch (chan.ptr) {
! 316: case 1:
! 317: WriteCR1(chan, data);
! 318: break;
! 319: case 2:
! 320: WriteCR2(chan, data);
! 321: break;
! 322: case 3:
! 323: WriteCR3(chan, data);
! 324: break;
! 325: case 4:
! 326: WriteCR4(chan, data);
! 327: break;
! 328: case 5:
! 329: WriteCR5(chan, data);
! 330: break;
! 331: case 6:
! 332: WriteCR6(chan, data);
! 333: break;
! 334: case 7:
! 335: WriteCR7(chan, data);
! 336: break;
! 337: default:
! 338: __unreachable();
! 339: }
! 340: // アクセス後は CR0 へ戻す
! 341: chan.ptr = 0;
! 342: }
! 343: }
! 344:
! 345: // 制御ポートの Peek
! 346: uint8
! 347: SIODevice::PeekCtrl(const MPSCCChan& chan) const
! 348: {
! 349: switch (chan.ptr) {
! 350: case 0: // SR0
! 351: return GetSR0(chan);
! 352:
! 353: case 1: // SR1
! 354: return chan.sr1;
! 355:
! 356: case 2: // SR2
! 357: // SR2A はない。SR2B は割り込み要因込みのベクタ番号。
! 358: if (chan.id == 1) {
! 359: return GetSR2B();
! 360: }
! 361: FALLTHROUGH;
! 362:
! 363: default:
! 364: // 未調査
! 365: return 0xff;
! 366: }
! 367: }
! 368:
! 369: // CR1 レジスタの内容を取得
! 370: uint8
! 371: SIODevice::GetCR1(const MPSCCChan& chan) const
! 372: {
! 373: uint8 data = 0;
! 374:
! 375: if (chan.wait_enable)
! 376: data |= MPSCC::CR1_WAIT_EN;
! 377: if (chan.wait_on_rx)
! 378: data |= MPSCC::CR1_WAIT_RX;
! 379: // 内部フォーマットから元のビットを求める
! 380: switch (chan.rxint_mode) {
! 381: case MPSCCChan::RXINT_DISABLE:
! 382: break;
! 383: case MPSCCChan::RXINT_1STCHAR:
! 384: data |= MPSCC::CR1_RXINT_1STCHAR;
! 385: break;
! 386: case MPSCCChan::RXINT_ALLCHAR:
! 387: if (chan.sp_parity) {
! 388: data |= MPSCC::CR1_RXINT_ALLCHAR;
! 389: } else {
! 390: data |= MPSCC::CR1_RXINT_ALL_BUT_PE;
! 391: }
! 392: break;
! 393: default:
! 394: assert(false);
! 395: }
! 396: if (chan.txint_enable)
! 397: data |= MPSCC::CR1_TXINT_EN;
! 398: if (chan.esint_enable)
! 399: data |= MPSCC::CR1_ESINT_EN;
! 400:
! 401: return data;
! 402: }
! 403:
! 404: // CR2A レジスタの内容を取得
! 405: uint8
! 406: SIODevice::GetCR2A() const
! 407: {
! 408: uint8 data = 0;
! 409:
! 410: data |= mpscc.syncb ? MPSCC::CR2_SYNCB : 0;
! 411: data |= mpscc.vectored_mode ? MPSCC::CR2_VM : 0;
! 412: data |= mpscc.int_mode << 3;
! 413: data |= mpscc.priority_select ? MPSCC::CR2_PRIOSEL : 0;
! 414: data |= mpscc.intdma_mode;
! 415:
! 416: return data;
! 417: }
! 418:
! 419: // CR2B レジスタの内容を取得
! 420: inline uint8
! 421: SIODevice::GetCR2B() const
! 422: {
! 423: return mpscc.vector;
! 424: }
1.1.1.3 root 425:
1.1.1.9 ! root 426: // SR0 レジスタの内容を取得
! 427: uint8
! 428: SIODevice::GetSR0(const MPSCCChan& chan) const
! 429: {
! 430: uint8 data = 0;
! 431:
! 432: if (chan.break_detected)data |= MPSCC::SR0_BREAK;
! 433: if (chan.tx_underrun) data |= MPSCC::SR0_TXUNDER;
! 434: if (chan.nCTS) data |= MPSCC::SR0_nCTS;
! 435: if (chan.nSYNC) data |= MPSCC::SR0_nSYNC;
! 436: if (chan.nDCD) data |= MPSCC::SR0_nDCD;
! 437: if (chan.txlen == 0) data |= MPSCC::SR0_TXEMPTY;
! 438: if (chan.intpend != 0) data |= MPSCC::SR0_INTPEND;
! 439: if (chan.rxlen != 0) data |= MPSCC::SR0_RXAVAIL;
! 440:
! 441: return data;
! 442: }
! 443:
! 444: // CR0 への書き込み
! 445: void
! 446: SIODevice::WriteCR0(MPSCCChan& chan, uint32 data)
! 447: {
! 448: // XXX b7,b6 は未対応。
! 449: // b5,b4,b3 がコマンド。
! 450: // b2,b1,b0 が次にアクセスするレジスタ(chan->ptr)の切り替え。
! 451: chan.crc_cmd = (data & MPSCC::CR0_CRC) >> 6;
! 452: chan.cmd = (data & MPSCC::CR0_CMD) >> 3;
! 453: chan.ptr = data & MPSCC::CR0_PTR;
! 454:
! 455: if (chan.crc_cmd != 0) {
! 456: putlog(0, "%s crc_cmd %d 未実装", CRName(chan, 0), chan.crc_cmd);
! 457: }
! 458:
! 459: if (chan.cmd == 0) {
! 460: // コマンド0 ならレジスタ切り替え
! 461: putlog(3, "%s <- $%02x (ptr=%d)", CRName(chan, 0), data, chan.ptr);
! 462: } else {
! 463: // 0 以外ならコマンド発行
! 464: putlog(2, "%s <- $%02x", CRName(chan, 0), data);
! 465: }
! 466: switch (chan.cmd) {
! 467: case 0: // No operation
! 468: break;
! 469: case 1: // Send Abort
! 470: SendAbort(chan);
! 471: break;
! 472: case 2: // Reset External/Status Interrupt
! 473: ResetESIntr(chan);
! 474: break;
! 475: case 3: // Channel Reset
! 476: putlog(1, "Channel %c Reset", chan.name);
! 477: ResetChannel(chan);
! 478: break;
! 479: case 4: // Enable Interrupt On Next Rx Character
! 480: EnableIntrOnNextRx(chan);
! 481: break;
! 482: case 5: // Reset Transmitter Interrupt/DMA Pending
! 483: ResetTxIntrPending(chan);
! 484: break;
! 485: case 6: // Error Reset
! 486: ErrorReset(chan);
! 487: break;
! 488: case 7: // End of Interrupt
! 489: // uPD7201 ではチャンネル A のみ有効。
! 490: // (チャンネル B でどうなるかは書いてない)
! 491: if (chan.id == 0) {
! 492: ResetHighestIUS(chan);
! 493: } else {
! 494: putlog(0, "%s: Command 'End of Interrupt' 未定義", CRName(chan, 0));
! 495: }
! 496: break;
! 497: default:
! 498: __unreachable();
! 499: }
! 500: }
! 501:
! 502: // CR1 への書き込み
! 503: void
! 504: SIODevice::WriteCR1(MPSCCChan& chan, uint32 data)
! 505: {
! 506: putlog(2, "%s <- $%02x", CRName(chan), data);
! 507:
! 508: chan.wait_enable = (data & MPSCC::CR1_WAIT_EN);
! 509: chan.wait_on_rx = (data & MPSCC::CR1_WAIT_RX);
! 510: // RXINT は内部フォーマットで覚えておく。
! 511: // all_or_first の初期値もここでセット。
! 512: // o RXINT_DISABLE なら (使わないけど一応) false にしとく。
! 513: // o RXINT_1STCHAR なら初期状態が true。
! 514: // o RXINT_ALLCHAR なら常時 true。
! 515: switch ((data >> 3) & 3) {
! 516: case 0:
! 517: chan.rxint_mode = MPSCCChan::RXINT_DISABLE;
! 518: chan.all_or_first = false;
! 519: break;
! 520: case 1:
! 521: chan.rxint_mode = MPSCCChan::RXINT_1STCHAR;
! 522: chan.sp_parity = false;
! 523: chan.all_or_first = true;
! 524: break;
! 525: case 2:
! 526: chan.rxint_mode = MPSCCChan::RXINT_ALLCHAR;
! 527: chan.sp_parity = false;
! 528: chan.all_or_first = true;
! 529: break;
1.1.1.3 root 530: case 3:
1.1.1.9 ! root 531: chan.rxint_mode = MPSCCChan::RXINT_ALLCHAR;
! 532: chan.sp_parity = true;
! 533: chan.all_or_first = true;
! 534: default:
! 535: __unreachable();
1.1.1.3 root 536: }
1.1.1.9 ! root 537:
! 538: if (chan.id == 0) {
! 539: mpscc.sav_vis = (data & MPSCC::CR1_SAV);
! 540: // sav を変更したので vis モードを更新
! 541: SetVIS();
! 542: }
! 543:
! 544: chan.txint_enable = (data & MPSCC::CR1_TXINT_EN);
! 545: chan.esint_enable = (data & MPSCC::CR1_ESINT_EN);
1.1 root 546: }
547:
1.1.1.9 ! root 548: // CR2 への書き込み
1.1 root 549: void
1.1.1.9 ! root 550: SIODevice::WriteCR2(MPSCCChan& chan, uint32 data)
1.1 root 551: {
1.1.1.9 ! root 552: if (chan.id == 0) { // CR2A
! 553: putlog(2, "%s <- $%02x", CRName(chan), data);
! 554: mpscc.syncb = (data & MPSCC::CR2_SYNCB);
! 555: mpscc.vectored_mode = (data & MPSCC::CR2_VM);
! 556: mpscc.int_mode = (data & MPSCC::CR2_INT);
! 557: mpscc.priority_select = (data & MPSCC::CR2_PRIOSEL);
! 558: mpscc.intdma_mode = (data & MPSCC::CR2_INTDMA);
! 559: // int_mode を変更したので vis モードを更新
! 560: SetVIS();
! 561: } else { // CR2B
! 562: putlog(2, "%s <- $%02x (Set vector)", CRName(chan), data);
! 563: mpscc.vector = data;
! 564: }
! 565: }
! 566:
! 567: // CR1 の SAV と CR2 の INT_MODE に従って VIS を更新
! 568: void
! 569: SIODevice::SetVIS()
! 570: {
! 571: if (mpscc.sav_vis) {
! 572: if (mpscc.int_mode == MPSCC::INTMODE_86) {
! 573: mpscc.vis = MPSCC::VIS_210;
! 574: } else {
! 575: mpscc.vis = MPSCC::VIS_432;
! 576: }
! 577: } else {
! 578: mpscc.vis = MPSCC::VIS_FIXED;
! 579: }
! 580: }
! 581:
! 582: // モニター
! 583: void
! 584: SIODevice::MonitorUpdate(Monitor *, TextScreen& screen)
! 585: {
! 586: uint cr2a;
! 587: uint cr2b;
! 588: uint sr2b;
! 589: int y;
! 590:
! 591: cr2a = GetCR2A();
! 592: cr2b = mpscc.vector;
! 593: sr2b = GetSR2B();
! 594:
! 595: screen.Clear();
! 596: for (int i = 0; i < 2; i++) {
! 597: int x = 0;
! 598: y = i * 10;
! 599: MonitorUpdateCh(screen, i, x, y);
! 600: }
! 601:
! 602: // CR2A
! 603: y = 20;
! 604: screen.Print(0, y, "CR2A:$%02x", cr2a);
! 605: if ((cr2a & MPSCC::CR2_SYNCB)) {
! 606: screen.Print(9, y, TA::On, "SYNC");
! 607: } else {
! 608: screen.Print(9, y, "RTSB");
! 609: }
! 610: screen.Print(14, y, TA::Disable, "----");
! 611: screen.Print(19, y, TA::OnOff((cr2a & MPSCC::CR2_VM)), "Vect");
! 612: if ((cr2a & MPSCC::CR2_INT) == 0x10) {
! 613: screen.Print(24, y, "IM=V4-V2");
! 614: } else {
! 615: screen.Print(24, y, "IM=V2-V0");
! 616: }
! 617: screen.Print(34, y, TA::OnOff((cr2a & MPSCC::CR2_PRIOSEL)), "PRIO");
! 618: // bit1,0 はよく分からん
! 619: screen.Print(39, y, "INT/DMA=%d", (cr2a & MPSCC::CR2_INTDMA));
! 620: y++;
! 621:
! 622: // CR2B
! 623: screen.Print(0, y, "CR2B:$%02x / SR2B:$%02x", cr2b, sr2b);
! 624: }
! 625:
! 626: // モニター (1チャンネル)
! 627: void
! 628: SIODevice::MonitorUpdateCh(TextScreen& screen, int ch, int xbase, int ybase)
! 629: {
! 630: const MPSCCChan& chan = mpscc.chan[ch];
! 631: uint cr0;
! 632: uint cr1;
! 633: uint cr3;
! 634: uint cr4;
! 635: uint cr5;
! 636: uint sr0;
! 637: uint sr1;
! 638: uint rxlen;
! 639: int x;
! 640: int y;
! 641:
! 642: cr0 = GetCR0(chan);
! 643: cr1 = GetCR1(chan);
! 644: cr3 = GetCR3(chan);
! 645: cr4 = chan.cr4;
! 646: cr5 = GetCR5(chan);
! 647: sr0 = GetSR0(chan);
! 648: sr1 = chan.sr1;
! 649: rxlen = chan.rxlen;
! 650:
! 651: // 0 1 2 3 4 5 6
! 652: // 0123456789012345678901234567890123456789012345678901234567890123456789
! 653: // 0123 0123 0123 0123 0123 0123 0123 0123
! 654: // Channel A: Serial Console DataAddr $00000000
! 655: // CR0: $xx CRC=x CMD=x PTR=x CtrlAddr $00000000
! 656: // CR1: $xx WE 0 WR RXInt=x 0 TXEn ESEn
! 657: // RXBuf: 0 --- --- --- Intr: SP Rx ES Tx
! 658:
! 659: x = xbase;
! 660: y = ybase;
! 661: screen.Print(x, y++, "Channel %c: %s", chan.name, chan.desc);
! 662: screen.Print(x, y++, "CR0: $%02x", cr0);
! 663: screen.Print(x, y++, "CR1: $%02x", cr1);
! 664: screen.Print(x, y++, "CR3: $%02x", cr3);
! 665: screen.Print(x, y++, "CR4: $%02x", cr4);
! 666: screen.Print(x, y++, "CR5: $%02x", cr5);
! 667: screen.Print(x, y++, "SR0: $%02x", sr0);
! 668: screen.Print(x, y++, "SR1: $%02x", sr1);
! 669: screen.Print(x, y, "RXbuf: %d", rxlen);
! 670: int i;
! 671: for (i = 0; i < rxlen; i++) {
! 672: screen.Print(x + 9 + i * 4, y, "$%02x", chan.rxbuf[i]);
! 673: }
! 674: for (; i < sizeof(chan.rxbuf); i++) {
! 675: screen.Print(x + 9 + i * 4, y, "---");
! 676: }
! 677: // 内部割り込み状態
! 678: screen.Print(x + 31, y, "Intr:");
! 679: screen.Print(x + 37, y, TA::OnOff(chan.intpend & INTPEND_SP), "SP");
! 680: screen.Print(x + 40, y, TA::OnOff(chan.intpend & INTPEND_RX), "Rx");
! 681: screen.Print(x + 43, y, TA::OnOff(chan.intpend & INTPEND_ES), "ES");
! 682: screen.Print(x + 46, y, TA::OnOff(chan.intpend & INTPEND_TX), "Tx");
! 683:
! 684: y = ybase + 1;
! 685: x = xbase;
! 686: // CR0
! 687: screen.Print(x + 9, y, "CRC=%d", (cr0 >> 6));
! 688: static const char * const cmd_str[] = {
! 689: // 0123456789012345
! 690: "No operation",
! 691: "Send Abort",
! 692: "Reset E/S Int",
! 693: "Channel Reset",
! 694: "Enable IntNextCh",
! 695: "Reset TxIntPend",
! 696: "Error Reset",
! 697: "End of Interrupt",
! 698: };
! 699: uint cmd = (cr0 >> 3) & 7;
! 700: screen.Print(x + 19, y, "CMD=%d(%s)", cmd, cmd_str[cmd]);
! 701: screen.Print(x + 43, y, "PTR=%d", (cr0 & 7));
! 702: y++;
! 703:
! 704: // CR1
! 705: static const char * const cr1_str[] = {
! 706: "Wait", "-", "OnRx", "", "", "SAV", "TxIE", "ESIE"
! 707: };
! 708: MonitorReg(screen, x + 9, y, cr1, cr1_str);
! 709: // XXX All Char 割り込みのうちパリティエラーの扱いは表示省略。
! 710: // パリティエラーの扱いが必要になったら考える。
! 711: static const char * const rxint_str[] = {
! 712: // 012345678
! 713: "RxInt=Dis",
! 714: "RI=1stChr",
! 715: "RI=AllChr", // Parity Error を Special Condition に含む
! 716: "RI=AllChr", // Parity Error を Special Condition に含まない
! 717: };
! 718: screen.Puts(x + 24, y, rxint_str[(cr1 >> 3) & 3]);
! 719: // CR1 の bit2 (Modified Vector) は CR1B のみ。
! 720: if (ch == 0) {
! 721: screen.Puts(x + 34, y, TA::Disable, "----");
! 722: }
! 723: y++;
! 724:
! 725: // CR3,CR4,CR5
! 726: y = MonitorUpdateCR345(screen, x, y, cr3, cr4, cr5);
! 727:
! 728: // SR0
! 729: static const char * const sr0_str[] = {
! 730: "BrAb", "TxUn", "!CTS", "!SYN", "!DCD", "TxEm", "IntP", "RxAv"
! 731: };
! 732: MonitorReg(screen, x + 9, y, sr0, sr0_str);
! 733: // SR0 の bit1 (Interrupt Pending) は SR0A のみ。SR0B では 0。
! 734: if (ch == 1) {
! 735: screen.Print(39, y, TA::Disable, "----");
! 736: }
! 737: y++;
! 738:
! 739: // SR1
! 740: MonitorUpdateSR1(screen, x, y, sr1);
! 741: y++;
! 742:
! 743: // 右列
! 744: y = ybase;
! 745: x = xbase + 51;
! 746: screen.Print(x, y++, "DataAddr $%08x", chan.dataaddr);
! 747: screen.Print(x, y++, "CtrlAddr $%08x", chan.ctrladdr);
! 748: y++;
! 749: screen.Print(x, y++, "Param %12s", GetParamStr(chan).c_str());
! 750: screen.Print(x, y++, "Rx Bits/Frame %2d", chan.rxbits);
! 751: screen.Print(x, y++, "Tx Bits/Frame %2d", chan.txbits);
! 752: }
! 753:
! 754: // ペンディングのうち最も優先度の高い割り込み要因を返す
! 755: uint
! 756: SIODevice::GetHighestInt() const
! 757: {
! 758: // 優先度は CR2A b2 (priority_select) で決まるが、
! 759: // Int/DMA が %01 なら priority_select によらず 0 と同じほうになるという
! 760: // ことのようだ。
! 761: //
! 762: // CR2 b210 High -> Low
! 763: // uPD7201 0 0 0 RxA TxA RxB TxB ESA ESB
! 764: // uPD7201 x 0 1 RxA TxA RxB TxB ESA ESB
! 765: // uPD7201 0 1 0 RxA TxA RxB TxB ESA ESB
! 766: //
! 767: // uPD7201 1 0 0 RxA RxB TxA TxB ESA ESB
! 768: // uPD7201 1 1 0 RxA RxB TxA TxB ESA ESB
! 769:
! 770: if (mpscc.intdma_mode == 1 || mpscc.priority_select == false) {
! 771: if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
! 772: if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
! 773: if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
! 774: if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
! 775: if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
! 776: if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
! 777: if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
! 778: if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
! 779:
! 780: } else {
! 781: if ((mpscc.chan[0].intpend & INTPEND_SP)) return MPSCC::VS_SPA;
! 782: if ((mpscc.chan[0].intpend & INTPEND_RX)) return MPSCC::VS_RxA;
! 783: if ((mpscc.chan[1].intpend & INTPEND_SP)) return MPSCC::VS_SPB;
! 784: if ((mpscc.chan[1].intpend & INTPEND_RX)) return MPSCC::VS_RxB;
! 785: if ((mpscc.chan[0].intpend & INTPEND_TX)) return MPSCC::VS_TxA;
! 786: if ((mpscc.chan[1].intpend & INTPEND_TX)) return MPSCC::VS_TxB;
! 787: if ((mpscc.chan[0].intpend & INTPEND_ES)) return MPSCC::VS_ESA;
! 788: if ((mpscc.chan[1].intpend & INTPEND_ES)) return MPSCC::VS_ESB;
! 789: }
! 790:
! 791: return MPSCC::VS_none;
1.1 root 792: }
1.1.1.8 root 793:
794: void
795: SIODevice::Tx(int ch, uint32 data)
796: {
797: switch (ch) {
798: case 0:
1.1.1.9 ! root 799: hostcom->Tx(data);
1.1.1.8 root 800: break;
801: case 1:
802: gKeyboard->Command(data);
803: break;
804: default:
805: __unreachable();
806: }
807: }
1.1.1.9 ! root 808:
! 809: // ログ表示用のレジスタ名
! 810: /*static*/ const char * const
! 811: SIODevice::crnames[16] = {
! 812: "CR0A", "CR0B",
! 813: "CR1A", "CR1B",
! 814: "CR2A", "CR2B",
! 815: "CR3A", "CR3B",
! 816: "CR4A", "CR4B",
! 817: "CR5A", "CR5B",
! 818: "CR6A", "CR6B",
! 819: "CR7A", "CR7B",
! 820: };
! 821: /*static*/ const char * const
! 822: SIODevice::srnames[16] = {
! 823: "SR0A", "SR0B",
! 824: "SR1A", "SR1B",
! 825: "SR2A?", "SR2B",
! 826: "SR3A?", "SR3B?",
! 827: "SR4A?", "SR4B?",
! 828: "SR5A?", "SR5B?",
! 829: "SR6A?", "SR6B?",
! 830: "SR7A?", "SR7B?",
! 831: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.