// // 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 { /// /// UART_771_RUHW_2CFG 控制器:同步串口、遥测、有中断 /// 接收缓存0B,发送缓存2048B,输入时钟24MHz /// 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(); rxFifo = new Queue(); // 创建中断线 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 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 rxFifo; private readonly Queue txFifo; private bool RxfifoEnabled; private bool TxfifoEnabled; private bool transmissionScheduled; private ulong transmissionGeneration; private ulong microsecondsPerByte; private bool InterruptTriggerCondition; //FIFO为空后写入64字节才允许触发中断 } }