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