|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.