File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / rtc.h
Revision 1.1.1.15 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (3 months 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
//

//
// RTC の共通部分
//

#pragma once

#include "device.h"
#include <sys/time.h>

class Syncer;

class RTCDevice : public IODevice
{
	using inherited = IODevice;

 public:
	RTCDevice();
	~RTCDevice() override;

	bool Init() override;

	virtual void StartTime();

	// 電源 OFF 時の実時間でのクロック入力。
	// 次回のクロック発生までの時間間隔を返す。
	uint64 ClockIn_PowerOff();

	// 現在の日付時刻を返す。
	// ここで取得できる値は機種によらず共通のフォーマットだが、
	// 値は範囲外の状態になる可能性が常にあることに注意。
	//
	// RP5C15 の場合、1つのレジスタが10進数一桁ごとを扱っているため、特に
	// ゲストプログラムが月の更新するしようとするときに一時的に範囲外の
	// 状態になることが避けられない。
	// 例えば、もともと12月31日だったものを9月30日に変更する場合、
	// 上の桁から更新したら(M10,M1,D10,D1)
	//  12/31 -> 02/31 -> 09/31 -> 09/31 -> 09/30
	// 下の桁から更新したら(D1,D10,M1,M10)
	//  12/31 -> 12/30 -> 12/30 -> 19/30 -> 09/30
	// このように、2/31, 9/31, 19/30 などが中間状態として発生する。
	virtual uint GetSec() const = 0;	// 秒(0-59)
	virtual uint GetMin() const = 0;	// 分(0-59)
	virtual uint GetHour() const = 0;	// 時(0-23)
	virtual uint GetWday() const = 0;	// 曜日(0-6、0が日曜)
	virtual uint GetMday() const = 0;	// 日(1-31)
	virtual uint GetMon() const = 0;	// 月(1-12)
	virtual uint GetYear() const = 0;	// 年(西暦)
	virtual uint GetLeap() const = 0;	// うるう年カウンタ(0-3、0がうるう年)

 protected:
	// 32Hz クロック入力。
	// clock-sync の設定に応じて、実時間または仮想時間で
	// 32Hz ごとに呼ばれて、これが RTC の時計を進める処理をするところ。
	void ClockIn();

	// 仮想 RTC のクロック出力

	// 継承クラス向けに 32Hz で呼び出される。
	virtual void Tick32Hz();

	// 継承クラス向けに 2Hz で呼び出される。
	// タイミングは、0/32秒目と 16/32秒目。
	virtual void Tick2Hz();

	// 継承クラス向けに 1Hz で呼び出される。
	// タイミングは、0/32秒目。
	// この関数から秒カウンタ更新をすること。
	virtual void Tick1Hz();

	// 秒をカウントアップし、秒以上の繰り上がりを処理する。
	void CountUpSec();
	// 分をカウントアップし、分以上の繰り上がりを処理する。
	// RP5C15 の ADJUST 機能を実現するために秒と分離。
	void CountUpMin();

	virtual void SetSec(uint v) = 0;
	virtual void SetMin(uint v) = 0;
	virtual void SetHour(uint v) = 0;
	virtual void SetWday(uint v) = 0;
	virtual void SetMday(uint v) = 0;
	virtual void SetMon(uint v) = 0;
	virtual void SetYear(uint v) = 0;
	virtual void SetLeap(uint v) = 0;

	// 32Hz でカウントアップする内部カウンタ
	uint64 cnt {};

	// 年エポック。システムに依存。
	uint year_epoch {};

	// 時刻設定時に localtime を使う場合は true
	bool use_localtime {};

	// レジスタとして読める値を定数にすることで、仮想マシン状態を
	// 常に同じ状態にするためのパフォーマンス測定用フラグ。
	// なお NVRAM 部分は影響されない。
	bool force_fixed {};

	// RTC の入力クロックが実時間の場合は true
	// 仮想時間の場合は false
	bool sync_rt {};

	// 設定で指定された日付時刻
	struct tm rtc_tm {};

	// 曜日文字列 (0 = "Sun", ...)
	// MK48T02 の誤運用にも対応するため 0..7 の範囲をとる。
	static const char * const wdays[8];

 private:
	// デバッグオプションの日付時刻文字列を解析する。
	bool ParseDate(const std::string& str, int *y, int *m, int *d, int *w);
	bool ParseTime(const std::string& str, int *h, int *m, int *s);

	// 現在の月の最終日を返す (月の繰り上がり処理用)
	uint GetLastMday() const;

	// イベントコールバック
	void Callback(Event *);

	// イベント間隔
	const uint64 period = 31.25_msec;

	// システムクロックが刻んでいる時刻
	uint64 stime {};

	Syncer *syncer {};

	// RTC クロック入力
	Event *event {};
};

inline RTCDevice *GetRTCDevice() {
	return Object::GetObject<RTCDevice>(OBJ_RTC);
}

unix.superglobalmegacorp.com

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