Compare commits

...

21 Commits

Author SHA1 Message Date
dc5c201933 更新 SJA1000_CAN.cs
修改缓冲区为队列
2026-04-17 08:55:34 +08:00
14e8fcb94b 上传文件至「/」 2026-04-16 14:14:08 +08:00
8d994d82cb 上传文件至「/」 2026-04-14 09:05:32 +08:00
f2c4529212 上传文件至「/」
模板文件
2026-04-10 16:39:39 +08:00
d301451757 上传文件至「/」 2026-04-01 11:03:44 +08:00
a74f508c32 上传文件至「/」 2026-04-01 10:47:29 +08:00
482f44b7cc 上传文件至「/」 2026-04-01 10:46:42 +08:00
be1fc1495f 上传文件至「/」 2026-04-01 10:46:14 +08:00
d276237532 上传文件至「/」 2026-03-31 17:52:48 +08:00
50c00e2723 上传文件至「/」 2026-03-30 17:48:41 +08:00
8795aa4476 上传文件至「/」 2026-03-30 17:22:32 +08:00
3a5d1263d7 上传文件至「/」 2026-03-30 16:37:17 +08:00
040d8fa1ab 上传文件至「/」 2026-03-30 16:36:33 +08:00
45a6d8d4be 上传文件至「/」
地测串口
2026-03-30 16:34:41 +08:00
4528700b84 上传文件至「/」 2026-03-25 16:01:19 +08:00
0bb3dcf93b 上传文件至「/」 2026-03-25 15:58:59 +08:00
liuwb
f71918cc95 task 2026-03-25 15:48:09 +08:00
liuwb
be97d67a65 时间 2026-03-25 15:03:08 +08:00
liuwb
699d6216ae 时间片+中断控制器成功版本 2026-03-25 14:20:10 +08:00
dengxingting
73aad61a78 OC 2026-03-23 10:53:21 +08:00
dengxingting
71a97fd10d ADC代码(ADC0) 2026-03-23 10:49:49 +08:00
21 changed files with 6703 additions and 0 deletions

40
1.txt Normal file
View File

@@ -0,0 +1,40 @@
task_create_info default_task_create_table[TASK_MAX_NUM] = {
{0},
{TRUE, FUNC_STR_AND_NAME(app_daq_main), 32768, VX_FP_TASK,
85, TASK_RNDALL, TASK_TYPE_DAQ, TASK_ERRACT_RESET,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(orbit_main), 16384, VX_FP_TASK,
97, TASK_RNDALL, TASK_TYPE_ORBIT, TASK_ERRACT_RESET,
TASK_RUN_IN_CYCLE},
{FALSE, FUNC_STR_AND_NAME(PoseDertMng), 32768, VX_FP_TASK,
100, TASK_RNDALL, TASK_TYPE_AOCS1, TASK_ERRACT_RESET,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(PoseCtrlMain), 32768, VX_FP_TASK,
101, TASK_RNDALL, TASK_TYPE_AOCS2, TASK_ERRACT_RESET,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(tc_main), 32768, 0,
90, TASK_RNDA, TASK_TYPE_TC, TASK_ERRACT_REBOOT,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(tm_main), 32768, VX_FP_TASK,
87, TASK_RNDALL, TASK_TYPE_TM, TASK_ERRACT_REBOOT,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(energy_main), 16384, VX_FP_TASK,
110, TASK_RNDB, TASK_TYPE_ENERGY, TASK_ERRACT_REBOOT,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(thermal_main), 16384, VX_FP_TASK,
112, TASK_RNDC, TASK_TYPE_THERMAL, TASK_ERRACT_REBOOT,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(ground_test_main), 32768, 0,
92, TASK_RNDALL, TASK_TYPE_GTEST, TASK_ERRACT_RESET,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(amm_main), 32768, VX_FP_TASK,
115, TASK_RNDD, TASK_TYPE_AMM, TASK_ERRACT_REBOOT,
TASK_RUN_IN_CYCLE},
{TRUE, FUNC_STR_AND_NAME(auto_assemble_pkg_initial), 8192, 0,
96, TASK_RNDA, TASK_TYPE_AUTO_TM, TASK_ERRACT_RESET,
TASK_RUN_ONCE},
};

274
Custom_RTC_TLZA.cs Normal file
View File

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

238
Custom_TLZA_ADU.cs Normal file
View File

@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Logging;
namespace Antmicro.Renode.Peripherals.ADUADC0
{
public class ADU0 : IDoubleWordPeripheral, IKnownSize
{
// 通道组内部偏移(来自表格,未左移)
private const uint GROUP1_START = 0x122; // 通道 1-14
private const uint GROUP2_START = 0x142; // 通道 15-28
private const uint GROUP3_START = 0x162; // 通道 29-42
private const uint GROUP4_START = 0x182; // 通道 43-56
private const uint GROUP5_START = 0x1A2; // 通道 57-64
// 寄存器存储
private readonly Dictionary<long, ushort> registerMap;
private readonly object lockObject = new object();
private readonly uint baseAddress;
public ADU0(IMachine machine)
{
// ADC0基地址
baseAddress = 0x21800000;
registerMap = new Dictionary<long, ushort>();
InitializeRegisters();
LogInitializationInfo();
}
private void InitializeRegisters()
{
lock (lockObject)
{
// ========== 第一组: 通道 1-14 (ADC0通道1-14) ==========
// 通道 1-2
registerMap[GROUP1_START << 2] = 1;
registerMap[(GROUP1_START << 2) + 4] = 2;
// 通道 3-4
registerMap[(GROUP1_START + 4) << 2] = 3;
registerMap[((GROUP1_START + 4) << 2) + 4] = 4;
// 通道 5-6
registerMap[(GROUP1_START + 8) << 2] = 5;
registerMap[((GROUP1_START + 8) << 2) + 4] = 6;
// 通道 7-8
registerMap[(GROUP1_START + 12) << 2] = 7;
registerMap[((GROUP1_START + 12) << 2) + 4] = 8;
// 通道 9-10
registerMap[(GROUP1_START + 16) << 2] = 9;
registerMap[((GROUP1_START + 16) << 2) + 4] = 10;
// 通道 11-12
registerMap[(GROUP1_START + 20) << 2] = 11;
registerMap[((GROUP1_START + 20) << 2) + 4] = 12;
// 通道 13-14
registerMap[(GROUP1_START + 24) << 2] = 13;
registerMap[((GROUP1_START + 24) << 2) + 4] = 14;
// ========== 第二组: 通道 15-28 (ADC0通道15-28) ==========
// 通道 15-16
registerMap[GROUP2_START << 2] = 15;
registerMap[(GROUP2_START << 2) + 4] = 16;
// 通道 17-18
registerMap[(GROUP2_START + 4) << 2] = 17;
registerMap[((GROUP2_START + 4) << 2) + 4] = 18;
// 通道 19-20
registerMap[(GROUP2_START + 8) << 2] = 19;
registerMap[((GROUP2_START + 8) << 2) + 4] = 20;
// 通道 21-22
registerMap[(GROUP2_START + 12) << 2] = 21;
registerMap[((GROUP2_START + 12) << 2) + 4] = 22;
// 通道 23-24
registerMap[(GROUP2_START + 16) << 2] = 23;
registerMap[((GROUP2_START + 16) << 2) + 4] = 24;
// 通道 25-26
registerMap[(GROUP2_START + 20) << 2] = 25;
registerMap[((GROUP2_START + 20) << 2) + 4] = 26;
// 通道 27-28
registerMap[(GROUP2_START + 24) << 2] = 27;
registerMap[((GROUP2_START + 24) << 2) + 4] = 28;
// ========== 第三组: 通道 29-42 (ADC0通道29-42) ==========
// 通道 29-30
registerMap[GROUP3_START << 2] = 29;
registerMap[(GROUP3_START << 2) + 4] = 30;
// 通道 31-32
registerMap[(GROUP3_START + 4) << 2] = 31;
registerMap[((GROUP3_START + 4) << 2) + 4] = 32;
// 通道 33-34
registerMap[(GROUP3_START + 8) << 2] = 33;
registerMap[((GROUP3_START + 8) << 2) + 4] = 34;
// 通道 35-36
registerMap[(GROUP3_START + 12) << 2] = 35;
registerMap[((GROUP3_START + 12) << 2) + 4] = 36;
// 通道 37-38
registerMap[(GROUP3_START + 16) << 2] = 37;
registerMap[((GROUP3_START + 16) << 2) + 4] = 38;
// 通道 39-40
registerMap[(GROUP3_START + 20) << 2] = 39;
registerMap[((GROUP3_START + 20) << 2) + 4] = 40;
// 通道 41-42
registerMap[(GROUP3_START + 24) << 2] = 41;
registerMap[((GROUP3_START + 24) << 2) + 4] = 42;
// ========== 第四组: 通道 43-56 (ADC0通道43-56) ==========
// 通道 43-44
registerMap[GROUP4_START << 2] = 43;
registerMap[(GROUP4_START << 2) + 4] = 44;
// 通道 45-46
registerMap[(GROUP4_START + 4) << 2] = 45;
registerMap[((GROUP4_START + 4) << 2) + 4] = 46;
// 通道 47-48
registerMap[(GROUP4_START + 8) << 2] = 47;
registerMap[((GROUP4_START + 8) << 2) + 4] = 48;
// 通道 49-50
registerMap[(GROUP4_START + 12) << 2] = 49;
registerMap[((GROUP4_START + 12) << 2) + 4] = 50;
// 通道 51-52
registerMap[(GROUP4_START + 16) << 2] = 51;
registerMap[((GROUP4_START + 16) << 2) + 4] = 52;
// 通道 53-54
registerMap[(GROUP4_START + 20) << 2] = 53;
registerMap[((GROUP4_START + 20) << 2) + 4] = 54;
// 通道 55-56
registerMap[(GROUP4_START + 24) << 2] = 55;
registerMap[((GROUP4_START + 24) << 2) + 4] = 56;
// ========== 第五组: 通道 57-64 (ADC0通道57-64) ==========
// 通道 57-58
registerMap[GROUP5_START << 2] = 57;
registerMap[(GROUP5_START << 2) + 4] = 58;
// 通道 59-60
registerMap[(GROUP5_START + 4) << 2] = 59;
registerMap[((GROUP5_START + 4) << 2) + 4] = 60;
// 通道 61-62
registerMap[(GROUP5_START + 8) << 2] = 61;
registerMap[((GROUP5_START + 8) << 2) + 4] = 62;
// 通道 63-64
registerMap[(GROUP5_START + 12) << 2] = 63;
registerMap[((GROUP5_START + 12) << 2) + 4] = 64;
}
}
private void LogInitializationInfo()
{
this.Log(LogLevel.Info, "==========================================");
this.Log(LogLevel.Info, "ADU0初始化完成");
this.Log(LogLevel.Info, "ADC0基地址: 0x{0:X8}", baseAddress);
this.Log(LogLevel.Info, "64个通道寄存器低16位有效初始值=通道号");
this.Log(LogLevel.Info, "通道1-64 (ADC0内部通道1-64)");
this.Log(LogLevel.Info, "");
this.Log(LogLevel.Info, "重要地址映射:");
this.Log(LogLevel.Info, " 通道1 地址: 0x{0:X8}", baseAddress + (GROUP1_START << 2));
this.Log(LogLevel.Info, " 通道2 地址: 0x{0:X8}", baseAddress + (GROUP1_START << 2) + 4);
this.Log(LogLevel.Info, " 通道64 地址: 0x{0:X8}", baseAddress + ((GROUP5_START + 12) << 2) + 4);
this.Log(LogLevel.Info, "==========================================");
}
public uint ReadDoubleWord(long offset)
{
lock (lockObject)
{
uint fullAddress = baseAddress + (uint)offset;
if (registerMap.TryGetValue(offset, out ushort value))
{
this.Log(LogLevel.Debug, "ADC0读取: 地址0x{0:X8} (偏移0x{1:X8}), 值0x{2:X4} (通道{3})",
fullAddress, offset, value, value);
return value;
}
this.Log(LogLevel.Warning, "ADC0读取未定义地址: 0x{0:X8} (偏移0x{1:X8})", fullAddress, offset);
return 0;
}
}
public void WriteDoubleWord(long offset, uint value)
{
lock (lockObject)
{
uint fullAddress = baseAddress + (uint)offset;
if (registerMap.ContainsKey(offset))
{
ushort writeValue = (ushort)(value & 0xFFFF);
registerMap[offset] = writeValue;
this.Log(LogLevel.Info, "ADC0写入: 地址0x{0:X8} (偏移0x{1:X8}), 值0x{2:X4} (通道{3})",
fullAddress, offset, writeValue, writeValue);
}
else
{
this.Log(LogLevel.Warning, "ADC0尝试写入未定义地址: 0x{0:X8} (偏移0x{1:X8}), 值0x{2:X8}",
fullAddress, offset, value);
}
}
}
public void Reset()
{
lock (lockObject)
{
registerMap.Clear();
InitializeRegisters();
}
this.Log(LogLevel.Info, "ADC0 (基地址0x{0:X8}) 已复位", baseAddress);
}
public long Size => 0x0700;
}
}

169
Custom_TLZA_OC_HDC1.cs Normal file
View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Logging;
namespace Antmicro.Renode.Peripherals.ThermalOC
{
public class ThermalOC1 : IDoubleWordPeripheral, IKnownSize
{
private readonly Dictionary<long, byte> registerMap;
private readonly object lockObject = new object();
private readonly uint baseAddress;
private const uint REG_HEAT_1_8 = 0x20; // 1-8路加热输出
private const uint REG_HEAT_9_16 = 0x24; // 9-16路加热输出
private const uint REG_HEAT_17_24 = 0x28; // 17-24路加热输出
private const uint REG_HEAT_25_32 = 0x2C; // 25-32路加热输出
private const uint REG_HEAT_33_40 = 0x30; // 33-40路加热输出
private const uint REG_HEAT_41_48 = 0x34; // 41-48路加热输出
private const uint REG_HEAT_49_56 = 0x38; // 49-56路加热输出
private const uint REG_HEAT_57_64 = 0x3C; // 57-64路加热输出
private readonly (uint offset, int start, int end)[] registers = new[]
{
(REG_HEAT_1_8, 1, 8),
(REG_HEAT_9_16, 9, 16),
(REG_HEAT_17_24, 17, 24),
(REG_HEAT_25_32, 25, 32),
(REG_HEAT_33_40, 33, 40),
(REG_HEAT_41_48, 41, 48),
(REG_HEAT_49_56, 49, 56),
(REG_HEAT_57_64, 57, 64)
};
public ThermalOC1(IMachine machine)
{
baseAddress = 0x22000000;
registerMap = new Dictionary<long, byte>();
InitializeRegisters();
LogInitializationInfo();
}
private void InitializeRegisters()
{
lock (lockObject)
{
foreach (var reg in registers)
{
registerMap[reg.offset] = 0x00;
}
}
}
private void LogInitializationInfo()
{
this.Log(LogLevel.Info, "==========================================");
this.Log(LogLevel.Info, "热控OC1初始化完成");
this.Log(LogLevel.Info, "基地址: 0x{0:X8}", baseAddress);
this.Log(LogLevel.Info, "每个寄存器控制8路加热输出");
this.Log(LogLevel.Info, "共64路加热输出通道 (通道1-64)");
this.Log(LogLevel.Info, "寄存器定义: 低8位有效1表示输出0表示关闭");
this.Log(LogLevel.Info, "位对应关系: D0=通道起始, D7=通道起始+7");
this.Log(LogLevel.Info, "所有通道初始状态: 关闭");
this.Log(LogLevel.Info, "");
this.Log(LogLevel.Info, "寄存器地址映射:");
foreach (var reg in registers)
{
uint fullAddress = baseAddress + reg.offset;
this.Log(LogLevel.Info, " 地址0x{0:X8} (偏移0x{1:X2}), 控制通道{2}-{3}",
fullAddress, reg.offset, reg.start, reg.end);
}
this.Log(LogLevel.Info, "==========================================");
}
private string GetBinaryString(byte value)
{
return Convert.ToString(value, 2).PadLeft(8, '0');
}
private string GetChannelStatus(byte value, int start)
{
List<string> active = new List<string>();
for (int i = 0; i < 8; i++)
{
if ((value & (1 << i)) != 0)
{
active.Add($"通道{start + i}");
}
}
return active.Count > 0 ? string.Join(", ", active) : "无";
}
public uint ReadDoubleWord(long offset)
{
lock (lockObject)
{
uint fullAddress = baseAddress + (uint)offset;
foreach (var reg in registers)
{
if (offset == reg.offset)
{
if (registerMap.TryGetValue(offset, out byte value))
{
string binary = GetBinaryString(value);
string channels = GetChannelStatus(value, reg.start);
this.Log(LogLevel.Info, "热控OC1读取: 地址0x{0:X8} (偏移0x{1:X2})", fullAddress, offset);
this.Log(LogLevel.Info, " 十六进制: 0x{0:X2}", value);
this.Log(LogLevel.Info, " 二进制: {0} (D7-D0)", binary);
this.Log(LogLevel.Info, " 开启通道: {0}", channels);
return value;
}
break;
}
}
this.Log(LogLevel.Warning, "热控OC1读取未定义地址: 0x{0:X8}", fullAddress);
return 0;
}
}
public void WriteDoubleWord(long offset, uint value)
{
lock (lockObject)
{
uint fullAddress = baseAddress + (uint)offset;
byte writeValue = (byte)(value & 0xFF);
foreach (var reg in registers)
{
if (offset == reg.offset)
{
byte oldValue = registerMap.ContainsKey(offset) ? registerMap[offset] : (byte)0;
registerMap[offset] = writeValue;
string oldBinary = GetBinaryString(oldValue);
string newBinary = GetBinaryString(writeValue);
string newChannels = GetChannelStatus(writeValue, reg.start);
this.Log(LogLevel.Info, "热控OC1写入: 地址0x{0:X8} (偏移0x{1:X2})", fullAddress, offset);
this.Log(LogLevel.Info, " 写入值: 0x{0:X2} (二进制: {1})", writeValue, newBinary);
this.Log(LogLevel.Info, " 原值: 0x{0:X2} (二进制: {1})", oldValue, oldBinary);
this.Log(LogLevel.Info, " 开启通道: {0}", newChannels);
return;
}
}
this.Log(LogLevel.Warning, "热控OC1尝试写入未定义地址: 0x{0:X8}, 值0x{1:X2}", fullAddress, writeValue);
}
}
public void Reset()
{
lock (lockObject)
{
registerMap.Clear();
InitializeRegisters();
}
this.Log(LogLevel.Info, "热控OC1 (基地址0x{0:X8}) 已复位", baseAddress);
}
public long Size => 0x40;
}
}

View File

@@ -0,0 +1,387 @@
//============================================================================
// 作者liuwenbo
// 日期2026-03-24-2026-03-25
//============================================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.IRQControllers;
namespace Antmicro.Renode.Peripherals.Timers
{
public class LC3233_TaskTimer : BasicDoubleWordPeripheral, IKnownSize
{
public LC3233_TaskTimer(IMachine machine) : base(machine)
{
this.machine = machine;
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 定时器已初始化 @ 0x80000000");
this.Log(LogLevel.Info, " 周期: 250ms (4Hz), 用于VxWorks任务调度");
}
private void ScheduleNextTick()
{
if(timerScheduled || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
timerScheduled = true;
var generation = timerGeneration;
machine.ScheduleAction(TimeInterval.FromMilliseconds(250), _ =>
{
timerScheduled = false;
if(generation != timerGeneration || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
OnTimerExpired();
});
}
private void OnTimerExpired()
{
timerExpiredCount++;
isPending = true;
this.Log(LogLevel.Info, "========== 定时器溢出 #{0} ==========", timerExpiredCount);
this.Log(LogLevel.Info, "准备触发中断线4...");
IRQ.Set(true);
this.Log(LogLevel.Info, "已调用 IRQ.Set(true),信号应发送到 lc3233IntCtrl@4");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "中断脉冲结束");
});
if ((timerCtrl & TIMER_CTRL_T0_LOEN) != 0)
{
timer0Cntr = timer0Reld;
ScheduleNextTick();
}
}
private void DefineRegisters()
{
Registers.TimerCtrl.Define(this)
.WithValueField(0, 32, name: "timer_ctrl",
writeCallback: (_, val) =>
{
timerCtrl = (uint)val;
// Bit 0: Timer0 Enable
bool t0Enable = (val & TIMER_CTRL_T0_EN) != 0;
if(!t0Enable)
{
timerGeneration++;
timerScheduled = false;
}
else
{
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
this.Log(LogLevel.Info, "TIMER_CTRL 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " Timer0 Enable: {0}", t0Enable);
this.Log(LogLevel.Info, " Auto Reload: {0}", (val & TIMER_CTRL_T0_LOEN) != 0);
},
valueProviderCallback: _ => timerCtrl);
Registers.Timer0Cntr.Define(this)
.WithValueField(0, 32, name: "timer0_cntr",
writeCallback: (_, val) =>
{
timer0Cntr = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_CNTR 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Cntr);
Registers.Timer0Reld.Define(this)
.WithValueField(0, 32, name: "timer0_reld",
writeCallback: (_, val) =>
{
timer0Reld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Reld);
Registers.Timer0DivFreq.Define(this)
.WithValueField(0, 32, name: "timer0_divfreq",
writeCallback: (_, val) =>
{
timer0DivFreq = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DIVFREQ 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DivFreq);
Registers.Timer0DfReld.Define(this)
.WithValueField(0, 32, name: "timer0_df_reld",
writeCallback: (_, val) =>
{
timer0DfReld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DF_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DfReld);
}
public override void Reset()
{
base.Reset();
timerCtrl = TIMER_CTRL_T0_EN | TIMER_CTRL_T0_LOEN;
timer0Cntr = 0;
timer0Reld = 0;
timer0DivFreq = 0;
timer0DfReld = 0;
isPending = false;
timerExpiredCount = 0;
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
public long Size => 0x100;
public GPIO IRQ { get; } = new GPIO();
private enum Registers
{
TimerCtrl = 0x00,
Timer0Cntr = 0x04,
Timer0Reld = 0x08,
WdgCntr = 0x0C,
Timer1Cntr = 0x10,
Timer1Reld = 0x14,
Timer0DivFreq = 0x18,
Timer0DfReld = 0x1C,
}
private const uint TIMER_CTRL_T0_EN = 0x00000001;
private const uint TIMER_CTRL_T0_LOEN = 0x00000002;
private const uint TIMER_CTRL_T0_RSTA = 0x00000004;
private readonly IMachine machine;
private uint timerCtrl;
private uint timer0Cntr;
private uint timer0Reld;
private uint timer0DivFreq;
private uint timer0DfReld;
private bool isPending;
private bool timerScheduled;
private ulong timerGeneration;
private ulong timerExpiredCount;
}
}
namespace Antmicro.Renode.Peripherals.IRQControllers
{
public class LC3233_InterruptController : BasicDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput, IGPIOReceiver
{
public LC3233_InterruptController(IMachine machine) : base(machine)
{
this.machine = machine;
connections = new Dictionary<int, IGPIO>();
for (int i = 0; i <= 15; i++)
{
connections[i] = new GPIO();
}
Connections = new ReadOnlyDictionary<int, IGPIO>(connections);
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000");
this.Log(LogLevel.Info, " 管理15个中断源 (1-15)");
}
/// <summary>
/// 定义寄存器映射
/// </summary>
private void DefineRegisters()
{
Registers.IntMaskPriority.Define(this)
.WithValueField(0, 32, name: "int_mask_priority",
writeCallback: (_, val) =>
{
intMaskPriority = (uint)val;
this.Log(LogLevel.Info, "INT_MASK_PRIORITY 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " 临时兼容: IRQ4 强制视为使能");
for (int i = 1; i <= 15; i++)
{
if ((val & (uint)(1 << i)) != 0)
{
this.Log(LogLevel.Debug, " 中断 {0} 已使能", i);
}
}
UpdateInterrupts();
},
valueProviderCallback: _ => intMaskPriority);
Registers.IntFTP.Define(this)
.WithValueField(0, 32, name: "int_f_t_p",
writeCallback: (_, val) =>
{
intFTP |= (uint)val;
this.Log(LogLevel.Debug, "INT_F_T_P 写入: 0x{0:X8}, 当前值: 0x{1:X8}", val, intFTP);
UpdateInterrupts();
},
valueProviderCallback: _ => intFTP);
Registers.IntForce.Define(this)
.WithValueField(0, 32, FieldMode.Write, name: "int_force",
writeCallback: (_, val) =>
{
this.Log(LogLevel.Info, "INT_FORCE 写入: 0x{0:X8}", val);
intFTP |= (uint)val;
UpdateInterrupts();
});
Registers.IntClr.Define(this)
.WithValueField(0, 32, FieldMode.Write, name: "int_clr",
writeCallback: (_, val) =>
{
this.Log(LogLevel.Debug, "INT_CLR 写入: 0x{0:X8}", val);
intFTP &= ~(uint)val;
UpdateInterrupts();
});
}
public void OnGPIO(int irq, bool value)
{
if (irq < 0 || irq > 15)
{
this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
return;
}
this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
if (value)
{
intFTP |= (uint)(1 << irq);
this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
}
else
{
}
this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
UpdateInterrupts();
}
private void UpdateInterrupts()
{
this.Log(LogLevel.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}",
intMaskPriority, intFTP);
for (int i = 1; i <= 15; i++)
{
bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4);
bool pending = (intFTP & (uint)(1 << i)) != 0;
if (i == 4)
{
this.Log(LogLevel.Info, "IRQ4 状态检查: masked={0}, pending={1}", masked, pending);
}
if (masked && pending)
{
if (Connections.TryGetValue(i, out var gpio))
{
this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i);
gpio.Set(true);
var localI = i;
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
if (Connections.TryGetValue(localI, out var g))
{
g.Set(false);
}
});
}
else
{
this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i);
}
}
}
}
public override void Reset()
{
base.Reset();
intMaskPriority = 0;
intFTP = 0;
}
public long Size => 0x10;
public IReadOnlyDictionary<int, IGPIO> Connections { get; }
private readonly IMachine machine;
private readonly Dictionary<int, IGPIO> connections;
private readonly bool forceEnableIRQ4 = true;
private uint intMaskPriority;
private uint intFTP;
// 寄存器定义
private enum Registers
{
IntMaskPriority = 0x00,
IntFTP = 0x04,
IntForce = 0x08,
IntClr = 0x0C,
}
}
}

View File

@@ -0,0 +1,441 @@
//============================================================================
// 作者liuwenbo
// 日期2026-03-24-2026-03-25
//============================================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.IRQControllers;
namespace Antmicro.Renode.Peripherals.Timers
{
public class LC3233_TaskTimer : BasicDoubleWordPeripheral, IKnownSize
{
public LC3233_TaskTimer(IMachine machine) : base(machine)
{
this.machine = machine;
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 定时器已初始化 @ 0x80000000");
this.Log(LogLevel.Info, " 周期: 250ms (4Hz), 用于VxWorks任务调度");
}
private void ScheduleNextTick()
{
if(timerScheduled || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
timerScheduled = true;
var generation = timerGeneration;
machine.ScheduleAction(TimeInterval.FromMilliseconds(250), _ =>
{
timerScheduled = false;
if(generation != timerGeneration || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
OnTimerExpired();
});
}
private void OnTimerExpired()
{
timerExpiredCount++;
//isPending = true;
this.Log(LogLevel.Info, "========== 定时器溢出 #{0} ==========", timerExpiredCount);
this.Log(LogLevel.Info, "准备触发中断线4...");
IRQ.Set(true);
this.Log(LogLevel.Info, "已调用 IRQ.Set(true),信号应发送到 lc3233IntCtrl@4");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "中断脉冲结束");
});
if ((timerCtrl & TIMER_CTRL_T0_LOEN) != 0)
{
timer0Cntr = timer0Reld;
ScheduleNextTick();
}
}
private void DefineRegisters()
{
Registers.TimerCtrl.Define(this)
.WithValueField(0, 32, name: "timer_ctrl",
writeCallback: (_, val) =>
{
timerCtrl = (uint)val;
// Bit 0: Timer0 Enable
bool t0Enable = (val & TIMER_CTRL_T0_EN) != 0;
if(!t0Enable)
{
timerGeneration++;
timerScheduled = false;
}
else
{
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
this.Log(LogLevel.Info, "TIMER_CTRL 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " Timer0 Enable: {0}", t0Enable);
this.Log(LogLevel.Info, " Auto Reload: {0}", (val & TIMER_CTRL_T0_LOEN) != 0);
},
valueProviderCallback: _ => timerCtrl);
Registers.Timer0Cntr.Define(this)
.WithValueField(0, 32, name: "timer0_cntr",
writeCallback: (_, val) =>
{
timer0Cntr = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_CNTR 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Cntr);
Registers.Timer0Reld.Define(this)
.WithValueField(0, 32, name: "timer0_reld",
writeCallback: (_, val) =>
{
timer0Reld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Reld);
Registers.Timer0DivFreq.Define(this)
.WithValueField(0, 32, name: "timer0_divfreq",
writeCallback: (_, val) =>
{
timer0DivFreq = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DIVFREQ 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DivFreq);
Registers.Timer0DfReld.Define(this)
.WithValueField(0, 32, name: "timer0_df_reld",
writeCallback: (_, val) =>
{
timer0DfReld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DF_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DfReld);
}
public override void Reset()
{
base.Reset();
timerCtrl = TIMER_CTRL_T0_EN | TIMER_CTRL_T0_LOEN;
timer0Cntr = 0;
timer0Reld = 0;
timer0DivFreq = 0;
timer0DfReld = 0;
isPending = false;
timerExpiredCount = 0;
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
public long Size => 0x100;
public GPIO IRQ { get; } = new GPIO();
private enum Registers
{
TimerCtrl = 0x00,
Timer0Cntr = 0x04,
Timer0Reld = 0x08,
WdgCntr = 0x0C,
Timer1Cntr = 0x10,
Timer1Reld = 0x14,
Timer0DivFreq = 0x18,
Timer0DfReld = 0x1C,
}
private const uint TIMER_CTRL_T0_EN = 0x00000001;
private const uint TIMER_CTRL_T0_LOEN = 0x00000002;
private const uint TIMER_CTRL_T0_RSTA = 0x00000004;
private readonly IMachine machine;
private uint timerCtrl;
private uint timer0Cntr;
private uint timer0Reld;
private uint timer0DivFreq;
private uint timer0DfReld;
private bool isPending;
private bool timerScheduled;
private ulong timerGeneration;
private ulong timerExpiredCount;
}
}
namespace Antmicro.Renode.Peripherals.IRQControllers
{
public class LC3233_InterruptController : BasicDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput, IGPIOReceiver
{
public LC3233_InterruptController(IMachine machine) : base(machine)
{
this.machine = machine;
connections = new Dictionary<int, IGPIO>();
for (int i = 0; i <= 15; i++)
{
connections[i] = new GPIO();
}
Connections = new ReadOnlyDictionary<int, IGPIO>(connections);
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000");
this.Log(LogLevel.Info, " 管理15个中断源 (1-15)");
}
/// <summary>
/// 定义寄存器映射
/// </summary>
private void DefineRegisters()
{
// Registers.IntMaskPriority.Define(this)
// .WithValueField(0, 32, name: "int_mask_priority",
// writeCallback: (_, val) =>
// {
// intMaskPriority = (uint)val;
// this.Log(LogLevel.Info, "INT_MASK_PRIORITY 写入: 0x{0:X8}", val);
// this.Log(LogLevel.Info, " 临时兼容: IRQ4 强制视为使能");
// for (int i = 1; i <= 15; i++)
// {
// if ((val & (uint)(1 << i)) != 0)
// {
// this.Log(LogLevel.Debug, " 中断 {0} 已使能", i);
// }
// }
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intMaskPriority);
// Registers.IntFTP.Define(this)
// .WithValueField(0, 32, name: "int_f_t_p",
// writeCallback: (_, val) =>
// {
// intFTP |= (uint)val;
// this.Log(LogLevel.Debug, "INT_F_T_P 写入: 0x{0:X8}, 当前值: 0x{1:X8}", val, intFTP);
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intFTP);
// Registers.IntForce.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_force",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Info, "INT_FORCE 写入: 0x{0:X8}", val);
// intFTP |= (uint)val;
// UpdateInterrupts();
// });
// Registers.IntClr.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_clr",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Debug, "INT_CLR 写入: 0x{0:X8}", val);
// intFTP &= ~(uint)val;
// UpdateInterrupts();
// });
}
public void OnGPIO(int irq, bool value)
{
if (irq < 0 || irq > 15)
{
this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
return;
}
if(value)
{
this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// 自动使能中断
intMaskPriority |= (uint)(1 << irq);
this.Log(LogLevel.Info, "自动使能中断 {0}: INT_MASK_PRIORITY = 0x{1:X8}",
irq, intMaskPriority);
//设置挂起寄存器
intFTP |= (uint)(1 << irq);
this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
UpdateInterrupts();
}
else
{
}
//this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
//UpdateInterrupts();
// if (irq < 0 || irq > 15)
// {
// this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
// return;
// }
// this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// if (value)
// {
// intFTP |= (uint)(1 << irq);
// this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
// }
// else
// {
// }
// this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
// UpdateInterrupts();
}
private void UpdateInterrupts()
{
this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
this.Log(LogLevel.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}",
intMaskPriority, intFTP);
for (int i = 15; i > 0; i--)
{
//bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4);
bool masked = ((intMaskPriority & (uint)(1 << i)) != 0);
bool pending = (intFTP & (uint)(1 << i)) != 0;
if (i == 5)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (i == 4)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (masked && pending)
{
if (Connections.TryGetValue(i, out var gpio))
{
gpio.Set(true);
this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i);
var localI = i;
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
if (Connections.TryGetValue(localI, out var g))
{
g.Set(false);
machine.ScheduleAction(TimeInterval.FromMicroseconds(5000),
_ => {
intFTP &= ~(uint)(1 << localI);
this.Log(LogLevel.Info, "*** 5ms 安全期已过,自动清除中断 {0} 的挂起位 ***", localI);
UpdateInterrupts();
});
}
});
}
else
{
this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i);
}
}
}
}
public override void Reset()
{
base.Reset();
intMaskPriority = 0;
intFTP = 0;
intClr = 0;
}
public long Size => 0x10;
public IReadOnlyDictionary<int, IGPIO> Connections { get; }
private readonly IMachine machine;
private readonly Dictionary<int, IGPIO> connections;
private readonly Dictionary<IGPIO, int> gpioToIrqMap; // 字段声明
private readonly bool forceEnableIRQ4 = true;
private uint intMaskPriority;
private uint intFTP;
private uint intClr;
// 寄存器定义
private enum Registers
{
IntMaskPriority = 0x00,
IntFTP = 0x04,
IntForce = 0x08,
IntClr = 0x0C,
}
}
}

View File

@@ -0,0 +1,441 @@
//============================================================================
// 作者liuwenbo
// 日期2026-03-24-2026-03-25
//============================================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.IRQControllers;
namespace Antmicro.Renode.Peripherals.Timers
{
public class LC3233_TaskTimer : BasicDoubleWordPeripheral, IKnownSize
{
public LC3233_TaskTimer(IMachine machine) : base(machine)
{
this.machine = machine;
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 定时器已初始化 @ 0x80000000");
this.Log(LogLevel.Info, " 周期: 250ms (4Hz), 用于VxWorks任务调度");
}
private void ScheduleNextTick()
{
if(timerScheduled || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
timerScheduled = true;
var generation = timerGeneration;
machine.ScheduleAction(TimeInterval.FromMilliseconds(250), _ =>
{
timerScheduled = false;
if(generation != timerGeneration || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
OnTimerExpired();
});
}
private void OnTimerExpired()
{
timerExpiredCount++;
//isPending = true;
this.Log(LogLevel.Info, "========== 定时器溢出 #{0} ==========", timerExpiredCount);
this.Log(LogLevel.Info, "准备触发中断线4...");
IRQ.Set(true);
this.Log(LogLevel.Info, "已调用 IRQ.Set(true),信号应发送到 lc3233IntCtrl@4");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "中断脉冲结束");
});
if ((timerCtrl & TIMER_CTRL_T0_LOEN) != 0)
{
timer0Cntr = timer0Reld;
ScheduleNextTick();
}
}
private void DefineRegisters()
{
Registers.TimerCtrl.Define(this)
.WithValueField(0, 32, name: "timer_ctrl",
writeCallback: (_, val) =>
{
timerCtrl = (uint)val;
// Bit 0: Timer0 Enable
bool t0Enable = (val & TIMER_CTRL_T0_EN) != 0;
if(!t0Enable)
{
timerGeneration++;
timerScheduled = false;
}
else
{
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
this.Log(LogLevel.Info, "TIMER_CTRL 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " Timer0 Enable: {0}", t0Enable);
this.Log(LogLevel.Info, " Auto Reload: {0}", (val & TIMER_CTRL_T0_LOEN) != 0);
},
valueProviderCallback: _ => timerCtrl);
Registers.Timer0Cntr.Define(this)
.WithValueField(0, 32, name: "timer0_cntr",
writeCallback: (_, val) =>
{
timer0Cntr = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_CNTR 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Cntr);
Registers.Timer0Reld.Define(this)
.WithValueField(0, 32, name: "timer0_reld",
writeCallback: (_, val) =>
{
timer0Reld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Reld);
Registers.Timer0DivFreq.Define(this)
.WithValueField(0, 32, name: "timer0_divfreq",
writeCallback: (_, val) =>
{
timer0DivFreq = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DIVFREQ 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DivFreq);
Registers.Timer0DfReld.Define(this)
.WithValueField(0, 32, name: "timer0_df_reld",
writeCallback: (_, val) =>
{
timer0DfReld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DF_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DfReld);
}
public override void Reset()
{
base.Reset();
timerCtrl = TIMER_CTRL_T0_EN | TIMER_CTRL_T0_LOEN;
timer0Cntr = 0;
timer0Reld = 0;
timer0DivFreq = 0;
timer0DfReld = 0;
isPending = false;
timerExpiredCount = 0;
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
public long Size => 0x100;
public GPIO IRQ { get; } = new GPIO();
private enum Registers
{
TimerCtrl = 0x00,
Timer0Cntr = 0x04,
Timer0Reld = 0x08,
WdgCntr = 0x0C,
Timer1Cntr = 0x10,
Timer1Reld = 0x14,
Timer0DivFreq = 0x18,
Timer0DfReld = 0x1C,
}
private const uint TIMER_CTRL_T0_EN = 0x00000001;
private const uint TIMER_CTRL_T0_LOEN = 0x00000002;
private const uint TIMER_CTRL_T0_RSTA = 0x00000004;
private readonly IMachine machine;
private uint timerCtrl;
private uint timer0Cntr;
private uint timer0Reld;
private uint timer0DivFreq;
private uint timer0DfReld;
private bool isPending;
private bool timerScheduled;
private ulong timerGeneration;
private ulong timerExpiredCount;
}
}
namespace Antmicro.Renode.Peripherals.IRQControllers
{
public class LC3233_InterruptController : BasicDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput, IGPIOReceiver
{
public LC3233_InterruptController(IMachine machine) : base(machine)
{
this.machine = machine;
connections = new Dictionary<int, IGPIO>();
for (int i = 0; i <= 15; i++)
{
connections[i] = new GPIO();
}
Connections = new ReadOnlyDictionary<int, IGPIO>(connections);
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000");
this.Log(LogLevel.Info, " 管理15个中断源 (1-15)");
}
/// <summary>
/// 定义寄存器映射
/// </summary>
private void DefineRegisters()
{
// Registers.IntMaskPriority.Define(this)
// .WithValueField(0, 32, name: "int_mask_priority",
// writeCallback: (_, val) =>
// {
// intMaskPriority = (uint)val;
// this.Log(LogLevel.Info, "INT_MASK_PRIORITY 写入: 0x{0:X8}", val);
// this.Log(LogLevel.Info, " 临时兼容: IRQ4 强制视为使能");
// for (int i = 1; i <= 15; i++)
// {
// if ((val & (uint)(1 << i)) != 0)
// {
// this.Log(LogLevel.Debug, " 中断 {0} 已使能", i);
// }
// }
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intMaskPriority);
// Registers.IntFTP.Define(this)
// .WithValueField(0, 32, name: "int_f_t_p",
// writeCallback: (_, val) =>
// {
// intFTP |= (uint)val;
// this.Log(LogLevel.Debug, "INT_F_T_P 写入: 0x{0:X8}, 当前值: 0x{1:X8}", val, intFTP);
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intFTP);
// Registers.IntForce.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_force",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Info, "INT_FORCE 写入: 0x{0:X8}", val);
// intFTP |= (uint)val;
// UpdateInterrupts();
// });
// Registers.IntClr.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_clr",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Debug, "INT_CLR 写入: 0x{0:X8}", val);
// intFTP &= ~(uint)val;
// UpdateInterrupts();
// });
}
public void OnGPIO(int irq, bool value)
{
if (irq < 0 || irq > 15)
{
this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
return;
}
if(value)
{
this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// 自动使能中断
intMaskPriority |= (uint)(1 << irq);
this.Log(LogLevel.Info, "自动使能中断 {0}: INT_MASK_PRIORITY = 0x{1:X8}",
irq, intMaskPriority);
//设置挂起寄存器
intFTP |= (uint)(1 << irq);
this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
UpdateInterrupts();
}
else
{
}
//this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
//UpdateInterrupts();
// if (irq < 0 || irq > 15)
// {
// this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
// return;
// }
// this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// if (value)
// {
// intFTP |= (uint)(1 << irq);
// this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
// }
// else
// {
// }
// this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
// UpdateInterrupts();
}
private void UpdateInterrupts()
{
this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
this.Log(LogLevel.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}",
intMaskPriority, intFTP);
for (int i = 15; i > 0; i--)
{
//bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4);
bool masked = ((intMaskPriority & (uint)(1 << i)) != 0);
bool pending = (intFTP & (uint)(1 << i)) != 0;
if (i == 5)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (i == 4)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (masked && pending)
{
if (Connections.TryGetValue(i, out var gpio))
{
gpio.Set(true);
this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i);
var localI = i;
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
if (Connections.TryGetValue(localI, out var g))
{
g.Set(false);
machine.ScheduleAction(TimeInterval.FromMicroseconds(10),
_ => {
intFTP &= ~(uint)(1 << localI);
this.Log(LogLevel.Info, "*** 10us 安全期已过,自动清除中断 {0} 的挂起位 ***", localI);
UpdateInterrupts();
});
}
});
}
else
{
this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i);
}
}
}
}
public override void Reset()
{
base.Reset();
intMaskPriority = 0;
intFTP = 0;
intClr = 0;
}
public long Size => 0x10;
public IReadOnlyDictionary<int, IGPIO> Connections { get; }
private readonly IMachine machine;
private readonly Dictionary<int, IGPIO> connections;
private readonly Dictionary<IGPIO, int> gpioToIrqMap; // 字段声明
private readonly bool forceEnableIRQ4 = true;
private uint intMaskPriority;
private uint intFTP;
private uint intClr;
// 寄存器定义
private enum Registers
{
IntMaskPriority = 0x00,
IntFTP = 0x04,
IntForce = 0x08,
IntClr = 0x0C,
}
}
}

View File

@@ -0,0 +1,422 @@
//============================================================================
// 作者liuwenbo
// 日期2026-03-24-2026-03-25
//============================================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.IRQControllers;
namespace Antmicro.Renode.Peripherals.Timers
{
public class LC3233_TaskTimer : BasicDoubleWordPeripheral, IKnownSize
{
public LC3233_TaskTimer(IMachine machine) : base(machine)
{
this.machine = machine;
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 定时器已初始化 @ 0x80000000");
this.Log(LogLevel.Info, " 周期: 250ms (4Hz), 用于VxWorks任务调度");
}
private void ScheduleNextTick()
{
if(timerScheduled || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
timerScheduled = true;
var generation = timerGeneration;
machine.ScheduleAction(TimeInterval.FromMilliseconds(250), _ =>
{
timerScheduled = false;
if(generation != timerGeneration || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
OnTimerExpired();
});
}
private void OnTimerExpired()
{
timerExpiredCount++;
//isPending = true;
this.Log(LogLevel.Info, "========== 定时器溢出 #{0} ==========", timerExpiredCount);
this.Log(LogLevel.Info, "准备触发中断线4...");
IRQ.Set(true);
this.Log(LogLevel.Info, "已调用 IRQ.Set(true),信号应发送到 lc3233IntCtrl@4");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "中断脉冲结束");
});
if ((timerCtrl & TIMER_CTRL_T0_LOEN) != 0)
{
timer0Cntr = timer0Reld;
ScheduleNextTick();
}
}
private void DefineRegisters()
{
Registers.TimerCtrl.Define(this)
.WithValueField(0, 32, name: "timer_ctrl",
writeCallback: (_, val) =>
{
timerCtrl = (uint)val;
// Bit 0: Timer0 Enable
bool t0Enable = (val & TIMER_CTRL_T0_EN) != 0;
if(!t0Enable)
{
timerGeneration++;
timerScheduled = false;
}
else
{
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
this.Log(LogLevel.Info, "TIMER_CTRL 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " Timer0 Enable: {0}", t0Enable);
this.Log(LogLevel.Info, " Auto Reload: {0}", (val & TIMER_CTRL_T0_LOEN) != 0);
},
valueProviderCallback: _ => timerCtrl);
Registers.Timer0Cntr.Define(this)
.WithValueField(0, 32, name: "timer0_cntr",
writeCallback: (_, val) =>
{
timer0Cntr = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_CNTR 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Cntr);
Registers.Timer0Reld.Define(this)
.WithValueField(0, 32, name: "timer0_reld",
writeCallback: (_, val) =>
{
timer0Reld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Reld);
Registers.Timer0DivFreq.Define(this)
.WithValueField(0, 32, name: "timer0_divfreq",
writeCallback: (_, val) =>
{
timer0DivFreq = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DIVFREQ 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DivFreq);
Registers.Timer0DfReld.Define(this)
.WithValueField(0, 32, name: "timer0_df_reld",
writeCallback: (_, val) =>
{
timer0DfReld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DF_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DfReld);
}
public override void Reset()
{
base.Reset();
timerCtrl = TIMER_CTRL_T0_EN | TIMER_CTRL_T0_LOEN;
timer0Cntr = 0;
timer0Reld = 0;
timer0DivFreq = 0;
timer0DfReld = 0;
isPending = false;
timerExpiredCount = 0;
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
public long Size => 0x100;
public GPIO IRQ { get; } = new GPIO();
private enum Registers
{
TimerCtrl = 0x00,
Timer0Cntr = 0x04,
Timer0Reld = 0x08,
WdgCntr = 0x0C,
Timer1Cntr = 0x10,
Timer1Reld = 0x14,
Timer0DivFreq = 0x18,
Timer0DfReld = 0x1C,
}
private const uint TIMER_CTRL_T0_EN = 0x00000001;
private const uint TIMER_CTRL_T0_LOEN = 0x00000002;
private const uint TIMER_CTRL_T0_RSTA = 0x00000004;
private readonly IMachine machine;
private uint timerCtrl;
private uint timer0Cntr;
private uint timer0Reld;
private uint timer0DivFreq;
private uint timer0DfReld;
private bool isPending;
private bool timerScheduled;
private ulong timerGeneration;
private ulong timerExpiredCount;
}
}
namespace Antmicro.Renode.Peripherals.IRQControllers
{
public class LC3233_InterruptController : BasicDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput, IGPIOReceiver
{
public LC3233_InterruptController(IMachine machine) : base(machine)
{
this.machine = machine;
connections = new Dictionary<int, IGPIO>();
for (int i = 0; i <= 15; i++)
{
connections[i] = new GPIO();
}
Connections = new ReadOnlyDictionary<int, IGPIO>(connections);
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000");
this.Log(LogLevel.Info, " 管理15个中断源 (1-15)");
}
/// <summary>
/// 定义寄存器映射
/// </summary>
private void DefineRegisters()
{
Registers.IntMaskPriority.Define(this)
.WithValueField(0, 32, name: "int_mask_priority",
writeCallback: (_, val) =>
{
intMaskPriority = (uint)val;
this.Log(LogLevel.Info, "INT_MASK_PRIORITY 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " 临时兼容: IRQ4 强制视为使能");
for (int i = 1; i <= 15; i++)
{
if ((val & (uint)(1 << i)) != 0)
{
this.Log(LogLevel.Debug, " 中断 {0} 已使能", i);
}
}
UpdateInterrupts();
},
valueProviderCallback: _ => intMaskPriority);
Registers.IntFTP.Define(this)
.WithValueField(0, 32, name: "int_f_t_p",
writeCallback: (_, val) =>
{
intFTP |= (uint)val;
this.Log(LogLevel.Debug, "INT_F_T_P 写入: 0x{0:X8}, 当前值: 0x{1:X8}", val, intFTP);
UpdateInterrupts();
},
valueProviderCallback: _ => intFTP);
Registers.IntForce.Define(this)
.WithValueField(0, 32, FieldMode.Write, name: "int_force",
writeCallback: (_, val) =>
{
this.Log(LogLevel.Info, "INT_FORCE 写入: 0x{0:X8}", val);
intFTP |= (uint)val;
UpdateInterrupts();
});
Registers.IntClr.Define(this)
.WithValueField(0, 32, FieldMode.Write, name: "int_clr",
writeCallback: (_, val) =>
{
this.Log(LogLevel.Debug, "INT_CLR 写入: 0x{0:X8}", val);
intFTP &= ~(uint)val;
UpdateInterrupts();
});
}
public void OnGPIO(int irq, bool value)
{
if (irq < 0 || irq > 15)
{
this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
return;
}
if(value)
{
this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// 自动使能中断
intMaskPriority |= (uint)(1 << irq);
this.Log(LogLevel.Info, "自动使能中断 {0}: INT_MASK_PRIORITY = 0x{1:X8}", irq, intMaskPriority);
//设置挂起寄存器
intFTP |= (uint)(1 << irq);
this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
}
else
{
}
this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
UpdateInterrupts();
// if (irq < 0 || irq > 15)
// {
// this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
// return;
// }
// this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// if (value)
// {
// intFTP |= (uint)(1 << irq);
// this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
// }
// else
// {
// }
// this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
// UpdateInterrupts();
}
private void UpdateInterrupts()
{
this.Log(LogLevel.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}",
intMaskPriority, intFTP);
for (int i = 15; i > 0; i--)
{
//bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4);
bool masked = ((intMaskPriority & (uint)(1 << i)) != 0);
bool pending = (intFTP & (uint)(1 << i)) != 0;
if (i == 5)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (i == 4)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (masked && pending)
{
if (Connections.TryGetValue(i, out var gpio))
{
this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i);
gpio.Set(true);
var localI = i;
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
if (Connections.TryGetValue(localI, out var g))
{
g.Set(false);
}
});
}
else
{
this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i);
}
}
}
}
public override void Reset()
{
base.Reset();
intMaskPriority = 0;
intFTP = 0;
}
public long Size => 0x10;
public IReadOnlyDictionary<int, IGPIO> Connections { get; }
private readonly IMachine machine;
private readonly Dictionary<int, IGPIO> connections;
private readonly bool forceEnableIRQ4 = true;
private uint intMaskPriority;
private uint intFTP;
// 寄存器定义
private enum Registers
{
IntMaskPriority = 0x00,
IntFTP = 0x04,
IntForce = 0x08,
IntClr = 0x0C,
}
}
}

510
SJA1000_CAN.cs Normal file
View File

@@ -0,0 +1,510 @@
//
// SJA1000 CAN 控制器外设实现(简化版,支持发送/接收队列,提高速率)
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
// 发送缓冲区(地址 16-26、RBSA 和 CDR。命令寄存器位2=RRB位3=CDO。
// 接收为单帧,无 FIFO无数据溢出处理。
// 所有寄存器可随时读写,无复位模式限制。
//
// author: Generated based on UART16550 template
//
using System;
using System.Text;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// 简化版 SJA1000 CAN 控制器PeliCAN 模式,仅标准帧)
/// </summary>
public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize
{
public SJA1000_CAN(IMachine machine)
{
this.machine = machine;
IRQ = new GPIO();
txBuffer = new byte[11];
rxBuffer = new byte[11];
txFrameQueue = new Queue<byte[]>(); // 新增:发送队列
rxFrameQueue = new Queue<byte[]>(); // 新增:接收队列
Reset();
}
public void Reset()
{
mod = 0;
ier = 0;
btr0 = 0;
btr1 = 0;
ocr = 0;
rxerr = 0;
txerr = 0;
rbsa = 0;
cdr = 0;
sr_tbs = 1; // 发送缓冲区初始为空闲
sr_rbs = 0; // 接收缓冲区初始为空
ir = 0;
Array.Clear(txBuffer, 0, txBuffer.Length);
Array.Clear(rxBuffer, 0, rxBuffer.Length);
txFrameQueue.Clear(); // 清空发送队列
rxFrameQueue.Clear(); // 清空接收队列
UpdateInterrupts();
this.Log(LogLevel.Info, "SJA1000 CAN controller reset (simplified)");
}
// ================ IBusPeripheral 接口实现 ================
public uint ReadDoubleWord(long offset)
{
return ReadByte(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteByte(offset, (byte)value);
}
public byte ReadByte(long offset)
{
byte value = 0;
switch ((Registers)offset)
{
case Registers.MOD:
value = mod;
this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value);
break;
case Registers.CMR:
// 命令寄存器只写读返回0
this.Log(LogLevel.Info, "Read CMR (always 0)");
value = 0;
break;
case Registers.SR:
value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0
this.Log(LogLevel.Info, "Read SR: TBS={0}, RBS={1} -> 0x{2:X2}", sr_tbs, sr_rbs, value);
break;
case Registers.IR:
value = ir;
// 读 IR 后清零,但需要根据当前 RBS 重新评估 RI电平触发
ir = 0;
UpdateIrFromRbs();
UpdateInterrupts();
this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value);
break;
case Registers.IER:
value = ier;
this.Log(LogLevel.Info, "Read IER: 0x{0:X2}", value);
break;
case Registers.BTR0:
value = btr0;
break;
case Registers.BTR1:
value = btr1;
break;
case Registers.OCR:
value = ocr;
break;
case Registers.RXERR:
value = rxerr;
break;
case Registers.TXERR:
value = txerr;
break;
case Registers.RBSA:
value = rbsa;
break;
case Registers.CDR:
value = cdr;
break;
// 发送/接收缓冲区地址 16-26
case Registers.TX_FRAME_INFO:
case Registers.TX_ID1:
case Registers.TX_ID2:
case Registers.TX_DATA1:
case Registers.TX_DATA2:
case Registers.TX_DATA3:
case Registers.TX_DATA4:
case Registers.TX_DATA5:
case Registers.TX_DATA6:
case Registers.TX_DATA7:
case Registers.TX_DATA8:
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
if (sr_rbs == 1)
{
// 接收缓冲区有数据时,读返回接收帧的内容
value = rxBuffer[bufIndex/4];
this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
}
else
{
//否则返回发送缓冲区的内容(通常无意义)
value = txBuffer[bufIndex/4];
this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
}
break;
default:
// 未实现的寄存器返回0
this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset);
value = 0;
break;
}
return value;
}
public void WriteByte(long offset, byte value)
{
switch ((Registers)offset)
{
case Registers.MOD:
mod = value;
this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value);
break;
case Registers.CMR:
// 命令寄存器只写,处理命令
this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value);
if ((value & CMR_TR) != 0)
{
// 发送请求
if (sr_tbs == 1)
{
// 将当前 txBuffer 复制一份加入发送队列
var frame = new byte[11];
Array.Copy(txBuffer, frame, 11);
lock (lockObject)
{
txFrameQueue.Enqueue(frame);
}
// 清空发送缓冲区,并立即释放 TBS允许 CPU 继续写入下一帧
Array.Clear(txBuffer, 0, txBuffer.Length);
sr_tbs = 1;
this.Log(LogLevel.Info, "Frame enqueued for transmission, queue size: {0}", txFrameQueue.Count);
}
else
{
this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
}
}
if ((value & CMR_RRB) != 0)
{
// 释放接收缓冲器:尝试从接收队列中加载下一帧
lock (lockObject)
{
LoadNextRxFrame();
}
this.Log(LogLevel.Info, "Receive buffer released");
}
if ((value & CMR_CDO) != 0)
{
// 清除数据溢出(无操作)
this.Log(LogLevel.Info, "Clear data overflow (no effect)");
}
break;
case Registers.SR:
if (sr_tbs == 1)
{
sr_tbs = 0;
}
else
{
sr_tbs = 1;
}
if (sr_rbs == 1)
{
sr_rbs = 0;
}
else
{
sr_rbs = 1;
}
break;
case Registers.IR:
// 只读,忽略写
this.Log(LogLevel.Warning, "Attempted write to read-only IR");
break;
case Registers.IER:
ier = (byte)(value & 0x01); // 只使用 bit0 (RIE)
UpdateIrFromRbs();
UpdateInterrupts();
this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier);
break;
case Registers.BTR0:
btr0 = value;
this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value);
break;
case Registers.BTR1:
btr1 = value;
this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value);
break;
case Registers.OCR:
ocr = value;
this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value);
break;
case Registers.RXERR:
rxerr = value;
this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value);
break;
case Registers.TXERR:
txerr = value;
this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value);
break;
case Registers.RBSA:
rbsa = value;
this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value);
break;
case Registers.CDR:
cdr = value;
this.Log(LogLevel.Info, "Write CDR: 0x{0:X2}", value);
break;
// 发送缓冲区写入
case Registers.TX_FRAME_INFO:
case Registers.TX_ID1:
case Registers.TX_ID2:
case Registers.TX_DATA1:
case Registers.TX_DATA2:
case Registers.TX_DATA3:
case Registers.TX_DATA4:
case Registers.TX_DATA5:
case Registers.TX_DATA6:
case Registers.TX_DATA7:
case Registers.TX_DATA8:
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
if (sr_tbs == 1)
{
txBuffer[bufIndex/4] = value;
this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
}
else
{
this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored");
}
break;
default:
// 未实现的寄存器忽略写
this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
// ================ 公共方法与事件 ================
private void UpdateIrFromRbs()
{
if (sr_rbs == 1)
ir |= IR_RI;
else
ir = (byte)(ir & ~IR_RI);
}
private void UpdateInterrupts()
{
bool interrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0);
IRQ.Set(interrupt);
if (interrupt)
{
machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ =>
{
IRQ.Set(false);
});
this.Log(LogLevel.Info, "Interrupt asserted (RI)");
}
else
{
this.Log(LogLevel.Info, "Interrupt deasserted");
}
}
private readonly object lockObject = new object(); // 用于线程安全的锁对象
/// <summary>
/// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
/// 调用后清空发送队列。
/// </summary>
public string GetTxBufferDataString()
{
lock (lockObject)
{
if (txFrameQueue.Count == 0)
{
Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
return null;
}
var sb = new StringBuilder();
while (txFrameQueue.Count > 0)
{
var frame = txFrameQueue.Dequeue();
for (int i = 0; i < frame.Length; i++)
{
if (i > 0) sb.Append(" ");
sb.Append(frame[i].ToString("X2"));
}
sb.AppendLine(); // 帧间换行
}
string result = sb.ToString().TrimEnd();
Console.WriteLine("GetTxBufferDataString returning: " + result);
return result;
}
}
/// <summary>
/// 外部接口注入一帧接收数据11字节的十六进制字符串空格分隔
/// 可多次调用以注入多帧,帧将存入接收队列。
/// </summary>
public void SendRxBufferDataString(string frameString)
{
lock (lockObject)
{
if (string.IsNullOrWhiteSpace(frameString))
{
Console.WriteLine("SendRxBufferDataString: empty string, ignored");
return;
}
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 11)
{
Console.WriteLine($"SendRxBufferDataString: expected 11 bytes, got {parts.Length}, ignored");
return;
}
byte[] frame = new byte[11];
for (int i = 0; i < 11; i++)
{
string part = parts[i].Trim();
if (!byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
System.Globalization.CultureInfo.InvariantCulture, out byte b))
{
Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
b = 0;
}
frame[i] = b;
}
rxFrameQueue.Enqueue(frame);
Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
// 如果当前接收缓冲区空闲,立即加载第一帧
if (sr_rbs == 0)
{
LoadNextRxFrame();
}
}
}
// 从接收队列中加载下一帧到 rxBuffer并更新状态
private void LoadNextRxFrame()
{
if (rxFrameQueue.Count > 0)
{
var frame = rxFrameQueue.Dequeue();
Array.Copy(frame, rxBuffer, 11);
sr_rbs = 1;
UpdateIrFromRbs();
UpdateInterrupts();
Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
}
else
{
sr_rbs = 0;
UpdateIrFromRbs();
UpdateInterrupts();
Console.WriteLine("RX queue empty, buffer cleared");
}
}
// ================ 属性 ================
public long Size => 0x80; // 地址范围 0-31
public GPIO IRQ { get; }
// ================ 寄存器枚举 ================
private enum Registers : long
{
MOD = 0x00,
CMR = 0x04,
SR = 0x08,
IR = 0x0C,
IER = 0x10,
BTR0 = 0x18,
BTR1 = 0x1C,
OCR = 0x20,
RXERR = 0x38, // 14
TXERR = 0x3C, // 15
TX_FRAME_INFO = 0x40, // 16
TX_ID1 = 0x44,
TX_ID2 = 0x48,
TX_DATA1 = 0x4C,
TX_DATA2 = 0x50,
TX_DATA3 = 0x54,
TX_DATA4 = 0x58,
TX_DATA5 = 0x5C,
TX_DATA6 = 0x60,
TX_DATA7 = 0x64,
TX_DATA8 = 0x68, // 26
RBSA = 0x78, // 30
CDR = 0x7C, // 31
}
// ================ 常量位定义 ================
private const byte CMR_TR = 0x01; // 发送请求 (bit0)
private const byte CMR_RRB = 0x04; // 释放接收缓冲器 (bit2)
private const byte CMR_CDO = 0x08; // 清除数据溢出 (bit3)
private const byte SR_BS = 0x80; // 总线状态 (bit7) - 本模拟中恒0
private const byte SR_TBS = 0x04; // 发送缓冲器状态 (bit2)
private const byte SR_RBS = 0x01; // 接收缓冲器状态 (bit0)
private const byte IR_RI = 0x01; // 接收中断 (bit0)
private const byte IER_RIE = 0x01; // 接收中断使能 (bit0)
// ================ 私有字段 ================
private readonly IMachine machine;
// 寄存器存储
private byte mod;
private byte ier;
private byte btr0, btr1;
private byte ocr;
private byte rxerr, txerr;
private byte rbsa;
private byte cdr;
// 状态位
private byte sr_tbs; // 1=空闲
private byte sr_rbs; // 1=有数据
private byte ir; // 仅 bit0 有效
private readonly byte[] txBuffer; // 临时发送缓冲区(单帧)
private readonly byte[] rxBuffer; // 当前接收帧(单帧)
private readonly Queue<byte[]> txFrameQueue; // 发送队列
private readonly Queue<byte[]> rxFrameQueue; // 接收队列
}
}

677
UART16550.cs Normal file
View File

@@ -0,0 +1,677 @@
//
// 16550 UART 外设实现
// 基于 16550 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
// author:liuwenbo
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// 16550 UART 控制器
/// 兼容 16550 UART 规格,支持 FIFO、中断和调制解调器控制
/// </summary>
public class UART16550 : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize
{
public UART16550(IMachine machine, uint clockFrequency = 1843200)
: base(machine)
{
this.clockFrequency = clockFrequency;
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "16550 UART initialized, clock: {0} Hz", clockFrequency);
}
public override void Reset()
{
rxFifo.Clear();
txFifo.Clear();
// 寄存器复位值
ier = 0x00;
lcr = 0x00;
mcr = 0x00;
lsr = (byte)(LSR_TEMT | LSR_THRE); // 发送器初始为空
msr = 0x00;
scr = 0x00;
dll = 0x00;
dlh = 0x00;
fcr = 0x00;
fifoEnabled = false;
fifoTriggerLevel = 1;
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Debug, "16550 UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
// 因为 16550 是字节外设,但 Renode 通常使用 32 位访问
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadByte(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteByte(offset, (byte)value);
}
public byte ReadByte(long offset)
{
byte value = 0;
switch (offset)
{
case (long)Registers.RBR_THR_DLL:
if ((lcr & LCR_DLAB) != 0)
{
// DLAB=1: 读取 DLL
value = dll;
this.Log(LogLevel.Noisy, "Read DLL: 0x{0:X2}", value);
}
else
{
// DLAB=0: 读取 RBR
value = ReadRBR();
}
break;
case (long)Registers.IER_DLH:
if ((lcr & LCR_DLAB) != 0)
{
// DLAB=1: 读取 DLH
value = dlh;
this.Log(LogLevel.Noisy, "Read DLH: 0x{0:X2}", value);
}
else
{
// DLAB=0: 读取 IER
value = (byte)(ier & 0x0F);
this.Log(LogLevel.Noisy, "Read IER: 0x{0:X2}", value);
}
break;
case (long)Registers.IIR_FCR:
// IIR - 中断识别寄存器
value = ReadIIR();
break;
case (long)Registers.LCR:
value = lcr;
this.Log(LogLevel.Noisy, "Read LCR: 0x{0:X2}", value);
break;
case (long)Registers.MCR:
value = mcr;
this.Log(LogLevel.Noisy, "Read MCR: 0x{0:X2}", value);
break;
case (long)Registers.LSR:
value = lsr;
this.Log(LogLevel.Noisy, "Read LSR: 0x{0:X2}", value);
// 读取 LSR 清除错误位
lsr = (byte)(lsr & ~(LSR_BI | LSR_FE | LSR_PE));
UpdateInterrupts();
break;
case (long)Registers.MSR:
value = msr;
this.Log(LogLevel.Noisy, "Read MSR: 0x{0:X2}", value);
// 读取 MSR 清除变化位
msr = (byte)(msr & 0xF0);
UpdateInterrupts();
break;
case (long)Registers.SCR:
value = scr;
this.Log(LogLevel.Noisy, "Read SCR: 0x{0:X2}", value);
break;
default:
this.Log(LogLevel.Warning, "Read from unknown offset: 0x{0:X}", offset);
break;
}
return value;
}
public void WriteByte(long offset, byte value)
{
switch (offset)
{
case (long)Registers.RBR_THR_DLL:
if ((lcr & LCR_DLAB) != 0)
{
// DLAB=1: 写入 DLL
dll = value;
UpdateBaudRate();
this.Log(LogLevel.Debug, "Write DLL: 0x{0:X2}", value);
}
else
{
// DLAB=0: 写入 THR
WriteTHR(value);
}
break;
case (long)Registers.IER_DLH:
if ((lcr & LCR_DLAB) != 0)
{
// DLAB=1: 写入 DLH
dlh = value;
UpdateBaudRate();
this.Log(LogLevel.Debug, "Write DLH: 0x{0:X2}", value);
}
else
{
// DLAB=0: 写入 IER
ier = (byte)(value & 0x0F);
this.Log(LogLevel.Debug, "Write IER: 0x{0:X2}", ier);
UpdateInterrupts();
}
break;
case (long)Registers.IIR_FCR:
// FCR - FIFO 控制寄存器
WriteFCR(value);
break;
case (long)Registers.LCR:
lcr = value;
this.Log(LogLevel.Debug, "Write LCR: 0x{0:X2}", value);
UpdateLineParameters();
break;
case (long)Registers.MCR:
mcr = (byte)(value & 0x1F);
this.Log(LogLevel.Debug, "Write MCR: 0x{0:X2}", mcr);
UpdateModemControl();
break;
case (long)Registers.LSR:
// LSR 是只读寄存器
this.Log(LogLevel.Warning, "Attempted write to read-only LSR");
break;
case (long)Registers.MSR:
// MSR 是只读寄存器
this.Log(LogLevel.Warning, "Attempted write to read-only MSR");
break;
case (long)Registers.SCR:
scr = value;
this.Log(LogLevel.Noisy, "Write SCR: 0x{0:X2}", value);
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
// ========================================
// FIFO 和数据传输
// ========================================
private byte ReadRBR()
{
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Debug, "Read RBR: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
// 更新状态
if (rxFifo.Count == 0)
{
lsr = (byte)(lsr & ~LSR_DR); // 清除数据就绪
}
// 检查溢出
if (rxFifo.Count == 0)
{
lsr = (byte)(lsr & ~LSR_OE); // 清除溢出错误
}
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
UpdateInterrupts();
return value;
}
private void WriteTHR(byte value)
{
this.Log(LogLevel.Debug, "Write THR: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
if (fifoEnabled)
{
if (txFifo.Count < FIFO_SIZE)
{
txFifo.Enqueue(value);
lsr = (byte)(lsr & ~LSR_THRE); // THR 非空
lsr = (byte)(lsr & ~LSR_TEMT); // 发送器非空
}
else
{
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,直接发送
txFifo.Clear();
txFifo.Enqueue(value);
lsr = (byte)(lsr & ~LSR_THRE);
lsr = (byte)(lsr & ~LSR_TEMT);
}
// 实际发送数据
TransmitData();
}
private void WriteFCR(byte value)
{
fcr = value;
this.Log(LogLevel.Debug, "Write FCR: 0x{0:X2}", value);
// FIFO 使能
bool newFifoEnabled = (value & FCR_FIFO_EN) != 0;
if (newFifoEnabled != fifoEnabled)
{
fifoEnabled = newFifoEnabled;
this.Log(LogLevel.Info, "FIFO {0}", fifoEnabled ? "enabled" : "disabled");
if (!fifoEnabled)
{
// 禁用 FIFO 时清空
rxFifo.Clear();
txFifo.Clear();
}
}
// 清除 RX FIFO
if ((value & FCR_RCVR_RESET) != 0)
{
rxFifo.Clear();
lsr = (byte)(lsr & ~LSR_DR);
this.Log(LogLevel.Debug, "RX FIFO cleared");
}
// 清除 TX FIFO
if ((value & FCR_XMIT_RESET) != 0)
{
txFifo.Clear();
lsr = (byte)(lsr | (LSR_THRE | LSR_TEMT));
this.Log(LogLevel.Debug, "TX FIFO cleared");
}
// 设置触发级别
byte trigger = (byte)((value >> 6) & 0x03);
switch (trigger)
{
case 0: fifoTriggerLevel = 1; break;
case 1: fifoTriggerLevel = 4; break;
case 2: fifoTriggerLevel = 8; break;
case 3: fifoTriggerLevel = 14; break;
}
this.Log(LogLevel.Debug, "FIFO trigger level: {0} bytes", fifoTriggerLevel);
UpdateInterrupts();
}
private byte ReadIIR()
{
byte iir = IIR_NO_INT; // 默认无中断
// 检查中断使能
if ((mcr & MCR_OUT2) == 0)
{
// OUT2 未置位,禁用中断
this.Log(LogLevel.Noisy, "Read IIR: 0x{0:X2} (interrupts disabled)", iir);
return iir;
}
// 按优先级检查中断
// 1. 接收线路状态中断 (最高优先级)
if ((ier & IER_ELSI) != 0 && (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) != 0)
{
iir = IIR_RLS; // 0x06
}
// 2. 接收数据可用中断
else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count >= fifoTriggerLevel)
{
iir = IIR_RDA; // 0x04
}
// 3. 字符超时中断
else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count > 0)
{
iir = IIR_CTI; // 0x0C
}
// 4. THR 空中断
else if ((ier & IER_ETBEI) != 0 && (lsr & LSR_THRE) != 0)
{
iir = IIR_THRE; // 0x02
}
// 5. 调制解调器状态中断 (最低优先级)
else if ((ier & IER_EDSSI) != 0 && (msr & 0x0F) != 0)
{
iir = IIR_MS; // 0x00
}
// FIFO 使能状态
if (fifoEnabled)
{
iir |= IIR_FIFO_EN;
}
this.Log(LogLevel.Noisy, "Read IIR: 0x{0:X2}", iir);
// 读取 IIR 清除 THRE 中断
if ((iir & 0x0F) == IIR_THRE)
{
UpdateInterrupts();
}
return iir;
}
private void TransmitData()
{
// 从 TX FIFO 发送数据
while (txFifo.Count > 0)
{
byte data = txFifo.Dequeue();
// 调用基类的 TransmitCharacter 发送数据
TransmitCharacter(data);
this.Log(LogLevel.Debug, "Transmitted: 0x{0:X2} ('{1}')", data,
(data >= 32 && data < 127) ? (char)data : '.');
}
// 更新状态
lsr = (byte)(lsr | LSR_THRE); // THR 空
lsr = (byte)(lsr | LSR_TEMT); // 发送器空
UpdateInterrupts();
}
// ========================================
// UARTBase 接口实现
// ========================================
public override void WriteChar(byte value)
{
// 从外部接收数据 (例如从终端或网络)
if (fifoEnabled)
{
if (rxFifo.Count < FIFO_SIZE)
{
rxFifo.Enqueue(value);
lsr = (byte)(lsr | LSR_DR); // 数据就绪
this.Log(LogLevel.Debug, "Received: 0x{0:X2} ('{1}'), FIFO count: {2}",
value, (value >= 32 && value < 127) ? (char)value : '.', rxFifo.Count);
}
else
{
lsr = (byte)(lsr | LSR_OE); // 溢出错误
this.Log(LogLevel.Warning, "RX FIFO overflow");
}
}
else
{
// 非 FIFO 模式
if (rxFifo.Count > 0)
{
lsr = (byte)(lsr | LSR_OE); // 溢出错误
}
rxFifo.Clear();
rxFifo.Enqueue(value);
lsr = (byte)(lsr | LSR_DR);
}
UpdateInterrupts();
}
protected override void CharWritten()
{
// UARTBase 要求实现此方法
// 在字符写入后调用,这里不需要额外操作
}
protected override void QueueEmptied()
{
// UARTBase 要求实现此方法
// 当队列为空时调用,这里不需要额外操作
}
public override Bits StopBits
{
get
{
return ((lcr & LCR_STB) != 0) ? Bits.Two : Bits.One;
}
}
public override Parity ParityBit
{
get
{
if ((lcr & LCR_PEN) == 0)
return Parity.None;
if ((lcr & LCR_EPS) != 0)
return Parity.Even;
else
return Parity.Odd;
}
}
public override uint BaudRate
{
get { return currentBaudRate; }
}
// ========================================
// 辅助方法
// ========================================
private void UpdateBaudRate()
{
ushort divisor = (ushort)((dlh << 8) | dll);
if (divisor == 0)
{
currentBaudRate = 0;
}
else
{
currentBaudRate = clockFrequency / (16u * divisor);
this.Log(LogLevel.Info, "Baud rate set to {0} (divisor: {1})", currentBaudRate, divisor);
}
}
private void UpdateLineParameters()
{
// 字长
byte wordLength = (byte)((lcr & LCR_WLS) + 5);
// 停止位
string stopBits = ((lcr & LCR_STB) != 0) ? "2" : "1";
// 奇偶校验
string parity;
if ((lcr & LCR_PEN) == 0)
parity = "N";
else if ((lcr & LCR_EPS) != 0)
parity = "E";
else
parity = "O";
this.Log(LogLevel.Info, "Line format: {0}{1}{2}", wordLength, parity, stopBits);
}
private void UpdateModemControl()
{
this.Log(LogLevel.Debug, "Modem control: DTR={0}, RTS={1}, OUT1={2}, OUT2={3}, LOOP={4}",
(mcr & MCR_DTR) != 0, (mcr & MCR_RTS) != 0, (mcr & MCR_OUT1) != 0,
(mcr & MCR_OUT2) != 0, (mcr & MCR_LOOP) != 0);
UpdateInterrupts();
}
private void UpdateInterrupts()
{
bool interrupt = false;
// OUT2 必须置位才能产生中断
if ((mcr & MCR_OUT2) != 0)
{
// 检查各种中断条件
if ((ier & IER_ELSI) != 0 && (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) != 0)
interrupt = true;
else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count >= fifoTriggerLevel)
interrupt = true;
else if ((ier & IER_ETBEI) != 0 && (lsr & LSR_THRE) != 0)
interrupt = true;
else if ((ier & IER_EDSSI) != 0 && (msr & 0x0F) != 0)
interrupt = true;
}
IRQ.Set(interrupt);
if (interrupt)
{
this.Log(LogLevel.Debug, "Interrupt asserted");
}
}
public long Size => 0x08;
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
RBR_THR_DLL = 0x00, // RBR/THR (DLAB=0), DLL (DLAB=1)
IER_DLH = 0x01, // IER (DLAB=0), DLH (DLAB=1)
IIR_FCR = 0x02, // IIR (R), FCR (W)
LCR = 0x03, // Line Control Register
MCR = 0x04, // Modem Control Register
LSR = 0x05, // Line Status Register
MSR = 0x06, // Modem Status Register
SCR = 0x07, // Scratch Register
}
// LCR 位定义
private const byte LCR_WLS = 0x03; // 字长选择
private const byte LCR_STB = 0x04; // 停止位
private const byte LCR_PEN = 0x08; // 奇偶校验使能
private const byte LCR_EPS = 0x10; // 偶校验选择
private const byte LCR_SPAR = 0x20; // 强制奇偶校验
private const byte LCR_SBC = 0x40; // 设置中断
private const byte LCR_DLAB = 0x80; // 除数锁存访问
// LSR 位定义
private const byte LSR_DR = 0x01; // 数据就绪
private const byte LSR_OE = 0x02; // 溢出错误
private const byte LSR_PE = 0x04; // 奇偶校验错误
private const byte LSR_FE = 0x08; // 帧错误
private const byte LSR_BI = 0x10; // 中断指示
private const byte LSR_THRE = 0x20; // THR 空
private const byte LSR_TEMT = 0x40; // 发送器空
private const byte LSR_FIFO_ERR = 0x80; // FIFO 错误
// IER 位定义
private const byte IER_ERBFI = 0x01; // 使能接收数据可用中断
private const byte IER_ETBEI = 0x02; // 使能 THR 空中断
private const byte IER_ELSI = 0x04; // 使能接收线路状态中断
private const byte IER_EDSSI = 0x08; // 使能调制解调器状态中断
// IIR 值定义
private const byte IIR_NO_INT = 0x01; // 无中断挂起
private const byte IIR_MS = 0x00; // 调制解调器状态
private const byte IIR_THRE = 0x02; // THR 空
private const byte IIR_RDA = 0x04; // 接收数据可用
private const byte IIR_RLS = 0x06; // 接收线路状态
private const byte IIR_CTI = 0x0C; // 字符超时
private const byte IIR_FIFO_EN = 0xC0; // FIFO 使能标志
// FCR 位定义
private const byte FCR_FIFO_EN = 0x01; // FIFO 使能
private const byte FCR_RCVR_RESET = 0x02; // 清除 RX FIFO
private const byte FCR_XMIT_RESET = 0x04; // 清除 TX FIFO
// MCR 位定义
private const byte MCR_DTR = 0x01; // DTR
private const byte MCR_RTS = 0x02; // RTS
private const byte MCR_OUT1 = 0x04; // OUT1
private const byte MCR_OUT2 = 0x08; // OUT2
private const byte MCR_LOOP = 0x10; // 环回模式
// 常量
private const int FIFO_SIZE = 16;
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte ier; // 中断使能寄存器
private byte lcr; // 线路控制寄存器
private byte mcr; // 调制解调器控制寄存器
private byte lsr; // 线路状态寄存器
private byte msr; // 调制解调器状态寄存器
private byte scr; // 暂存寄存器
private byte dll; // 除数锁存低字节
private byte dlh; // 除数锁存高字节
private byte fcr; // FIFO 控制寄存器
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool fifoEnabled;
private int fifoTriggerLevel;
}
}

615
UART_kx12A1.cs Normal file
View File

@@ -0,0 +1,615 @@
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器
/// 接收缓存512B发送缓存512B时钟24MHz
/// </summary>
public class UART_771_RUHW_2CFG1 : IDoubleWordPeripheral, IBytePeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG1(IMachine machine)
{
this.clockFrequency = 24000000;
this.machine = machine; //TODO
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
rxFifo.Clear();
txFifo.Clear();
ucr = 0x00; // 控制寄存器
usr = USR_TFE;// 状态寄存器
mcr = 0x00; // 调制控制寄存器:中断使能,接收使能
brsr_l = 0x00; // 波特率设置寄存器
brsr_h = 0x00;
fsta = (byte)(FSTA_TEMP | FSTA_REMP); // FIFO状态寄存器
tbr = 0; // 发送FIFO剩余字节数
rbr = 0 ; // 接收FIFO剩余字节数
rstr = 0x00; // 复位/使能寄存器
ext_signal = 0x00; // 向外部提供读写信号
RxfifoEnabled = true; //接收fifo使能
TxfifoEnabled = true; //发送fifo使能
fifoTriggerLevel = 1;
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Info, "UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
this.Log(LogLevel.Info, "entry ReadDoubleWord: 0x{0}", offset);
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
this.Log(LogLevel.Info, "entry ReadRegisters: 0x{0}", offset);
uint value = 0;
switch (offset)
{
case (long)Registers.TBR_RBR: //接收FIFO读操作
// 在接收FIFO寄存器中读取数据
value = ReadRBR();
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //USR状态寄存器
value = (byte)(usr & 0xFF);
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
// usr = (byte)(usr & (~USR_RBFI)); //usr寄存器取消接收中断与hw_uart_isr关联暂定
break;
case (long)Registers.MCR: //MCR调制控制寄存器
value = (byte)(mcr & 0xFF);
this.Log(LogLevel.Info, "Read MCR: 0x{0:X2}", value);
break;
case (long)Registers.BRSR: //波特率寄存器,暂无读操作
value = (uint)((brsr_h << 8) + brsr_l);
this.Log(LogLevel.Info, "Read MCR: 0x{0}", value);
break;
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.TBR_FreeBytes: //发送FIFO剩余字节数
tbr = (ushort)txFifo.Count;
value = (uint)tbr;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.RBR_FreeBytes: //接收FIFO剩余字节数
rbr = (ushort)rxFifo.Count;
value = (uint)rbr;
this.Log(LogLevel.Info, "Read RBR_FreeBytes: {0}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (uint)rstr;
break;
case (long)Registers.EXTI: //自定义,向外部提供读写信号
value = (uint)(ext_signal & 0xFF);
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
this.Log(LogLevel.Info, "entry WriteRegisters: 0x{0}, value: 0x{1}", offset, value);
switch (offset)
{
case (long)Registers.TBR_RBR:
WriteTBR((byte)value);
this.Log(LogLevel.Info, "Write TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //控制寄存器
WriteByte(offset, (byte)value);
break;
case (long)Registers.MCR: //调制控制寄存器
WriteByte(offset, (byte)value);
break;
case (long)Registers.BRSR: //波特率寄存器
if(value != 0)
{
currentBaudRate = (uint)(clockFrequency / value);;
brsr_l = (byte)(value);
brsr_h = (byte)(value >> 8);
this.Log(LogLevel.Info, "Write BRSR: {0}", value);
WriteByte(offset, brsr_l);
WriteByte((offset + 0x01), brsr_h);
}
break;
case (long)Registers.RSTR: // 复位/使能
WriteByte(offset, (byte)value);
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
value = (uint)ext_signal;
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
public byte ReadByte(long offset)
{
this.Log(LogLevel.Info, "entry ReadByte: 0x{0}", offset);
return 0x00;
}
public void WriteByte(long offset, byte value)
{
this.Log(LogLevel.Info, "entry WriteByte: 0x{0}, value: 0x{1}", offset, value);
switch(offset)
{
case (long)Registers.UCR_USR: //控制寄存器
ucr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write UCR_USR: 0x{0:X2}", ucr);
break;
case (long)Registers.MCR: //调制控制寄存器
mcr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write MCR: 0x{0:X2}", mcr);
UpdateModemControl();
break;
case (long)Registers.BRSR: //波特率寄存器
if(value != 0)
{
brsr_l = value;
this.Log(LogLevel.Info, "Write BRSR: 0x{0:X2}", brsr_l);
}
break;
case (long)Registers.BRSR_H:
if(value != 0)
{
brsr_h = value;
this.Log(LogLevel.Info, "Write BRSR: 0x{0:X2}", brsr_h);
}
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
WriteRXFIFOData((byte)value);
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
private void UpdateInterrupts()
{
bool interrupt = false;
// D2中断使能 必须置位才能产生中断
if ((mcr & MCR_BEN) != 0)
{
// 检查各种中断条件
if ((usr & USR_TCMP) != 0 ) //发送完成发送FIFO空发送中断
interrupt = true;
else if ((usr & USR_RBFI) != 0 ) //接收FIFO中有数据后延迟10ms产生一次接收中断
interrupt = true;
else if ((usr & (USR_PE | USR_FE | USR_OE | USR_BI)) != 0 ) //校验错、帧错、溢出错、接收碎片
interrupt = true;
}
IRQ.Set(interrupt);
if (interrupt)
{
this.Log(LogLevel.Info, "Interrupt asserted");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Info, "Interrupt deasserted");
});
}
}
private void UpdateModemControl()
{
if( (mcr & MCR_REN) == 0)
{
RxfifoEnabled = false; //待定
}
this.Log(LogLevel.Info, "Modem control: MCR_BEN={0}, MCR_REN={1}",
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
UpdateInterrupts();
}
public void WriteTBR(byte value)
{
// 从星务接收数据 操作txFifo
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
if (TxfifoEnabled)
{
if (txFifo.Count < TX_FIFO_SIZE)
{
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
usr = (byte)(usr & (~USR_TFE)); //发送FIFO不为空D6置0
}
else
{
fsta = (byte)(fsta | FSTA_TFUL); // 发送FIFO满
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,待定
txFifo.Clear();
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
}
// 暂时不发送数据,由中间层自取
}
public uint GetTXFIFOData()
{
uint data = 0x00;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if (txFifo.Count > 0)
{
data = txFifo.Dequeue();
// 调用基类的 TransmitCharacter 发送数据
// TransmitCharacter(data);
this.Log(LogLevel.Info, "Transmitted: 0x{0:X2} ('{1}')", data,
(data >= 32 && data < 127) ? (char)data : '.');
}
else
{
this.Log(LogLevel.Info, "TXFIFO Null ");
}
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public string GetTXFIFODataString()
{
string data = "0x";
byte tmp;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if(txFifo.Count == 0)
{
this.Log(LogLevel.Info, "TXFIFO Null");
return "0x00";
}
while (txFifo.Count > 0)
{
tmp = txFifo.Dequeue();
data += tmp.ToString("X2"); // 转换为16进制字符串
}
this.Log(LogLevel.Info, "Transmitted: 0x{0}, TXFIFO Null", data);
ext_signal = (byte)(ext_signal & (~EXT_SIGNAL_READ)); // 通知外部不可读
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public byte ReadRBR()
{
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Info, "Read: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
// 更新状态
if (rxFifo.Count == 0)
{
fsta = (byte)(fsta | FSTA_REMP); // 接收FIFO空
usr = (byte)(usr & (~USR_OE)); // 清除溢出错误
ext_signal = (byte)(ext_signal | EXT_SIGNAL_WRITE); // 通知外部可写
}
UpdateInterrupts();
return value;
}
public void WriteRXFIFOData(byte value)
{
// 向外部网络提供RXFIFO数据写入功能
if(RxfifoEnabled)
{
if(rxFifo.Count < RX_FIFO_SIZE)
{
rxFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
//待定
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms暂不实现
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
UpdateInterrupts();
}
public void WriteRXFIFODataString(string value)
{
// 向外部网络提供RXFIFO数据写入功能value=0xAABB...
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
string tmpString;
byte tmpHex;
int i;
if(RxfifoEnabled)
{
if(data.Length % 2 != 0)
{
data = "0" + data; // 前面补0
}
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
{
this.Log(LogLevel.Warning, "Data too long");
return;
}
for(i = 0; i < data.Length ; i+=2)
{
tmpString = data.Substring(i, 2);
tmpHex = Convert.ToByte(tmpString, 16);
rxFifo.Enqueue(tmpHex);
}
ext_signal = (byte)(ext_signal & (~EXT_SIGNAL_WRITE)); // 通知外部不可写
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
if(rxFifo.Count == RX_FIFO_SIZE)
{
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
machine.ScheduleAction(TimeInterval.FromMicroseconds(10000),
_ => {
UpdateInterrupts(); //等待10ms
});
}
else
{
}
}
public long Size => 0x28; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // TBR发送FIFORBR接收FIFO
UCR_USR = 0x04, // UCR控制寄存器,USR状态寄存器
MCR = 0x08, // 调制控制寄存器
BRSR = 0x0C, // 波特率设置寄存器
BRSR_H = 0x0D, // 波特率设置寄存器-高位
FSTA = 0x10, // FIFO状态寄存器
TBR_FreeBytes = 0x14, // 发送FIFO剩余字节数
RBR_FreeBytes = 0x18, // 接收FIFO剩余字节数
RSTR = 0x20, // 复位/使能 x55复位其他使能
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// UCR控制寄存器 位定义
private const byte UCR_STB = 0x01; // 停止位1位
private const byte UCR_PB = 0x0E; // 奇偶校验3位
private const byte USR_PE = 0x01; // 校验错
private const byte USR_FE = 0x02; // 帧错
private const byte USR_OE = 0x04; // 溢出错
private const byte USR_BI = 0x08; // 接收碎片
private const byte USR_TCMP = 0x20; // 发送完成(发送中断)
private const byte USR_TFE = 0x40; // 发送FIFO空
private const byte USR_RBFI = 0x80; // 接收中断
// MCR 调制控制寄存器
private const byte MCR_BEN = 0x04; // 中断使能
private const byte MCR_REN = 0x20; // 接收使能
// FSTA FIFO状态寄存器
private const byte FSTA_TEMP = 0x01; // 发送FIFO空
private const byte FSTA_TLHF= 0x02; // 发送FIFO低阈值半满
private const byte FSTA_TFUL = 0x04; // 发送FIFO满
private const byte FSTA_THHF = 0x08; // 发送FIFO高阈值半满
private const byte FSTA_REMP = 0x10; // 接收FIFO空
private const byte FSTA_RLHF = 0x20; // 接收FIFO低阈值半满
private const byte FSTA_RFUL = 0x40; // 接收FIFO满
private const byte FSTA_RHHF = 0x80; // 接收FIFO 高阈值半满
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 复位
private const byte RSTR_EN = 0xAA; // 使能
private const byte EXT_SIGNAL_WRITE = 0x0F; //0x0F表示外部可写
private const byte EXT_SIGNAL_READ = 0xF0; //0xF0表示外部可读
// 常量
private const int RX_FIFO_SIZE = 512; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 512; // 发送FIFO_SIZE
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte ucr; // 控制寄存器
private byte usr; // 状态寄存器
private byte mcr; // 调制控制寄存器
private byte brsr_l; // 波特率设置寄存器
private byte brsr_h; // 波特率设置寄存器
private byte fsta; // FIFO状态寄存器
private ushort tbr; // 发送FIFO剩余字节数
private ushort rbr; // 接收FIFO剩余字节数
private byte rstr; // 复位/使能寄存器
private byte ext_signal; //外部提供读写信号,读信号待确定
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private int fifoTriggerLevel;
}
}

402
UART_kx12A2.cs Normal file
View File

@@ -0,0 +1,402 @@
//
//UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器高速通信HSP
/// 接收缓存0B发送缓存512B时钟25MHz
/// </summary>
public class UART_771_RUHW_2CFG2 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG2(IMachine machine)
{
this.clockFrequency = 25000000;
this.machine = machine; //TODO
// 创建 FIFO
rxFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
rxFifo.Clear();
ucr = 0x00; // 控制寄存器(默认0x02)
usr = 0x00; // 状态寄存器
mcr = MCR_REN; // 调制控制寄存器:中断使能,接收使能
brsr = 0x43; // 波特率设置寄存器
fsta = 0x00; // FIFO状态寄存器
rstr = 0x00; // 复位/使能寄存器
RxfifoEnabled = true; //接收fifo使能
fifoTriggerLevel = 1;
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Info, "UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.RBR: //接收FIFO读操作
// 在接收FIFO寄存器中读取数据高速数据串口为双字节读取暂定小端TODO
value = (uint)(ReadRBR() << 8) + (uint)ReadRBR();
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X8}", value);
break;
case (long)Registers.UCR_USR: //USR状态寄存器
value = (byte)(usr & 0xFF);
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
usr = 0x00; // 高速上行:读取该寄存器后,自动清寄存器(来自需求)
break;
case (long)Registers.MCR: //MCR调制控制寄存器
value = (byte)(mcr & 0xFF);
this.Log(LogLevel.Info, "Read MCR: 0x{0:X2}", value);
break;
case (long)Registers.BRSR: //波特率寄存器,暂无读操作
value = (uint)brsr;
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (byte)(rstr & 0xFF);
this.Log(LogLevel.Info, "Read RSTR: 0x{0:X2}", value);
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.UCR_USR: //控制寄存器UCR
ucr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write UCR_USR: 0x{0:X2}", ucr);
break;
case (long)Registers.MCR: //调制控制寄存器
mcr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write MCR: 0x{0:X2}", mcr);
UpdateModemControl();
break;
case (long)Registers.BRSR: //波特率寄存器
if(value != 0)
{
currentBaudRate = (uint)(clockFrequency / value);
brsr = (ushort)value;
this.Log(LogLevel.Info, "Write BRSR: {0}", brsr);
}
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
//WriteRXFIFOData(value);
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
private void UpdateInterrupts()
{
bool interrupt = false;
// D2中断使能 必须置位才能产生中断
if ((mcr & MCR_BEN) != 0)
{
// 检查各种中断条件
if ((usr & USR_RBFI) != 0 ) //接收FIFO中有数据后延迟10ms产生一次接收中断
interrupt = true;
else if ((usr & (USR_PE | USR_FE | USR_OE | USR_BI)) != 0 ) //校验错、帧错、溢出错、接收碎片
interrupt = true;
}
IRQ.Set(interrupt);
if (interrupt)
{
this.Log(LogLevel.Info, "Interrupt asserted");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Info, "Interrupt deasserted");
});
}
}
private void UpdateModemControl()
{
if( (mcr & MCR_REN) == 0)
{
RxfifoEnabled = false;
}
this.Log(LogLevel.Info, "Modem control: MCR_BEN={0}, MCR_REN={1}",
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
UpdateInterrupts();
}
public byte ReadRBR()
{
//单字节读取
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Info, "Read: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
// 更新状态
if (rxFifo.Count == 0)
{
fsta = (byte)(fsta | FSTA_REMP); // 接收FIFO空
usr = (byte)(usr & (~USR_OE)); // 清除溢出错误
}
UpdateInterrupts();
return value;
}
public void WriteRXFIFOData(uint value)
{
// 向外部网络提供RXFIFO数据写入功能,value低16位有效
if(RxfifoEnabled)
{
if(rxFifo.Count < RX_FIFO_SIZE)
{
byte tmp = (byte)(value >> 8);
rxFifo.Enqueue(tmp);
tmp = (byte)value;
rxFifo.Enqueue(tmp);
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X4} ('{1}')", (ushort)value);
}
else
{
//待定
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms暂不实现
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
UpdateInterrupts();
}
public void WriteRXFIFODataString(string value)
{
// 向外部网络提供RXFIFO数据写入功能value=0xAABB...
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
string tmpString;
byte tmpHex;
int i;
if(RxfifoEnabled)
{
if(data.Length % 2 != 0)
{
data = "0" + data; // 前面补0
}
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
{
this.Log(LogLevel.Warning, "Data too long");
return;
}
for(i = 0; i < data.Length ; i+=2)
{
tmpString = data.Substring(i, 2);
tmpHex = Convert.ToByte(tmpString, 16);
rxFifo.Enqueue(tmpHex);
}
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
if(rxFifo.Count == RX_FIFO_SIZE)
{
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms暂不实现
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
UpdateInterrupts();
}
else
{
}
}
public long Size => 0x28; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
RBR = 0x00, // RBR接收FIFO无发送操作
UCR_USR = 0x04, // UCR控制寄存器,USR状态寄存器
MCR = 0x08, // 调制控制寄存器
BRSR = 0x0C, // 波特率设置寄存器
RSTR = 0x10, /// 复位/使能 x55复位其他使能
FSTA = 0x14, // FIFO状态寄存器
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// UCR控制寄存器 位定义
private const byte UCR_STB = 0x01; // 停止位1位
private const byte UCR_PB = 0x0E; // 奇偶校验3位
private const byte USR_PE = 0x01; // 校验错
private const byte USR_FE = 0x02; // 帧错
private const byte USR_OE = 0x04; // 溢出错
private const byte USR_BI = 0x08; // 接收碎片
private const byte USR_TCMP = 0x20; // 发送完成(发送中断)
private const byte USR_TFE = 0x40; // 发送FIFO空
private const byte USR_RBFI = 0x80; // 接收中断
// MCR 调制控制寄存器
private const byte MCR_BEN = 0x04; // 中断使能
private const byte MCR_REN = 0x20; // 接收使能
// FSTA FIFO状态寄存器
private const byte FSTA_REMP = 0x10; // 接收FIFO空
private const byte FSTA_RLHF = 0x20; // 接收FIFO低阈值半满
private const byte FSTA_RFUL = 0x40; // 接收FIFO满
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 复位
private const byte RSTR_EN = 0xAA; // 使能
// 常量
private const int RX_FIFO_SIZE = 2048; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 512; // 发送FIFO_SIZE
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte ucr; // 控制寄存器
private byte usr; // 状态寄存器
private byte mcr; // 调制控制寄存器
private ushort brsr; // 波特率设置寄存器
private byte fsta; // FIFO状态寄存器
private byte rstr; // 复位/使能寄存器
// FIFO
private readonly Queue<byte> rxFifo;
private bool RxfifoEnabled;
private int fifoTriggerLevel;
}
}

542
UART_kx12A3.cs Normal file
View File

@@ -0,0 +1,542 @@
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器
/// 接收缓存512B发送缓存2048B时钟24MHz
/// </summary>
public class UART_771_RUHW_2CFG3 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG3(IMachine machine)
{
this.clockFrequency = 24000000;
this.machine = machine; //TODO
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
rxFifo.Clear();
txFifo.Clear();
ucr = 0x00; // 控制寄存器
usr = USR_TFE;// 状态寄存器
mcr = 0x00; // 调制控制寄存器:中断使能,接收使能
brsr = 0; // 波特率设置寄存器
fsta = (byte)(FSTA_TEMP | FSTA_REMP); // FIFO状态寄存器
tbr = 0; // 发送FIFO剩余字节数
rbr = 0; // 接收FIFO剩余字节数
rstr = 0x00; // 复位/使能寄存器
RxfifoEnabled = true; //接收fifo使能
TxfifoEnabled = true; //发送fifo使能
fifoTriggerLevel = 1;
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Info, "UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.TBR_RBR: //接收FIFO读操作
// 在接收FIFO寄存器中读取数据
value = ReadRBR();
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //USR状态寄存器
value = (byte)(usr & 0xFF);
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
// usr = (byte)(usr & (~USR_RBFI)); //usr寄存器取消接收中断与hw_uart_isr关联暂定
break;
case (long)Registers.MCR: //MCR调制控制寄存器
value = (byte)(mcr & 0xFF);
this.Log(LogLevel.Info, "Read MCR: 0x{0:X2}", value);
break;
case (long)Registers.BRSR: //波特率寄存器,暂无读操作
value = (uint)(brsr);
this.Log(LogLevel.Info, "Read MCR: 0x{0}", value);
break;
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
//GetTXFIFODataString(); //测试TODO,删除
break;
case (long)Registers.TBR_FreeBytes: //发送FIFO剩余字节数
tbr = (ushort)txFifo.Count;
value = (uint)tbr;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.RBR_FreeBytes: //接收FIFO剩余字节数
rbr = (ushort)rxFifo.Count;
value = (uint)rbr;
this.Log(LogLevel.Info, "Read RBR_FreeBytes: {0}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (uint)rstr;
break;
case (long)Registers.EXTI: //自定义向外部提供读发送FIFO寄存器
//value = (uint)GetTXFIFOData();
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.TBR_RBR:
WriteTBR((byte)value);
this.Log(LogLevel.Info, "Write TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //控制寄存器
ucr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write UCR_USR: 0x{0:X2}", ucr);
break;
case (long)Registers.MCR: //调制控制寄存器
mcr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write MCR: 0x{0:X2}", mcr);
UpdateModemControl();
break;
case (long)Registers.BRSR: //波特率寄存器
if(value != 0)
{
currentBaudRate = (uint)(clockFrequency / value);
brsr = (ushort)value;
this.Log(LogLevel.Info, "Write BRSR: {0}", brsr);
}
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
//WriteRXFIFOData((byte)value);
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
private void UpdateInterrupts()
{
bool interrupt = false;
// D2中断使能 必须置位才能产生中断
if ((mcr & MCR_BEN) != 0)
{
// 检查各种中断条件
if ((usr & USR_TCMP) != 0 ) //发送完成发送FIFO空发送中断
interrupt = true;
else if ((usr & USR_RBFI) != 0 ) //接收FIFO中有数据后延迟10ms产生一次接收中断
interrupt = true;
else if ((usr & (USR_PE | USR_FE | USR_OE | USR_BI)) != 0 ) //校验错、帧错、溢出错、接收碎片
interrupt = true;
}
IRQ.Set(interrupt);
if (interrupt)
{
this.Log(LogLevel.Info, "Interrupt asserted");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Info, "Interrupt deasserted");
});
}
}
private void UpdateModemControl()
{
if((mcr & MCR_REN) == 0)
{
RxfifoEnabled = false; //待定
}
this.Log(LogLevel.Info, "Modem control: MCR_BEN={0}, MCR_REN={1}",
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
UpdateInterrupts();
}
public void WriteTBR(byte value)
{
// 从星务接收数据 操作txFifo
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
if (TxfifoEnabled)
{
if (txFifo.Count < TX_FIFO_SIZE)
{
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
usr = (byte)(usr & (~USR_TFE)); //发送FIFO不为空D6置0
}
else
{
fsta = (byte)(fsta | FSTA_TFUL); // 发送FIFO满
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,待定
txFifo.Clear();
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
}
// 暂时不发送数据,由中间层自取
}
public uint GetTXFIFOData()
{
uint data = 0x00;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if (txFifo.Count > 0)
{
data = txFifo.Dequeue();
// 调用基类的 TransmitCharacter 发送数据
// TransmitCharacter(data);
this.Log(LogLevel.Info, "Transmitted: 0x{0:X2} ('{1}')", data,
(data >= 32 && data < 127) ? (char)data : '.');
}
else
{
this.Log(LogLevel.Info, "TXFIFO Null ");
}
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public string GetTXFIFODataString()
{
string data = "0x";
byte tmp;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if(txFifo.Count == 0)
{
this.Log(LogLevel.Info, "TXFIFO Null");
return "0x00";
}
while (txFifo.Count > 0)
{
tmp = txFifo.Dequeue();
data += tmp.ToString("X2"); // 转换为16进制字符串
}
this.Log(LogLevel.Info, "Transmitted: 0x{0}, TXFIFO Null", data);
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public byte ReadRBR()
{
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Info, "Read: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
// 更新状态
if (rxFifo.Count == 0)
{
fsta = (byte)(fsta | FSTA_REMP); // 接收FIFO空
usr = (byte)(usr & (~USR_OE)); // 清除溢出错误
}
UpdateInterrupts();
return value;
}
public void WriteRXFIFOData(byte value)
{
// 向外部网络提供RXFIFO数据写入功能
if(RxfifoEnabled)
{
if(rxFifo.Count < RX_FIFO_SIZE)
{
rxFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
//待定
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
machine.ScheduleAction(TimeInterval.FromMicroseconds(10000),
_ => {
UpdateInterrupts(); //等待10ms
});
}
public void WriteRXFIFODataString(string value)
{
// 向外部网络提供RXFIFO数据写入功能value=0xAABB...
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
string tmpString;
byte tmpHex;
int i;
if(RxfifoEnabled)
{
if(data.Length % 2 != 0)
{
data = "0" + data; // 前面补0
}
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
{
this.Log(LogLevel.Warning, "Data too long");
return;
}
for(i = 0; i < data.Length ; i+=2)
{
tmpString = data.Substring(i, 2);
tmpHex = Convert.ToByte(tmpString, 16);
rxFifo.Enqueue(tmpHex);
}
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
if(rxFifo.Count == RX_FIFO_SIZE)
{
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms暂不实现
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
UpdateInterrupts();
}
else
{
}
}
public long Size => 0x28; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // TBR发送FIFORBR接收FIFO
UCR_USR = 0x04, // UCR控制寄存器,USR状态寄存器
MCR = 0x08, // 调制控制寄存器
BRSR = 0x0C, // 波特率设置寄存器
FSTA = 0x10, // FIFO状态寄存器
TBR_FreeBytes = 0x14, // 发送FIFO剩余字节数
RBR_FreeBytes = 0x18, // 接收FIFO剩余字节数
RSTR = 0x20, // 复位/使能 x55复位其他使能
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// UCR控制寄存器 位定义
private const byte UCR_STB = 0x01; // 停止位1位
private const byte UCR_PB = 0x0E; // 奇偶校验3位
private const byte USR_PE = 0x01; // 校验错
private const byte USR_FE = 0x02; // 帧错
private const byte USR_OE = 0x04; // 溢出错
private const byte USR_BI = 0x08; // 接收碎片
private const byte USR_TCMP = 0x20; // 发送完成(发送中断)
private const byte USR_TFE = 0x40; // 发送FIFO空
private const byte USR_RBFI = 0x80; // 接收中断
// MCR 调制控制寄存器
private const byte MCR_BEN = 0x04; // 中断使能
private const byte MCR_REN = 0x20; // 接收使能
// FSTA FIFO状态寄存器
private const byte FSTA_TEMP = 0x01; // 发送FIFO空
private const byte FSTA_TLHF= 0x02; // 发送FIFO低阈值半满
private const byte FSTA_TFUL = 0x04; // 发送FIFO满
private const byte FSTA_THHF = 0x08; // 发送FIFO高阈值半满
private const byte FSTA_REMP = 0x10; // 接收FIFO空
private const byte FSTA_RLHF = 0x20; // 接收FIFO低阈值半满
private const byte FSTA_RFUL = 0x40; // 接收FIFO满
private const byte FSTA_RHHF = 0x80; // 接收FIFO 高阈值半满
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 复位
private const byte RSTR_EN = 0xAA; // 使能
// 常量
private const int RX_FIFO_SIZE = 512; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 2048; // 发送FIFO_SIZE
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte ucr; // 控制寄存器
private byte usr; // 状态寄存器
private byte mcr; // 调制控制寄存器
private ushort brsr; // 波特率设置寄存器
private byte fsta; // FIFO状态寄存器
private ushort tbr; // 发送FIFO剩余字节数
private ushort rbr; // 接收FIFO剩余字节数
private byte rstr; // 复位/使能寄存器
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private int fifoTriggerLevel;
}
}

543
UART_kx12A4.cs Normal file
View File

@@ -0,0 +1,543 @@
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器
/// 接收缓存1024B发送缓存2048B时钟24MHz
/// </summary>
public class UART_771_RUHW_2CFG4 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG4(IMachine machine)
{
this.clockFrequency = 24000000;
this.machine = machine; //TODO
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
rxFifo.Clear();
txFifo.Clear();
ucr = 0x00; // 控制寄存器
usr = USR_TFE; // 状态寄存器
mcr = 0x00; // 调制控制寄存器:中断使能,接收使能
brsr = 0; // 波特率设置寄存器
fsta = (byte)(FSTA_TEMP | FSTA_REMP); // FIFO状态寄存器
tbr = 0; // 发送FIFO剩余字节数
rbr = 0; // 接收FIFO剩余字节数
rstr = 0x00; // 复位/使能寄存器
RxfifoEnabled = true; //接收fifo使能
TxfifoEnabled = true; //发送fifo使能
fifoTriggerLevel = 1;
IRQ.Set(false);
UpdateInterrupts();
this.Log(LogLevel.Info, "UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.TBR_RBR: //接收FIFO读操作
// 在接收FIFO寄存器中读取数据
value = ReadRBR();
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //USR状态寄存器
value = (byte)(usr & 0xFF);
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
usr = (byte)(usr & (~(USR_RBFI | USR_TCMP))); //usr寄存器取消中断与hw_uart_isr关联暂定
UpdateInterrupts();
break;
case (long)Registers.MCR: //MCR调制控制寄存器
value = (byte)(mcr & 0xFF);
this.Log(LogLevel.Info, "Read MCR: 0x{0:X2}", value);
break;
case (long)Registers.BRSR: //波特率寄存器,暂无读操作
value = (uint)(brsr);
this.Log(LogLevel.Info, "Read MCR: 0x{0}", value);
break;
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
//GetTXFIFODataString(); //测试TODO,删除
break;
case (long)Registers.TBR_FreeBytes: //发送FIFO剩余字节数
tbr = (ushort)txFifo.Count;
value = (uint)tbr;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.RBR_FreeBytes: //接收FIFO剩余字节数
rbr = (ushort)rxFifo.Count;
value = (uint)rbr;
this.Log(LogLevel.Info, "Read RBR_FreeBytes: {0}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (uint)rstr;
break;
case (long)Registers.EXTI: //自定义向外部提供读发送FIFO寄存器
//value = (uint)GetTXFIFOData();
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.TBR_RBR:
WriteTBR((byte)value);
this.Log(LogLevel.Info, "Write TBR_RBR: 0x{0:X2}", value);
break;
case (long)Registers.UCR_USR: //控制寄存器
ucr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write UCR_USR: 0x{0:X2}", ucr);
break;
case (long)Registers.MCR: //调制控制寄存器
mcr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write MCR: 0x{0:X2}", mcr);
UpdateModemControl();
break;
case (long)Registers.BRSR: //波特率寄存器
if(value != 0)
{
currentBaudRate = (uint)(clockFrequency / value);
brsr = (ushort)value;
this.Log(LogLevel.Info, "Write BRSR: {0}", brsr);
}
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
//WriteRXFIFOData((byte)value);
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
private void UpdateInterrupts()
{
bool interrupt = false;
// D2中断使能 必须置位才能产生中断
if ((mcr & MCR_BEN) != 0)
{
// 检查各种中断条件
if ((usr & USR_TCMP) != 0 ) //发送完成发送FIFO空发送中断
interrupt = true;
else if ((usr & USR_RBFI) != 0 ) //接收FIFO中有数据后延迟10ms产生一次接收中断
interrupt = true;
else if ((usr & (USR_PE | USR_FE | USR_OE | USR_BI)) != 0 ) //校验错、帧错、溢出错、接收碎片
interrupt = true;
}
IRQ.Set(interrupt);
if (interrupt)
{
this.Log(LogLevel.Info, "Interrupt asserted");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Info, "Interrupt deasserted");
});
}
}
private void UpdateModemControl()
{
if((mcr & MCR_REN) == 0)
{
RxfifoEnabled = false; //待定
}
this.Log(LogLevel.Info, "Modem control: MCR_BEN={0}, MCR_REN={1}",
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
UpdateInterrupts();
}
public void WriteTBR(byte value)
{
// 从星务接收数据 操作txFifo
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
if (TxfifoEnabled)
{
if (txFifo.Count < TX_FIFO_SIZE)
{
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
usr = (byte)(usr & (~USR_TFE)); //发送FIFO不为空D6置0
}
else
{
fsta = (byte)(fsta | FSTA_TFUL); // 发送FIFO满
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,待定
txFifo.Clear();
txFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
}
// 暂时不发送数据,由中间层自取
}
public uint GetTXFIFOData()
{
uint data = 0x00;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if (txFifo.Count > 0)
{
data = txFifo.Dequeue();
// 调用基类的 TransmitCharacter 发送数据
// TransmitCharacter(data);
this.Log(LogLevel.Info, "Transmitted: 0x{0:X2} ('{1}')", data,
(data >= 32 && data < 127) ? (char)data : '.');
}
else
{
this.Log(LogLevel.Info, "TXFIFO Null ");
}
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public string GetTXFIFODataString()
{
string data = "0x";
byte tmp;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if(txFifo.Count == 0)
{
this.Log(LogLevel.Info, "TXFIFO Null");
return "0x00";
}
while (txFifo.Count > 0)
{
tmp = txFifo.Dequeue();
data += tmp.ToString("X2"); // 转换为16进制字符串
}
this.Log(LogLevel.Info, "Transmitted: 0x{0}, TXFIFO Null", data);
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)((fsta &0xF0) | FSTA_TEMP); // 发送缓冲区为空D0置0
usr = (byte)(usr | USR_TFE); // 发送FIFO空
usr = (byte)(usr | USR_TCMP); // 发送完成(发送中断)
}
UpdateInterrupts();
return data;
}
public byte ReadRBR()
{
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Info, "Read: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
// 更新状态
if (rxFifo.Count == 0)
{
fsta = (byte)(fsta | FSTA_REMP); // 接收FIFO空
usr = (byte)(usr & (~USR_OE)); // 清除溢出错误
}
UpdateInterrupts();
return value;
}
public void WriteRXFIFOData(byte value)
{
// 向外部网络提供RXFIFO数据写入功能
if(RxfifoEnabled)
{
if(rxFifo.Count < RX_FIFO_SIZE)
{
rxFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
//待定
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
UpdateInterrupts();
}
public void WriteRXFIFODataString(string value)
{
// 向外部网络提供RXFIFO数据写入功能value=0xAABB...
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
//this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
string tmpString;
byte tmpHex;
int i;
if(RxfifoEnabled)
{
if(data.Length % 2 != 0)
{
data = "0" + data; // 前面补0
}
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
{
this.Log(LogLevel.Warning, "Data too long");
return;
}
for(i = 0; i < data.Length ; i+=2)
{
tmpString = data.Substring(i, 2);
tmpHex = Convert.ToByte(tmpString, 16);
rxFifo.Enqueue(tmpHex);
}
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
if(rxFifo.Count == RX_FIFO_SIZE)
{
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
usr = (byte)(usr | USR_RBFI); //usr寄存器置接收中断
machine.ScheduleAction(TimeInterval.FromMicroseconds(10000),
_ => {
UpdateInterrupts();
});
}
else
{
}
}
public long Size => 0x28; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // TBR发送FIFORBR接收FIFO
UCR_USR = 0x04, // UCR控制寄存器,USR状态寄存器
MCR = 0x08, // 调制控制寄存器
BRSR = 0x0C, // 波特率设置寄存器
FSTA = 0x10, // FIFO状态寄存器
TBR_FreeBytes = 0x14, // 发送FIFO剩余字节数
RBR_FreeBytes = 0x18, // 接收FIFO剩余字节数
RSTR = 0x20, // 复位/使能 x55复位其他使能
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// UCR控制寄存器 位定义
private const byte UCR_STB = 0x01; // 停止位1位
private const byte UCR_PB = 0x0E; // 奇偶校验3位
private const byte USR_PE = 0x01; // 校验错
private const byte USR_FE = 0x02; // 帧错
private const byte USR_OE = 0x04; // 溢出错
private const byte USR_BI = 0x08; // 接收碎片
private const byte USR_TCMP = 0x20; // 发送完成(发送中断)
private const byte USR_TFE = 0x40; // 发送FIFO空
private const byte USR_RBFI = 0x80; // 接收中断
// MCR 调制控制寄存器
private const byte MCR_BEN = 0x04; // 中断使能
private const byte MCR_REN = 0x20; // 接收使能
// FSTA FIFO状态寄存器
private const byte FSTA_TEMP = 0x01; // 发送FIFO空
private const byte FSTA_TLHF= 0x02; // 发送FIFO低阈值半满
private const byte FSTA_TFUL = 0x04; // 发送FIFO满
private const byte FSTA_THHF = 0x08; // 发送FIFO高阈值半满
private const byte FSTA_REMP = 0x10; // 接收FIFO空
private const byte FSTA_RLHF = 0x20; // 接收FIFO低阈值半满
private const byte FSTA_RFUL = 0x40; // 接收FIFO满
private const byte FSTA_RHHF = 0x80; // 接收FIFO 高阈值半满
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 复位
private const byte RSTR_EN = 0xAA; // 使能
// 常量
private const int RX_FIFO_SIZE = 1024; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 2048; // 发送FIFO_SIZE
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte ucr; // 控制寄存器
private byte usr; // 状态寄存器
private byte mcr; // 调制控制寄存器
private ushort brsr; // 波特率设置寄存器
private byte fsta; // FIFO状态寄存器
private ushort tbr; // 发送FIFO剩余字节数
private ushort rbr; // 接收FIFO剩余字节数
private byte rstr; // 复位/使能寄存器
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private int fifoTriggerLevel;
}
}

336
UART_kx12A5.cs Normal file
View File

@@ -0,0 +1,336 @@
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器:同步串口,遥控,无中断
/// 接收缓存1024B发送缓存1024B时钟2000Hz
/// </summary>
public class UART_771_RUHW_2CFG5 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG5(IMachine machine)
{
this.clockFrequency = 2000;
this.machine = machine; //TODO
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
rxFifo.Clear();
txFifo.Clear();
fsta = 0x00; // FIFO状态寄存器
frm_cnt = 0x00; //帧头校验正确计数
rbr = 0; // 接收FIFO剩余字节数
crc_rcnt = 0x00; //crc正确计数
crc_ecnt = 0x00; //crc错误计数
rstr = 0x00; // 复位/使能寄存器
full_cnt = 0x00; //fifo 满计数
RxfifoEnabled = true; //接收fifo使能
TxfifoEnabled = false; //发送fifo禁止
fifoTriggerLevel = 1;
currentBaudRate = 0;
IRQ.Set(false);
this.Log(LogLevel.Info, "UART reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.TBR_RBR: //接收FIFO读操作
// 在接收FIFO寄存器中读取数据
value = (uint)ReadRBR();
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X2}", (ushort)value);
break;
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.FRM_CNT: //帧头校验正确计数,TODO如何修改
value = (uint)frm_cnt;
this.Log(LogLevel.Info, "Read FRM_CNT: {0}", value);
break;
case (long)Registers.RBR_FreeBytes: //接收FIFO剩余字节数
rbr = (ushort)rxFifo.Count;
value = (uint)rbr;
this.Log(LogLevel.Info, "Read RBR_FreeBytes: {0}", value);
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
//WriteRXFIFOData((byte)value);
break;
case (long)Registers.FSTA:
WriteFIFOStatus((byte)value); //向外部提供写FIFO状态遥控数据是否接收完成
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
public byte ReadRBR()
{
byte value = 0;
if (rxFifo.Count > 0)
{
value = rxFifo.Dequeue();
this.Log(LogLevel.Info, "Read: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
this.Log(LogLevel.Warning, "Read from empty RBR");
}
// 更新状态
if (rxFifo.Count == 0)
{
fsta = (byte)(fsta | FSTA_REMP); // 接收FIFO空
}
return value;
}
public void WriteRXFIFOData(byte value)
{
// 向外部网络提供RXFIFO数据写入功能低16位有效
if(RxfifoEnabled)
{
if(rxFifo.Count < RX_FIFO_SIZE)
{
rxFifo.Enqueue(value);
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
}
else
{
//待定
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
fsta = (byte)(fsta & (~FSTA_RGF) ); // 遥控数据接收未完成
}
public void WriteFIFOStatus(byte value)
{
// 向外部网络提供FIFO状态寄存器数据写入功能遥控数据是否接收完成
//value=0x80为完成
fsta = (byte)(fsta | value); // 遥控数据接收完成状态位设置
this.Log(LogLevel.Info, "External Write RXFIFOStatus: 0x{0:X2} ('{1}')", value,
(value >= 32 && value < 127) ? (char)value : '.');
if ((value & FSTA_RGF) != 0)
{
frm_cnt++; //完整接收一帧,更新帧计数
}
}
public void WriteRXFIFODataString(string value)
{
// 向外部网络提供RXFIFO数据写入功能value=0xAABB...
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
string tmpString;
byte tmpHex;
int i;
if(RxfifoEnabled)
{
if(data.Length % 2 != 0)
{
data = "0" + data; // 前面补0
}
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
{
this.Log(LogLevel.Warning, "Data too long");
return;
}
for(i = 0; i < data.Length ; i+=2)
{
tmpString = data.Substring(i, 2);
tmpHex = Convert.ToByte(tmpString, 16);
rxFifo.Enqueue(tmpHex);
}
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
fsta = (byte)(fsta | FSTA_RGF); //遥控数据接收完成状态位设置
frm_cnt++; //完整接收一帧,更新帧计数
if(rxFifo.Count == RX_FIFO_SIZE)
{
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
this.Log(LogLevel.Warning, "RX FIFO Already Full");
}
}
else
{
}
}
public long Size => 0x80; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // RBR接收FIFO
FSTA = 0x04, // FIFO状态寄存器
FRM_CNT = 0x1C, // 帧头校验正确计数
RBR_FreeBytes = 0x0C, // 接收FIFO剩余字节数
CRC_RCNT = 0x14, // 同步头航天识别字虚拟信道号crc正确计数
CRC_ECNT = 0x18, //同步头航天识别字虚拟信道号正确crc错误计数
RSTR = 0x7C, // 复位/使能 x55复位其他使能
FULL_CNT = 0x10, // fifo 满计数
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// FSTA FIFO状态寄存器
private const byte FSTA_REMP = 0x01; // 接收FIFO空
private const byte FSTA_RLHF= 0x02; // 接收FIFO半满
private const byte FSTA_RFUL = 0x04; // 接收FIFO满
private const byte FSTA_RGF = 0x08; // 接收FIFO门控空闲遥控数据接收完成
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 复位
private const byte RSTR_EN = 0xAA; // 使能
// 常量
private const int RX_FIFO_SIZE = 1024; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 1024; // 发送FIFO_SIZE
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
// 寄存器
private byte fsta; // FIFO状态寄存器
private ushort frm_cnt; // 帧头校验正确计数
private ushort rbr; // 接收FIFO剩余字节数
private ushort crc_rcnt; // crc正确计数
private ushort crc_ecnt; // crc错误计数
private byte rstr; // 复位/使能寄存器
private ushort full_cnt; // fifo 满计数
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private int fifoTriggerLevel;
}
}

390
UART_kx12A6.cs Normal file
View File

@@ -0,0 +1,390 @@
//
// UART 外设实现
// 基于 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能
//
using System;
using System.Collections.Generic;
using Antmicro.Renode.Core;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.UART;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
namespace Antmicro.Renode.Peripherals.CustomPeripherals
{
/// <summary>
/// UART_771_RUHW_2CFG 控制器:同步串口、遥测、有中断
/// 接收缓存0B发送缓存2048B输入时钟24MHz
/// </summary>
public class UART_771_RUHW_2CFG6 : IDoubleWordPeripheral, IKnownSize
{
private readonly IMachine machine; //TODO
public UART_771_RUHW_2CFG6(IMachine machine)
{
this.clockFrequency = 24000000;
this.machine = machine; //TODO
// 创建 FIFO
txFifo = new Queue<byte>();
rxFifo = new Queue<byte>();
// 创建中断线
IRQ = new GPIO();
// 初始化寄存器
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
}
public void Reset()
{
txFifo.Clear();
fsta = FSTA_TEMP; // FIFO状态寄存器
frm_cnt = 0; // 帧计数
tbr = 0; // 发送FIFO剩余字节数
currentBaudRate = 16384; // 时钟配置缺省为16384Hz
clk_set = (ushort)(clockFrequency / (2 * currentBaudRate) - 1);
scramble_ctrl = 0x00; // 加解扰使能禁止
rstr = 0x00; // 复位/使能寄存器
TxfifoEnabled = true; //发送fifo使能
fifoTriggerLevel = 1;
byte_cnt = 0;
IRQ.Set(false);
UpdateInterrupts(false);
this.Log(LogLevel.Info, "TX_FIFO_SIZE reset");
}
private void DefineRegisters()
{
// 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现
}
// ========================================
// IBusPeripheral 接口实现
// ========================================
public uint ReadDoubleWord(long offset)
{
return ReadRegisters(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
WriteRegisters(offset, value);
}
// ========================================
// 自定义
// ========================================
public uint ReadRegisters(long offset)
{
uint value = 0;
switch (offset)
{
case (long)Registers.FSTA: // FIFO状态寄存器
value = (byte)(fsta & 0xFF);
this.Log(LogLevel.Info, "Read FSTA: 0x{0:X2}", value);
break;
case (long)Registers.FRM_CNT: //帧计数,待定
value = (uint)frm_cnt;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.TBR_FreeBytes: //发送FIFO剩余字节数
tbr = (ushort)txFifo.Count;
value = (uint)tbr;
this.Log(LogLevel.Info, "Read TBR_FreeBytes: {0}", value);
break;
case (long)Registers.CLK_SET: //时钟配置,暂无读操作
value = (uint)clk_set;
this.Log(LogLevel.Info, "Read CLK_SET: {0}", value);
break;
case (long)Registers.SCRAMBLE_CTRL: //加解扰使能禁止,暂无读操作
value = (uint)(scramble_ctrl & 0xFF);
this.Log(LogLevel.Info, "Read SCRAMBLE_CTRL: 0x{0}", value);
break;
case (long)Registers.RSTR: // 复位/使能,暂无读操作
value = (uint)(rstr & 0xFF);
this.Log(LogLevel.Info, "Read RSTR: 0x{0}", value);
break;
case (long)Registers.EXTI: //自定义向外部提供读发送FIFO寄存器
//value = (uint)GetTXFIFOData();
break;
default:
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
return value;
}
public void WriteRegisters(long offset, uint value)
{
switch (offset)
{
case (long)Registers.TBR_RBR: // 发送FIFO
WriteTBR(value);
this.Log(LogLevel.Info, "Write TBR_RBR: {0}", value);
break;
case (long)Registers.CLK_SET: // 时钟配置
clk_set = (ushort)value;
currentBaudRate = (ushort)(clockFrequency / 2 / (1 + value));
this.Log(LogLevel.Info, "Write CLK_SET: {0}, currentBaudRate: {1}", value, currentBaudRate);
break;
case (long)Registers.SCRAMBLE_CTRL: // 加解扰使能禁止
scramble_ctrl = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write SCRAMBLE_CTRL: 0x{0:X2}", value);
break;
case (long)Registers.RSTR: // 复位/使能
rstr = (byte)(value & 0xFF);
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
if ((rstr & 0XFF) == RSTR_RES)
{
Reset();
}
break;
default:
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
break;
}
}
private void UpdateInterrupts(bool flag)
{
IRQ.Set(flag);
if (flag)
{
this.Log(LogLevel.Info, "Interrupt asserted");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "Interrupt deasserted");
});
}
}
public void WriteTBR(uint value)
{
// 从星务接收数据 操作txFifo
// value 低16位有效
if (TxfifoEnabled)
{
if (txFifo.Count < TX_FIFO_SIZE)
{
byte tmp = (byte)(value >> 8);
txFifo.Enqueue(tmp);
tmp = (byte)value;
txFifo.Enqueue(tmp);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
// 更新帧计数
byte_cnt += 2;
frm_cnt = (ushort)(byte_cnt / FRAME_LONG); // 遥测帧固定1024字节
if (txFifo.Count == (TX_FIFO_SIZE / 2))
{
// 置半满标志
fsta = (byte)(fsta | FSTA_TLHF); // 发送FIFO半满,D2置1
}
if (txFifo.Count > IRQ_MAXBYTES) //FIFO中的字节数大于96字节时中断自动清除
{
UpdateInterrupts(false);
}
}
else
{
fsta = (byte)(fsta | FSTA_TFUL); // 发送FIFO满
this.Log(LogLevel.Warning, "TX FIFO overflow");
}
}
else
{
// 非 FIFO 模式,待定
txFifo.Clear();
txFifo.Enqueue((byte)value);
fsta = (byte)(fsta & (~FSTA_TEMP)); // 发送缓冲区不为空D0置0
}
// 暂时不发送数据,由中间层自取
}
public uint GetTXFIFOData()
{
// 低16位有效
uint data = 0x00;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if (txFifo.Count > 0)
{
data = (uint)(txFifo.Dequeue() << 8) + (uint)txFifo.Dequeue();
this.Log(LogLevel.Info, "Transmitted: {0} ", data);
}
else
{
this.Log(LogLevel.Info, "TXFIFO Null ");
}
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)(FSTA_TEMP | FSTA_THHF); // 发送缓冲区为空D0置0,D2置0D3置1
}
else if(frm_cnt == 0)
{
// 遥测FIFO空时需要先写入大于64个字节数才能触发中断
// 无中断操作
}
else if(txFifo.Count < IRQ_MINBYTES) //FIFO中的字节数小于64字节时会产生中断
{
UpdateInterrupts(true);
}
return data;
}
public string GetTXFIFODataString()
{
string data = "0x";
byte tmp;
// 从 TX FIFO 发送数据中间层获取txfifo接口
if(txFifo.Count == 0)
{
this.Log(LogLevel.Info, "TXFIFO Null");
return "0x00";
}
while (txFifo.Count > 0)
{
tmp = txFifo.Dequeue();
data += tmp.ToString("X2"); // 转换为16进制字符串
}
this.Log(LogLevel.Info, "Transmitted: 0x{0}, TXFIFO Null", data);
// 更新状态
if (txFifo.Count == 0)
{
fsta = (byte)(FSTA_TEMP | FSTA_THHF); // 发送缓冲区为空D0置0,D2置0D3置1
UpdateInterrupts(true);
}
else if(frm_cnt == 0)
{
// 遥测FIFO空时需要先写入大于64个字节数才能触发中断
// 无中断操作
}
else if(txFifo.Count < IRQ_MINBYTES) //FIFO中的字节数小于64字节时会产生中断
{
UpdateInterrupts(true);
}
return data;
}
public long Size => 0x80; //uart地址长度总空间
public GPIO IRQ { get; }
// ========================================
// 寄存器定义
// ========================================
private enum Registers : long
{
TBR_RBR = 0x00, // TBR发送FIFO
FSTA = 0x04, // FIFO状态寄存器
FRM_CNT = 0x08, // 帧计数
TBR_FreeBytes = 0x0C, // 发送FIFO剩余字节数
CLK_SET = 0x10, // 时钟配置
SCRAMBLE_CTRL = 0x14, // 加解扰使能禁止
RSTR = 0x7C, // 复位/使能 x55复位其他使能
EXTI = 0x24 // 向外部提供读写FIFO接口
}
// FSTA FIFO状态寄存器
private const byte FSTA_TEMP = 0x01; // 发送FIFO空
private const byte FSTA_TLHF= 0x02; // 发送FIFO半满
private const byte FSTA_TFUL = 0x04; // 发送FIFO满
private const byte FSTA_THHF = 0x08; // 1为空闲0为正在发送
// RSTR 复位/使能寄存器
private const byte RSTR_RES = 0x55; // 0x55复位其他使能
private const byte SCRAMBLE_CTRL_ENABLE = 0x55; // 0x55加解扰使能其他禁止
// 常量
private const int RX_FIFO_SIZE = 0; // 接收FIFO_SIZE
private const int TX_FIFO_SIZE = 2048; // 发送FIFO_SIZE
private const int FRAME_LONG = 1024; // 帧长固定为1024B
private const int IRQ_MINBYTES = 64; // FIFO中的字节数小于64字节时会产生中断
private const int IRQ_MAXBYTES = 96; // FIFO中的字节数大于96字节时会清中断
// ========================================
// 私有字段
// ========================================
private readonly uint clockFrequency;
private uint currentBaudRate;
private uint byte_cnt; // 字节计数,计算帧计数
// 寄存器
private byte fsta; // FIFO状态寄存器
private ushort frm_cnt; // 帧计数
private ushort tbr; // 发送FIFO剩余字节数
private ushort clk_set; // 时钟配置
private byte scramble_ctrl; // 加解扰使能禁止
private byte rstr; // 复位/使能
// FIFO
private readonly Queue<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool RxfifoEnabled;
private bool TxfifoEnabled;
private int fifoTriggerLevel;
}
}

66
generated.repl Normal file
View File

@@ -0,0 +1,66 @@
// Simple platform with LEON_Control_Regs_SIMPLE
sysbus:
Endianess: Endianess.BigEndian
//cpu: CPU.Sparc @ sysbus
cpu: CPU.Sparc @ sysbus
cpuType: "leon3"
rom: Memory.MappedMemory @ sysbus 0x00000000
size: 0x20000
ddr: Memory.MappedMemory @ sysbus 0x40000000
size: 0x20000000
sdram: Memory.MappedMemory @ sysbus 0x60000000
size: 0x10000000
ahbInfo: Bus.GaislerAHBPlugAndPlayInfo @ sysbus <0xfffff000, +0xfff>
apbController: Bus.GaislerAPBController @ sysbus <0x800ff000, +0xfff>
// Use simplified LEON Control Regs
//leonRegs: Miscellaneous.LEON_Control_Regs_SIMPLE @ sysbus 0x80000000
// MIC at the address VxWorks expects (0x80000090)
// Note: GaislerMIC needs a range, so we use <base, +size> syntax
//mic: IRQControllers.GaislerMIC @ sysbus <0x80000090, +0x10>
// 0 -> cpu@0 | cpu@1 | cpu@2
// 0 -> cpu@0
mic: IRQControllers.GaislerMIC @ sysbus <0x80000200, +0x100>
0 -> cpu@0 | cpu@1 | cpu@2
//ioRegs: Miscellaneous.Simple_IO_Regs @ sysbus 0x800000A0
// TimeSliceIRQ -> mic@4
uart: UART.GaislerAPBUART @ sysbus <0x80000100, +0x100>
-> mic@2
timer: Timers.Gaisler_GPTimer @ sysbus 0x80000300
// 0 -> mic@8
0 -> mic@8
numberOfTimers: 2
separateInterrupts: false
frequency: 50000000
eth: Network.GaislerEth @ sysbus 0x80000B00
-> mic@12
gpio: GPIOPort.Gaisler_GPIO @ sysbus 0x80000800
numberOfConnections: 16
numberOfInterrupts: 1
rtc: Timers.Custom_RTC_R17V1 @sysbus 0x20800D80
lc3233IntCtrl:IRQControllers.LC3233_InterruptController @sysbus 0x80020000
4 -> mic@4
lc3233Timer:Timers.LC3233_TaskTimer @ sysbus 0x80000000
IRQ -> lc3233IntCtrl@4
//adc1: ADUADC1.ADU1 @ sysbus 0x21800800
//timer1: Timers1.TimeSlice_Timer_v2.cs @ sysbus 0x80000000
// txInterrupt -> mic@2

49
generated.resc Normal file
View File

@@ -0,0 +1,49 @@
# Renode Simulation Script - Auto Generated
# Generated: 2026-01-06 14:19:56
# Architecture: SPARC V8 / Leon3
using sysbus
# Load peripherals
include @LEON_Control_Regs_SIMPLE.cs
#include @Custom_RTC_R17V1_CORRECT_ADDR.cs
#include @Simple_IO_Regs.cs
include @LC3233_Timer_InterruptController.cs
#include @Custom_ADC_R17V1.cs
include @Custom_TLZA_Rwa.cs
include @Custom_TLZA_ADU.cs
include @Custom_TLZA_ADU1.cs
include @Custom_RTC_TLZA.cs
#include @timer_trigger.cs
include @UART_kx12A1.cs
include @UART_kx12A2.cs
include @UART_kx12A3.cs
include @UART_kx12A4.cs
include @UART_kx12A5.cs
include @UART_kx12A6.cs
# ===== 创建机器 =====
mach create "SPARC V8_Leon3"
# ===== 加载硬件平台描述(引用 .repl 文件)=====
machine LoadPlatformDescription @generated.repl
# ===== CPU 性能配置 =====
cpu PerformanceInMips 80
# ===== 固件加载 =====
# Load VxWorks
sysbus LoadBinary @C:/Users/PingCe/Desktop/1_simulation/KX12A_Z/vxworks_smu/default/vxWorks 0x40003000
sysbus WriteDoubleWord 0x80000240 0x90130
# ===== 调试配置 =====
machine StartGdbServer 3333 true
# ===== 仿真参数 =====
emulation SetGlobalQuantum "0.00001"
# ===== 日志配置 =====
logLevel 1
# ===== 启动命令 =====
# start

112
generated_yyq.repl Normal file
View File

@@ -0,0 +1,112 @@
// Simple platform with LEON_Control_Regs_SIMPLE
sysbus:
Endianess: Endianess.BigEndian
//cpu: CPU.Sparc @ sysbus
cpu: CPU.Sparc @ sysbus
cpuType: "leon3"
rom: Memory.MappedMemory @ sysbus 0x00000000
size: 0x20000
ddr: Memory.MappedMemory @ sysbus 0x40000000
size: 0x20000000
sdram: Memory.MappedMemory @ sysbus 0x60000000
size: 0x10000000
ahbInfo: Bus.GaislerAHBPlugAndPlayInfo @ sysbus <0xfffff000, +0xfff>
apbController: Bus.GaislerAPBController @ sysbus <0x800ff000, +0xfff>
// Use simplified LEON Control Regs
//leonRegs: Miscellaneous.LEON_Control_Regs_SIMPLE @ sysbus 0x80000000
// MIC at the address VxWorks expects (0x80000090)
// Note: GaislerMIC needs a range, so we use <base, +size> syntax
//mic: IRQControllers.GaislerMIC @ sysbus <0x80000090, +0x10>
// 0 -> cpu@0 | cpu@1 | cpu@2
// 0 -> cpu@0
mic: IRQControllers.GaislerMIC @ sysbus <0x80000200, +0x100>
0 -> cpu@0 | cpu@1 | cpu@2
//ioRegs: Miscellaneous.Simple_IO_Regs @ sysbus 0x800000A0
// TimeSliceIRQ -> mic@4
//uart: UART.GaislerAPBUART @ sysbus <0x80000100, +0x100>
// -> mic@2
//timer: Timers.Gaisler_GPTimer @ sysbus 0x80000300
// 0 -> mic@8
// 0 -> mic@8
// numberOfTimers: 2
// separateInterrupts: false
// frequency: 50000000
eth: Network.GaislerEth @ sysbus 0x80000B00
-> mic@12
gpio: GPIOPort.Gaisler_GPIO @ sysbus 0x80000800
numberOfConnections: 16
numberOfInterrupts: 1
rtc: Timers.Custom_RTC_R17V1 @sysbus 0x20800D80
lc3233IntCtrl:IRQControllers.LC3233_InterruptController @sysbus 0x80020000
4 -> mic@4
8 -> mic@8
13 -> mic@13
lc3233Timer:Timers.LC3233_TaskTimer @ sysbus 0x80000000
IRQ -> lc3233IntCtrl@4
//adc1: ADUADC1.ADU1 @ sysbus 0x21800800
//timer1: Timers1.TimeSlice_Timer_v2.cs @ sysbus 0x80000000
// txInterrupt -> mic@2
uart0: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800000 //光纤陀螺A
uart1: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800080 //光纤陀螺B
uart2: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800100 //陀螺C
uart3: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800180 //激光探测仪
uart4: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800200 //暂无
uart5: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800280 //暂无
uart6: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800300 //陀螺A
uart7: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800380 //陀螺B
uart8: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800400 //陀螺C
uart9: CustomPeripherals.UART_771_RUHW_2CFG3 @ sysbus 0x20800480 //星敏B,A3
uart10: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800500 //星敏C
uart11: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800580 //天气效应1-Jcydrl
uart12: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800600 //天气效应3-Jcydr2
uart13: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800680 //天气效应3-Jcydr3
uart14: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800700 //智能载荷1未使用
uart15: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800780 //智能载荷2未使用
uart16: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800800 //MHI预留1
uart17: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800880 //MHI预留2
uart18: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800900 //亚角秒星敏2
uart19: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800980 //亚角秒星敏1
uart20: CustomPeripherals.UART_771_RUHW_2CFG3 @ sysbus 0x20800A00 //亚角秒星敏接收/ 工程遥测主 gcyc[0] ,A3
uart21: CustomPeripherals.UART_771_RUHW_2CFG3 @ sysbus 0x20800A80 //星敏B接收2/工程遥测备 gcyc[1] ,A3
uart22: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800B00 //复接重构主
uart23: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800B80 //复接重构备
uart24: CustomPeripherals.UART_771_RUHW_2CFG4 @ sysbus 0x20800C00 //地测串口, A4
IRQ -> lc3233IntCtrl@8
uart25: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800C80 //GPS串口
uart26: CustomPeripherals.UART_771_RUHW_2CFG2 @ sysbus 0x20C00000 //高速通信, A2
uart27: CustomPeripherals.UART_771_RUHW_2CFG5 @ sysbus 0x20800E80 //USB-A遥控, A5
uart28: CustomPeripherals.UART_771_RUHW_2CFG5 @ sysbus 0x20800F00 //USB-B遥控, A5
uart29: CustomPeripherals.UART_771_RUHW_2CFG5 @ sysbus 0x20800F80 //高速通信机遥控, A5
uart30: CustomPeripherals.UART_771_RUHW_2CFG6 @ sysbus 0x20800E00 //遥测, A6
IRQ -> lc3233IntCtrl@13

49
generated_yyq.resc Normal file
View File

@@ -0,0 +1,49 @@
# Renode Simulation Script - Auto Generated
# Generated: 2026-01-06 14:19:56
# Architecture: SPARC V8 / Leon3
using sysbus
# Load peripherals
include @LEON_Control_Regs_SIMPLE.cs
#include @Custom_RTC_R17V1_CORRECT_ADDR.cs
#include @Simple_IO_Regs.cs
include @LC3233_Timer_InterruptController.cs
#include @Custom_ADC_R17V1.cs
include @Custom_TLZA_Rwa.cs
include @Custom_TLZA_ADU.cs
include @Custom_TLZA_ADU1.cs
include @Custom_RTC_TLZA.cs
#include @timer_trigger.cs
include @UART_kx12A1.cs
include @UART_kx12A2.cs
include @UART_kx12A3.cs
include @UART_kx12A4.cs
include @UART_kx12A5.cs
include @UART_kx12A6.cs
# ===== 创建机器 =====
mach create "SPARC V8_Leon3"
# ===== 加载硬件平台描述(引用 .repl 文件)=====
machine LoadPlatformDescription @generated.repl
# ===== CPU 性能配置 =====
cpu PerformanceInMips 80
# ===== 固件加载 =====
# Load VxWorks
sysbus LoadBinary @C:/Users/PingCe/Desktop/1_simulation/KX12A_Z/vxworks_smu/default/vxWorks 0x40003000
sysbus WriteDoubleWord 0x80000240 0x92130
# ===== 调试配置 =====
machine StartGdbServer 3333 true
# ===== 仿真参数 =====
emulation SetGlobalQuantum "0.00001"
# ===== 日志配置 =====
logLevel 1
# ===== 启动命令 =====
# start

BIN
代码.rar Normal file

Binary file not shown.