Annotation of nono/hd64180/hd647180dev.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2023 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // HD647180 I/O デバイス
        !             9: //
        !            10: 
        !            11: #include "mpu64180.h"
        !            12: #include "hd647180.h"
        !            13: #include "scheduler.h"
        !            14: 
        !            15: //
        !            16: // タイマー (Programmable Reload Timer)
        !            17: //
        !            18: 
        !            19: // タイマーを開始する時 つまり TDE{0,1} の立ち上がりで呼ぶ。
        !            20: // 該当チャンネルの running をセットしてから呼ぶこと。
        !            21: void
        !            22: MPU64180Device::EnableTimer()
        !            23: {
        !            24:        // すでに他方が開始しているなら、もう何もしなくていい
        !            25:        if (timer[0].running && timer[1].running) {
        !            26:                return;
        !            27:        } else if (timer[0].running == false && timer[1].running == false) {
        !            28:                PANIC("must be called when running");
        !            29:        }
        !            30: 
        !            31:        // TDE を立ててから1回目の TDR の減算が始まるまでの時間は
        !            32:        // 0 < t < 20φ と書いてあるので (HD647180.pdf p.112, Figure 13-3)、
        !            33:        // タイマーの tick はタイマー開始時点からカウントし始める方式ではなく、
        !            34:        // フリーランしている tick が来た時に処理をする方式のようだ。
        !            35:        // これの開始点はおそらくリセット時なので、
        !            36:        // 停止していたのを開始する時だけ次の tick までの時間を求める。
        !            37: 
        !            38:        uint64 now = scheduler->GetVirtTime() - timer_epoch;
        !            39:        uint64 tick = now / (clock_nsec * 20);
        !            40:        uint64 next = (tick + 1) * (clock_nsec * 20);
        !            41: 
        !            42:        timer_event.time = next - now;
        !            43:        scheduler->StartEvent(timer_event);
        !            44: }
        !            45: 
        !            46: // タイマー系の割り込み線の状態を変更する。
        !            47: // HD647180.pdf p.112, Figure 13-5。
        !            48: // TIEn, TIFn, IEF1 の変更でコールすること。
        !            49: void
        !            50: MPU64180Device::ChangeTimerInterrupt()
        !            51: {
        !            52:        for (int ch = 0; ch < timer.size(); ch++) {
        !            53:                auto& t = timer[ch];
        !            54:                if (t.tif != 0 && t.intr_enable && GetIEF1()) {
        !            55:                        AssertIntmap(HD647180::IntmapTimer(ch));
        !            56:                } else {
        !            57:                        NegateIntmap(HD647180::IntmapTimer(ch));
        !            58:                }
        !            59:        }
        !            60: }
        !            61: 
        !            62: // タイマーイベント
        !            63: void
        !            64: MPU64180Device::TimerCallback(Event& ev)
        !            65: {
        !            66:        // アクティブがなければ停止
        !            67:        if (active_timer.empty()) {
        !            68:                return;
        !            69:        }
        !            70: 
        !            71:        // 少なくとも片方は有効
        !            72:        for (auto tp : active_timer) {
        !            73:                auto& t = *tp;
        !            74:                if (__predict_false(t.count == 0)) {
        !            75:                        // 0 になった次の tick でリロード
        !            76:                        t.count = t.reload;
        !            77:                } else {
        !            78:                        t.count--;
        !            79:                        // 0 になったら割り込みを上げる
        !            80:                        if (t.count == 0) {
        !            81:                                t.tif = 0x03;
        !            82:                                ChangeTimerInterrupt();
        !            83:                        }
        !            84:                }
        !            85:        }
        !            86: 
        !            87:        // タイマーへの入力は原クロックの20倍なので、
        !            88:        // 厳密には 162.7604… * 20 = 3.255… [nsec] だが、
        !            89:        // ここでは clock_nsec * 20 = 3.260   [nsec] とする。
        !            90:        // この代入は本当は1回目だけでいいのだが。
        !            91:        timer_event.time = clock_nsec * 20;
        !            92:        scheduler->RestartEvent(ev);
        !            93: }
        !            94: 
        !            95: // アクティブタイマーリストを(再)構成する。
        !            96: // 数が少ないので毎回作り直す。
        !            97: // running を変更するたびに呼ぶこと。
        !            98: void
        !            99: MPU64180Device::MakeActiveTimer()
        !           100: {
        !           101:        active_timer.clear();
        !           102: 
        !           103:        for (int ch = 0; ch < timer.size(); ch++) {
        !           104:                auto& t = timer[ch];
        !           105:                if (t.running) {
        !           106:                        active_timer.push_back(&t);
        !           107:                }
        !           108:        }
        !           109: }

unix.superglobalmegacorp.com

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