Files
simulation_Peripheral/Custom_RTC_TLZA.cs
2026-03-25 15:03:08 +08:00

274 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
public long Size => 0x1000; // 4KB地址空间
}
}