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