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