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

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

unix.superglobalmegacorp.com

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