// // 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 { /// /// 简化版 SJA1000 CAN 控制器(PeliCAN 模式,仅标准帧) /// 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]; 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); 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) { sr_tbs = 0; // 锁定发送缓冲区 /*** 测试 ***/ GetTxBufferDataString(); } else { this.Log(LogLevel.Warning, "Send request while TBS=0 ignored"); } } if ((value & CMR_RRB) != 0) { // 释放接收缓冲器 sr_rbs = 0; UpdateIrFromRbs(); UpdateInterrupts(); 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_RI; 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(); // 用于线程安全的锁对象 public string GetTxBufferDataString() { if(sr_tbs ==1) { Console.WriteLine("sr_tbs=1"); return null; } lock (lockObject) { var sb = new StringBuilder(); for (int i = 0; i < txBuffer.Length; i++) { if (i > 0) sb.Append(" "); sb.Append(txBuffer[i].ToString("X2")); } string result = sb.ToString(); Console.WriteLine("GetTxBufferDataString returning: " + result); Array.Clear(txBuffer, 0, txBuffer.Length); sr_tbs = 1; return result; } } public void SendRxBufferDataString(string frameString) { lock (lockObject) { if (string.IsNullOrWhiteSpace(frameString)) { Console.WriteLine("ReceiveFrame: empty string, ignored"); return; } if (sr_rbs==1) { Console.WriteLine("rxBuffer is full"); return; } Array.Clear(rxBuffer, 0, rxBuffer.Length); string[] parts = frameString.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); int count = Math.Min(parts.Length, rxBuffer.Length); for (int i = 0; i < count; i++) { string part = parts[i].Trim(); if (byte.TryParse(part, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out byte b)) { rxBuffer[i] = b; } else { Console.WriteLine($"ReceiveFrame: invalid hex byte '{part}' at index {i}, set to 0"); rxBuffer[i] = 0; } } sr_rbs = 1; UpdateIrFromRbs(); UpdateInterrupts(); // 打印 rxBuffer 内容 var sb = new StringBuilder(); sb.Append("RX Buffer after receive: "); for (int i = 0; i < rxBuffer.Length; i++) { if (i > 0) sb.Append(" "); sb.Append(rxBuffer[i].ToString("X2")); } Console.WriteLine(sb.ToString()); Console.WriteLine($"Frame received from string: {frameString}"); } } // ================ 属性 ================ 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; // 地址16-26 private readonly byte[] rxBuffer; // 当前接收帧 } }