1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.CAN; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.CAN 17 { 18 public class LPC_CAN : BasicDoubleWordPeripheral, ICAN 19 { LPC_CAN(IMachine machine)20 public LPC_CAN(IMachine machine) : base(machine) 21 { 22 transmitBuffers = new TransmitBuffer[NumberOfTransmitBuffers]; 23 for(int i = 0; i < NumberOfTransmitBuffers; ++i) 24 { 25 transmitBuffers[i] = new TransmitBuffer 26 { 27 parent = this, 28 data = new IValueRegisterField[2], // 2 double words 29 }; 30 } 31 receiveFifo = new Queue<CANMessageFrame>(); 32 TxIRQ = new GPIO(); 33 RxIRQ = new GPIO(); 34 35 DefineRegisters(); 36 Reset(); 37 } 38 39 public GPIO TxIRQ { get; } 40 public GPIO RxIRQ { get; } 41 Reset()42 public override void Reset() 43 { 44 receiveFifo.Clear(); 45 TxIRQ.Unset(); 46 RxIRQ.Unset(); 47 base.Reset(); 48 } 49 OnFrameReceived(CANMessageFrame message)50 public void OnFrameReceived(CANMessageFrame message) 51 { 52 this.DebugLog("Received {0} bytes [{1}] on id 0x{2:X}", message.Data.Length, message.DataAsHex, message.Id); 53 receiveFifo.Enqueue(message); 54 UpdateInterrupts(); 55 } 56 57 public event Action<CANMessageFrame> FrameSent; 58 TransmitMessage(CANMessageFrame message)59 private void TransmitMessage(CANMessageFrame message) 60 { 61 var fs = FrameSent; 62 if(fs == null) 63 { 64 this.WarningLog("Tried to transmit {0} bytes [{1}] to id 0x{2:X} while not connected to the medium", 65 message.Data.Length, message.DataAsHex, message.Id); 66 return; 67 } 68 69 this.DebugLog("Transmitting {0} bytes [{1}] to id 0x{2:X}", message.Data.Length, message.DataAsHex, message.Id); 70 fs(message); 71 } 72 UpdateInterrupts()73 private void UpdateInterrupts() 74 { 75 receiveInterruptFlag.Value = receiveFifo.Any(); 76 77 var txIrqValue = transmitBuffers.Any(b => b.transmitInterruptEnable.Value && b.transmitInterruptFlag.Value); 78 var rxIrqValue = receiveInterruptEnable.Value && receiveInterruptFlag.Value; 79 if(TxIRQ.IsSet == txIrqValue && RxIRQ.IsSet == rxIrqValue) 80 { 81 return; 82 } 83 84 this.NoisyLog("Setting interrupts: TX={0}, RX={1}", txIrqValue, rxIrqValue); 85 TxIRQ.Set(txIrqValue); 86 RxIRQ.Set(rxIrqValue); 87 } 88 DefineRegisters()89 private void DefineRegisters() 90 { 91 Registers.OperatingMode.Define(this) 92 .WithTaggedFlag("RM", 0) 93 .WithTaggedFlag("LOM", 1) 94 .WithTaggedFlag("STM", 2) 95 .WithTaggedFlag("TPM", 3) 96 .WithTaggedFlag("SM", 4) 97 .WithTaggedFlag("RPM", 5) 98 .WithReservedBits(6, 1) 99 .WithTaggedFlag("TM", 7) 100 .WithReservedBits(8, 24); 101 102 Registers.Command.Define(this) 103 .WithFlag(0, mode: FieldMode.WriteOneToClear, name: "TR", writeCallback: (_, value) => 104 { 105 if(value) 106 { 107 var buffersToTransmit = transmitBuffers.Where(b => b.select.Value).OrderBy(b => b.priority.Value).ToList(); 108 if(!buffersToTransmit.Any()) 109 { 110 // If no buffers are selected with the STB bits, we always transmit buffer 1. 111 transmitBuffers[0].DoTransmission(); 112 // In this case we also force its transmit interrupt enable flag to on. 113 transmitBuffers[0].transmitInterruptEnable.Value = true; 114 } 115 else 116 { 117 foreach(var buffer in buffersToTransmit) 118 { 119 buffer.DoTransmission(); 120 } 121 } 122 } 123 }) 124 .WithTaggedFlag("AT", 1) 125 .WithFlag(2, mode: FieldMode.WriteOneToClear, name: "RRB", writeCallback: (_, value) => 126 { 127 if(value) 128 { 129 receiveFifo.TryDequeue(out var __); // Release Receive Buffer, discard the current message 130 } 131 }) 132 .WithTaggedFlag("CDO", 3) 133 .WithTaggedFlag("SRR", 4) 134 .WithFlag(5, out transmitBuffers[0].select, name: "STB1") 135 .WithFlag(6, out transmitBuffers[1].select, name: "STB2") 136 .WithFlag(7, out transmitBuffers[2].select, name: "STB3") 137 .WithReservedBits(8, 24) 138 .WithWriteCallback((_, __) => UpdateInterrupts()); 139 140 Registers.GlobalStatus.Define(this, 0x3C) 141 .WithFlag(0, mode: FieldMode.Read, name: "RBS", 142 valueProviderCallback: _ => receiveFifo.Any()) 143 .WithTaggedFlag("DOS", 1) 144 .WithTaggedFlag("TBS", 2) 145 .WithTaggedFlag("TCS", 3) 146 .WithTaggedFlag("RS", 4) 147 .WithTaggedFlag("TS", 5) 148 .WithTaggedFlag("ES", 6) 149 .WithTaggedFlag("BS", 7) 150 .WithReservedBits(8, 8) 151 .WithTag("RXERR", 16, 8) 152 .WithTag("TXERR", 24, 8); 153 154 Registers.InterruptCapture.Define(this) 155 .WithFlag(0, out receiveInterruptFlag, mode: FieldMode.Read, name: "RI") 156 .WithFlag(1, out transmitBuffers[0].transmitInterruptFlag, mode: FieldMode.ReadToClear, name: "TI1") 157 .WithTaggedFlag("EI", 2) 158 .WithTaggedFlag("DOI", 3) 159 .WithTaggedFlag("WUI", 4) 160 .WithTaggedFlag("EPI", 5) 161 .WithTaggedFlag("ALI", 6) 162 .WithTaggedFlag("BEI", 7) 163 .WithTaggedFlag("IDI", 8) 164 .WithFlag(9, out transmitBuffers[1].transmitInterruptFlag, mode: FieldMode.ReadToClear, name: "TI2") 165 .WithFlag(10, out transmitBuffers[2].transmitInterruptFlag, mode: FieldMode.ReadToClear, name: "TI3") 166 .WithReservedBits(11, 5) 167 .WithTag("ERRBIT4_0", 16, 5) 168 .WithTaggedFlag("ERRDIR", 21) 169 .WithTag("ERRC1_0", 22, 2) 170 .WithTag("ALCBIT", 24, 8) 171 .WithReadCallback((_, __) => UpdateInterrupts()); 172 173 Registers.InterruptEnable.Define(this) 174 .WithFlag(0, out receiveInterruptEnable, name: "RIE") 175 .WithFlag(1, out transmitBuffers[0].transmitInterruptEnable, name: "TIE1") 176 .WithTaggedFlag("EIE", 2) 177 .WithTaggedFlag("DOIE", 3) 178 .WithTaggedFlag("WUIE", 4) 179 .WithTaggedFlag("EPIE", 5) 180 .WithTaggedFlag("ALIE", 6) 181 .WithTaggedFlag("BEIE", 7) 182 .WithTaggedFlag("IDIE", 8) 183 .WithFlag(9, out transmitBuffers[1].transmitInterruptEnable, name: "TIE2") 184 .WithFlag(10, out transmitBuffers[2].transmitInterruptEnable, name: "TIE3") 185 .WithReservedBits(11, 21) 186 .WithWriteCallback((_, __) => UpdateInterrupts()); 187 188 Registers.BusTiming.Define(this, 0x1C0000) 189 .WithTag("BRP", 0, 10) 190 .WithReservedBits(10, 4) 191 .WithTag("SJW", 14, 2) 192 .WithTag("TESG1", 16, 4) 193 .WithTag("TESG2", 20, 3) 194 .WithTaggedFlag("SAM", 23) 195 .WithReservedBits(24, 8); 196 197 Registers.ErrorWarningLimit.Define(this, 0x60) 198 .WithTag("EWL", 0, 8) 199 .WithReservedBits(8, 24); 200 201 Registers.Status.Define(this, 0x3C3C3C) 202 .WithFlag(0, mode: FieldMode.Read, name: "RBS_1", 203 valueProviderCallback: _ => receiveFifo.Any()) // Same as RBS in GlobalStatus 204 .WithTaggedFlag("DOS_1", 1) 205 .WithTaggedFlag("TBS1_1", 2) 206 .WithTaggedFlag("TCS1_1", 3) 207 .WithTaggedFlag("RS_1", 4) 208 .WithTaggedFlag("TS1_1", 5) 209 .WithTaggedFlag("ES_1", 6) 210 .WithTaggedFlag("BS_1", 7) 211 .WithFlag(8, mode: FieldMode.Read, name: "RBS_2", 212 valueProviderCallback: _ => receiveFifo.Any()) // Same as RBS in GlobalStatus 213 .WithTaggedFlag("DOS_2", 9) 214 .WithTaggedFlag("TBS2_2", 10) 215 .WithTaggedFlag("TCS2_2", 11) 216 .WithTaggedFlag("RS_2", 12) 217 .WithTaggedFlag("TS2_2", 13) 218 .WithTaggedFlag("ES_2", 14) 219 .WithTaggedFlag("BS_2", 15) 220 .WithFlag(16, mode: FieldMode.Read, name: "RBS_3", 221 valueProviderCallback: _ => receiveFifo.Any()) // Same as RBS in GlobalStatus 222 .WithTaggedFlag("DOS_3", 17) 223 .WithTaggedFlag("TBS3_3", 18) 224 .WithTaggedFlag("TCS3_3", 19) 225 .WithTaggedFlag("RS_3", 20) 226 .WithTaggedFlag("TS3_3", 21) 227 .WithTaggedFlag("ES_3", 22) 228 .WithTaggedFlag("BS_3", 23) 229 .WithReservedBits(24, 8); 230 231 Registers.ReceiveFrameStatus.Define(this) 232 .WithTag("IDINDEX", 0, 10) 233 .WithTaggedFlag("BP", 10) 234 .WithReservedBits(11, 5) 235 .WithValueField(16, 4, mode: FieldMode.Read, name: "DLC", 236 valueProviderCallback: _ => (ulong)Math.Min(receiveFifo.FirstOrDefault()?.Data.Length ?? 0, FrameMaxLength)) 237 .WithReservedBits(20, 10) 238 .WithTaggedFlag("RTR", 30) 239 .WithTaggedFlag("FF", 31); 240 241 Registers.ReceivedIdentifier.Define(this) 242 .WithValueField(0, 11, mode: FieldMode.Read, name: "ID", 243 valueProviderCallback: _ => (ulong)receiveFifo.FirstOrDefault()?.Id) 244 .WithReservedBits(11, 21); 245 246 Registers.ReceivedDataBytes1To4.DefineMany(this, 2, stepInBytes: 4, setup: (register, registerIndex) => register 247 .WithValueFields(0, 8, 4, FieldMode.Read, 248 valueProviderCallback: (i, _) => receiveFifo.FirstOrDefault()?.Data.ElementAtOrDefault(registerIndex * 4 + i) ?? 0) 249 ); 250 251 // Each transmit buffer consists of these 4 registers 252 Registers.TransmitBuffer1FrameInfo.DefineMany(this, NumberOfTransmitBuffers, stepInBytes: TransmitBufferStride, setup: (register, i) => register 253 .WithValueField(0, 8, out transmitBuffers[i].priority, name: "PRIO") 254 .WithReservedBits(8, 8) 255 .WithValueField(16, 4, out transmitBuffers[i].dataLengthCode, name: "DLC") 256 .WithReservedBits(20, 10) 257 .WithTaggedFlag("RTR", 30) 258 .WithTaggedFlag("FF", 31) 259 ); 260 261 Registers.TransmitBuffer1Identifier.DefineMany(this, NumberOfTransmitBuffers, stepInBytes: TransmitBufferStride, setup: (register, i) => register 262 .WithValueField(0, 11, out transmitBuffers[i].id, name: "ID") 263 .WithReservedBits(11, 21) // 29-bit ID mode (FrameInfo.FF=1) is not implemented 264 ); 265 266 Registers.TransmitBuffer1DataBytes1To4.DefineMany(this, NumberOfTransmitBuffers, stepInBytes: TransmitBufferStride, setup: (register, i) => register 267 .WithValueField(0, 32, out transmitBuffers[i].data[0], name: "DATA[1:4]") 268 ); 269 270 Registers.TransmitBuffer1DataBytes5To8.DefineMany(this, NumberOfTransmitBuffers, stepInBytes: TransmitBufferStride, setup: (register, i) => register 271 .WithValueField(0, 32, out transmitBuffers[i].data[1], name: "DATA[5:8]") 272 ); 273 } 274 275 private readonly TransmitBuffer[] transmitBuffers; 276 private readonly Queue<CANMessageFrame> receiveFifo; 277 278 private IFlagRegisterField receiveInterruptFlag; 279 private IFlagRegisterField receiveInterruptEnable; 280 281 private const int NumberOfTransmitBuffers = 3; 282 private const int FrameMaxLength = 8; 283 private const int TransmitBufferStride = Registers.TransmitBuffer2FrameInfo - Registers.TransmitBuffer1FrameInfo; 284 285 private struct TransmitBuffer 286 { DoTransmissionAntmicro.Renode.Peripherals.CAN.LPC_CAN.TransmitBuffer287 public void DoTransmission() 288 { 289 var length = Math.Min((int)dataLengthCode.Value, FrameMaxLength); 290 if(length == 0) 291 { 292 return; 293 } 294 295 var bytes = data.SelectMany(d => BitConverter.GetBytes((uint)d.Value)).Take(length).ToArray(); 296 parent.TransmitMessage(new CANMessageFrame((uint)id.Value, bytes)); 297 transmitInterruptFlag.Value = true; 298 } 299 300 public LPC_CAN parent; 301 public IFlagRegisterField transmitInterruptEnable; 302 public IFlagRegisterField transmitInterruptFlag; 303 public IFlagRegisterField select; 304 public IValueRegisterField priority; 305 public IValueRegisterField id; 306 public IValueRegisterField dataLengthCode; 307 public IValueRegisterField[] data; 308 } 309 310 private enum Registers 311 { 312 OperatingMode = 0x00, 313 Command = 0x04, 314 GlobalStatus = 0x08, 315 InterruptCapture = 0x0c, 316 InterruptEnable = 0x10, 317 BusTiming = 0x14, 318 ErrorWarningLimit = 0x18, 319 Status = 0x1c, 320 // Receive buffer 321 ReceiveFrameStatus = 0x20, 322 ReceivedIdentifier = 0x24, 323 ReceivedDataBytes1To4 = 0x28, 324 ReceivedDataBytes5To8 = 0x2c, 325 // Transmit buffer #1 326 TransmitBuffer1FrameInfo = 0x30, 327 TransmitBuffer1Identifier = 0x34, 328 TransmitBuffer1DataBytes1To4 = 0x38, 329 TransmitBuffer1DataBytes5To8 = 0x3c, 330 // Transmit buffer #2 331 TransmitBuffer2FrameInfo = 0x40, 332 TransmitBuffer2Identifier = 0x44, 333 TransmitBuffer2DataBytes1To4 = 0x48, 334 TransmitBuffer2DataBytes5To8 = 0x4c, 335 // Transmit buffer #3 336 TransmitBuffer3FrameInfo = 0x50, 337 TransmitBuffer3Identifier = 0x54, 338 TransmitBuffer3DataBytes1To4 = 0x58, 339 TransmitBuffer3DataBytes5To8 = 0x5c, 340 } 341 } 342 } 343