|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.9 ! root 7: // システムクロックは実時間または仮想時間のいずれかに同期するため、
! 8: // システムクロック独自の時刻 stime を持つ。
! 9: // stime は、割り込みを発生させるごとに、LUNA-I なら 16.67msec、
! 10: // LUNA88k なら 10msec 進行する。
! 11:
1.1 root 12: #include "sysclk.h"
1.1.1.6 root 13: #include "config.h"
14: #include "interrupt.h"
15:
16: std::unique_ptr<SysClkDevice> gSysClk;
1.1 root 17:
18: SysClkDevice::SysClkDevice()
1.1.1.9 ! root 19: : inherited("SystemClock")
1.1 root 20: {
1.1.1.9 ! root 21: AddAlias("SysClk");
! 22:
1.1 root 23: devaddr = 0x63000000;
24:
1.1.1.9 ! root 25: monitor.func = (MonitorCallback_t)&SysClkDevice::MonitorUpdate;
! 26: monitor.SetSize(31, 2);
! 27: monitor.Regist(ID_MONITOR_SYSCLK);
! 28:
1.1 root 29: event.code = 0;
1.1.1.2 root 30: event.SetName("System Clock");
1.1 root 31: }
32:
33: SysClkDevice::~SysClkDevice()
34: {
35: }
36:
37: bool
1.1.1.4 root 38: SysClkDevice::Init()
39: {
40: // クロックは機種ごとに異なる
41: const ConfigItem& item = gConfig->Find("!sysclk-period");
1.1.1.9 ! root 42: period = item.AsInt();
! 43: event.time = period;
! 44:
! 45: // クロックの同期方法
! 46: const ConfigItem& item_sync = gConfig->Find("clock-sync");
! 47: auto clock_sync = item_sync.AsString();
! 48: if (clock_sync == "real") {
! 49: sync_rt = true;
! 50: } else if (clock_sync == "virtual") {
! 51: sync_rt = false;
! 52: } else {
! 53: item_sync.Err();
! 54: return false;
! 55: }
! 56: if (sync_rt) {
! 57: event.func = (DeviceCallback_t)&SysClkDevice::Callback_rt;
! 58: } else {
! 59: event.func = (DeviceCallback_t)&SysClkDevice::Callback;
! 60: }
! 61:
1.1.1.4 root 62: return true;
63: }
64:
65: bool
1.1 root 66: SysClkDevice::PowerOn()
67: {
1.1.1.9 ! root 68: if (sync_rt) {
! 69: stime = gRealtime.Elapsed();
! 70: }
! 71: // XXX スーパーリセット時にスケジューラの時刻が再初期化されないので
! 72: // ここでどうするかはそのときまた再検討すること。
! 73:
1.1 root 74: // 電源オンですぐ起動
1.1.1.8 root 75: sysint = false;
1.1.1.3 root 76: event.Start();
1.1 root 77: return true;
78: }
79:
80: uint64
1.1.1.7 root 81: SysClkDevice::Read(uint32 offset)
1.1 root 82: {
1.1.1.3 root 83: // 1 ポートしかない
84: return GetInt();
85: }
1.1 root 86:
1.1.1.3 root 87: uint64
1.1.1.7 root 88: SysClkDevice::Write(uint32 offset, uint32 data)
1.1.1.3 root 89: {
90: // 何か書き込まれたら、フラグをクリア
91: putlog(1, "システムクロック割り込みクリア");
1.1.1.6 root 92: sysint = false;
93: gInterrupt->NegateINT(this);
1.1.1.3 root 94: return 0;
1.1 root 95: }
96:
97: uint64
1.1.1.7 root 98: SysClkDevice::Peek(uint32 offset)
1.1 root 99: {
1.1.1.3 root 100: return GetInt();
101: }
102:
1.1.1.9 ! root 103: void
! 104: SysClkDevice::MonitorUpdate(Monitor *, TextScreen& screen)
! 105: {
! 106: int y;
! 107:
! 108: screen.Clear();
! 109: y = 0;
! 110:
! 111: int width = stime < 86400_sec ? 20 : 25;
! 112: screen.Print(0, y++, "Sync: %s", sync_rt ? "Real Time" : "Virtual Time");
! 113: screen.Print(0, y++, "Time: %*s", width, TimeToStr(stime).c_str());
! 114: }
! 115:
1.1.1.3 root 116: // 割り込み状態を取得(?)
117: uint8
118: SysClkDevice::GetInt() const
119: {
120: uint8 data = 0;
1.1 root 121:
1.1.1.3 root 122: if (sysint) {
123: data |= 0x80;
1.1 root 124: }
1.1.1.3 root 125: return data;
1.1 root 126: }
127:
128: // イベントハンドラ
129: void
1.1.1.5 root 130: SysClkDevice::Callback(Event& ev)
1.1 root 131: {
132: putlog(3, "システムクロック割り込み発生");
1.1.1.9 ! root 133: stime += period;
! 134: sysint = true;
! 135: gInterrupt->AssertINT(this);
! 136: ev.Start();
! 137: }
! 138:
! 139: void
! 140: SysClkDevice::Callback_rt(Event& ev)
! 141: {
! 142: putlog(3, "システムクロック割り込み発生");
! 143: // システムクロックとしての現在時刻。
! 144: // 足す前は前回の割り込み発生時刻なので
! 145: // period を足すと現在時刻。
! 146: stime += period;
! 147:
! 148: uint64 now = gRealtime.Elapsed();
! 149:
! 150: // +- period 時間範囲で処理する
! 151: if (now > stime + period) {
! 152: // 実時間がさらに 1 period 以上進んでいる
! 153: // 実時間に追いつかないといけないので、システムクロックの
! 154: // 周期を短くして回復運転させる。
! 155: // 周期を短くしすぎるとゲストが処理できなくなるので、
! 156: // 10% カットに留める。
! 157: ev.time = period - period / 10;
! 158: } else if (now < stime - period) {
! 159: // システムクロックがさらに 1 period 以上進んでいる
! 160: // 実時間を追い越してしまっているので、システムクロックの
! 161: // 周期を長くして待つ。長くする方はいくらでも長くしていいので、
! 162: // 連続した場合はどんどん長くしていく。
! 163: ev.time += period;
! 164: } else {
! 165: // おおむね同期している
! 166: ev.time = period;
! 167: }
! 168:
1.1 root 169: sysint = true;
1.1.1.6 root 170: gInterrupt->AssertINT(this);
1.1.1.5 root 171: ev.Start();
1.1 root 172: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.