|
|
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"
11: #include "mpu.h"
1.1 root 12: #include <atomic>
13: #include <condition_variable>
1.1.1.3 root 14: #include <list>
1.1 root 15: #include <mutex>
16: #include <pthread.h>
17:
18: // スケジューラ
19: class Scheduler : public Device
20: {
1.1.1.3 root 21: using inherited = Device;
1.1 root 22:
23: // リクエストフラグ
24: static const uint REQ_SYNC = 0x0001; // スケジューラを同期モードに
25: static const uint REQ_FAST = 0x0002; // スケジューラを高速モードに
26: static const uint REQ_RUN = 0x0004; // MPU が通常状態になった
27: static const uint REQ_STOP = 0x0008; // MPU が STOP 状態になった
28: static const uint REQ_MODEMASK = 0x000f; // mode マスク
29: static const uint REQ_POWER_ON = 0x0010; // 電源オン
30: static const uint REQ_POWER_OFF = 0x0020; // 電源オフ
31: static const uint REQ_EXIT = 0x0040; // アプリケーション終了
32:
33: // 動作モード
34: // 動作モード変数 (mode) は高速モードか通常モードかと、MPU が通常状態が
35: // STOP 状態かを同時に保持している。高速走行中であっても MPU が STOP 状態
36: // なら通常走行するというロジックを比較1回で済ませるため。
37: static const uint32 SCHED_STOP = 0x0001; // スケジューラが STOP 状態
38: static const uint32 SCHED_SYNC = 0x0002; // 同期(%1)/高速(%0)モード
1.1.1.3 root 39:
40: // 演算を1回で済ませるために、この2値は同じ値にすること。
41: // ただしこれをチェックするために全員が m68030.h/m88100.h を include すると
42: // m88k を修正するたびに m68k も含めて全部ビルドが走るのはかなりつらいので
43: // 定義されてる時だけチェックすることにする。
44: // もともと将来のポカよけなのでビルド中1回でも通過すれば十分。
45: #if defined(CPU_REQ_STOP)
1.1 root 46: static_assert(SCHED_STOP == CPU_REQ_STOP, "must be the same");
1.1.1.3 root 47: #endif
1.1 root 48:
49: public:
50: Scheduler();
1.1.1.3 root 51: ~Scheduler() override;
1.1 root 52:
1.1.1.3 root 53: bool Init() override;
1.1 root 54:
1.1.1.4 ! root 55: nnSize GetMonitorSize() override;
! 56: void MonitorUpdate(TextScreen&) override;
1.1 root 57:
58: // スレッド開始
59: void ThreadRun();
60:
1.1.1.2 root 61: // スレッド終了
1.1 root 62: void Terminate();
63:
64: // スケジューラを開始 (電源オン時に vm から呼ばれる)
65: void Run();
66:
67: // 電源オフ要求
68: void RequestPowerOff() {
69: atomic_reqflag |= REQ_POWER_OFF;
70: }
71:
72: // サイクル数を仮想時間 [nsec] に変換
73: uint64 Cycle2Vtime(uint64 cycle) const {
74: return cycle * 1000 * 1000 / mpu_clock;
75: }
76:
77: // 仮想時間 [nsec] をサイクル数に変換
78: uint64 Vtime2Cycle(uint64 vtime) const {
79: return vtime * mpu_clock / (1000 * 1000);
80: }
81:
82: // 仮想時刻取得
83: uint64 GetVirtTime() const {
84: return Cycle2Vtime(gMPU->total_cycle());
85: }
86:
87: // スケジューラが高速モードなら true を返す。
88: // ここでいう高速モードは STOP 状態中でも高速モード。
89: bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }
90:
91: // スケジューラの動作モードを設定する。
92: // true なら高速モード、false なら同期モード。
93: void SetFullSpeed(bool enable);
94:
1.1.1.2 root 95: // イベントを開始する
96: void StartEvent(Event *newev);
97: // イベントを停止する
98: void StopEvent(Event *event);
1.1 root 99:
100: std::list<Event *> eventlist {}; // 有効なイベントリスト
101: std::mutex evcs {}; // イベントリストのロック
102:
103: // 状態変更要求
104: // スケジューラループの状態を変更したい場合はこのフラグを立てる。
105: // REQ_MODE_* の相反するビット以外は同時に複数立ててもいいはず。
106: // 処理されると再び 0 になる。
107: std::atomic<uint32> atomic_reqflag {};
108: std::condition_variable cv {};
109: std::mutex cvmtx {};
110:
111: private:
1.1.1.2 root 112: pthread_t thread {};
113: bool thread_created = false; // スレッドが作成されたら true
114:
1.1 root 115: // スケジューラの動作モード。SCHED_*
116: uint32 mode = 0;
117:
118: int mpu_clock = 0; // MPU クロック [kHz]
119:
120: uint64 rtimestart = 0; // スケジューラ開始実時刻
121: uint64 rtimebase = 0; // 実時間の基準時刻
122: uint64 vtimebase = 0; // 仮想時間の基準時刻
123:
124: // 前回 RTC へ 32Hz 入力パルスを入れた時刻 (実時間の絶対時刻系)
125: uint64 rtc_last_clock = 0;
126: };
127:
1.1.1.2 root 128: extern std::unique_ptr<Scheduler> gScheduler;
1.1 root 129:
130: // 現在時刻 [nsec] を取得する
131: static inline uint64 GetRealTime()
132: {
133: struct timeval tv;
134: gettimeofday(&tv, NULL);
135: return (uint64)(tv.tv_sec * 1000 * 1000 + tv.tv_usec) * 1000;
136: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.