File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / sync.h
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:11 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v016, v015, HEAD
nono 0.3.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// 実時間同期
//

#pragma once

#include "event.h"
#include "fixedqueue.h"
#include "message.h"
#include "monitor.h"
#include "stopwatch.h"

class Sync : public Device
{
	using inherited = Device;

 public:
	// 動作モード
	// 動作モード変数 (mode) はスケジューラの走行状態を表している。以下の
	// ビットがすべて %0 なら高速モード、どれかでも %1 なら通常モードになる。
	//
	//      | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
	// mode |         |POFF|KEY |BOOT|SYNC| CPUSTAT |
	//                  |    |    |    |     +---+---- CPU の状態
	//                  |    |    |    +-------------- 高速モード抑制
	//                  |    |    +------------------- ブートページ実行中
	//                  |    +------------------------ キー入力中
	//                  +----------------------------- 電源オフ
	//
	// bit1,0 (CPUSTAT) は CPU の状態を示す。%00 の時だけ高速走行が可能。
	// これは RequestCPUMode() の引数で指定する。
	//   b1 b0
	//    0  0  通常状態
	//    0  1  STOP 状態 (m88k なら擬似 STOP 状態)
	//    1  0  HALT 状態 (ダブルバスフォールト)
	//    1  1  HALT 状態だがこちらのビットパターンは使わない

	static const uint32 SCHED_CPU_STOP	= 0x0001;	// CPU が STOP 状態
	static const uint32 SCHED_CPU_HALT	= 0x0002;	// CPU が HALT 状態
	static const uint32 SCHED_SYNC		= 0x0004;	// 高速モード抑制指示(UI)
	static const uint32 SCHED_BOOT		= 0x0008;	// ブートページ実行中
	static const uint32 SCHED_KEY		= 0x0010;	// キー入力中
	static const uint32 SCHED_POWEROFF	= 0x0020;	// 電源オフ

	// 便宜上用意しておく
	static const uint32 SCHED_CPU_NORMAL= 0x0000;	// CPU が通常状態
	static const uint32 SCHED_CPU_MASK = (SCHED_CPU_STOP | SCHED_CPU_HALT);

 public:
	Sync();
	~Sync() override;

	bool Init() override;

	void StartTime();			// 時間の始まり

	void StartRealTime();		// 実時間を再開
	void StopRealTime();		// 実時間を停止

	uint64 GetRealTime() const { return rtime; }

	// 現在の実行モードを返す。
	uint32 GetRunMode() const { return mode; }

	// CPU 状態変更を指示する。
	void RequestCPUMode(uint32 mode_);

	// 高速モード(UIによる指示)なら true を返す。
	// ここでいう高速モードは STOP 状態中でも高速モード。
	bool GetFullSpeed() const { return ((mode & SCHED_SYNC) == 0); }

	// 高速モードを指示する。
	// true なら高速モード、false なら同期モード。
	void RequestFullSpeed(bool enable);

	// ブートページモードの変更を指示する。
	void RequestBootPageMode(bool isrom);

	// キー入力状態の変更を指示する。
	void RequestKeyPressed(bool pressed);

	// 電源オフの状態の変更を指示する。オフになったとき true。
	void RequestPowerOffMode(bool poweroff);

	// パフォーマンス測定用に実時間をログ出力
	void PutlogRealtime();

	// パフォーマンスカウンタの値取得 (UI 表示用)
	int GetPerfCounter() const { return perf_counter; }

	// モニタ更新の下請け
	int MonitorUpdateSub(TextScreen& screen, uint64 vtime);

 private:
	void ChangeMode(uint32 newmode);

	// 同期イベント
	void SyncCallback(Event& ev);

	// 動作モード変更メッセージ
	void ChangeModeCallback(MessageID, uint32);

	// 同期処理
	void DoSync();

	void CalcPerf();

	// スケジューラの動作モード。SCHED_*
	uint32 mode {};

	// 実時間の基準となるストップウォッチ
	Stopwatch realtime {};

	// 同期した時点の実経過時間
	uint64 rtime {};

	// 同期調整用
	uint64 rtime_epoch {};
	uint64 vtime_epoch {};

	// sleep しすぎた時間の最大値
	uint64 overslept {};

	// 同期回数
	uint sync_count {};			// 現在の1秒間での同期回数
	uint last_sync_count {};	// 前回の1秒間での同期回数

	// パフォーマンスカウンタ
	// perfq が移動平均用のバッファ。四捨五入用に10倍値を持っておく
	// (100% なら 1000)。perf_counter は perfq から求めた実行率で
	// 小数以下を四捨五入する (のでこっちは 100% なら 100)。
	int perf_counter {};			// 実行率 [%]
	FixedQueue<uint32, 3> perfq {};	// 移動平均用のバッファ
	uint64 next_perf_rtime {};		// 次回測定予定の実経過時間
	uint64 last_perf_rtime {};		// 前回測定時の実経過時間
	uint64 last_perf_vtime {};		// 前回測定時の仮想経過時間

	// 同期イベント
	Event sync_event { this };
};

extern Sync *gSync;

unix.superglobalmegacorp.com

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