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 => 0x80; // 4KB地址空间 } }