// // 16550 UART 外设实现 // 基于 16550 UART 规格,包含完整的 FIFO、中断和调制解调器控制功能 // 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.Utilities; namespace Antmicro.Renode.Peripherals.CustomPeripherals { /// /// 16550 UART 控制器 /// 兼容 16550 UART 规格,支持 FIFO、中断和调制解调器控制 /// public class UART16550 : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize { public UART16550(IMachine machine, uint clockFrequency = 1843200) : base(machine) { this.clockFrequency = clockFrequency; // 创建 FIFO rxFifo = new Queue(); txFifo = new Queue(); // 创建中断线 IRQ = new GPIO(); // 初始化寄存器 DefineRegisters(); Reset(); this.Log(LogLevel.Info, "16550 UART initialized, clock: {0} Hz", clockFrequency); } public override void Reset() { rxFifo.Clear(); txFifo.Clear(); // 寄存器复位值 ier = 0x00; lcr = 0x00; mcr = 0x00; lsr = (byte)(LSR_TEMT | LSR_THRE); // 发送器初始为空 msr = 0x00; scr = 0x00; dll = 0x00; dlh = 0x00; fcr = 0x00; fifoEnabled = false; fifoTriggerLevel = 1; IRQ.Set(false); UpdateInterrupts(); this.Log(LogLevel.Debug, "16550 UART reset"); } private void DefineRegisters() { // 寄存器访问通过 ReadDoubleWord/WriteDoubleWord 实现 // 因为 16550 是字节外设,但 Renode 通常使用 32 位访问 } // ======================================== // IBusPeripheral 接口实现 // ======================================== public uint ReadDoubleWord(long offset) { return ReadByte(offset); } public void WriteDoubleWord(long offset, uint value) { WriteByte(offset, (byte)value); } public byte ReadByte(long offset) { byte value = 0; switch (offset) { case (long)Registers.RBR_THR_DLL: if ((lcr & LCR_DLAB) != 0) { // DLAB=1: 读取 DLL value = dll; this.Log(LogLevel.Noisy, "Read DLL: 0x{0:X2}", value); } else { // DLAB=0: 读取 RBR value = ReadRBR(); } break; case (long)Registers.IER_DLH: if ((lcr & LCR_DLAB) != 0) { // DLAB=1: 读取 DLH value = dlh; this.Log(LogLevel.Noisy, "Read DLH: 0x{0:X2}", value); } else { // DLAB=0: 读取 IER value = (byte)(ier & 0x0F); this.Log(LogLevel.Noisy, "Read IER: 0x{0:X2}", value); } break; case (long)Registers.IIR_FCR: // IIR - 中断识别寄存器 value = ReadIIR(); break; case (long)Registers.LCR: value = lcr; this.Log(LogLevel.Noisy, "Read LCR: 0x{0:X2}", value); break; case (long)Registers.MCR: value = mcr; this.Log(LogLevel.Noisy, "Read MCR: 0x{0:X2}", value); break; case (long)Registers.LSR: value = lsr; this.Log(LogLevel.Noisy, "Read LSR: 0x{0:X2}", value); // 读取 LSR 清除错误位 lsr = (byte)(lsr & ~(LSR_BI | LSR_FE | LSR_PE)); UpdateInterrupts(); break; case (long)Registers.MSR: value = msr; this.Log(LogLevel.Noisy, "Read MSR: 0x{0:X2}", value); // 读取 MSR 清除变化位 msr = (byte)(msr & 0xF0); UpdateInterrupts(); break; case (long)Registers.SCR: value = scr; this.Log(LogLevel.Noisy, "Read SCR: 0x{0:X2}", value); break; default: this.Log(LogLevel.Warning, "Read from unknown offset: 0x{0:X}", offset); break; } return value; } public void WriteByte(long offset, byte value) { switch (offset) { case (long)Registers.RBR_THR_DLL: if ((lcr & LCR_DLAB) != 0) { // DLAB=1: 写入 DLL dll = value; UpdateBaudRate(); this.Log(LogLevel.Debug, "Write DLL: 0x{0:X2}", value); } else { // DLAB=0: 写入 THR WriteTHR(value); } break; case (long)Registers.IER_DLH: if ((lcr & LCR_DLAB) != 0) { // DLAB=1: 写入 DLH dlh = value; UpdateBaudRate(); this.Log(LogLevel.Debug, "Write DLH: 0x{0:X2}", value); } else { // DLAB=0: 写入 IER ier = (byte)(value & 0x0F); this.Log(LogLevel.Debug, "Write IER: 0x{0:X2}", ier); UpdateInterrupts(); } break; case (long)Registers.IIR_FCR: // FCR - FIFO 控制寄存器 WriteFCR(value); break; case (long)Registers.LCR: lcr = value; this.Log(LogLevel.Debug, "Write LCR: 0x{0:X2}", value); UpdateLineParameters(); break; case (long)Registers.MCR: mcr = (byte)(value & 0x1F); this.Log(LogLevel.Debug, "Write MCR: 0x{0:X2}", mcr); UpdateModemControl(); break; case (long)Registers.LSR: // LSR 是只读寄存器 this.Log(LogLevel.Warning, "Attempted write to read-only LSR"); break; case (long)Registers.MSR: // MSR 是只读寄存器 this.Log(LogLevel.Warning, "Attempted write to read-only MSR"); break; case (long)Registers.SCR: scr = value; this.Log(LogLevel.Noisy, "Write SCR: 0x{0:X2}", value); break; default: this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value); break; } } // ======================================== // FIFO 和数据传输 // ======================================== private byte ReadRBR() { byte value = 0; if (rxFifo.Count > 0) { value = rxFifo.Dequeue(); this.Log(LogLevel.Debug, "Read RBR: 0x{0:X2} ('{1}')", value, (value >= 32 && value < 127) ? (char)value : '.'); // 更新状态 if (rxFifo.Count == 0) { lsr = (byte)(lsr & ~LSR_DR); // 清除数据就绪 } // 检查溢出 if (rxFifo.Count == 0) { lsr = (byte)(lsr & ~LSR_OE); // 清除溢出错误 } } else { this.Log(LogLevel.Warning, "Read from empty RBR"); } UpdateInterrupts(); return value; } private void WriteTHR(byte value) { this.Log(LogLevel.Debug, "Write THR: 0x{0:X2} ('{1}')", value, (value >= 32 && value < 127) ? (char)value : '.'); if (fifoEnabled) { if (txFifo.Count < FIFO_SIZE) { txFifo.Enqueue(value); lsr = (byte)(lsr & ~LSR_THRE); // THR 非空 lsr = (byte)(lsr & ~LSR_TEMT); // 发送器非空 } else { this.Log(LogLevel.Warning, "TX FIFO overflow"); } } else { // 非 FIFO 模式,直接发送 txFifo.Clear(); txFifo.Enqueue(value); lsr = (byte)(lsr & ~LSR_THRE); lsr = (byte)(lsr & ~LSR_TEMT); } // 实际发送数据 TransmitData(); } private void WriteFCR(byte value) { fcr = value; this.Log(LogLevel.Debug, "Write FCR: 0x{0:X2}", value); // FIFO 使能 bool newFifoEnabled = (value & FCR_FIFO_EN) != 0; if (newFifoEnabled != fifoEnabled) { fifoEnabled = newFifoEnabled; this.Log(LogLevel.Info, "FIFO {0}", fifoEnabled ? "enabled" : "disabled"); if (!fifoEnabled) { // 禁用 FIFO 时清空 rxFifo.Clear(); txFifo.Clear(); } } // 清除 RX FIFO if ((value & FCR_RCVR_RESET) != 0) { rxFifo.Clear(); lsr = (byte)(lsr & ~LSR_DR); this.Log(LogLevel.Debug, "RX FIFO cleared"); } // 清除 TX FIFO if ((value & FCR_XMIT_RESET) != 0) { txFifo.Clear(); lsr = (byte)(lsr | (LSR_THRE | LSR_TEMT)); this.Log(LogLevel.Debug, "TX FIFO cleared"); } // 设置触发级别 byte trigger = (byte)((value >> 6) & 0x03); switch (trigger) { case 0: fifoTriggerLevel = 1; break; case 1: fifoTriggerLevel = 4; break; case 2: fifoTriggerLevel = 8; break; case 3: fifoTriggerLevel = 14; break; } this.Log(LogLevel.Debug, "FIFO trigger level: {0} bytes", fifoTriggerLevel); UpdateInterrupts(); } private byte ReadIIR() { byte iir = IIR_NO_INT; // 默认无中断 // 检查中断使能 if ((mcr & MCR_OUT2) == 0) { // OUT2 未置位,禁用中断 this.Log(LogLevel.Noisy, "Read IIR: 0x{0:X2} (interrupts disabled)", iir); return iir; } // 按优先级检查中断 // 1. 接收线路状态中断 (最高优先级) if ((ier & IER_ELSI) != 0 && (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) != 0) { iir = IIR_RLS; // 0x06 } // 2. 接收数据可用中断 else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count >= fifoTriggerLevel) { iir = IIR_RDA; // 0x04 } // 3. 字符超时中断 else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count > 0) { iir = IIR_CTI; // 0x0C } // 4. THR 空中断 else if ((ier & IER_ETBEI) != 0 && (lsr & LSR_THRE) != 0) { iir = IIR_THRE; // 0x02 } // 5. 调制解调器状态中断 (最低优先级) else if ((ier & IER_EDSSI) != 0 && (msr & 0x0F) != 0) { iir = IIR_MS; // 0x00 } // FIFO 使能状态 if (fifoEnabled) { iir |= IIR_FIFO_EN; } this.Log(LogLevel.Noisy, "Read IIR: 0x{0:X2}", iir); // 读取 IIR 清除 THRE 中断 if ((iir & 0x0F) == IIR_THRE) { UpdateInterrupts(); } return iir; } private void TransmitData() { // 从 TX FIFO 发送数据 while (txFifo.Count > 0) { byte data = txFifo.Dequeue(); // 调用基类的 TransmitCharacter 发送数据 TransmitCharacter(data); this.Log(LogLevel.Debug, "Transmitted: 0x{0:X2} ('{1}')", data, (data >= 32 && data < 127) ? (char)data : '.'); } // 更新状态 lsr = (byte)(lsr | LSR_THRE); // THR 空 lsr = (byte)(lsr | LSR_TEMT); // 发送器空 UpdateInterrupts(); } // ======================================== // UARTBase 接口实现 // ======================================== public override void WriteChar(byte value) { // 从外部接收数据 (例如从终端或网络) if (fifoEnabled) { if (rxFifo.Count < FIFO_SIZE) { rxFifo.Enqueue(value); lsr = (byte)(lsr | LSR_DR); // 数据就绪 this.Log(LogLevel.Debug, "Received: 0x{0:X2} ('{1}'), FIFO count: {2}", value, (value >= 32 && value < 127) ? (char)value : '.', rxFifo.Count); } else { lsr = (byte)(lsr | LSR_OE); // 溢出错误 this.Log(LogLevel.Warning, "RX FIFO overflow"); } } else { // 非 FIFO 模式 if (rxFifo.Count > 0) { lsr = (byte)(lsr | LSR_OE); // 溢出错误 } rxFifo.Clear(); rxFifo.Enqueue(value); lsr = (byte)(lsr | LSR_DR); } UpdateInterrupts(); } protected override void CharWritten() { // UARTBase 要求实现此方法 // 在字符写入后调用,这里不需要额外操作 } protected override void QueueEmptied() { // UARTBase 要求实现此方法 // 当队列为空时调用,这里不需要额外操作 } public override Bits StopBits { get { return ((lcr & LCR_STB) != 0) ? Bits.Two : Bits.One; } } public override Parity ParityBit { get { if ((lcr & LCR_PEN) == 0) return Parity.None; if ((lcr & LCR_EPS) != 0) return Parity.Even; else return Parity.Odd; } } public override uint BaudRate { get { return currentBaudRate; } } // ======================================== // 辅助方法 // ======================================== private void UpdateBaudRate() { ushort divisor = (ushort)((dlh << 8) | dll); if (divisor == 0) { currentBaudRate = 0; } else { currentBaudRate = clockFrequency / (16u * divisor); this.Log(LogLevel.Info, "Baud rate set to {0} (divisor: {1})", currentBaudRate, divisor); } } private void UpdateLineParameters() { // 字长 byte wordLength = (byte)((lcr & LCR_WLS) + 5); // 停止位 string stopBits = ((lcr & LCR_STB) != 0) ? "2" : "1"; // 奇偶校验 string parity; if ((lcr & LCR_PEN) == 0) parity = "N"; else if ((lcr & LCR_EPS) != 0) parity = "E"; else parity = "O"; this.Log(LogLevel.Info, "Line format: {0}{1}{2}", wordLength, parity, stopBits); } private void UpdateModemControl() { this.Log(LogLevel.Debug, "Modem control: DTR={0}, RTS={1}, OUT1={2}, OUT2={3}, LOOP={4}", (mcr & MCR_DTR) != 0, (mcr & MCR_RTS) != 0, (mcr & MCR_OUT1) != 0, (mcr & MCR_OUT2) != 0, (mcr & MCR_LOOP) != 0); UpdateInterrupts(); } private void UpdateInterrupts() { bool interrupt = false; // OUT2 必须置位才能产生中断 if ((mcr & MCR_OUT2) != 0) { // 检查各种中断条件 if ((ier & IER_ELSI) != 0 && (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) != 0) interrupt = true; else if ((ier & IER_ERBFI) != 0 && (lsr & LSR_DR) != 0 && rxFifo.Count >= fifoTriggerLevel) interrupt = true; else if ((ier & IER_ETBEI) != 0 && (lsr & LSR_THRE) != 0) interrupt = true; else if ((ier & IER_EDSSI) != 0 && (msr & 0x0F) != 0) interrupt = true; } IRQ.Set(interrupt); if (interrupt) { this.Log(LogLevel.Debug, "Interrupt asserted"); } } public long Size => 0x08; public GPIO IRQ { get; } // ======================================== // 寄存器定义 // ======================================== private enum Registers : long { RBR_THR_DLL = 0x00, // RBR/THR (DLAB=0), DLL (DLAB=1) IER_DLH = 0x01, // IER (DLAB=0), DLH (DLAB=1) IIR_FCR = 0x02, // IIR (R), FCR (W) LCR = 0x03, // Line Control Register MCR = 0x04, // Modem Control Register LSR = 0x05, // Line Status Register MSR = 0x06, // Modem Status Register SCR = 0x07, // Scratch Register } // LCR 位定义 private const byte LCR_WLS = 0x03; // 字长选择 private const byte LCR_STB = 0x04; // 停止位 private const byte LCR_PEN = 0x08; // 奇偶校验使能 private const byte LCR_EPS = 0x10; // 偶校验选择 private const byte LCR_SPAR = 0x20; // 强制奇偶校验 private const byte LCR_SBC = 0x40; // 设置中断 private const byte LCR_DLAB = 0x80; // 除数锁存访问 // LSR 位定义 private const byte LSR_DR = 0x01; // 数据就绪 private const byte LSR_OE = 0x02; // 溢出错误 private const byte LSR_PE = 0x04; // 奇偶校验错误 private const byte LSR_FE = 0x08; // 帧错误 private const byte LSR_BI = 0x10; // 中断指示 private const byte LSR_THRE = 0x20; // THR 空 private const byte LSR_TEMT = 0x40; // 发送器空 private const byte LSR_FIFO_ERR = 0x80; // FIFO 错误 // IER 位定义 private const byte IER_ERBFI = 0x01; // 使能接收数据可用中断 private const byte IER_ETBEI = 0x02; // 使能 THR 空中断 private const byte IER_ELSI = 0x04; // 使能接收线路状态中断 private const byte IER_EDSSI = 0x08; // 使能调制解调器状态中断 // IIR 值定义 private const byte IIR_NO_INT = 0x01; // 无中断挂起 private const byte IIR_MS = 0x00; // 调制解调器状态 private const byte IIR_THRE = 0x02; // THR 空 private const byte IIR_RDA = 0x04; // 接收数据可用 private const byte IIR_RLS = 0x06; // 接收线路状态 private const byte IIR_CTI = 0x0C; // 字符超时 private const byte IIR_FIFO_EN = 0xC0; // FIFO 使能标志 // FCR 位定义 private const byte FCR_FIFO_EN = 0x01; // FIFO 使能 private const byte FCR_RCVR_RESET = 0x02; // 清除 RX FIFO private const byte FCR_XMIT_RESET = 0x04; // 清除 TX FIFO // MCR 位定义 private const byte MCR_DTR = 0x01; // DTR private const byte MCR_RTS = 0x02; // RTS private const byte MCR_OUT1 = 0x04; // OUT1 private const byte MCR_OUT2 = 0x08; // OUT2 private const byte MCR_LOOP = 0x10; // 环回模式 // 常量 private const int FIFO_SIZE = 16; // ======================================== // 私有字段 // ======================================== private readonly uint clockFrequency; private uint currentBaudRate; // 寄存器 private byte ier; // 中断使能寄存器 private byte lcr; // 线路控制寄存器 private byte mcr; // 调制解调器控制寄存器 private byte lsr; // 线路状态寄存器 private byte msr; // 调制解调器状态寄存器 private byte scr; // 暂存寄存器 private byte dll; // 除数锁存低字节 private byte dlh; // 除数锁存高字节 private byte fcr; // FIFO 控制寄存器 // FIFO private readonly Queue rxFifo; private readonly Queue txFifo; private bool fifoEnabled; private int fifoTriggerLevel; } }