From be97d67a653259a8c9d711933b025cee699490d9 Mon Sep 17 00:00:00 2001 From: liuwb Date: Wed, 25 Mar 2026 15:03:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Custom_RTC_TLZA.cs | 274 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 Custom_RTC_TLZA.cs diff --git a/Custom_RTC_TLZA.cs b/Custom_RTC_TLZA.cs new file mode 100644 index 0000000..1cc04cd --- /dev/null +++ b/Custom_RTC_TLZA.cs @@ -0,0 +1,274 @@ +using System; +using System.Collections.Generic; +using Antmicro.Renode.Core; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Logging; + +namespace Antmicro.Renode.Peripherals.Timers +{ + public class Custom_RTC_R17V1 : IDoubleWordPeripheral, IKnownSize + { + // 寄存器偏移地址定义 + private const uint CMD_ADDR_OFFSET = 0x00000000; // 命令寄存器 + private const uint STATUS_ADDR_OFFSET = 0x00000004; // 状态寄存器 + private const uint US_LOW_ADDR_OFFSET = 0x00000008; // 微秒低位 + private const uint US_HIGH_ADDR_OFFSET = 0x0000000C; // 微秒高位 + private const uint SEC_LOW_ADDR_OFFSET = 0x00000010; // 秒低位 + private const uint SEC_HIGH_ADDR_OFFSET = 0x00000014; // 秒高位 + + // 寄存器存储 + private readonly Dictionary registerMap; + private readonly object lockObject = new object(); + private readonly uint baseAddress; + + // 时间相关变量 + private DateTime startTime; + private ulong baseOffsetUs; + private ulong baseOffsetSec; + private bool isTimeLocked; + private uint lockedUsLow; + private uint lockedUsHigh; + private uint lockedSecLow; + private uint lockedSecHigh; + + public Custom_RTC_R17V1(IMachine machine) + { + baseAddress = 0x20800D80; + registerMap = new Dictionary(); + + // 设置启动时间对齐到整秒 + var now = DateTime.Now; + startTime = new DateTime(now.Year, now.Month, now.Day, + now.Hour, now.Minute, now.Second, + DateTimeKind.Local); + + InitializeRegisters(); + LogInitializationInfo(); + } + + private void InitializeRegisters() + { + lock (lockObject) + { + // 初始化所有寄存器为0 + registerMap[CMD_ADDR_OFFSET] = 0x00000000; + registerMap[STATUS_ADDR_OFFSET] = 0x00000000; + registerMap[US_LOW_ADDR_OFFSET] = 0x00000000; + registerMap[US_HIGH_ADDR_OFFSET] = 0x00000000; + registerMap[SEC_LOW_ADDR_OFFSET] = 0x00000000; + registerMap[SEC_HIGH_ADDR_OFFSET] = 0x00000000; + + baseOffsetUs = 0; + baseOffsetSec = 0; + isTimeLocked = false; + lockedUsLow = 0; + lockedUsHigh = 0; + lockedSecLow = 0; + lockedSecHigh = 0; + } + } + + private void LogInitializationInfo() + { + this.Log(LogLevel.Info, "=========================================="); + this.Log(LogLevel.Info, "RTC实时时钟初始化完成"); + this.Log(LogLevel.Info, "基地址: 0x{0:X8}", baseAddress); + this.Log(LogLevel.Info, "6个寄存器,32位有效"); + this.Log(LogLevel.Info, "寄存器定义: CMD(写0xBB锁定时间), US_LOW+US_HIGH(微秒20位), SEC_LOW+SEC_HIGH(秒32位)"); + this.Log(LogLevel.Info, "启动时间已对齐到整秒: {0}", startTime.ToString("HH:mm:ss.fff")); + this.Log(LogLevel.Info, ""); + this.Log(LogLevel.Info, "寄存器地址映射:"); + this.Log(LogLevel.Info, " CMD寄存器 : 地址0x{0:X8} (偏移0x00), 写入0xBB锁定时间", baseAddress + CMD_ADDR_OFFSET); + this.Log(LogLevel.Info, " STATUS寄存器 : 地址0x{0:X8} (偏移0x04), 只读", baseAddress + STATUS_ADDR_OFFSET); + this.Log(LogLevel.Info, " US_LOW寄存器 : 地址0x{0:X8} (偏移0x08), 微秒低16位", baseAddress + US_LOW_ADDR_OFFSET); + this.Log(LogLevel.Info, " US_HIGH寄存器: 地址0x{0:X8} (偏移0x0C), 微秒高4位", baseAddress + US_HIGH_ADDR_OFFSET); + this.Log(LogLevel.Info, " SEC_LOW寄存器: 地址0x{0:X8} (偏移0x10), 秒低16位", baseAddress + SEC_LOW_ADDR_OFFSET); + this.Log(LogLevel.Info, " SEC_HIGH寄存器: 地址0x{0:X8} (偏移0x14), 秒高16位(读取后自动解锁)", baseAddress + SEC_HIGH_ADDR_OFFSET); + this.Log(LogLevel.Info, "=========================================="); + } + + // 获取当前微秒值 + private uint GetCurrentMicrosecondsLow() + { + var elapsed = DateTime.Now - startTime; + if (elapsed.TotalSeconds < 0) + { + this.Log(LogLevel.Error, "检测到系统时间回退!重置startTime"); + startTime = DateTime.Now; + elapsed = TimeSpan.Zero; + } + + double totalSeconds = elapsed.TotalSeconds + (double)baseOffsetSec; + double fractionalSeconds = totalSeconds - Math.Floor(totalSeconds); + ulong microseconds = (ulong)(fractionalSeconds * 1_000_000.0); + + if (microseconds >= 1_000_000) + { + microseconds = 999_999; + } + + return (uint)(microseconds & 0xFFFF); + } + + private uint GetCurrentMicrosecondsHigh() + { + var elapsed = DateTime.Now - startTime; + if (elapsed.TotalSeconds < 0) + { + return 0; + } + + double totalSeconds = elapsed.TotalSeconds + (double)baseOffsetSec; + double fractionalSeconds = totalSeconds - Math.Floor(totalSeconds); + ulong microseconds = (ulong)(fractionalSeconds * 1_000_000.0); + + if (microseconds >= 1_000_000) + { + microseconds = 999_999; + } + + return (uint)((microseconds >> 16) & 0xF); + } + + // 获取当前秒值 + private uint GetCurrentSecondsLow() + { + var elapsed = DateTime.Now - startTime; + if (elapsed.TotalSeconds < 0) + { + return (uint)(baseOffsetSec & 0xFFFF); + } + ulong seconds = baseOffsetSec + (ulong)elapsed.TotalSeconds; + return (uint)(seconds & 0xFFFF); + } + + private uint GetCurrentSecondsHigh() + { + var elapsed = DateTime.Now - startTime; + if (elapsed.TotalSeconds < 0) + { + return (uint)((baseOffsetSec >> 16) & 0xFFFF); + } + ulong seconds = baseOffsetSec + (ulong)elapsed.TotalSeconds; + return (uint)((seconds >> 16) & 0xFFFF); + } + + // 锁定时间 + private void LockTime() + { + lockedUsLow = GetCurrentMicrosecondsLow(); + lockedUsHigh = GetCurrentMicrosecondsHigh(); + lockedSecLow = GetCurrentSecondsLow(); + lockedSecHigh = GetCurrentSecondsHigh(); + isTimeLocked = true; + + this.Log(LogLevel.Debug, "时间已锁定: 微秒=0x{0:X4}{1:X4}, 秒=0x{2:X4}{3:X4}", + lockedUsHigh, lockedUsLow, lockedSecHigh, lockedSecLow); + } + + public uint ReadDoubleWord(long offset) + { + lock (lockObject) + { + uint fullAddress = baseAddress + (uint)offset; + + // 处理各个寄存器的读取 + if (offset == US_LOW_ADDR_OFFSET) + { + uint value = isTimeLocked ? lockedUsLow : GetCurrentMicrosecondsLow(); + this.Log(LogLevel.Info, "US_LOW读取: 地址0x{0:X8} (偏移0x08), 值0x{1:X4}", + fullAddress, value); + return value; + } + else if (offset == US_HIGH_ADDR_OFFSET) + { + uint value = isTimeLocked ? lockedUsHigh : GetCurrentMicrosecondsHigh(); + this.Log(LogLevel.Info, "US_HIGH读取: 地址0x{0:X8} (偏移0x0C), 值0x{1:X4}", + fullAddress, value); + return value; + } + else if (offset == SEC_LOW_ADDR_OFFSET) + { + uint value = isTimeLocked ? lockedSecLow : GetCurrentSecondsLow(); + this.Log(LogLevel.Info, "SEC_LOW读取: 地址0x{0:X8} (偏移0x10), 值0x{1:X4}", + fullAddress, value); + return value; + } + else if (offset == SEC_HIGH_ADDR_OFFSET) + { + uint value = isTimeLocked ? lockedSecHigh : GetCurrentSecondsHigh(); + this.Log(LogLevel.Info, "SEC_HIGH读取: 地址0x{0:X8} (偏移0x14), 值0x{1:X4}", + fullAddress, value); + + // 读取SEC_HIGH后自动解锁 + if (isTimeLocked) + { + isTimeLocked = false; + this.Log(LogLevel.Debug, "时间自动解锁(读取SEC_HIGH后)"); + } + + return value; + } + else if (offset == STATUS_ADDR_OFFSET) + { + uint value = 0; // 状态寄存器始终返回0 + this.Log(LogLevel.Info, "STATUS读取: 地址0x{0:X8} (偏移0x04), 值0x{1:X4}", + fullAddress, value); + return value; + } + + this.Log(LogLevel.Warning, "尝试读取未定义的寄存器偏移: 0x{0:X8} (地址0x{1:X8})", + offset, fullAddress); + return 0; + } + } + + public void WriteDoubleWord(long offset, uint value) + { + lock (lockObject) + { + uint fullAddress = baseAddress + (uint)offset; + + // 只允许写入CMD寄存器 + if (offset == CMD_ADDR_OFFSET) + { + this.Log(LogLevel.Info, "CMD写入: 地址0x{0:X8} (偏移0x00), 值0x{1:X8}", + fullAddress, value); + + if (value == 0xBB) + { + LockTime(); + this.Log(LogLevel.Info, "时间锁定命令已执行"); + } + else + { + this.Log(LogLevel.Warning, "未知的CMD命令: 0x{0:X8}", value); + } + } + else + { + this.Log(LogLevel.Warning, "尝试写入未定义的寄存器偏移: 0x{0:X8} (地址0x{1:X8}), 值0x{2:X8}", + offset, fullAddress, value); + } + } + } + + public void Reset() + { + lock (lockObject) + { + registerMap.Clear(); + InitializeRegisters(); + + // 重置启动时间 + var now = DateTime.Now; + startTime = new DateTime(now.Year, now.Month, now.Day, + now.Hour, now.Minute, now.Second, + DateTimeKind.Local); + } + this.Log(LogLevel.Info, "RTC (基地址0x{0:X8}) 已复位,时间重置", baseAddress); + } + + public long Size => 0x1000; // 4KB地址空间 + } +} \ No newline at end of file