Annotation of nono/hd64180/hd647180dev.cpp, revision 1.1.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.