|
|
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.4 root 7: #include "keyboard.h"
1.1 root 8: #include "mfp.h"
1.1.1.4 root 9: #include "mpu680x0.h"
1.1 root 10: #include "mystring.h"
11: #include "scheduler.h"
12:
1.1.1.3 root 13: std::unique_ptr<MFPDevice> gMFP;
1.1 root 14:
15: // コンストラクタ
16: MFPDevice::MFPDevice()
17: {
18: logname = "mfp";
19: devname = "MFP";
20: devaddr = baseaddr;
21: devlen = 0x2000;
1.1.1.5 ! root 22: monitor_size = nnSize(65, 17);
1.1 root 23:
24: for (int ch = 0; ch < countof(event); ch++) {
25: event[ch].dev = this;
26: event[ch].func = (DeviceCallback_t)&MFPDevice::TimerCallback;
27: event[ch].code = ch;
1.1.1.2 root 28: event[ch].SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1 root 29: }
1.1.1.4 root 30:
31: // キーボード周りは x68kkbd.cpp のコメント参照
32: key_event.dev = this;
33: key_event.func = (DeviceCallback_t)&MFPDevice::KeyCallback;
34: key_event.time = 3750_usec;
35: key_event.SetName("MFP USART");
1.1 root 36: }
37:
38: // デストラクタ
39: MFPDevice::~MFPDevice()
40: {
41: }
42:
43: // MPU の RESET 命令によるリセット
44: void
45: MFPDevice::ResetSoft()
46: {
47: // TxDR, UDR, TSR はクリアされない
48:
49: // ?
50: mfp.tsr = 0x80;
51:
52: // それ以外のすべてのレジスタはクリア?
53: mfp.vr = 0;
54:
55: // タイマーはすべてストップなのでイベントを削除
56: for (int ch = 0; ch < countof(event); ch++) {
1.1.1.3 root 57: event[ch].Stop();
1.1 root 58: }
1.1.1.4 root 59: key_event.Stop();
1.1 root 60:
1.1.1.4 root 61: // 信号線
62: rr = false;
1.1.1.3 root 63:
1.1.1.4 root 64: // ペンディング割り込みクリア
1.1.1.3 root 65: }
66:
1.1 root 67: uint64
1.1.1.4 root 68: MFPDevice::Read(uint32 addr)
1.1 root 69: {
70: uint8 data;
71:
1.1.1.4 root 72: switch (addr) {
1.1 root 73: case MFP::GPIP:
74: data = mfp.gpip;
75: break;
76: case MFP::AER:
77: data = mfp.aer;
78: break;
79: case MFP::DDR:
80: data = mfp.ddr;
81: break;
82: case MFP::IERA:
83: data = mfp.ier.a;
84: break;
85: case MFP::IERB:
86: data = mfp.ier.b;
87: break;
88: case MFP::IPRA:
89: data = mfp.ipr.a;
90: break;
91: case MFP::IPRB:
92: data = mfp.ipr.b;
93: break;
94: case MFP::ISRA:
95: data = mfp.isr.a;
96: break;
97: case MFP::ISRB:
98: data = mfp.isr.b;
99: break;
100: case MFP::IMRA:
101: data = mfp.imr.a;
102: break;
103: case MFP::IMRB:
104: data = mfp.imr.b;
105: break;
106: case MFP::VR:
107: data = mfp.vr;
108: break;
109: case MFP::TACR:
110: data = mfp.tcr[0];
111: break;
112: case MFP::TBCR:
113: data = mfp.tcr[1];
114: break;
115: case MFP::TCDCR:
116: data = (mfp.tcr[2] << 4) | mfp.tcr[3];
117: break;
118: case MFP::TADR:
119: data = GetTDR(0);
120: break;
121: case MFP::TBDR:
122: data = GetTDR(1);
123: break;
124: case MFP::TCDR:
125: data = GetTDR(2);
126: break;
127: case MFP::TDDR:
128: data = GetTDR(3);
129: break;
130: case MFP::SCR:
131: data = mfp.scr;
132: break;
133: case MFP::UCR:
134: data = mfp.ucr;
135: break;
136: case MFP::RSR:
137: data = mfp.rsr;
138: break;
139: case MFP::TSR:
140: data = mfp.tsr;
141: break;
142: case MFP::UDR:
143: data = mfp.udr;
144: break;
1.1.1.4 root 145: default:
146: data = 0xff;
147: break;
1.1 root 148: }
149: return data;
150: }
151:
152: uint64
1.1.1.4 root 153: MFPDevice::Write(uint32 addr, uint32 data)
1.1 root 154: {
1.1.1.4 root 155: switch (addr) {
1.1 root 156: case MFP::GPIP:
157: putlog(0, "GPIP <- $%02x 未実装書き込み", data);
158: mfp.gpip = data;
159: break;
160: case MFP::AER:
161: putlog(0, "AER <- $%02x 未実装書き込み", data);
162: mfp.aer = data;
163: break;
164: case MFP::DDR:
165: if (data != 0) {
166: putlog(0, "DDR <- $%02x 未実装書き込み", data);
167: }
168: mfp.ddr = data;
169: break;
170: case MFP::IERA:
171: putlog(2, "IERA <- $%02x", data);
172: mfp.ier.a = data;
173: break;
174: case MFP::IERB:
175: putlog(2, "IERB <- $%02x", data);
176: mfp.ier.b = data;
177: break;
178: case MFP::IPRA:
179: putlog(2, "IPRA <- $%02x", data);
180: mfp.ipr.a = data;
181: break;
182: case MFP::IPRB:
183: putlog(2, "IPRB <- $%02x", data);
184: mfp.ipr.b = data;
185: break;
186: case MFP::ISRA:
187: putlog(2, "ISRA <- $%02x", data);
188: mfp.isr.a = data;
189: break;
190: case MFP::ISRB:
191: putlog(2, "ISRB <- $%02x", data);
192: mfp.isr.b = data;
193: break;
194: case MFP::IMRA:
195: putlog(2, "IMRA <- $%02x", data);
196: mfp.imr.a = data;
197: break;
198: case MFP::IMRB:
199: putlog(2, "IMRB <- $%02x", data);
200: mfp.imr.b = data;
201: break;
202: case MFP::VR:
203: mfp.vr = data & 0xf0;
204: putlog(2, "VR <- $%02x", mfp.vr);
205: break;
206: case MFP::TACR:
207: putlog(2, "TACR <- $%02x", data);
208: SetTCR(0, data);
209: break;
210: case MFP::TBCR:
211: putlog(2, "TBCR <- $%02x", data);
212: SetTCR(1, data);
213: break;
214: case MFP::TCDCR:
215: putlog(2, "TCDCR <- $%02x", data);
216: SetTCR(2, data >> 4);
217: SetTCR(3, data & 7);
218: break;
219: case MFP::TADR:
220: putlog(2, "TADR <- $%02x", data);
221: SetTDR(0, data);
222: break;
223: case MFP::TBDR:
224: putlog(2, "TBDR <- $%02x", data);
225: SetTDR(1, data);
226: break;
227: case MFP::TCDR:
228: putlog(2, "TCDR <- $%02x", data);
229: SetTDR(2, data);
230: break;
231: case MFP::TDDR:
232: putlog(2, "TDDR <- $%02x", data);
233: SetTDR(3, data);
234: break;
235: case MFP::SCR:
236: putlog(0, "SCR <- $%02x 未実装書き込み", data);
237: mfp.scr = data;
238: break;
239: case MFP::UCR:
1.1.1.4 root 240: putlog(2, "UCR <- $%02x", data);
241: SetUCR(data);
1.1 root 242: break;
243: case MFP::RSR:
1.1.1.4 root 244: putlog(2, "RSR <- $%02x", data);
245: SetRSR(data);
1.1 root 246: break;
247: case MFP::TSR:
248: putlog(0, "TSR <- $%02x 未実装書き込み", data);
249: mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
250: break;
251: case MFP::UDR:
1.1.1.4 root 252: if (data == 0x40 || data == 0x41) {
253: // MSCTRL だけ頻度が高いのでログレベルを上げておく
254: putlog(3, "UDR <- $%02x", data);
255: } else {
256: putlog(2, "UDR <- $%02x", data);
257: }
258: SetUDR(data);
259: break;
260: default:
1.1 root 261: break;
262: }
263: return 0;
264: }
265:
266: uint64
1.1.1.4 root 267: MFPDevice::Peek(uint32 addr)
1.1 root 268: {
269: uint8 data;
270:
1.1.1.4 root 271: switch (addr) {
1.1 root 272: case MFP::GPIP:
273: data = mfp.gpip;
274: break;
275: case MFP::AER:
276: data = mfp.aer;
277: break;
278: case MFP::DDR:
279: data = mfp.ddr;
280: break;
281: case MFP::IERA:
282: data = mfp.ier.a;
283: break;
284: case MFP::IERB:
285: data = mfp.ier.b;
286: break;
287: case MFP::IPRA:
288: data = mfp.ipr.a;
289: break;
290: case MFP::IPRB:
291: data = mfp.ipr.b;
292: break;
293: case MFP::ISRA:
294: data = mfp.isr.a;
295: break;
296: case MFP::ISRB:
297: data = mfp.isr.b;
298: break;
299: case MFP::IMRA:
300: data = mfp.imr.a;
301: break;
302: case MFP::IMRB:
303: data = mfp.imr.b;
304: break;
305: case MFP::VR:
306: data = mfp.vr;
307: break;
308: case MFP::TACR:
309: data = mfp.tcr[0];
310: break;
311: case MFP::TBCR:
312: data = mfp.tcr[1];
313: break;
314: case MFP::TCDCR:
315: data = (mfp.tcr[2] << 4) | mfp.tcr[3];
316: break;
317: case MFP::TADR:
318: data = GetTDR(0);
319: break;
320: case MFP::TBDR:
321: data = GetTDR(1);
322: break;
323: case MFP::TCDR:
324: data = GetTDR(2);
325: break;
326: case MFP::TDDR:
327: data = GetTDR(3);
328: break;
329: case MFP::SCR:
330: data = mfp.scr;
331: break;
332: case MFP::UCR:
333: data = mfp.ucr;
334: break;
335: case MFP::RSR:
336: data = mfp.rsr;
337: break;
338: case MFP::TSR:
339: data = mfp.tsr;
340: break;
341: case MFP::UDR:
342: data = mfp.udr;
343: break;
1.1.1.4 root 344: default:
345: data = 0xff;
1.1 root 346: }
347: return data;
348: }
349:
1.1.1.5 ! root 350: void
! 351: MFPDevice::MonitorUpdate(TextScreen& monitor)
1.1 root 352: {
353: int x;
354: int y;
355:
356: monitor.Clear();
357:
358: // 0 1 2 3 4 5 6
359: // 012345678901234567890123456789012345678901234567890123456789012345
360: // IER IMR IPR ISR Mode TDR Cnt
361: // An:MPSC TxEmpty Enable Mask Pend Serv Timer-A Delay(50us) 255 255
362:
363: // 割り込み関連
364: monitor.Print(0, 0, " %-12s %-6s %-4s %-4s %-4s",
365: "", "IER", "IMR", "IPR", "ISR");
366: y = 1;
367: for (int i = 15; i >= 0; i--, y++) {
368: uint16 mask = (1 << i);
369: monitor.Print(0, y, "%c%d:%-12s %-6s %-4s %-4s %-4s",
370: i >= 8 ? 'A' : 'B',
371: (i % 8),
372: intrname[i],
373: (mfp.ier.w & mask) ? "Enable" : "",
374: (mfp.imr.w & mask) ? "" : "Mask", // %0 でマスクする
375: (mfp.ipr.w & mask) ? "Pend" : "",
376: (mfp.isr.w & mask) ? "Serv" : "");
377: }
378:
379: // タイマー関連
380: x = 39;
381: y = 1;
382: for (int ch = 0; ch < 4; ch++) {
383: y = ch + 1;
384: monitor.Print(x, y, "Timer-%c", ch + 'A');
385: if (mfp.tcr[ch] == 0) {
386: monitor.Print(x + 8, y, "Stopped");
387: } else if (mfp.tcr[ch] == 8) {
388: monitor.Print(x + 8, y, "Event");
389: } else if (mfp.tcr[ch] > 8) {
390: monitor.Print(x + 8, y, "Pulse(%s)", prescale_str[mfp.tcr[ch] - 8]);
391: } else {
392: monitor.Print(x + 8, y, "Delay(%s)", prescale_str[mfp.tcr[ch]]);
393: }
394:
395: monitor.Print(x + 19, y, "%3d", GetTDR(ch));
396: monitor.Print(x + 23, y, "%3d", mfp.tdr[ch]);
397: }
398:
399: // GPIP 関連
400: x = 39;
401: y = 8;
1.1.1.4 root 402: monitor.Puts(x, y++, "GPIP Name GPIP AER DDR");
1.1 root 403: for (int i = 7; i >= 0; i--, y++) {
404: uint mask = (1 << i);
405: monitor.Print(x, y, "b%d %-6s %d %d %s", i, gpipname[i],
406: (mfp.gpip & mask) ? 1 : 0,
407: (mfp.aer & mask) ? 1 : 0,
408: (mfp.ddr & mask) ? "OUT" : "IN");
409: }
410: }
411:
412: /*static*/ const char *
413: MFPDevice::intrname[] = {
414: "RTC Alarm",
415: "EXPON",
416: "POW SW",
417: "FM IRQ",
418: "Timer-D",
419: "Timer-C",
420: "V-Disp",
421: "---",
422: "Timer-B",
423: "MPSC TxErr",
424: "MPSC TxEmpty",
425: "MPSC RxErr",
426: "MPSC RxFull",
427: "Timer-A",
428: "CRTC IRQ",
429: "H-Sync",
430: };
431:
432: /*static*/ const char *
433: MFPDevice::gpipname[] = {
434: "ALARM",
435: "EXPON",
436: "POW SW",
437: "FMIRQ",
438: "V-Disp",
439: "------",
440: "CIRQ",
441: "H-Sync",
442: };
443:
444: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
445: /*static*/ const int
446: MFPDevice::prescale_ns[8] = {
447: 0,
448: 1000, // /4
449: 2500, // /10
450: 4000, // /16
451: 12500, // /50
452: 16000, // /64
453: 25000, // /100
454: 50000, // /200
455: };
456:
457: /*static*/ const char *
458: MFPDevice::prescale_str[8] = {
459: "",
460: "1us",
461: "2.5us",
462: "4us",
463: "12.5us",
464: "16us",
465: "25us",
466: "50us",
467: };
468:
469: // タイマーのチャンネルからベクタ(ビット番号) に変換する
470: /*static*/ const int
1.1.1.4 root 471: MFPDevice::timer_vector[4] = {
472: MFP::INTR_TIMER_A,
473: MFP::INTR_TIMER_B,
474: MFP::INTR_TIMER_C,
475: MFP::INTR_TIMER_D,
476: };
1.1 root 477:
478: // このタイマーで割り込みを上げる必要があるかどうかを返す
479: bool
480: MFPDevice::IsTimerIntrEnable(uint ch) const
481: {
1.1.1.3 root 482: assertmsg(ch < 4, "ch=%u", ch);
1.1 root 483: __assume(ch < 4);
484:
485: // 割り込みが無効なら false
486: if ((mfp.ier.w & (1 << timer_vector[ch])) == 0) {
487: return false;
488: }
489:
490: // 割り込みがマスクされていれば false
491: if ((mfp.imr.w & (1 << timer_vector[ch])) == 0) {
492: return false;
493: }
494:
495: // そうでなければ、割り込みを上げる必要がある
496: return true;
497: }
498:
499: // TxCR をセットする
500: void
501: MFPDevice::SetTCR(int ch, uint32 data)
502: {
503: uint32 prev;
504:
505: prev = mfp.tcr[ch];
506: data &= 0x0f;
507:
508: mfp.tcr[ch] = data;
509: if (mfp.tcr[ch] > 0x08) {
510: putlog(0, "T%cCR サポートしていないモード $%02x",
511: ch + 'A', mfp.tcr[ch]);
512: return;
513: }
514: if (mfp.tcr[ch] == 8) {
515: // イベントカウントモード
516:
517: // TDR をロードする
518: mfp.initial_tdr[ch] = mfp.tdr[ch];
519: putlog(1, "Timer-%c イベントカウントモード", ch + 'A');
520: return;
521:
522: } else if (mfp.tcr[ch] == 0) {
523: // タイマー停止
524: if (prev != 0) {
525: putlog(1, "Timer-%c 停止", ch + 'A');
526: }
527: mfp.timer_start[ch] = 0;
1.1.1.3 root 528: event[ch].Stop();
1.1 root 529: return;
530:
531: } else {
532: // タイマー開始
533: int scale = prescale_ns[mfp.tcr[ch]];
534: if (prev == 0) {
535: // タイマー停止中に開始
536: // ここで initial_tdr にロード
537: mfp.initial_tdr[ch] = mfp.tdr[ch] ?: 256;
538: mfp.timer_start[ch] = gScheduler->GetVirtTime();
539: } else {
540: // タイマー動作中に(再)開始
541:
542: // タイマー動作中に TxCR に書き込むと、TxDR は影響を受けずに、
543: // プリスケーラのカウンタがリセットされる。
544: // 例えば、TCR = 0x01 (プリスケール 10)、TDR = 0x05 で、
545: // プリスケールカウントが12回進行した時点で TCR に再び 0x01
546: // (プリスケール10) が書き込まれた場合、以下のようになるはず。
547: //
548: // time ->
549: // prescale cnt| 0 1 2 3 4 5 6 7 8 9 0 1 2
550: // main count | 5 ----------------> 4 -->
551: // * ここで TCR 書き込み
552: // TCR書き込み後のprescale cnt | 0 1 2 3 4 5 6 7 8 9 0 1
553: // TCR書き込み後のmain count | 4 ----------------> 3 ->
554: uint64 ellapsed;
555: uint deccount;
556:
557: // タイマー開始時からの経過時間
558: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
559:
560: // タイマー開始時から今までのメインカウンタ減算回数
561: deccount = ellapsed / scale;
562:
563: // 再設定
564: mfp.initial_tdr[ch] -= deccount;
565: mfp.timer_start[ch] += gScheduler->GetVirtTime();
566: }
567:
568: // 割り込みを上げる必要があれば、カウントダウン終了時にイベントを
569: // 起こす。
570: // 割り込みを上げる必要がない場合は、TxDR を読み出す時に正しい値が
571: // 算出できるだけでよくて、それは timer_start 等により行えているので
572: // 他には何もしなくてよい。Timer-B 対策。
573: if (IsTimerIntrEnable(ch)) {
574: event[ch].time = mfp.initial_tdr[ch] * scale;
1.1.1.3 root 575: event[ch].Start();
1.1 root 576: }
577:
578: putlog(1, "Timer-%c ディレイモード開始(%d.%d x %d usec)",
579: ch + 'A',
580: scale / 1000,
581: (scale / 100) % 10,
582: mfp.initial_tdr[ch]);
583: }
584: }
585:
586: // TxDR の読み出し
587: // タイマーデータレジスタの現在値は保持しておらず、
588: // タイマー開始時刻と減算量が分かっているので読み出しのたびに求める。
589: // この操作に副作用はないので Peek/Monitor でも使用可能。
590: uint8
1.1.1.3 root 591: MFPDevice::GetTDR(int ch) const
1.1 root 592: {
593: uint64 ellapsed;
594: uint64 count;
595: uint32 data;
596:
597: // イベントカウントモードなら initial_tdr が読める?
598: if (mfp.tcr[ch] == 8) {
599: return mfp.initial_tdr[ch];
600: }
601:
602: // タイマー停止中なら TxDR と同じでよい?
603: if (mfp.tcr[ch] == 0) {
604: return mfp.tdr[ch];
605: }
606:
607: // タイマー開始時からの経過時間
608: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
609:
610: // タイマー開始時から現在までのメインカウンタ減算回数
611: count = ellapsed / prescale_ns[mfp.tcr[ch]];
612:
613: // カウント終了時に割り込みが上がる設定になっていれば
614: // count は必ず 0 から initail_tdr-1 までの範囲だが、
615: // カウント終了時に割り込みが上がる設定になっていない場合は
616: // 経過時間とそれに伴い count はひたすら増える。
617: // そのため initial_tdr で modulo する。
618: count %= mfp.initial_tdr[ch];
619:
620: // count は減算回数だが、
621: // TxDR レジスタの読み出し値は減算カウンタの現在値。
622: // TxDR = 10 で開始して count = 0 のうちは TxDR 読み出しは 10。
623: // TxDR = 10 で開始して count = 1 のうちは TxDR 読み出しは 9。
624: // :
625: // TxDR = 10 で開始して count = 9 のうちは TxDR 読み出しは 1。
626: data = mfp.initial_tdr[ch] - count;
627:
628: return data;
629: }
630:
631: // TxDR への書き込み
632: void
633: MFPDevice::SetTDR(int ch, uint32 data)
634: {
635: uint64 ellapsed;
636: uint64 scale;
637: uint64 period;
638: uint64 timer_end;
639:
640: mfp.tdr[ch] = data;
641:
642: // イベントカウントモードなら即ロード
643: if (mfp.tcr[ch] == 8) {
644: mfp.initial_tdr[ch] = mfp.tdr[ch];
645: }
646:
647: // カウント終了時に割り込みが上がる設定になっていれば、
648: // そのイベントコールバックで tdr を initial_tdr にロードするが、
649: // 割り込みが上がらない設定の場合、そのままでは tdr をリロードする
650: // 機会がない。そのためこのケースでは書き込み時点の次のカウント終了
651: // 時にイベントを起こす必要がある。
652: //
653: // TCR=1(プリスケール10)、TDR=5 で 38カウント目に TDR がセットされた
654: // 場合、ここから 12カウント目がリロードタイミング。
655: //
656: // pre | 0 ... 0 ... 0 ... 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
657: // main| 5 --> 4 --> 3 --> 2 ------------->*
658: // |<--------------------->|
659: // イベントを起こすまでの時間
660: if (IsTimerIntrEnable(ch) == false) {
661: // タイマー開始時から現在までの経過時間
662: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
663: // プリスケールカウント時間 (上でいう1カウントの時間)
664: scale = prescale_ns[mfp.tcr[ch]];
1.1.1.3 root 665: if (__predict_true(scale > 0)) {
666: // 1タイマー期間(上でいう50カウントに相当する時間)
667: period = scale * mfp.initial_tdr[ch];
668: // タイマー開始時から次のタイムアップ時刻までの時間
669: timer_end = ((ellapsed + period - 1) / period) * period;
670: // タイムアップ時刻
671: timer_end = mfp.timer_start[ch] + timer_end;
672: } else {
673: // タイムアップ時刻
674: timer_end = mfp.timer_start[ch];
675: }
1.1 root 676: // 現在から次のタイムアップ時刻まで
677: event[ch].time = timer_end - gScheduler->GetVirtTime();
1.1.1.3 root 678: event[ch].Start();
1.1 root 679:
680: putlog(3, "Timer-%c TDR 更新予約 %d.%09d", ch + 'A',
681: (int)(event[ch].time / (1000 * 1000 * 1000)),
682: (int)(event[ch].time % (1000 * 1000 * 1000)));
683: }
684: }
685:
686: // イベントコールバック
687: void
688: MFPDevice::TimerCallback(int arg)
689: {
690: int ch = arg;
691: int prevtdr;
692: uint64 ellapsed;
693: uint64 scale;
694: uint64 period;
695: uint64 timer_end;
696:
697: // タイムアップした時刻を計算。現在時刻ではない。
698: // 現在時刻はタイムアップした直後の命令境界の時刻なので。
699:
700: // タイマー開始時から現在までの経過時間
701: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
702: // 1プリスケール期間
703: scale = prescale_ns[mfp.tcr[ch]];
704: // 1タイマー期間
705: period = scale * mfp.initial_tdr[ch];
706: // タイマー開始時から直近のタイムアップ時刻まで
707: timer_end = (ellapsed / period) * period;
708:
709: // TxDR がゼロになったので TxDR をリロード
710: prevtdr = mfp.initial_tdr[ch];
711: mfp.initial_tdr[ch] = mfp.tdr[ch] ?: 256;
712: // 今タイムアップ時刻を次のタイマー起点に更新
713: mfp.timer_start[ch] += timer_end;
714:
715: // 割り込み有効なら
716: if (IsTimerIntrEnable(ch)) {
717: // 1タイマー期間を新しい TDR で再計算
718: period = prescale_ns[mfp.tcr[ch]] * mfp.initial_tdr[ch];
719: // イベント再設定
720: event[ch].time = period;
1.1.1.3 root 721: event[ch].Start();
1.1 root 722:
723: // 割り込みを上げる
1.1.1.4 root 724: gMPU680x0->Interrupt(this, 6, mfp.vr + timer_vector[ch]);
1.1 root 725: }
726:
727: if (mfp.initial_tdr[ch] != prevtdr) {
728: putlog(1, "Timer-%c ディレイモード更新(%u.%u x %u usec)",
729: ch + 'A',
730: (uint)(scale / 1000),
731: (uint)((scale / 100) % 10),
732: (uint)mfp.initial_tdr[ch]);
733: }
734: }
735:
736: // VDisp 入力
737: void
738: MFPDevice::SetVDisp(bool vdisp)
739: {
740: // TAI への入力はイベントカウントモードの時のみ
741: if (mfp.tcr[0] == 8) {
742: // AER が示す方向と同じエッジ方向の時
743: bool aer = (mfp.aer & (1 << MFP::GPIP_VDISP));
744: if (aer == vdisp) {
745: // カウンタを減算
746: mfp.initial_tdr[0]--;
747: if (mfp.initial_tdr[0] == 0) {
748: // 0 になったらリロード
749: mfp.initial_tdr[0] = mfp.tdr[0];
750:
751: // XXX ここで割り込みを上げる
752: }
753: }
754: }
755:
756: // GPIP への入力
757: SetGPIP(MFP::GPIP_VDISP, vdisp);
758: }
759:
760: // GPIP への入力。
761: // num はビット番号(0..7)。
762: void
763: MFPDevice::SetGPIP(int num, bool val)
764: {
765: bool aer = (mfp.aer & (1 << num));
766: bool old = (mfp.gpip & (1 << num));
767:
768: // 立ち上がりか立ち下がりで割り込みを上げる (AER による)
769: // AER OLD VAL Interrupt
770: // 0 0 0 0
771: // 0 0 1 0
772: // 0 1 0 1
773: // 0 1 1 0
774: // 1 0 0 0
775: // 1 0 1 1
776: // 1 1 0 0
777: // 1 1 1 0
1.1.1.3 root 778: if ((old != val) && (aer == val)) {
1.1 root 779: // XXX ここで割り込みを上げる
780: }
781:
782: if (val) {
783: mfp.gpip |= (1 << num);
784: } else {
785: mfp.gpip &= ~(1 << num);
786: }
787: }
1.1.1.4 root 788:
789: // UCR への書き込み
790: void
791: MFPDevice::SetUCR(uint32 data)
792: {
793: mfp.ucr = data;
794:
795: if ((mfp.ucr & MFP::UCR_CLK) == 0) {
796: putlog(0, "UCR CLK=0 未実装");
797: }
798: if (((mfp.ucr & MFP::UCR_WL) >> 5) != 0) {
799: putlog(0, "UCR WL=%d 未実装", (mfp.ucr >> 5) & 3);
800: }
801: if (((mfp.ucr & MFP::UCR_ST) >> 3) != 1) {
802: putlog(0, "UCR ST=%d 未実装", (mfp.ucr >> 3) & 3);
803: }
804: }
805:
806: // RSR への書き込み
807: void
808: MFPDevice::SetRSR(uint32 data)
809: {
810: uint32 old = mfp.rsr;
811:
812: mfp.rsr = data;
813:
814: if ((old & MFP::RSR_RE) == 0 && (mfp.rsr & MFP::RSR_RE)) {
815: // RE 0 -> 1
816: rr = true;
817: }
818: if ((old & MFP::RSR_RE) && (mfp.rsr & MFP::RSR_RE) == 0) {
819: // RE 1 -> 0
820: rr = false;
821: mfp.rsr &= 0x0f; // 上位4ビットのステータスを %0 に
822: }
823: }
824:
825: // UDR への書き込み
826: void
827: MFPDevice::SetUDR(uint32 data)
828: {
829: if ((mfp.tsr & MFP::TSR_TE)) {
830: gKeyboard->Command(data);
831: }
832: }
833:
834: // システムポート#4 の KEY CTRL の状態を受け取る。
835: void
836: MFPDevice::SetKeyCtrl(bool val)
837: {
838: key_ctrl = val;
839: putlog(1, "KEYCTRL = %d", key_ctrl);
840: }
841:
842: // RR (Receiver Ready) 線の状態を返す。true なら Ready。
843: // これはシステムポート#4 の KEY CTRL の状態も加味したもの。
844: bool
845: MFPDevice::IsRR() const
846: {
847: return rr && key_ctrl;
848: }
849:
850: // キーボードからデータを受信
851: void
852: MFPDevice::Rx(uint32 data)
853: {
854: // Ready を下げる
855: rr = false;
856:
857: key_event.code = data;
858: key_event.Start();
859: }
860:
861: // キーボードからのデータが受信し終わった頃に呼ばれるイベント。
862: void
863: MFPDevice::KeyCallback(int code)
864: {
865: // Ready を元に戻す
866: rr = true;
867:
868: mfp.udr = code;
869: mfp.rsr |= MFP::RSR_BF;
870:
871: // XXX この辺要再考察
872: mfp.isr.a |= 0x10;
873: // 割り込み有効でマスクされてない時だけ
874: if ((mfp.ier.a & 0x10) && (mfp.imr.a & 0x10)) {
875: gMPU680x0->Interrupt(this, 6, mfp.vr + MFP::INTR_RXFULL);
876: }
877: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.