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