|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // uPD7201(MPSC) と Z8530(SCC) の共通部分 (シリアルポート1個つき)
9: //
10:
11: // IODevice
12: // |
13: // | +-------------+
14: // +--| MPSCCDevice | (uPD7201 と Z8530 の共通部分)
15: // +-------------+
16: // |
17: // +-- SCCDevice (X68030、Z8530)
18: // +-- SIODevice (LUNA、uPD7201)
19:
20: #define MPSCC_SIO_LOG_HACK
21: #include "mpscc.h"
22: #include "bitops.h"
23: #include "hostcom.h"
24: #include "interrupt.h"
1.1.1.7 root 25: #include "monitor.h"
1.1 root 26: #include "scheduler.h"
1.1.1.3 root 27: #include "syncer.h"
1.1.1.2 root 28: #include <cmath>
1.1 root 29:
30: //
31: // MPSCC チャンネル
32: //
33:
34: // コンストラクタ
35: MPSCCChan::MPSCCChan()
36: {
1.1.1.2 root 37: // これらのレジスタの値の初期値は実際は不定だがそれは実際難しいのと
38: // 有効範囲内の値にしておく必要があるので、適当に初期値を固定しておく。
39: rxbits = 5;
40: txbits = 5;
41: clkrate = 1;
1.1 root 42: }
43:
44: // デストラクタ
45: MPSCCChan::~MPSCCChan()
46: {
47: }
48:
49: // 初期化
50: void
51: MPSCCChan::Init(int id_)
52: {
53: id = id_;
54: name = 'A' + id;
55: }
56:
57:
58: //
59: // MPSCC デバイス
60: //
61:
62: // コンストラクタ
1.1.1.3 root 63: MPSCCDevice::MPSCCDevice()
64: : inherited(OBJ_MPSCC)
1.1 root 65: {
66: for (int ch = 0; ch < mpscc.chan.size(); ch++) {
67: auto& chan = mpscc.chan[ch];
68: chan.Init(ch);
69: }
70:
71: // モニタは継承先で設定する
72: }
73:
74: // デストラクタ
75: MPSCCDevice::~MPSCCDevice()
76: {
77: if ((bool)hostcom) {
1.1.1.4 root 78: hostcom->SetRxCallback(NULL);
1.1 root 79: }
80: }
81:
82: bool
83: MPSCCDevice::Create()
84: {
85: // 対応するホストドライバを作成
1.1.1.9 ! root 86: try {
! 87: hostcom.reset(new HostCOMDevice(this, "HostCOM"));
! 88: } catch (...) { }
1.1.1.4 root 89: if ((bool)hostcom == false) {
1.1.1.9 ! root 90: warnx("Failed to initialize HostCOMDevice at %s", __method__);
1.1 root 91: return false;
92: }
93: hostcom->SetRxCallback(ToDeviceCallback(&MPSCCDevice::HostRxCallback));
94:
95: return true;
96: }
97:
98: void
99: MPSCCDevice::SetLogLevel(int loglevel_)
100: {
101: inherited::SetLogLevel(loglevel_);
102:
1.1.1.9 ! root 103: if ((bool)hostcom) {
! 104: hostcom->SetLogLevel(loglevel_);
! 105: }
1.1 root 106: }
107:
108: // 初期化
109: bool
110: MPSCCDevice::Init()
111: {
1.1.1.3 root 112: interrupt = GetInterruptDevice();
113:
114: scheduler->ConnectMessage(MessageID::HOSTCOM_RX, this,
1.1.1.5 root 115: ToMessageCallback(&MPSCCDevice::RxMessage));
1.1.1.6 root 116:
117: for (int ch = 0; ch < mpscc.chan.size(); ch++) {
118: // time は SetTxPeriod() でセット。
119: // 名前は継承先でセットする。機種ごとに名前を使い分けているため。
120: txevent[ch].dev = this;
121: txevent[ch].func = ToEventCallback(&MPSCCDevice::TxCallback);
122: txevent[ch].code = ch;
123: scheduler->RegistEvent(txevent[ch]);
124:
125: rxevent[ch].dev = this;
126: rxevent[ch].func = ToEventCallback(&MPSCCDevice::RxCallback);
127: rxevent[ch].code = ch;
128: scheduler->RegistEvent(rxevent[ch]);
129: }
130:
1.1 root 131: return true;
132: }
133:
134: // チャンネルリセットの共通部
135: void
136: MPSCCDevice::ResetChannelCommon(MPSCCChan& chan)
137: {
138: // 通信速度を反映する
1.1.1.2 root 139: ChangeBaudrate(chan);
1.1 root 140: SetTxPeriod(chan);
141: SetRxPeriod(chan);
142:
1.1.1.2 root 143: // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
144: chan.old_cr3 = GetCR3(chan);
145: chan.old_cr4 = GetCR4(chan);
146: chan.old_cr5 = GetCR5(chan);
147:
1.1 root 148: // リセットで送信バッファは空になるが、リセット直後に
149: // Tx 割り込みを許可しても Tx 割り込みは起こさない。
150: chan.txint_ready = false;
151:
152: // 割り込みをネゲートするため
153: ChangeInterrupt();
154: }
155:
1.1.1.6 root 156: bool
157: MPSCCDevice::PokePort(uint32 offset, uint32 data)
158: {
159: return false;
160: }
161:
1.1 root 162: // CR0/WR0 レジスタの内容を取得
163: // (値の取り出しだけなら共通)
1.1.1.2 root 164: /*static*/ uint8
165: MPSCCDevice::GetCR0(const MPSCCChan& chan)
1.1 root 166: {
167: uint8 data = (chan.crc_cmd << 6) | (chan.cmd << 3) | chan.ptr;
168: return data;
169: }
170:
1.1.1.2 root 171: // CR3/WR3 レジスタを設定
172: /*static*/ void
173: MPSCCDevice::SetCR3(MPSCCChan& chan, uint32 data)
174: {
1.1.1.3 root 175: uint cr3_rxbits = data & MPSCC::CR3_RXBITS;
176: switch (cr3_rxbits) {
1.1.1.2 root 177: case MPSCC::RXBITS_5:
178: chan.rxbits = 5;
179: break;
180: case MPSCC::RXBITS_6:
181: chan.rxbits = 6;
182: break;
183: case MPSCC::RXBITS_7:
184: chan.rxbits = 7;
185: break;
186: case MPSCC::RXBITS_8:
187: chan.rxbits = 8;
188: break;
189: default:
1.1.1.3 root 190: VMPANIC("corrupted cr3_rxbits=$%x", cr3_rxbits);
1.1.1.2 root 191: }
192:
193: chan.auto_enable = (data & MPSCC::CR3_AUTO_EN);
194: chan.cr3_sync = (data & MPSCC::CR3_SYNC_MASK);
195: chan.rx_enable = (data & MPSCC::CR3_RX_EN);
196: }
197:
1.1 root 198: // CR3/WR3 レジスタの内容を取得
1.1.1.2 root 199: /*static*/ uint8
200: MPSCCDevice::GetCR3(const MPSCCChan& chan)
1.1 root 201: {
202: uint8 data;
203:
1.1.1.2 root 204: data = chan.cr3_sync;
205: switch (chan.rxbits) {
206: case 5:
207: data |= MPSCC::RXBITS_5;
208: break;
209: case 6:
210: data |= MPSCC::RXBITS_6;
211: break;
212: case 7:
213: data |= MPSCC::RXBITS_7;
214: break;
215: case 8:
216: data |= MPSCC::RXBITS_8;
217: break;
218: default:
1.1.1.6 root 219: VMPANIC("corrupted chan.rxbits=%u", chan.rxbits);
1.1.1.2 root 220: }
221: if (chan.auto_enable) {
222: data |= MPSCC::CR3_AUTO_EN;
223: }
224: if (chan.rx_enable) {
1.1 root 225: data |= MPSCC::CR3_RX_EN;
1.1.1.2 root 226: }
227: return data;
228: }
1.1 root 229:
1.1.1.2 root 230: // CR4/WR4 レジスタを設定
231: /*static*/void
232: MPSCCDevice::SetCR4(MPSCCChan& chan, uint32 data)
233: {
1.1.1.3 root 234: uint cr4_clkrate = data & MPSCC::CR4_CLKRATE;
235: switch (cr4_clkrate) {
1.1.1.2 root 236: case MPSCC::CLKRATE_1:
237: chan.clkrate = 1;
238: break;
239: case MPSCC::CLKRATE_16:
240: chan.clkrate = 16;
241: break;
242: case MPSCC::CLKRATE_32:
243: chan.clkrate = 32;
244: break;
245: case MPSCC::CLKRATE_64:
246: chan.clkrate = 64;
247: break;
248: default:
1.1.1.3 root 249: VMPANIC("corrupted cr4_clkrate=$%x", cr4_clkrate);
1.1.1.2 root 250: }
251: chan.syncmode = (data & MPSCC::CR4_SYNCMODE);
252: chan.stopbits = (data & MPSCC::CR4_STOPBITS) >> 2;
253: chan.parity_even = (data & MPSCC::CR4_PARITY_EVEN);
254: chan.parity_enable = (data & MPSCC::CR4_PARITY_EN) ? 1 : 0;
255: }
256:
257: // CR4/WR4 レジスタの内容を取得
258: /*static*/ uint8
259: MPSCCDevice::GetCR4(const MPSCCChan& chan)
260: {
261: uint8 data = 0;
262:
263: switch (chan.clkrate) {
264: case 1:
265: data |= MPSCC::CLKRATE_1;
266: break;
267: case 16:
268: data |= MPSCC::CLKRATE_16;
269: break;
270: case 32:
271: data |= MPSCC::CLKRATE_32;
272: break;
273: case 64:
274: data |= MPSCC::CLKRATE_64;
275: break;
276: default:
1.1.1.6 root 277: VMPANIC("corrupted chan.clkrate=%u", chan.clkrate);
1.1.1.2 root 278: }
279: data |= chan.syncmode;
280: data |= chan.stopbits << 2;
281: if (chan.parity_even) {
282: data |= MPSCC::CR4_PARITY_EVEN;
283: }
284: if (chan.parity_enable) {
285: data |= MPSCC::CR4_PARITY_EN;
286: }
1.1 root 287: return data;
288: }
289:
1.1.1.2 root 290: // CR5/WR5 レジスタを設定
291: /*static*/ void
292: MPSCCDevice::SetCR5(MPSCCChan& chan, uint32 data)
293: {
1.1.1.3 root 294: uint cr5_txbits = data & MPSCC::CR5_TXBITS;
295: switch (cr5_txbits) {
1.1.1.2 root 296: case MPSCC::TXBITS_5:
297: chan.txbits = 5;
298: break;
299: case MPSCC::TXBITS_6:
300: chan.txbits = 6;
301: break;
302: case MPSCC::TXBITS_7:
303: chan.txbits = 7;
304: break;
305: case MPSCC::TXBITS_8:
306: chan.txbits = 8;
307: break;
308: default:
1.1.1.3 root 309: VMPANIC("corrupted cr5_txbits=$%x", cr5_txbits);
1.1.1.2 root 310: }
311: chan.nDTR = (data & MPSCC::CR5_nDTR);
312: chan.sendbreak = (data & MPSCC::CR5_SENDBREAK);
313: chan.tx_enable = (data & MPSCC::CR5_TX_EN);
314: chan.crc16 = (data & MPSCC::CR5_CRC16);
315: chan.nRTS = (data & MPSCC::CR5_nRTS);
316: chan.txcrc_en = (data & MPSCC::CR5_TXCRC_EN);
317: }
318:
1.1 root 319: // CR5/WR5 レジスタの内容を取得
1.1.1.2 root 320: /*static*/ uint8
321: MPSCCDevice::GetCR5(const MPSCCChan& chan)
1.1 root 322: {
1.1.1.2 root 323: uint8 data = 0;
1.1 root 324:
1.1.1.2 root 325: switch (chan.txbits) {
326: case 5:
327: data |= MPSCC::TXBITS_5;
328: break;
329: case 6:
330: data |= MPSCC::TXBITS_6;
331: break;
332: case 7:
333: data |= MPSCC::TXBITS_7;
334: break;
335: case 8:
336: data |= MPSCC::TXBITS_8;
337: break;
338: default:
1.1.1.6 root 339: VMPANIC("corrupted chan.txbits=%u", chan.txbits);
1.1.1.2 root 340: }
341: if (chan.nDTR) {
342: data |= MPSCC::CR5_nDTR;
343: }
344: if (chan.sendbreak) {
345: data |= MPSCC::CR5_SENDBREAK;
346: }
347: if (chan.tx_enable) {
1.1 root 348: data |= MPSCC::CR5_TX_EN;
1.1.1.2 root 349: }
350: if (chan.crc16) {
351: data |= MPSCC::CR5_CRC16;
352: }
353: if (chan.nRTS) {
354: data |= MPSCC::CR5_nRTS;
355: }
356: if (chan.txcrc_en) {
357: data |= MPSCC::CR5_TXCRC_EN;
358: }
1.1 root 359: return data;
360: }
361:
362: // SR2B/RR2B レジスタの内容を取得
363: uint8
364: MPSCCDevice::GetSR2B() const
365: {
366: uint8 data = mpscc.vector;
367:
368: // 割り込み要因をベクタに載せない
369: if (mpscc.vis == MPSCC::VIS_FIXED) {
370: return data;
371: }
372:
373: uint stat = GetHighestInt();
374:
375: // 8種類 (3bit) の割り込み要因をベクタに載せる。
376: // 載せる場所 (と向き) はそれぞれ 2種類ずつある。
377: switch (mpscc.vis) {
378: case MPSCC::VIS_432: // uPD7201: INTMode = INT85
379: // 割り込み要求がない場合は %111
380: if (stat == MPSCC::VS_none)
381: stat = 7;
382: data &= ~0x1c;
383: data |= stat << 2;
384: break;
385:
386: case MPSCC::VIS_210: // uPD7201: INTMode = INT86
387: // 割り込み要求がない場合は %111
388: if (stat == MPSCC::VS_none)
389: stat = 7;
390: data &= ~0x07;
391: data |= stat;
392: break;
393:
394: case MPSCC::VIS_321: // Z8530: StatusHigh/StatusLow = %0
395: // 割り込み要求がない場合は %011
396: if (stat == MPSCC::VS_none)
397: stat = 3;
398: data &= ~0x0e;
399: data |= stat << 1;
400: break;
401:
402: case MPSCC::VIS_456: // Z8530: StatusHigh/StatusLow = %1
403: // 割り込み要求がない場合は %011
404: if (stat == MPSCC::VS_none)
405: stat = 3;
406: // VIS_321 とはビット順が逆
407: data &= ~0x70;
1.1.1.8 root 408: data |= bitrev8(stat << 1);
1.1 root 409: break;
410: default:
1.1.1.6 root 411: VMPANIC("corrupted mpscc.vis=%u", (uint)mpscc.vis);
1.1 root 412: }
413:
414: return data;
415: }
416:
417: // CR0/WR0 Send Abort コマンド
418: void
419: MPSCCDevice::SendAbort(MPSCCChan& chan)
420: {
1.1.1.2 root 421: putlog(0, "%s: Command 'Send Abort' (NOT IMPLEMENTED)", CRName(chan, 0));
1.1 root 422: }
423:
424: // CR0/WR0 Reset External/Status Interrupt コマンド
425: void
426: MPSCCDevice::ResetESIntr(MPSCCChan& chan)
427: {
428: putlog(3, "%s: Command 'Reset E/S Interrupt'", CRName(chan, 0));
429: chan.es_latched = false;
430: }
431:
432: // CR0/WR0 Enable Interrupt on Next Rx Character コマンド
433: void
434: MPSCCDevice::EnableIntrOnNextRx(MPSCCChan& chan)
435: {
436: putlog(1, "%s: Command 'Enable Intr on Next Rx Character'",
437: CRName(chan, 0));
438: chan.all_or_first = true;
439: }
440:
441: // CR0/WR0 Reset Tx Interrupt/DMA Pending コマンド
442: void
443: MPSCCDevice::ResetTxIntrPending(MPSCCChan& chan)
444: {
445: putlog(2, "%s: Command 'Reset Tx Intr/DMA Pending'", CRName(chan, 0));
446: chan.txint_ready = false;
447: ChangeInterrupt();
448: }
449:
450: // CR0/WR0 Error Reset コマンド
451: void
452: MPSCCDevice::ErrorReset(MPSCCChan& chan)
453: {
454: putlog(1, "%s: Command 'Error Reset'", CRName(chan, 0));
455: chan.sr1 &= ~(MPSCC::SR1_ENDOFFRAME |
456: MPSCC::SR1_FRAMEERROR |
457: MPSCC::SR1_RXOVERRUN |
458: MPSCC::SR1_PARITYERROR);
459: // XXX Special Rx Condition は未実装
460: }
461:
462: // CR0 End of Interrupt コマンド
463: // WR0 Reset Highest IUS コマンド
464: // たぶん名前が違うだけで同じ。後者のほうが分かりやすいのでこっちを使う
465: void
466: MPSCCDevice::ResetHighestIUS(MPSCCChan& chan)
467: {
468: putlog(2, "%s: Command 'Reset Highest IUS'", CRName(chan, 0));
469:
470: // ペンディングのうち最も高い割り込み要因をクリア
471: uint stat = GetHighestInt();
472: switch (stat) {
473: case MPSCC::VS_TxB:
474: mpscc.chan[1].intpend &= ~INTPEND_TX;
475: break;
476: case MPSCC::VS_ESB:
477: mpscc.chan[1].intpend &= ~INTPEND_ES;
478: break;
479: case MPSCC::VS_RxB:
480: mpscc.chan[1].intpend &= ~INTPEND_RX;
481: break;
482: case MPSCC::VS_SPB:
483: mpscc.chan[1].intpend &= ~INTPEND_SP;
484: break;
485:
486: case MPSCC::VS_TxA:
487: mpscc.chan[0].intpend &= ~INTPEND_TX;
488: break;
489: case MPSCC::VS_ESA:
490: mpscc.chan[0].intpend &= ~INTPEND_ES;
491: break;
492: case MPSCC::VS_RxA:
493: mpscc.chan[0].intpend &= ~INTPEND_RX;
494: break;
495: case MPSCC::VS_SPA:
496: mpscc.chan[0].intpend &= ~INTPEND_SP;
497: break;
498:
499: default:
500: break;
501: }
502: ChangeInterrupt();
503: }
504:
505: // CR3/WR3 への書き込み
506: void
507: MPSCCDevice::WriteCR3(MPSCCChan& chan, uint32 data)
508: {
1.1.1.2 root 509: SetCR3(chan, data);
1.1 root 510: putlog(2, "%s <- $%02x", CRName(chan), data);
511:
512: SetRxPeriod(chan);
1.1.1.2 root 513:
514: // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
515: chan.old_cr3 = GetCR3(chan);
1.1 root 516: }
517:
518: // CR4/WR4 への書き込み
519: void
520: MPSCCDevice::WriteCR4(MPSCCChan& chan, uint32 data)
521: {
1.1.1.2 root 522: SetCR4(chan, data);
1.1 root 523: putlog(2, "%s <- $%02x", CRName(chan), data);
524:
1.1.1.2 root 525: if (chan.stopbits == MPSCC::STOPBITS_SYNC) {
1.1 root 526: // 同期モードはサポートしない
527: putlog(2, "Channel %c Synchronous mode not supported", chan.name);
528: } else {
529: const char *sm[] = { "?", "1", "1.5", "2" };
1.1.1.6 root 530: putlog(2, "Channel %c Async Mode (x%u clock, stopbit %s)",
1.1 root 531: chan.name,
1.1.1.2 root 532: chan.clkrate,
533: sm[chan.stopbits]);
534: // なんとなく順序的に何倍と表示した後に速度を表示
535: ChangeBaudrate(chan);
1.1 root 536: }
537:
538: SetTxPeriod(chan);
539: SetRxPeriod(chan);
1.1.1.2 root 540:
541: // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
542: chan.old_cr4 = GetCR4(chan);
1.1 root 543: }
544:
545: // CR5/WR5 への書き込み
546: void
547: MPSCCDevice::WriteCR5(MPSCCChan& chan, uint32 data)
548: {
1.1.1.2 root 549: SetCR5(chan, data);
1.1 root 550: putlog(2, "%s <- $%02x", CRName(chan), data);
551:
552: SetTxPeriod(chan);
1.1.1.2 root 553: // Set(Tx|Rx)Period() 呼び出し後は old_cr[345] を更新。
554: chan.old_cr5 = GetCR5(chan);
555:
1.1 root 556: TrySend(chan);
557: }
558:
559: // CR6/WR6 への書き込み
560: void
561: MPSCCDevice::WriteCR6(MPSCCChan& chan, uint32 data)
562: {
563: chan.cr6 = data;
564:
1.1.1.2 root 565: // どのみちサポートしてないけど初期化のために 0x00 を書き込むようなので
566: // それ以外ならログを出す。
567: if (data != 0) {
568: putlog(0, "Write %s <- $%02x (NOT IMPLEMENTED)", CRName(chan), data);
569: }
1.1 root 570: }
571:
572: // CR7/WR7 への書き込み
573: void
574: MPSCCDevice::WriteCR7(MPSCCChan& chan, uint32 data)
575: {
576: chan.cr7 = data;
577:
1.1.1.2 root 578: // どのみちサポートしてないけど初期化のために 0x00 を書き込むようなので
579: // それ以外ならログを出す。
580: if (data != 0) {
581: putlog(0, "Write %s <- $%02x (NOT IMPLEMENTED)", CRName(chan), data);
582: }
1.1 root 583: }
584:
585: // データポートの読み込み
586: uint8
587: MPSCCDevice::ReadData(MPSCCChan& chan)
588: {
589: uint8 data;
590:
591: // 受信バッファが空でも直近のデータが読めるので常に [0] でよい
592: data = chan.rxbuf[0];
593: if (chan.rxlen > 0) {
594: putlog(3, "Ch%c Data -> $%02x", chan.name, data);
595: chan.rxlen--;
596: if (chan.rxlen == 0) {
597: // 取り出して空になった
598: ChangeInterrupt();
599: } else {
600: chan.rxbuf[0] = chan.rxbuf[1];
601: chan.rxbuf[1] = chan.rxbuf[2];
602: }
603: } else {
604: putlog(3, "Ch%c Data -> $%02x (Empty)", chan.name, data);
605: }
606:
607: return data;
608: }
609:
610: // データポートの書き込み
611: void
612: MPSCCDevice::WriteData(MPSCCChan& chan, uint32 data)
613: {
614: char charbuf[4];
615:
616: if (isprint((int)data)) {
617: snprintf(charbuf, sizeof(charbuf), "'%c'", data);
618: } else {
619: charbuf[0] = '\0';
620: }
621: putlog(3, "Ch%c Data <- $%02x %s", chan.name, data, charbuf);
622:
623: // XXX: EMPTY でないときにデータを書いたらどうなるかは未定義
624:
625: // 1byte の TX Buffer
626: chan.txlen = 1;
627: chan.txbuf = data;
628:
629: // データ書き込み後に Empty になったら割り込みを上げるため
630: // ここで ready をセット
631: chan.txint_ready = true;
632:
633: TrySend(chan);
634: }
635:
636: // データポートの Peek
637: uint8
638: MPSCCDevice::PeekData(const MPSCCChan &chan) const
639: {
640: // 受信バッファにデータがあれば先頭バイトが見える。
641: // 受信バッファが空でも直近に取り出したバイトがそのまま見える。
642: return chan.rxbuf[0];
643: }
644:
645: // 送信できるか調べて送信する
646: void
647: MPSCCDevice::TrySend(MPSCCChan& chan)
648: {
649: // 送信可で送信バッファにデータがあって送信中でなければ
650: if (chan.tx_enable && chan.txlen && !txevent[chan.id].IsRunning()) {
651: // 送信する
652: chan.tx_shiftreg = chan.txbuf;
653: chan.txlen = 0;
1.1.1.3 root 654: scheduler->StartEvent(txevent[chan.id]);
1.1 root 655: putlog(2, "Ch%c send $%02x", chan.name, chan.tx_shiftreg);
656:
657: // XXX たぶん送信してから割り込みを上げるまでにいくらか遅れがあるはず
658: }
659:
660: // ネゲートされることがあるので、送信しなくても割り込み状態を更新する
661: ChangeInterrupt();
662: }
663:
664: // 送信のイベントコールバック
665: void
1.1.1.5 root 666: MPSCCDevice::TxCallback(Event& ev)
1.1 root 667: {
1.1.1.5 root 668: int ch = ev.code;
1.1 root 669: MPSCCChan& chan = mpscc.chan[ch];
670:
671: // 接続デバイスの呼び出し
672: Tx(ch, chan.tx_shiftreg);
673:
674: // 次の送信データが来てたら送信
675: TrySend(chan);
676: }
677:
678: // ホストスレッドからの受信通知
679: // (HostCOM スレッドで呼ばれる)
680: void
681: MPSCCDevice::HostRxCallback()
682: {
1.1.1.3 root 683: // XXX 暫定
684: // HostCom からメッセージが大量に送られると、スケジューラの
685: // メッセージキューが溢れてしまうことがあったので、とりあえず
686: // ここでメッセージを送るかどうかを見ているが、
687: // 本当はたぶんこうではなくて、送る側が速度調節するか、
688: // またはスケジューラにメッセージではないなにか別の方法で
689: // 通知を出すようにする必要がある。
690:
691: Event& ev = rxevent[COM_CH];
692:
693: if (ev.IsRunning() == false) {
694: // スレッドを超えるためにメッセージを投げる
695: scheduler->SendMessage(MessageID::HOSTCOM_RX);
696: }
1.1 root 697: }
698:
699: // 1バイト受信する。
700: // 受理されれば true を返す。
701: bool
702: MPSCCDevice::Rx(int ch, uint32 data)
703: {
704: MPSCCChan& chan = mpscc.chan[ch];
705:
706: // Rx Enable でなければ受け取らない?
707: if (chan.rx_enable == false) {
708: return false;
709: }
710:
711: // バッファが一杯なら Rx Overrun Error
712: if (chan.rxlen == sizeof(chan.rxbuf)) {
713: putlog(2, "Ch%c Rx Overrun", chan.name);
714: chan.sr1 |= MPSCC::SR1_RXOVERRUN;
715: // XXX special Rx condition interrupt occurs
716: return false;
717: }
718:
719: // 受信
720: putlog(2, "Ch%c recv $%02x", chan.name, data);
721: chan.rxbuf[chan.rxlen++] = data;
722:
723: // 割り込み状態を変更
724: ChangeInterrupt();
725:
726: return true;
727: }
728:
729: // ホストシリアルからの1バイト受信メッセージ
730: void
1.1.1.5 root 731: MPSCCDevice::RxMessage(MessageID msgid, uint32 arg)
1.1 root 732: {
733: Event& ev = rxevent[COM_CH];
734:
735: // 受信ループが止まっていれば開始
736: if (ev.IsRunning() == false) {
1.1.1.3 root 737: scheduler->StartEvent(ev);
1.1 root 738: }
739: }
740:
741: // 受信イベントコールバック
742: void
743: MPSCCDevice::RxCallback(Event& ev)
744: {
745: int ch = ev.code;
746: int data;
747:
748: // ホストキューにあるだけ取り出す
749: data = hostcom->Rx();
750: if (data >= 0) {
751: Rx(ch, data);
752:
1.1.1.3 root 753: scheduler->StartEvent(ev);
1.1 root 754: }
755: }
756:
757: static double
758: to_freq(uint64 nsec)
759: {
760: return (double)1.0 / nsec * 1e9;
761: }
762:
1.1.1.2 root 763: // ボーレートを再計算する。
764: // CR4(ClkRate) と xc12_ns の変更で呼ぶこと。
765: void
766: MPSCCDevice::ChangeBaudrate(MPSCCChan& chan)
1.1 root 767: {
1.1.1.2 root 768: double old_baudrate = chan.baudrate;
1.1 root 769:
1.1.1.2 root 770: // 誤差を減らすため 12bit 分の時間を基準とする。
771: chan.bit12_ns = chan.xc12_ns * chan.clkrate;
772: chan.baudrate = (double)to_freq(chan.bit12_ns) * 12;
1.1 root 773:
1.1.1.2 root 774: if (loglevel >= 3) {
775: if (chan.baudrate != old_baudrate) {
776: putlogn("Channel %c Baudrate %.1f", chan.name, chan.baudrate);
777: }
778: }
779: }
780:
781: // スタートビット、ストップビット、パリティビットの総数を返す。
782: // enable はサポートしていないモードの時にログを出すため。
783: int
784: MPSCCDevice::AdditionalBits(MPSCCChan& chan, bool enable)
785: {
786: int bit;
1.1 root 787:
788: // start bit
1.1.1.2 root 789: bit = 1;
1.1 root 790:
791: // parity bit
1.1.1.2 root 792: bit += chan.parity_enable;
1.1 root 793:
794: // stop bit
1.1.1.2 root 795: bit += GetStopBits(chan, enable);
796:
797: return bit;
798: }
799:
800: // ストップビット数を返す。
801: // サポートしていないモードなどの場合は enable ならログを出力する。
802: // enable は tx_enable か rx_enable。
803: int
804: MPSCCDevice::GetStopBits(MPSCCChan& chan, bool enable)
805: {
806: switch (chan.stopbits) {
1.1 root 807: case MPSCC::STOPBITS_SYNC:
808: // 非同期モードでの STOPBITS 0 は未定義 (Enable ならログ表示)
809: if (enable) {
1.1.1.2 root 810: putlog(0, "%s Undefined stopbit 0", CRName(chan, 4));
1.1 root 811: }
1.1.1.2 root 812: return 0;
1.1 root 813: case MPSCC::STOPBITS_1:
1.1.1.2 root 814: return 1;
1.1 root 815: case MPSCC::STOPBITS_1_5:
816: // サポートしない (Enable ならログ表示)
817: if (enable) {
1.1.1.2 root 818: putlog(0, "%s Stopbit 1.5 not supported", CRName(chan, 4));
1.1 root 819: }
1.1.1.2 root 820: return 0;
1.1 root 821: case MPSCC::STOPBITS_2:
1.1.1.2 root 822: return 2;
1.1.1.3 root 823:
824: default:
825: VMPANIC("corrupted chan.stopbits=$%x", chan.stopbits);
1.1 root 826: }
827: }
828:
1.1.1.2 root 829: // 受信イベントの時間を設定する。
830: // CR3 または CR4 の変更で呼ぶこと。また呼び出し後は old_cr3、old_cr4 を
831: // 更新すること。
1.1 root 832: void
833: MPSCCDevice::SetRxPeriod(MPSCCChan& chan)
834: {
1.1.1.6 root 835: uint bit;
1.1 root 836:
837: // 受信データビット数
1.1.1.2 root 838: bit = chan.rxbits;
839: // スタート/ストップ等を足す
840: bit += AdditionalBits(chan, chan.rx_enable);
841: chan.rxframebits = bit;
842:
1.1.1.3 root 843: rxevent[chan.id].time = bit * chan.bit12_ns / 12;
844:
1.1.1.2 root 845: if (loglevel >= 1) {
846: bool old_enable = chan.old_cr3 & MPSCC::CR3_RX_EN;
847: bool new_enable = chan.rx_enable;
848: if (old_enable == false && new_enable == false) {
849: // 無効→無効ならパラメータが変化しても表示しない
850:
851: } else if (old_enable == true && new_enable == false) {
852: // 有効→無効なら無効にしたことだけ表示
853: putlogn("Channel %c RX Disable", chan.name);
854: sr0_logphase = 0;
855:
856: } else if ((old_enable == false && new_enable == true) ||
857: (chan.old_cr4 ^ GetCR4(chan)) != 0 ||
858: ((chan.old_cr3 ^ GetCR3(chan)) & MPSCC::CR3_RXBITS) != 0)
859: {
860: // 無効→有効なら表示。
861: // そうでなければ(有効→有効なら)、パラメータが変化すれば表示。
862: std::string nsstr;
863: if (loglevel >= 2) {
864: nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns);
865: }
1.1.1.6 root 866: putlogn("Channel %c RX Enable, %.1f bps%s, %u bits/frame",
1.1.1.2 root 867: chan.name,
868: chan.baudrate,
869: nsstr.c_str(),
870: bit);
871: sr0_logphase = 0;
872: }
1.1 root 873: }
874:
875: // パフォーマンス測定用のギミック。
876: // シリアルポートを特定の設定 (本体 5bit、ストップビット 2bit) にすると、
877: // VM 電源オン時から現在までの実時間をログに出力する。NetBSD/OpenBSD の
878: // マルチユーザブートがあらかた終わってログインプロンプトが出る手前の
879: // /etc/rc.local に
880: //
881: // stty -f /dev/ttya cs5 cstopb; stty -f /dev/ttya cs8 -cstopb
882: //
883: // と書いておくことで、ここまでにかかる時間を表示できる。
884: // この値はホスト性能に依存するため、同一環境下での相対比較のみ可能。
885: // シリアルポートの設定を (通常ではまず使わなそうなやつに) 変えてすぐ戻す
886: // だけなので、実機でも副作用はないはず。
1.1.1.2 root 887: if (chan.id == 0 &&
888: chan.rxbits == 5 && chan.stopbits == MPSCC::STOPBITS_2)
1.1 root 889: {
1.1.1.3 root 890: GetSyncer()->PutlogRealtime();
1.1 root 891: }
892: }
893:
1.1.1.2 root 894: // 送信イベントの時間を設定する。
895: // CR4 または CR5 の変更で呼ぶこと。また呼び出し後は old_cr4、old_cr5 を
896: // 更新すること。
1.1 root 897: void
898: MPSCCDevice::SetTxPeriod(MPSCCChan& chan)
899: {
1.1.1.6 root 900: uint bit;
1.1 root 901:
902: // 送信データビット数
1.1.1.2 root 903: bit = chan.txbits;
904: // スタート/ストップ等を足す
905: bit += AdditionalBits(chan, chan.tx_enable);
906: chan.txframebits = bit;
907:
1.1.1.3 root 908: txevent[chan.id].time = bit * chan.bit12_ns / 12;
909:
1.1.1.2 root 910: if (loglevel >= 1) {
911: bool old_enable = chan.old_cr5 & MPSCC::CR5_TX_EN;
912: bool new_enable = chan.tx_enable;
913: if (old_enable == false && new_enable == false) {
914: // 無効→無効ならパラメータが変化しても表示しない
915:
916: } else if (old_enable == true && new_enable == false) {
917: // 有効→無効なら無効にしたことだけ表示
918: putlogn("Channel %c TX Disable", chan.name);
919: sr0_logphase = 0;
920:
921: } else if ((old_enable == false && new_enable == true) ||
922: (chan.old_cr4 ^ GetCR4(chan)) != 0 ||
923: ((chan.old_cr5 ^ GetCR5(chan)) & MPSCC::CR5_TXBITS) != 0)
924: {
925: // 無効→有効なら表示。
926: // そうでなければ(有効→有効なら)、パラメータが変化すれば表示。
927: std::string nsstr;
928: if (loglevel >= 2) {
929: nsstr = string_format(" (%" PRIu64 ")", chan.bit12_ns);
930: }
1.1.1.6 root 931: putlogn("Channel %c TX Enable, %.1f bps%s, %u bits/frame",
1.1.1.2 root 932: chan.name,
933: chan.baudrate,
934: nsstr.c_str(),
935: bit);
936: sr0_logphase = 0;
937: }
1.1 root 938: }
939: }
940:
941: // 割り込み状態を変更
942: //
943: // uPD7201 の場合:
944: //
945: // RxINT Disable (CR1 b4,3=%00) -->o--+ (注1)
946: // |
947: // o RxCharAvailable ----|& |
948: // |&---|OR +--|&
949: // All/First RxChar ----|& |OR |&--+
950: // |OR---------|& |
951: // o Special Rx Condition -----|OR +---|OR
952: // |OR
1.1.1.5 root 953: // o External/Status ------------------------------|OR----|& ___
954: // |OR |&-->o-- INT
955: // o Tx Buffer Empty ----------|& +---|OR +-|&
956: // |&-----|& | |
957: // Tx INT/DMA Enable --------|& |& | |
958: // (CR1 b1) |&-------+ |
959: // |& |
960: // INT/DMA Mode (CR2A b1,0) --------|& (注2) |
961: // |
962: // Master Interrupt Enable ---------------------------+ (注3)
963: // (Z8530 Only, WR9)
964: //
965: // 左端の o 印は割り込み要因(チャンネルあたり4種類)。他は制御フラグ。
1.1 root 966: //
967: // 注1: uPD7201/7201A Figure 3-2 では "Rx Disable (CR1:D1)" だがそこは
968: // Tx INT/DMA Enable ビットなので名称もビット位置も誤り。
969: // uPD7201 ユーザーズマニュアル p.23 の 図3-2 では "Rx Disable (CR1:D4-3=00)"
970: // とあるのでこれのビット位置が正しければ Rx Int Disable が正しいはず。
971: //
972: // 注2: uPD7201 のみ。Z8530 ではこの選択肢はないので常に true のはず。
973: //
1.1.1.5 root 974: // 注3: Z8530 のみ。uPD7201 ではこの選択肢はないので常に true にしてある。
975: //
1.1 root 976: void
977: MPSCCDevice::ChangeInterrupt()
978: {
979: uint total_intpend = 0;
980: bool int_enable[2];
981:
982: // uPD7201 の CR1 INT/DMA Mode による制御。
983: // Z8530 では intdma_mode = INT_INT 固定。
984: //
985: // ついでにここで txint_enable も演算しておく。見た目は
986: // 無駄っぽいけどコンパイラで最適化されるので気にしない。
987: if (__predict_true(mpscc.intdma_mode == MPSCC::INTDMA_INT_INT)) {
988: int_enable[0] = mpscc.chan[0].txint_enable && true; // ChA INT
989: int_enable[1] = mpscc.chan[1].txint_enable && true; // ChB INT
990: } else if (mpscc.intdma_mode == MPSCC::INTDMA_DMA_INT) {
991: int_enable[0] = mpscc.chan[0].txint_enable && false; // ChA DMA
992: int_enable[1] = mpscc.chan[1].txint_enable && true; // ChB INT
993: } else {
994: int_enable[0] = mpscc.chan[0].txint_enable && false; // ChA DMA
995: int_enable[1] = mpscc.chan[1].txint_enable && false; // ChB DMA
996: }
997:
998: for (auto& chan : mpscc.chan) {
999: // Rx
1000: bool rx_avail = (chan.rxlen > 0) && chan.all_or_first;
1001: // Special Rx (XXX not yet)
1002: bool special = false;
1003: bool rx_int = (chan.rxint_mode != MPSCCChan::RXINT_DISABLE) &&
1004: (rx_avail || special);
1005:
1006: // FirstChar モードなら1文字受信割り込み後にフラグを下ろす
1007: // (Rx 割り込み用の変数 rx_int が確定したここで行う)
1008: if (chan.rxint_mode == MPSCCChan::RXINT_1STCHAR) {
1009: chan.all_or_first = false;
1010: }
1011:
1012: // XXX E/S not yet
1013: bool es_int = false;
1014:
1015: // Tx
1016: bool tx_int = int_enable[chan.id] &&
1017: chan.txint_ready && (chan.txlen == 0);
1018:
1019: uint intpend = 0;
1020: if (rx_int)
1021: intpend |= INTPEND_RX;
1022: if (tx_int)
1023: intpend |= INTPEND_TX;
1024: if (es_int)
1025: intpend |= INTPEND_ES;
1026: chan.intpend = intpend;
1027:
1028: total_intpend |= chan.intpend;
1029: }
1030:
1.1.1.5 root 1031: // Z8530 の MIE。uPD7201 では true 固定にしてある。
1032: if (mpscc.master_int_enable == false) {
1033: total_intpend = 0;
1034: }
1035:
1.1 root 1036: // いずれかでもあれば割り込みをアサート
1.1.1.3 root 1037: interrupt->ChangeINT(this, total_intpend);
1.1 root 1038: }
1039:
1.1.1.3 root 1040: // "9600,N,8,1" みたいなのを返す。最大13桁?
1.1 root 1041: std::string
1042: MPSCCDevice::GetParamStr(const MPSCCChan& chan) const
1043: {
1044: std::string rv;
1045: char parity;
1046: char bits;
1047: char stopbits;
1048:
1049: int parity_idx = 0;
1.1.1.2 root 1050: if (chan.parity_enable) {
1.1 root 1051: parity_idx++;
1.1.1.2 root 1052: if (chan.parity_even) {
1.1 root 1053: parity_idx++;
1054: }
1055: }
1056: parity = "NOE"[parity_idx];
1057:
1058: // bits は RX==TX のときのみ有効出力
1059: // 違うときは '?' にしておく。
1.1.1.2 root 1060: if (chan.rxbits == chan.txbits) {
1061: bits = '0' + chan.rxbits;
1.1 root 1062: } else {
1063: bits = '?';
1064: }
1065:
1066: // stop bit は 1, 2 のみ有効出力。
1067: // SYNC とか 1.5 bit とかは '?' にしておく。
1.1.1.2 root 1068: switch (chan.stopbits) {
1.1 root 1069: case MPSCC::STOPBITS_1:
1070: stopbits = '1';
1071: break;
1072: case MPSCC::STOPBITS_2:
1073: stopbits = '2';
1074: break;
1075: default:
1076: stopbits = '?';
1077: break;
1078: }
1079:
1.1.1.2 root 1080: // ここは、このポートに接続する時に相手方で指定する設定値を
1081: // 表示したいので、ボーレートをよく知られている値に丸めたい。
1082: // 75 * 2^n の +-5% に入っていたら採用。
1083: int baud;
1084: int e;
1085:
1086: // 75 * 2 ^ (e-1) を求める
1087: double a = (chan.baudrate / 75) * 1.5;
1088: std::frexp(a, &e);
1089: int b = 75 * (1 << (e - 1));
1090:
1091: if (b * 19 / 20 <= chan.baudrate && chan.baudrate <= b * 21 / 20) {
1092: baud = b;
1093: } else {
1094: // +-5% 範囲外なら仕方ないのでそのままの値
1095: baud = (int)chan.baudrate;
1096: }
1097:
1.1 root 1098: return string_format("%d,%c,%c,%c",
1.1.1.2 root 1099: baud,
1.1 root 1100: parity,
1101: bits,
1102: stopbits);
1103: }
1104:
1105: // モニタに CR3/WR3、CR4/WR4、CR5/WR5 の内容を書き出す。
1106: // 更新後の y を返す。
1107: int
1108: MPSCCDevice::MonitorUpdateCR345(TextScreen& screen, int x, int y,
1109: uint8 cr3, uint8 cr4, uint8 cr5)
1110: {
1.1.1.2 root 1111: const std::array<char, 4> bits_per_char { '5', '7', '6', '8' };
1112:
1.1 root 1113: // CR3/WR3
1114: static const char * const cr3_str[] = {
1115: "", "", "Auto", "", "", "", "", "RxEn"
1116: };
1117: MonitorReg(screen, x + 9, y, cr3, cr3_str);
1.1.1.2 root 1118: screen.Print(x + 9, y, "RxBits=%c", bits_per_char[(cr3 >> 6) & 3]);
1.1 root 1119: // b1-4 は非同期モードでは使わないのでグレーにしておく
1120: screen.Puts(x + 24, y, TA::Disable, (cr3 & 0x10) ? "1" : "0");
1121: screen.Puts(x + 29, y, TA::Disable, (cr3 & 0x08) ? "1" : "0");
1122: screen.Puts(x + 34, y, TA::Disable, (cr3 & 0x04) ? "1" : "0");
1123: screen.Puts(x + 39, y, TA::Disable, (cr3 & 0x02) ? "1" : "0");
1124: y++;
1125:
1126: // CR4/WR4
1127: static const char * const cr4_str[] = {
1128: "", "", "", "", "", "", "PaEv", "PaEn"
1129: };
1130: MonitorReg(screen, x + 9, y, cr4, cr4_str);
1.1.1.2 root 1131: static const char * const clkrate_str[] = {
1132: "1", "16", "32", "64"
1133: };
1134: screen.Print(x + 9, y, "Rate=x%s", clkrate_str[cr4 >> 6]);
1.1 root 1135: static const char * const syncmode_str[] = {
1136: "Mono", "Bi", "HDLC", "Ext"
1137: };
1138: uint stopbit = (cr4 >> 2) & 3;
1139: screen.Print(x + 19, y, (stopbit == 0 ? TA::Normal : TA::Disable),
1140: "Sync=%s", syncmode_str[(cr4 >> 4) & 3]);
1141: static const char * const stopbit_str[] = {
1142: "SyncMode",
1143: "StopBit=1",
1144: "Stop=1.5",
1145: "StopBit=2"
1146: };
1147: screen.Puts(x + 29, y, stopbit_str[stopbit]);
1148: y++;
1149:
1150: // CR5/WR5
1151: static const char * const cr5_str[] = {
1152: "!DTR", "", "", "SBrk", "TxEn", "CRC", "!RTS", "TCEn"
1153: };
1154: MonitorReg(screen, x + 9, y, cr5, cr5_str);
1.1.1.2 root 1155: screen.Print(x + 14, y, "TxBits=%c", bits_per_char[(cr5 >> 5) & 3]);
1.1 root 1156: y++;
1157:
1158: return y;
1159: }
1160:
1161: // モニタに SR1/RR1 の内容を書き出す。
1162: void
1163: MPSCCDevice::MonitorUpdateSR1(TextScreen& screen, int x, int y, uint8 sr1)
1164: {
1165: static const char * const sr1_str[] = {
1166: "EOF", "FrEr", "RxOv", "PaEr", "", "", "", "Sent"
1167: };
1168: MonitorReg(screen, x + 9, y, sr1, sr1_str);
1169: screen.Print(x + 29, y, TA::Disable, "ResidueCode=%d", (sr1 >> 1) & 7);
1170: }
1171:
1172: // レジスタをビットごとに表示する。MonitorUpdate の下請け。
1173: void
1174: MPSCCDevice::MonitorReg(TextScreen& screen,
1175: int x, int y, uint32 reg, const char * const *names)
1176: {
1177: for (int i = 0; i < 8; i++) {
1178: if (names[i][0] == '-') {
1179: screen.Puts(x + i * 5, y, TA::Disable, "----");
1180: } else {
1181: bool b = reg & (1 << (7 - i));
1182: screen.Puts(x + i * 5, y, TA::OnOff(b), names[i]);
1183: }
1184: }
1185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.