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