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