Files
simulation_Peripheral/UART_kx12A4_event.cs

627 lines
21 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 配合地测中断更改版本
//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();
// }
// }
// }