|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2017 [email protected]
4: //
5:
6: #include "mfp.h"
7: #include "mpu.h"
8: #include "mystring.h"
9: #include "scheduler.h"
10:
11: MFPDevice *gMFP;
12:
13: // コンストラクタ
14: MFPDevice::MFPDevice()
15: {
16: logname = "mfp";
17: devname = "MFP";
18: devaddr = baseaddr;
19: devlen = 0x2000;
20: monitor.Init(65, 17);
21:
22: for (int ch = 0; ch < countof(event); ch++) {
23: event[ch].dev = this;
24: event[ch].func = (DeviceCallback_t)&MFPDevice::TimerCallback;
25: event[ch].code = ch;
1.1.1.2 ! root 26: event[ch].SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1 root 27: }
28: }
29:
30: // デストラクタ
31: MFPDevice::~MFPDevice()
32: {
33: }
34:
35: // MPU の RESET 命令によるリセット
36: void
37: MFPDevice::ResetSoft()
38: {
39: // TxDR, UDR, TSR はクリアされない
40:
41: // ?
42: mfp.tsr = 0x80;
43:
44: // それ以外のすべてのレジスタはクリア?
45: mfp.vr = 0;
46:
47: // タイマーはすべてストップなのでイベントを削除
48: for (int ch = 0; ch < countof(event); ch++) {
49: gScheduler->DelEvent(&event[ch]);
50: }
51:
52: // ペンディング割り込みクリア
53:
54: }
55:
56: uint64
57: MFPDevice::Read8(uint32 addr)
58: {
59: uint8 data;
60:
61: if (addr % 2 == 0)
62: return (uint64)-1;
63:
64: int n = (addr - baseaddr) / 2;
65: switch (n) {
66: case MFP::GPIP:
67: data = mfp.gpip;
68: break;
69: case MFP::AER:
70: data = mfp.aer;
71: break;
72: case MFP::DDR:
73: data = mfp.ddr;
74: break;
75: case MFP::IERA:
76: data = mfp.ier.a;
77: break;
78: case MFP::IERB:
79: data = mfp.ier.b;
80: break;
81: case MFP::IPRA:
82: data = mfp.ipr.a;
83: break;
84: case MFP::IPRB:
85: data = mfp.ipr.b;
86: break;
87: case MFP::ISRA:
88: data = mfp.isr.a;
89: break;
90: case MFP::ISRB:
91: data = mfp.isr.b;
92: break;
93: case MFP::IMRA:
94: data = mfp.imr.a;
95: break;
96: case MFP::IMRB:
97: data = mfp.imr.b;
98: break;
99: case MFP::VR:
100: data = mfp.vr;
101: break;
102: case MFP::TACR:
103: data = mfp.tcr[0];
104: break;
105: case MFP::TBCR:
106: data = mfp.tcr[1];
107: break;
108: case MFP::TCDCR:
109: data = (mfp.tcr[2] << 4) | mfp.tcr[3];
110: break;
111: case MFP::TADR:
112: data = GetTDR(0);
113: break;
114: case MFP::TBDR:
115: data = GetTDR(1);
116: break;
117: case MFP::TCDR:
118: data = GetTDR(2);
119: break;
120: case MFP::TDDR:
121: data = GetTDR(3);
122: break;
123: case MFP::SCR:
124: data = mfp.scr;
125: break;
126: case MFP::UCR:
127: data = mfp.ucr;
128: break;
129: case MFP::RSR:
130: data = mfp.rsr;
131: break;
132: case MFP::TSR:
133: data = mfp.tsr;
134: break;
135: case MFP::UDR:
136: data = mfp.udr;
137: break;
138: default:
139: return (uint64)-1;
140: }
141: return data;
142: }
143:
144: uint64
145: MFPDevice::Read16(uint32 addr)
146: {
147: return (0xff00 | Read8(addr + 1));
148: }
149:
150: uint64
151: MFPDevice::Write8(uint32 addr, uint32 data)
152: {
153: if (addr % 2 == 0)
154: return (uint64)-1;
155:
156: int n = (addr - baseaddr) / 2;
157: switch (n) {
158: case MFP::GPIP:
159: putlog(0, "GPIP <- $%02x 未実装書き込み", data);
160: mfp.gpip = data;
161: break;
162: case MFP::AER:
163: putlog(0, "AER <- $%02x 未実装書き込み", data);
164: mfp.aer = data;
165: break;
166: case MFP::DDR:
167: if (data != 0) {
168: putlog(0, "DDR <- $%02x 未実装書き込み", data);
169: }
170: mfp.ddr = data;
171: break;
172: case MFP::IERA:
173: putlog(2, "IERA <- $%02x", data);
174: mfp.ier.a = data;
175: break;
176: case MFP::IERB:
177: putlog(2, "IERB <- $%02x", data);
178: mfp.ier.b = data;
179: break;
180: case MFP::IPRA:
181: putlog(2, "IPRA <- $%02x", data);
182: mfp.ipr.a = data;
183: break;
184: case MFP::IPRB:
185: putlog(2, "IPRB <- $%02x", data);
186: mfp.ipr.b = data;
187: break;
188: case MFP::ISRA:
189: putlog(2, "ISRA <- $%02x", data);
190: mfp.isr.a = data;
191: break;
192: case MFP::ISRB:
193: putlog(2, "ISRB <- $%02x", data);
194: mfp.isr.b = data;
195: break;
196: case MFP::IMRA:
197: putlog(2, "IMRA <- $%02x", data);
198: mfp.imr.a = data;
199: break;
200: case MFP::IMRB:
201: putlog(2, "IMRB <- $%02x", data);
202: mfp.imr.b = data;
203: break;
204: case MFP::VR:
205: mfp.vr = data & 0xf0;
206: putlog(2, "VR <- $%02x", mfp.vr);
207: break;
208: case MFP::TACR:
209: putlog(2, "TACR <- $%02x", data);
210: SetTCR(0, data);
211: break;
212: case MFP::TBCR:
213: putlog(2, "TBCR <- $%02x", data);
214: SetTCR(1, data);
215: break;
216: case MFP::TCDCR:
217: putlog(2, "TCDCR <- $%02x", data);
218: SetTCR(2, data >> 4);
219: SetTCR(3, data & 7);
220: break;
221: case MFP::TADR:
222: putlog(2, "TADR <- $%02x", data);
223: SetTDR(0, data);
224: break;
225: case MFP::TBDR:
226: putlog(2, "TBDR <- $%02x", data);
227: SetTDR(1, data);
228: break;
229: case MFP::TCDR:
230: putlog(2, "TCDR <- $%02x", data);
231: SetTDR(2, data);
232: break;
233: case MFP::TDDR:
234: putlog(2, "TDDR <- $%02x", data);
235: SetTDR(3, data);
236: break;
237: case MFP::SCR:
238: putlog(0, "SCR <- $%02x 未実装書き込み", data);
239: mfp.scr = data;
240: break;
241: case MFP::UCR:
242: putlog(0, "UCR <- $%02x 未実装書き込み", data);
243: mfp.ucr = data & 0xfe;
244: break;
245: case MFP::RSR:
246: putlog(0, "RSR <- $%02x 未実装書き込み", data);
247: mfp.rsr = data;
248: break;
249: case MFP::TSR:
250: putlog(0, "TSR <- $%02x 未実装書き込み", data);
251: mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
252: break;
253: case MFP::UDR:
254: putlog(0, "UDR <- $%02x 未実装書き込み", data);
255: mfp.udr = data;
256: break;
257: default:
258: return (uint64)-1;
259: }
260: return 0;
261: }
262:
263: uint64
264: MFPDevice::Write16(uint32 addr, uint32 data)
265: {
266: return Write8(addr + 1, data);
267: }
268:
269: uint64
270: MFPDevice::Peek8(uint32 addr)
271: {
272: uint8 data;
273:
274: if (addr % 2 == 0) {
275: return (uint64)-1;
276: }
277: int n = (addr - baseaddr) / 2;
278: switch (n) {
279: case MFP::GPIP:
280: data = mfp.gpip;
281: break;
282: case MFP::AER:
283: data = mfp.aer;
284: break;
285: case MFP::DDR:
286: data = mfp.ddr;
287: break;
288: case MFP::IERA:
289: data = mfp.ier.a;
290: break;
291: case MFP::IERB:
292: data = mfp.ier.b;
293: break;
294: case MFP::IPRA:
295: data = mfp.ipr.a;
296: break;
297: case MFP::IPRB:
298: data = mfp.ipr.b;
299: break;
300: case MFP::ISRA:
301: data = mfp.isr.a;
302: break;
303: case MFP::ISRB:
304: data = mfp.isr.b;
305: break;
306: case MFP::IMRA:
307: data = mfp.imr.a;
308: break;
309: case MFP::IMRB:
310: data = mfp.imr.b;
311: break;
312: case MFP::VR:
313: data = mfp.vr;
314: break;
315: case MFP::TACR:
316: data = mfp.tcr[0];
317: break;
318: case MFP::TBCR:
319: data = mfp.tcr[1];
320: break;
321: case MFP::TCDCR:
322: data = (mfp.tcr[2] << 4) | mfp.tcr[3];
323: break;
324: case MFP::TADR:
325: data = GetTDR(0);
326: break;
327: case MFP::TBDR:
328: data = GetTDR(1);
329: break;
330: case MFP::TCDR:
331: data = GetTDR(2);
332: break;
333: case MFP::TDDR:
334: data = GetTDR(3);
335: break;
336: case MFP::SCR:
337: data = mfp.scr;
338: break;
339: case MFP::UCR:
340: data = mfp.ucr;
341: break;
342: case MFP::RSR:
343: data = mfp.rsr;
344: break;
345: case MFP::TSR:
346: data = mfp.tsr;
347: break;
348: case MFP::UDR:
349: data = mfp.udr;
350: break;
351: default:
352: data = 0xff;
353: break;
354: }
355: return data;
356: }
357:
358: bool
359: MFPDevice::MonitorUpdate()
360: {
361: int x;
362: int y;
363:
364: monitor.Clear();
365:
366: // 0 1 2 3 4 5 6
367: // 012345678901234567890123456789012345678901234567890123456789012345
368: // IER IMR IPR ISR Mode TDR Cnt
369: // An:MPSC TxEmpty Enable Mask Pend Serv Timer-A Delay(50us) 255 255
370:
371: // 割り込み関連
372: monitor.Print(0, 0, " %-12s %-6s %-4s %-4s %-4s",
373: "", "IER", "IMR", "IPR", "ISR");
374: y = 1;
375: for (int i = 15; i >= 0; i--, y++) {
376: uint16 mask = (1 << i);
377: monitor.Print(0, y, "%c%d:%-12s %-6s %-4s %-4s %-4s",
378: i >= 8 ? 'A' : 'B',
379: (i % 8),
380: intrname[i],
381: (mfp.ier.w & mask) ? "Enable" : "",
382: (mfp.imr.w & mask) ? "" : "Mask", // %0 でマスクする
383: (mfp.ipr.w & mask) ? "Pend" : "",
384: (mfp.isr.w & mask) ? "Serv" : "");
385: }
386:
387: // タイマー関連
388: x = 39;
389: y = 1;
390: for (int ch = 0; ch < 4; ch++) {
391: y = ch + 1;
392: monitor.Print(x, y, "Timer-%c", ch + 'A');
393: if (mfp.tcr[ch] == 0) {
394: monitor.Print(x + 8, y, "Stopped");
395: } else if (mfp.tcr[ch] == 8) {
396: monitor.Print(x + 8, y, "Event");
397: } else if (mfp.tcr[ch] > 8) {
398: monitor.Print(x + 8, y, "Pulse(%s)", prescale_str[mfp.tcr[ch] - 8]);
399: } else {
400: monitor.Print(x + 8, y, "Delay(%s)", prescale_str[mfp.tcr[ch]]);
401: }
402:
403: monitor.Print(x + 19, y, "%3d", GetTDR(ch));
404: monitor.Print(x + 23, y, "%3d", mfp.tdr[ch]);
405: }
406:
407: // GPIP 関連
408: x = 39;
409: y = 8;
410: monitor.Print(x, y++, "GPIP Name GPIP AER DDR");
411: for (int i = 7; i >= 0; i--, y++) {
412: uint mask = (1 << i);
413: monitor.Print(x, y, "b%d %-6s %d %d %s", i, gpipname[i],
414: (mfp.gpip & mask) ? 1 : 0,
415: (mfp.aer & mask) ? 1 : 0,
416: (mfp.ddr & mask) ? "OUT" : "IN");
417: }
418:
419: return true;
420: }
421:
422: /*static*/ const char *
423: MFPDevice::intrname[] = {
424: "RTC Alarm",
425: "EXPON",
426: "POW SW",
427: "FM IRQ",
428: "Timer-D",
429: "Timer-C",
430: "V-Disp",
431: "---",
432: "Timer-B",
433: "MPSC TxErr",
434: "MPSC TxEmpty",
435: "MPSC RxErr",
436: "MPSC RxFull",
437: "Timer-A",
438: "CRTC IRQ",
439: "H-Sync",
440: };
441:
442: /*static*/ const char *
443: MFPDevice::gpipname[] = {
444: "ALARM",
445: "EXPON",
446: "POW SW",
447: "FMIRQ",
448: "V-Disp",
449: "------",
450: "CIRQ",
451: "H-Sync",
452: };
453:
454: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
455: /*static*/ const int
456: MFPDevice::prescale_ns[8] = {
457: 0,
458: 1000, // /4
459: 2500, // /10
460: 4000, // /16
461: 12500, // /50
462: 16000, // /64
463: 25000, // /100
464: 50000, // /200
465: };
466:
467: /*static*/ const char *
468: MFPDevice::prescale_str[8] = {
469: "",
470: "1us",
471: "2.5us",
472: "4us",
473: "12.5us",
474: "16us",
475: "25us",
476: "50us",
477: };
478:
479: // タイマーのチャンネルからベクタ(ビット番号) に変換する
480: /*static*/ const int
481: MFPDevice::timer_vector[4] = { 13, 8, 5, 4 };
482:
483: // このタイマーで割り込みを上げる必要があるかどうかを返す
484: bool
485: MFPDevice::IsTimerIntrEnable(uint ch) const
486: {
487: assert(ch < 4);
488: __assume(ch < 4);
489:
490: // 割り込みが無効なら false
491: if ((mfp.ier.w & (1 << timer_vector[ch])) == 0) {
492: return false;
493: }
494:
495: // 割り込みがマスクされていれば false
496: if ((mfp.imr.w & (1 << timer_vector[ch])) == 0) {
497: return false;
498: }
499:
500: // そうでなければ、割り込みを上げる必要がある
501: return true;
502: }
503:
504: // TxCR をセットする
505: void
506: MFPDevice::SetTCR(int ch, uint32 data)
507: {
508: uint32 prev;
509:
510: prev = mfp.tcr[ch];
511: data &= 0x0f;
512:
513: mfp.tcr[ch] = data;
514: if (mfp.tcr[ch] > 0x08) {
515: putlog(0, "T%cCR サポートしていないモード $%02x",
516: ch + 'A', mfp.tcr[ch]);
517: return;
518: }
519: if (mfp.tcr[ch] == 8) {
520: // イベントカウントモード
521:
522: // TDR をロードする
523: mfp.initial_tdr[ch] = mfp.tdr[ch];
524: putlog(1, "Timer-%c イベントカウントモード", ch + 'A');
525: return;
526:
527: } else if (mfp.tcr[ch] == 0) {
528: // タイマー停止
529: if (prev != 0) {
530: putlog(1, "Timer-%c 停止", ch + 'A');
531: }
532: mfp.timer_start[ch] = 0;
533: gScheduler->DelEvent(&event[ch]);
534: return;
535:
536: } else {
537: // タイマー開始
538: int scale = prescale_ns[mfp.tcr[ch]];
539: if (prev == 0) {
540: // タイマー停止中に開始
541: // ここで initial_tdr にロード
542: mfp.initial_tdr[ch] = mfp.tdr[ch] ?: 256;
543: mfp.timer_start[ch] = gScheduler->GetVirtTime();
544: } else {
545: // タイマー動作中に(再)開始
546:
547: // タイマー動作中に TxCR に書き込むと、TxDR は影響を受けずに、
548: // プリスケーラのカウンタがリセットされる。
549: // 例えば、TCR = 0x01 (プリスケール 10)、TDR = 0x05 で、
550: // プリスケールカウントが12回進行した時点で TCR に再び 0x01
551: // (プリスケール10) が書き込まれた場合、以下のようになるはず。
552: //
553: // time ->
554: // prescale cnt| 0 1 2 3 4 5 6 7 8 9 0 1 2
555: // main count | 5 ----------------> 4 -->
556: // * ここで TCR 書き込み
557: // TCR書き込み後のprescale cnt | 0 1 2 3 4 5 6 7 8 9 0 1
558: // TCR書き込み後のmain count | 4 ----------------> 3 ->
559: uint64 ellapsed;
560: uint deccount;
561:
562: // タイマー開始時からの経過時間
563: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
564:
565: // タイマー開始時から今までのメインカウンタ減算回数
566: deccount = ellapsed / scale;
567:
568: // 再設定
569: mfp.initial_tdr[ch] -= deccount;
570: mfp.timer_start[ch] += gScheduler->GetVirtTime();
571: }
572:
573: // 割り込みを上げる必要があれば、カウントダウン終了時にイベントを
574: // 起こす。
575: // 割り込みを上げる必要がない場合は、TxDR を読み出す時に正しい値が
576: // 算出できるだけでよくて、それは timer_start 等により行えているので
577: // 他には何もしなくてよい。Timer-B 対策。
578: if (IsTimerIntrEnable(ch)) {
579: event[ch].time = mfp.initial_tdr[ch] * scale;
580: gScheduler->AddEvent(&event[ch]);
581: }
582:
583: putlog(1, "Timer-%c ディレイモード開始(%d.%d x %d usec)",
584: ch + 'A',
585: scale / 1000,
586: (scale / 100) % 10,
587: mfp.initial_tdr[ch]);
588: }
589: }
590:
591: // TxDR の読み出し
592: // タイマーデータレジスタの現在値は保持しておらず、
593: // タイマー開始時刻と減算量が分かっているので読み出しのたびに求める。
594: // この操作に副作用はないので Peek/Monitor でも使用可能。
595: uint8
596: MFPDevice::GetTDR(int ch)
597: {
598: uint64 ellapsed;
599: uint64 count;
600: uint32 data;
601:
602: // イベントカウントモードなら initial_tdr が読める?
603: if (mfp.tcr[ch] == 8) {
604: return mfp.initial_tdr[ch];
605: }
606:
607: // タイマー停止中なら TxDR と同じでよい?
608: if (mfp.tcr[ch] == 0) {
609: return mfp.tdr[ch];
610: }
611:
612: // タイマー開始時からの経過時間
613: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
614:
615: // タイマー開始時から現在までのメインカウンタ減算回数
616: count = ellapsed / prescale_ns[mfp.tcr[ch]];
617:
618: // カウント終了時に割り込みが上がる設定になっていれば
619: // count は必ず 0 から initail_tdr-1 までの範囲だが、
620: // カウント終了時に割り込みが上がる設定になっていない場合は
621: // 経過時間とそれに伴い count はひたすら増える。
622: // そのため initial_tdr で modulo する。
623: count %= mfp.initial_tdr[ch];
624:
625: // count は減算回数だが、
626: // TxDR レジスタの読み出し値は減算カウンタの現在値。
627: // TxDR = 10 で開始して count = 0 のうちは TxDR 読み出しは 10。
628: // TxDR = 10 で開始して count = 1 のうちは TxDR 読み出しは 9。
629: // :
630: // TxDR = 10 で開始して count = 9 のうちは TxDR 読み出しは 1。
631: data = mfp.initial_tdr[ch] - count;
632:
633: return data;
634: }
635:
636: // TxDR への書き込み
637: void
638: MFPDevice::SetTDR(int ch, uint32 data)
639: {
640: uint64 ellapsed;
641: uint64 scale;
642: uint64 period;
643: uint64 timer_end;
644:
645: mfp.tdr[ch] = data;
646:
647: // イベントカウントモードなら即ロード
648: if (mfp.tcr[ch] == 8) {
649: mfp.initial_tdr[ch] = mfp.tdr[ch];
650: }
651:
652: // カウント終了時に割り込みが上がる設定になっていれば、
653: // そのイベントコールバックで tdr を initial_tdr にロードするが、
654: // 割り込みが上がらない設定の場合、そのままでは tdr をリロードする
655: // 機会がない。そのためこのケースでは書き込み時点の次のカウント終了
656: // 時にイベントを起こす必要がある。
657: //
658: // TCR=1(プリスケール10)、TDR=5 で 38カウント目に TDR がセットされた
659: // 場合、ここから 12カウント目がリロードタイミング。
660: //
661: // 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
662: // main| 5 --> 4 --> 3 --> 2 ------------->*
663: // |<--------------------->|
664: // イベントを起こすまでの時間
665: if (IsTimerIntrEnable(ch) == false) {
666: // タイマー開始時から現在までの経過時間
667: ellapsed = gScheduler->GetVirtTime() - mfp.timer_start[ch];
668: // プリスケールカウント時間 (上でいう1カウントの時間)
669: scale = prescale_ns[mfp.tcr[ch]];
670: // 1タイマー期間(上でいう50カウントに相当する時間)
671: period = scale * mfp.initial_tdr[ch];
672: // タイマー開始時から次のタイムアップ時刻までの時間
673: timer_end = ((ellapsed + period - 1) / period) * period;
674: // タイムアップ時刻
675: timer_end = mfp.timer_start[ch] + timer_end;
676: // 現在から次のタイムアップ時刻まで
677: event[ch].time = timer_end - gScheduler->GetVirtTime();
678: gScheduler->AddEvent(&event[ch]);
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;
721: gScheduler->AddEvent(&event[ch]);
722:
723: // 割り込みを上げる
724: gMPU->Interrupt(6, mfp.vr + timer_vector[ch]);
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
778: if ((old != val) & (aer == val)) {
779: // XXX ここで割り込みを上げる
780: }
781:
782: if (val) {
783: mfp.gpip |= (1 << num);
784: } else {
785: mfp.gpip &= ~(1 << num);
786: }
787: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.