File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / syncer.h
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:00 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
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);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.