337 lines
11 KiB
C#
337 lines
11 KiB
C#
//
|
||
// 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;
|
||
|
||
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||
{
|
||
/// <summary>
|
||
/// UART_771_RUHW_2CFG 控制器:同步串口,遥控,无中断
|
||
/// 接收缓存1024B,发送缓存1024B,时钟2000Hz
|
||
/// </summary>
|
||
public class UART_771_RUHW_2CFG5 : IDoubleWordPeripheral, IKnownSize
|
||
{
|
||
private readonly IMachine machine; //TODO
|
||
|
||
public UART_771_RUHW_2CFG5(IMachine machine)
|
||
{
|
||
this.clockFrequency = 2000;
|
||
this.machine = machine; //TODO
|
||
|
||
// 创建 FIFO
|
||
rxFifo = new Queue<byte>();
|
||
txFifo = new Queue<byte>();
|
||
|
||
// 创建中断线
|
||
IRQ = new GPIO();
|
||
|
||
// 初始化寄存器
|
||
DefineRegisters();
|
||
Reset();
|
||
|
||
this.Log(LogLevel.Info, "771 UART initialized, clock: {0} Hz", clockFrequency);
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
rxFifo.Clear();
|
||
txFifo.Clear();
|
||
|
||
fsta = 0x00; // FIFO状态寄存器
|
||
frm_cnt = 0x00; //帧头校验正确计数
|
||
rbr = 0; // 接收FIFO剩余字节数
|
||
crc_rcnt = 0x00; //crc正确计数
|
||
crc_ecnt = 0x00; //crc错误计数
|
||
rstr = 0x00; // 复位/使能寄存器
|
||
full_cnt = 0x00; //fifo 满计数
|
||
|
||
RxfifoEnabled = true; //接收fifo使能
|
||
TxfifoEnabled = false; //发送fifo禁止
|
||
fifoTriggerLevel = 1;
|
||
currentBaudRate = 0;
|
||
|
||
IRQ.Set(false);
|
||
|
||
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: //接收FIFO,读操作
|
||
// 在接收FIFO寄存器中读取数据
|
||
value = (uint)ReadRBR();
|
||
this.Log(LogLevel.Info, "Read TBR_RBR: 0x{0:X2}", (ushort)value);
|
||
break;
|
||
|
||
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: //帧头校验正确计数,TODO如何修改
|
||
value = (uint)frm_cnt;
|
||
this.Log(LogLevel.Info, "Read FRM_CNT: {0}", value);
|
||
break;
|
||
|
||
case (long)Registers.RBR_FreeBytes: //接收FIFO剩余字节数
|
||
rbr = (ushort)rxFifo.Count;
|
||
value = (uint)rbr;
|
||
this.Log(LogLevel.Info, "Read RBR_FreeBytes: {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.RSTR: // 复位/使能
|
||
rstr = (byte)(value & 0xFF);
|
||
this.Log(LogLevel.Info, "Write RSTR: 0x{0:X2}", rstr);
|
||
if ((rstr & 0XFF) == RSTR_RES)
|
||
{
|
||
Reset();
|
||
}
|
||
break;
|
||
|
||
case (long)Registers.EXTI: //向外部提供写RXFIFO寄存器
|
||
//WriteRXFIFOData((byte)value);
|
||
break;
|
||
|
||
case (long)Registers.FSTA:
|
||
WriteFIFOStatus((byte)value); //向外部提供写FIFO状态,遥控数据是否接收完成
|
||
break;
|
||
|
||
default:
|
||
this.Log(LogLevel.Warning, "Write to unknown offset: 0x{0:X} = 0x{1:X2}", offset, value);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
public byte ReadRBR()
|
||
{
|
||
byte value = 0;
|
||
|
||
if (rxFifo.Count > 0)
|
||
{
|
||
value = rxFifo.Dequeue();
|
||
this.Log(LogLevel.Info, "Read: 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); // 接收FIFO空
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
public void WriteRXFIFOData(byte value)
|
||
{
|
||
// 向外部网络提供RXFIFO数据写入功能,低16位有效
|
||
|
||
if(RxfifoEnabled)
|
||
{
|
||
if(rxFifo.Count < RX_FIFO_SIZE)
|
||
{
|
||
rxFifo.Enqueue(value);
|
||
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
|
||
this.Log(LogLevel.Info, "External Write RXFIFO: 0x{0:X2} ('{1}')", value,
|
||
(value >= 32 && value < 127) ? (char)value : '.');
|
||
}
|
||
else
|
||
{
|
||
//待定
|
||
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
|
||
this.Log(LogLevel.Warning, "RX FIFO Already Full");
|
||
}
|
||
}
|
||
fsta = (byte)(fsta & (~FSTA_RGF) ); // 遥控数据接收未完成
|
||
}
|
||
|
||
public void WriteFIFOStatus(byte value)
|
||
{
|
||
// 向外部网络提供FIFO状态寄存器数据写入功能:遥控数据是否接收完成
|
||
//value=0x80为完成
|
||
fsta = (byte)(fsta | value); // 遥控数据接收完成状态位设置
|
||
this.Log(LogLevel.Info, "External Write RXFIFOStatus: 0x{0:X2} ('{1}')", value,
|
||
(value >= 32 && value < 127) ? (char)value : '.');
|
||
|
||
if ((value & FSTA_RGF) != 0)
|
||
{
|
||
frm_cnt++; //完整接收一帧,更新帧计数
|
||
}
|
||
}
|
||
|
||
|
||
public void WriteRXFIFODataString(string value)
|
||
{
|
||
// 向外部网络提供RXFIFO数据写入功能,value=0xAABB...
|
||
string data = value.StartsWith("0x",StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value;
|
||
this.Log(LogLevel.Info, "External Write RXFIFO: {0} ", value);
|
||
|
||
string tmpString;
|
||
byte tmpHex;
|
||
int i;
|
||
|
||
if(RxfifoEnabled)
|
||
{
|
||
if(data.Length % 2 != 0)
|
||
{
|
||
data = "0" + data; // 前面补0
|
||
}
|
||
|
||
if((data.Length/2) > (RX_FIFO_SIZE - rxFifo.Count)) //value超出fifo剩余
|
||
{
|
||
this.Log(LogLevel.Warning, "Data too long");
|
||
return;
|
||
}
|
||
|
||
for(i = 0; i < data.Length ; i+=2)
|
||
{
|
||
tmpString = data.Substring(i, 2);
|
||
tmpHex = Convert.ToByte(tmpString, 16);
|
||
rxFifo.Enqueue(tmpHex);
|
||
}
|
||
|
||
fsta = (byte)(fsta & (~FSTA_REMP)); //接收FIFO非空
|
||
fsta = (byte)(fsta | FSTA_RGF); //遥控数据接收完成状态位设置
|
||
frm_cnt++; //完整接收一帧,更新帧计数
|
||
|
||
if(rxFifo.Count == RX_FIFO_SIZE)
|
||
{
|
||
fsta = (byte)(fsta | FSTA_RFUL); //接收FIFO满
|
||
this.Log(LogLevel.Warning, "RX FIFO Already Full");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
|
||
}
|
||
|
||
public long Size => 0x80; //uart地址长度总空间
|
||
|
||
public GPIO IRQ { get; }
|
||
|
||
// ========================================
|
||
// 寄存器定义
|
||
// ========================================
|
||
|
||
private enum Registers : long
|
||
{
|
||
TBR_RBR = 0x00, // RBR接收FIFO
|
||
FSTA = 0x04, // FIFO状态寄存器
|
||
FRM_CNT = 0x1C, // 帧头校验正确计数
|
||
RBR_FreeBytes = 0x0C, // 接收FIFO剩余字节数
|
||
CRC_RCNT = 0x14, // 同步头,航天识别字,虚拟信道号,crc正确计数
|
||
CRC_ECNT = 0x18, //同步头,航天识别字,虚拟信道号正确,crc错误计数
|
||
RSTR = 0x7C, // 复位/使能 x55复位;其他使能
|
||
FULL_CNT = 0x10, // fifo 满计数
|
||
EXTI = 0x24 // 向外部提供读写FIFO接口
|
||
}
|
||
|
||
|
||
// FSTA FIFO状态寄存器
|
||
private const byte FSTA_REMP = 0x01; // 接收FIFO空
|
||
private const byte FSTA_RLHF= 0x02; // 接收FIFO半满
|
||
private const byte FSTA_RFUL = 0x04; // 接收FIFO满
|
||
private const byte FSTA_RGF = 0x08; // 接收FIFO门控空闲,遥控数据接收完成
|
||
|
||
|
||
// RSTR 复位/使能寄存器
|
||
private const byte RSTR_RES = 0x55; // 复位
|
||
private const byte RSTR_EN = 0xAA; // 使能
|
||
|
||
// 常量
|
||
private const int RX_FIFO_SIZE = 1024; // 接收FIFO_SIZE
|
||
private const int TX_FIFO_SIZE = 1024; // 发送FIFO_SIZE
|
||
|
||
// ========================================
|
||
// 私有字段
|
||
// ========================================
|
||
|
||
private readonly uint clockFrequency;
|
||
private uint currentBaudRate;
|
||
|
||
|
||
// 寄存器
|
||
|
||
private byte fsta; // FIFO状态寄存器
|
||
private ushort frm_cnt; // 帧头校验正确计数
|
||
private ushort rbr; // 接收FIFO剩余字节数
|
||
private ushort crc_rcnt; // crc正确计数
|
||
private ushort crc_ecnt; // crc错误计数
|
||
private byte rstr; // 复位/使能寄存器
|
||
private ushort full_cnt; // fifo 满计数
|
||
|
||
|
||
// FIFO
|
||
private readonly Queue<byte> rxFifo;
|
||
private readonly Queue<byte> txFifo;
|
||
private bool RxfifoEnabled;
|
||
private bool TxfifoEnabled;
|
||
private int fifoTriggerLevel;
|
||
}
|
||
}
|