forked from liuwenbo/simulation_Peripheral
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d07b18df57 | |||
| 1bad9fd8ce | |||
| bb7a43b08f | |||
|
|
ea96c1e806 | ||
|
|
d9c0f0f07c | ||
| f5a2fa7725 | |||
| 6762a420a5 | |||
| 0c5dc92a2b | |||
| 9ee6d96eff | |||
| dda997df24 | |||
| 493561a8eb | |||
| dc5c201933 | |||
| 14e8fcb94b | |||
| 8d994d82cb | |||
| f2c4529212 | |||
| d301451757 | |||
| a74f508c32 | |||
| 482f44b7cc | |||
| be1fc1495f |
163
Custom_MS.cs
Normal file
163
Custom_MS.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// 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>
|
||||
/// 毫秒计数器
|
||||
/// </summary>
|
||||
public class Custom_MS : IDoubleWordPeripheral, IKnownSize
|
||||
{
|
||||
private readonly IMachine machine;
|
||||
|
||||
public Custom_MS(IMachine machine)
|
||||
{
|
||||
this.machine = machine;
|
||||
|
||||
// 初始化寄存器
|
||||
DefineRegisters();
|
||||
Reset();
|
||||
|
||||
this.Log(LogLevel.Info, "Custom_MS initialized");
|
||||
|
||||
// 启动后台计时任务
|
||||
// StartCountingTask();
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
ms_cnt = 0; // 毫秒计数
|
||||
rstr = 0x00; // 复位/使能寄存器
|
||||
startTime = machine.ElapsedVirtualTime; //记录启动时间
|
||||
|
||||
this.Log(LogLevel.Info, "Custom_MS reset, startTime={0}", startTime.TimeElapsed);
|
||||
}
|
||||
|
||||
|
||||
void get_msCnt()
|
||||
{
|
||||
TimeStamp currentTime = machine.ElapsedVirtualTime;
|
||||
TimeInterval timeDifference = currentTime.TimeElapsed - startTime.TimeElapsed;
|
||||
|
||||
double timeDiffMs = timeDifference.TotalMilliseconds;
|
||||
// ms_cnt = (ushort)(timeDiffMs % 1000);
|
||||
ms_cnt = (ushort)timeDiffMs;
|
||||
this.Log(LogLevel.Info, "Custom_MS currentTime={0}", currentTime.TimeElapsed);
|
||||
this.Log(LogLevel.Info, "Custom_MS timeDiffMs={0}", timeDiffMs);
|
||||
}
|
||||
|
||||
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.CNT_REG: // 毫秒延迟计时
|
||||
get_msCnt();
|
||||
value = (uint)ms_cnt;
|
||||
this.Log(LogLevel.Info, "Read CNT_REG: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.RSTR_REG: // 复位/使能,暂无读操作
|
||||
value = (uint)(rstr & 0xFF);
|
||||
this.Log(LogLevel.Info, "Read RSTR_REG: 0x{0}", value);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X}", offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public void WriteRegisters(long offset, uint value)
|
||||
{
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
|
||||
case (long)Registers.RSTR_REG: // 复位/使能,暂无读操作
|
||||
rstr = (byte)(value & 0xFF);
|
||||
this.Log(LogLevel.Info, "Write RSTR_REG: 0x{0:X2}", rstr);
|
||||
if ((rstr & 0XFF) == RSTR_RES)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X}", offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public long Size => 0x80; //uart地址长度总空间
|
||||
|
||||
|
||||
// ========================================
|
||||
// 寄存器定义
|
||||
// ========================================
|
||||
|
||||
private enum Registers : long
|
||||
{
|
||||
CNT_REG = 0x00, // 毫秒延迟计时
|
||||
RSTR_REG = 0x7C // 复位/使能 0x55复位清零;其他使能
|
||||
}
|
||||
|
||||
|
||||
|
||||
// RSTR 复位/使能寄存器
|
||||
private const byte RSTR_RES = 0x55; // 0x55复位清零,其他使能
|
||||
|
||||
|
||||
// ========================================
|
||||
// 私有字段
|
||||
// ========================================
|
||||
private TimeStamp startTime; // 记录累加器启动时间
|
||||
|
||||
// 寄存器
|
||||
private ushort ms_cnt; // FIFO状态寄存器
|
||||
private byte rstr; // 复位/使能
|
||||
|
||||
}
|
||||
}
|
||||
441
LC3233_Timer_InterruptController_NO4.cs
Normal file
441
LC3233_Timer_InterruptController_NO4.cs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
518
SJA1000_CAN.cs
Normal file
518
SJA1000_CAN.cs
Normal file
@@ -0,0 +1,518 @@
|
||||
//
|
||||
// SJA1000 CAN 控制器外设实现(简化版,支持发送/接收队列,可配置长度)
|
||||
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
|
||||
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
|
||||
// 发送缓冲区(地址 16-26)、RBSA 和 CDR。命令寄存器位2=RRB,位3=CDO。
|
||||
// 所有寄存器可随时读写,无复位模式限制。
|
||||
//
|
||||
// 队列长度可通过修改静态字段 MaxTxQueueSize 和 MaxRxQueueSize 调整。
|
||||
// 发送队列满时,CPU 发送请求被忽略,并设置 TBS=0(发送缓冲区忙);
|
||||
// 接收队列满时,外部注入的新帧被丢弃。
|
||||
//
|
||||
// 日志开关:EnableVerboseLog = false 可关闭所有日志输出。
|
||||
//
|
||||
|
||||
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
|
||||
{
|
||||
// 日志开关(设置为 false 可屏蔽所有日志)
|
||||
public static bool EnableVerboseLog = false;
|
||||
|
||||
// 队列长度配置(可修改)
|
||||
public static int MaxTxQueueSize = 64; // 发送队列最大帧数
|
||||
public static int MaxRxQueueSize = 64; // 接收队列最大帧数
|
||||
|
||||
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();
|
||||
|
||||
lastInterruptState = false; // 重置中断边沿状态
|
||||
UpdateInterrupts();
|
||||
|
||||
if (EnableVerboseLog)
|
||||
this.Log(LogLevel.Info, $"SJA1000 CAN controller reset (txQueueMax={MaxTxQueueSize}, rxQueueMax={MaxRxQueueSize})");
|
||||
}
|
||||
|
||||
// ================ 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;
|
||||
lock (lockObject)
|
||||
{
|
||||
switch ((Registers)offset)
|
||||
{
|
||||
case Registers.MOD:
|
||||
value = mod;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case Registers.CMR:
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read CMR (always 0)");
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
case Registers.SR:
|
||||
value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0
|
||||
if (EnableVerboseLog) 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 = 0;
|
||||
UpdateIrFromRbs();
|
||||
// 中断被软件清除,重置边沿检测状态,允许下次条件满足时再次触发中断
|
||||
lastInterruptState = false;
|
||||
UpdateInterrupts();
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value);
|
||||
break;
|
||||
|
||||
case Registers.IER:
|
||||
value = ier;
|
||||
if (EnableVerboseLog) 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) / 4;
|
||||
if (sr_rbs == 1)
|
||||
{
|
||||
value = rxBuffer[bufIndex];
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = txBuffer[bufIndex];
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex, value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset);
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void WriteByte(long offset, byte value)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
switch ((Registers)offset)
|
||||
{
|
||||
case Registers.MOD:
|
||||
mod = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case Registers.CMR:
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value);
|
||||
if ((value & CMR_TR) != 0)
|
||||
{
|
||||
// 发送请求
|
||||
if (sr_tbs == 1)
|
||||
{
|
||||
var frame = new byte[11];
|
||||
|
||||
if (txFrameQueue.Count < (MaxTxQueueSize - 1))
|
||||
{
|
||||
Array.Copy(txBuffer, frame, 11);
|
||||
txFrameQueue.Enqueue(frame);
|
||||
Array.Clear(txBuffer, 0, txBuffer.Length);
|
||||
sr_tbs = 1;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Frame enqueued for transmission, queue size: {0}", txFrameQueue.Count);
|
||||
}
|
||||
else if (txFrameQueue.Count == (MaxTxQueueSize - 1))
|
||||
{
|
||||
Array.Copy(txBuffer, frame, 11);
|
||||
txFrameQueue.Enqueue(frame);
|
||||
Array.Clear(txBuffer, 0, txBuffer.Length);
|
||||
sr_tbs = 0;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Frame enqueued, TX queue now full, TBS cleared");
|
||||
}
|
||||
else
|
||||
{
|
||||
sr_tbs = 0;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
|
||||
}
|
||||
}
|
||||
if ((value & CMR_RRB) != 0)
|
||||
{
|
||||
LoadNextRxFrame();
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Receive buffer released");
|
||||
}
|
||||
if ((value & CMR_CDO) != 0)
|
||||
{
|
||||
// 清除数据溢出(无操作,但保留接口)
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Clear data overflow (no effect)");
|
||||
}
|
||||
break;
|
||||
|
||||
case Registers.SR:
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Attempted write to read-only SR");
|
||||
break;
|
||||
|
||||
case Registers.IR:
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Attempted write to read-only IR");
|
||||
break;
|
||||
|
||||
case Registers.IER:
|
||||
ier = (byte)(value & 0x01);
|
||||
UpdateIrFromRbs();
|
||||
UpdateInterrupts();
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier);
|
||||
break;
|
||||
|
||||
case Registers.BTR0:
|
||||
btr0 = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.BTR1:
|
||||
btr1 = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.OCR:
|
||||
ocr = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.RXERR:
|
||||
rxerr = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.TXERR:
|
||||
txerr = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.RBSA:
|
||||
rbsa = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value);
|
||||
break;
|
||||
case Registers.CDR:
|
||||
cdr = value;
|
||||
if (EnableVerboseLog) 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) / 4;
|
||||
if (sr_tbs == 1)
|
||||
{
|
||||
txBuffer[bufIndex] = value;
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (EnableVerboseLog) 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 currentInterrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0);
|
||||
if (currentInterrupt && !lastInterruptState)
|
||||
{
|
||||
IRQ.Set(true);
|
||||
machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ =>
|
||||
{
|
||||
IRQ.Set(false);
|
||||
});
|
||||
if (EnableVerboseLog) this.Log(LogLevel.Info, "Interrupt pulse generated (RI)");
|
||||
}
|
||||
lastInterruptState = currentInterrupt;
|
||||
}
|
||||
|
||||
private readonly object lockObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
|
||||
/// 调用后清空发送队列,并恢复发送缓冲区状态(如果之前因队列满被锁定)。
|
||||
/// </summary>
|
||||
public string GetTxBufferDataString()
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (txFrameQueue.Count == 0)
|
||||
{
|
||||
if (EnableVerboseLog) Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
|
||||
if (sr_tbs == 0) sr_tbs = 1;
|
||||
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();
|
||||
sr_tbs = 1;
|
||||
if (EnableVerboseLog) Console.WriteLine("GetTxBufferDataString returning: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外部接口注入一帧接收数据(11字节的十六进制字符串,空格分隔)
|
||||
/// 可多次调用以注入多帧,帧将存入接收队列。
|
||||
/// 若接收队列已满,则新帧被丢弃。
|
||||
/// </summary>
|
||||
public void SendRxBufferDataString(string frameString)
|
||||
{
|
||||
lock (lockObject)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(frameString))
|
||||
{
|
||||
if (EnableVerboseLog) Console.WriteLine("SendRxBufferDataString: empty string, ignored");
|
||||
return;
|
||||
}
|
||||
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length != 11)
|
||||
{
|
||||
if (EnableVerboseLog) 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))
|
||||
{
|
||||
if (EnableVerboseLog) Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
|
||||
b = 0;
|
||||
}
|
||||
frame[i] = b;
|
||||
}
|
||||
|
||||
if (rxFrameQueue.Count >= MaxRxQueueSize)
|
||||
{
|
||||
if (EnableVerboseLog) Console.WriteLine($"SendRxBufferDataString: RX queue full (max={MaxRxQueueSize}), frame dropped");
|
||||
return;
|
||||
}
|
||||
|
||||
rxFrameQueue.Enqueue(frame);
|
||||
if (EnableVerboseLog) Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
|
||||
|
||||
if (sr_rbs == 0)
|
||||
{
|
||||
LoadNextRxFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadNextRxFrame()
|
||||
{
|
||||
if (rxFrameQueue.Count > 0)
|
||||
{
|
||||
var frame = rxFrameQueue.Dequeue();
|
||||
Array.Copy(frame, rxBuffer, 11);
|
||||
sr_rbs = 1;
|
||||
UpdateIrFromRbs();
|
||||
UpdateInterrupts();
|
||||
if (EnableVerboseLog) Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
sr_rbs = 0;
|
||||
UpdateIrFromRbs();
|
||||
UpdateInterrupts();
|
||||
if (EnableVerboseLog) Console.WriteLine("RX queue empty, buffer cleared");
|
||||
}
|
||||
}
|
||||
|
||||
// ================ 属性 ================
|
||||
|
||||
public long Size => 0x80;
|
||||
|
||||
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,
|
||||
TXERR = 0x3C,
|
||||
TX_FRAME_INFO = 0x40,
|
||||
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,
|
||||
RBSA = 0x78,
|
||||
CDR = 0x7C,
|
||||
}
|
||||
|
||||
// ================ 常量位定义 ================
|
||||
|
||||
private const byte CMR_TR = 0x01;
|
||||
private const byte CMR_RRB = 0x04;
|
||||
private const byte CMR_CDO = 0x08;
|
||||
|
||||
private const byte SR_BS = 0x80;
|
||||
private const byte SR_TBS = 0x04;
|
||||
private const byte SR_RBS = 0x01;
|
||||
|
||||
private const byte IR_RI = 0x01;
|
||||
private const byte IER_RIE = 0x01;
|
||||
|
||||
// ================ 私有字段 ================
|
||||
|
||||
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;
|
||||
private byte sr_rbs;
|
||||
private byte ir;
|
||||
|
||||
private bool lastInterruptState; // 用于中断边沿检测
|
||||
|
||||
private readonly byte[] txBuffer;
|
||||
private readonly byte[] rxBuffer;
|
||||
|
||||
private readonly Queue<byte[]> txFrameQueue;
|
||||
private readonly Queue<byte[]> rxFrameQueue;
|
||||
}
|
||||
}
|
||||
677
UART16550.cs
Normal file
677
UART16550.cs
Normal 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
615
UART_kx12A1.cs
Normal 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发送FIFO,RBR接收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
402
UART_kx12A2.cs
Normal 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
542
UART_kx12A3.cs
Normal 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发送FIFO,RBR接收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;
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,8 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
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关联,暂定
|
||||
usr = (byte)(usr & (~(USR_RBFI | USR_TCMP))); //usr寄存器,取消中断,与hw_uart_isr关联,暂定
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case (long)Registers.MCR: //MCR调制控制寄存器
|
||||
@@ -224,8 +225,6 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
if (interrupt)
|
||||
{
|
||||
this.Log(LogLevel.Info, "Interrupt asserted");
|
||||
}
|
||||
|
||||
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
|
||||
_ => {
|
||||
IRQ.Set(false);
|
||||
@@ -234,6 +233,9 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void UpdateModemControl()
|
||||
{
|
||||
if((mcr & MCR_REN) == 0)
|
||||
@@ -397,7 +399,6 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
}
|
||||
}
|
||||
|
||||
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms,暂不实现
|
||||
usr = (byte)(usr | USR_RBFI); //usr寄存器,置接收中断
|
||||
UpdateInterrupts();
|
||||
|
||||
@@ -442,10 +443,9 @@ namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
this.Log(LogLevel.Warning, "RX FIFO Already Full");
|
||||
}
|
||||
|
||||
// this.Wait(TimeInterval.FromMilliseconds(10)); 无法实现等待10ms,暂不实现
|
||||
usr = (byte)(usr | USR_RBFI); //usr寄存器,置接收中断
|
||||
machine.ScheduleAction(TimeInterval.FromMicroseconds(10000),
|
||||
_ => {
|
||||
usr = (byte)(usr | USR_RBFI); //usr寄存器,置接收中断
|
||||
UpdateInterrupts();
|
||||
});
|
||||
|
||||
|
||||
582
UART_kx12A4_128.cs
Normal file
582
UART_kx12A4_128.cs
Normal file
@@ -0,0 +1,582 @@
|
||||
//
|
||||
// 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 string GetTXFIFODataString()
|
||||
{
|
||||
string data = "0x";
|
||||
byte tmp;
|
||||
var bytesToTransmit = Math.Min(txFifo.Count, TX_FIFO_BURST_SIZE);
|
||||
var fifoBecameEmpty = false;
|
||||
|
||||
if(txFifo.Count == 0)
|
||||
{
|
||||
this.Log(LogLevel.Info, "TXFIFO Null");
|
||||
return "0x00";
|
||||
}
|
||||
|
||||
while (bytesToTransmit > 0)
|
||||
{
|
||||
tmp = txFifo.Dequeue();
|
||||
data += tmp.ToString("X2"); // 转换16进制字符
|
||||
bytesToTransmit--;
|
||||
}
|
||||
|
||||
fifoBecameEmpty = (txFifo.Count == 0);
|
||||
this.Log(LogLevel.Info, "Transmitted: 0x{0}, Remaining={1}", data, txFifo.Count);
|
||||
|
||||
|
||||
// 更新状态
|
||||
if (fifoBecameEmpty)
|
||||
{
|
||||
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寄存器,置接收中断
|
||||
UpdateInterrupts();
|
||||
// machine.ScheduleAction(TimeInterval.FromMicroseconds(10000),
|
||||
// _ => {
|
||||
// UpdateInterrupts();
|
||||
// });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public long Size => 0x28; //uart地址长度总空间
|
||||
|
||||
public GPIO IRQ { get; }
|
||||
|
||||
// ========================================
|
||||
// 寄存器定义
|
||||
// ========================================
|
||||
|
||||
private enum Registers : long
|
||||
{
|
||||
TBR_RBR = 0x00, // TBR发送FIFO,RBR接收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 const int TX_FIFO_BURST_SIZE = 128; //输出的128大小
|
||||
|
||||
// ========================================
|
||||
// 私有字段
|
||||
// ========================================
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
626
UART_kx12A4_event.cs
Normal file
626
UART_kx12A4_event.cs
Normal file
@@ -0,0 +1,626 @@
|
||||
// 配合地测中断更改版本
|
||||
//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.Time;
|
||||
|
||||
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
{
|
||||
/// <summary>
|
||||
/// UART_771_RUHW_2CFG 控制器
|
||||
/// 接收缓存1024B,发送缓存2048B,时钟24MHz
|
||||
/// 事件驱动版本 - 使用machine.ScheduleAction精确模拟波特率
|
||||
/// </summary>
|
||||
public class UART_771_RUHW_2CFG4 : IDoubleWordPeripheral, IKnownSize, IUART
|
||||
{
|
||||
private readonly IMachine machine;
|
||||
private readonly object txFifoLock = new object();
|
||||
private readonly object rxFifoLock = new object();
|
||||
|
||||
public UART_771_RUHW_2CFG4(IMachine machine)
|
||||
{
|
||||
this.clockFrequency = 24000000;
|
||||
this.machine = machine;
|
||||
|
||||
// 创建 FIFO
|
||||
rxFifo = new Queue<byte>();
|
||||
txFifo = new Queue<byte>();
|
||||
|
||||
// 创建中断线
|
||||
IRQ = new GPIO();
|
||||
|
||||
// 初始化寄存器
|
||||
DefineRegisters();
|
||||
Reset();
|
||||
|
||||
this.Log(LogLevel.Info, "771 UART initialized (event-driven), clock: {0} Hz", clockFrequency);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
txFifo.Clear();
|
||||
}
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
rxFifo.Clear();
|
||||
}
|
||||
|
||||
ucr = 0x00;
|
||||
usr = USR_TFE; // 初始FIFO空
|
||||
mcr = 0x00;
|
||||
brsr = 0;
|
||||
fsta = (byte)(FSTA_TEMP | FSTA_REMP);
|
||||
tbr = 0;
|
||||
rbr = 0;
|
||||
rstr = 0x00;
|
||||
|
||||
RxfifoEnabled = true;
|
||||
TxfifoEnabled = true;
|
||||
fifoTriggerLevel = 1;
|
||||
|
||||
transmissionScheduled = false;
|
||||
transmissionGeneration++;
|
||||
|
||||
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:
|
||||
value = ReadRBR();
|
||||
this.Log(LogLevel.Info, "Read RBR: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.UCR_USR:
|
||||
value = (byte)(usr & 0xFF);
|
||||
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
|
||||
// 读取USR会清除中断标志
|
||||
usr = (byte)(usr & (~(USR_RBFI | USR_TCMP)));
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case (long)Registers.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.Debug, "Read BRSR: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.FSTA:
|
||||
value = (byte)(fsta & 0xFF);
|
||||
this.Log(LogLevel.Debug, "Read FSTA: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.TBR_FreeBytes:
|
||||
lock(txFifoLock)
|
||||
{
|
||||
tbr = (ushort)txFifo.Count;
|
||||
}
|
||||
value = (uint)tbr;
|
||||
this.Log(LogLevel.Debug, "Read TBR_FreeBytes: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.RBR_FreeBytes:
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
rbr = (ushort)rxFifo.Count;
|
||||
}
|
||||
value = (uint)rbr;
|
||||
this.Log(LogLevel.Debug, "Read RBR_FreeBytes: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.RSTR:
|
||||
value = (uint)rstr;
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X}", offset);
|
||||
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: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.UCR_USR:
|
||||
ucr = (byte)(value & 0xFF);
|
||||
this.Log(LogLevel.Info, "Write UCR: 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}, BaudRate: {1}", brsr, currentBaudRate);
|
||||
}
|
||||
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 interrupt = false;
|
||||
|
||||
if ((mcr & MCR_BEN) != 0)
|
||||
{
|
||||
if ((usr & USR_TCMP) != 0) // 发送完成中断
|
||||
interrupt = true;
|
||||
else if ((usr & USR_RBFI) != 0) // 接收中断
|
||||
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, "UART interrupt triggered: USR=0x{0:X2}", usr);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateModemControl()
|
||||
{
|
||||
if((mcr & MCR_REN) == 0)
|
||||
{
|
||||
RxfifoEnabled = false;
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Info, "Modem control: INT_EN={0}, RX_EN={1}",
|
||||
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// CPU写TBR寄存器(发送数据)- 事件驱动
|
||||
// ========================================
|
||||
public void WriteTBR(byte value)
|
||||
{
|
||||
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
|
||||
(value >= 32 && value < 127) ? (char)value : '.');
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
if (TxfifoEnabled)
|
||||
{
|
||||
if (txFifo.Count < TX_FIFO_SIZE)
|
||||
{
|
||||
bool wasEmpty = (txFifo.Count == 0);
|
||||
|
||||
txFifo.Enqueue(value);
|
||||
|
||||
// 更新FIFO状态
|
||||
fsta = (byte)(fsta & (~FSTA_TEMP)); // FIFO非空
|
||||
usr = (byte)(usr & (~USR_TFE)); // 清除FIFO空标志
|
||||
|
||||
// FIFO从空变为非空,清除发送完成中断
|
||||
if (wasEmpty)
|
||||
{
|
||||
usr = (byte)(usr & (~USR_TCMP));
|
||||
this.Log(LogLevel.Info, "FIFO: Empty->NonEmpty, clearing TCMP");
|
||||
|
||||
// 启动传输调度(事件驱动)
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
|
||||
if (txFifo.Count == TX_FIFO_SIZE)
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_TFUL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_TFUL);
|
||||
usr = (byte)(usr | USR_OE); // 溢出错误
|
||||
this.Log(LogLevel.Warning, "TX FIFO overflow");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
txFifo.Clear();
|
||||
txFifo.Enqueue(value);
|
||||
fsta = (byte)(fsta & (~FSTA_TEMP));
|
||||
usr = (byte)(usr & (~USR_TFE));
|
||||
usr = (byte)(usr & (~USR_TCMP));
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 核心:按波特率调度发送(事件驱动)
|
||||
// ========================================
|
||||
private void ScheduleNextByteTransmit()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
// 防止重复调度
|
||||
if (transmissionScheduled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count == 0)
|
||||
{
|
||||
// FIFO空,设置发送完成标志
|
||||
fsta = (byte)((fsta & 0xF0) | FSTA_TEMP);
|
||||
usr = (byte)(usr | USR_TFE);
|
||||
usr = (byte)(usr | USR_TCMP); // 触发发送完成中断
|
||||
|
||||
this.Log(LogLevel.Info, "TX FIFO empty, setting TCMP interrupt");
|
||||
|
||||
UpdateInterrupts();
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算传输时间(使用官方IUART扩展方法的逻辑)
|
||||
int bitsPerByte = 1; // 起始位
|
||||
bitsPerByte += 8; // 数据位
|
||||
|
||||
// 校验位判断
|
||||
byte parityBits = (byte)((ucr & UCR_PB) >> 1); // 提取bits 1-3
|
||||
if (parityBits != 0x07)
|
||||
{
|
||||
bitsPerByte += 1; // ?有校验位(奇校验或偶校验)
|
||||
|
||||
// 对于你的配置:
|
||||
// ucr应该被设置为 0x02 (二进制: 00000010)
|
||||
// parityBits = (0x02 & 0x0E) >> 1 = 0x02 >> 1 = 0x01 (奇校验)
|
||||
}
|
||||
|
||||
// 根据配置添加停止位
|
||||
if ((ucr & UCR_STB) != 0)
|
||||
{
|
||||
bitsPerByte += 2; // 2停止位
|
||||
}
|
||||
else
|
||||
{
|
||||
bitsPerByte += 1; // 1停止位
|
||||
}
|
||||
|
||||
// 计算传输时间(秒)
|
||||
double secondsPerByte = (double)bitsPerByte / currentBaudRate;
|
||||
long microsecondsPerByte = (long)(secondsPerByte * 1000000);
|
||||
|
||||
this.Log(LogLevel.Debug,
|
||||
"Scheduling byte transmission: {0} bits @ {1} bps = {2}μs",
|
||||
bitsPerByte, currentBaudRate, microsecondsPerByte);
|
||||
|
||||
transmissionScheduled = true;
|
||||
var currentGeneration = transmissionGeneration;
|
||||
|
||||
// 使用Renode虚拟时间调度
|
||||
machine.ScheduleAction(
|
||||
TimeInterval.FromMicroseconds(microsecondsPerByte),
|
||||
_ => TransmitOneByte(currentGeneration)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransmitOneByte(ulong generation)
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
transmissionScheduled = false;
|
||||
|
||||
// 检查是否被Reset取消
|
||||
if (generation != transmissionGeneration)
|
||||
{
|
||||
this.Log(LogLevel.Debug, "Transmission cancelled (reset)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count > 0)
|
||||
{
|
||||
byte data = txFifo.Dequeue();
|
||||
|
||||
// 触发CharReceived事件(外部Backend可订阅 网络中间层改为订阅这个事件的方式)
|
||||
TransmitCharacter(data);
|
||||
|
||||
this.Log(LogLevel.Info,
|
||||
"Transmitted: 0x{0:X2} ('{1}'), Remaining: {2}",
|
||||
data,
|
||||
(data >= 32 && data < 127) ? (char)data : '.',
|
||||
txFifo.Count);
|
||||
|
||||
// 继续调度下一个字节
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实现IUART接口的TransmitCharacter(触发事件)
|
||||
protected void TransmitCharacter(byte character)
|
||||
{
|
||||
CharReceived?.Invoke(character);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 可选:提供批量读取接口(给网络层用)
|
||||
// ========================================
|
||||
public string GetTXFIFODataString()
|
||||
{
|
||||
// 这个方法现在只是读取接口,不负责触发中断
|
||||
// 中断逻辑完全由ScheduleNextByteTransmit处理
|
||||
|
||||
string data = "110118"; // 协议头
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
if (txFifo.Count == 0)
|
||||
{
|
||||
return "0x001800"; // 空数据标识
|
||||
}
|
||||
|
||||
// 批量读取(可选,用于网络传输优化)
|
||||
int bytesToRead = Math.Min(txFifo.Count, 128);
|
||||
|
||||
for (int i = 0; i < bytesToRead; i++)
|
||||
{
|
||||
if (txFifo.Count > 0)
|
||||
{
|
||||
byte tmp = txFifo.Dequeue();
|
||||
data += tmp.ToString("X2");
|
||||
}
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Debug, "Batch read: {0} bytes, Remaining: {1}",
|
||||
bytesToRead, txFifo.Count);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// RX方向:接收数据
|
||||
// ========================================
|
||||
public byte ReadRBR()
|
||||
{
|
||||
byte value = 0;
|
||||
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
if (rxFifo.Count > 0)
|
||||
{
|
||||
value = rxFifo.Dequeue();
|
||||
this.Log(LogLevel.Info, "Read RBR: 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);
|
||||
usr = (byte)(usr & (~USR_OE));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
return value;
|
||||
}
|
||||
|
||||
// 实现IUART接口的WriteChar(外部写入)
|
||||
public void WriteChar(byte value)
|
||||
{
|
||||
WriteRXFIFOData(value);
|
||||
}
|
||||
|
||||
public void WriteRXFIFOData(byte value)
|
||||
{
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
if(RxfifoEnabled)
|
||||
{
|
||||
if(rxFifo.Count < RX_FIFO_SIZE)
|
||||
{
|
||||
rxFifo.Enqueue(value);
|
||||
fsta = (byte)(fsta & (~FSTA_REMP));
|
||||
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
|
||||
(value >= 32 && value < 127) ? (char)value : '.');
|
||||
}
|
||||
else
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_RFUL);
|
||||
this.Log(LogLevel.Warning, "RX FIFO full");
|
||||
}
|
||||
}
|
||||
|
||||
usr = (byte)(usr | USR_RBFI);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// IUART接口实现
|
||||
// ========================================
|
||||
public uint BaudRate => currentBaudRate;
|
||||
|
||||
public Bits StopBits => ((ucr & UCR_STB) != 0) ? Bits.Two : Bits.One;
|
||||
|
||||
public Parity ParityBit
|
||||
{
|
||||
get
|
||||
{
|
||||
// 提取UCR的bits 1-3
|
||||
byte parityBits = (byte)((ucr & UCR_PB) >> 1);
|
||||
|
||||
if (parityBits == 0x07) // 111b = 0x07 = 无校验
|
||||
return Parity.None;
|
||||
|
||||
if (parityBits == 0x01) // 001b = 0x01 = 奇校验
|
||||
return Parity.Odd;
|
||||
|
||||
if (parityBits == 0x00) // 000b = 0x00 = 偶校验
|
||||
return Parity.Even;
|
||||
|
||||
// 其他值默认为无校验
|
||||
return Parity.None;
|
||||
}
|
||||
}
|
||||
|
||||
[field: Transient]
|
||||
public event Action<byte> CharReceived; // 事件:外部可订阅
|
||||
|
||||
public long Size => 0x28;
|
||||
public GPIO IRQ { get; }
|
||||
|
||||
// ========================================
|
||||
// 寄存器定义
|
||||
// ========================================
|
||||
private enum Registers : long
|
||||
{
|
||||
TBR_RBR = 0x00,
|
||||
UCR_USR = 0x04,
|
||||
MCR = 0x08,
|
||||
BRSR = 0x0C,
|
||||
FSTA = 0x10,
|
||||
TBR_FreeBytes = 0x14,
|
||||
RBR_FreeBytes = 0x18,
|
||||
RSTR = 0x20,
|
||||
EXTI = 0x24
|
||||
}
|
||||
|
||||
// 位定义
|
||||
private const byte UCR_STB = 0x01;
|
||||
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;
|
||||
private const byte USR_RBFI = 0x80;
|
||||
private const byte MCR_BEN = 0x04;
|
||||
private const byte MCR_REN = 0x20;
|
||||
private const byte FSTA_TEMP = 0x01;
|
||||
private const byte FSTA_TFUL = 0x04;
|
||||
private const byte FSTA_REMP = 0x10;
|
||||
private const byte FSTA_RFUL = 0x40;
|
||||
private const byte RSTR_RES = 0x55;
|
||||
private const int RX_FIFO_SIZE = 1024;
|
||||
private const int TX_FIFO_SIZE = 2048;
|
||||
|
||||
// 私有字段
|
||||
private readonly uint clockFrequency;
|
||||
private uint currentBaudRate = 115200;
|
||||
private byte ucr;
|
||||
private byte usr;
|
||||
private byte mcr;
|
||||
private ushort brsr;
|
||||
private byte fsta;
|
||||
private ushort tbr;
|
||||
private ushort rbr;
|
||||
private byte rstr;
|
||||
private readonly Queue<byte> rxFifo;
|
||||
private readonly Queue<byte> txFifo;
|
||||
private bool RxfifoEnabled;
|
||||
private bool TxfifoEnabled;
|
||||
private int fifoTriggerLevel;
|
||||
private bool transmissionScheduled;
|
||||
private ulong transmissionGeneration;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// // 网络层修改示例(伪代码)
|
||||
// class UDPNetworkLayer
|
||||
// {
|
||||
// private List<byte> buffer = new List<byte>();
|
||||
|
||||
// public void Initialize(UART_771_RUHW_2CFG4 uart)
|
||||
// {
|
||||
// // 订阅事件,替代25Hz定时器
|
||||
// uart.CharReceived += OnUartDataReceived;
|
||||
// }
|
||||
|
||||
// private void OnUartDataReceived(byte data)
|
||||
// {
|
||||
// buffer.Add(data);
|
||||
|
||||
// // 批量发送(可选的优化)
|
||||
// if (buffer.Count >= 128 || bufferTimeout)
|
||||
// {
|
||||
// SendToUDP(buffer.ToArray());
|
||||
// buffer.Clear();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
642
UART_kx12A4_event_1.cs
Normal file
642
UART_kx12A4_event_1.cs
Normal file
@@ -0,0 +1,642 @@
|
||||
// 配合地测中断更改版本
|
||||
//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.Time;
|
||||
using Antmicro.Migrant;
|
||||
|
||||
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
{
|
||||
/// <summary>
|
||||
/// UART_771_RUHW_2CFG 控制器
|
||||
/// 接收缓存1024B,发送缓存2048B,时钟24MHz
|
||||
/// 事件驱动版本 - 使用machine.ScheduleAction精确模拟波特率
|
||||
/// </summary>
|
||||
public class UART_771_RUHW_2CFG4 : IDoubleWordPeripheral, IKnownSize, IUART
|
||||
{
|
||||
private readonly IMachine machine;
|
||||
private readonly object txFifoLock = new object();
|
||||
private readonly object rxFifoLock = new object();
|
||||
|
||||
public UART_771_RUHW_2CFG4(IMachine machine)
|
||||
{
|
||||
this.clockFrequency = 24000000;
|
||||
this.machine = machine;
|
||||
transmissionGeneration = 0;
|
||||
|
||||
// 创建 FIFO
|
||||
rxFifo = new Queue<byte>();
|
||||
txFifo = new Queue<byte>();
|
||||
|
||||
// 创建中断线
|
||||
IRQ = new GPIO();
|
||||
|
||||
// 初始化寄存器
|
||||
DefineRegisters();
|
||||
Reset();
|
||||
|
||||
this.Log(LogLevel.Info, "771 UART initialized (event-driven), clock: {0} Hz", clockFrequency);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
txFifo.Clear();
|
||||
}
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
rxFifo.Clear();
|
||||
}
|
||||
|
||||
ucr = 0x00;
|
||||
usr = USR_TFE; // 初始FIFO空
|
||||
mcr = 0x00;
|
||||
brsr = 0;
|
||||
fsta = (byte)(FSTA_TEMP | FSTA_REMP);
|
||||
tbr = 0;
|
||||
rbr = 0;
|
||||
rstr = 0x00;
|
||||
currentBaudRate = 115200;
|
||||
|
||||
RxfifoEnabled = true;
|
||||
TxfifoEnabled = true;
|
||||
fifoTriggerLevel = 1;
|
||||
|
||||
transmissionScheduled = false;
|
||||
transmissionGeneration++;
|
||||
|
||||
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:
|
||||
value = ReadRBR();
|
||||
this.Log(LogLevel.Info, "Read RBR: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.UCR_USR:
|
||||
value = (byte)(usr & 0xFF);
|
||||
this.Log(LogLevel.Info, "Read USR: 0x{0:X2}", value);
|
||||
// 读取USR会清除中断标志
|
||||
usr = (byte)(usr & (~(USR_RBFI | USR_TCMP)));
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
case (long)Registers.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.Debug, "Read BRSR: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.FSTA:
|
||||
value = (byte)(fsta & 0xFF);
|
||||
this.Log(LogLevel.Debug, "Read FSTA: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.TBR_FreeBytes:
|
||||
lock(txFifoLock)
|
||||
{
|
||||
tbr = (ushort)txFifo.Count;
|
||||
}
|
||||
value = (uint)tbr;
|
||||
this.Log(LogLevel.Debug, "Read TBR_FreeBytes: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.RBR_FreeBytes:
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
rbr = (ushort)rxFifo.Count;
|
||||
}
|
||||
value = (uint)rbr;
|
||||
this.Log(LogLevel.Debug, "Read RBR_FreeBytes: {0}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.RSTR:
|
||||
value = (uint)rstr;
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Log(LogLevel.Warning, "Read to unknown offset: 0x{0:X}", offset);
|
||||
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: 0x{0:X2}", value);
|
||||
break;
|
||||
|
||||
case (long)Registers.UCR_USR:
|
||||
ucr = (byte)(value & 0xFF);
|
||||
this.Log(LogLevel.Info, "Write UCR: 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}, BaudRate: {1}", brsr, currentBaudRate);
|
||||
// 计算传输速率
|
||||
ComputeTransRate();
|
||||
}
|
||||
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 interrupt = false;
|
||||
|
||||
if ((mcr & MCR_BEN) != 0)
|
||||
{
|
||||
if ((usr & USR_TCMP) != 0) // 发送完成中断
|
||||
interrupt = true;
|
||||
else if ((usr & USR_RBFI) != 0) // 接收中断
|
||||
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, "UART interrupt triggered: USR=0x{0:X2}", usr);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateModemControl()
|
||||
{
|
||||
if((mcr & MCR_REN) == 0)
|
||||
{
|
||||
RxfifoEnabled = false;
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Info, "Modem control: INT_EN={0}, RX_EN={1}",
|
||||
(mcr & MCR_BEN) != 0, (mcr & MCR_REN) != 0);
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 按波特率计算传输速率
|
||||
// ========================================
|
||||
public void ComputeTransRate()
|
||||
{
|
||||
// 计算传输时间(使用官方IUART扩展方法的逻辑)
|
||||
int bitsPerByte = 1; // 起始位
|
||||
bitsPerByte += 8; // 数据位
|
||||
|
||||
// 校验位判断
|
||||
byte parityBits = (byte)((ucr & UCR_PB) >> 1); // 提取bits 1-3
|
||||
if (parityBits != 0x07)
|
||||
{
|
||||
bitsPerByte += 1; // ?有校验位(奇校验或偶校验)
|
||||
|
||||
// 对于你的配置:
|
||||
// ucr应该被设置为 0x02 (二进制: 00000010)
|
||||
// parityBits = (0x02 & 0x0E) >> 1 = 0x02 >> 1 = 0x01 (奇校验)
|
||||
}
|
||||
|
||||
// 根据配置添加停止位
|
||||
if ((ucr & UCR_STB) != 0)
|
||||
{
|
||||
bitsPerByte += 2; // 2停止位
|
||||
}
|
||||
else
|
||||
{
|
||||
bitsPerByte += 1; // 1停止位
|
||||
}
|
||||
|
||||
// 计算传输时间(秒)
|
||||
if(currentBaudRate == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
double secondsPerByte = (double)bitsPerByte / currentBaudRate;
|
||||
microsecondsPerByte = (ulong)(secondsPerByte * 1000000);
|
||||
|
||||
this.Log(LogLevel.Debug,
|
||||
"Scheduling byte transmission: {0} bits @ {1} bps = {2}μs",
|
||||
bitsPerByte, currentBaudRate, microsecondsPerByte);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// CPU写TBR寄存器(发送数据)- 事件驱动
|
||||
// ========================================
|
||||
public void WriteTBR(byte value)
|
||||
{
|
||||
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2} ('{1}')", value,
|
||||
(value >= 32 && value < 127) ? (char)value : '.');
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
if (TxfifoEnabled)
|
||||
{
|
||||
if (txFifo.Count < TX_FIFO_SIZE)
|
||||
{
|
||||
bool wasEmpty = (txFifo.Count == 0);
|
||||
|
||||
txFifo.Enqueue(value);
|
||||
|
||||
// 更新FIFO状态
|
||||
fsta = (byte)(fsta & (~FSTA_TEMP)); // FIFO非空
|
||||
usr = (byte)(usr & (~USR_TFE)); // 清除FIFO空标志
|
||||
|
||||
// FIFO从空变为非空,清除发送完成中断
|
||||
if (wasEmpty)
|
||||
{
|
||||
usr = (byte)(usr & (~USR_TCMP));
|
||||
this.Log(LogLevel.Info, "FIFO: Empty->NonEmpty, clearing TCMP");
|
||||
|
||||
// 启动传输调度(事件驱动)
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
|
||||
if (txFifo.Count == TX_FIFO_SIZE)
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_TFUL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_TFUL);
|
||||
usr = (byte)(usr | USR_OE); // 溢出错误
|
||||
this.Log(LogLevel.Warning, "TX FIFO overflow");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
txFifo.Clear();
|
||||
txFifo.Enqueue(value);
|
||||
fsta = (byte)(fsta & (~FSTA_TEMP));
|
||||
usr = (byte)(usr & (~USR_TFE));
|
||||
usr = (byte)(usr & (~USR_TCMP));
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 核心:按波特率调度发送(事件驱动)
|
||||
// ========================================
|
||||
private void ScheduleNextByteTransmit()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
// 防止重复调度
|
||||
if (transmissionScheduled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count == 0)
|
||||
{
|
||||
// FIFO空,设置发送完成标志
|
||||
fsta = (byte)((fsta & 0xF0) | FSTA_TEMP);
|
||||
usr = (byte)(usr | USR_TFE);
|
||||
usr = (byte)(usr | USR_TCMP); // 触发发送完成中断
|
||||
|
||||
this.Log(LogLevel.Info, "TX FIFO empty, setting TCMP interrupt");
|
||||
|
||||
UpdateInterrupts();
|
||||
return;
|
||||
}
|
||||
|
||||
transmissionScheduled = true;
|
||||
var currentGeneration = transmissionGeneration;
|
||||
|
||||
// 使用Renode虚拟时间调度
|
||||
machine.ScheduleAction(
|
||||
TimeInterval.FromMicroseconds(microsecondsPerByte),
|
||||
_ => TransmitOneByte(currentGeneration)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransmitOneByte(ulong generation)
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
transmissionScheduled = false;
|
||||
|
||||
// 检查是否被Reset取消
|
||||
if (generation != transmissionGeneration)
|
||||
{
|
||||
this.Log(LogLevel.Debug, "Transmission cancelled (reset)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count > 0)
|
||||
{
|
||||
byte data = txFifo.Dequeue();
|
||||
|
||||
// 触发CharReceived事件(外部Backend可订阅 网络中间层改为订阅这个事件的方式)
|
||||
TransmitCharacter(data);
|
||||
|
||||
this.Log(LogLevel.Info,
|
||||
"Transmitted: 0x{0:X2} ('{1}'), Remaining: {2}",
|
||||
data,
|
||||
(data >= 32 && data < 127) ? (char)data : '.',
|
||||
txFifo.Count);
|
||||
|
||||
// 继续调度下一个字节
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实现IUART接口的TransmitCharacter(触发事件)
|
||||
protected void TransmitCharacter(byte character)
|
||||
{
|
||||
CharReceived?.Invoke(character);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 可选:提供批量读取接口(给网络层用)
|
||||
// ========================================
|
||||
public string GetTXFIFODataString()
|
||||
{
|
||||
// 这个方法现在只是读取接口,不负责触发中断
|
||||
// 中断逻辑完全由ScheduleNextByteTransmit处理
|
||||
|
||||
string data = "110118"; // 协议头
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
if (txFifo.Count == 0)
|
||||
{
|
||||
return "0x001800"; // 空数据标识
|
||||
}
|
||||
|
||||
// 批量读取(可选,用于网络传输优化)
|
||||
int bytesToRead = Math.Min(txFifo.Count, 128);
|
||||
|
||||
for (int i = 0; i < bytesToRead; i++)
|
||||
{
|
||||
if (txFifo.Count > 0)
|
||||
{
|
||||
byte tmp = txFifo.Dequeue();
|
||||
data += tmp.ToString("X2");
|
||||
}
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Debug, "Batch read: {0} bytes, Remaining: {1}",
|
||||
bytesToRead, txFifo.Count);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// RX方向:接收数据
|
||||
// ========================================
|
||||
public byte ReadRBR()
|
||||
{
|
||||
byte value = 0;
|
||||
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
if (rxFifo.Count > 0)
|
||||
{
|
||||
value = rxFifo.Dequeue();
|
||||
this.Log(LogLevel.Info, "Read RBR: 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);
|
||||
usr = (byte)(usr & (~USR_OE));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateInterrupts();
|
||||
return value;
|
||||
}
|
||||
|
||||
// 实现IUART接口的WriteChar(外部写入)
|
||||
public void WriteChar(byte value)
|
||||
{
|
||||
WriteRXFIFOData(value);
|
||||
}
|
||||
|
||||
public void WriteRXFIFOData(byte value)
|
||||
{
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
if(RxfifoEnabled)
|
||||
{
|
||||
if(rxFifo.Count < RX_FIFO_SIZE)
|
||||
{
|
||||
rxFifo.Enqueue(value);
|
||||
fsta = (byte)(fsta & (~FSTA_REMP));
|
||||
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
|
||||
(value >= 32 && value < 127) ? (char)value : '.');
|
||||
}
|
||||
else
|
||||
{
|
||||
fsta = (byte)(fsta | FSTA_RFUL);
|
||||
this.Log(LogLevel.Warning, "RX FIFO full");
|
||||
}
|
||||
}
|
||||
|
||||
usr = (byte)(usr | USR_RBFI);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// IUART接口实现
|
||||
// ========================================
|
||||
public uint BaudRate => currentBaudRate;
|
||||
|
||||
public Bits StopBits => ((ucr & UCR_STB) != 0) ? Bits.Two : Bits.One;
|
||||
|
||||
public Parity ParityBit
|
||||
{
|
||||
get
|
||||
{
|
||||
// 提取UCR的bits 1-3
|
||||
byte parityBits = (byte)((ucr & UCR_PB) >> 1);
|
||||
|
||||
if (parityBits == 0x07) // 111b = 0x07 = 无校验
|
||||
return Parity.None;
|
||||
|
||||
if (parityBits == 0x01) // 001b = 0x01 = 奇校验
|
||||
return Parity.Odd;
|
||||
|
||||
if (parityBits == 0x00) // 000b = 0x00 = 偶校验
|
||||
return Parity.Even;
|
||||
|
||||
// 其他值默认为无校验
|
||||
return Parity.None;
|
||||
}
|
||||
}
|
||||
[field: Transient]
|
||||
public event Action<byte> CharReceived; // 事件:外部可订阅
|
||||
|
||||
public long Size => 0x28;
|
||||
public GPIO IRQ { get; }
|
||||
|
||||
// ========================================
|
||||
// 寄存器定义
|
||||
// ========================================
|
||||
private enum Registers : long
|
||||
{
|
||||
TBR_RBR = 0x00,
|
||||
UCR_USR = 0x04,
|
||||
MCR = 0x08,
|
||||
BRSR = 0x0C,
|
||||
FSTA = 0x10,
|
||||
TBR_FreeBytes = 0x14,
|
||||
RBR_FreeBytes = 0x18,
|
||||
RSTR = 0x20,
|
||||
EXTI = 0x24
|
||||
}
|
||||
|
||||
// 位定义
|
||||
private const byte UCR_STB = 0x01;
|
||||
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;
|
||||
private const byte USR_RBFI = 0x80;
|
||||
private const byte MCR_BEN = 0x04;
|
||||
private const byte MCR_REN = 0x20;
|
||||
private const byte FSTA_TEMP = 0x01;
|
||||
private const byte FSTA_TFUL = 0x04;
|
||||
private const byte FSTA_REMP = 0x10;
|
||||
private const byte FSTA_RFUL = 0x40;
|
||||
private const byte RSTR_RES = 0x55;
|
||||
private const int RX_FIFO_SIZE = 1024;
|
||||
private const int TX_FIFO_SIZE = 2048;
|
||||
|
||||
// 私有字段
|
||||
private readonly uint clockFrequency;
|
||||
private uint currentBaudRate;
|
||||
private byte ucr;
|
||||
private byte usr;
|
||||
private byte mcr;
|
||||
private ushort brsr;
|
||||
private byte fsta;
|
||||
private ushort tbr;
|
||||
private ushort rbr;
|
||||
private byte rstr;
|
||||
private readonly Queue<byte> rxFifo;
|
||||
private readonly Queue<byte> txFifo;
|
||||
private bool RxfifoEnabled;
|
||||
private bool TxfifoEnabled;
|
||||
private int fifoTriggerLevel;
|
||||
private bool transmissionScheduled;
|
||||
private ulong transmissionGeneration;
|
||||
private ulong microsecondsPerByte;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// // 网络层修改示例(伪代码)
|
||||
// class UDPNetworkLayer
|
||||
// {
|
||||
// private List<byte> buffer = new List<byte>();
|
||||
|
||||
// public void Initialize(UART_771_RUHW_2CFG4 uart)
|
||||
// {
|
||||
// // 订阅事件,替代25Hz定时器
|
||||
// uart.CharReceived += OnUartDataReceived;
|
||||
// }
|
||||
|
||||
// private void OnUartDataReceived(byte data)
|
||||
// {
|
||||
// buffer.Add(data);
|
||||
|
||||
// // 批量发送(可选的优化)
|
||||
// if (buffer.Count >= 128 || bufferTimeout)
|
||||
// {
|
||||
// SendToUDP(buffer.ToArray());
|
||||
// buffer.Clear();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
336
UART_kx12A5.cs
Normal file
336
UART_kx12A5.cs
Normal 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
390
UART_kx12A6.cs
Normal 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置0,D3置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置0,D3置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;
|
||||
}
|
||||
}
|
||||
501
UART_kx12A6_event.cs
Normal file
501
UART_kx12A6_event.cs
Normal file
@@ -0,0 +1,501 @@
|
||||
//
|
||||
// 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;
|
||||
using Antmicro.Migrant;
|
||||
|
||||
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;
|
||||
private readonly object txFifoLock = new object();
|
||||
private readonly object rxFifoLock = new object();
|
||||
|
||||
public UART_771_RUHW_2CFG6(IMachine machine)
|
||||
{
|
||||
this.clockFrequency = 24000000;
|
||||
this.machine = machine;
|
||||
transmissionGeneration = 0;
|
||||
|
||||
// 创建 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()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
txFifo.Clear();
|
||||
}
|
||||
lock(rxFifoLock)
|
||||
{
|
||||
rxFifo.Clear();
|
||||
}
|
||||
|
||||
fsta = FSTA_TEMP; // FIFO状态寄存器
|
||||
frm_cnt = 0; // 帧计数
|
||||
byte_cnt = 0;
|
||||
tbr = 0; // 发送FIFO剩余字节数
|
||||
currentBaudRate = 16384; // 时钟配置缺省为16384Hz
|
||||
clk_set = (ushort)(clockFrequency / (2 * currentBaudRate) - 1);
|
||||
scramble_ctrl = 0x00; // 加解扰使能禁止
|
||||
rstr = 0x00; // 复位/使能寄存器
|
||||
|
||||
RxfifoEnabled = true;
|
||||
TxfifoEnabled = true; //发送fifo使能
|
||||
|
||||
transmissionScheduled = false;
|
||||
transmissionGeneration++;
|
||||
InterruptTriggerCondition = false; //重置后不满足条件
|
||||
|
||||
IRQ.Set(false);
|
||||
UpdateInterrupts();
|
||||
|
||||
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剩余字节数
|
||||
lock(txFifoLock)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
// 计算传输速率
|
||||
ComputeTransRate();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ========================================
|
||||
// 按波特率计算传输速率,同步串口无起始位、停止位、奇偶校验位
|
||||
// ========================================
|
||||
public void ComputeTransRate()
|
||||
{
|
||||
// 计算传输时间
|
||||
int bitsPerByte = 8; // 数据位
|
||||
|
||||
// 计算传输时间(秒),16384hz->488.24us
|
||||
if(currentBaudRate == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
double secondsPerByte = (double)bitsPerByte / currentBaudRate;
|
||||
microsecondsPerByte = (ulong)(secondsPerByte * 1000000);
|
||||
|
||||
this.Log(LogLevel.Debug,
|
||||
"Scheduling byte transmission: {0} bits @ {1} bps = {2}μs",
|
||||
bitsPerByte, currentBaudRate, microsecondsPerByte);
|
||||
}
|
||||
|
||||
private void UpdateInterrupts()
|
||||
{
|
||||
if(InterruptTriggerCondition == false)
|
||||
{
|
||||
// FIFO空 → 必须先写满>64,期间绝对不触发中断
|
||||
IRQ.Set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
// <64 中断,>96 清除,中间保持
|
||||
if (txFifo.Count < IRQ_MINBYTES)
|
||||
{
|
||||
IRQ.Set(true);
|
||||
this.Log(LogLevel.Info, "Interrupt asserted");
|
||||
}
|
||||
else if (txFifo.Count > IRQ_MAXBYTES)
|
||||
{
|
||||
IRQ.Set(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void WriteTBR(uint value)
|
||||
{
|
||||
// 从星务接收数据 ,操作txFifo
|
||||
// value 低16位有效
|
||||
this.Log(LogLevel.Info, "Write TBR: 0x{0:X2}", value);
|
||||
|
||||
lock(txFifoLock)
|
||||
{
|
||||
if (TxfifoEnabled)
|
||||
{
|
||||
if ((txFifo.Count + 2) <= TX_FIFO_SIZE)
|
||||
{
|
||||
bool wasEmpty = (txFifo.Count == 0);
|
||||
|
||||
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字节
|
||||
|
||||
// FIFO从空变为非空
|
||||
if(wasEmpty)
|
||||
{
|
||||
this.Log(LogLevel.Info, "FIFO: Empty->NonEmpty");
|
||||
// 启动传输调度(事件驱动)
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
|
||||
if (txFifo.Count >= (TX_FIFO_SIZE / 2))
|
||||
{
|
||||
// 置半满标志
|
||||
fsta = (byte)(fsta | FSTA_TLHF); // 发送FIFO半满,D2置1
|
||||
}
|
||||
|
||||
if((InterruptTriggerCondition == false) && (txFifo.Count > IRQ_MINBYTES))
|
||||
{
|
||||
InterruptTriggerCondition = true;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ========================================
|
||||
// 核心:按波特率调度发送(事件驱动)
|
||||
// ========================================
|
||||
private void ScheduleNextByteTransmit()
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
// 防止重复调度
|
||||
if (transmissionScheduled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count == 0)
|
||||
{
|
||||
// FIFO空
|
||||
fsta = (byte)((fsta & 0xF0) | FSTA_TEMP);
|
||||
fsta |= FSTA_THHF; //空闲置1
|
||||
this.Log(LogLevel.Info, "TX FIFO empty");
|
||||
InterruptTriggerCondition = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count < (TX_FIFO_SIZE / 2))
|
||||
{
|
||||
// 清半满标志
|
||||
fsta = (byte)(fsta & (~FSTA_TLHF)); // 发送FIFO非半满,D2清0
|
||||
}
|
||||
|
||||
transmissionScheduled = true;
|
||||
fsta = (byte)(fsta & (~FSTA_THHF)); //正在发送,置0
|
||||
var currentGeneration = transmissionGeneration;
|
||||
|
||||
// 使用Renode虚拟时间调度
|
||||
machine.ScheduleAction(
|
||||
TimeInterval.FromMicroseconds(microsecondsPerByte),
|
||||
_ => TransmitOneByte(currentGeneration)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void TransmitOneByte(ulong generation)
|
||||
{
|
||||
lock(txFifoLock)
|
||||
{
|
||||
transmissionScheduled = false;
|
||||
|
||||
// 检查是否被Reset取消
|
||||
if (generation != transmissionGeneration)
|
||||
{
|
||||
this.Log(LogLevel.Debug, "Transmission cancelled (reset)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (txFifo.Count > 0)
|
||||
{
|
||||
byte data = txFifo.Dequeue();
|
||||
|
||||
// 触发CharReceived事件(外部Backend可订阅 网络中间层改为订阅这个事件的方式)
|
||||
TransmitCharacter(data);
|
||||
|
||||
this.Log(LogLevel.Info,
|
||||
"Transmitted: 0x{0:X2} ('{1}'), Remaining: {2}",
|
||||
data,
|
||||
(data >= 32 && data < 127) ? (char)data : '.',
|
||||
txFifo.Count);
|
||||
|
||||
// 继续调度下一个字节
|
||||
UpdateInterrupts();
|
||||
ScheduleNextByteTransmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
UpdateInterrupts();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 同步串口属性
|
||||
// ========================================
|
||||
public uint BaudRate => 0;
|
||||
public enum Bits { None }
|
||||
public Bits StopBits => Bits.None;
|
||||
public enum Parity { None }
|
||||
public Parity ParityBit => Parity.None;
|
||||
|
||||
public uint GetFSTA() => fsta;
|
||||
public uint GetByteCount() => byte_cnt;
|
||||
public ushort GetFrameCount() => frm_cnt;
|
||||
|
||||
public event Action<byte> CharReceived;
|
||||
|
||||
private void TransmitCharacter(byte data)
|
||||
{
|
||||
CharReceived?.Invoke(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复位;其他使能
|
||||
}
|
||||
|
||||
|
||||
// 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 bool transmissionScheduled;
|
||||
private ulong transmissionGeneration;
|
||||
private ulong microsecondsPerByte;
|
||||
private bool InterruptTriggerCondition; //FIFO为空后写入64字节才允许触发中断
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
318
YB29LV160Flash.cs
Normal file
318
YB29LV160Flash.cs
Normal file
@@ -0,0 +1,318 @@
|
||||
using System;
|
||||
|
||||
using Antmicro.Renode.Core;
|
||||
using Antmicro.Renode.Logging;
|
||||
using Antmicro.Renode.Peripherals.Bus;
|
||||
|
||||
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||
{
|
||||
public class YB29LV160Flash : IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IKnownSize, IGPIOReceiver
|
||||
{
|
||||
public YB29LV160Flash(IMachine machine, long size = DefaultFlashSize)
|
||||
{
|
||||
if(size <= 0 || size > int.MaxValue)
|
||||
{
|
||||
throw new ArgumentException($"Invalid flash size: {size}", nameof(size));
|
||||
}
|
||||
|
||||
Size = size;
|
||||
storage = new byte[(int)size];
|
||||
Ready = new GPIO();
|
||||
Array.Fill(storage, ErasedValue);
|
||||
Reset();
|
||||
}
|
||||
|
||||
public byte ReadByte(long offset)
|
||||
{
|
||||
if(!TryValidateRange(offset, 1))
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return storage[(int)offset];
|
||||
}
|
||||
|
||||
public ushort ReadWord(long offset)
|
||||
{
|
||||
if(!TryValidateRange(offset, 2))
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
var index = (int)offset;
|
||||
return (ushort)(storage[index] | (storage[index + 1] << 8));
|
||||
}
|
||||
|
||||
public uint ReadDoubleWord(long offset)
|
||||
{
|
||||
if(!TryValidateRange(offset, 4))
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
var index = (int)offset;
|
||||
return (uint)(
|
||||
storage[index]
|
||||
| (storage[index + 1] << 8)
|
||||
| (storage[index + 2] << 16)
|
||||
| (storage[index + 3] << 24)
|
||||
);
|
||||
}
|
||||
|
||||
public void WriteByte(long offset, byte value)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Unhandled byte write at offset 0x{0:X}: 0x{1:X2}; firmware is expected to use 32-bit accesses", offset, value);
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
}
|
||||
|
||||
public void WriteWord(long offset, ushort value)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Unhandled word write at offset 0x{0:X}: 0x{1:X4}; firmware is expected to use 32-bit accesses", offset, value);
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
}
|
||||
|
||||
public void WriteDoubleWord(long offset, uint value)
|
||||
{
|
||||
if(!TryValidateRange(offset, 4))
|
||||
{
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
return;
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Noisy, "Flash write offset 0x{0:X}, value 0x{1:X8}, state {2}", offset, value, commandState);
|
||||
|
||||
switch(commandState)
|
||||
{
|
||||
case FlashCommandState.ReadArray:
|
||||
if(IsUnlock1(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.GotAA;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlashCommandState.GotAA:
|
||||
if(IsUnlock2(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.GotAA55;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlashCommandState.GotAA55:
|
||||
if(IsProgramSetup(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.ProgramSetup;
|
||||
return;
|
||||
}
|
||||
if(IsEraseSetup(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.EraseSetup;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlashCommandState.ProgramSetup:
|
||||
ProgramDoubleWord(offset, value);
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
return;
|
||||
|
||||
case FlashCommandState.EraseSetup:
|
||||
if(IsUnlock1(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.EraseGotAA;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlashCommandState.EraseGotAA:
|
||||
if(IsUnlock2(offset, value))
|
||||
{
|
||||
commandState = FlashCommandState.EraseGotAA55;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case FlashCommandState.EraseGotAA55:
|
||||
if(value == SectorEraseConfirm)
|
||||
{
|
||||
EraseSectorContaining(offset);
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this.Log(LogLevel.Warning, "Unexpected flash command write at offset 0x{0:X}: 0x{1:X8} in state {2}", offset, value, commandState);
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
}
|
||||
|
||||
public void OnGPIO(int number, bool value)
|
||||
{
|
||||
switch(number)
|
||||
{
|
||||
case WriteProtectInput:
|
||||
// The board-level WP pin is active low in the C driver.
|
||||
writeProtected = !value;
|
||||
this.Log(LogLevel.Debug, "Hardware write protect {0}", writeProtected ? "enabled" : "disabled");
|
||||
break;
|
||||
|
||||
default:
|
||||
this.Log(LogLevel.Warning, "Unhandled GPIO #{0} value {1}", number, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
commandState = FlashCommandState.ReadArray;
|
||||
writeProtected = true;
|
||||
SetReady(true);
|
||||
}
|
||||
|
||||
public void SetWriteProtect(bool enabled)
|
||||
{
|
||||
writeProtected = enabled;
|
||||
}
|
||||
|
||||
public GPIO Ready { get; }
|
||||
|
||||
public long Size { get; }
|
||||
|
||||
private void ProgramDoubleWord(long offset, uint value)
|
||||
{
|
||||
if(writeProtected)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Ignoring program command at 0x{0:X}; hardware write protect is enabled", offset);
|
||||
return;
|
||||
}
|
||||
|
||||
// NOR programming can only drive bits from 1 to 0.
|
||||
var index = (int)offset;
|
||||
storage[index] = (byte)(storage[index] & (value & 0xFF));
|
||||
storage[index + 1] = (byte)(storage[index + 1] & ((value >> 8) & 0xFF));
|
||||
storage[index + 2] = (byte)(storage[index + 2] & ((value >> 16) & 0xFF));
|
||||
storage[index + 3] = (byte)(storage[index + 3] & ((value >> 24) & 0xFF));
|
||||
this.Log(LogLevel.Debug, "Programmed flash at 0x{0:X} with 0x{1:X8}", offset, value);
|
||||
}
|
||||
|
||||
private void EraseSectorContaining(long offset)
|
||||
{
|
||||
if(writeProtected)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Ignoring sector erase at 0x{0:X}; hardware write protect is enabled", offset);
|
||||
return;
|
||||
}
|
||||
|
||||
var sectorStart = GetSectorStart(offset, out var sectorSize);
|
||||
if(sectorSize == 0)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Cannot erase sector for offset 0x{0:X}", offset);
|
||||
return;
|
||||
}
|
||||
|
||||
for(var i = 0; i < sectorSize; i++)
|
||||
{
|
||||
storage[sectorStart + i] = ErasedValue;
|
||||
}
|
||||
this.Log(LogLevel.Debug, "Erased sector at 0x{0:X}, size 0x{1:X}", sectorStart, sectorSize);
|
||||
}
|
||||
|
||||
private void SetReady(bool value)
|
||||
{
|
||||
Ready.Set(value);
|
||||
}
|
||||
|
||||
private int GetSectorStart(long offset, out int sectorSize)
|
||||
{
|
||||
if(offset < 0 || offset >= Size)
|
||||
{
|
||||
sectorSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mirror the firmware's get_flash_sector_addr_size() layout.
|
||||
if(offset >= 0x3F8000)
|
||||
{
|
||||
sectorSize = 0x8000;
|
||||
return 0x3F8000;
|
||||
}
|
||||
if(offset >= 0x3F4000)
|
||||
{
|
||||
sectorSize = 0x4000;
|
||||
return 0x3F4000;
|
||||
}
|
||||
if(offset >= 0x3F0000)
|
||||
{
|
||||
sectorSize = 0x4000;
|
||||
return 0x3F0000;
|
||||
}
|
||||
if(offset >= 0x3E0000)
|
||||
{
|
||||
sectorSize = 0x10000;
|
||||
return 0x3E0000;
|
||||
}
|
||||
|
||||
sectorSize = 0x20000;
|
||||
return (int)(offset / sectorSize) * sectorSize;
|
||||
}
|
||||
|
||||
private bool TryValidateRange(long offset, int width)
|
||||
{
|
||||
if(offset < 0 || offset + width > Size)
|
||||
{
|
||||
this.Log(LogLevel.Warning, "Out-of-range flash access at offset 0x{0:X}, width {1}", offset, width);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsUnlock1(long offset, uint value)
|
||||
{
|
||||
return offset == UnlockAddress1 && value == UnlockData1;
|
||||
}
|
||||
|
||||
private static bool IsUnlock2(long offset, uint value)
|
||||
{
|
||||
return offset == UnlockAddress2 && value == UnlockData2;
|
||||
}
|
||||
|
||||
private static bool IsProgramSetup(long offset, uint value)
|
||||
{
|
||||
return offset == UnlockAddress1 && value == ProgramSetupData;
|
||||
}
|
||||
|
||||
private static bool IsEraseSetup(long offset, uint value)
|
||||
{
|
||||
return offset == UnlockAddress1 && value == EraseSetupData;
|
||||
}
|
||||
|
||||
private readonly byte[] storage;
|
||||
private FlashCommandState commandState;
|
||||
private bool writeProtected;
|
||||
|
||||
private enum FlashCommandState
|
||||
{
|
||||
ReadArray,
|
||||
GotAA,
|
||||
GotAA55,
|
||||
ProgramSetup,
|
||||
EraseSetup,
|
||||
EraseGotAA,
|
||||
EraseGotAA55
|
||||
}
|
||||
|
||||
private const long DefaultFlashSize = 0x400000;
|
||||
private const byte ErasedValue = 0xFF;
|
||||
private const int WriteProtectInput = 0;
|
||||
|
||||
private const long UnlockAddress1 = 0x1554;
|
||||
private const long UnlockAddress2 = 0x0AA8;
|
||||
|
||||
private const uint UnlockData1 = 0x00AA00AA;
|
||||
private const uint UnlockData2 = 0x00550055;
|
||||
private const uint ProgramSetupData = 0x00A000A0;
|
||||
private const uint EraseSetupData = 0x00800080;
|
||||
private const uint SectorEraseConfirm = 0x00300030;
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,15 @@ mic: IRQControllers.GaislerMIC @ sysbus <0x80000200, +0x100>
|
||||
//ioRegs: Miscellaneous.Simple_IO_Regs @ sysbus 0x800000A0
|
||||
// TimeSliceIRQ -> mic@4
|
||||
|
||||
//uart: UART.GaislerAPBUART @ sysbus <0x80000100, +0x100>
|
||||
// -> mic@2
|
||||
uart: UART.GaislerAPBUART @ sysbus <0x80000100, +0x100>
|
||||
-> mic@2
|
||||
|
||||
//timer: Timers.Gaisler_GPTimer @ sysbus 0x80000300
|
||||
timer: Timers.Gaisler_GPTimer @ sysbus 0x80000300
|
||||
// 0 -> mic@8
|
||||
// 0 -> mic@8
|
||||
// numberOfTimers: 2
|
||||
// separateInterrupts: false
|
||||
// frequency: 50000000
|
||||
0 -> mic@8
|
||||
numberOfTimers: 2
|
||||
separateInterrupts: false
|
||||
frequency: 50000000
|
||||
|
||||
eth: Network.GaislerEth @ sysbus 0x80000B00
|
||||
-> mic@12
|
||||
@@ -55,18 +55,36 @@ rtc: Timers.Custom_RTC_R17V1 @sysbus 0x20800D80
|
||||
|
||||
lc3233IntCtrl:IRQControllers.LC3233_InterruptController @sysbus 0x80020000
|
||||
4 -> mic@4
|
||||
5 -> mic@5
|
||||
10 -> mic@10
|
||||
8 -> mic@8
|
||||
13 -> mic@13
|
||||
|
||||
lc3233Timer:Timers.LC3233_TaskTimer @ sysbus 0x80000000
|
||||
IRQ -> lc3233IntCtrl@4
|
||||
|
||||
//adc1: ADUADC1.ADU1 @ sysbus 0x21800800
|
||||
can_a:CustomPeripherals.SJA1000_CAN @sysbus 0xC0000000
|
||||
IRQ -> lc3233IntCtrl@10
|
||||
|
||||
//timer1: Timers1.TimeSlice_Timer_v2.cs @ sysbus 0x80000000
|
||||
// txInterrupt -> mic@2
|
||||
can_b:CustomPeripherals.SJA1000_CAN @sysbus 0xD0000000
|
||||
IRQ -> lc3233IntCtrl@5
|
||||
|
||||
|
||||
//TimerTrigger:Timers.TaskTimer @ sysbus 0x80002000
|
||||
// IRQ -> lc3233IntCtrl@4
|
||||
|
||||
adc0: ADUADC0.ADU0 @ sysbus 0x21800000
|
||||
adc1: ADUADC1.ADU1 @ sysbus 0x21800800
|
||||
adc2: ADUADC2.ADU2 @ sysbus 0x21801000
|
||||
adc3: ADUADC3.ADU3 @ sysbus 0x21C00000
|
||||
adc4: ADUADC4.ADU4 @ sysbus 0x21C00800
|
||||
adc5: ADUADC5.ADU5 @ sysbus 0x21C01000
|
||||
|
||||
oc1: ThermalOC1.ThermalOC1 @ sysbus 0x22000000
|
||||
oc2: ThermalOC2.ThermalOC2 @ sysbus 0x22400000
|
||||
|
||||
oc_SIU1:OCModule.OC_LIMSIU64 @ sysbus 0x21400000
|
||||
oc_SIU2:OCModule_1.OC_LIMSIU64_1 @ sysbus 0x21400020
|
||||
|
||||
uart0: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800000 //光纤陀螺A
|
||||
uart1: CustomPeripherals.UART_771_RUHW_2CFG1 @ sysbus 0x20800080 //光纤陀螺B
|
||||
@@ -110,3 +128,9 @@ uart29: CustomPeripherals.UART_771_RUHW_2CFG5 @ sysbus 0x20800F80 //高速
|
||||
|
||||
uart30: CustomPeripherals.UART_771_RUHW_2CFG6 @ sysbus 0x20800E00 //遥测, A6
|
||||
IRQ -> lc3233IntCtrl@13
|
||||
//timer1: Timers1.TimeSlice_Timer_v2.cs @ sysbus 0x80000000
|
||||
// txInterrupt -> mic@2
|
||||
|
||||
|
||||
time_ms: CustomPeripherals.Custom_MS @ sysbus 0x20801500
|
||||
// 毫秒计数器, Custom_MS
|
||||
|
||||
@@ -7,12 +7,23 @@ using sysbus
|
||||
include @LEON_Control_Regs_SIMPLE.cs
|
||||
#include @Custom_RTC_R17V1_CORRECT_ADDR.cs
|
||||
#include @Simple_IO_Regs.cs
|
||||
include @LC3233_Timer_InterruptController.cs
|
||||
include @LC3233_Timer_InterruptController_NO3.cs
|
||||
#include @Custom_ADC_R17V1.cs
|
||||
include @Custom_TLZA_Rwa.cs
|
||||
include @Custom_TLZA_ADU.cs
|
||||
include @Custom_TLZA_ADU1.cs
|
||||
include @Custom_TLZA_ADU2.cs
|
||||
include @Custom_TLZA_ADU3.cs
|
||||
include @Custom_TLZA_ADU4.cs
|
||||
include @Custom_TLZA_ADU5.cs
|
||||
|
||||
include @Custom_TLZA_OC_HDC1.cs
|
||||
include @Custom_TLZA_OC_HDC2.cs
|
||||
include @Custom_TLZA_OC_LMSIU64.cs
|
||||
include @Custom_TLZA_OC_LMSIU64_1.cs
|
||||
|
||||
include @Custom_RTC_TLZA.cs
|
||||
include @SJA1000_CAN.cs
|
||||
#include @timer_trigger.cs
|
||||
include @UART_kx12A1.cs
|
||||
include @UART_kx12A2.cs
|
||||
@@ -21,6 +32,8 @@ include @UART_kx12A4.cs
|
||||
include @UART_kx12A5.cs
|
||||
include @UART_kx12A6.cs
|
||||
|
||||
include @Custom_MS.cs
|
||||
|
||||
# ===== 创建机器 =====
|
||||
mach create "SPARC V8_Leon3"
|
||||
|
||||
@@ -28,13 +41,13 @@ mach create "SPARC V8_Leon3"
|
||||
machine LoadPlatformDescription @generated.repl
|
||||
|
||||
# ===== CPU 性能配置 =====
|
||||
cpu PerformanceInMips 80
|
||||
cpu PerformanceInMips 2000
|
||||
|
||||
# ===== 固件加载 =====
|
||||
# Load VxWorks
|
||||
sysbus LoadBinary @C:/Users/PingCe/Desktop/1_simulation/KX12A_Z/vxworks_smu/default/vxWorks 0x40003000
|
||||
|
||||
sysbus WriteDoubleWord 0x80000240 0x10
|
||||
sysbus WriteDoubleWord 0x80000240 0x92530
|
||||
|
||||
# ===== 调试配置 =====
|
||||
machine StartGdbServer 3333 true
|
||||
|
||||
Reference in New Issue
Block a user