Annotation of nono/vm/mfp.cpp, revision 1.1.1.19

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.