|
|
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.3 ! root 55: bool MonitorUpdate() override;
1.1 root 56:
57: // スレッド開始
58: void ThreadRun();
59:
1.1.1.2 root 60: // スレッド終了
1.1 root 61: void Terminate();
62:
63: // スケジューラを開始 (電源オン時に vm から呼ばれる)
64: void Run();
65:
66: // 電源オフ要求
67: void RequestPowerOff() {
68: atomic_reqflag |= REQ_POWER_OFF;
69: }
70:
71: // サイクル数を仮想時間 [nsec] に変換
72: uint64 Cycle2Vtime(uint64 cycle) const {
73: return cycle * 1000 * 1000 / mpu_clock;
74: }
75:
76: // 仮想時間 [nsec] をサイクル数に変換
77: uint64 Vtime2Cycle(uint64 vtime) const {
78: return vtime * mpu_clock / (1000 * 1000);
79: }
80:
81: // 仮想時刻取得
82: uint64 GetVirtTime() const {
83: return Cycle2Vtime(gMPU->total_cycle());
84: }
85:
86: // スケジューラが高速モードなら true を返す。
87: // ここでいう高速モードは STOP 状態中でも高速モード。
88: bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }
89:
90: // スケジューラの動作モードを設定する。
91: // true なら高速モード、false なら同期モード。
92: void SetFullSpeed(bool enable);
93:
1.1.1.2 root 94: // イベントを開始する
95: void StartEvent(Event *newev);
96: // イベントを停止する
97: void StopEvent(Event *event);
1.1 root 98:
99: std::list<Event *> eventlist {}; // 有効なイベントリスト
100: std::mutex evcs {}; // イベントリストのロック
101:
102: // 状態変更要求
103: // スケジューラループの状態を変更したい場合はこのフラグを立てる。
104: // REQ_MODE_* の相反するビット以外は同時に複数立ててもいいはず。
105: // 処理されると再び 0 になる。
106: std::atomic<uint32> atomic_reqflag {};
107: std::condition_variable cv {};
108: std::mutex cvmtx {};
109:
110: private:
1.1.1.2 root 111: pthread_t thread {};
112: bool thread_created = false; // スレッドが作成されたら true
113:
1.1 root 114: // スケジューラの動作モード。SCHED_*
115: uint32 mode = 0;
116:
117: int mpu_clock = 0; // MPU クロック [kHz]
118:
119: uint64 rtimestart = 0; // スケジューラ開始実時刻
120: uint64 rtimebase = 0; // 実時間の基準時刻
121: uint64 vtimebase = 0; // 仮想時間の基準時刻
122:
123: // 前回 RTC へ 32Hz 入力パルスを入れた時刻 (実時間の絶対時刻系)
124: uint64 rtc_last_clock = 0;
125: };
126:
1.1.1.2 root 127: extern std::unique_ptr<Scheduler> gScheduler;
1.1 root 128:
129: // 現在時刻 [nsec] を取得する
130: static inline uint64 GetRealTime()
131: {
132: struct timeval tv;
133: gettimeofday(&tv, NULL);
134: return (uint64)(tv.tv_sec * 1000 * 1000 + tv.tv_usec) * 1000;
135: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.