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