Files
simulation_Peripheral/SJA1000_CAN.cs
yaomingjun dc5c201933 更新 SJA1000_CAN.cs
修改缓冲区为队列
2026-04-17 08:55:34 +08:00

510 lines
18 KiB
C#
Raw Permalink Blame History

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