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