Annotation of nono/vm/scheduler.h, revision 1.1.1.8

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: #pragma once
                      8: 
1.1.1.3   root        9: #include "device.h"
                     10: #include "event.h"
1.1.1.8 ! root       11: #include "eventqueue.h"
        !            12: #include "fixedqueue.h"
1.1.1.3   root       13: #include "mpu.h"
1.1.1.8 ! root       14: #include "statistics.h"
        !            15: #include "stopwatch.h"
1.1       root       16: #include <atomic>
                     17: #include <condition_variable>
1.1.1.3   root       18: #include <list>
1.1       root       19: #include <mutex>
                     20: #include <pthread.h>
                     21: 
                     22: // スケジューラ
                     23: class Scheduler : public Device
                     24: {
1.1.1.3   root       25:        using inherited = Device;
1.1       root       26: 
1.1.1.7   root       27:  public:
                     28:        // 動作モード
                     29:        // 動作モード変数 (mode) はスケジューラの走行状態を表している。以下の
                     30:        // ビットがすべて %0 なら高速モード、どれかでも %1 なら通常モードになる。
                     31:        //
                     32:        //      | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
1.1.1.8 ! root       33:        // mode |              |KEY |BOOT|SYNC| CPUSTAT |
        !            34:        //                       |    |    |     +---+---- CPU の状態
        !            35:        //                       |    |    +-------------- 高速モード抑制
        !            36:        //                       |    +------------------- ブートページ実行中
        !            37:        //                       +------------------------ キー入力中
1.1.1.7   root       38:        //
                     39:        // bit1,0 (CPUSTAT) は CPU の状態を示す。%00 の時だけ高速走行が可能。
                     40:        // これは MPUDevice::Run() の戻り値でもある。
                     41:        //   b1 b0
                     42:        //    0  0  通常状態
                     43:        //    0  1  STOP 状態 (m88k なら擬似 STOP 状態)
                     44:        //    1  0  HALT 状態 (ダブルバスフォールト)
                     45:        //    1  1  HALT 状態だがこちらのビットパターンは使わない
                     46:        //
                     47:        // bit2 (SYNC) が UI からの高速モード指示。%0 なら高速、%1 なら通常。
                     48:        // なのでどっちかというと高速モード抑制指示というほうがいいかも。
                     49: 
                     50:        static const uint32 SCHED_CPU_STOP      = 0x0001;       // CPU が STOP 状態
                     51:        static const uint32 SCHED_CPU_HALT      = 0x0002;       // CPU が HALT 状態
                     52:        static const uint32 SCHED_SYNC          = 0x0004;       // 高速モード抑制指示(UI)
1.1.1.8 ! root       53:        static const uint32 SCHED_BOOT          = 0x0008;       // ブートページ実行中
        !            54:        static const uint32 SCHED_KEY           = 0x0010;       // キー入力中
1.1.1.7   root       55: 
                     56:        // 便宜上用意しておく
                     57:        static const uint32 SCHED_CPU_NORMAL= 0x0000;   // CPU が通常状態
                     58:        static const uint32 SCHED_CPU_MASK = (SCHED_CPU_STOP | SCHED_CPU_HALT);
                     59: 
                     60:  private:
1.1       root       61:        // リクエストフラグ
1.1.1.7   root       62:        // REQ_CPU_MODE は CPU mode が何らか変化することのフラグ。どの状態に変化
                     63:        // するかは new_cpumode 変数で示す。1回のループ期間中に複数回の変化が
                     64:        // 起きても最終状態だけに変化するため。
                     65:        // REQ_USER_MODE と new_usermode も同様。
                     66:        static const uint REQ_CPU_MODE  = 0x0001;       // CPU 状態を変更
                     67:        static const uint REQ_USER_MODE = 0x0002;       // 同期/高速モード変更
1.1.1.8 ! root       68:        static const uint REQ_BOOT_MODE = 0x0004;       // ブートページモード変更
        !            69:        static const uint REQ_KEY_MODE  = 0x0008;       // キー入力モード変更
1.1       root       70:        static const uint REQ_POWER_ON  = 0x0010;       // 電源オン
                     71:        static const uint REQ_POWER_OFF = 0x0020;       // 電源オフ
                     72:        static const uint REQ_EXIT              = 0x0040;       // アプリケーション終了
1.1.1.5   root       73:        static const uint REQ_RESET             = 0x0080;       // ハードウェアリセット
1.1.1.8 ! root       74:        static const uint REQ_RESTART   = 0x0100;       // 電源入れ直し
1.1       root       75: 
                     76:  public:
                     77:        Scheduler();
1.1.1.6   root       78:        virtual ~Scheduler() override;
1.1       root       79: 
1.1.1.3   root       80:        bool Init() override;
1.1       root       81: 
1.1.1.4   root       82:        nnSize GetMonitorSize() override;
                     83:        void MonitorUpdate(TextScreen&) override;
1.1       root       84: 
                     85:        // スレッド開始
                     86:        void ThreadRun();
                     87: 
1.1.1.2   root       88:        // スレッド終了
1.1       root       89:        void Terminate();
                     90: 
1.1.1.8 ! root       91:        // 電源オン要求
        !            92:        // 当然電源オフ時に呼ぶので VM スレッド外から呼ばれることになる。
        !            93:        void RequestPowerOn() {
        !            94:                atomic_reqflag |= REQ_POWER_ON;
        !            95:        }
1.1       root       96: 
                     97:        // 電源オフ要求
1.1.1.8 ! root       98:        // → ここでフラグを立ててスケジューラスレッドに通知、
        !            99:        // → スケジューラスレッドが各デバイスの PowerOff() をコール、
        !           100:        // → 電源オフ状態に移行、
        !           101:        // → (コールバックが登録されていれば) UI スレッドに通知。
1.1       root      102:        void RequestPowerOff() {
                    103:                atomic_reqflag |= REQ_POWER_OFF;
                    104:        }
                    105: 
1.1.1.5   root      106:        // リセット要求
                    107:        void RequestResetHard() {
                    108:                atomic_reqflag |= REQ_RESET;
                    109:        }
                    110: 
1.1.1.8 ! root      111:        // 電源入れ直し要求
        !           112:        void RequestRestartVM() {
        !           113:                atomic_reqflag |= REQ_RESTART;
        !           114:        }
        !           115: 
        !           116:        // 現在の実行モードを返す。
        !           117:        uint32 GetRunMode() const { return mode; }
        !           118: 
        !           119:        // 電源オンなら true を返す。
        !           120:        bool IsPower() const { return ispower; }
1.1       root      121: 
1.1.1.8 ! root      122:        // 高速モード(UIによる指示)なら true を返す。
1.1       root      123:        // ここでいう高速モードは STOP 状態中でも高速モード。
                    124:        bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }
                    125: 
1.1.1.8 ! root      126:        // 高速モードを指示する。
1.1       root      127:        // true なら高速モード、false なら同期モード。
                    128:        void SetFullSpeed(bool enable);
                    129: 
1.1.1.8 ! root      130:        // ブートページモードの設定。
        !           131:        void RequestBootPageMode(bool isrom);
        !           132: 
        !           133:        // キー入力中モードの設定。
        !           134:        void RequestKeyPressed(bool pressed);
        !           135: 
1.1.1.2   root      136:        // イベントを開始する
                    137:        void StartEvent(Event *newev);
                    138:        // イベントを停止する
                    139:        void StopEvent(Event *event);
1.1       root      140: 
1.1.1.8 ! root      141:        // VM 電源オフ時のコールバックを設定する。(GUI から呼ばれる)
        !           142:        void SetPowerOffCallback(void (*callback)());
1.1       root      143: 
1.1.1.8 ! root      144:        // パフォーマンスカウンタの値取得 (UI 表示用)
        !           145:        int GetPerfCounter() const { return perf_counter; }
        !           146: 
        !           147:        EventQueue eventq {};                           // 有効なイベントキュー
        !           148:        std::mutex evcs {};                                     // イベントリストのロック
1.1       root      149: 
                    150:  private:
1.1.1.8 ! root      151:        // 同期イベント
        !           152:        void SyncCallback(Event& ev);
        !           153: 
        !           154:        // メインループ
        !           155:        bool RunOff();
        !           156:        bool RunOn();
        !           157: 
        !           158:        // 同期処理
        !           159:        uint64 Sync();
        !           160: 
        !           161:        // RTC を進める。
        !           162:        void RunRTC();
        !           163: 
        !           164:        // REQ_* フラグのデバッグ表示
        !           165:        void PutlogReqFlag(uint32 req) const;
1.1.1.5   root      166: 
1.1.1.7   root      167:        // スレッド終了を指示する
                    168:        void RequestExit();
                    169: 
1.1.1.2   root      170:        pthread_t thread {};
1.1.1.5   root      171:        bool thread_created {};         // スレッドが作成されたら true
1.1.1.2   root      172: 
1.1.1.8 ! root      173:        // スケジューラスレッドに処理を要求する場合はこのフラグを立てる
        !           174:        std::atomic<uint32> atomic_reqflag {};
        !           175: 
        !           176:        // 電源オンなら true
        !           177:        bool ispower {};
        !           178: 
1.1       root      179:        // スケジューラの動作モード。SCHED_*
1.1.1.5   root      180:        uint32 mode {};
1.1       root      181: 
1.1.1.7   root      182:        // REQ_CPU_MODE フラグで変更するモード
                    183:        uint32 new_cpumode {};
                    184: 
                    185:        // REQ_USER_MODE フラグで変更するモード
                    186:        uint32 new_usermode {};
                    187: 
1.1.1.8 ! root      188:        // REQ_BOOT_MODE フラグで変更するモード
        !           189:        uint32 new_bootmode {};
        !           190: 
        !           191:        // REQ_KEY_MODE フラグで変更するモード
        !           192:        uint32 new_keymode {};
        !           193: 
        !           194:        uint64 rtime {};                        // 現在の実経過時間
        !           195:        uint64 vtime {};                        // 現在の仮想経過時間
1.1       root      196: 
1.1.1.8 ! root      197:        // 同期調整用
        !           198:        uint64 rtime_epoch {};
        !           199:        uint64 vtime_epoch {};
        !           200: 
        !           201:        // sleep しすぎた時間の最大値
        !           202:        uint64 overslept {};
        !           203: 
        !           204:        // 同期回数
        !           205:        uint sync_count {};                     // 現在の1秒間での同期回数
        !           206:        uint last_sync_count {};        // 前回の1秒間での同期回数
        !           207: 
        !           208:        // 次回 RTC へ 32Hz 入力パルスを入れる予定の実経過時間
        !           209:        uint64 next_rtc_rtime {};
        !           210: 
        !           211:        // パフォーマンスカウンタ
        !           212:        // perfq が移動平均用のバッファ。四捨五入用に10倍値を持っておく
        !           213:        // (100% なら 1000)。perf_counter は perfq から求めた実行率で
        !           214:        // 小数以下を四捨五入する (のでこっちは 100% なら 100)。
        !           215:        int perf_counter {};                    // 実行率 [%]
        !           216:        FixedQueue<uint32, 3> perfq {}; // 移動平均用のバッファ
        !           217:        uint64 next_perf_rtime {};              // 次回測定予定の実経過時間
        !           218:        uint64 last_perf_rtime {};              // 前回測定時の実経過時間
        !           219:        uint64 last_perf_vtime {};              // 前回測定時の仮想経過時間
        !           220: 
        !           221:        Statistics<uint64> last_event_stat {};  // 直近実1秒のイベント統計
        !           222: 
        !           223:        // 同期イベント
        !           224:        Event sync_event {};
        !           225: 
        !           226:        // 電源オフを UI に通知するためのコールバック
        !           227:        void (*poweroff_callback)() {};
1.1       root      228: };
                    229: 
1.1.1.8 ! root      230: extern Stopwatch gRealtime;
1.1       root      231: 
1.1.1.8 ! root      232: extern std::unique_ptr<Scheduler> gScheduler;

unix.superglobalmegacorp.com

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