更新 SJA1000_CAN.cs
修改缓冲区为队列
This commit is contained in:
990
SJA1000_CAN.cs
990
SJA1000_CAN.cs
@@ -1,480 +1,510 @@
|
|||||||
//
|
//
|
||||||
// SJA1000 CAN 控制器外设实现(简化版)
|
// SJA1000 CAN 控制器外设实现(简化版,支持发送/接收队列,提高速率)
|
||||||
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
|
// 仅支持 PeliCAN 模式的标准帧,不考虑 BasicCAN、扩展帧、错误处理、多帧、验收滤波和发送中断。
|
||||||
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
|
// 寄存器地址映射基于 PeliCAN 模式,包含 MOD, CMR, SR, IR, IER, BTR0, BTR1, OCR, RXERR, TXERR,
|
||||||
// 发送缓冲区(地址 16-26)、RBSA 和 CDR。命令寄存器位2=RRB,位3=CDO。
|
// 发送缓冲区(地址 16-26)、RBSA 和 CDR。命令寄存器位2=RRB,位3=CDO。
|
||||||
// 接收为单帧,无 FIFO,无数据溢出处理。
|
// 接收为单帧,无 FIFO,无数据溢出处理。
|
||||||
// 所有寄存器可随时读写,无复位模式限制。
|
// 所有寄存器可随时读写,无复位模式限制。
|
||||||
//
|
//
|
||||||
// author: Generated based on UART16550 template
|
// author: Generated based on UART16550 template
|
||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Antmicro.Renode.Core;
|
using Antmicro.Renode.Core;
|
||||||
using Antmicro.Renode.Logging;
|
using Antmicro.Renode.Logging;
|
||||||
using Antmicro.Renode.Peripherals.Bus;
|
using Antmicro.Renode.Peripherals.Bus;
|
||||||
using Antmicro.Renode.Utilities;
|
using Antmicro.Renode.Utilities;
|
||||||
using Antmicro.Renode.Time;
|
using Antmicro.Renode.Time;
|
||||||
|
|
||||||
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
namespace Antmicro.Renode.Peripherals.CustomPeripherals
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 简化版 SJA1000 CAN 控制器(PeliCAN 模式,仅标准帧)
|
/// 简化版 SJA1000 CAN 控制器(PeliCAN 模式,仅标准帧)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize
|
public class SJA1000_CAN : IDoubleWordPeripheral, IBytePeripheral, IKnownSize
|
||||||
{
|
{
|
||||||
public SJA1000_CAN(IMachine machine)
|
public SJA1000_CAN(IMachine machine)
|
||||||
{
|
{
|
||||||
this.machine = machine;
|
this.machine = machine;
|
||||||
IRQ = new GPIO();
|
IRQ = new GPIO();
|
||||||
|
|
||||||
txBuffer = new byte[11];
|
txBuffer = new byte[11];
|
||||||
rxBuffer = new byte[11];
|
rxBuffer = new byte[11];
|
||||||
|
txFrameQueue = new Queue<byte[]>(); // 新增:发送队列
|
||||||
Reset();
|
rxFrameQueue = new Queue<byte[]>(); // 新增:接收队列
|
||||||
}
|
|
||||||
|
Reset();
|
||||||
public void Reset()
|
}
|
||||||
{
|
|
||||||
mod = 0;
|
public void Reset()
|
||||||
ier = 0;
|
{
|
||||||
btr0 = 0;
|
mod = 0;
|
||||||
btr1 = 0;
|
ier = 0;
|
||||||
ocr = 0;
|
btr0 = 0;
|
||||||
rxerr = 0;
|
btr1 = 0;
|
||||||
txerr = 0;
|
ocr = 0;
|
||||||
rbsa = 0;
|
rxerr = 0;
|
||||||
cdr = 0;
|
txerr = 0;
|
||||||
|
rbsa = 0;
|
||||||
sr_tbs = 1; // 发送缓冲区初始为空闲
|
cdr = 0;
|
||||||
sr_rbs = 0; // 接收缓冲区初始为空
|
|
||||||
ir = 0;
|
sr_tbs = 1; // 发送缓冲区初始为空闲
|
||||||
|
sr_rbs = 0; // 接收缓冲区初始为空
|
||||||
Array.Clear(txBuffer, 0, txBuffer.Length);
|
ir = 0;
|
||||||
Array.Clear(rxBuffer, 0, rxBuffer.Length);
|
|
||||||
|
Array.Clear(txBuffer, 0, txBuffer.Length);
|
||||||
UpdateInterrupts();
|
Array.Clear(rxBuffer, 0, rxBuffer.Length);
|
||||||
|
txFrameQueue.Clear(); // 清空发送队列
|
||||||
this.Log(LogLevel.Info, "SJA1000 CAN controller reset (simplified)");
|
rxFrameQueue.Clear(); // 清空接收队列
|
||||||
}
|
|
||||||
|
UpdateInterrupts();
|
||||||
// ================ IBusPeripheral 接口实现 ================
|
|
||||||
|
this.Log(LogLevel.Info, "SJA1000 CAN controller reset (simplified)");
|
||||||
public uint ReadDoubleWord(long offset)
|
}
|
||||||
{
|
|
||||||
return ReadByte(offset);
|
// ================ IBusPeripheral 接口实现 ================
|
||||||
}
|
|
||||||
|
public uint ReadDoubleWord(long offset)
|
||||||
public void WriteDoubleWord(long offset, uint value)
|
{
|
||||||
{
|
return ReadByte(offset);
|
||||||
WriteByte(offset, (byte)value);
|
}
|
||||||
}
|
|
||||||
|
public void WriteDoubleWord(long offset, uint value)
|
||||||
public byte ReadByte(long offset)
|
{
|
||||||
{
|
WriteByte(offset, (byte)value);
|
||||||
byte value = 0;
|
}
|
||||||
switch ((Registers)offset)
|
|
||||||
{
|
public byte ReadByte(long offset)
|
||||||
case Registers.MOD:
|
{
|
||||||
value = mod;
|
byte value = 0;
|
||||||
this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value);
|
switch ((Registers)offset)
|
||||||
break;
|
{
|
||||||
|
case Registers.MOD:
|
||||||
case Registers.CMR:
|
value = mod;
|
||||||
// 命令寄存器只写,读返回0
|
this.Log(LogLevel.Info, "Read MOD: 0x{0:X2}", value);
|
||||||
this.Log(LogLevel.Info, "Read CMR (always 0)");
|
break;
|
||||||
value = 0;
|
|
||||||
break;
|
case Registers.CMR:
|
||||||
|
// 命令寄存器只写,读返回0
|
||||||
case Registers.SR:
|
this.Log(LogLevel.Info, "Read CMR (always 0)");
|
||||||
value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0
|
value = 0;
|
||||||
this.Log(LogLevel.Info, "Read SR: TBS={0}, RBS={1} -> 0x{2:X2}", sr_tbs, sr_rbs, value);
|
break;
|
||||||
break;
|
|
||||||
|
case Registers.SR:
|
||||||
case Registers.IR:
|
value = (byte)((sr_tbs << 2) | sr_rbs); // BS 恒为0
|
||||||
value = ir;
|
this.Log(LogLevel.Info, "Read SR: TBS={0}, RBS={1} -> 0x{2:X2}", sr_tbs, sr_rbs, value);
|
||||||
// 读 IR 后清零,但需要根据当前 RBS 重新评估 RI(电平触发)
|
break;
|
||||||
ir = 0;
|
|
||||||
UpdateIrFromRbs();
|
case Registers.IR:
|
||||||
UpdateInterrupts();
|
value = ir;
|
||||||
this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value);
|
// 读 IR 后清零,但需要根据当前 RBS 重新评估 RI(电平触发)
|
||||||
break;
|
ir = 0;
|
||||||
|
UpdateIrFromRbs();
|
||||||
case Registers.IER:
|
UpdateInterrupts();
|
||||||
value = ier;
|
this.Log(LogLevel.Info, "Read IR: 0x{0:X2}, cleared", value);
|
||||||
this.Log(LogLevel.Info, "Read IER: 0x{0:X2}", value);
|
break;
|
||||||
break;
|
|
||||||
|
case Registers.IER:
|
||||||
case Registers.BTR0:
|
value = ier;
|
||||||
value = btr0;
|
this.Log(LogLevel.Info, "Read IER: 0x{0:X2}", value);
|
||||||
break;
|
break;
|
||||||
case Registers.BTR1:
|
|
||||||
value = btr1;
|
case Registers.BTR0:
|
||||||
break;
|
value = btr0;
|
||||||
case Registers.OCR:
|
break;
|
||||||
value = ocr;
|
case Registers.BTR1:
|
||||||
break;
|
value = btr1;
|
||||||
case Registers.RXERR:
|
break;
|
||||||
value = rxerr;
|
case Registers.OCR:
|
||||||
break;
|
value = ocr;
|
||||||
case Registers.TXERR:
|
break;
|
||||||
value = txerr;
|
case Registers.RXERR:
|
||||||
break;
|
value = rxerr;
|
||||||
case Registers.RBSA:
|
break;
|
||||||
value = rbsa;
|
case Registers.TXERR:
|
||||||
break;
|
value = txerr;
|
||||||
case Registers.CDR:
|
break;
|
||||||
value = cdr;
|
case Registers.RBSA:
|
||||||
break;
|
value = rbsa;
|
||||||
|
break;
|
||||||
// 发送/接收缓冲区地址 16-26
|
case Registers.CDR:
|
||||||
case Registers.TX_FRAME_INFO:
|
value = cdr;
|
||||||
case Registers.TX_ID1:
|
break;
|
||||||
case Registers.TX_ID2:
|
|
||||||
case Registers.TX_DATA1:
|
// 发送/接收缓冲区地址 16-26
|
||||||
case Registers.TX_DATA2:
|
case Registers.TX_FRAME_INFO:
|
||||||
case Registers.TX_DATA3:
|
case Registers.TX_ID1:
|
||||||
case Registers.TX_DATA4:
|
case Registers.TX_ID2:
|
||||||
case Registers.TX_DATA5:
|
case Registers.TX_DATA1:
|
||||||
case Registers.TX_DATA6:
|
case Registers.TX_DATA2:
|
||||||
case Registers.TX_DATA7:
|
case Registers.TX_DATA3:
|
||||||
case Registers.TX_DATA8:
|
case Registers.TX_DATA4:
|
||||||
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
|
case Registers.TX_DATA5:
|
||||||
if (sr_rbs == 1)
|
case Registers.TX_DATA6:
|
||||||
{
|
case Registers.TX_DATA7:
|
||||||
// 接收缓冲区有数据时,读返回接收帧的内容
|
case Registers.TX_DATA8:
|
||||||
value = rxBuffer[bufIndex/4];
|
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
|
||||||
this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
if (sr_rbs == 1)
|
||||||
}
|
{
|
||||||
else
|
// 接收缓冲区有数据时,读返回接收帧的内容
|
||||||
{
|
value = rxBuffer[bufIndex/4];
|
||||||
//否则返回发送缓冲区的内容(通常无意义)
|
this.Log(LogLevel.Info, "Read RX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
||||||
value = txBuffer[bufIndex/4];
|
}
|
||||||
this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
else
|
||||||
|
{
|
||||||
}
|
//否则返回发送缓冲区的内容(通常无意义)
|
||||||
break;
|
value = txBuffer[bufIndex/4];
|
||||||
|
this.Log(LogLevel.Info, "Read TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
||||||
default:
|
|
||||||
// 未实现的寄存器返回0
|
}
|
||||||
this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset);
|
break;
|
||||||
value = 0;
|
|
||||||
break;
|
default:
|
||||||
}
|
// 未实现的寄存器返回0
|
||||||
return value;
|
this.Log(LogLevel.Info, "Read from unimplemented offset 0x{0:X}", offset);
|
||||||
}
|
value = 0;
|
||||||
|
break;
|
||||||
public void WriteByte(long offset, byte value)
|
}
|
||||||
{
|
return value;
|
||||||
switch ((Registers)offset)
|
}
|
||||||
{
|
|
||||||
case Registers.MOD:
|
public void WriteByte(long offset, byte value)
|
||||||
mod = value;
|
{
|
||||||
this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value);
|
switch ((Registers)offset)
|
||||||
break;
|
{
|
||||||
|
case Registers.MOD:
|
||||||
case Registers.CMR:
|
mod = value;
|
||||||
// 命令寄存器只写,处理命令
|
this.Log(LogLevel.Info, "Write MOD: 0x{0:X2}", value);
|
||||||
this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value);
|
break;
|
||||||
if ((value & CMR_TR) != 0)
|
|
||||||
{
|
case Registers.CMR:
|
||||||
// 发送请求
|
// 命令寄存器只写,处理命令
|
||||||
if (sr_tbs == 1)
|
this.Log(LogLevel.Info, "Write CMR: 0x{0:X2}", value);
|
||||||
{
|
if ((value & CMR_TR) != 0)
|
||||||
sr_tbs = 0; // 锁定发送缓冲区
|
{
|
||||||
/*** 测试 ***/
|
// 发送请求
|
||||||
GetTxBufferDataString();
|
if (sr_tbs == 1)
|
||||||
}
|
{
|
||||||
else
|
// 将当前 txBuffer 复制一份加入发送队列
|
||||||
{
|
var frame = new byte[11];
|
||||||
this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
|
Array.Copy(txBuffer, frame, 11);
|
||||||
}
|
lock (lockObject)
|
||||||
}
|
{
|
||||||
if ((value & CMR_RRB) != 0)
|
txFrameQueue.Enqueue(frame);
|
||||||
{
|
}
|
||||||
// 释放接收缓冲器
|
// 清空发送缓冲区,并立即释放 TBS,允许 CPU 继续写入下一帧
|
||||||
sr_rbs = 0;
|
Array.Clear(txBuffer, 0, txBuffer.Length);
|
||||||
UpdateIrFromRbs();
|
sr_tbs = 1;
|
||||||
UpdateInterrupts();
|
this.Log(LogLevel.Info, "Frame enqueued for transmission, queue size: {0}", txFrameQueue.Count);
|
||||||
this.Log(LogLevel.Info, "Receive buffer released");
|
}
|
||||||
}
|
else
|
||||||
if ((value & CMR_CDO) != 0)
|
{
|
||||||
{
|
this.Log(LogLevel.Warning, "Send request while TBS=0 ignored");
|
||||||
// 清除数据溢出(无操作)
|
}
|
||||||
this.Log(LogLevel.Info, "Clear data overflow (no effect)");
|
}
|
||||||
}
|
if ((value & CMR_RRB) != 0)
|
||||||
break;
|
{
|
||||||
|
// 释放接收缓冲器:尝试从接收队列中加载下一帧
|
||||||
case Registers.SR:
|
lock (lockObject)
|
||||||
if (sr_tbs == 1)
|
{
|
||||||
{
|
LoadNextRxFrame();
|
||||||
sr_tbs = 0;
|
}
|
||||||
}
|
this.Log(LogLevel.Info, "Receive buffer released");
|
||||||
else
|
}
|
||||||
{
|
if ((value & CMR_CDO) != 0)
|
||||||
sr_tbs = 1;
|
{
|
||||||
}
|
// 清除数据溢出(无操作)
|
||||||
if (sr_rbs == 1)
|
this.Log(LogLevel.Info, "Clear data overflow (no effect)");
|
||||||
{
|
}
|
||||||
sr_rbs = 0;
|
break;
|
||||||
}
|
|
||||||
else
|
case Registers.SR:
|
||||||
{
|
if (sr_tbs == 1)
|
||||||
sr_rbs = 1;
|
{
|
||||||
}
|
sr_tbs = 0;
|
||||||
break;
|
}
|
||||||
case Registers.IR:
|
else
|
||||||
// 只读,忽略写
|
{
|
||||||
this.Log(LogLevel.Warning, "Attempted write to read-only IR");
|
sr_tbs = 1;
|
||||||
break;
|
}
|
||||||
|
if (sr_rbs == 1)
|
||||||
case Registers.IER:
|
{
|
||||||
ier = (byte)(value & 0x01); // 只使用 bit0 (RIE)
|
sr_rbs = 0;
|
||||||
UpdateIrFromRbs();
|
}
|
||||||
UpdateInterrupts();
|
else
|
||||||
this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier);
|
{
|
||||||
break;
|
sr_rbs = 1;
|
||||||
|
}
|
||||||
case Registers.BTR0:
|
break;
|
||||||
btr0 = value;
|
case Registers.IR:
|
||||||
this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value);
|
// 只读,忽略写
|
||||||
break;
|
this.Log(LogLevel.Warning, "Attempted write to read-only IR");
|
||||||
case Registers.BTR1:
|
break;
|
||||||
btr1 = value;
|
|
||||||
this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value);
|
case Registers.IER:
|
||||||
break;
|
ier = (byte)(value & 0x01); // 只使用 bit0 (RIE)
|
||||||
case Registers.OCR:
|
UpdateIrFromRbs();
|
||||||
ocr = value;
|
UpdateInterrupts();
|
||||||
this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value);
|
this.Log(LogLevel.Info, "Write IER: 0x{0:X2}", ier);
|
||||||
break;
|
break;
|
||||||
case Registers.RXERR:
|
|
||||||
rxerr = value;
|
case Registers.BTR0:
|
||||||
this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value);
|
btr0 = value;
|
||||||
break;
|
this.Log(LogLevel.Info, "Write BTR0: 0x{0:X2}", value);
|
||||||
case Registers.TXERR:
|
break;
|
||||||
txerr = value;
|
case Registers.BTR1:
|
||||||
this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value);
|
btr1 = value;
|
||||||
break;
|
this.Log(LogLevel.Info, "Write BTR1: 0x{0:X2}", value);
|
||||||
case Registers.RBSA:
|
break;
|
||||||
rbsa = value;
|
case Registers.OCR:
|
||||||
this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value);
|
ocr = value;
|
||||||
break;
|
this.Log(LogLevel.Info, "Write OCR: 0x{0:X2}", value);
|
||||||
case Registers.CDR:
|
break;
|
||||||
cdr = value;
|
case Registers.RXERR:
|
||||||
this.Log(LogLevel.Info, "Write CDR: 0x{0:X2}", value);
|
rxerr = value;
|
||||||
break;
|
this.Log(LogLevel.Info, "Write RXERR: 0x{0:X2}", value);
|
||||||
|
break;
|
||||||
// 发送缓冲区写入
|
case Registers.TXERR:
|
||||||
case Registers.TX_FRAME_INFO:
|
txerr = value;
|
||||||
case Registers.TX_ID1:
|
this.Log(LogLevel.Info, "Write TXERR: 0x{0:X2}", value);
|
||||||
case Registers.TX_ID2:
|
break;
|
||||||
case Registers.TX_DATA1:
|
case Registers.RBSA:
|
||||||
case Registers.TX_DATA2:
|
rbsa = value;
|
||||||
case Registers.TX_DATA3:
|
this.Log(LogLevel.Info, "Write RBSA: 0x{0:X2}", value);
|
||||||
case Registers.TX_DATA4:
|
break;
|
||||||
case Registers.TX_DATA5:
|
case Registers.CDR:
|
||||||
case Registers.TX_DATA6:
|
cdr = value;
|
||||||
case Registers.TX_DATA7:
|
this.Log(LogLevel.Info, "Write CDR: 0x{0:X2}", value);
|
||||||
case Registers.TX_DATA8:
|
break;
|
||||||
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
|
|
||||||
if (sr_tbs == 1)
|
// 发送缓冲区写入
|
||||||
{
|
case Registers.TX_FRAME_INFO:
|
||||||
txBuffer[bufIndex/4] = value;
|
case Registers.TX_ID1:
|
||||||
this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
case Registers.TX_ID2:
|
||||||
}
|
case Registers.TX_DATA1:
|
||||||
else
|
case Registers.TX_DATA2:
|
||||||
{
|
case Registers.TX_DATA3:
|
||||||
this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored");
|
case Registers.TX_DATA4:
|
||||||
}
|
case Registers.TX_DATA5:
|
||||||
break;
|
case Registers.TX_DATA6:
|
||||||
|
case Registers.TX_DATA7:
|
||||||
default:
|
case Registers.TX_DATA8:
|
||||||
// 未实现的寄存器忽略写
|
int bufIndex = (int)(offset - (long)Registers.TX_FRAME_INFO);
|
||||||
this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value);
|
if (sr_tbs == 1)
|
||||||
break;
|
{
|
||||||
}
|
txBuffer[bufIndex/4] = value;
|
||||||
}
|
this.Log(LogLevel.Info, "Write TX buffer[{0}]: 0x{1:X2}", bufIndex/4, value);
|
||||||
|
}
|
||||||
// ================ 公共方法与事件 ================
|
else
|
||||||
|
{
|
||||||
|
this.Log(LogLevel.Warning, "Write to TX buffer while TBS=0 ignored");
|
||||||
|
}
|
||||||
|
break;
|
||||||
private void UpdateIrFromRbs()
|
|
||||||
{
|
default:
|
||||||
if (sr_rbs == 1)
|
// 未实现的寄存器忽略写
|
||||||
ir |= IR_RI;
|
this.Log(LogLevel.Info, "Write to unimplemented offset 0x{0:X} = 0x{1:X2}", offset, value);
|
||||||
else
|
break;
|
||||||
// ir &= (byte)~IR_RI;
|
}
|
||||||
ir = (byte)(ir & ~IR_RI);
|
}
|
||||||
}
|
|
||||||
|
// ================ 公共方法与事件 ================
|
||||||
private void UpdateInterrupts()
|
|
||||||
{
|
private void UpdateIrFromRbs()
|
||||||
bool interrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0);
|
{
|
||||||
IRQ.Set(interrupt);
|
if (sr_rbs == 1)
|
||||||
if (interrupt)
|
ir |= IR_RI;
|
||||||
{
|
else
|
||||||
machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ =>
|
ir = (byte)(ir & ~IR_RI);
|
||||||
{
|
}
|
||||||
IRQ.Set(false);
|
|
||||||
});
|
private void UpdateInterrupts()
|
||||||
this.Log(LogLevel.Info, "Interrupt asserted (RI)");
|
{
|
||||||
}
|
bool interrupt = ((ir & IR_RI) != 0) && ((ier & IER_RIE) != 0);
|
||||||
else
|
IRQ.Set(interrupt);
|
||||||
{
|
if (interrupt)
|
||||||
this.Log(LogLevel.Info, "Interrupt deasserted");
|
{
|
||||||
}
|
machine.ScheduleAction(TimeInterval.FromMicroseconds(1), _ =>
|
||||||
}
|
{
|
||||||
private readonly object lockObject = new object(); // 用于线程安全的锁对象
|
IRQ.Set(false);
|
||||||
|
});
|
||||||
public string GetTxBufferDataString()
|
this.Log(LogLevel.Info, "Interrupt asserted (RI)");
|
||||||
{
|
}
|
||||||
if(sr_tbs ==1)
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("sr_tbs=1");
|
this.Log(LogLevel.Info, "Interrupt deasserted");
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
lock (lockObject)
|
private readonly object lockObject = new object(); // 用于线程安全的锁对象
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
/// <summary>
|
||||||
for (int i = 0; i < txBuffer.Length; i++)
|
/// 获取发送队列中所有帧的字符串表示(每帧以空格分隔的十六进制字节,帧间用换行分隔)
|
||||||
{
|
/// 调用后清空发送队列。
|
||||||
if (i > 0) sb.Append(" ");
|
/// </summary>
|
||||||
sb.Append(txBuffer[i].ToString("X2"));
|
public string GetTxBufferDataString()
|
||||||
}
|
{
|
||||||
string result = sb.ToString();
|
lock (lockObject)
|
||||||
Console.WriteLine("GetTxBufferDataString returning: " + result);
|
{
|
||||||
Array.Clear(txBuffer, 0, txBuffer.Length);
|
if (txFrameQueue.Count == 0)
|
||||||
sr_tbs = 1;
|
{
|
||||||
return result;
|
Console.WriteLine("GetTxBufferDataString: no frames in TX queue");
|
||||||
}
|
return null;
|
||||||
}
|
}
|
||||||
|
var sb = new StringBuilder();
|
||||||
public void SendRxBufferDataString(string frameString)
|
while (txFrameQueue.Count > 0)
|
||||||
{
|
{
|
||||||
lock (lockObject)
|
var frame = txFrameQueue.Dequeue();
|
||||||
{
|
for (int i = 0; i < frame.Length; i++)
|
||||||
|
{
|
||||||
|
if (i > 0) sb.Append(" ");
|
||||||
if (string.IsNullOrWhiteSpace(frameString))
|
sb.Append(frame[i].ToString("X2"));
|
||||||
{
|
}
|
||||||
Console.WriteLine("ReceiveFrame: empty string, ignored");
|
sb.AppendLine(); // 帧间换行
|
||||||
return;
|
}
|
||||||
}
|
string result = sb.ToString().TrimEnd();
|
||||||
if (sr_rbs==1)
|
Console.WriteLine("GetTxBufferDataString returning: " + result);
|
||||||
{
|
return result;
|
||||||
Console.WriteLine("rxBuffer is full");
|
}
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
Array.Clear(rxBuffer, 0, rxBuffer.Length);
|
/// <summary>
|
||||||
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
/// 外部接口注入一帧接收数据(11字节的十六进制字符串,空格分隔)
|
||||||
int count = Math.Min(parts.Length, rxBuffer.Length);
|
/// 可多次调用以注入多帧,帧将存入接收队列。
|
||||||
|
/// </summary>
|
||||||
for (int i = 0; i < count; i++)
|
public void SendRxBufferDataString(string frameString)
|
||||||
{
|
{
|
||||||
string part = parts[i].Trim();
|
lock (lockObject)
|
||||||
if (byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
|
{
|
||||||
System.Globalization.CultureInfo.InvariantCulture, out byte b))
|
if (string.IsNullOrWhiteSpace(frameString))
|
||||||
{
|
{
|
||||||
rxBuffer[i] = b;
|
Console.WriteLine("SendRxBufferDataString: empty string, ignored");
|
||||||
}
|
return;
|
||||||
else
|
}
|
||||||
{
|
string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
Console.WriteLine($"ReceiveFrame: invalid hex byte '{part}' at index {i}, set to 0");
|
if (parts.Length != 11)
|
||||||
rxBuffer[i] = 0;
|
{
|
||||||
}
|
Console.WriteLine($"SendRxBufferDataString: expected 11 bytes, got {parts.Length}, ignored");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
sr_rbs = 1;
|
byte[] frame = new byte[11];
|
||||||
UpdateIrFromRbs();
|
for (int i = 0; i < 11; i++)
|
||||||
UpdateInterrupts();
|
{
|
||||||
|
string part = parts[i].Trim();
|
||||||
// 打印 rxBuffer 内容
|
if (!byte.TryParse(part, System.Globalization.NumberStyles.HexNumber,
|
||||||
var sb = new StringBuilder();
|
System.Globalization.CultureInfo.InvariantCulture, out byte b))
|
||||||
sb.Append("RX Buffer after receive: ");
|
{
|
||||||
for (int i = 0; i < rxBuffer.Length; i++)
|
Console.WriteLine($"SendRxBufferDataString: invalid hex byte '{part}' at index {i}, set to 0");
|
||||||
{
|
b = 0;
|
||||||
if (i > 0) sb.Append(" ");
|
}
|
||||||
sb.Append(rxBuffer[i].ToString("X2"));
|
frame[i] = b;
|
||||||
}
|
}
|
||||||
Console.WriteLine(sb.ToString());
|
rxFrameQueue.Enqueue(frame);
|
||||||
|
Console.WriteLine($"Frame enqueued to RX queue, size: {rxFrameQueue.Count}");
|
||||||
Console.WriteLine($"Frame received from string: {frameString}");
|
|
||||||
}
|
// 如果当前接收缓冲区空闲,立即加载第一帧
|
||||||
}
|
if (sr_rbs == 0)
|
||||||
// ================ 属性 ================
|
{
|
||||||
|
LoadNextRxFrame();
|
||||||
public long Size => 0x80; // 地址范围 0-31
|
}
|
||||||
|
}
|
||||||
public GPIO IRQ { get; }
|
}
|
||||||
|
|
||||||
// ================ 寄存器枚举 ================
|
// 从接收队列中加载下一帧到 rxBuffer,并更新状态
|
||||||
|
private void LoadNextRxFrame()
|
||||||
private enum Registers : long
|
{
|
||||||
{
|
if (rxFrameQueue.Count > 0)
|
||||||
MOD = 0x00,
|
{
|
||||||
CMR = 0x04,
|
var frame = rxFrameQueue.Dequeue();
|
||||||
SR = 0x08,
|
Array.Copy(frame, rxBuffer, 11);
|
||||||
IR = 0x0C,
|
sr_rbs = 1;
|
||||||
IER = 0x10,
|
UpdateIrFromRbs();
|
||||||
BTR0 = 0x18,
|
UpdateInterrupts();
|
||||||
BTR1 = 0x1C,
|
Console.WriteLine("Loaded next RX frame into buffer, queue remaining: {0}", rxFrameQueue.Count);
|
||||||
OCR = 0x20,
|
}
|
||||||
RXERR = 0x38, // 14
|
else
|
||||||
TXERR = 0x3C, // 15
|
{
|
||||||
TX_FRAME_INFO = 0x40, // 16
|
sr_rbs = 0;
|
||||||
TX_ID1 = 0x44,
|
UpdateIrFromRbs();
|
||||||
TX_ID2 = 0x48,
|
UpdateInterrupts();
|
||||||
TX_DATA1 = 0x4C,
|
Console.WriteLine("RX queue empty, buffer cleared");
|
||||||
TX_DATA2 = 0x50,
|
}
|
||||||
TX_DATA3 = 0x54,
|
}
|
||||||
TX_DATA4 = 0x58,
|
|
||||||
TX_DATA5 = 0x5C,
|
// ================ 属性 ================
|
||||||
TX_DATA6 = 0x60,
|
|
||||||
TX_DATA7 = 0x64,
|
public long Size => 0x80; // 地址范围 0-31
|
||||||
TX_DATA8 = 0x68, // 26
|
|
||||||
RBSA = 0x78, // 30
|
public GPIO IRQ { get; }
|
||||||
CDR = 0x7C, // 31
|
|
||||||
|
// ================ 寄存器枚举 ================
|
||||||
}
|
|
||||||
|
private enum Registers : long
|
||||||
// ================ 常量位定义 ================
|
{
|
||||||
|
MOD = 0x00,
|
||||||
private const byte CMR_TR = 0x01; // 发送请求 (bit0)
|
CMR = 0x04,
|
||||||
private const byte CMR_RRB = 0x04; // 释放接收缓冲器 (bit2)
|
SR = 0x08,
|
||||||
private const byte CMR_CDO = 0x08; // 清除数据溢出 (bit3)
|
IR = 0x0C,
|
||||||
|
IER = 0x10,
|
||||||
private const byte SR_BS = 0x80; // 总线状态 (bit7) - 本模拟中恒0
|
BTR0 = 0x18,
|
||||||
private const byte SR_TBS = 0x04; // 发送缓冲器状态 (bit2)
|
BTR1 = 0x1C,
|
||||||
private const byte SR_RBS = 0x01; // 接收缓冲器状态 (bit0)
|
OCR = 0x20,
|
||||||
|
RXERR = 0x38, // 14
|
||||||
private const byte IR_RI = 0x01; // 接收中断 (bit0)
|
TXERR = 0x3C, // 15
|
||||||
|
TX_FRAME_INFO = 0x40, // 16
|
||||||
private const byte IER_RIE = 0x01; // 接收中断使能 (bit0)
|
TX_ID1 = 0x44,
|
||||||
|
TX_ID2 = 0x48,
|
||||||
// ================ 私有字段 ================
|
TX_DATA1 = 0x4C,
|
||||||
|
TX_DATA2 = 0x50,
|
||||||
private readonly IMachine machine;
|
TX_DATA3 = 0x54,
|
||||||
|
TX_DATA4 = 0x58,
|
||||||
// 寄存器存储
|
TX_DATA5 = 0x5C,
|
||||||
private byte mod;
|
TX_DATA6 = 0x60,
|
||||||
private byte ier;
|
TX_DATA7 = 0x64,
|
||||||
private byte btr0, btr1;
|
TX_DATA8 = 0x68, // 26
|
||||||
private byte ocr;
|
RBSA = 0x78, // 30
|
||||||
private byte rxerr, txerr;
|
CDR = 0x7C, // 31
|
||||||
private byte rbsa;
|
|
||||||
private byte cdr;
|
}
|
||||||
|
|
||||||
// 状态位
|
// ================ 常量位定义 ================
|
||||||
private byte sr_tbs; // 1=空闲
|
|
||||||
private byte sr_rbs; // 1=有数据
|
private const byte CMR_TR = 0x01; // 发送请求 (bit0)
|
||||||
|
private const byte CMR_RRB = 0x04; // 释放接收缓冲器 (bit2)
|
||||||
private byte ir; // 仅 bit0 有效
|
private const byte CMR_CDO = 0x08; // 清除数据溢出 (bit3)
|
||||||
|
|
||||||
private readonly byte[] txBuffer; // 地址16-26
|
private const byte SR_BS = 0x80; // 总线状态 (bit7) - 本模拟中恒0
|
||||||
private readonly byte[] rxBuffer; // 当前接收帧
|
private const byte SR_TBS = 0x04; // 发送缓冲器状态 (bit2)
|
||||||
}
|
private const byte SR_RBS = 0x01; // 接收缓冲器状态 (bit0)
|
||||||
}
|
|
||||||
|
private const byte IR_RI = 0x01; // 接收中断 (bit0)
|
||||||
|
|
||||||
|
private const byte IER_RIE = 0x01; // 接收中断使能 (bit0)
|
||||||
|
|
||||||
|
// ================ 私有字段 ================
|
||||||
|
|
||||||
|
private readonly IMachine machine;
|
||||||
|
|
||||||
|
// 寄存器存储
|
||||||
|
private byte mod;
|
||||||
|
private byte ier;
|
||||||
|
private byte btr0, btr1;
|
||||||
|
private byte ocr;
|
||||||
|
private byte rxerr, txerr;
|
||||||
|
private byte rbsa;
|
||||||
|
private byte cdr;
|
||||||
|
|
||||||
|
// 状态位
|
||||||
|
private byte sr_tbs; // 1=空闲
|
||||||
|
private byte sr_rbs; // 1=有数据
|
||||||
|
|
||||||
|
private byte ir; // 仅 bit0 有效
|
||||||
|
|
||||||
|
private readonly byte[] txBuffer; // 临时发送缓冲区(单帧)
|
||||||
|
private readonly byte[] rxBuffer; // 当前接收帧(单帧)
|
||||||
|
|
||||||
|
private readonly Queue<byte[]> txFrameQueue; // 发送队列
|
||||||
|
private readonly Queue<byte[]> rxFrameQueue; // 接收队列
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user