|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2025 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // HD647180 ASCI (非同期シリアル)
9: //
10:
11: #include "hd647180asci.h"
12: #include "hostcom.h"
13: #include "monitor.h"
14: #include "mpu64180.h"
15: #include "scheduler.h"
16:
17: // コンストラクタ
18: HD647180ASCIDevice::HD647180ASCIDevice()
19: : inherited(OBJ_XP_ASCI)
20: {
21: // 入力クロックφ= 6.144MHz だが、設定に関わらず必ず 160 分周は
22: // されるので、それをした後の値を基本周波数(周期)とする。
23: // 6.144MHz / 160 = 38400 [bps] = 26.04166... [usec/bit]
24: // 12倍すると 312.5 [usec]
25: xc12_ns = 312.5_usec;
26:
27: for (uint i = 0; i < channels.size(); i++) {
28: channels[i].id = i;
29: }
30:
31: monitor = gMonitorManager->Regist(ID_MONITOR_XPASCI, this);
32: monitor->func = ToMonitorCallback(&HD647180ASCIDevice::MonitorUpdate);
33: monitor->SetSize(63, 12);
34: }
35:
36: // デストラクタ
37: HD647180ASCIDevice::~HD647180ASCIDevice()
38: {
39: for (uint n = 0; n < channels.size(); n++) {
40: if ((bool)hostcom[n]) {
41: hostcom[n]->ResetRxCallback();
42: }
43: }
44: }
45:
46: bool
47: HD647180ASCIDevice::Create()
48: {
49: static const char * const names[2] = {
50: "XP ASCI Ch.0",
51: "XP ASCI Ch.1",
52: };
53:
54: // 対応するホストドライバを作成。
55: for (auto& chan : channels) {
56: uint n = chan.id;
57: try {
58: hostcom[n].reset(new HostCOMDevice(this, n + 1, names[n]));
59: } catch (...) { }
60: if ((bool)hostcom[n] == false) {
61: warnx("Failed to initialize HostCOMDevice at %s", __method__);
62: return false;
63: }
64: auto func = ToDeviceCallback(&HD647180ASCIDevice::HostRxCallback);
65: hostcom[n]->SetRxCallback(func, n);
66: }
67:
68: return true;
69: }
70:
71: // 初期化
72: bool
73: HD647180ASCIDevice::Init()
74: {
75: xp = GetMPU64180Device();
76:
77: for (auto& chan : channels) {
78: uint n = chan.id;
79:
80: chan.tdr_empty = true;
81: chan.rdr_full = false;
82:
83: scheduler->ConnectMessage(MessageID::HOSTCOM_RX(n + 1), this,
84: ToMessageCallback(&HD647180ASCIDevice::RxMessage));
85:
86: txevent[n].dev = this;
87: txevent[n].func = ToEventCallback(&HD647180ASCIDevice::TxCallback);
88: txevent[n].code = n;
89: txevent[n].SetName(string_format("XP ASCI Ch%c TX", n + '0'));
90: scheduler->RegistEvent(txevent[n]);
91:
92: rxevent[n].dev = this;
93: rxevent[n].func = ToEventCallback(&HD647180ASCIDevice::RxCallback);
94: rxevent[n].code = n;
95: rxevent[n].SetName(string_format("XP ASCI Ch%c RX", n + '0'));
96: scheduler->RegistEvent(rxevent[n]);
97: }
98:
99: return true;
100: }
101:
102: // リセット
103: void
104: HD647180ASCIDevice::ResetHard(bool poweron)
105: {
106: // TDR, RDR はリセットの影響を受けない。
107: // リセットで転送は止まる (.. are stopped during RESET) とは書いてあるが
108: // TSR, RSR がどうなるかは不明。さすがにリセットされるか。
109:
110: nRTS0 = true;
111: cka1_disable = true;
112:
113: for (auto& chan : channels) {
114: uint n = chan.id;
115:
116: chan.rx_enable = false;
117: chan.tx_enable = false;
118: chan.rx_intr_enable = false;
119: chan.tx_intr_enable = false;
120: chan.data8bit = false;
121: chan.parity_en = false;
122: chan.stop2bit = false;
123: chan.parity_odd = false;
124: chan.prescale = false;
125: chan.divratio = false;
126: chan.ss = 7;
127: chan.nCTS = false; // ?
128: chan.tsr = -1;
129: chan.rsr = -1;
130: ChangeBaudRate(chan.id);
131: ChangeInterrupt(chan.id);
132:
133: scheduler->StopEvent(txevent[n]);
134: scheduler->StopEvent(rxevent[n]);
135: }
136: }
137:
138: uint32
139: HD647180ASCIDevice::ReadCNTLA(uint n)
140: {
141: uint32 data = PeekCNTLA(n);
142: putlog(3, "CNTLA%u -> $%02x", n, data);
143: return data;
144: }
145:
146: uint32
147: HD647180ASCIDevice::ReadCNTLB(uint n)
148: {
149: uint32 data = PeekCNTLB(n);
150: putlog(3, "CNTLB%u -> $%02x", n, data);
151: return data;
152: }
153:
154: uint32
155: HD647180ASCIDevice::ReadSTAT(uint n)
156: {
157: uint32 data = PeekSTAT(n);
158: putlog(3, "STAT%u -> $%02x", n, data);
159: return data;
160: }
161:
162: uint32
163: HD647180ASCIDevice::ReadTDR(uint n)
164: {
165: // TDR は副作用なく読み出し可能。
166: uint32 data = PeekTDR(n);
167: putlog(3, "TDR%u -> $%02x", n, data);
168: return data;
169: }
170:
171: uint32
172: HD647180ASCIDevice::ReadRDR(uint n)
173: {
174: Channel& chan = channels[n];
175:
176: uint32 data = PeekRDR(n);
177: if (chan.rsr >= 0) {
178: chan.rdr = chan.rsr;
179: chan.rsr = -1;
180: } else {
181: chan.rdr_full = false;
182: }
183: putlog(4, "RDR%u -> $%02x", n, data);
184: return data;
185: }
186:
187: uint32
188: HD647180ASCIDevice::WriteCNTLA(uint n, uint32 data)
189: {
190: Channel& chan = channels[n];
191: std::string msg;
192:
193: if ((data & CNTL_MPE)) {
194: putlog(0, "MPE=1 (NOT IMPLEMENTED)");
195: }
196:
197: bool newrxe = (data & CNTL_RE);
198: if (chan.rx_enable != newrxe) {
199: chan.rx_enable = newrxe;
200: if (__predict_false(loglevel >= 1)) {
201: msg += string_format(" RX=%s", (newrxe ? "Enable" : "Disable"));
202: }
203: }
204:
205: bool newtxe = (data & CNTL_TE);
206: if (chan.tx_enable != newtxe) {
207: chan.tx_enable = newtxe;
208: if (__predict_false(loglevel >= 1)) {
209: msg += string_format(" TX=%s", (newtxe ? "Enable" : "Disable"));
210: }
211: }
212:
213: if (n == 0) {
214: nRTS0 = (data & CNTL_nRTS0);
215: } else {
216: cka1_disable = (data & CNTL_CKA1D);
217: if (cka1_disable == false) {
218: putlog(0, "CKA1D=0 (NOT IMPLEMENTED)");
219: }
220: }
221:
222: if ((data & CNTL_EFR)) {
223: // OVRN, FE, PE をクリアする。
224: chan.overrun = false;
225: ChangeInterrupt(n);
226: }
227:
228: bool new8bit = (data & CNTL_DATA8);
229: bool newpen = (data & CNTL_PAREN);
230: bool newstop = (data & CNTL_STOP2);
231: if (chan.data8bit != new8bit ||
232: chan.parity_en != newpen ||
233: chan.stop2bit != newstop)
234: {
235: chan.data8bit = new8bit;
236: chan.parity_en = newpen;
237: chan.stop2bit = newstop;
238: ChangeBaudRate(n);
239: if (__predict_false(loglevel >= 1)) {
240: msg += string_format(" data=%u,stop=%u,parity=%s",
241: (chan.data8bit ? 8 : 7),
242: (chan.stop2bit ? 2 : 1),
243: (chan.parity_en ? "on" : "off"));
244: }
245: }
246:
247: if (__predict_false(loglevel >= 1)) {
248: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
249: int req;
250: if (msg.empty()) {
251: // 状態が変わっていない。
252: req = 2;
253: } else {
254: req = 1;
255: msg[0] = '(';
256: msg += ')';
257: }
258: putlog(req, "CNTLA%u <- $%02x %s", n, data, msg.c_str());
259: }
260:
261: return 0;
262: }
263:
264: uint32
265: HD647180ASCIDevice::WriteCNTLB(uint n, uint32 data)
266: {
267: Channel& chan = channels[n];
268: std::string msg;
269:
270: if ((data & (CNTL_MPBT | CNTL_MP))) {
271: putlog(0, "MPBT|MP=1 (NOT IMPLEMENTED)");
272: }
273:
274: bool newpo = (data & CNTL_PEO);
275: if (chan.parity_odd != newpo) {
276: chan.parity_odd = newpo;
277: if (__predict_false(loglevel >= 1)) {
278: msg += string_format(" Parity=%s", (newpo ? "Odd" : "Even"));
279: }
280: }
281:
282: bool newps = (data & CNTL_PS);
283: bool newdr = (data & CNTL_DR);
284: uint32 newss = (data & CNTL_SS);
285: if (chan.prescale != newps ||
286: chan.divratio != newdr ||
287: chan.ss != newss)
288: {
289: chan.prescale = newps;
290: chan.divratio = newdr;
291: chan.ss = newss;
292: ChangeBaudRate(n);
293: if (__predict_false(loglevel >= 1)) {
294: msg += string_format(" PS=%u DR=%u SS=%u",
295: (uint)newps, (uint)newdr, newss);
296: if (chan.baudrate > 0) {
297: msg += string_format(", %u bps", chan.baudrate);
298: }
299: }
300: }
301:
302: if (__predict_false(loglevel >= 1)) {
303: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
304: int req;
305: if (msg.empty()) {
306: // 状態が変わっていない。
307: req = 2;
308: } else {
309: req = 1;
310: msg[0] = '(';
311: msg += ')';
312: }
313: putlog(req, "CNTLB%u <- $%02x %s", n, data, msg.c_str());
314: }
315:
316: return 0;
317: }
318:
319: uint32
320: HD647180ASCIDevice::WriteSTAT(uint n, uint32 data)
321: {
322: Channel& chan = channels[n];
323: std::string msg;
324:
325: if (n == 1) {
326: cts1_enable = (data & STAT_CTS1E);
327: if (cts1_enable) {
328: putlog(0, "CTS1E=1 (NOT IMPLEMENTED)");
329: }
330: }
331:
332: bool newrie = (data & STAT_RIE);
333: if (chan.rx_intr_enable != newrie) {
334: chan.rx_intr_enable = newrie;
335: ChangeInterrupt(n);
336: msg += string_format(" RIE=%s", newrie ? "Enable" : "Disable");
337: }
338:
339: bool newtie = (data & STAT_TIE);
340: if (chan.tx_intr_enable != newtie) {
341: chan.tx_intr_enable = newtie;
342: ChangeInterrupt(n);
343: msg += string_format(" TIE=%s", newrie ? "Enable" : "Disable");
344: }
345:
346: if (__predict_false(loglevel >= 1)) {
347: // ログレベル1なら状態が変わった時だけ、2ならすべて表示。
348: int req;
349: if (msg.empty()) {
350: // 状態が変わっていない。
351: req = 2;
352: } else {
353: req = 1;
354: msg[0] = '(';
355: msg += ')';
356: }
357: putlog(req, "STAT%u <- $%02x %s", n, data, msg.c_str());
358: }
359:
360: return 0;
361: }
362:
363: uint32
364: HD647180ASCIDevice::WriteTDR(uint n, uint32 data)
365: {
366: Channel& chan = channels[n];
367:
368: // どちらにしても一旦 TDR には置く。
369: chan.tdr = data;
370: putlog(4, "TDR%u <- $%02x", n, data);
371:
372: // TDR TSR TDR TSR
373: // --- --- --- ---
374: // なし なし -> なし data イベント始動
375: // なし 有り -> data 有り (イベントは動いてるはず)
376: // 有り なし (すぐ1行上に遷移するのでこの状態にはならない)
377: // 有り 有り -> data 有り
378:
379: if (chan.tsr < 0) {
380: // TSR が空なら即コピーして、送信イベント開始。
381: chan.tsr = chan.tdr;
382: chan.tdr_empty = true;
383: if (txevent[n].IsRunning() == false) {
384: scheduler->StartEvent(txevent[n]);
385: }
386: } else {
387: // TSR が埋まっていれば何もしない。(イベントは動いてるはず)
388: chan.tdr_empty = false;
389: }
390:
391: ChangeInterrupt(n);
392: return 0;
393: }
394:
395: uint32
396: HD647180ASCIDevice::WriteRDR(uint n, uint32 data)
397: {
398: Channel& chan = channels[n];
399:
400: // RDR が空の時に限り、書き込み出来る。(p.69)
401: if (chan.rdr_full) {
402: putlog(1, "RDR%u <- $%02x (Write Ignored)", n, data);
403: } else {
404: chan.rdr = data;
405: putlog(4, "RDR%u <- $%02x", n, data);
406: }
407: return 0;
408: }
409:
410: uint32
411: HD647180ASCIDevice::PeekCNTLA(uint n) const
412: {
413: const Channel& chan = channels[n];
414: uint32 data = 0;
415:
416: // MPE Not implemented
417:
418: if (chan.rx_enable) {
419: data |= CNTL_RE;
420: }
421: if (chan.tx_enable) {
422: data |= CNTL_TE;
423: }
424: if (n == 0) {
425: if (nRTS0) {
426: data |= CNTL_nRTS0;
427: }
428: } else {
429: if (cka1_disable) {
430: data |= CNTL_CKA1D;
431: }
432: }
433: if (chan.data8bit) {
434: data |= CNTL_DATA8;
435: }
436: if (chan.parity_en) {
437: data |= CNTL_PAREN;
438: }
439: if (chan.stop2bit) {
440: data |= CNTL_STOP2;
441: }
442:
443: return data;
444: }
445:
446: uint32
447: HD647180ASCIDevice::PeekCNTLB(uint n) const
448: {
449: const Channel& chan = channels[n];
450: uint32 data = 0;
451:
452: // MPBT, MP: Not implemented
453:
454: if (chan.nCTS) {
455: data |= CNTL_nCTS;
456: }
457: if (chan.parity_odd) {
458: data |= CNTL_PEO;
459: }
460: if (chan.divratio) {
461: data |= CNTL_DR;
462: }
463: data |= chan.ss;
464:
465: return data;
466: }
467:
468: uint32
469: HD647180ASCIDevice::PeekSTAT(uint n) const
470: {
471: const Channel& chan = channels[n];
472: uint32 data = 0;
473:
474: if (chan.rdr_full) {
475: data |= STAT_RDRF;
476: }
477: if (chan.overrun) {
478: data |= STAT_OVRN;
479: }
480:
481: // PE, FE は立たない。
482:
483: if (chan.rx_intr_enable) {
484: data |= STAT_RIE;
485: }
486: if (n == 0) {
487: if (nDCD0) {
488: data |= STAT_nDCD0;
489: }
490: } else {
491: if (cts1_enable) {
492: data |= STAT_CTS1E;
493: }
494: }
495: if (chan.tdr_empty) {
496: data |= STAT_TDRE;
497: }
498: if (chan.tx_intr_enable) {
499: data |= STAT_TIE;
500: }
501:
502: return data;
503: }
504:
505: uint32
506: HD647180ASCIDevice::PeekTDR(uint n) const
507: {
508: const Channel& chan = channels[n];
509:
510: return chan.tdr;
511: }
512:
513: uint32
514: HD647180ASCIDevice::PeekRDR(uint n) const
515: {
516: const Channel& chan = channels[n];
517:
518: return chan.rdr;
519: }
520:
521: void
522: HD647180ASCIDevice::MonitorUpdate(Monitor *, TextScreen& screen)
523: {
524: screen.Clear();
525:
526: MonitorUpdateChan(screen, 0, 0);
527: MonitorUpdateChan(screen, 6, 1);
528: }
529:
530: void
531: HD647180ASCIDevice::MonitorUpdateChan(TextScreen& screen, int y, int n) const
532: {
533: Channel tmp = channels[n];
534: uint32 cntla = PeekCNTLA(n);
535: uint32 cntlb = PeekCNTLB(n);
536: uint32 stat = PeekSTAT(n);
537: int x;
538:
539: screen.Print(0, y++, "<Ch.%c>", n + '0');
540:
541: x = 16;
542: screen.Print(0, y, "%02XH CNTLA%u=$%02x:", 0 + n, n, cntla);
543: screen.Puts(x + 0, y, TA::OnOff(cntla & 0x80), "MPE");
544: screen.Puts(x + 6, y, TA::OnOff(cntla & 0x40), "RE");
545: screen.Puts(x + 12, y, TA::OnOff(cntla & 0x20), "TE");
546: screen.Puts(x + 18, y, TA::OnOff(cntla & 0x10),
547: (n == 0 ? "!RTS0" : "CKA1D"));
548: screen.Puts(x + 24, y, TA::OnOff(cntla & 0x08), "MPBR");
549: screen.Puts(x + 30, y, TA::OnOff(cntla & 0x04), "8BIT");
550: screen.Puts(x + 36, y, TA::OnOff(cntla & 0x02), "ParEn");
551: screen.Puts(x + 42, y, TA::OnOff(cntla & 0x01), "STOP2");
552: y++;
553:
554: screen.Print(0, y, "%02XH CNTLB%u=$%02x:", 2 + n, n, cntlb);
555: screen.Puts(x + 0, y, TA::OnOff(cntlb & 0x80), "MPBT");
556: screen.Puts(x + 6, y, TA::OnOff(cntlb & 0x40), "MP");
557: screen.Puts(x + 12, y, TA::OnOff(cntlb & 0x20), "!CTS");
558: screen.Puts(x + 18, y, TA::OnOff(cntlb & 0x10), "PEO");
559: screen.Print(x + 24, y, "DR=%u", tmp.divratio ? 1 : 0);
560: screen.Print(x + 30, y, "SS[210]=%u", (cntlb & 0x07));
561: screen.Print(x + 42, y, "PS=%u", tmp.prescale ? 1 : 0);
562: y++;
563:
564: screen.Print(0, y, "%02XH STAT%u =$%02x:", 4 + n, n, stat);
565: screen.Puts(x + 0, y, TA::OnOff(stat & 0x80), "RDRF");
566: screen.Puts(x + 6, y, TA::OnOff(stat & 0x40), "OVRN");
567: screen.Puts(x + 12, y, TA::OnOff(stat & 0x20), "PE");
568: screen.Puts(x + 18, y, TA::OnOff(stat & 0x10), "FE");
569: screen.Puts(x + 24, y, TA::OnOff(stat & 0x08), "RIE");
570: screen.Puts(x + 30, y, TA::OnOff(stat & 0x04),
571: (n == 0 ? "!DCD0" : "CTS1E"));
572: screen.Puts(x + 36, y, TA::OnOff(stat & 0x02), "TDRE");
573: screen.Puts(x + 42, y, TA::OnOff(stat & 0x01), "TIE");
574: y++;
575:
576: screen.Print(0, y, "%02XH TDR%u =", 6 + n, n);
577: screen.Print(11, y, (tmp.tdr_empty ? TA::Disable : TA::Normal),
578: "$%02x", tmp.tdr);
579: screen.Puts(x, y, "TSR:");
580: if (__predict_true(tmp.tsr < 0)) {
581: screen.Puts(x + 4, y, TA::Disable, "---");
582: } else {
583: screen.Print(x + 4, y, "$%02x", tmp.tsr);
584: }
585: y++;
586:
587: screen.Print(0, y, "%02XH RDR%u =", 8 + n, n);
588: screen.Print(11, y, (tmp.rdr_full ? TA::Normal : TA::Disable),
589: "$%02x", tmp.rdr);
590: screen.Puts(x, y, "RSR:");
591: if (__predict_true(tmp.rsr < 0)) {
592: screen.Puts(x + 4, y, TA::Disable, "---");
593: } else {
594: screen.Print(x + 4, y, "$%02x", tmp.rsr);
595: }
596:
597: // Param: 19200,N,8,2
598: screen.Puts(x + 29, y, "Param:");
599: if (tmp.baudrate == 0) {
600: screen.Puts(x + 36, y, "(ExtClock)");
601: } else {
602: char p;
603: if (tmp.parity_en) {
604: p = tmp.parity_odd ? 'O' : 'E';
605: } else {
606: p = 'N';
607: }
608: screen.Print(x + 36, y, "%5u,%c,%u,%u",
609: tmp.baudrate, p, (tmp.data8bit ? 8 : 7), (tmp.stop2bit ? 2 : 1));
610: }
611: }
612:
613:
614: // 割り込み状態を更新する。
615: // RDFn, OVRNn, RIEn, TDREn, TIEn のいずれかでも変更したら呼ぶこと。
616: void
617: HD647180ASCIDevice::ChangeInterrupt(uint n)
618: {
619: // p.77 Fig 2.10.3 より、片方のチャンネルの割り込み要求ロジック。
620: // ____
621: // DCD0(*) --|OR (*) Ch0 のみ
622: // RDRFn ----|OR
623: // OVRNn ----|OR-----|& : IEF1
624: // PEn -----|OR |& : |
625: // FEn -----|OR |&-----|OR : |
626: // |& |OR : +--|&
627: // RIEn -----|& |OR : |&----> ASCIn Int
628: // |OR-----------|&
629: // TDREn ----|& |OR :
630: // |&-----|OR :
631: // TIEn -----|& :
632: // :
633: // この関数でやってるのはここまで : こっちは xp->ChangeASCIInt()
634:
635: const Channel& chan = channels[n];
636:
637: // PE, FE (, !DCD0) はない。
638: bool rcond = chan.rdr_full || chan.overrun;
639: bool rintr = rcond && chan.rx_intr_enable;
640:
641: bool tintr = chan.tdr_empty && chan.tx_intr_enable;
642:
643: bool intr = (rintr || tintr);
644:
645: // IEF1 は向こうで処理している。
646: xp->ChangeASCIInt(n, intr);
647: }
648:
649: static double
650: to_freq(uint64 nsec)
651: {
652: return (double)1e9 / nsec;
653: }
654:
655: // 現在の Prescale, DivideRatio, SS からボーレートを再計算する。
656: // ここで 1文字分の時間も計算するため、CNTLA の MOD が変わっても呼ぶこと。
657: void
658: HD647180ASCIDevice::ChangeBaudRate(uint n)
659: {
660: Channel& chan = channels[n];
661:
662: if (__predict_false(chan.ss == 7)) {
663: chan.baudrate = 0;
664: } else {
665: uint d = (1U << chan.ss);
666:
667: // PreScaler で 30 か 10 分周が指定出来るが、このうち 10 は計算済み。
668: if (chan.prescale) {
669: d *= 3;
670: }
671:
672: // DivideRatio で 64 か 16 分周が指定できるが、このうち 16 は計算済み。
673: if (chan.divratio) {
674: d *= 4;
675: }
676:
677: chan.bit12_ns = xc12_ns * d;
678: chan.baudrate = to_freq(chan.bit12_ns / 12);
679:
680: // 1文字の送受信にかかる時間。
681: uint bits = 1/*start*/ + 7/*data*/ + 1/*stop*/;
682: if (chan.data8bit) {
683: bits++;
684: }
685: if (chan.parity_en) {
686: bits++;
687: }
688: if (chan.stop2bit) {
689: bits++;
690: }
691: uint64 time = chan.bit12_ns * bits / 12;
692: txevent[n].time = time;
693: rxevent[n].time = time;
694: }
695: }
696:
697: // 送信イベント。
698: void
699: HD647180ASCIDevice::TxCallback(Event& ev)
700: {
701: uint n = ev.code;
702: Channel& chan = channels[n];
703:
704: // 1文字分の時間が経過したので TSR の文字をホストに送信。
705: hostcom[n]->Tx(chan.tsr);
706:
707: if (chan.tdr_empty) {
708: // 次がなければ終わり。
709: chan.tsr = -1;
710: } else {
711: // 次の文字がある。
712: chan.tsr = chan.tdr;
713: chan.tdr_empty = true;
714: ChangeInterrupt(n);
715:
716: scheduler->StartEvent(ev);
717: }
718: }
719:
720: // ホストスレッドからの受信通知。
721: // (HostCOM スレッドで呼ばれる)
722: void
723: HD647180ASCIDevice::HostRxCallback(uint32 arg)
724: {
725: // XXX mpscc.cpp の同関数のコメント参照。
726:
727: uint n = arg;
728: Event& ev = rxevent[n];
729:
730: if (ev.IsRunning() == false) {
731: // スレッドを超えるためにメッセージを投げる。
732: scheduler->SendMessage(MessageID::HOSTCOM_RX(n + 1));
733: }
734: }
735:
736: // ホストシリアルからの1バイト受信メッセージ
737: // (VM スレッドで呼ばれる)
738: void
739: HD647180ASCIDevice::RxMessage(MessageID msgid, uint32 arg)
740: {
741: uint n = msgid - MessageID::HOSTCOM1_RX;
742: Event& ev = rxevent[n];
743:
744: // 受信ループが止まっていれば開始。
745: if (ev.IsRunning() == false) {
746: scheduler->StartEvent(ev);
747: }
748: }
749:
750: // 受信イベントコールバック。
751: void
752: HD647180ASCIDevice::RxCallback(Event& ev)
753: {
754: uint n = ev.code;
755: int data;
756:
757: data = hostcom[n]->Rx();
758: if (data >= 0) {
759: Rx(n, data);
760:
761: scheduler->StartEvent(ev);
762: }
763: }
764:
765: // 1バイト受信する。
766: bool
767: HD647180ASCIDevice::Rx(uint n, uint32 data)
768: {
769: Channel& chan = channels[n];
770:
771: // Rx Enable でなければ受け取らない?
772: if (chan.rx_enable == false) {
773: return false;
774: }
775:
776: // 受信前 受信後の状態
777: // RDR RSR RDR RSR
778: // --- --- --- ---
779: // なし なし -> data なし
780: // なし 有り (すぐに1行下の状態に遷移するためこの状態はない)
781: // 有り なし -> 有り data
782: // 有り 有り -> 有り 有り (Overrun)
783:
784: // バッファが一杯なら Overrun。
785: if (chan.rdr_full && chan.rsr >= 0) {
786: putlog(2, "Ch%u Rx Overrun", n);
787: chan.overrun = true;
788: ChangeInterrupt(n);
789: return false;
790: }
791:
792: // 受信。
793: putlog(2, "Ch%u recv $%02x", n, data);
794: if (chan.rdr_full) {
795: chan.rsr = data;
796: } else {
797: chan.rdr = data;
798: chan.rdr_full = true;
799: chan.rsr = -1;
800: ChangeInterrupt(n);
801: }
802:
803: return true;
804: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.