|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.