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

//
// NVRAM/RTC (MK48T02)
//

#pragma once

#include "rtc.h"
#include "mappedfile.h"

// MK48T02 の時計部分のレジスタと内部状態
struct MK48T02Clock
{
	// MK48T02 の場合:
	//
	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +----+----+----+----+----+----+----+----+
	// 7ff |              YEAR (4+4bit)            |  (YEAR: 00..99)
	//     +----+----+----+----+----+----+----+----+
	// 7fe | XX   XX   XX |      MONTH (1+4bit)    |  (MONTH: 01..12)
	//     +----+----+----+----+----+----+----+----+
	// 7fd | XX   XX |         DATE (2+4bit)       |  (DATE: 01..31)
	//     +----+----+----+----+----+----+----+----+
	// 7fc | XX | FT | XX   XX   XX |WEEKDAY (3bit)|  (WEEKDAY: 1..7)
	//     +----+----+----+----+----+----+----+----+
	// 7fb | KS | XX |         HOUR (2+4bit)       |  (HOURS: 00..23)
	//     +----+----+----+----+----+----+----+----+
	// 7fa | XX |           MINUTES (3+4bit)       |  (MINUTES: 00..59)
	//     +----+----+----+----+----+----+----+----+
	// 7f9 | ST |           SECONDS (3+4bit)       |  (SECONDS: 00..59)
	//     +----+----+----+----+----+----+----+----+
	// 7f8 |  W |  R |        CALIBRATION          |  (CONTROL)
	//     +----+----+----+----+----+----+----+----+
	//
	// 'XX' はデータシートでは '0' だが書き込んだ値が読み返せるようだ。
	// SPARCstation2 の PROM で少なくとも +7fa の b7 はそう観測されている
	// ように思える(Issue#75)。他のビットも全部同じ挙動をするかは確認手段
	// が手元にないので分からないが、内部構造的にはただの SRAM が見えてそう
	// な気もするので、とりあえずデータシートで '0' になっているところは
	// 全てメモリとして扱うことにする。何か分かったらまた対応する。
	//
	//
	// (参考までに) M48T02 の場合:
	//
	// 互換チップ M48T02 は、そのデータシート上 '0' のところでも、常に %0
	// しか読み出せないところ (以下表中 '0')と、書き込んだ値が読み出せる
	// ところ (以下表中 'XX') とがあるようだ。
	// また機種によっては以下の位置に BLE/BE 拡張と CEB/CB 拡張がある。
	// BLE, BL は Battery Low Enable, Battery Low。(BL は Read Only)
	// CEB, CB は Century Enable Bit, Century Bit。
	//
	//       b7   b6   b5   b4   b3   b2   b1   b0
	//     +----+----+----+----+----+----+----+----+
	// 7ff |                  YEAR                 |
	//     +----+----+----+----+----+----+----+----+
	// 7fe |  0    0    0 |       MONTH            |
	//     +----+----+----+----+----+----+----+----+
	// 7fd | BLE| BL |            DATE             |
	//     +----+----+----+----+----+----+----+----+
	// 7fc | XX | FT | CEB| CB |  0 |   WEEKDAY    |
	//     +----+----+----+----+----+----+----+----+
	// 7fb | KS |  0 |            HOUR             |
	//     +----+----+----+----+----+----+----+----+
	// 7fa |  0 |               MINUTES            |
	//     +----+----+----+----+----+----+----+----+
	// 7f9 | ST |               SECONDS            |
	//     +----+----+----+----+----+----+----+----+
	// 7f8 |  W |  R |        CALIBRATION          |
	//     +----+----+----+----+----+----+----+----+

	// コントロールレジスタは全ビットを保持。
	// ただし b5-b0 のキャリブレーションは未実装。
	static const uint8 WRITE	= 0x80;	// WRITE BIT
	static const uint8 READ		= 0x40;	// READ BIT

	// 内部のカウンタと毎秒ラッチされるレジスタの2ステージ構成になっている。
	// ここには制御ビット部分は含まない。
	struct calendar {
		uint8 sec;		// BCD 秒(00-59)
		uint8 min;		// BCD 分(00-59)
		uint8 hour;		// BCD 時(00-23)
		uint8 wday;		// 曜日(1-7; 7=日曜)
		uint8 mday;		// BCD 日(01-31)
		uint8 mon;		// BCD 月(01-12)
		uint8 year;		// BCD 年(00-99; 西暦年の下二桁)
	};
	calendar in {};	// 内部カウンタ

	// 秒カウンタの bit7 が STOP ビット。
	static const uint8 STOP = 0x80;
	// STOP 状態を保持。
	uint8 stop {};

	// 時カウンタの bit7 が KICKSTART ビット。
	// KICKSTART は内部発振器のスタートに使用するが、改良版である
	// M48T02 (K なし)では廃止された。動作は実装しない。
	static const uint8 KICKSTART = 0x80;
	// KICKSTART 状態を保持
	uint8 kickstart {};

	// 曜日カウンタの bit6 が Frequency Test ビット。動作は実装しない。
	static const uint8 FREQTEST = 0x40;
	// FreqTest 状態を保持
	uint8 freqtest {};
};

class MK48T02Device : public RTCDevice
{
	using inherited = RTCDevice;
 public:
	MK48T02Device();
	~MK48T02Device() override;

	bool Init() override;

	void StartTime() override;

	// 指定したアドレスからの文字列を読み出す (内蔵 ROM からのアクセス用)
	std::string PeekString(uint32 addr) const;
	// 指定したアドレスに文字列を書き込む (内蔵 ROM からのアクセス用)
	bool WriteString(uint32 addr, const std::string& data);
	// 全域をゼロクリアする (内蔵 ROM からのアクセス用)
	void ClearAll();

	// 内蔵カウンタへのアクセス。
	// ラッチカウンタではないことに注意。
	uint GetSec() const override;	// 秒(0-59)
	uint GetMin() const override;	// 分(0-59)
	uint GetHour() const override;	// 時(0-23)
	uint GetWday() const override;	// 曜日(0が日曜)
	uint GetMday() const override;	// 日(1-31)
	uint GetMon() const override;	// 月(1-12)
	uint GetYear() const override;	// 年(西暦)
	uint GetLeap() const override;	// うるう年カウンタ(0..3)

	// BusIO インタフェース
	// (内蔵 ROM からのアクセス用に特別に public にしてある)
	busdata ReadPort(uint32 offset);
	busdata WritePort(uint32 offset, uint32 data);
	busdata PeekPort(uint32 offset);
 protected:
	static const uint32 NPORT = 2048;
	bool PokePort(uint32 offset, uint32 data);

	// 仮想RTCからのクロック
	void Tick1Hz() override;

	// 内蔵カウンタへのアクセス。
	void SetSec(uint v) override;
	void SetMin(uint v) override;
	void SetHour(uint v) override;
	void SetWday(uint v) override;
	void SetMday(uint v) override;
	void SetMon(uint v) override;
	void SetYear(uint v) override;
	void SetLeap(uint v) override;

 private:
	// バイナリ <-> BCD 変換
	static inline uint8 num2BCD(uint8);
	static inline uint8 BCD2num(uint8);

	// 年のデコード。
	uint DecodeYear(uint bcd_year) const;

	// コントロールレジスタへの書き込み
	void WriteCtrl(uint32 data);

	// NVRAM からカレンダへロード
	MK48T02Clock::calendar Load() const;

	// カレンダを NVRAM にストア
	void Store(const MK48T02Clock::calendar& cal);

	DECLARE_MONITOR_SCREEN(MonitorScreen);

	// ファイル
	std::string filename {};
	MappedFile file {};
	uint8 *mem {};

	// 時計
	MK48T02Clock reg {};

	// うるう年補正量
	uint adjust_leap {};

	// 外部レジスタをホールド(更新停止)しているときは true
	bool hold {};

	Monitor *monitor {};
};

inline MK48T02Device *GetMK48T02Device() {
	return Object::GetObject<MK48T02Device>(OBJ_RTC);
}

unix.superglobalmegacorp.com

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