Annotation of nono/vm/sysclk.cpp, revision 1.1.1.9

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: }

unix.superglobalmegacorp.com

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