Files
simulation_Peripheral/Custom_RTC_TLZA.cs

274 lines
11 KiB
C#
Raw Normal View History

2026-03-25 15:03:08 +08:00
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<long, uint> 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<long, uint>();
// 设置启动时间对齐到整秒
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);
}
2026-03-30 16:37:17 +08:00
public long Size => 0x80; // 4KB地址空间
2026-03-25 15:03:08 +08:00
}
}