diff --git a/UART_kx12A4_event.cs b/UART_kx12A4_event.cs new file mode 100644 index 0000000..3ea9334 --- /dev/null +++ b/UART_kx12A4_event.cs @@ -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 +{ + /// + /// UART_771_RUHW_2CFG 控制器 + /// 接收缓存1024B,发送缓存2048B,时钟24MHz + /// 事件驱动版本 - 使用machine.ScheduleAction精确模拟波特率 + /// + 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(); + txFifo = new Queue(); + + // 创建中断线 + 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 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 rxFifo; + private readonly Queue txFifo; + private bool RxfifoEnabled; + private bool TxfifoEnabled; + private int fifoTriggerLevel; + private bool transmissionScheduled; + private ulong transmissionGeneration; + } +} + + + + +// // 网络层修改示例(伪代码) +// class UDPNetworkLayer +// { +// private List buffer = new List(); + +// 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(); +// } +// } +// }