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