--- nono/vm/mk48t02.h 2026/04/29 17:04:59 1.1.1.10 +++ nono/vm/mk48t02.h 2026/04/29 17:05:18 1.1.1.13 @@ -4,6 +4,10 @@ // Licensed under nono-license.txt // +// +// NVRAM/RTC (MK48T02) +// + #pragma once #include "device.h" @@ -14,31 +18,65 @@ // MK48T02 の時計部分のレジスタと内部状態 struct MK48T02Clock { + // MK48T02 の場合: + // // b7 b6 b5 b4 b3 b2 b1 b0 // +----+----+----+----+----+----+----+----+ // 7ff | YEAR (4+4bit) | (YEAR: 00..99) // +----+----+----+----+----+----+----+----+ - // 7fe | 0 0 0 | MONTH (1+4bit) | (MONTH: 01..12) + // 7fe | XX XX XX | MONTH (1+4bit) | (MONTH: 01..12) // +----+----+----+----+----+----+----+----+ - // 7fd | XX | 0 | DATE (2+4bit) | (DATE: 01..31) + // 7fd | XX XX | DATE (2+4bit) | (DATE: 01..31) // +----+----+----+----+----+----+----+----+ - // 7fc | XX | FT | XX XX | 0 |WEEKDAY (3bit)| (WEEKDAY: 1..7) + // 7fc | XX | FT | XX XX XX |WEEKDAY (3bit)| (WEEKDAY: 1..7) // +----+----+----+----+----+----+----+----+ - // 7fb | KS | 0 | HOUR (2+4bit) | (HOURS: 00..23) + // 7fb | KS | XX | HOUR (2+4bit) | (HOURS: 00..23) // +----+----+----+----+----+----+----+----+ - // 7fa | 0 | MINUTES (3+4bit) | (MINUTES: 00..59) + // 7fa | XX | MINUTES (3+4bit) | (MINUTES: 00..59) // +----+----+----+----+----+----+----+----+ // 7f9 | ST | SECONDS (3+4bit) | (SECONDS: 00..59) // +----+----+----+----+----+----+----+----+ // 7f8 | W | R | CALIBRATION | (CONTROL) // +----+----+----+----+----+----+----+----+ // - // '0' はデータシートでは '0' で、実際書き込んでも '0' になる。 - // 'XX' はデータシートでは '0' だが '1' が書き込める。 + // '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 のキャリブレーションは未実装。 - uint8 ctrl; static const uint8 WRITE = 0x80; // WRITE BIT static const uint8 READ = 0x40; // READ BIT @@ -54,7 +92,6 @@ struct MK48T02Clock uint8 year; // BCD 年(00-99; 西暦年の下二桁) }; calendar in {}; // 内部カウンタ - calendar ex {}; // 外部レジスタ // 秒カウンタの bit7 が STOP ビット static const uint8 STOP = 0x80; @@ -84,6 +121,8 @@ class MK48T02Device : public RTCDevice bool Init() override; + void StartTime() override; + // 指定したアドレスからの文字列を読み出す (内蔵 ROM からのアクセス用) std::string PeekString(uint32 addr) const; // 指定したアドレスに文字列を書き込む (内蔵 ROM からのアクセス用) @@ -96,6 +135,7 @@ class MK48T02Device : public RTCDevice uint64 Read(uint32 offset); uint64 Write(uint32 offset, uint32 data); uint64 Peek(uint32 offset); + uint64 Poke(uint32 offset, uint32 data) override; // 内蔵カウンタへのアクセス。 // ラッチカウンタではないことに注意。 @@ -136,6 +176,12 @@ class MK48T02Device : public RTCDevice // コントロールレジスタへの書き込み void WriteCtrl(uint32 data); + // NVRAM からカレンダへロード + MK48T02Clock::calendar Load() const; + + // カレンダを NVRAM にストア + void Store(const MK48T02Clock::calendar& cal); + DECLARE_MONITOR_CALLBACK(MonitorUpdate); // ファイル @@ -154,3 +200,7 @@ class MK48T02Device : public RTCDevice Monitor monitor { this }; }; + +static inline MK48T02Device *GetMK48T02Device() { + return Object::GetObject(OBJ_RTC); +}