|
|
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.21! root 107: #include "mainbus.h"
1.1.1.17 root 108: #include "monitor.h"
1.1.1.12 root 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);
1.1.1.21! root 122: monitor->SetCallback(&MFPDevice::MonitorScreen);
1.1.1.17 root 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 {
1.1.1.21! root 313: putlogn("$%06x -> $%02x",
! 314: GetMainbusDevice()->GetPaddr(), data.Data());
1.1.1.16 root 315: }
316: }
1.1.1.15 root 317: data |= wait;
1.1.1.16 root 318: data |= BusData::Size1;
1.1 root 319: return data;
320: }
321:
1.1.1.15 root 322: busdata
1.1.1.16 root 323: MFPDevice::WritePort(uint32 offset, uint32 data)
1.1 root 324: {
1.1.1.8 root 325: switch (offset) {
1.1 root 326: case MFP::GPIP:
1.1.1.13 root 327: putlog(0, "Write GPIP <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 328: mfp.gpip = data;
329: break;
330: case MFP::AER:
1.1.1.16 root 331: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 332: mfp.aer = data;
333: break;
334: case MFP::DDR:
335: if (data != 0) {
1.1.1.13 root 336: putlog(0, "Write DDR <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 337: }
338: mfp.ddr = data;
339: break;
340: case MFP::IERA:
1.1.1.16 root 341: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.19 root 342: SetIER((data << 8) | mfp.ier.b);
1.1 root 343: break;
344: case MFP::IERB:
1.1.1.16 root 345: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.19 root 346: SetIER((mfp.ier.a << 8) | data);
1.1 root 347: break;
348: case MFP::IPRA:
1.1.1.16 root 349: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 350: mfp.ipr.a = data;
1.1.1.7 root 351: ChangeInterrupt();
1.1 root 352: break;
353: case MFP::IPRB:
1.1.1.16 root 354: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 355: mfp.ipr.b = data;
1.1.1.7 root 356: ChangeInterrupt();
1.1 root 357: break;
358: case MFP::ISRA:
1.1.1.16 root 359: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 360: mfp.isr.a = data;
361: break;
362: case MFP::ISRB:
1.1.1.16 root 363: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 364: mfp.isr.b = data;
365: break;
366: case MFP::IMRA:
1.1.1.16 root 367: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 368: mfp.imr.a = data;
1.1.1.7 root 369: ChangeInterrupt();
1.1 root 370: break;
371: case MFP::IMRB:
1.1.1.16 root 372: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 373: mfp.imr.b = data;
1.1.1.7 root 374: ChangeInterrupt();
1.1 root 375: break;
376: case MFP::VR:
1.1.1.7 root 377: mfp.vr_vec = data & 0xf0;
378: mfp.vr_s = data & 0x08;
1.1.1.16 root 379: putlog(2, "%s <- $%02x", regname[offset], mfp.GetVR());
1.1 root 380: break;
381: case MFP::TACR:
1.1.1.16 root 382: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 383: SetTCR(0, data);
384: break;
385: case MFP::TBCR:
1.1.1.16 root 386: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 387: SetTCR(1, data);
388: break;
389: case MFP::TCDCR:
1.1.1.16 root 390: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 391: SetTCR(2, data >> 4);
392: SetTCR(3, data & 7);
393: break;
394: case MFP::TADR:
1.1.1.16 root 395: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 396: SetTDR(0, data);
397: break;
398: case MFP::TBDR:
1.1.1.16 root 399: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 400: SetTDR(1, data);
401: break;
402: case MFP::TCDR:
1.1.1.16 root 403: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 404: SetTDR(2, data);
405: break;
406: case MFP::TDDR:
1.1.1.16 root 407: putlog(2, "%s <- $%02x", regname[offset], data);
1.1 root 408: SetTDR(3, data);
409: break;
410: case MFP::SCR:
1.1.1.13 root 411: putlog(0, "SCR <- $%02x (NOT IMPLEMENTED)", data);
1.1 root 412: mfp.scr = data;
413: break;
414: case MFP::UCR:
1.1.1.16 root 415: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4 root 416: SetUCR(data);
1.1 root 417: break;
418: case MFP::RSR:
1.1.1.16 root 419: putlog(2, "%s <- $%02x", regname[offset], data);
1.1.1.4 root 420: SetRSR(data);
1.1 root 421: break;
422: case MFP::TSR:
1.1.1.13 root 423: if ((data & 0x0e)) {
424: // SO 端子関係の B, H, L ビットは未実装
425: putlog(0, "TSR <- $%02x (B,H,L bit NOT IMPLEMENTED)", data);
426: }
1.1 root 427: mfp.tsr = (mfp.tsr & 0xf0) | (data & 0x0f);
428: break;
429: case MFP::UDR:
1.1.1.16 root 430: if (__predict_false(loglevel >= 2)) {
431: if (data == 0x40 || data == 0x41) {
432: // MSCTRL だけ頻度が高いのでログレベルを上げておく
433: putlog(3, "%s <- $%02x", regname[offset], data);
434: } else {
435: putlogn("%s <- $%02x", regname[offset], data);
436: }
1.1.1.4 root 437: }
438: SetUDR(data);
439: break;
440: default:
1.1 root 441: break;
442: }
1.1.1.15 root 443:
1.1.1.16 root 444: busdata r = wait;
445: r |= BusData::Size1;
446: return r;
1.1 root 447: }
448:
1.1.1.15 root 449: busdata
1.1.1.16 root 450: MFPDevice::PeekPort(uint32 offset)
1.1 root 451: {
452: uint8 data;
453:
1.1.1.8 root 454: switch (offset) {
1.1 root 455: case MFP::GPIP:
456: data = mfp.gpip;
457: break;
458: case MFP::AER:
459: data = mfp.aer;
460: break;
461: case MFP::DDR:
462: data = mfp.ddr;
463: break;
464: case MFP::IERA:
465: data = mfp.ier.a;
466: break;
467: case MFP::IERB:
468: data = mfp.ier.b;
469: break;
470: case MFP::IPRA:
471: data = mfp.ipr.a;
472: break;
473: case MFP::IPRB:
474: data = mfp.ipr.b;
475: break;
476: case MFP::ISRA:
477: data = mfp.isr.a;
478: break;
479: case MFP::ISRB:
480: data = mfp.isr.b;
481: break;
482: case MFP::IMRA:
483: data = mfp.imr.a;
484: break;
485: case MFP::IMRB:
486: data = mfp.imr.b;
487: break;
488: case MFP::VR:
1.1.1.7 root 489: data = mfp.GetVR();
1.1 root 490: break;
491: case MFP::TACR:
1.1.1.16 root 492: data = mfp.timer[0].tcr;
1.1 root 493: break;
494: case MFP::TBCR:
1.1.1.16 root 495: data = mfp.timer[1].tcr;
1.1 root 496: break;
497: case MFP::TCDCR:
1.1.1.16 root 498: data = mfp.GetTCDCR();
1.1 root 499: break;
500: case MFP::TADR:
501: data = GetTDR(0);
502: break;
503: case MFP::TBDR:
504: data = GetTDR(1);
505: break;
506: case MFP::TCDR:
507: data = GetTDR(2);
508: break;
509: case MFP::TDDR:
510: data = GetTDR(3);
511: break;
512: case MFP::SCR:
513: data = mfp.scr;
514: break;
515: case MFP::UCR:
516: data = mfp.ucr;
517: break;
518: case MFP::RSR:
519: data = mfp.rsr;
520: break;
521: case MFP::TSR:
522: data = mfp.tsr;
523: break;
524: case MFP::UDR:
525: data = mfp.udr;
526: break;
1.1.1.4 root 527: default:
528: data = 0xff;
1.1 root 529: }
530: return data;
531: }
532:
1.1.1.16 root 533: bool
534: MFPDevice::PokePort(uint32 offset, uint32 data)
535: {
536: return false;
537: }
538:
1.1.1.5 root 539: void
1.1.1.21! root 540: MFPDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1 root 541: {
1.1.1.15 root 542: MFP mfp_;
543: std::array<uint8, 4> tdr_;
1.1 root 544: int x;
545: int y;
546:
1.1.1.15 root 547: // ローカルにコピー。
548: memcpy(&mfp_, &mfp, sizeof(mfp));
549: for (int ch = 0; ch < tdr_.size(); ch++) {
550: tdr_[ch] = GetTDR(ch);
551: }
552:
1.1.1.10 root 553: screen.Clear();
1.1 root 554:
555: // 0 1 2 3 4 5 6
1.1.1.7 root 556: // 01234567890123456789012345678901234567890123456789012345678901234567890
557: // $e88001(GPIP):$00 $e88007(IERA):$00 $e88019(TACR):$00 $e88027
1.1.1.13 root 558: // IER IMR IPR ISR Mode TDR Cnt
559: // An:MPSC TxEmpty Enable Mask Pend Serv Timer-A Delay(50us) 255 255
1.1 root 560:
1.1.1.7 root 561: #define A(x) (baseaddr + (x * 2) + 1)
562:
563: // レジスタ生値
564: // 1列目(GPIP 関連と VR)
565: x = 0;
566: y = 0;
1.1.1.15 root 567: screen.Print(x, y++, "$%06x(GPIP):$%02x", A(MFP::GPIP), mfp_.gpip);
568: screen.Print(x, y++, "$%06x(AER): $%02x", A(MFP::AER), mfp_.aer);
569: screen.Print(x, y++, "$%06x(DDR): $%02x", A(MFP::DDR), mfp_.ddr);
570: screen.Print(x, y++, "$%06x(VR): $%02x", A(MFP::VR), mfp_.GetVR());
1.1.1.7 root 571: // 2列目(割り込み関連)
572: x = 20;
573: y = 0;
1.1.1.15 root 574: screen.Print(x, y++, "$%06x(IERA):$%02x", A(MFP::IERA), mfp_.ier.a);
575: screen.Print(x, y++, "$%06x(IERB):$%02x", A(MFP::IERB), mfp_.ier.b);
576: screen.Print(x, y++, "$%06x(IPRA):$%02x", A(MFP::IPRA), mfp_.ipr.a);
577: screen.Print(x, y++, "$%06x(IPRB):$%02x", A(MFP::IPRB), mfp_.ipr.b);
578: screen.Print(x, y++, "$%06x(ISRA):$%02x", A(MFP::ISRA), mfp_.isr.a);
579: screen.Print(x, y++, "$%06x(ISRB):$%02x", A(MFP::ISRB), mfp_.isr.b);
580: screen.Print(x, y++, "$%06x(IMRA):$%02x", A(MFP::IMRA), mfp_.imr.a);
581: screen.Print(x, y++, "$%06x(IMRB):$%02x", A(MFP::IMRB), mfp_.imr.b);
1.1.1.7 root 582: // 3列目(タイマー関連)
583: x = 40;
584: y = 0;
1.1.1.16 root 585: screen.Print(x, y++, "$%06x(TACR): $%02x", A(MFP::TACR), mfp_.timer[0].tcr);
586: screen.Print(x, y++, "$%06x(TBCR): $%02x", A(MFP::TBCR), mfp_.timer[1].tcr);
587: screen.Print(x, y++, "$%06x(TCDCR):$%02x", A(MFP::TCDCR), mfp_.GetTCDCR());
1.1.1.15 root 588: screen.Print(x, y++, "$%06x(TADR): $%02x", A(MFP::TADR), tdr_[0]);
589: screen.Print(x, y++, "$%06x(TBDR): $%02x", A(MFP::TBDR), tdr_[1]);
590: screen.Print(x, y++, "$%06x(TCDR): $%02x", A(MFP::TCDR), tdr_[2]);
591: screen.Print(x, y++, "$%06x(TDDR): $%02x", A(MFP::TDDR), tdr_[3]);
1.1.1.7 root 592: // 4列目(USART 関連)
593: x = 61;
594: y = 0;
1.1.1.15 root 595: screen.Print(x, y++, "$%06x(SCR):$%02x", A(MFP::SCR), mfp_.scr);
596: screen.Print(x, y++, "$%06x(UCR):$%02x", A(MFP::UCR), mfp_.ucr);
597: screen.Print(x, y++, "$%06x(RSR):$%02x", A(MFP::RSR), mfp_.rsr);
598: screen.Print(x, y++, "$%06x(TSR):$%02x", A(MFP::TSR), mfp_.tsr);
1.1.1.10 root 599: screen.Print(x, y, "$%06x(UDR):", A(MFP::UDR));
1.1.1.15 root 600: if ((int16)mfp_.udr >= 0) {
601: screen.Print(x + 13, y, "$%02x", mfp_.udr);
1.1.1.7 root 602: } else {
1.1.1.10 root 603: screen.Print(x + 13, y, "---");
1.1.1.7 root 604: }
605:
1.1 root 606: // 割り込み関連
1.1.1.7 root 607: y = 9;
1.1.1.10 root 608: screen.Print(0, y++, "<Interrupt> %-6s %-4s %-4s %-4s",
1.1.1.7 root 609: "IER", "IMR", "IPR", "ISR");
1.1 root 610: for (int i = 15; i >= 0; i--, y++) {
1.1.1.20 root 611: uint16 mask = (1U << i);
1.1.1.16 root 612: screen.Print(0, y, "%c%u:%-12s %-6s %-4s %-4s %-4s",
1.1 root 613: i >= 8 ? 'A' : 'B',
614: (i % 8),
615: intrname[i],
1.1.1.15 root 616: (mfp_.ier.w & mask) ? "Enable" : "",
617: (mfp_.imr.w & mask) ? "" : "Mask", // %0 でマスクする
618: (mfp_.ipr.w & mask) ? "Pend" : "",
619: (mfp_.isr.w & mask) ? "Serv" : "");
1.1 root 620: }
621:
622: // タイマー関連
1.1.1.13 root 623: x = 40;
1.1.1.7 root 624: y = 9;
1.1.1.15 root 625: screen.Print(x, y++, "<Timer> Mode TDR Next");
1.1 root 626: for (int ch = 0; ch < 4; ch++) {
1.1.1.10 root 627: screen.Print(x, y, "Timer-%c", ch + 'A');
1.1.1.16 root 628: uint8 tcr = mfp_.timer[ch].tcr;
629: if (tcr == 0) {
1.1.1.10 root 630: screen.Print(x + 8, y, "Stopped");
1.1.1.19 root 631: } else if (tcr < 8) {
632: screen.Print(x + 8, y, "Delay(%s)", prescale_str[tcr]);
1.1.1.16 root 633: } else if (tcr == 8) {
1.1.1.10 root 634: screen.Print(x + 8, y, "Event");
1.1 root 635: } else {
1.1.1.19 root 636: screen.Print(x + 8, y, "Pulse(%s)", prescale_str[tcr - 8]);
1.1 root 637: }
638:
1.1.1.16 root 639: screen.Print(x + 20, y, "%3u", tdr_[ch]);
640: screen.Print(x + 25, y, "%3u", mfp_.timer[ch].next_tdr & 0xff);
1.1.1.7 root 641: y++;
1.1 root 642: }
643:
644: // GPIP 関連
1.1.1.13 root 645: x = 40;
1.1.1.7 root 646: y = 9 + 8;
1.1.1.10 root 647: screen.Puts(x, y++, "<GPIP> GPIP AER DDR");
1.1 root 648: for (int i = 7; i >= 0; i--, y++) {
1.1.1.20 root 649: uint mask = (1U << i);
1.1.1.16 root 650: screen.Print(x, y, "b%u %-6s %u %u %s", i, gpipname[i],
1.1.1.15 root 651: (mfp_.gpip & mask) ? 1 : 0,
652: (mfp_.aer & mask) ? 1 : 0,
653: (mfp_.ddr & mask) ? "OUT" : "IN");
1.1 root 654: }
655: }
656:
657: /*static*/ const char *
658: MFPDevice::intrname[] = {
659: "RTC Alarm",
660: "EXPON",
661: "POW SW",
662: "FM IRQ",
663: "Timer-D",
664: "Timer-C",
665: "V-Disp",
666: "---",
667: "Timer-B",
668: "MPSC TxErr",
669: "MPSC TxEmpty",
670: "MPSC RxErr",
671: "MPSC RxFull",
672: "Timer-A",
673: "CRTC IRQ",
674: "H-Sync",
675: };
676:
677: /*static*/ const char *
678: MFPDevice::gpipname[] = {
679: "ALARM",
680: "EXPON",
681: "POW SW",
682: "FMIRQ",
683: "V-Disp",
684: "------",
685: "CIRQ",
686: "H-Sync",
687: };
688:
689: // TxCR の設定値から分周期間というかメインカウンタ1回分の時間を返す
1.1.1.19 root 690: /*static*/ const uint64
1.1.1.21! root 691: MFPDevice::prescale_tsec[8] = {
1.1 root 692: 0,
1.1.1.19 root 693: 1000_nsec, // /4
694: 2500_nsec, // /10
695: 4000_nsec, // /16
696: 12500_nsec, // /50
697: 16000_nsec, // /64
698: 25000_nsec, // /100
699: 50000_nsec, // /200
1.1 root 700: };
701:
702: /*static*/ const char *
703: MFPDevice::prescale_str[8] = {
704: "",
705: "1us",
706: "2.5us",
707: "4us",
708: "12.5us",
709: "16us",
710: "25us",
711: "50us",
712: };
713:
1.1.1.7 root 714: // タイマーのチャンネルから MFP 割り込みチャンネル番号に変換する
1.1.1.16 root 715: /*static*/ const uint
1.1.1.4 root 716: MFPDevice::timer_vector[4] = {
717: MFP::INTR_TIMER_A,
718: MFP::INTR_TIMER_B,
719: MFP::INTR_TIMER_C,
720: MFP::INTR_TIMER_D,
721: };
1.1 root 722:
1.1.1.19 root 723: // IER[AB] に new_ier (16 ビット全体) をセットする。
1.1.1.15 root 724: void
1.1.1.19 root 725: MFPDevice::SetIER(uint16 new_ier)
1.1.1.15 root 726: {
1.1.1.19 root 727: // raising はこの書き込みで %0 -> %1 に変化するビットだけを立てたもの、
728: // falling はこの書き込みで %1 -> %0 に変化するビットだけを立てたもの。
729: uint16 raising = new_ier & (mfp.ier.w ^ new_ier);
730: uint16 falling = mfp.ier.w & (mfp.ier.w ^ new_ier);
731:
732: // タイマー用の event[] は、割り込みを起こす必要がある時しか回さない
733: // 構造なので、割り込みなしでスタートしたタイマーをその動作中に後から
734: // 割り込み許可に変更したら、ここで何事もなかったようにタイマーイベントを
735: // 開始しなければいけない。
736: for (int ch = 0; ch < countof(mfp.timer); ch++) {
737: uint timer_mask = 1U << timer_vector[ch];
738: if ((raising & timer_mask) != 0 && mfp.timer[ch].IsDelay()) {
1.1.1.20 root 739: event[ch]->SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1.1.19 root 740: RestartTimerEvent(ch);
741: }
742: }
1.1.1.15 root 743:
744: // IER を下げたところは IPR も下げる。(紙資料 p4-4)
1.1.1.19 root 745: mfp.ipr.w &= ~falling;
1.1.1.15 root 746:
747: // どちらにしても新しい IER によって信号線の状態は変える。
1.1.1.19 root 748: mfp.ier.w = new_ier;
1.1.1.15 root 749: ChangeInterrupt();
750: }
751:
1.1.1.19 root 752: // このタイマーの現在のメインカウンタの値を求める。
753: inline uint8
754: MFP::Timer::GetCounter(uint64 now, uint64 period) const
755: {
756: uint8 data = tdr - (((now - start) / period) % tdr);
757: return data;
758: }
759:
1.1 root 760: // TxCR をセットする
761: void
762: MFPDevice::SetTCR(int ch, uint32 data)
763: {
1.1.1.19 root 764: MFP::Timer& timer = mfp.timer[ch];
1.1 root 765: uint32 prev;
766:
1.1.1.19 root 767: prev = timer.tcr;
1.1 root 768: data &= 0x0f;
769:
1.1.1.19 root 770: timer.tcr = data;
1.1.1.7 root 771: if (data == 0) {
772: if (prev == 0) {
773: // 0 -> 0 なら何も起きない
774: return;
775: } else if (prev < 8) {
776: // タイマー停止
1.1.1.13 root 777: putlog(1, "Timer-%c Stop", ch + 'A');
1.1.1.7 root 778:
779: // ここで TDR を確定させる。
1.1.1.19 root 780: // タイマー動作中の TDR の参照はイベント開始時刻から求めていたが
781: // イベントを停止すると求められなくなるので、停止前に求めておく。
1.1.1.21! root 782: uint64 period = prescale_tsec[prev];
1.1.1.14 root 783: uint64 now = scheduler->GetVirtTime();
1.1.1.19 root 784: mfp.timer[ch].tdr = timer.GetCounter(now, period);
1.1.1.7 root 785:
786: // でイベント停止
1.1.1.19 root 787: StopTimerEvent(ch);
1.1.1.7 root 788: return;
789: } else if (prev == 8) {
790: // イベントカウントモードから停止しても何も起きないはず
791: } else {
792: // パルス幅測定モード (未実装)
793: }
1.1 root 794: return;
1.1.1.7 root 795:
796: } else if (data < 8) {
1.1.1.19 root 797: // タイマー開始。
1.1.1.7 root 798:
1.1.1.19 root 799: // タイマー開始時は TDR はリロードしない。
800: // 割り込みを上げる必要がある時だけイベントを使う。
801:
1.1.1.21! root 802: uint64 period = prescale_tsec[data];
1.1.1.19 root 803: uint64 now = scheduler->GetVirtTime();
804: timer.start = now;
805: if (IsTimerIntrEnable(ch)) {
1.1.1.20 root 806: event[ch]->time = period * timer.tdr;
807: event[ch]->SetName(string_format("MFP Timer-%c", ch + 'A'));
1.1.1.19 root 808: if (sync_rt) {
809: // 自分の実時間軸の基準をここにする。
810: stime[ch] = syncer->GetRealTime();
811: // event.time はこの後変動するので、周期は別で覚えておく。
1.1.1.20 root 812: rt_period[ch] = event[ch]->time;
1.1.1.19 root 813:
814: scheduler->StartRealtimeEvent(event[ch],
815: stime[ch], rt_period[ch]);
816: } else {
817: scheduler->RestartEvent(event[ch]);
818: }
819: } else {
1.1.1.20 root 820: event[ch]->SetName(string_format("MFP Timer-%c FreeRun", ch + 'A'));
1.1.1.19 root 821: }
1.1.1.7 root 822:
1.1.1.21! root 823: putlog(1, "Timer-%c Start Delay mode(%u x %.1fusec)",
1.1.1.7 root 824: ch + 'A',
1.1.1.19 root 825: timer.tdr,
1.1.1.21! root 826: (double)period / 1_usec);
1.1.1.7 root 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 を読み出しても割り込みと整合しないがもう仕方ない。
1.1.1.21! root 861: uint64 period = prescale_tsec[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 (のリロード値) が変わったのでタイマー周りも再設定。
1.1.1.21! root 917: uint64 period = prescale_tsec[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();
1.1.1.21! root 961: uint64 period = prescale_tsec[timer.tcr];
1.1.1.19 root 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.