// 配合地测中断更改版本 //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(); // } // } // }