|
|
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.9 root 13: #include "monitor.h"
1.1.1.3 root 14: #include "mpu.h"
1.1.1.8 root 15: #include "statistics.h"
16: #include "stopwatch.h"
1.1 root 17: #include <atomic>
18: #include <condition_variable>
1.1.1.3 root 19: #include <list>
1.1 root 20: #include <mutex>
21: #include <pthread.h>
22:
23: // スケジューラ
24: class Scheduler : public Device
25: {
1.1.1.3 root 26: using inherited = Device;
1.1 root 27:
1.1.1.7 root 28: public:
29: // 動作モード
30: // 動作モード変数 (mode) はスケジューラの走行状態を表している。以下の
31: // ビットがすべて %0 なら高速モード、どれかでも %1 なら通常モードになる。
32: //
33: // | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
1.1.1.8 root 34: // mode | |KEY |BOOT|SYNC| CPUSTAT |
35: // | | | +---+---- CPU の状態
36: // | | +-------------- 高速モード抑制
37: // | +------------------- ブートページ実行中
38: // +------------------------ キー入力中
1.1.1.7 root 39: //
40: // bit1,0 (CPUSTAT) は CPU の状態を示す。%00 の時だけ高速走行が可能。
41: // これは MPUDevice::Run() の戻り値でもある。
42: // b1 b0
43: // 0 0 通常状態
44: // 0 1 STOP 状態 (m88k なら擬似 STOP 状態)
45: // 1 0 HALT 状態 (ダブルバスフォールト)
46: // 1 1 HALT 状態だがこちらのビットパターンは使わない
47: //
48: // bit2 (SYNC) が UI からの高速モード指示。%0 なら高速、%1 なら通常。
49: // なのでどっちかというと高速モード抑制指示というほうがいいかも。
50:
51: static const uint32 SCHED_CPU_STOP = 0x0001; // CPU が STOP 状態
52: static const uint32 SCHED_CPU_HALT = 0x0002; // CPU が HALT 状態
53: static const uint32 SCHED_SYNC = 0x0004; // 高速モード抑制指示(UI)
1.1.1.8 root 54: static const uint32 SCHED_BOOT = 0x0008; // ブートページ実行中
55: static const uint32 SCHED_KEY = 0x0010; // キー入力中
1.1.1.7 root 56:
57: // 便宜上用意しておく
58: static const uint32 SCHED_CPU_NORMAL= 0x0000; // CPU が通常状態
59: static const uint32 SCHED_CPU_MASK = (SCHED_CPU_STOP | SCHED_CPU_HALT);
60:
61: private:
1.1 root 62: // リクエストフラグ
1.1.1.7 root 63: // REQ_CPU_MODE は CPU mode が何らか変化することのフラグ。どの状態に変化
64: // するかは new_cpumode 変数で示す。1回のループ期間中に複数回の変化が
65: // 起きても最終状態だけに変化するため。
66: // REQ_USER_MODE と new_usermode も同様。
67: static const uint REQ_CPU_MODE = 0x0001; // CPU 状態を変更
68: static const uint REQ_USER_MODE = 0x0002; // 同期/高速モード変更
1.1.1.8 root 69: static const uint REQ_BOOT_MODE = 0x0004; // ブートページモード変更
70: static const uint REQ_KEY_MODE = 0x0008; // キー入力モード変更
1.1 root 71: static const uint REQ_POWER_ON = 0x0010; // 電源オン
72: static const uint REQ_POWER_OFF = 0x0020; // 電源オフ
73: static const uint REQ_EXIT = 0x0040; // アプリケーション終了
1.1.1.5 root 74: static const uint REQ_RESET = 0x0080; // ハードウェアリセット
1.1.1.8 root 75: static const uint REQ_RESTART = 0x0100; // 電源入れ直し
1.1 root 76:
77: public:
78: Scheduler();
1.1.1.6 root 79: virtual ~Scheduler() override;
1.1 root 80:
1.1.1.3 root 81: bool Init() override;
1.1 root 82:
83: // スレッド開始
84: void ThreadRun();
85:
1.1.1.2 root 86: // スレッド終了
1.1 root 87: void Terminate();
88:
1.1.1.9 root 89: // スレッド終了を待機する
90: void Wait();
91:
92: // スレッド終了を指示する
93: void RequestExit();
94:
1.1.1.8 root 95: // 電源オン要求
96: // 当然電源オフ時に呼ぶので VM スレッド外から呼ばれることになる。
97: void RequestPowerOn() {
98: atomic_reqflag |= REQ_POWER_ON;
99: }
1.1 root 100:
101: // 電源オフ要求
1.1.1.8 root 102: // → ここでフラグを立ててスケジューラスレッドに通知、
103: // → スケジューラスレッドが各デバイスの PowerOff() をコール、
104: // → 電源オフ状態に移行、
105: // → (コールバックが登録されていれば) UI スレッドに通知。
1.1 root 106: void RequestPowerOff() {
107: atomic_reqflag |= REQ_POWER_OFF;
108: }
109:
1.1.1.5 root 110: // リセット要求
111: void RequestResetHard() {
112: atomic_reqflag |= REQ_RESET;
113: }
114:
1.1.1.8 root 115: // 電源入れ直し要求
116: void RequestRestartVM() {
117: atomic_reqflag |= REQ_RESTART;
118: }
119:
120: // 現在の実行モードを返す。
121: uint32 GetRunMode() const { return mode; }
122:
123: // 電源オンなら true を返す。
124: bool IsPower() const { return ispower; }
1.1 root 125:
1.1.1.8 root 126: // 高速モード(UIによる指示)なら true を返す。
1.1 root 127: // ここでいう高速モードは STOP 状態中でも高速モード。
128: bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }
129:
1.1.1.8 root 130: // 高速モードを指示する。
1.1 root 131: // true なら高速モード、false なら同期モード。
132: void SetFullSpeed(bool enable);
133:
1.1.1.8 root 134: // ブートページモードの設定。
135: void RequestBootPageMode(bool isrom);
136:
137: // キー入力中モードの設定。
138: void RequestKeyPressed(bool pressed);
139:
1.1.1.2 root 140: // イベントを開始する
141: void StartEvent(Event *newev);
142: // イベントを停止する
143: void StopEvent(Event *event);
1.1 root 144:
1.1.1.8 root 145: // パフォーマンスカウンタの値取得 (UI 表示用)
146: int GetPerfCounter() const { return perf_counter; }
147:
148: EventQueue eventq {}; // 有効なイベントキュー
149: std::mutex evcs {}; // イベントリストのロック
1.1 root 150:
151: private:
1.1.1.8 root 152: // 同期イベント
153: void SyncCallback(Event& ev);
154:
1.1.1.9 root 155: DECLARE_MONITOR_CALLBACK(MonitorUpdate);
156:
1.1.1.8 root 157: // メインループ
158: bool RunOff();
159: bool RunOn();
160:
161: // 同期処理
162: uint64 Sync();
163:
164: // RTC を進める。
165: void RunRTC();
166:
167: // REQ_* フラグのデバッグ表示
168: void PutlogReqFlag(uint32 req) const;
1.1.1.5 root 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: // 同期イベント
1.1.1.9 root 224: Event sync_event { this };
225:
226: Monitor monitor { this };
1.1 root 227: };
228:
1.1.1.9 root 229: extern const std::string TimeToStr(uint64 t);
230:
1.1.1.8 root 231: extern Stopwatch gRealtime;
1.1 root 232:
1.1.1.8 root 233: 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.