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