|
|
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.12 root 7: //
8: // MFP (MC68901)
9: //
10:
1.1 root 11: #include "mfp.h"
1.1.1.7 root 12: #include "interrupt.h"
13: #include "keyboard.h"
1.1.1.12 root 14: #include "mpu.h"
15: #include "scheduler.h"
1.1.1.9 root 16: #include "x68kkbd.h"
1.1 root 17:
1.1.1.15 root 18: // InsideOut p.135
19: static const busdata wait = busdata::Wait(24 * 40_nsec);
20:
1.1 root 21: // コンストラクタ
22: MFPDevice::MFPDevice()
1.1.1.14 root 23: : inherited(OBJ_MFP)
1.1 root 24: {
1.1.1.12 root 25: monitor.func = ToMonitorCallback(&MFPDevice::MonitorUpdate);
1.1.1.10 root 26: monitor.SetSize(77, 26);
27: monitor.Regist(ID_MONITOR_MFP);
1.1 root 28: }
29:
30: // デストラクタ
31: MFPDevice::~MFPDevice()
32: {
1.1.1.14 root 33: }
34:
35: // 初期化
36: bool
37: MFPDevice::Init()
38: {
39: if (inherited::Init() == false) {
40: return false;
41: }
42:
43: interrupt = GetInterruptDevice();
44: keyboard = dynamic_cast<X68030Keyboard *>(GetKeyboard());
45:
1.1.1.16! root 46: for (int ch = 0; ch < event.size(); ch++) {
! 47: event[ch].dev = this;
! 48: event[ch].func = ToEventCallback(&MFPDevice::TimerCallback);
! 49: event[ch].code = ch;
! 50: event[ch].SetName(string_format("MFP Timer-%c", ch + 'A'));
! 51: scheduler->RegistEvent(event[ch]);
! 52: }
! 53:
! 54: // キーボード周りは x68kkbd.cpp のコメント参照
! 55: key_event.func = ToEventCallback(&MFPDevice::KeyCallback);
! 56: key_event.time = 3750_usec;
! 57: key_event.SetName("MFP USART");
! 58: scheduler->RegistEvent(key_event);
! 59:
1.1.1.14 root 60: return true;
1.1 root 61: }
62:
1.1.1.12 root 63: // リセット
1.1.1.6 root 64: void
1.1.1.12 root 65: MFPDevice::ResetHard(bool poweron)
1.1.1.6 root 66: {
1.1.1.15 root 67: // 3.3 RESET OPERATION には
1.1.1.6 root 68: // All internal registers are cleared expect the TxDR, UDR, and TSR.
1.1.1.15 root 69: // と書いてあるが、6.2.1 には TxDR はリセット時に $00 と書いてある。
70: // 内部カウンタは影響を受けずに next_tdr だけリセットされるという
71: // 意味だろうか。
1.1.1.6 root 72: mfp.aer = 0;
73: mfp.ddr = 0;
74: mfp.ier.w = 0;
75: mfp.ipr.w = 0;
76: mfp.isr.w = 0;
77: mfp.imr.w = 0;
1.1.1.16! root 78: for (int i = 0; i < countof(mfp.timer); i++) {
! 79: mfp.timer[i].tcr = 0;
! 80: mfp.timer[i].next_tdr = 256;
1.1.1.6 root 81: }
82: mfp.scr = 0;
83: mfp.ucr = 0;
84: mfp.rsr = 0;
85: // XXX TSR は変化しないがたぶんバッファはクリアされるので BE は立つ
86: // ということかな。
87: mfp.tsr = MFP::TSR_BE;
1.1 root 88:
1.1.1.6 root 89: // All timers are stopped.
1.1.1.11 root 90: for (auto& ev : event) {
1.1.1.14 root 91: scheduler->StopEvent(ev);
1.1 root 92: }
1.1.1.14 root 93: scheduler->StopEvent(key_event);
1.1 root 94:
1.1.1.6 root 95: // USART RX and TX are disabled.
96: // SO line is placed in HighZ.
97: // The interrupt channels are disabled, and
98: // any pending interrupts are cleared.
99: // GPIO lines are placed in HighZ.
100: // timer outputs are driven low.
101: // External signals are nagated.
102: // VR is initialized to $00 (not $0f).
1.1.1.7 root 103: mfp.vr_vec = 0;
104: mfp.vr_s = 0;
1.1.1.13 root 105:
106: // CIRQ | FMIRQ | EXPON | ALARM にしておく
107: mfp.gpip = 0x6b;
1.1.1.15 root 108:
109: ChangeInterrupt();
1.1.1.3 root 110: }
111:
1.1.1.15 root 112: busdata
1.1.1.16! root 113: MFPDevice::ReadPort(uint32 offset)
1.1 root 114: {
1.1.1.15 root 115: busdata data;
1.1.1.6 root 116:
1.1.1.8 root 117: switch (offset) {
1.1 root 118: case MFP::GPIP:
119: data = mfp.gpip;
120: break;
121: case MFP::AER:
122: data = mfp.aer;
123: break;
124: case MFP::DDR:
125: data = mfp.ddr;
126: break;
127: case MFP::IERA:
128: data = mfp.ier.a;
129: break;
130: case MFP::IERB:
131: data = mfp.ier.b;
132: break;
133: case MFP::IPRA:
134: data = mfp.ipr.a;
135: break;
136: case MFP::IPRB:
137: data = mfp.ipr.b;
138: break;
139: case MFP::ISRA:
140: data = mfp.isr.a;
141: break;
142: case MFP::ISRB:
143: data = mfp.isr.b;
144: break;
145: case MFP::IMRA:
146: data = mfp.imr.a;
147: break;
148: case MFP::IMRB:
149: data = mfp.imr.b;
150: break;
151: case MFP::VR:
1.1.1.7 root 152: data = mfp.GetVR();
1.1 root 153: break;
154: case MFP::TACR:
1.1.1.16! root 155: data = mfp.timer[0].tcr;
1.1 root 156: break;
157: case MFP::TBCR:
1.1.1.16! root 158: data = mfp.timer[1].tcr;
1.1 root 159: break;
160: case MFP::TCDCR:
1.1.1.16! root 161: data = mfp.GetTCDCR();
1.1 root 162: break;
163: case MFP::TADR:
164: data = GetTDR(0);
165: break;
166: case MFP::TBDR:
167: data = GetTDR(1);
168: break;
169: case MFP::TCDR:
170: data = GetTDR(2);
171: break;
172: case MFP::TDDR:
173: data = GetTDR(3);
174: break;
175: case MFP::SCR:
176: data = mfp.scr;
177: break;
178: case MFP::UCR:
179: data = mfp.ucr;
180: break;
181: case MFP::RSR:
182: data = mfp.rsr;
183: break;
184: case MFP::TSR:
185: data = mfp.tsr;
186: break;
187: case MFP::UDR:
1.1.1.9 root 188: // UDR からデータを読み出したら Buffer Full をクリア
1.1 root 189: data = mfp.udr;
1.1.1.9 root 190: ClearBF();
1.1 root 191: break;
1.1.1.4 root 192: default:
193: data = 0xff;
194: break;
1.1 root 195: }
1.1.1.15 root 196:
1.1.1.16! root 197: if (__predict_false(loglevel >= 3)) {
! 198: if (offset == MFP::TCDR) {
! 199: putlog(4, "%s -> $%02x", regname[offset], data.Data());
! 200: } else if (offset < MFP::RegMax) {
! 201: putlogn("%s -> $%02x", regname[offset], data.Data());
! 202: } else {
! 203: putlogn("$%06x -> $%02x", mpu->GetPaddr(), data.Data());
! 204: }
! 205: }
1.1.1.15 root 206: data |= wait;
1.1.1.16! root 207: data |= BusData::Size1;
1.1 root 208: return data;
209: }
210:
1.1.1.15 root 211: busdata
1.1.1.16! root 212: MFPDevice::WritePort(uint32 offset, uint32 data)
1.1 root 213: {
1.1.1.8 root 214: switch (offset) {
1.1 root 215: case MFP::GPIP:
1.1.1.13 root 216: putlog(0, "Write GPIP <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 217: mfp.gpip = data;
218: break;
219: case MFP::AER:
1.1.1.16! root 220: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 221: mfp.aer = data;
222: break;
223: case MFP::DDR:
224: if (data != 0) {
1.1.1.13 root 225: putlog(0, "Write DDR <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 226: }
227: mfp.ddr = data;
228: break;
229: case MFP::IERA:
1.1.1.16! root 230: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.15 root 231: SetIER(mfp.ier.a, mfp.ipr.a, data);
1.1 root 232: break;
233: case MFP::IERB:
1.1.1.16! root 234: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.15 root 235: SetIER(mfp.ier.b, mfp.ipr.b, data);
1.1 root 236: break;
237: case MFP::IPRA:
1.1.1.16! root 238: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 239: mfp.ipr.a = data;
1.1.1.7 root 240: ChangeInterrupt();
1.1 root 241: break;
242: case MFP::IPRB:
1.1.1.16! root 243: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 244: mfp.ipr.b = data;
1.1.1.7 root 245: ChangeInterrupt();
1.1 root 246: break;
247: case MFP::ISRA:
1.1.1.16! root 248: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 249: mfp.isr.a = data;
250: break;
251: case MFP::ISRB:
1.1.1.16! root 252: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 253: mfp.isr.b = data;
254: break;
255: case MFP::IMRA:
1.1.1.16! root 256: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 257: mfp.imr.a = data;
1.1.1.7 root 258: ChangeInterrupt();
1.1 root 259: break;
260: case MFP::IMRB:
1.1.1.16! root 261: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 262: mfp.imr.b = data;
1.1.1.7 root 263: ChangeInterrupt();
1.1 root 264: break;
265: case MFP::VR:
1.1.1.7 root 266: mfp.vr_vec = data & 0xf0;
267: mfp.vr_s = data & 0x08;
1.1.1.16! root 268: putlog(2, "%s <- $%02x", regname[offset], mfp.GetVR());
1.1 root 269: break;
270: case MFP::TACR:
1.1.1.16! root 271: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 272: SetTCR(0, data);
273: break;
274: case MFP::TBCR:
1.1.1.16! root 275: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 276: SetTCR(1, data);
277: break;
278: case MFP::TCDCR:
1.1.1.16! root 279: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 280: SetTCR(2, data >> 4);
281: SetTCR(3, data & 7);
282: break;
283: case MFP::TADR:
1.1.1.16! root 284: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 285: SetTDR(0, data);
286: break;
287: case MFP::TBDR:
1.1.1.16! root 288: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 289: SetTDR(1, data);
290: break;
291: case MFP::TCDR:
1.1.1.16! root 292: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 293: SetTDR(2, data);
294: break;
295: case MFP::TDDR:
1.1.1.16! root 296: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 297: SetTDR(3, data);
298: break;
299: case MFP::SCR:
1.1.1.13 root 300: putlog(0, "SCR <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 301: mfp.scr = data;
302: break;
303: case MFP::UCR:
1.1.1.16! root 304: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4 root 305: SetUCR(data);
1.1 root 306: break;
307: case MFP::RSR:
1.1.1.16! root 308: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4 root 309: SetRSR(data);
1.1 root 310: break;
311: case MFP::TSR:
1.1.1.13 root 312: if ((data & 0x0e)) {
313: // SO 端子関係の B, H, L ビットは未実装
314: putlog(0, "TSR <- $%02x (B,H,L bit NOT IMPLEMENTED)", data);
315: }
1.1 root 316: mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
317: break;
318: case MFP::UDR:
1.1.1.16! root 319: if (__predict_false(loglevel >= 2)) {
! 320: if (data == 0x40 || data == 0x41) {
! 321: // MSCTRL だけ頻度が高いのでログレベルを上げておく
! 322: putlog(3, "%s <- $%02x", regname[offset], data);
! 323: } else {
! 324: putlogn("%s <- $%02x", regname[offset], data);
! 325: }
1.1.1.4 root 326: }
327: SetUDR(data);
328: break;
329: default:
1.1 root 330: break;
331: }
1.1.1.15 root 332:
1.1.1.16! root 333: busdata r = wait;
! 334: r |= BusData::Size1;
! 335: return r;
1.1 root 336: }
337:
1.1.1.15 root 338: busdata
1.1.1.16! root 339: MFPDevice::PeekPort(uint32 offset)
1.1 root 340: {
341: uint8 data;
342:
1.1.1.8 root 343: switch (offset) {
1.1 root 344: case MFP::GPIP:
345: data = mfp.gpip;
346: break;
347: case MFP::AER:
348: data = mfp.aer;
349: break;
350: case MFP::DDR:
351: data = mfp.ddr;
352: break;
353: case MFP::IERA:
354: data = mfp.ier.a;
355: break;
356: case MFP::IERB:
357: data = mfp.ier.b;
358: break;
359: case MFP::IPRA:
360: data = mfp.ipr.a;
361: break;
362: case MFP::IPRB:
363: data = mfp.ipr.b;
364: break;
365: case MFP::ISRA:
366: data = mfp.isr.a;
367: break;
368: case MFP::ISRB:
369: data = mfp.isr.b;
370: break;
371: case MFP::IMRA:
372: data = mfp.imr.a;
373: break;
374: case MFP::IMRB:
375: data = mfp.imr.b;
376: break;
377: case MFP::VR:
1.1.1.7 root 378: data = mfp.GetVR();
1.1 root 379: break;
380: case MFP::TACR:
1.1.1.16! root 381: data = mfp.timer[0].tcr;
1.1 root 382: break;
383: case MFP::TBCR:
1.1.1.16! root 384: data = mfp.timer[1].tcr;
1.1 root 385: break;
386: case MFP::TCDCR:
1.1.1.16! root 387: data = mfp.GetTCDCR();
1.1 root 388: break;
389: case MFP::TADR:
390: data = GetTDR(0);
391: break;
392: case MFP::TBDR:
393: data = GetTDR(1);
394: break;
395: case MFP::TCDR:
396: data = GetTDR(2);
397: break;
398: case MFP::TDDR:
399: data = GetTDR(3);
400: break;
401: case MFP::SCR:
402: data = mfp.scr;
403: break;
404: case MFP::UCR:
405: data = mfp.ucr;
406: break;
407: case MFP::RSR:
408: data = mfp.rsr;
409: break;
410: case MFP::TSR:
411: data = mfp.tsr;
412: break;
413: case MFP::UDR:
414: data = mfp.udr;
415: break;
1.1.1.4 root 416: default:
417: data = 0xff;
1.1 root 418: }
419: return data;
420: }
421:
1.1.1.16! root 422: bool
! 423: MFPDevice::PokePort(uint32 offset, uint32 data)
! 424: {
! 425: return false;
! 426: }
! 427:
1.1.1.5 root 428: void
1.1.1.10 root 429: MFPDevice::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 430: {
1.1.1.15 root 431: MFP mfp_;
432: std::array<uint8, 4> tdr_;
1.1 root 433: int x;
434: int y;
435:
1.1.1.15 root 436: // ローカルにコピー。
437: memcpy(&mfp_, &mfp, sizeof(mfp));
438: for (int ch = 0; ch < tdr_.size(); ch++) {
439: tdr_[ch] = GetTDR(ch);
440: }
441:
1.1.1.10 root 442: screen.Clear();
1.1 root 443:
444: // 0 1 2 3 4 5 6
1.1.1.7 root 445: // 01234567890123456789012345678901234567890123456789012345678901234567890
446: // $e88001(GPIP):$00 $e88007(IERA):$00 $e88019(TACR):$00 $e88027
1.1.1.13 root 447: // IER IMR IPR ISR Mode TDR Cnt
448: // An:MPSC TxEmpty Enable Mask Pend Serv Timer-A Delay(50us) 255 255
1.1 root 449:
1.1.1.7 root 450: #define A(x) (baseaddr + (x * 2) + 1)
451:
452: // レジスタ生値
453: // 1列目(GPIP 関連と VR)
454: x = 0;
455: y = 0;
1.1.1.15 root 456: screen.Print(x, y++, "$%06x(GPIP):$%02x", A(MFP::GPIP), mfp_.gpip);
457: screen.Print(x, y++, "$%06x(AER): $%02x", A(MFP::AER), mfp_.aer);
458: screen.Print(x, y++, "$%06x(DDR): $%02x", A(MFP::DDR), mfp_.ddr);
459: screen.Print(x, y++, "$%06x(VR): $%02x", A(MFP::VR), mfp_.GetVR());
1.1.1.7 root 460: // 2列目(割り込み関連)
461: x = 20;
462: y = 0;
1.1.1.15 root 463: screen.Print(x, y++, "$%06x(IERA):$%02x", A(MFP::IERA), mfp_.ier.a);
464: screen.Print(x, y++, "$%06x(IERB):$%02x", A(MFP::IERB), mfp_.ier.b);
465: screen.Print(x, y++, "$%06x(IPRA):$%02x", A(MFP::IPRA), mfp_.ipr.a);
466: screen.Print(x, y++, "$%06x(IPRB):$%02x", A(MFP::IPRB), mfp_.ipr.b);
467: screen.Print(x, y++, "$%06x(ISRA):$%02x", A(MFP::ISRA), mfp_.isr.a);
468: screen.Print(x, y++, "$%06x(ISRB):$%02x", A(MFP::ISRB), mfp_.isr.b);
469: screen.Print(x, y++, "$%06x(IMRA):$%02x", A(MFP::IMRA), mfp_.imr.a);
470: screen.Print(x, y++, "$%06x(IMRB):$%02x", A(MFP::IMRB), mfp_.imr.b);
1.1.1.7 root 471: // 3列目(タイマー関連)
472: x = 40;
473: y = 0;
1.1.1.16! root 474: screen.Print(x, y++, "$%06x(TACR): $%02x", A(MFP::TACR), mfp_.timer[0].tcr);
! 475: screen.Print(x, y++, "$%06x(TBCR): $%02x", A(MFP::TBCR), mfp_.timer[1].tcr);
! 476: screen.Print(x, y++, "$%06x(TCDCR):$%02x", A(MFP::TCDCR), mfp_.GetTCDCR());
1.1.1.15 root 477: screen.Print(x, y++, "$%06x(TADR): $%02x", A(MFP::TADR), tdr_[0]);
478: screen.Print(x, y++, "$%06x(TBDR): $%02x", A(MFP::TBDR), tdr_[1]);
479: screen.Print(x, y++, "$%06x(TCDR): $%02x", A(MFP::TCDR), tdr_[2]);
480: screen.Print(x, y++, "$%06x(TDDR): $%02x", A(MFP::TDDR), tdr_[3]);
1.1.1.7 root 481: // 4列目(USART 関連)
482: x = 61;
483: y = 0;
1.1.1.15 root 484: screen.Print(x, y++, "$%06x(SCR):$%02x", A(MFP::SCR), mfp_.scr);
485: screen.Print(x, y++, "$%06x(UCR):$%02x", A(MFP::UCR), mfp_.ucr);
486: screen.Print(x, y++, "$%06x(RSR):$%02x", A(MFP::RSR), mfp_.rsr);
487: screen.Print(x, y++, "$%06x(TSR):$%02x", A(MFP::TSR), mfp_.tsr);
1.1.1.10 root 488: screen.Print(x, y, "$%06x(UDR):", A(MFP::UDR));
1.1.1.15 root 489: if ((int16)mfp_.udr >= 0) {
490: screen.Print(x + 13, y, "$%02x", mfp_.udr);
1.1.1.7 root 491: } else {
1.1.1.10 root 492: screen.Print(x + 13, y, "---");
1.1.1.7 root 493: }
494:
1.1 root 495: // 割り込み関連
1.1.1.7 root 496: y = 9;
1.1.1.10 root 497: screen.Print(0, y++, "<Interrupt> %-6s %-4s %-4s %-4s",
1.1.1.7 root 498: "IER", "IMR", "IPR", "ISR");
1.1 root 499: for (int i = 15; i >= 0; i--, y++) {
500: uint16 mask = (1 << i);
1.1.1.16! root 501: screen.Print(0, y, "%c%u:%-12s %-6s %-4s %-4s %-4s",
1.1 root 502: i >= 8 ? 'A' : 'B',
503: (i % 8),
504: intrname[i],
1.1.1.15 root 505: (mfp_.ier.w & mask) ? "Enable" : "",
506: (mfp_.imr.w & mask) ? "" : "Mask", // %0 でマスクする
507: (mfp_.ipr.w & mask) ? "Pend" : "",
508: (mfp_.isr.w & mask) ? "Serv" : "");
1.1 root 509: }
510:
511: // タイマー関連
1.1.1.13 root 512: x = 40;
1.1.1.7 root 513: y = 9;
1.1.1.15 root 514: screen.Print(x, y++, "<Timer> Mode TDR Next");
1.1 root 515: for (int ch = 0; ch < 4; ch++) {
1.1.1.10 root 516: screen.Print(x, y, "Timer-%c", ch + 'A');
1.1.1.16! root 517: uint8 tcr = mfp_.timer[ch].tcr;
! 518: if (tcr == 0) {
1.1.1.10 root 519: screen.Print(x + 8, y, "Stopped");
1.1.1.16! root 520: } else if (tcr == 8) {
1.1.1.10 root 521: screen.Print(x + 8, y, "Event");
1.1.1.16! root 522: } else if (tcr > 8) {
! 523: screen.Print(x + 8, y, "Pulse(%s)", prescale_str[tcr - 8]);
1.1 root 524: } else {
1.1.1.16! root 525: screen.Print(x + 8, y, "Delay(%s)", prescale_str[tcr]);
1.1 root 526: }
527:
1.1.1.16! root 528: screen.Print(x + 20, y, "%3u", tdr_[ch]);
! 529: screen.Print(x + 25, y, "%3u", mfp_.timer[ch].next_tdr & 0xff);
1.1.1.7 root 530: y++;
1.1 root 531: }
532:
533: // GPIP 関連
1.1.1.13 root 534: x = 40;
1.1.1.7 root 535: y = 9 + 8;
1.1.1.10 root 536: screen.Puts(x, y++, "<GPIP> GPIP AER DDR");
1.1 root 537: for (int i = 7; i >= 0; i--, y++) {
538: uint mask = (1 << i);
1.1.1.16! root 539: screen.Print(x, y, "b%u %-6s %u %u %s", i, gpipname[i],
1.1.1.15 root 540: (mfp_.gpip & mask) ? 1 : 0,
541: (mfp_.aer & mask) ? 1 : 0,
542: (mfp_.ddr & mask) ? "OUT" : "IN");
1.1 root 543: }
544: }
545:
546: /*static*/ const char *
547: MFPDevice::intrname[] = {
548: "RTC Alarm",
549: "EXPON",
550: "POW SW",
551: "FM IRQ",
552: "Timer-D",
553: "Timer-C",
554: "V-Disp",
555: "---",
556: "Timer-B",
557: "MPSC TxErr",
558: "MPSC TxEmpty",
559: "MPSC RxErr",
560: "MPSC RxFull",
561: "Timer-A",
562: "CRTC IRQ",
563: "H-Sync",
564: };
565:
566: /*static*/ const char *
567: MFPDevice::gpipname[] = {
568: "ALARM",
569: "EXPON",
570: "POW SW",
571: "FMIRQ",
572: "V-Disp",
573: "------",
574: "CIRQ",
575: "H-Sync",
576: };
577:
578: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
1.1.1.16! root 579: /*static*/ const uint
1.1 root 580: MFPDevice::prescale_ns[8] = {
581: 0,
582: 1000, // /4
583: 2500, // /10
584: 4000, // /16
585: 12500, // /50
586: 16000, // /64
587: 25000, // /100
588: 50000, // /200
589: };
590:
591: /*static*/ const char *
592: MFPDevice::prescale_str[8] = {
593: "",
594: "1us",
595: "2.5us",
596: "4us",
597: "12.5us",
598: "16us",
599: "25us",
600: "50us",
601: };
602:
1.1.1.7 root 603: // タイマーのチャンネルから MFP 割り込みチャンネル番号に変換する
1.1.1.16! root 604: /*static*/ const uint
1.1.1.4 root 605: MFPDevice::timer_vector[4] = {
606: MFP::INTR_TIMER_A,
607: MFP::INTR_TIMER_B,
608: MFP::INTR_TIMER_C,
609: MFP::INTR_TIMER_D,
610: };
1.1 root 611:
1.1.1.15 root 612: // IER[AB] に data をセットする
613: void
614: MFPDevice::SetIER(uint8& ier, uint8& ipr, uint32 data)
615: {
616: // clr は、data によって %1 -> %0 に変化するビットだけを立てたもの。
617: uint8 clr = ier & (ier ^ data);
618:
619: // IER を下げたところは IPR も下げる。(紙資料 p4-4)
620: ipr &= ~clr;
621:
622: // どちらにしても新しい IER によって信号線の状態は変える。
623: ier = data;
624: ChangeInterrupt();
625: }
626:
1.1 root 627: // TxCR をセットする
628: void
629: MFPDevice::SetTCR(int ch, uint32 data)
630: {
631: uint32 prev;
632:
1.1.1.16! root 633: prev = mfp.timer[ch].tcr;
1.1 root 634: data &= 0x0f;
635:
1.1.1.16! root 636: mfp.timer[ch].tcr = data;
1.1.1.7 root 637: if (data == 0) {
638: if (prev == 0) {
639: // 0 -> 0 なら何も起きない
640: return;
641: } else if (prev < 8) {
642: // タイマー停止
1.1.1.13 root 643: putlog(1, "Timer-%c Stop", ch + 'A');
1.1.1.7 root 644:
645: // ここで TDR を確定させる。
646: // タイマー動作中の TDR の参照はイベント終了時刻から現在値を逆算
647: // していたが、イベントを停止すると求められなくなるので、イベント
648: // 停止前に求めておく。
649: uint64 period = prescale_ns[prev];
1.1.1.14 root 650: uint64 now = scheduler->GetVirtTime();
1.1.1.16! root 651: mfp.timer[ch].tdr = ((event[ch].vtime - now) + period - 1) / period;
1.1.1.7 root 652:
653: // でイベント停止
1.1.1.14 root 654: scheduler->StopEvent(event[ch]);
1.1.1.7 root 655: return;
656: } else if (prev == 8) {
657: // イベントカウントモードから停止しても何も起きないはず
658: } else {
659: // パルス幅測定モード (未実装)
660: }
1.1 root 661: return;
1.1.1.7 root 662:
663: } else if (data < 8) {
664: // タイマー開始
665:
1.1.1.15 root 666: // TDR は触らずイベントを開始。
1.1.1.16! root 667: uint64 period = prescale_ns[mfp.timer[ch].tcr];
! 668: event[ch].time = period * mfp.timer[ch].tdr;
1.1.1.14 root 669: scheduler->RestartEvent(event[ch]);
1.1.1.7 root 670:
1.1.1.13 root 671: putlog(1, "Timer-%c Start Delay mode(%u x %u.%uusec)",
1.1.1.7 root 672: ch + 'A',
1.1.1.16! root 673: mfp.timer[ch].tdr,
1.1.1.7 root 674: (uint)period / 1000,
675: (uint)(period / 100) % 10);
676: return;
677:
678: } else if (data == 8) {
1.1 root 679: // イベントカウントモード
680:
681: // TDR をロードする
1.1.1.16! root 682: mfp.timer[ch].next_tdr = mfp.timer[ch].tdr;
1.1.1.13 root 683: putlog(1, "Timer-%c Event count mode", ch + 'A');
1.1 root 684: return;
685:
686: } else {
1.1.1.13 root 687: putlog(0, "T%cCR Pulse-Width Measurement Mode $%02x (NOT IMPLEMENTED)",
1.1.1.7 root 688: ch + 'A', data);
689: return;
1.1 root 690: }
691: }
692:
693: // TxDR の読み出し
1.1.1.7 root 694: // (副作用はないので Peek 系からも呼び出してよい)
1.1 root 695: uint8
1.1.1.3 root 696: MFPDevice::GetTDR(int ch) const
1.1 root 697: {
1.1.1.16! root 698: uint8 tcr = mfp.timer[ch].tcr;
1.1 root 699:
1.1.1.7 root 700: if (tcr == 0) {
701: // 停止中なら tdr に現在値が保持されている
1.1.1.16! root 702: return mfp.timer[ch].tdr & 0xff;
1.1 root 703:
1.1.1.7 root 704: } else if (tcr < 8) {
705: // ディレイモード動作中なら現在値は保持していないので、
706: // プリスケーラと終了時刻から算出。
707:
708: uint64 period = prescale_ns[tcr];
1.1.1.14 root 709: uint64 now = scheduler->GetVirtTime();
1.1.1.15 root 710: uint8 data = ((event[ch].vtime - now) + period - 1) / period;
711: return data;
1.1 root 712:
1.1.1.7 root 713: } else {
714: // イベントモード、パルス幅測定モードは未対応
1.1.1.16! root 715: return mfp.timer[ch].tdr & 0xff;
1.1 root 716:
1.1.1.7 root 717: }
1.1 root 718: }
719:
720: // TxDR への書き込み
721: void
722: MFPDevice::SetTDR(int ch, uint32 data)
723: {
1.1.1.16! root 724: uint8& tcr = mfp.timer[ch].tcr;
1.1 root 725:
1.1.1.15 root 726: if (data == 0) {
727: data = 256;
728: }
1.1.1.16! root 729: mfp.timer[ch].next_tdr = data;
1.1.1.15 root 730:
1.1.1.7 root 731: if (tcr == 0) {
1.1.1.15 root 732: // 停止中の書き込みはメインカウンタも更新。
1.1.1.16! root 733: mfp.timer[ch].tdr = data;
1.1.1.7 root 734:
735: } else if (tcr < 8) {
1.1.1.15 root 736: // ディレイモード動作中の書き込みは
737: // メインカウンタは影響を受けない。
1.1 root 738:
1.1.1.7 root 739: } else {
740: // イベントモード、パルス幅測定モードは未対応
1.1.1.13 root 741: putlog(0, "Write T%cDR $%02x during unsupported mode (NOT IMPLEMENTED)",
1.1.1.16! root 742: ch + 'A', mfp.timer[ch].next_tdr);
1.1 root 743: }
744: }
745:
746: // イベントコールバック
747: void
1.1.1.6 root 748: MFPDevice::TimerCallback(Event& ev)
1.1 root 749: {
1.1.1.6 root 750: int& ch = ev.code;
1.1 root 751:
1.1.1.7 root 752: // TDR がゼロになったところで呼ばれるので、TDR をリロードする
1.1.1.16! root 753: mfp.timer[ch].tdr = mfp.timer[ch].next_tdr;
1.1 root 754:
1.1.1.7 root 755: // 割り込みを上げる
756: SetInterrupt(timer_vector[ch]);
757:
758: // 次のイベントをセット
759: // XXX 1回のイベントで複数のタイムアウトパルスを跨ぐ状況は考慮してない
760:
761: // period が1メインパルス期間
762: // time が1タイムアウトパルス期間
1.1.1.16! root 763: uint64 period = prescale_ns[mfp.timer[ch].tcr];
! 764: ev.time = period * mfp.timer[ch].tdr;
1.1.1.14 root 765: scheduler->RestartEvent(ev);
1.1.1.12 root 766: }
767:
768: // HSync 入力
769: void
770: MFPDevice::SetHSync(bool hsync)
771: {
772: SetGPIP(MFP::GPIP_HSYNC, hsync);
1.1 root 773: }
774:
775: // VDisp 入力
776: void
777: MFPDevice::SetVDisp(bool vdisp)
778: {
779: // TAI への入力はイベントカウントモードの時のみ
1.1.1.16! root 780: if (mfp.timer[0].tcr == 8) {
1.1 root 781: // AER が示す方向と同じエッジ方向の時
782: bool aer = (mfp.aer & (1 << MFP::GPIP_VDISP));
783: if (aer == vdisp) {
784: // カウンタを減算
1.1.1.16! root 785: mfp.timer[0].tdr--;
! 786: if (mfp.timer[0].tdr == 0) {
1.1 root 787: // 0 になったらリロード
1.1.1.16! root 788: mfp.timer[0].tdr = mfp.timer[0].next_tdr;
1.1 root 789:
1.1.1.7 root 790: SetInterrupt(MFP::INTR_TIMER_A);
1.1 root 791: }
792: }
793: }
794:
795: // GPIP への入力
796: SetGPIP(MFP::GPIP_VDISP, vdisp);
797: }
798:
1.1.1.13 root 799: // 電源ボタン状態入力 (PowerDevice から呼ばれる)
800: void
801: MFPDevice::SetPowSW(bool powsw)
802: {
803: SetGPIP(MFP::GPIP_POWSW, powsw);
804: }
805:
806: // ALARM 信号入力 (RTC の ALARM_OUT 出力端子)
807: void
808: MFPDevice::SetAlarmOut(bool alarm)
809: {
810: SetGPIP(MFP::GPIP_ALARM, alarm);
811: }
812:
1.1 root 813: // GPIP への入力。
814: // num はビット番号(0..7)。
815: void
816: MFPDevice::SetGPIP(int num, bool val)
817: {
818: bool aer = (mfp.aer & (1 << num));
819: bool old = (mfp.gpip & (1 << num));
820:
821: // 立ち上がりか立ち下がりで割り込みを上げる (AER による)
822: // AER OLD VAL Interrupt
823: // 0 0 0 0
824: // 0 0 1 0
825: // 0 1 0 1
826: // 0 1 1 0
827: // 1 0 0 0
828: // 1 0 1 1
829: // 1 1 0 0
830: // 1 1 1 0
1.1.1.3 root 831: if ((old != val) && (aer == val)) {
1.1.1.13 root 832: // ここで割り込みを上げる
833: // XXX GPIP ビット番号と INTR の対応どうなってんの
834: int intr;
835: if (num < 4) {
836: intr = num;
837: } else if (num < 6) {
838: intr = num + 2;
839: } else {
840: intr = num - MFP::GPIP_CIRQ + MFP::INTR_CRTC_IRQ;
841: }
842: SetInterrupt(intr);
1.1 root 843: }
844:
845: if (val) {
846: mfp.gpip |= (1 << num);
847: } else {
848: mfp.gpip &= ~(1 << num);
849: }
850: }
1.1.1.4 root 851:
852: // UCR への書き込み
853: void
854: MFPDevice::SetUCR(uint32 data)
855: {
856: mfp.ucr = data;
857:
858: if ((mfp.ucr & MFP::UCR_CLK) == 0) {
1.1.1.13 root 859: putlog(0, "UCR CLK=0 (NOT IMPLEMENTED)");
1.1.1.4 root 860: }
861: if (((mfp.ucr & MFP::UCR_WL) >> 5) != 0) {
1.1.1.16! root 862: putlog(0, "UCR WL=%u (NOT IMPLEMENTED)", (mfp.ucr >> 5) & 3);
1.1.1.4 root 863: }
864: if (((mfp.ucr & MFP::UCR_ST) >> 3) != 1) {
1.1.1.16! root 865: putlog(0, "UCR ST=%u (NOT IMPLEMENTED)", (mfp.ucr >> 3) & 3);
1.1.1.4 root 866: }
867: }
868:
869: // RSR への書き込み
870: void
871: MFPDevice::SetRSR(uint32 data)
872: {
873: uint32 old = mfp.rsr;
874:
875: mfp.rsr = data;
876:
877: if ((old & MFP::RSR_RE) == 0 && (mfp.rsr & MFP::RSR_RE)) {
878: // RE 0 -> 1
879: }
880: if ((old & MFP::RSR_RE) && (mfp.rsr & MFP::RSR_RE) == 0) {
881: // RE 1 -> 0
1.1.1.9 root 882: // 上位4ビットのステータスを %0 に
883: mfp.rsr &= ~(MFP::RSR_OE | MFP::RSR_PE | MFP::RSR_FE);
884: ClearBF();
1.1.1.4 root 885: }
886: }
887:
1.1.1.9 root 888: // RSR::BF (Buffer Full) をセットする
889: void
890: MFPDevice::SetBF()
891: {
892: mfp.rsr |= MFP::RSR_BF;
893: }
894:
895: // RSR::BF (Buffer Full) をクリアする
896: void
897: MFPDevice::ClearBF()
898: {
899: mfp.rsr &= ~MFP::RSR_BF;
900:
901: // バッファが空いたのでキーボードに次の転送を催促。
902: // 実際のハードウェアでは、キーボードが本体 MFP が Ready になるのを待って
903: // いるが、それに相当。
904: // システムポートの KEYCTRL はキーボード側で処理している。
1.1.1.16! root 905: if (RxIsReady()) {
! 906: keyboard->Ready();
! 907: }
1.1.1.9 root 908: }
909:
1.1.1.4 root 910: // UDR への書き込み
911: void
912: MFPDevice::SetUDR(uint32 data)
913: {
914: if ((mfp.tsr & MFP::TSR_TE)) {
1.1.1.14 root 915: keyboard->Command(data);
1.1.1.4 root 916: }
917: }
918:
1.1.1.9 root 919: // __
920: // RR 線の状態を返す。アサートなら true。
921: bool
922: MFPDevice::IsRR() const
1.1.1.4 root 923: {
1.1.1.9 root 924: // __
925: // 実際の RR 信号線は、BF が立っていて、PE | FE がクリアされている場合に
926: // アサートされる。ただしエミュレータでは Parity Error も Frame Error も
927: // 起きないので、この2ビットは無視する。
928: return ((mfp.rsr & MFP::RSR_BF) != 0);
1.1.1.4 root 929: }
930:
1.1.1.9 root 931: // キーボードからの受信が可能なら true を返す。
1.1.1.4 root 932: bool
1.1.1.9 root 933: MFPDevice::RxIsReady() const
1.1.1.4 root 934: {
1.1.1.9 root 935: // __
936: // RR は本来 MFP から CPU/DMAC など上位に対しての Ready で、
937: // UDR にデータが用意できたので引き取ってほしいの意。
938: // X680x0 ではこれを CPU/DMAC (上位) 向けではなく、下位のキーボードからの
939: // フロー制御に流用しており、
940: // 上位への(本来の)「UDR にデータが用意できた」(IsRR() = true) は、
941: // キーボードに対しては「UDR にデータがあるので送信禁止」、
942: // 上位への(本来の)「UDR にデータが用意できていない」(IsRR() = false) は、
943: // キーボードに対しては「UDR は空いているので送信してよい」と
944: // ここで意味が論理反転することに注意。
945: //
946: // また、システムポートの KEYCTRL は X680x0Keyboard 側で処理しているので
947: // こちらでは不要。
948: //
949: // UDR が空いていてキーボードからデータが送られてきている間は RR は Ready
950: // だが、そもそもキーボードは送出作業中で、新たな送信はできないはずなので
951: // この場合、つまり key_event の動作中も false (送信不可) にする。
952:
953: return !IsRR() && !key_event.IsRunning();
1.1.1.4 root 954: }
955:
956: // キーボードからデータを受信
957: void
958: MFPDevice::Rx(uint32 data)
959: {
1.1.1.9 root 960: // ここは受信したビットをシフトレジスタへ入れ始めたところに相当する
961: // ので、まだ Buffer Full は立てない。
1.1.1.4 root 962:
963: key_event.code = data;
1.1.1.14 root 964: scheduler->RestartEvent(key_event);
1.1.1.4 root 965: }
966:
967: // キーボードからのデータが受信し終わった頃に呼ばれるイベント。
968: void
1.1.1.6 root 969: MFPDevice::KeyCallback(Event& ev)
1.1.1.4 root 970: {
1.1.1.9 root 971: // UDR にデータを置いて Buffer Full をセット
1.1.1.6 root 972: mfp.udr = ev.code;
1.1.1.9 root 973: SetBF();
974:
975: // Manual 7-5 7.2.1 Receiver Interrupt Channels より
976: // | 割り込みは1文字受信ごとに1回しか発生しませんが、2つの専用割り込み
977: // | チャネルにより、正常な受信状態と異常な受信状態に別々のベクター番号を
978: // | 割り当てることができます。受信したワードにエラーがあり、エラー割り込み
979: // | チャネルが有効な場合は、エラーチャネルのみに割り込みが発生します。
980: // | しかし、エラーチャネルが無効の場合、エラー状態の割り込みは、
981: // | バッファフル状態の割り込みと一緒にバッファフル割り込みチャネルに
982: // | 生成されます。どのエラー条件で割り込みが発生したかを判断するためには、
983: // | 常にRSRを読み出す必要があります。
984: // XXX: まだエラー状態は実装されていない、なおエラーは起きないので
985: // メモだけのままかも知れない。
1.1.1.4 root 986:
1.1.1.7 root 987: SetInterrupt(MFP::INTR_RXFULL);
988: }
989:
990: // 必要なら割り込みを上げる。
991: // ch は MFP 内の割り込みチャンネル番号。MFP::INTR_*
992: void
993: MFPDevice::SetInterrupt(uint ch)
994: {
995: assertmsg(ch < 16, "ch=%u", ch);
996: __assume(ch < 16);
997:
998: uint b = (1U << ch);
999:
1000: // IER で割り込みが無効なら何もしない
1001: if ((mfp.ier.w & b) == 0) {
1002: return;
1.1.1.4 root 1003: }
1.1.1.7 root 1004:
1005: // IPR にペンディングを立てる
1006: mfp.ipr.w |= b;
1007:
1008: // 割り込み信号線の状態を変える
1009: ChangeInterrupt();
1010: }
1011:
1012: // 割り込み信号線の状態を変える
1013: void
1014: MFPDevice::ChangeInterrupt()
1015: {
1016: // ペンディングの割り込みがあればアサートされる、
1017: // IPR をクリアするか IMR をクリアすると /IRQ はネゲートされる。
1018: bool irq = ((mfp.ipr.w & mfp.imr.w) != 0);
1.1.1.14 root 1019: interrupt->ChangeINT(this, irq);
1.1.1.7 root 1020: }
1021:
1022: // 割り込みアクノリッジ
1.1.1.15 root 1023: busdata
1.1.1.7 root 1024: MFPDevice::InterruptAcknowledge()
1025: {
1.1.1.15 root 1026: busdata data;
1027:
1028: // IPR が誰も立ってなければ、無視するっぽい?
1029: // 実際には MFP がバスエラーを出しているのではなく、MFP は俺知らない
1030: // と思って放置してると上位回路 (たぶん SAKI ちゃん) がタイムアウトして
1031: // MPU にバスエラー応答する。
1.1.1.7 root 1032: uint32 pending = mfp.ipr.w;
1.1.1.15 root 1033: if (__predict_false(pending == 0)) {
1034: data.SetBusErr();
1035: } else {
1036: // ch はこの時点で IPR に立ってる一番優先度の高いチャンネルのビット
1037: int ch = 31 - __builtin_clz(pending);
1038: uint b = (1U << ch);
1.1.1.7 root 1039:
1.1.1.15 root 1040: // MPU にベクタを引き渡したので Pending をクリア
1041: mfp.ipr.w &= ~b;
1042: ChangeInterrupt();
1.1.1.7 root 1043:
1.1.1.15 root 1044: // ソフトウェア EOI なら In Service を立てる
1045: if (mfp.vr_s) {
1046: mfp.isr.w |= b;
1047: }
1.1.1.7 root 1048:
1.1.1.15 root 1049: data = mfp.vr_vec + ch;
1.1.1.7 root 1050: }
1051:
1.1.1.15 root 1052: // /IEI ネゲート時の /IACK と /IEI の関係がいまいち分からないけど、
1053: // とりあえず /IACK がアサートされてから 3 MFP クロック後に
1054: // データバスにベクタを供給、次の 1 MFP クロックで DTACK 応答。
1055: // で次の 1 MFP クロック以内に CPU が /IACK を下げるとして、
1056: // 計 5 MFP クロック (= 1.25_usec) としておく。
1057: const busdata intack_wait = busdata::Wait(5 * 250_nsec);
1058: data |= intack_wait;
1059:
1060: return data;
1.1.1.4 root 1061: }
1.1.1.16! root 1062:
! 1063: /*static*/ const char *
! 1064: MFPDevice::regname[MFP::RegMax] = {
! 1065: "GPIP",
! 1066: "AER",
! 1067: "DDR",
! 1068: "IERA",
! 1069: "IERB",
! 1070: "IPRA",
! 1071: "IPRB",
! 1072: "ISRA",
! 1073: "ISRB",
! 1074: "IMRA",
! 1075: "IMRB",
! 1076: "VR",
! 1077: "TACR",
! 1078: "TBCR",
! 1079: "TCDCR",
! 1080: "TADR",
! 1081: "TBDR",
! 1082: "TCDR",
! 1083: "TDDR",
! 1084: "SCR",
! 1085: "UCR",
! 1086: "RSR",
! 1087: "TSR",
! 1088: "UDR",
! 1089: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.