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