|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// 実時間同期
//
#pragma once
#include "fixedqueue.h"
#include "message.h"
#include "stopwatch.h"
class MPU680x0Device;
class ThreadManager;
class Syncer : public Device
{
using inherited = Device;
public:
// 動作モード
// 動作モード変数 (mode) はスケジューラの走行状態を表している。以下の
// ビットがすべて %0 なら高速モード、どれかでも %1 なら通常モードになる。
//
// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
// mode | |SND |POFF|KEY |SYNC|HALT|IDLE|
// | | | | | +---- CPU & DMAC アイドル
// | | | | +--------- CPU HALT
// | | | +-------------- 高速モード抑制
// | | +------------------- キー入力中
// | +------------------------ 電源オフ
// +----------------------------- サウンド再生中
//
// bit1,0 は CPU から来るが、このうち bit0 だけ DMAC からのアイドル
// ビットとの積(AND) になっているので、mode 中の bit0 は CPU も DMAC も
// ともにアイドルの時だけ 1 になる。
//
// CPU HALT (bit1) ----------------------> HALT (bit1)
// CPU STOP (bit0) -----------------|&
// |&---> IDLE (bit0)
// DMAC Active ---|>--- DMAC Idle ---|&
static const uint32 SYNCMODE_IDLE = 0x0001; // CPU & DMAC アイドル
static const uint32 SYNCMODE_CPU_HALT = 0x0002; // CPU が HALT 状態
static const uint32 SYNCMODE_SYNC = 0x0004; // 等速モード指示(UI)
static const uint32 SYNCMODE_KEY = 0x0008; // キー入力中
static const uint32 SYNCMODE_POWEROFF = 0x0010; // 電源オフ
static const uint32 SYNCMODE_SOUND = 0x0020; // サウンド再生中
// 便宜上用意しておく
static const uint32 SYNCMODE_CPU_NORMAL = 0x0000; // CPU が通常状態
static const uint32 SYNCMODE_CPU_STOP = 0x0001; // CPU が STOP 状態
static const uint32 SYNCMODE_CPU_MASK = 0x0003; // (HALT|STOP)
public:
Syncer();
~Syncer() override;
bool Init() override;
// 実時間系デバイスの時間軸を実時間に追従する場合は true を返す。
bool GetSyncRealtime() const noexcept { return sync_realtime; }
void StartTime(); // 時間の始まり
void StartRealTime(); // 実時間を再開
void StopRealTime(); // 実時間を停止
uint64 GetRealTime() const { return rtime; }
// 現在の実行モードを返す。
uint32 GetRunMode() const { return mode; }
// CPU 状態変更を指示する。
void NotifyCPUMode(uint32 mode_);
// DMAC のアクティブ状態を指示する。
void NotifyDMACActive(bool active);
// 高速モード(UIによる指示)なら true を返す。
// ここでいう高速モードは STOP 状態中でも高速モード。
bool GetFullSpeed() const { return ((mode & SYNCMODE_SYNC) == 0); }
// 高速モードを指示する。
// true なら高速モード、false なら同期モード。
void NotifyFullSpeed(bool enable);
// キー入力状態の変更を指示する。
void NotifyKeyPressed(bool pressed);
// 電源オフの状態の変更を指示する。オフになったとき true。
void NotifyPowerOffMode(bool poweroff);
// サウンド出力状態の変更を指示するう。
void NotifySoundRunning(bool running);
// パフォーマンス測定用に実時間をログ出力
void PutlogRealtime();
// パフォーマンスカウンタの値取得 (UI 表示用)
uint GetPerfCounter() const { return perf_counter; }
// モニタ更新の下請け
int MonitorScreenSub(TextScreen& screen, uint64 vtime);
private:
void ChangeMode(uint32 newmode);
// 同期イベント
void SyncCallback(Event *);
// 動作モード変更メッセージ
void ChangeModeMessage(MessageID, uint32);
// 同期処理
void DoSync();
void CalcPerf();
// 実時間系デバイスの時間軸を実時間に追従する場合は true。
bool sync_realtime {};
// スケジューラの動作モード。SYNCMODE_*
uint32 mode {};
uint32 halt {}; // CPU が HALT なら SYNCMODE_CPU_HALT
uint32 cpu_idle {}; // CPU が STOP なら SYNCMODE_CPU_STOP
uint32 dmac_idle {}; // DMAC がアイドルなら SYNCMODE_IDLE
// 実時間の基準となるストップウォッチ
Stopwatch realtime {};
// 同期した時点の実経過時間
uint64 rtime {};
// 同期調整用
uint64 rtime_epoch {};
uint64 vtime_epoch {};
// sleep しすぎた時間の最大値
uint64 overslept {};
// 同期回数
uint sync_count {}; // 現在の1秒間での同期回数
uint last_sync_count {}; // 前回の1秒間での同期回数
uint64 last_mpu_exec {};
uint64 last_mpu_exec_per_sec {};
// パフォーマンスカウンタ
// perfq が移動平均用のバッファ。四捨五入用に10倍値を持っておく
// (100% なら 1000)。perf_counter は perfq から求めた実行率で
// 小数以下を四捨五入する (のでこっちは 100% なら 100)。
uint perf_counter {}; // 実行率 [%]
FixedQueue<uint32, 3> perfq {}; // 移動平均用のバッファ
uint64 next_perf_rtime {}; // 次回測定予定の実経過時間
uint64 last_perf_rtime {}; // 前回測定時の実経過時間
uint64 last_perf_vtime {}; // 前回測定時の仮想経過時間
uint clock_khz {}; // MHz 表示用の定格クロック数
MPU680x0Device *mpu680x0 {};
ThreadManager *thman {};
// 同期イベント
Event *sync_event {};
};
inline Syncer *GetSyncer() {
return Object::GetObject<Syncer>(OBJ_SYNCER);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.