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