Files
simulation_Peripheral/UART16550.cs

678 lines
23 KiB
C#
Raw Normal View History

2026-04-10 16:39:39 +08:00
//
// 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
{
/// <summary>
/// 16550 UART 控制器
/// 兼容 16550 UART 规格,支持 FIFO、中断和调制解调器控制
/// </summary>
public class UART16550 : UARTBase, IDoubleWordPeripheral, IBytePeripheral, IKnownSize
{
public UART16550(IMachine machine, uint clockFrequency = 1843200)
: base(machine)
{
this.clockFrequency = clockFrequency;
// 创建 FIFO
rxFifo = new Queue<byte>();
txFifo = new Queue<byte>();
// 创建中断线
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<byte> rxFifo;
private readonly Queue<byte> txFifo;
private bool fifoEnabled;
private int fifoTriggerLevel;
}
}