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