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