增加一个事件驱动的串口逻辑 待测

This commit is contained in:
liuwb
2026-04-28 16:25:50 +08:00
parent d9c0f0f07c
commit ea96c1e806

626
UART_kx12A4_event.cs Normal file
View 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();
// }
// }
// }