1 //
2 // Copyright (c) 2010-2025 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.Migrant;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Debugging;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Peripherals.I2C;
18 using Antmicro.Renode.Peripherals.SPI;
19 using Antmicro.Renode.Peripherals.UART;
20 using Antmicro.Renode.Time;
21 using Antmicro.Renode.Utilities;
22 
23 namespace Antmicro.Renode.Peripherals.UART
24 {
25     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
26     public class RenesasRA8M1_SCI : IUART, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize,
27         IPeripheralContainer<IUART, NullRegistrationPoint>,
28         IPeripheralContainer<ISPIPeripheral, NullRegistrationPoint>,
29         IPeripheralContainer<II2CPeripheral, NumberRegistrationPoint<int>>
30     {
RenesasRA8M1_SCI(IMachine machine, ulong frequency)31         public RenesasRA8M1_SCI(IMachine machine, ulong frequency)
32         {
33             this.machine = machine;
34             this.frequency = frequency;
35 
36             ReceiveIRQ = new GPIO();
37             TransmitIRQ = new GPIO();
38             TransmitEndIRQ = new GPIO();
39 
40             receiveQueue = new Queue<ushort>();
41             iicTransmitQueue = new Queue<byte>();
42 
43             uartContainer = new NullRegistrationPointContainerHelper<IUART>(machine, this);
44             spiContainer = new NullRegistrationPointContainerHelper<ISPIPeripheral>(machine, this);
45             i2cContainer = new SimpleContainerHelper<II2CPeripheral>(machine, this);
46 
47             RegistersCollection = new DoubleWordRegisterCollection(this);
48             DefineRegisters();
49 
50             Reset();
51         }
52 
ReadDoubleWord(long offset)53         public uint ReadDoubleWord(long offset)
54         {
55             return RegistersCollection.Read(offset);
56         }
57 
WriteDoubleWord(long offset, uint value)58         public void WriteDoubleWord(long offset, uint value)
59         {
60             RegistersCollection.Write(offset, value);
61         }
62 
WriteChar(byte value)63         public void WriteChar(byte value)
64         {
65             if(!receiveEnabled.Value)
66             {
67                 this.Log(LogLevel.Warning, "Receiving is not enabled, ignoring byte 0x{0:X}", value);
68                 return;
69             }
70 
71             receiveQueue.Enqueue(value);
72             UpdateInterrupts();
73         }
74 
Reset()75         public void Reset()
76         {
77             receiveQueue.Clear();
78             iicTransmitQueue.Clear();
79 
80             ReceiveIRQ.Unset();
81             TransmitIRQ.Unset();
82             TransmitEndIRQ.Unset();
83             RegistersCollection.Reset();
84 
85             currentPeripheralMode = PeripheralMode.UART;
86         }
87 
GetRegistrationPoints(ISPIPeripheral peripheral)88         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(ISPIPeripheral peripheral)
89         {
90             return spiContainer.GetRegistrationPoints(peripheral);
91         }
92 
Register(ISPIPeripheral peripheral, NullRegistrationPoint registrationPoint)93         public void Register(ISPIPeripheral peripheral, NullRegistrationPoint registrationPoint)
94         {
95             spiContainer.Register(peripheral, registrationPoint);
96         }
97 
Unregister(ISPIPeripheral peripheral)98         public void Unregister(ISPIPeripheral peripheral)
99         {
100             spiContainer.Unregister(peripheral);
101         }
102 
GetRegistrationPoints(IUART peripheral)103         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(IUART peripheral)
104         {
105             return uartContainer.GetRegistrationPoints(peripheral);
106         }
107 
Register(IUART peripheral, NullRegistrationPoint registrationPoint)108         public void Register(IUART peripheral, NullRegistrationPoint registrationPoint)
109         {
110             uartContainer.Register(peripheral, registrationPoint);
111         }
112 
Unregister(IUART peripheral)113         public void Unregister(IUART peripheral)
114         {
115             uartContainer.Unregister(peripheral);
116         }
117 
Register(II2CPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)118         public virtual void Register(II2CPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)
119         {
120             i2cContainer.Register(peripheral, registrationPoint);
121         }
122 
Unregister(II2CPeripheral peripheral)123         public virtual void Unregister(II2CPeripheral peripheral)
124         {
125             i2cContainer.Unregister(peripheral);
126         }
127 
GetRegistrationPoints(II2CPeripheral peripheral)128         public IEnumerable<NumberRegistrationPoint<int>> GetRegistrationPoints(II2CPeripheral peripheral)
129         {
130             return i2cContainer.GetRegistrationPoints(peripheral);
131         }
132 
133         IEnumerable<IRegistered<IUART, NullRegistrationPoint>> IPeripheralContainer<IUART, NullRegistrationPoint>.Children => uartContainer.Children;
134         IEnumerable<IRegistered<ISPIPeripheral, NullRegistrationPoint>> IPeripheralContainer<ISPIPeripheral, NullRegistrationPoint>.Children => spiContainer.Children;
135         IEnumerable<IRegistered<II2CPeripheral, NumberRegistrationPoint<int>>> IPeripheralContainer<II2CPeripheral, NumberRegistrationPoint<int>>.Children => i2cContainer.Children;
136 
137         public DoubleWordRegisterCollection RegistersCollection { get; }
138 
139         public GPIO ReceiveIRQ { get; }
140         public GPIO TransmitIRQ { get; }
141         public GPIO TransmitEndIRQ { get; }
142 
143         public uint BaudRate
144         {
145             get
146             {
147                 var n = clockSelect.Value == 0 ? 1UL : 2UL << (2 * (ushort)clockSelect.Value - 1);
148                 return (uint)(frequency / (64UL * n * bitRate.Value)) - 1;
149             }
150         }
151 
152         public Bits StopBits => useTwoStopBits.Value ? Bits.Two : Bits.One;
153 
154         public Parity ParityBit
155         {
156             get
157             {
158                 if(!parityEnabled.Value)
159                 {
160                     return Parity.None;
161                 }
162 
163                 return useOddParity.Value ? Parity.Odd : Parity.Even;
164             }
165         }
166 
167         public long Size => 0x100;
168 
169         [field: Transient]
170         public event Action<byte> CharReceived;
171 
UpdateInterrupts()172         private void UpdateInterrupts()
173         {
174             if(currentPeripheralMode == PeripheralMode.IIC)
175             {
176                 UpdateInterruptsInIICMode();
177                 return;
178             }
179             var rxState = receiveInterruptEnabled.Value && IsReceiveDataFull;
180             var txState = transmitInterruptEnabled.Value && IsDataTransmitted;
181             var teState = transmitEndInterruptEnabled.Value;
182             this.DebugLog("ReceiveIRQ: {0}blinking, TransmitIRQ: {1}blinking, TransmitEndIRQ: {2}blinking", rxState ? "" : "not ", txState ? "" : "not ", teState ? "" : "not ");
183 
184             if(rxState)
185             {
186                 ReceiveIRQ.Blink();
187             }
188             if(txState)
189             {
190                 TransmitIRQ.Blink();
191             }
192             if(teState)
193             {
194                 TransmitEndIRQ.Blink();
195             }
196         }
197 
UpdateInterruptsInIICMode()198         private void UpdateInterruptsInIICMode()
199         {
200             // This does not update the Transmit/Receive interrupts, as there are not status flags in this mode and they are expected just to blink
201             bool teState = transmitEndInterruptEnabled.Value && conditionCompletedFlag.Value;
202             this.DebugLog("TransmitEndIRQ: {0}.", teState ? "set" : "unset");
203 
204             if(teState)
205             {
206                 TransmitEndIRQ.Blink();
207             }
208         }
209 
BlinkTxIRQ()210         private void BlinkTxIRQ()
211         {
212             DebugHelper.Assert(currentPeripheralMode == PeripheralMode.IIC);
213 
214             if(transmitInterruptEnabled.Value)
215             {
216                 TransmitIRQ.Blink();
217             }
218         }
219 
FlushIICTransmitQueue()220         private void FlushIICTransmitQueue()
221         {
222             if(iicTransmitQueue.Count != 0)
223             {
224                 selectedIICSlave.Write(iicTransmitQueue.ToArray());
225                 iicTransmitQueue.Clear();
226             }
227         }
228 
EmulateIICStartStopCondition(IICCondition condition)229         private void EmulateIICStartStopCondition(IICCondition condition)
230         {
231             conditionCompletedFlag.Value = true;
232             if(condition == IICCondition.Stop)
233             {
234                 if(selectedIICSlave == null)
235                 {
236                     this.WarningLog("No slave selected. This condition will have no effect");
237                     return;
238                 }
239 
240                 switch(iicDirection)
241                 {
242                     case IICTransactionDirection.Write:
243                         FlushIICTransmitQueue();
244                         break;
245                     case IICTransactionDirection.Read:
246                         receiveQueue.Clear();
247                         break;
248                     default:
249                         throw new ArgumentException("Unknown IIC direction");
250                 }
251                 selectedIICSlave.FinishTransmission();
252                 selectedIICSlave = null;
253             }
254             else if(condition == IICCondition.Restart)
255             {
256                 //Flush the register address
257                 FlushIICTransmitQueue();
258             }
259 
260             iicState = IICState.Idle;
261             iicDirection = IICTransactionDirection.Unset;
262             UpdateInterruptsInIICMode();
263         }
264 
SetPeripheralMode()265         private void SetPeripheralMode()
266         {
267             switch(nonSmartCommunicationMode.Value)
268             {
269                 case CommunicationMode.SimpleI2C:
270                     if(i2cContainer.ChildCollection.Count != 0)
271                     {
272                         currentPeripheralMode = PeripheralMode.IIC;
273                         return;
274                     }
275                     break;
276                 case CommunicationMode.SimpleSPI:
277                     if(spiContainer.RegisteredPeripheral != null)
278                     {
279                        currentPeripheralMode = PeripheralMode.SPI;
280                        return;
281                     }
282                     break;
283                 default:
284                     break;
285             }
286             currentPeripheralMode = PeripheralMode.UART;
287         }
288 
DefineRegisters()289         private void DefineRegisters()
290         {
291             Registers.ReceiveData.Define(this)
292                 .WithReservedBits(29, 3)
293                 .WithTag("FER", 28, 1)
294                 .WithTag("PER", 27, 1)
295                 .WithReservedBits(25, 2)
296                 .WithTag("ORER", 24, 1)
297                 .WithReservedBits(13, 11)
298                 .WithTag("FFER", 12, 1)
299                 .WithTag("FPER", 11, 1)
300                 .WithTag("DR", 10, 1)
301                 .WithTag("MPB", 9, 1)
302                 .WithValueField(0, 9, FieldMode.Read, name: "RDAT",
303                     valueProviderCallback: _ =>
304                     {
305                         if(currentPeripheralMode == PeripheralMode.IIC)
306                         {
307                             if(iicState != IICState.InTransaction)
308                             {
309                                 this.WarningLog("Trying to read the received data in the wrong state");
310                             }
311                             BlinkTxIRQ();
312                             return TryReadFromIICSlave();
313                         }
314 
315                         if(!receiveQueue.TryDequeue(out var result))
316                         {
317                             this.Log(LogLevel.Warning, "Queue is empty, returning 0.");
318                             return 0;
319                         }
320                         UpdateInterrupts();
321                         return result;
322                     });
323 
324             Registers.TransmitData.Define(this)
325                 .WithReservedBits(13, 19)
326                 .WithTag("TSYNC", 12, 1)
327                 .WithReservedBits(10, 2)
328                 .WithTag("MPBT", 9, 1)
329                 .WithValueField(0, 9, FieldMode.Write, name: "TDAT",
330                     writeCallback: (_, value) =>
331                     {
332                         if(!transmitEnabled.Value)
333                         {
334                             this.Log(LogLevel.Warning, "Transmission is not enabled, ignoring byte 0x{0:X}", value);
335                             return;
336                         }
337 
338                         switch(currentPeripheralMode)
339                         {
340                             case PeripheralMode.UART:
341                                 TransmitUART((byte)value);
342                                 break;
343                             case PeripheralMode.SPI:
344                                 TransmitSPI((byte)value);
345                                 break;
346                             case PeripheralMode.IIC:
347                                 TransmitIICData((byte)value);
348                                 // No need to update the interrupts - in IIC mode we just blink the Tx interrupt
349                                 return;
350                             default:
351                                 throw new Exception("unreachable");
352                         }
353 
354                         UpdateInterrupts();
355                     });
356 
357             Registers.CommonControl0.Define(this)
358                 .WithReservedBits(25, 7)
359                 .WithTag("SSE", 24, 1)
360                 .WithReservedBits(22, 2)
361                 .WithFlag(21, out transmitEndInterruptEnabled, name: "TEIE")
362                 .WithFlag(20, out transmitInterruptEnabled, name: "TIE")
363                 .WithReservedBits(17, 3)
364                 .WithFlag(16, out receiveInterruptEnabled, name: "RIE")
365                 .WithReservedBits(11, 5)
366                 .WithTag("IDSEL", 10, 1)
367                 .WithTag("DCME", 9, 1)
368                 .WithTag("MPIE", 8, 1)
369                 .WithReservedBits(5, 3)
370                 .WithFlag(4, out transmitEnabled, name: "TE", writeCallback: (_, val) =>
371                     {
372                         if(!val)
373                         {
374                             conditionCompletedFlag.Value = false;
375                         }
376                     })
377                 .WithReservedBits(1, 3)
378                 .WithFlag(0, out receiveEnabled, name: "RE")
379                 .WithChangeCallback((_, __) =>
380                 {
381                     // The documentation states that the TXI interrupt should be fired when both TE and TIE are set
382                     // with a single write operation. On the hardware however it takes some time to actually do that.
383                     // The delay mechanism introduced below will prevent Renode from activating the interrupt too soon,
384                     // because in some cases interrupts could be handled in the wrong order.
385                     if(transmitEnabled.Value && transmitInterruptEnabled.Value)
386                     {
387                         machine.ScheduleAction(TimeInterval.FromMilliseconds(InterruptDelay), ___ => UpdateInterrupts());
388                         return;
389                     }
390                     UpdateInterrupts();
391                 });
392 
393             Registers.CommonControl1.Define(this)
394                 .WithReservedBits(30, 2)
395                 .WithTag("NFM", 29, 1)
396                 .WithTag("NFEN", 28, 1)
397                 .WithReservedBits(27, 1)
398                 .WithTag("NFCS", 24, 3)
399                 .WithReservedBits(21, 3)
400                 .WithTag("SHARPS", 20, 1)
401                 .WithReservedBits(17, 3)
402                 .WithTag("SPLP", 16, 1)
403                 .WithReservedBits(14, 2)
404                 .WithTag("RINV", 13, 1)
405                 .WithTag("TINV", 12, 1)
406                 .WithReservedBits(10, 2)
407                 .WithFlag(9, out useOddParity, name: "PM")
408                 .WithFlag(8, out parityEnabled, name: "PE")
409                 .WithReservedBits(6, 2)
410                 .WithTag("SPB2IO", 5, 1)
411                 .WithTag("SPB2DT", 4, 1)
412                 .WithReservedBits(2, 2)
413                 .WithTag("CTSPEN", 1, 1)
414                 .WithTag("CTSE", 0, 1);
415 
416             Registers.CommonControl2.Define(this)
417                 .WithTag("MDDR", 24, 8)
418                 .WithReservedBits(22, 2)
419                 .WithValueField(20, 2, out clockSelect, name: "CKS")
420                 .WithReservedBits(17, 3)
421                 .WithTag("BRME", 16, 1)
422                 .WithValueField(8, 8, out bitRate, name: "BRR")
423                 .WithTag("ABCSE2", 7, 1)
424                 .WithTag("ABCSE", 6, 1)
425                 .WithTag("ABCS", 5, 1)
426                 .WithTag("BGDM", 4, 1)
427                 .WithReservedBits(3, 1)
428                 .WithTag("BCP", 0, 3);
429 
430             Registers.CommonControl3.Define(this)
431                 .WithReservedBits(30, 2)
432                 .WithTag("BLK", 29, 1)
433                 .WithTag("GM", 28, 1)
434                 .WithReservedBits(27, 1)
435                 .WithTag("ACS0", 26, 1)
436                 .WithTag("CKE", 24, 2)
437                 .WithReservedBits(22, 2)
438                 .WithTag("DEN", 21, 1)
439                 .WithTag("FM", 20, 1)
440                 .WithTag("MP", 19, 1)
441                 .WithEnumField<DoubleWordRegister, CommunicationMode>(16, 3, out nonSmartCommunicationMode,
442                     writeCallback: (_, __) => SetPeripheralMode(), name: "MOD")
443                 .WithTag("RXDESEL", 15, 1)
444                 .WithFlag(14, out useTwoStopBits, name: "STP")
445                 .WithTag("SINV", 13, 1)
446                 .WithTag("LSBF", 12, 1)
447                 .WithReservedBits(10, 2)
448                 .WithTag("CHR", 8, 2)
449                 .WithTag("BPEN", 7, 1)
450                 .WithReservedBits(2, 5)
451                 .WithTag("CPOL", 1, 1)
452                 .WithTag("CPHA", 0, 1);
453 
454             Registers.CommonControl4.Define(this)
455                 .WithTag("AET", 31, 1)
456                 .WithTag("ATT", 28, 3)
457                 .WithTag("AJD", 27, 1)
458                 .WithTag("AST", 24, 3)
459                 .WithReservedBits(20, 4)
460                 .WithTag("SCKSEL", 19, 1)
461                 .WithReservedBits(18, 1)
462                 .WithTag("ATEN", 17, 1)
463                 .WithTag("ASEN", 16, 1)
464                 .WithReservedBits(9, 7)
465                 .WithTag("CMPD", 0, 9);
466 
467             Registers.CommunicationEnableStatus.Define(this)
468                 .WithReservedBits(5, 27)
469                 .WithFlag(4, FieldMode.Read, name: "TIST", valueProviderCallback: _ => transmitEnabled.Value)
470                 .WithReservedBits(1, 3)
471                 .WithFlag(0, FieldMode.Read, name: "RIST", valueProviderCallback: _ => receiveEnabled.Value);
472 
473             Registers.SimpleIICControl.Define(this)
474                 .WithReservedBits(24, 8)
475                 .WithTag("IICSCLS", 22, 2)
476                 .WithTag("IICSDAS", 20, 2)
477                 .WithReservedBits(19, 1)
478                 .WithFlag(18, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
479                     {
480                         if(val)
481                         {
482                             this.DebugLog("Stop Condition Requested!");
483                             EmulateIICStartStopCondition(IICCondition.Stop);
484                         }
485                     }, name: "IICSTPREQ")
486                 .WithFlag(17, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
487                     {
488                         if(val)
489                         {
490                             this.DebugLog("Restart Condition Requested!");
491                             EmulateIICStartStopCondition(IICCondition.Restart);
492                         }
493                     }, name: "IICRSTAREQ")
494                 .WithFlag(16, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
495                     {
496                         if(val)
497                         {
498                             this.DebugLog("Start Condition Requested!");
499                             EmulateIICStartStopCondition(IICCondition.Start);
500                         }
501                     }, name: "IICSTAREQ")
502                 .WithReservedBits(14, 2)
503                 .WithFlag(13,
504                     writeCallback: (_, val) =>
505                     {
506                         if(useRxTxInterrupts.Value)
507                         {
508                             return;
509                         }
510                         if(val)
511                         {
512                             BlinkTxIRQ();
513                         }
514                     }, name:"IICACKT")
515                 .WithReservedBits(10, 3)
516                 .WithTag("IICCSC", 9, 1)
517                 .WithFlag(8, out useRxTxInterrupts, name: "IICINTM")
518                 .WithReservedBits(5, 3)
519                 .WithTag("IICDL", 0, 5)
520                 .WithWriteCallback((_, val) =>
521                     {
522                         var conditionRequestBits = val & 0x70000;
523                         if(conditionRequestBits != 0 && ((conditionRequestBits & (conditionRequestBits - 1)) != 0))
524                         {
525                             this.WarningLog("More than one IIC condition requested at the same register acces");
526                         }
527                         else if(conditionRequestBits == 0)
528                         {
529                             // conditionCompletedFlag being zeroed
530                             UpdateInterruptsInIICMode();
531                         }
532                     });
533 
534             Registers.FIFOControl.Define(this)
535                 .WithReservedBits(29, 3)
536                 .WithTag("RSTRG", 24, 5)
537                 .WithTag("RFRST[]", 23, 1)
538                 .WithReservedBits(21, 2)
539                 .WithTag("RTRG", 16, 5)
540                 .WithTag("TFRST", 15, 1)
541                 .WithReservedBits(13, 2)
542                 .WithTag("TTRG", 8, 5)
543                 .WithReservedBits(1, 7)
544                 .WithTag("DRES", 0, 1);
545 
546             Registers.ManchesterControl.Define(this)
547                 .WithReservedBits(27, 5)
548                 .WithTag("SBEREN", 26, 1)
549                 .WithTag("SYEREN", 25, 1)
550                 .WithTag("PFEREN", 24, 1)
551                 .WithReservedBits(22, 2)
552                 .WithTag("RPPAT", 20, 2)
553                 .WithTag("RPLEN", 16, 4)
554                 .WithReservedBits(14, 2)
555                 .WithTag("TPPAT", 12, 2)
556                 .WithTag("TPLEN", 8, 4)
557                 .WithReservedBits(7, 1)
558                 .WithTag("SBSEL", 6, 1)
559                 .WithTag("SYNSEL", 5, 1)
560                 .WithTag("SYNVAL", 4, 1)
561                 .WithReservedBits(3, 1)
562                 .WithTag("ERTEN", 2, 1)
563                 .WithTag("TMPOL", 1, 1)
564                 .WithTag("RMPOL", 0, 1);
565 
566             Registers.DriverControl.Define(this)
567                 .WithReservedBits(21, 11)
568                 .WithTag("DENGT", 16, 5)
569                 .WithReservedBits(13, 3)
570                 .WithTag("DEAST", 8, 5)
571                 .WithReservedBits(1, 7)
572                 .WithTag("DEPOL", 0, 1);
573 
574             Registers.SimpleLINControl0.Define(this)
575                 .WithReservedBits(26, 6)
576                 .WithTag("BCCS", 24, 2)
577                 .WithReservedBits(23, 1)
578                 .WithTag("AEDIE", 22, 1)
579                 .WithTag("COFIE", 21, 1)
580                 .WithTag("BFDIE", 20, 1)
581                 .WithReservedBits(18, 2)
582                 .WithTag("BCDIE", 17, 1)
583                 .WithTag("BFOIE", 16, 1)
584                 .WithTag("PIBS", 13, 3)
585                 .WithTag("PIBE", 12, 1)
586                 .WithTag("CF1DS", 10, 2)
587                 .WithTag("CF0RE", 9, 1)
588                 .WithTag("BFE", 8, 1)
589                 .WithReservedBits(2, 6)
590                 .WithTag("TCCS", 0, 2);
591 
592             Registers.SimpleLINControl1.Define(this)
593                 .WithTag("CF1CE", 24, 8)
594                 .WithTag("SCF1D", 16, 8)
595                 .WithTag("PCF1D", 8, 8)
596                 .WithReservedBits(6, 2)
597                 .WithTag("BMEN", 5, 1)
598                 .WithTag("SDST", 4, 1)
599                 .WithReservedBits(1, 3)
600                 .WithTag("TCST", 0, 1);
601 
602             Registers.SimpleLINControl2.Define(this)
603                 .WithTag("BFLW", 16, 16)
604                 .WithTag("CF0CE", 8, 8)
605                 .WithTag("CF0D", 0, 8);
606 
607             Registers.CommonStatus.Define(this)
608                 .WithTag("RDRF", 31, 1)
609                 .WithFlag(30, FieldMode.Read, valueProviderCallback: _ => true, name: "TEND")
610                 .WithTag("TDRE", 29, 1)
611                 .WithTag("FER", 28, 1)
612                 .WithTag("PER", 27, 1)
613                 .WithTag("MFF", 26, 1)
614                 .WithReservedBits(25, 1)
615                 .WithTag("ORER", 24, 1)
616                 .WithReservedBits(19, 5)
617                 .WithTag("DFER", 18, 1)
618                 .WithTag("DPER", 17, 1)
619                 .WithTag("DCMF", 16, 1)
620                 .WithTag("RXDMON", 15, 1)
621                 .WithReservedBits(5, 10)
622                 .WithTag("ERS", 4, 1)
623                 .WithReservedBits(0, 4);
624 
625             Registers.SimpleIICStatus.Define(this)
626                 .WithReservedBits(4, 28)
627                 .WithFlag(3, out conditionCompletedFlag, FieldMode.Read, name: "IICSTIF")
628                 .WithReservedBits(1, 2)
629                 .WithTag("IICACKR", 0, 1);
630 
631             Registers.FIFOReceiveStatus.Define(this)
632                 .WithReservedBits(30, 2)
633                 .WithTag("FNUM", 24, 6)
634                 .WithReservedBits(22, 2)
635                 .WithTag("PNUM", 16, 6)
636                 .WithReservedBits(14, 2)
637                 .WithTag("R", 8, 6)
638                 .WithReservedBits(1, 7)
639                 .WithTag("DR", 0, 1);
640 
641             Registers.FIFOTransmitStatus.Define(this)
642                 .WithReservedBits(6, 26)
643                 .WithTag("T", 0, 6);
644 
645             Registers.ManchesterStatus.Define(this)
646                 .WithReservedBits(7, 25)
647                 .WithTag("RSYNC", 6, 1)
648                 .WithReservedBits(5, 1)
649                 .WithTag("MER", 4, 1)
650                 .WithReservedBits(3, 1)
651                 .WithTag("SBER", 2, 1)
652                 .WithTag("SYER", 1, 1)
653                 .WithTag("PFER", 0, 1);
654 
655             Registers.SimpleLINStatus0.Define(this)
656                 .WithTag("CF1RD", 24, 8)
657                 .WithTag("CF0RD", 16, 8)
658                 .WithTag("AEDF", 15, 1)
659                 .WithTag("COF", 14, 1)
660                 .WithTag("PIBDF", 13, 1)
661                 .WithTag("CF1MF", 12, 1)
662                 .WithTag("CF0MF", 11, 1)
663                 .WithTag("BFDF", 10, 1)
664                 .WithTag("BCDF", 9, 1)
665                 .WithTag("BFOF", 8, 1)
666                 .WithReservedBits(2, 6)
667                 .WithTag("RXDSF", 1, 1)
668                 .WithTag("SFSF", 0, 1);
669 
670             Registers.SimpleIICStatus1.Define(this)
671                 .WithReservedBits(16, 16)
672                 .WithTag("TCNT", 0, 16);
673 
674             Registers.CommonFlagClear.Define(this)
675                 .WithTag("RDRFC", 31, 1)
676                 .WithReservedBits(30, 1)
677                 .WithTag("TDREC", 29, 1)
678                 .WithTag("FERC", 28, 1)
679                 .WithTag("PERC", 27, 1)
680                 .WithTag("MFFC", 26, 1)
681                 .WithReservedBits(25, 1)
682                 .WithTag("ORERC", 24, 1)
683                 .WithReservedBits(19, 5)
684                 .WithTag("DFERC", 18, 1)
685                 .WithTag("DPERC", 17, 1)
686                 .WithTag("DCMFC", 16, 1)
687                 .WithReservedBits(5, 11)
688                 .WithTag("ERSC", 4, 1)
689                 .WithReservedBits(0, 4);
690 
691             Registers.SimpleIICFlagCLear.Define(this)
692                 .WithReservedBits(4, 28)
693                 .WithFlag(3, name: "IICSTIFC", writeCallback: (_, val) =>
694                     {
695                         if(val)
696                         {
697                             conditionCompletedFlag.Value = false;
698                         }
699                     })
700                 .WithReservedBits(0, 3);
701 
702             Registers.FIFOFlagClear.Define(this)
703                 .WithReservedBits(1, 31)
704                 .WithTag("DRC", 0, 1);
705 
706             Registers.ManchesterFlagClear.Define(this)
707                 .WithReservedBits(5, 27)
708                 .WithTag("MERC", 4, 1)
709                 .WithReservedBits(3, 1)
710                 .WithTag("SBERC", 2, 1)
711                 .WithTag("SYERC", 1, 1)
712                 .WithTag("PFERC", 0, 1);
713 
714             Registers.SimpleLINFlagClear.Define(this)
715                 .WithReservedBits(16, 16)
716                 .WithTag("AEDC", 15, 1)
717                 .WithTag("COFC", 14, 1)
718                 .WithTag("PIBDC", 13, 1)
719                 .WithTag("CF1MC", 12, 1)
720                 .WithTag("CF0MC", 11, 1)
721                 .WithTag("BFDC", 10, 1)
722                 .WithTag("BCDC", 9, 1)
723                 .WithTag("BFOC", 8, 1)
724                 .WithReservedBits(0, 8);
725         }
726 
TransmitUART(byte value)727         private void TransmitUART(byte value)
728         {
729             CharReceived?.Invoke(value);
730         }
731 
TransmitSPI(byte value)732         private void TransmitSPI(byte value)
733         {
734             if(spiContainer.RegisteredPeripheral == null)
735             {
736                 this.WarningLog("No SPI peripheral connected");
737                 return;
738             }
739 
740             receiveQueue.Enqueue(spiContainer.RegisteredPeripheral.Transmit(value));
741         }
742 
TryReadFromIICSlave()743         private ulong TryReadFromIICSlave()
744         {
745             ushort readByte;
746             if(selectedIICSlave == null)
747             {
748                 this.WarningLog("No peripheral selected. Will not perform read");
749                 return 0UL;
750             }
751             if(!receiveQueue.TryDequeue(out readByte))
752             {
753                 // This will obviously try to read too much bytes, but this is necessary, as we have no way of guessing how many bytes the driver intends to read
754                 receiveQueue.EnqueueRange(selectedIICSlave.Read(IICReadBufferCount).Select(element => (ushort)element));
755 
756                 if(!receiveQueue.TryDequeue(out readByte))
757                 {
758                     this.ErrorLog("Unable to get bytes from the peripheral");
759                     return 0ul;
760                 }
761             }
762             return readByte;
763         }
764 
TransmitUARTData(byte value)765         private void TransmitUARTData(byte value)
766         {
767             CharReceived?.Invoke(value);
768         }
769 
TransmitIICData(byte value)770         private void TransmitIICData(byte value)
771         {
772             DebugHelper.Assert((iicState == IICState.Idle) || (iicDirection != IICTransactionDirection.Unset), $"Incorrect communication direction {iicDirection} in state {iicState}");
773             switch(iicState)
774             {
775                 case IICState.Idle:
776                     // Addressing frame
777                     var rwBit = (value & 0x1);
778                     var slaveAddress = value >> 1;
779 
780                     iicDirection = (rwBit == 1) ? IICTransactionDirection.Read : IICTransactionDirection.Write;
781                     if(!i2cContainer.TryGetByAddress((int)slaveAddress, out selectedIICSlave))
782                     {
783                         this.WarningLog("Selecting unconnected IIC slave address: 0x{0:X}", slaveAddress);
784                     }
785                     this.DebugLog("Selected slave address 0x{0:X} for {1}", slaveAddress, iicDirection);
786                     iicState = IICState.InTransaction;
787                     conditionCompletedFlag.Value = false;
788                     BlinkTxIRQ();
789                     break;
790                 case IICState.InTransaction:
791                     if(iicDirection == IICTransactionDirection.Write)
792                     {
793                         iicTransmitQueue.Enqueue(value);
794                         BlinkTxIRQ();
795                     }
796                     else
797                     {
798                         if(value == DummyTransmitByte)
799                         {
800                             this.DebugLog("Ignoring the dummy transmission");
801                             BlinkTxIRQ();
802                         }
803                     }
804                     break;
805                  default:
806                     throw new Exception("Unreachable");
807             }
808         }
809 
TransmitSPIData(byte value)810         private void TransmitSPIData(byte value)
811         {
812             if(spiContainer.RegisteredPeripheral == null)
813             {
814                 this.WarningLog("No SPI peripheral connected");
815                 return;
816             }
817             receiveQueue.Enqueue(spiContainer.RegisteredPeripheral.Transmit((byte)value));
818         }
819 
820         // This is used in the non-FIFO mode where there is room just for a single byte, hence "full" means non-empty queue
821         private bool IsReceiveDataFull => receiveQueue.Count > 0;
822         // This is used in the non-FIFO. Single character is transmitted instantly so this is always true
823         private bool IsDataTransmitted => true;
824 
825         private readonly IMachine machine;
826         private readonly Queue<ushort> receiveQueue;
827         private readonly SimpleContainerHelper<II2CPeripheral> i2cContainer;
828         private readonly Queue<byte> iicTransmitQueue;
829 
830         private IICState iicState;
831         private II2CPeripheral selectedIICSlave;
832         private IICTransactionDirection iicDirection;
833 
834         private readonly NullRegistrationPointContainerHelper<IUART> uartContainer;
835         private readonly NullRegistrationPointContainerHelper<ISPIPeripheral> spiContainer;
836 
837         private readonly ulong frequency;
838 
839         private PeripheralMode currentPeripheralMode;
840 
841         private IFlagRegisterField transmitEndInterruptEnabled;
842         private IFlagRegisterField transmitInterruptEnabled;
843         private IFlagRegisterField receiveInterruptEnabled;
844         private IFlagRegisterField transmitEnabled;
845         private IFlagRegisterField receiveEnabled;
846 
847         private IFlagRegisterField parityEnabled;
848         private IFlagRegisterField useOddParity;
849 
850         private IFlagRegisterField useTwoStopBits;
851 
852         private IValueRegisterField clockSelect;
853         private IValueRegisterField bitRate;
854 
855         private IFlagRegisterField conditionCompletedFlag;
856 
857         private IFlagRegisterField useRxTxInterrupts;
858 
859         private IEnumRegisterField<CommunicationMode> nonSmartCommunicationMode;
860 
861         private const int InterruptDelay = 1;
862         private const int IICReadBufferCount = 24;
863         // This byte is used to trigger reception on IIC bus. It should not be transmitted
864         private const byte DummyTransmitByte = 0xFF;
865 
866         private enum Registers
867         {
868             ReceiveData = 0x0,
869             TransmitData = 0x4,
870             CommonControl0 = 0x8,
871             CommonControl1 = 0xC,
872             CommonControl2 = 0x10,
873             CommonControl3 = 0x14,
874             CommonControl4 = 0x18,
875             CommunicationEnableStatus = 0x1C,
876             SimpleIICControl = 0x20,
877             FIFOControl = 0x24,
878             ManchesterControl = 0x2C,
879             DriverControl = 0x30,
880             SimpleLINControl0 = 0x34,
881             SimpleLINControl1 = 0x38,
882             SimpleLINControl2 = 0x3C,
883             CommonStatus = 0x48,
884             SimpleIICStatus = 0x4C,
885             FIFOReceiveStatus = 0x50,
886             FIFOTransmitStatus = 0x54,
887             ManchesterStatus = 0x58,
888             SimpleLINStatus0 = 0x5C,
889             SimpleIICStatus1 = 0x60,
890             CommonFlagClear = 0x68,
891             SimpleIICFlagCLear = 0x6C,
892             FIFOFlagClear = 0x70,
893             ManchesterFlagClear = 0x74,
894             SimpleLINFlagClear = 0x78,
895         }
896 
897         private enum CommunicationMode
898         {
899             Asynchronous        = 0b000,
900             SmartCardInterface  = 0b001,
901             ClockSynchronous    = 0b010,
902             SimpleSPI           = 0b011,
903             SimpleI2C           = 0b100,
904             Machnester          = 0b101,
905             SimpleLIN           = 0b111,
906         }
907 
908         private enum PeripheralMode
909         {
910             UART,
911             SPI,
912             IIC,
913         }
914 
915         private enum IICState
916         {
917             Idle = 0,
918             InTransaction = 1,
919         }
920 
921         private enum IICTransactionDirection
922         {
923             Unset,
924             Read,
925             Write,
926         }
927 
928         private enum IICCondition
929         {
930             Start,
931             Stop,
932             Restart,
933         }
934     }
935 }
936 
937 
938