diff --git a/UART16550.cs b/UART16550.cs new file mode 100644 index 0000000..5e147e3 --- /dev/null +++ b/UART16550.cs @@ -0,0 +1,677 @@ +// +// 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; + } +}