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.Peripherals.Bus; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.Peripherals.CAN 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 20 public class MPFS_CAN : IKnownSize, IDoubleWordPeripheral, ICAN 21 { MPFS_CAN()22 public MPFS_CAN() 23 { 24 IRQ = new GPIO(); 25 InitializeBuffers(); 26 27 var registersMap = new Dictionary<long, DoubleWordRegister> 28 { 29 { 30 (long)ControllerRegisters.InterruptEnable, 31 new DoubleWordRegister(this) 32 .WithFlag(0, out interruptsEnabled, name: "Int_enbl") 33 .WithReservedBits(1, 1) 34 .WithTag("arb_loss_enbl", 2, 1) 35 .WithTag("ovr_load_enbl", 3, 1) 36 .WithTag("bit_err_enbl", 4, 1) 37 .WithTag("stuff_err_enbl", 5, 1) 38 .WithTag("ack_err_enbl", 6, 1) 39 .WithTag("form_err_enbl", 7, 1) 40 .WithTag("crc_err_enbl", 8, 1) 41 .WithTag("bus_off_enbl", 9, 1) 42 .WithFlag(10, out rxMessageLossEnabled, name: "rx_msg_loss") 43 .WithFlag(11, out txInterruptsEnabled, name: "tx_msg_enbl") 44 .WithFlag(12, out rxInterruptsEnabled, name: "rx_msg_enbl") 45 .WithTag("rtr_msg_enbl", 13, 1) 46 .WithTag("stuck_at_0_enbl", 14, 1) 47 .WithTag("sst_failure_enbl", 15, 1) 48 .WithReservedBits(16, 15) 49 }, 50 { 51 (long)ControllerRegisters.InterruptStatus, 52 new DoubleWordRegister(this) 53 .WithReservedBits(0, 2) 54 .WithTag("ARB_LOSS", 2, 1) 55 .WithTag("OVR_LOAD", 3, 1) 56 .WithTag("BIT_ERR", 4, 1) 57 .WithTag("STUFF_ERR", 5, 1) 58 .WithTag("ACK_ERR", 6, 1) 59 .WithTag("FORM_ERR", 7, 1) 60 .WithTag("CRC_ERR", 8, 1) 61 .WithTag("BUS_OFF", 9, 1) 62 .WithFlag(10, out rxMessageLossStatus, FieldMode.WriteOneToClear | FieldMode.Read, name: "RX_MSG_LOSS") 63 .WithFlag(11, out txMessageInterruptsStatus, FieldMode.WriteOneToClear | FieldMode.Read, name: "TX_MSG") 64 .WithFlag(12, out rxMessageInterruptsStatus, FieldMode.WriteOneToClear | FieldMode.Read, name: "RX_MSG") 65 .WithTag("RTR_MSG", 13, 1) 66 .WithTag("STUCK_AT_0", 14, 1) 67 .WithTag("SST_FAILURE", 15, 1) 68 .WithReservedBits(16, 15) 69 .WithWriteCallback((_, __) => UpdateInterrupts()) 70 }, 71 { 72 (long)ControllerRegisters.Config, 73 new DoubleWordRegister(this) 74 .WithTag("EDGE_MODE", 0, 1) 75 .WithTag("SAMPLING_MODE", 1, 1) 76 .WithTag("CFG_SJW", 2, 2) 77 .WithTag("AUTO_RESTART", 4, 1) 78 .WithTag("CFG_TSEG2", 5, 3) 79 .WithTag("CFG_TSEG1", 8, 4) 80 .WithTag("CFG_ARBITER", 12, 1) 81 .WithFlag(13, out swapEndian, name: "SWAP_ENDIAN") 82 .WithTag("ECR_MODE", 14, 1) 83 .WithReservedBits(15, 1) 84 .WithTag("CFG_BITRATE", 16, 15) 85 }, 86 { 87 (long)ControllerRegisters.Command, 88 new DoubleWordRegister(this) 89 .WithFlag(0, name: "RunStopMode") 90 .WithTag("ListenOnlyMode", 1, 1) 91 .WithTag("LoopbackTestMode", 2, 1) 92 .WithTag("SRAMTestMode", 3, 1) 93 .WithReservedBits(4, 12) 94 .WithTag("Revision_Control", 16, 15) 95 }, 96 { 97 (long)ControllerRegisters.TransmitBufferStatus, 98 new DoubleWordRegister(this) 99 .WithValueField(0, 32, FieldMode.Read, 100 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(txMessageBuffers.Select(x => x.IsRequestPending)), 101 name: "TX_STATUS") 102 }, 103 { 104 (long)ControllerRegisters.ReceiveBufferStatus, 105 new DoubleWordRegister(this) 106 .WithValueField(0, 32, FieldMode.Read, 107 valueProviderCallback: _ => BitHelper.GetValueFromBitsArray(rxMessageBuffers.Select(x => x.IsMessageAvailable)), 108 name: "RX_STATUS") 109 } 110 }; 111 112 for(int i = 0; i < BufferCount; ++i) 113 { 114 var index = i; 115 116 // TX buffer registers 117 registersMap.Add( 118 (long)ControllerRegisters.TransmitMessageControlCommand + shiftBetweenTxRegisters * index, 119 new DoubleWordRegister(this) 120 .WithFlag(0, 121 writeCallback: (_, val) => 122 { 123 if(val) 124 { 125 txMessageBuffers[index].IsRequestPending = true; 126 } 127 }, 128 valueProviderCallback: _ => txMessageBuffers[index].IsRequestPending, 129 name: "TxReq") 130 .WithTag("TxAbort", 1, 1) 131 .WithFlag(2, 132 writeCallback: (_, val) => txMessageBuffers[index].InterruptEnable = val, 133 valueProviderCallback: _ => txMessageBuffers[index].InterruptEnable, 134 name: "TxIntEbl") 135 .WithTag("WPN", 3, 1) 136 .WithValueField(16, 4, 137 writeCallback: (_, val) => txMessageBuffers[index].DataLengthCode = (uint)val, 138 valueProviderCallback: _ => txMessageBuffers[index].DataLengthCode, 139 name: "DLC") 140 .WithTag("IDE", 20, 1) 141 .WithTag("RTR", 21, 1) 142 .WithReservedBits(22, 1) 143 .WithTag("WPN", 23, 1) 144 .WithWriteCallback((_, val) => 145 { 146 if(txMessageBuffers[index].IsRequestPending) 147 { 148 RequestSendingMessage(txMessageBuffers[index]); 149 } 150 }) 151 ); 152 registersMap.Add( 153 (long)ControllerRegisters.TransmitMessageID + shiftBetweenTxRegisters * index, 154 new DoubleWordRegister(this) 155 .WithValueField(3, 29, 156 writeCallback: (_, val) => txMessageBuffers[index].MessageId = (uint)val, 157 valueProviderCallback: _ => txMessageBuffers[index].MessageId, 158 name: "ID") 159 ); 160 registersMap.Add( 161 (long)ControllerRegisters.TransmitMessageDataHigh + shiftBetweenTxRegisters * index, 162 new DoubleWordRegister(this) 163 .WithValueField(0, 32, FieldMode.Write, 164 writeCallback: (_, val) => txMessageBuffers[index].SetData((uint)val, Offset.High), 165 name: $"TX_MSG{index}_DATA_HIGH") 166 ); 167 registersMap.Add( 168 (long)ControllerRegisters.TransmitMessageDataLow + shiftBetweenTxRegisters * index, 169 new DoubleWordRegister(this) 170 .WithValueField(0, 32, FieldMode.Write, 171 writeCallback: (_, val) => txMessageBuffers[index].SetData((uint)val, Offset.Low), 172 name: $"TX_MSG{index}_DATA_LOW") 173 ); 174 175 // RX buffer registers 176 registersMap.Add( 177 (long)ControllerRegisters.ReceiveMessageControlCommand + shiftBetweenRxRegisters * index, 178 new DoubleWordRegister(this) 179 .WithFlag(0, FieldMode.WriteOneToClear | FieldMode.Read, 180 changeCallback: (_, __) => rxMessageBuffers[index].IsMessageAvailable = false, 181 valueProviderCallback: _ => rxMessageBuffers[index].IsMessageAvailable, 182 name: "MsgAv") 183 .WithTag("RTRP", 1, 1) 184 .WithTag("RTRabort", 2, 1) 185 .WithFlag(3, 186 writeCallback: (_, val) => rxMessageBuffers[index].Enabled = val, 187 valueProviderCallback: _ => rxMessageBuffers[index].Enabled, 188 name: "RxBufferEbl") 189 .WithFlag(4, 190 writeCallback: (_, val) => rxMessageBuffers[index].IsAutoreplyEnabled = val, 191 valueProviderCallback: _ => rxMessageBuffers[index].IsAutoreplyEnabled, 192 name: "RTRreply") 193 .WithFlag(5, 194 writeCallback: (_, val) => rxMessageBuffers[index].InterruptEnable = val, 195 valueProviderCallback: _ => rxMessageBuffers[index].InterruptEnable, 196 name: "RxIntEbl") 197 .WithFlag(6, 198 writeCallback: (_, val) => rxMessageBuffers[index].IsLinked = val, 199 valueProviderCallback: _ => rxMessageBuffers[index].IsLinked, 200 name: "LF") 201 .WithFlag(7, name: "WPNL") 202 .WithValueField(16, 4, FieldMode.Read, 203 writeCallback: (_, val) => rxMessageBuffers[index].DataLengthCode = (uint)val, 204 valueProviderCallback: _ => rxMessageBuffers[index].DataLengthCode, 205 name: "DLC") 206 .WithTag("IDE", 20, 1) 207 .WithTag("RTR", 21, 1) 208 .WithFlag(23, name: "WPNH") 209 ); 210 registersMap.Add( 211 (long)ControllerRegisters.ReceiveMessageID + shiftBetweenRxRegisters * index, 212 new DoubleWordRegister(this) 213 .WithValueField(3, 29, 214 writeCallback: (_, val) => rxMessageBuffers[index].MessageId = (uint)val, 215 valueProviderCallback: _ => rxMessageBuffers[index].MessageId, 216 name: "ID") 217 ); 218 registersMap.Add( 219 (long)ControllerRegisters.ReceiveMessageDataHigh + shiftBetweenRxRegisters * index, 220 new DoubleWordRegister(this) 221 .WithValueField(0, 32, FieldMode.Read, 222 valueProviderCallback: _ => rxMessageBuffers[index].GetData(swapEndian.Value, Offset.High), 223 name: $"RX_MSG{index}_DATA_HIGH") 224 ); 225 registersMap.Add( 226 (long)ControllerRegisters.ReceiveMessageDataLow + shiftBetweenRxRegisters * index, 227 new DoubleWordRegister(this) 228 .WithValueField(0, 32, FieldMode.Read, 229 valueProviderCallback: _ => rxMessageBuffers[index].GetData(swapEndian.Value, Offset.Low), 230 name: $"RX_MSG{index}_DATA_LOW") 231 ); 232 registersMap.Add( 233 (long)ControllerRegisters.ReceiveMessageAcceptanceMaskRegister + shiftBetweenRxRegisters * index, 234 new DoubleWordRegister(this) 235 .WithReservedBits(0, 1) 236 .WithTag("RTR", 1, 1) 237 .WithTag("IDE", 2, 1) 238 .WithValueField(3, 29, 239 writeCallback: (_, val) => rxMessageBuffers[index].AcceptanceMask = (uint)val, 240 valueProviderCallback: _ => rxMessageBuffers[index].AcceptanceMask, 241 name: "Identifier") 242 ); 243 registersMap.Add( 244 (long)ControllerRegisters.ReceiveMessageAcceptanceCodeRegister + shiftBetweenRxRegisters * index, 245 new DoubleWordRegister(this) 246 .WithReservedBits(0, 1) 247 .WithTag("RTR", 1, 1) 248 .WithTag("IDE", 2, 1) 249 .WithValueField(3, 29, 250 writeCallback: (_, val) => rxMessageBuffers[index].AcceptanceCode = (uint)val, 251 valueProviderCallback: _ => rxMessageBuffers[index].AcceptanceCode, 252 name: "Identifier") 253 ); 254 registersMap.Add( 255 (long)ControllerRegisters.ReceiveMessageAcceptanceMaskRegisterData + shiftBetweenRxRegisters * index, 256 new DoubleWordRegister(this) 257 .WithValueField(0, 16, 258 writeCallback: (_, val) => rxMessageBuffers[index].AcceptanceMaskData = (uint)val, 259 valueProviderCallback: _ => rxMessageBuffers[index].AcceptanceMaskData, 260 name: $"RX_MSG{index}_AMR_DATA") 261 ); 262 registersMap.Add( 263 (long)ControllerRegisters.ReceiveMessageAcceptanceCodeRegisterData + shiftBetweenRxRegisters * index, 264 new DoubleWordRegister(this) 265 .WithValueField(0, 16, 266 writeCallback: (_, val) => rxMessageBuffers[index].AcceptanceCodeData = (uint)val, 267 valueProviderCallback: _ => rxMessageBuffers[index].AcceptanceCodeData, 268 name: $"RX_MSG{index}_ACR_DATA") 269 ); 270 } 271 272 registers = new DoubleWordRegisterCollection(this, registersMap); 273 UpdateInterrupts(); 274 } 275 OnFrameReceived(CANMessageFrame message)276 public void OnFrameReceived(CANMessageFrame message) 277 { 278 var wasMessageSet = false; 279 var buffer = rxMessageBuffers.FirstOrDefault(x => x.CanReceiveMessage(message, swapEndian.Value)); 280 if(buffer != null) 281 { 282 wasMessageSet = buffer.TrySetMessage(message); 283 if(!wasMessageSet && buffer.IsLinked) 284 { 285 for(var index = buffer.BufferId + 1; index < BufferCount; index++) 286 { 287 if(rxMessageBuffers[index].AcceptanceMaskData == buffer.AcceptanceMaskData 288 && rxMessageBuffers[index].AcceptanceCodeData == buffer.AcceptanceCodeData) 289 { 290 wasMessageSet = rxMessageBuffers[index].TrySetMessage(message); 291 if(wasMessageSet || !rxMessageBuffers[index].IsLinked) 292 { 293 break; 294 } 295 } 296 } 297 } 298 } 299 if(wasMessageSet) 300 { 301 rxMessageInterruptsStatus.Value = true; 302 } 303 else 304 { 305 this.Log(LogLevel.Warning, "Could not find any empty mailbox for message: {0}", message); 306 rxMessageLossStatus.Value = true; 307 } 308 UpdateInterrupts(); 309 } 310 ReadDoubleWord(long offset)311 public uint ReadDoubleWord(long offset) 312 { 313 return registers.Read(offset); 314 } 315 WriteDoubleWord(long offset, uint value)316 public void WriteDoubleWord(long offset, uint value) 317 { 318 registers.Write(offset, value); 319 } 320 Reset()321 public void Reset() 322 { 323 registers.Reset(); 324 InitializeBuffers(); 325 UpdateInterrupts(); 326 } 327 328 public long Size => 0x1000; 329 public GPIO IRQ { get; private set; } 330 public event Action<CANMessageFrame> FrameSent; 331 InitializeBuffers()332 private void InitializeBuffers() 333 { 334 txMessageBuffers = new TxMessageBuffer[BufferCount]; 335 rxMessageBuffers = new RxMessageBuffer[BufferCount]; 336 for(uint i = 0; i < BufferCount; ++i) 337 { 338 txMessageBuffers[i] = new TxMessageBuffer(this, i); 339 rxMessageBuffers[i] = new RxMessageBuffer(this, i); 340 } 341 } 342 RequestSendingMessage(TxMessageBuffer buffer)343 private void RequestSendingMessage(TxMessageBuffer buffer) 344 { 345 var message = buffer.UnloadMessage(swapEndian.Value); 346 if(message == null) 347 { 348 this.Log(LogLevel.Error, "No message in mailbox."); 349 return; 350 } 351 352 var fs = FrameSent; 353 if(fs != null) 354 { 355 fs.Invoke(message); 356 } 357 else 358 { 359 this.Log(LogLevel.Warning, "FrameSent is not initialized. Am I connected to medium?"); 360 } 361 362 this.Log(LogLevel.Info, "Message sent: {0}.", message); 363 txMessageInterruptsStatus.Value = true; 364 UpdateInterrupts(); 365 } 366 UpdateInterrupts()367 private void UpdateInterrupts() 368 { 369 var rxInterrupt = rxInterruptsEnabled.Value && rxMessageBuffers.Any(x => x.IsMessageAvailable && x.InterruptEnable); 370 var txInterrupt = txInterruptsEnabled.Value && txMessageBuffers.Any(x => x.IsRequestPending && x.InterruptEnable); 371 372 var configInterrupt = (txInterruptsEnabled.Value && txMessageInterruptsStatus.Value) 373 || (rxInterruptsEnabled.Value && rxMessageInterruptsStatus.Value) 374 || (rxMessageLossEnabled.Value && rxMessageLossStatus.Value); 375 376 IRQ.Set(interruptsEnabled.Value && (rxInterrupt || txInterrupt || configInterrupt)); 377 } 378 379 private TxMessageBuffer[] txMessageBuffers; 380 private RxMessageBuffer[] rxMessageBuffers; 381 private IFlagRegisterField interruptsEnabled; 382 private IFlagRegisterField rxMessageLossEnabled; 383 private IFlagRegisterField txInterruptsEnabled; 384 private IFlagRegisterField rxInterruptsEnabled; 385 private IFlagRegisterField rxMessageLossStatus; 386 private IFlagRegisterField txMessageInterruptsStatus; 387 private IFlagRegisterField rxMessageInterruptsStatus; 388 private IFlagRegisterField swapEndian; 389 390 private readonly DoubleWordRegisterCollection registers; 391 392 private const int BufferCount = 32; 393 private const int shiftBetweenRxRegisters = 0x20; 394 private const int shiftBetweenTxRegisters = 0x10; 395 396 private abstract class MessageBuffer 397 { MessageBuffer(MPFS_CAN parent, uint id)398 protected MessageBuffer(MPFS_CAN parent, uint id) 399 { 400 this.parent = parent; 401 BufferId = id; 402 } 403 404 public uint BufferId { get; private set; } 405 public uint MessageId { get; set; } 406 public bool InterruptEnable { get; set; } 407 public uint DataLengthCode 408 { 409 get 410 { 411 return dataLengthCode; 412 } 413 set 414 { 415 if(value > MaxDataLength) 416 { 417 parent.Log(LogLevel.Warning, "Tried to set data length code to {0}, but it was truncated to {1}.", value, MaxDataLength); 418 dataLengthCode = MaxDataLength; 419 } 420 else 421 { 422 dataLengthCode = value; 423 } 424 } 425 } 426 427 protected readonly MPFS_CAN parent; 428 protected const int MaxDataLength = 8; 429 430 private uint dataLengthCode; 431 } 432 433 private class TxMessageBuffer : MessageBuffer 434 { TxMessageBuffer(MPFS_CAN parent, uint bufferId)435 public TxMessageBuffer(MPFS_CAN parent, uint bufferId) : base(parent, bufferId) 436 { 437 data = new byte[MaxDataLength]; 438 } 439 UnloadMessage(bool isSwapped)440 public CANMessageFrame UnloadMessage(bool isSwapped) 441 { 442 if(!HasValidData) 443 { 444 return null; 445 } 446 var messageData = isSwapped 447 ? data.Take((int)DataLengthCode).ToArray() 448 : data.Reverse().Take((int)DataLengthCode).ToArray(); 449 IsRequestPending = false; 450 HasValidData = false; 451 return new CANMessageFrame(MessageId, messageData); 452 } 453 SetData(uint registerValue, Offset offset)454 public void SetData(uint registerValue, Offset offset) 455 { 456 if(!HasValidData) 457 { 458 Array.Clear(data, 0, MaxDataLength); 459 HasValidData = true; 460 } 461 for(var i = 0; i < 4; ++i) 462 { 463 data[i + (int)offset] = (byte)BitHelper.GetValue(registerValue, (i * 8), 8); 464 } 465 } 466 467 public bool IsRequestPending { get; set; } 468 public bool HasValidData { get; set; } 469 470 private readonly byte[] data; 471 } 472 473 private class RxMessageBuffer : MessageBuffer 474 { RxMessageBuffer(MPFS_CAN parent, uint bufferId)475 public RxMessageBuffer(MPFS_CAN parent, uint bufferId) : base(parent, bufferId) 476 { 477 } 478 CanReceiveMessage(CANMessageFrame message, bool isSwapped)479 public bool CanReceiveMessage(CANMessageFrame message, bool isSwapped) 480 { 481 if(!Enabled) 482 { 483 return false; 484 } 485 // AMR/ACR data registers use filters based on 2 first message bytes 486 487 if(message.Data.Length == 0) 488 { 489 parent.Log(LogLevel.Warning, "Mailbox #{0} cannot receive message with no data.", BufferId); 490 return false; 491 } 492 var data = BitHelper.ToUInt16(message.Data, 0, reverse: isSwapped); 493 494 var hasIdFilteringPassed = (~AcceptanceMask & (message.Id ^ AcceptanceCode)) == 0; 495 var hasDataFilteringPassed = (~AcceptanceMaskData & (data ^ AcceptanceCodeData)) == 0; 496 return hasIdFilteringPassed && hasDataFilteringPassed; 497 } 498 TrySetMessage(CANMessageFrame message)499 public bool TrySetMessage(CANMessageFrame message) 500 { 501 if(IsMessageAvailable) 502 { 503 parent.Log(LogLevel.Warning, "Mailbox #{1} already contains a message: {0}", Message.ToString(), BufferId); 504 return false; 505 } 506 507 // http://www.seanano.org/projects/canport/27241003.pdf, p.28: 508 // "When the 82527 receives a message, the entire message identifier, the data length code (DLC) 509 // and the Direction bit are stored into the corresponding message object." 510 DataLengthCode = (uint)message.Data.Length; 511 MessageId = message.Id; 512 Message = message; 513 parent.Log(LogLevel.Info, "Received message {0} in mailbox #{1}", message, BufferId); 514 515 IsMessageAvailable = true; 516 return true; 517 } 518 GetData(bool isSwapped, Offset offset)519 public uint GetData(bool isSwapped, Offset offset) 520 { 521 if(Message == null) 522 { 523 return 0; 524 } 525 return BitHelper.ToUInt32(Message.Data, (int)offset, 4, isSwapped); 526 } 527 528 public bool Enabled { get; set; } 529 public bool IsLinked { get; set; } 530 public uint AcceptanceMaskData { get; set; } 531 public uint AcceptanceCodeData { get; set; } 532 public uint AcceptanceMask { get; set; } 533 public uint AcceptanceCode { get; set; } 534 public bool IsAutoreplyEnabled { get; set; } 535 public bool IsMessageAvailable { get; set; } 536 public CANMessageFrame Message { get; private set; } 537 } 538 539 private enum Offset 540 { 541 High = 4, 542 Low = 0 543 } 544 545 private enum ControllerRegisters 546 { 547 InterruptStatus = 0x000, 548 InterruptEnable = 0x004, 549 TransmitBufferStatus = 0x00C, 550 ReceiveBufferStatus = 0x008, 551 Command = 0x014, 552 Config = 0x018, 553 TransmitMessageControlCommand = 0x020, 554 TransmitMessageID = 0x024, 555 TransmitMessageDataHigh = 0x028, 556 TransmitMessageDataLow = 0x02C, 557 ReceiveMessageControlCommand = 0x220, 558 ReceiveMessageID = 0x224, 559 ReceiveMessageDataHigh = 0x228, 560 ReceiveMessageDataLow = 0x22C, 561 ReceiveMessageAcceptanceMaskRegister = 0x230, 562 ReceiveMessageAcceptanceCodeRegister = 0x234, 563 ReceiveMessageAcceptanceMaskRegisterData = 0x238, 564 ReceiveMessageAcceptanceCodeRegisterData = 0x23C 565 } 566 } 567 } 568