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.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Core.Structure;
13 using Antmicro.Renode.Debugging;
14 using Antmicro.Renode.Exceptions;
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 using Antmicro.Migrant;
23 
24 namespace Antmicro.Renode.Peripherals.SCI
25 {
26     // Due to unusual register offsets we cannot use address translations
27     public class RenesasRA6M5_SCI : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IUART, IWordPeripheral, IBytePeripheral, IProvidesRegisterCollection<WordRegisterCollection>, IKnownSize,
28         IPeripheralContainer<IUART, NullRegistrationPoint>, IPeripheralContainer<II2CPeripheral, NumberRegistrationPoint<int>>
29     {
RenesasRA6M5_SCI(IMachine machine, ulong frequency, bool enableManchesterMode, bool enableFIFO, bool fullModel = true)30         public RenesasRA6M5_SCI(IMachine machine, ulong frequency, bool enableManchesterMode, bool enableFIFO, bool fullModel = true) : base(machine)
31         {
32             this.machine = machine;
33             this.frequency = frequency;
34             i2cContainer = new SimpleContainerHelper<II2CPeripheral>(machine, this);
35             ReceiveIRQ = new GPIO();
36             TransmitIRQ = new GPIO();
37             TransmitEndIRQ = new GPIO();
38             receiveQueue = new Queue<ushort>();
39             iicTransmitQueue = new Queue<byte>();
40             RegistersCollection = new WordRegisterCollection(this);
41 
42             DefineRegisters(enableManchesterMode, enableFIFO, fullModel);
43             Size = fullModel ? 0x100 : 0x20;
44             Reset();
45         }
46 
ReadWord(long offset)47         public ushort ReadWord(long offset)
48         {
49             return RegistersCollection.Read(offset);
50         }
51 
WriteWord(long offset, ushort value)52         public void WriteWord(long offset, ushort value)
53         {
54             RegistersCollection.Write(offset, value);
55         }
56 
ReadByte(long offset)57         public byte ReadByte(long offset)
58         {
59             return (byte)RegistersCollection.Read(offset);
60         }
61 
WriteByte(long offset, byte value)62         public void WriteByte(long offset, byte value)
63         {
64             RegistersCollection.Write(offset, value);
65         }
66 
WriteChar(byte value)67         public void WriteChar(byte value)
68         {
69             receiveQueue.Enqueue(value);
70             UpdateInterrupts();
71         }
72 
Reset()73         public override void Reset()
74         {
75             fifoMode = false;
76             manchesterMode = false;
77             receiveQueue.Clear();
78             iicTransmitQueue.Clear();
79 
80             ReceiveIRQ.Unset();
81             TransmitIRQ.Unset();
82             TransmitEndIRQ.Unset();
83             RegistersCollection.Reset();
84             peripheralMode = PeripheralMode.UART;
85         }
86 
Register(IUART peripheral, NullRegistrationPoint registrationPoint)87         public void Register(IUART peripheral, NullRegistrationPoint registrationPoint)
88         {
89             if(registeredUartPeripheral != null)
90             {
91                 throw new RegistrationException($"UART peripheral alredy registered");
92             }
93 
94             machine.RegisterAsAChildOf(this, peripheral, registrationPoint);
95 
96             CharReceived += peripheral.WriteChar;
97             peripheral.CharReceived += WriteChar;
98 
99             registeredUartPeripheral = peripheral;
100         }
101 
Unregister(IUART peripheral)102         public void Unregister(IUART peripheral)
103         {
104             CharReceived -= peripheral.WriteChar;
105             peripheral.CharReceived -= WriteChar;
106 
107             registeredUartPeripheral = null;
108         }
109 
GetRegistrationPoints(IUART peripheral)110         public IEnumerable<NullRegistrationPoint> GetRegistrationPoints(IUART peripheral)
111         {
112             return registeredUartPeripheral != null ?
113                 new[] { NullRegistrationPoint.Instance } :
114                 Enumerable.Empty<NullRegistrationPoint>();
115         }
116 
Register(II2CPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)117         public virtual void Register(II2CPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint) => i2cContainer.Register(peripheral, registrationPoint);
118 
Unregister(II2CPeripheral peripheral)119         public virtual void Unregister(II2CPeripheral peripheral) => i2cContainer.Unregister(peripheral);
120 
121         public IEnumerable<NumberRegistrationPoint<int>> GetRegistrationPoints(II2CPeripheral peripheral) => i2cContainer.GetRegistrationPoints(peripheral);
122 
123         public bool IsDataReadyFIFO { get => (ulong)receiveQueue.Count < receiveFIFOTriggerCount.Value; }
124 
125         public bool IsReceiveFIFOFull { get => (ulong)receiveQueue.Count >= receiveFIFOTriggerCount.Value; }
126 
127         // This is used in the non-FIFO mode where there is room just for a single byte, hence "full" means non-empty queue
128         public bool IsReceiveDataFull { get => receiveQueue.Count > 0; }
129 
130         public WordRegisterCollection RegistersCollection { get; }
131 
132         public GPIO ReceiveIRQ { get; }
133 
134         public GPIO TransmitIRQ { get; }
135 
136         public GPIO TransmitEndIRQ { get; }
137 
138         public uint BaudRate
139         {
140             get
141             {
142                 var n = clockSource.Value == 0 ? 1UL : 2UL << (2 * (ushort)clockSource.Value - 1);
143                 return (uint)(frequency / (64UL * n * bitRate.Value)) - 1;
144             }
145         }
146 
147         public Bits StopBits => hasTwoStopBits.Value ? Bits.Two : Bits.One;
148 
149         public Parity ParityBit => parityEnabled.Value ? parityBit : Parity.None;
150 
151         public long Size { get; }
152 
153         IEnumerable<IRegistered<IUART, NullRegistrationPoint>> IPeripheralContainer<IUART, NullRegistrationPoint>.Children
154         {
155             get => registeredUartPeripheral != null ?
156                 new [] { Registered.Create(registeredUartPeripheral, NullRegistrationPoint.Instance) } :
157                 Enumerable.Empty<IRegistered<IUART, NullRegistrationPoint>>();
158         }
159 
160         IEnumerable<IRegistered<II2CPeripheral, NumberRegistrationPoint<int>>> IPeripheralContainer<II2CPeripheral, NumberRegistrationPoint<int>>.Children =>
161             i2cContainer.Children;
162 
163         [field: Transient]
164         public event Action<byte> CharReceived;
165 
UpdateInterrupts()166         private void UpdateInterrupts()
167         {
168             if(peripheralMode == PeripheralMode.IIC)
169             {
170                 UpdateInterruptsInIICMode();
171                 return;
172             }
173             var rxState = receiveInterruptEnabled.Value && (fifoMode ? IsReceiveFIFOFull : IsReceiveDataFull);
174             var txState = transmitInterruptEnabled.Value && (fifoMode ? transmitFIFOEmpty.Value : true);
175             var teState = transmitEndInterruptEnabled.Value;
176 
177             this.DebugLog("ReceiveIRQ: {0}, TransmitIRQ: {1}, TransmitEndIRQ: {2}.", rxState ? "set" : "unset", txState ? "set" : "unset", teState ? "set" : "unset");
178             if(rxState)
179             {
180                 ReceiveIRQ.Blink();
181             }
182             if(txState)
183             {
184                 TransmitIRQ.Blink();
185             }
186             if(teState)
187             {
188                 TransmitEndIRQ.Blink();
189             }
190         }
191 
UpdateInterruptsInIICMode()192         private void UpdateInterruptsInIICMode()
193         {
194             // This does not update the Transmit/Receive interrupts, as there are not status flags in this mode and they are expected just to blink
195             bool teState = transmitEndInterruptEnabled.Value && conditionCompletedFlag.Value;
196             this.DebugLog("TransmitEndIRQ: {0}.", teState ? "set" : "unset");
197 
198             TransmitEndIRQ.Set(teState);
199         }
200 
BlinkTxIRQ()201         private void BlinkTxIRQ()
202         {
203             DebugHelper.Assert(peripheralMode == PeripheralMode.IIC);
204 
205             if(transmitInterruptEnabled.Value)
206             {
207                 TransmitIRQ.Blink();
208             }
209         }
210 
FlushIICTransmitQueue()211         private void FlushIICTransmitQueue()
212         {
213             if(iicTransmitQueue.Count != 0)
214             {
215                 selectedIICSlave.Write(iicTransmitQueue.ToArray());
216                 iicTransmitQueue.Clear();
217             }
218         }
219 
EmulateIICStartStopCondition(IICCondition condition)220         private void EmulateIICStartStopCondition(IICCondition condition)
221         {
222             conditionCompletedFlag.Value = true;
223             transmitEnd.Value = true;
224             if(condition == IICCondition.Stop)
225             {
226                 if(selectedIICSlave == null)
227                 {
228                     this.WarningLog("No slave selected. This condition will have no effect");
229                     return;
230                 }
231 
232                 switch(iicDirection)
233                 {
234                     case IICTransactionDirection.Write:
235                         FlushIICTransmitQueue();
236                         break;
237                     case IICTransactionDirection.Read:
238                         receiveQueue.Clear();
239                         break;
240                     default:
241                         throw new ArgumentException("Unknown IIC direction");
242                 }
243                 selectedIICSlave.FinishTransmission();
244             }
245             else if(condition == IICCondition.Restart)
246             {
247                 //Flush the register address
248                 FlushIICTransmitQueue();
249             }
250 
251             iicState = IICState.Idle;
252             iicDirection = IICTransactionDirection.Unset;
253             selectedIICSlave = null;
254             UpdateInterruptsInIICMode();
255         }
256 
SetPeripheralMode()257         private void SetPeripheralMode()
258         {
259             if(smartCardMode.Value)
260             {
261                 peripheralMode = PeripheralMode.SmartCardInterface;
262                 if(i2cMode.Value)
263                 {
264                     this.Log(LogLevel.Warning,
265                         "The IICM flag in the {0} register (SIMR1) should be unset for Smart Card Interface mode; it's set",
266                         nameof(Registers.IICMode1)
267                     );
268                 }
269                 return;
270             }
271 
272             if(i2cMode.Value)
273             {
274                 peripheralMode = PeripheralMode.IIC;
275                 if(nonSmartCommunicationMode.Value != CommunicationMode.AsynchOrSimpleIIC)
276                 {
277                     this.Log(LogLevel.Warning,
278                         "The CM flag in the {0} register (SMR) should be unset ({1}) for Simple I2C mode; it's set ({2})",
279                         nameof(Registers.SerialModeNonSmartCard), CommunicationMode.AsynchOrSimpleIIC, CommunicationMode.SynchOrSimpleSPI
280                     );
281                 }
282 
283                 if(dataTransferDirection.Value != DataTransferDirection.MSBFirst)
284                 {
285                     this.Log(LogLevel.Warning,
286                         "The SDIR flag in the {0} should be set ({1}) for Simple I2Cmode; it's unset ({2})",
287                         nameof(Registers.SmartCardMode), DataTransferDirection.MSBFirst, DataTransferDirection.LSBFirst
288                     );
289                 }
290                 return;
291             }
292 
293             switch(nonSmartCommunicationMode.Value)
294             {
295                 case CommunicationMode.AsynchOrSimpleIIC:
296                     if(i2cContainer.ChildCollection.Count != 0)
297                     {
298                         peripheralMode = PeripheralMode.IIC;
299                         return;
300                     }
301                     break;
302                 case CommunicationMode.SynchOrSimpleSPI:
303                     if(RegisteredPeripheral != null)
304                     {
305                        peripheralMode = PeripheralMode.SPI;
306                        return;
307                     }
308                     break;
309                 default:
310                     break;
311             }
312             peripheralMode = PeripheralMode.UART;
313         }
314 
DefineRegisters(bool enableManchesterMode, bool enableFIFO, bool fullModel)315         private void DefineRegisters(bool enableManchesterMode, bool enableFIFO, bool fullModel)
316         {
317             // Non-Smart Card Mode
318             Registers.SerialModeNonSmartCard.DefineConditional(this, () => !smartCardMode.Value)
319                 .WithValueField(0, 2, out clockSource, name: "CKS")
320                 .WithTaggedFlag("MP", 2)
321                 .WithFlag(3, out hasTwoStopBits, name: "STOP")
322                 .WithFlag(4, name: "PM",
323                     valueProviderCallback: _ => parityBit == Parity.Odd,
324                     writeCallback: (_, value) => parityBit = value ? Parity.Odd : Parity.Even)
325                 .WithFlag(5, out parityEnabled, name: "PE")
326                 .WithTaggedFlag("CHR", 6)
327                 .WithEnumField<WordRegister, CommunicationMode>(7, 1, out nonSmartCommunicationMode,
328                     writeCallback: (_, __) => SetPeripheralMode(), name: "CM")
329                 .WithReservedBits(8, 8);
330 
331             // Smart Card Mode
332             Registers.SerialModeSmartCard.DefineConditional(this, () => smartCardMode.Value)
333                 .WithTag("CKS", 0, 2)
334                 .WithTag("BCP", 2, 2)
335                 .WithTag("PM", 4, 1)
336                 .WithTag("PE", 5, 1)
337                 .WithTag("BLK", 6, 1)
338                 .WithTag("GM", 7, 1)
339                 .WithReservedBits(8, 8);
340 
341             Registers.BitRate.Define(this, 0xff)
342                 .WithValueField(0, 8, out bitRate,
343                     writeCallback: (oldVal, newVal) => bitRate.Value = (!transmitEnabled.Value && !receiveEnabled.Value) ? newVal : oldVal,
344                     name: "BRR")
345                 .WithReservedBits(8, 8);
346 
347             // Non-Smart Card Mode
348             Registers.SerialControlNonSmartCard.DefineConditional(this, () => !smartCardMode.Value)
349                 .WithTag("CKE", 0, 2)
350                 .WithFlag(2, out transmitEndInterruptEnabled, name: "TEIE")
351                 .WithTaggedFlag("MPIE", 3)
352                 .WithFlag(4, out receiveEnabled, name: "RE")
353                 .WithFlag(5, out transmitEnabled, name: "TE")
354                 .WithFlag(6, out receiveInterruptEnabled, name: "RIE")
355                 .WithFlag(7, out transmitInterruptEnabled, name: "TIE")
356                 .WithReservedBits(8, 8)
357                 .WithChangeCallback((_, __) =>
358                 {
359                     // The documentation states that the TXI interrupt should be fired when both TE and TIE are set
360                     // with a single write operation. On the hardware however it takes some time to actually do that.
361                     // The delay mechanism introduced below will prevent Renode from activating the interrupt too soon,
362                     // because in some cases interrupts could be handled in the wrong order.
363                     if(transmitEnabled.Value && transmitInterruptEnabled.Value)
364                     {
365                         machine.ScheduleAction(TimeInterval.FromMilliseconds(InterruptDelay), ___ => UpdateInterrupts());
366                         return;
367                     }
368                     UpdateInterrupts();
369                 });
370 
371             // Smart Card Mode
372             Registers.SerialControlSmartCard.DefineConditional(this, () => smartCardMode.Value)
373                 .WithTag("CKS", 0, 2)
374                 .WithTag("TEIE", 2, 1)
375                 .WithTag("MPIE", 3, 1)
376                 .WithTag("RE", 4, 1)
377                 .WithTag("TE", 5, 1)
378                 .WithTag("RIE", 6, 1)
379                 .WithTag("TIE", 7, 1)
380                 .WithReservedBits(8, 8);
381 
382             Registers.TransmitData.Define(this)
383                 .WithValueField(0, 8, FieldMode.Write, name: "TDR",
384                     writeCallback: (_, value) =>
385                     {
386                         if(!transmitEnabled.Value)
387                         {
388                             this.Log(LogLevel.Warning, "Transmission is not enabled, ignoring byte 0x{0:X}", value);
389                             return;
390                         }
391                         switch(peripheralMode) {
392                             case PeripheralMode.UART:
393                                 TransmitUARTData((byte)value);
394                                 break;
395                             case PeripheralMode.IIC:
396                                 TransmitIICData((byte)value);
397                                 // No need to update the interrupts - in IIC mode we just blink the Tx interrupt
398                                 return;
399                             case PeripheralMode.SPI:
400                                 TransmitSPIData((byte)value);
401                                 break;
402                             default:
403                                 throw new Exception($"Unknown peripheral mode {peripheralMode}");
404                         }
405                         UpdateInterrupts();
406                     })
407                 .WithReservedBits(8, 8);
408 
409             // Non-Smart Card, Non-FIFO, Non-Manchester
410             Registers.SerialStatusNonSmartCardNonFIFO.DefineConditional(this, () => !smartCardMode.Value && !fifoMode && !manchesterMode, 0x84)
411                 .WithTaggedFlag("MPBT", 0)
412                 .WithTaggedFlag("MPB", 1)
413                 .WithFlag(2, out transmitEnd, FieldMode.Read, name: "TEND")
414                 .WithTaggedFlag("PER", 3)
415                 .WithTaggedFlag("FER", 4)
416                 .WithTaggedFlag("ORER", 5)
417                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => IsReceiveDataFull, name: "RDRF")
418                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => true, name: "TDRE")
419                 .WithReservedBits(8, 8)
420                 .WithChangeCallback((_, __) => UpdateInterrupts());
421 
422             if(enableFIFO)
423             {
424                 // Non-Smart Card, FIFO, Non-manchester
425                 Registers.SerialStatusNonSmartCardFIFO.DefineConditional(this, () => !smartCardMode.Value && fifoMode && !manchesterMode, 0x84)
426                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => IsDataReadyFIFO, name: "DR")
427                     .WithReservedBits(1, 1)
428                     .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => true, name: "TEND")
429                     .WithTaggedFlag("PER", 3)
430                     .WithTaggedFlag("FER", 4)
431                     .WithTaggedFlag("ORER", 5)
432                     .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => IsReceiveFIFOFull, name: "RDF")
433                     .WithFlag(7, out transmitFIFOEmpty, FieldMode.Read | FieldMode.WriteZeroToClear,  name: "TDFE")
434                     .WithReservedBits(8, 8);
435             }
436 
437             // Smart Card, Non-manchester
438             Registers.SerialStatusSmartCard.DefineConditional(this, () => smartCardMode.Value && !manchesterMode, 0x84)
439                 .WithTaggedFlag("MPBT", 0)
440                 .WithTaggedFlag("MPB", 1)
441                 .WithTaggedFlag("TEND", 2)
442                 .WithTaggedFlag("PER", 3)
443                 .WithTaggedFlag("ERS", 4)
444                 .WithTaggedFlag("ORER", 5)
445                 .WithTaggedFlag("RDRF", 6)
446                 .WithTaggedFlag("TDRE", 7)
447                 .WithReservedBits(8, 8);
448 
449             // Non-Smart Card, Manchester
450             Registers.SerialStatusManchesterMode.DefineConditional(this, () => !smartCardMode.Value && manchesterMode, 0x84)
451                 .WithTaggedFlag("MER", 0)
452                 .WithTaggedFlag("MPB", 1)
453                 .WithTaggedFlag("TEND", 2)
454                 .WithTaggedFlag("PER", 3)
455                 .WithTaggedFlag("FER", 4)
456                 .WithTaggedFlag("ORER", 5)
457                 .WithTaggedFlag("RDRF", 6)
458                 .WithTaggedFlag("TDRE", 7)
459                 .WithReservedBits(8, 8);
460 
461             Registers.ReceiveData.Define(this)
462                 .WithValueField(0, 8, FieldMode.Read, name: "RDR",
463                     valueProviderCallback: _ =>
464                     {
465                         if(peripheralMode == PeripheralMode.IIC)
466                         {
467                             if(iicState != IICState.InTransaction)
468                             {
469                                 this.WarningLog("Trying to read the received data in the wrong state");
470                             }
471                             BlinkTxIRQ();
472                             return TryReadFromIICSlave();
473                         }
474 
475                         if(!receiveQueue.TryDequeue(out var result))
476                         {
477                             this.Log(LogLevel.Warning, "Queue is empty, returning 0.");
478                             return 0;
479                         }
480                         UpdateInterrupts();
481                         return result;
482                     })
483                 .WithReservedBits(8, 8);
484 
485             Registers.SmartCardMode.Define(this, 0xf2)
486                 .WithFlag(0, out smartCardMode, name: "SMIF")
487                 .WithReservedBits(1, 1)
488                 .WithTaggedFlag("SINV", 2)
489                 .WithEnumField(3, 1, out dataTransferDirection, name: "SDIR")
490                 .WithTaggedFlag("CHR1", 4)
491                 .WithReservedBits(5, 2)
492                 .WithTaggedFlag("BCP2", 7)
493                 .WithReservedBits(8, 8)
494                 .WithChangeCallback((_, __) => SetPeripheralMode());
495 
496             Registers.SerialExtendedMode.Define(this)
497                 .WithTaggedFlag("ACS0", 0)
498                 .WithTaggedFlag("PADIS", 1)
499                 .WithTaggedFlag("BRME", 2)
500                 .WithTaggedFlag("ABCSE", 3)
501                 .WithTaggedFlag("ABCS", 4)
502                 .WithTaggedFlag("NFEN", 5)
503                 .WithTaggedFlag("BGDM", 6)
504                 .WithTaggedFlag("RXDESEL", 7)
505                 .WithReservedBits(8, 8);
506 
507             Registers.NoiseFilterSetting.Define(this)
508                 .WithTag("NFCS", 0, 3)
509                 .WithReservedBits(3, 13);
510 
511             Registers.IICMode1.Define(this)
512                 .WithFlag(0, out i2cMode, changeCallback: (_, __) => SetPeripheralMode(), name: "IICM")
513                 .WithReservedBits(1, 2)
514                 .WithTag("IICDL", 3, 5)
515                 .WithReservedBits(8, 8);
516 
517             Registers.IICMode2.Define(this)
518                 .WithTag("IICINTM", 0, 1)
519                 .WithTaggedFlag("IICCSC", 1)
520                 .WithReservedBits(2, 3)
521                 .WithFlag(5, writeCallback: (_, val) => { if(val) BlinkTxIRQ(); }, name:"IICACKT")
522                 .WithReservedBits(6, 10);
523 
524             Registers.IICMode3.Define(this)
525                 .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
526                     {
527                         if(val)
528                         {
529                             this.DebugLog("Start Condition Requested!");
530                             EmulateIICStartStopCondition(IICCondition.Start);
531                         }
532                     }, name: "IICSTAREQ")
533                 .WithFlag(1, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
534                     {
535                         if(val)
536                         {
537                             this.DebugLog("Restart Condition Requested!");
538                             EmulateIICStartStopCondition(IICCondition.Restart);
539                         }
540                     }, name: "IICRSTAREQ")
541                 .WithFlag(2, FieldMode.WriteOneToClear, writeCallback: (_, val) =>
542                     {
543                         if(val)
544                         {
545                             this.DebugLog("Stop Condition Requested!");
546                             EmulateIICStartStopCondition(IICCondition.Stop);
547                         }
548                     }, name: "IICSTPREQ")
549                 .WithFlag(3, out conditionCompletedFlag, FieldMode.WriteZeroToClear,name: "IICSTIF")
550                 .WithValueField(4, 2, name: "IICSDAS")
551                 .WithValueField(6, 2, name: "IICSCLS")
552                 .WithReservedBits(8, 8)
553                 .WithWriteCallback((_, val) =>
554                     {
555                         var conditionRequestBits = val & 0b111;
556                         if(conditionRequestBits != 0 && ((conditionRequestBits & (conditionRequestBits - 1)) != 0))
557                         {
558                             this.WarningLog("More than one IIC condition requested at the same register acces");
559                         }
560                         else if(conditionRequestBits == 0)
561                         {
562                             // conditionCompletedFlag being zeroed
563                             UpdateInterruptsInIICMode();
564                         }
565                     });
566 
567             Registers.IICStatus.Define(this)
568                 .WithTaggedFlag("IICACKR", 0)
569                 .WithReservedBits(1, 7)
570                 .WithReservedBits(8, 8);
571 
572             Registers.SPIMode.Define(this)
573                 .WithTaggedFlag("SSE", 0)
574                 .WithTaggedFlag("CTSE", 1)
575                 .WithTaggedFlag("MSS", 2)
576                 .WithTaggedFlag("CTSPEN", 3)
577                 .WithTaggedFlag("MFF", 4)
578                 .WithReservedBits(5, 1)
579                 .WithTaggedFlag("CKPOL", 6)
580                 .WithTaggedFlag("CKPH", 7)
581                 .WithReservedBits(8, 8);
582 
583             Registers.TransmitDataNonManchesterMode.DefineConditional(this, () => !manchesterMode && !fifoMode, 0xff)
584                 .WithTag("TDAT", 0, 9)
585                 .WithReservedBits(9, 7);
586 
587             Registers.TransmitDataManchesterMode.DefineConditional(this, () => manchesterMode && !fifoMode, 0xff)
588                 .WithTag("TDAT", 0, 9)
589                 .WithTaggedFlag("MPBT", 9)
590                 .WithReservedBits(10, 2)
591                 .WithTaggedFlag("TSYNC", 12)
592                 .WithReservedBits(13, 3);
593 
594             if(enableFIFO)
595             {
596                 // TransmitFIFODataLowByte (below) is an 8-bits wide window of this register
597                 Registers.TransmitFIFOData.DefineConditional(this, () => fifoMode, 0xff)
598                     .WithValueField(0, 9, FieldMode.Write, name: "TDAT",
599                         writeCallback: (_, val) =>
600                         {
601                             TransmitUARTData((byte)(val >> 8));
602                             TransmitUARTData((byte)val);
603                             transmitFIFOEmpty.Value = true;
604                             UpdateInterrupts();
605                         })
606                     .WithTaggedFlag("MPBT", 9)
607                     .WithReservedBits(10, 6);
608 
609                 // this is the upper 8-bits of transmitFIFOData register
610                 Registers.TransmitFIFODataLowByte.DefineConditional(this, () => fifoMode, 0xff)
611                     .WithValueField(0, 8, FieldMode.Write, name: "TDATL",
612                         writeCallback: (_, val) =>
613                         {
614                             TransmitUARTData((byte)val);
615                             transmitFIFOEmpty.Value = true;
616                             UpdateInterrupts();
617                         })
618                     .WithReservedBits(9, 7);
619             }
620 
621             Registers.ReceiveDataNonManchesterMode.DefineConditional(this, () => !manchesterMode && !fifoMode)
622                 .WithTag("RDAT", 0, 9)
623                 .WithReservedBits(9, 7);
624 
625             Registers.ReceiveDataManchesterMode.DefineConditional(this, () => manchesterMode && !fifoMode)
626                 .WithReservedBits(10, 2)
627                 .WithTaggedFlag("RSYNC", 12)
628                 .WithReservedBits(13, 3);
629 
630             if(enableFIFO)
631             {
632                 Registers.ReceiveFIFOData.DefineConditional(this, () => fifoMode)
633                     .WithValueField(0, 9, FieldMode.Read, name: "RDAT",
634                         valueProviderCallback: _ =>
635                         {
636                             if(!receiveQueue.TryDequeue(out var result))
637                             {
638                                 this.Log(LogLevel.Warning, "Queue is empty, returning 0.");
639                                 return 0;
640                             }
641                             UpdateInterrupts();
642                             return result;
643                         })
644                     .WithTaggedFlag("MPB", 9)
645                     .WithFlag(10, FieldMode.Read, valueProviderCallback: _ => IsDataReadyFIFO, name: "DR")
646                     .WithTaggedFlag("PER", 11)
647                     .WithTaggedFlag("FER", 12)
648                     .WithTaggedFlag("ORER", 13)
649                     .WithFlag(14, FieldMode.Read, valueProviderCallback: _ => IsReceiveFIFOFull, name: "RDF")
650                     .WithReservedBits(15, 1);
651             }
652 
653             Registers.ModulationDuty.Define(this, 0xff)
654                 .WithTag("MDDR", 0, 8)
655                 .WithReservedBits(8, 8);
656 
657             Registers.DataCompareMatchControl.Define(this, 0x40)
658                 .WithTaggedFlag("DCMF", 0)
659                 .WithReservedBits(1, 2)
660                 .WithTaggedFlag("DPER", 3)
661                 .WithTaggedFlag("DFER", 4)
662                 .WithReservedBits(5, 1)
663                 .WithTaggedFlag("IDSEL", 6)
664                 .WithTaggedFlag("DCME", 7)
665                 .WithReservedBits(8, 8);
666 
667             if(enableFIFO)
668             {
669                 Registers.FIFOControl.Define(this, 0xF800)
670                     .WithFlag(0, name: "FM",
671                         writeCallback: (_, val) => fifoMode = val,
672                         valueProviderCallback: _ => fifoMode)
673                     .WithFlag(1, FieldMode.Read | FieldMode.WriteOneToClear, name: "RFRST",
674                         writeCallback: (_, __) =>
675                         {
676                             if(fifoMode)
677                             {
678                                 receiveQueue.Clear();
679                             }
680                         })
681                     .WithTaggedFlag("TFRST", 2)
682                     .WithTaggedFlag("DRES", 3)
683                     .WithTaggedFlag("TTRG", 4)
684                     .WithValueField(8, 4, out receiveFIFOTriggerCount, name: "RTRG")
685                     .WithTag("RSTRG", 12, 4);
686 
687                 Registers.FIFODataCount.Define(this)
688                     .WithValueField(0, 5, FieldMode.Read, name: "R",
689                         valueProviderCallback: _ => (ulong)receiveQueue.Count >= MaxFIFOSize ? MaxFIFOSize : (ulong)receiveQueue.Count)
690                     .WithReservedBits(5, 3)
691                     .WithTag("T", 8, 5)
692                     .WithReservedBits(13, 3);
693             }
694 
695             Registers.LineStatus.Define(this)
696                 .WithTaggedFlag("ORER", 0)
697                 .WithReservedBits(1, 1)
698                 .WithTag("FNUM", 2, 5)
699                 .WithReservedBits(7, 1)
700                 .WithTag("PNUM", 8, 5)
701                 .WithReservedBits(13, 3);
702 
703             Registers.CompareMatchData.Define(this)
704                 .WithTag("CMPD", 0, 9)
705                 .WithReservedBits(9, 7);
706 
707             Registers.SerialPort.Define(this, 0x03)
708                 .WithTaggedFlag("RXDMON", 0)
709                 .WithTaggedFlag("SPB2DT", 1)
710                 .WithTaggedFlag("SPB2IO", 2)
711                 .WithReservedBits(3, 1)
712                 .WithTaggedFlag("RINV", 4)
713                 .WithTaggedFlag("TINV", 5)
714                 .WithTaggedFlag("ASEN", 6)
715                 .WithTaggedFlag("ATEN", 7)
716                 .WithReservedBits(8, 8);
717 
718             Registers.AdjustmentCommunicationTiming.Define(this)
719                 .WithTag("AST", 0, 3)
720                 .WithTaggedFlag("AJD", 3)
721                 .WithTag("ATT", 4, 3)
722                 .WithTaggedFlag("AET", 7)
723                 .WithReservedBits(8, 8);
724 
725             if(!fullModel)
726             {
727                 return;
728             }
729 
730             if(enableManchesterMode)
731             {
732                 Registers.ManchesterMode.Define(this)
733                     .WithTag("RMPOL", 0, 1)
734                     .WithTag("TMPOL", 1, 1)
735                     .WithTag("ERTEN", 2, 1)
736                     .WithReservedBits(3, 1)
737                     .WithTag("SYNVAL", 4, 1)
738                     .WithTag("SYNSEL", 5, 1)
739                     .WithTag("SBSEL", 6, 1)
740                     .WithFlag(7, name: "MANEN",
741                         writeCallback: (_, val) => manchesterMode = val,
742                         valueProviderCallback: _ => manchesterMode)
743                     .WithReservedBits(8, 8);
744 
745                 Registers.TransmitManchesterPrefaceSetting.Define(this)
746                     .WithTag("TPLEN", 0, 3)
747                     .WithTag("TPPAT", 4, 2)
748                     .WithReservedBits(6, 10);
749 
750                 Registers.ReceiveManchesterPrefaceSetting.Define(this)
751                     .WithTag("RPLEN", 0, 3)
752                     .WithTag("RPPAT", 4, 2)
753                     .WithReservedBits(6, 10);
754 
755                 Registers.ManchesterExtendedErrorStatus.Define(this)
756                     .WithTag("PFER", 0, 1)
757                     .WithTag("SYER", 1, 1)
758                     .WithTag("SBER", 2, 1)
759                     .WithReservedBits(3, 13);
760 
761                 Registers.ManchesterExtendedErrorControl.Define(this)
762                     .WithTag("PFEREN", 0, 1)
763                     .WithTag("SYEREN", 1, 1)
764                     .WithTag("SBEREN", 2, 1)
765                     .WithReservedBits(3, 13);
766             }
767             else
768             {
769                 Registers.ExtendedSerialModuleEnable.Define(this)
770                     .WithReservedBits(1, 7)
771                     .WithTag("ESME", 0, 1)
772                     .WithReservedBits(8, 8);
773 
774                 Registers.Control1.Define(this)
775                     .WithTag("PIBS", 5, 3)
776                     .WithTag("PIBE", 4, 1)
777                     .WithTag("CF1DS", 2, 2)
778                     .WithTag("CF0RE", 1, 1)
779                     .WithTag("BFE", 0, 1)
780                     .WithReservedBits(8, 8);
781 
782                 Registers.Control2.Define(this)
783                     .WithTag("RTS", 6, 2)
784                     .WithTag("BSSS", 4, 2)
785                     .WithReservedBits(3, 1)
786                     .WithTag("DFCS", 0, 3)
787                     .WithReservedBits(8, 8);
788 
789                 Registers.Control3.Define(this)
790                     .WithReservedBits(1, 7)
791                     .WithTag("SDST", 0, 1)
792                     .WithReservedBits(8, 8);
793 
794                 Registers.PortControl.Define(this)
795                     .WithReservedBits(5, 3)
796                     .WithTag("SHARPS", 4, 1)
797                     .WithReservedBits(2, 2)
798                     .WithTag("RXDXPS", 1, 1)
799                     .WithTag("TXDXPS", 0, 1)
800                     .WithReservedBits(8, 8);
801             }
802 
803             Registers.Control0.Define(this)
804                 .WithReservedBits(4, 4)
805                 .WithTag("BRME", 3, 1)
806                 .WithTag("RXDSF", 2, 1)
807                 .WithTag("SFSF", 1, 1)
808                 .WithReservedBits(0, 1)
809                 .WithReservedBits(8, 8);
810 
811             Registers.InterruptControl.Define(this)
812                 .WithReservedBits(6, 2)
813                 .WithTag("AEDIE", 5, 1)
814                 .WithTag("BCDIE", 4, 1)
815                 .WithTag("PBDIE", 3, 1)
816                 .WithTag("CF1MIE", 2, 1)
817                 .WithTag("CF0MIE", 1, 1)
818                 .WithTag("BFDIE", 0, 1)
819                 .WithReservedBits(8, 8);
820 
821             Registers.Status.Define(this)
822                 .WithReservedBits(6, 2)
823                 .WithTag("AEDF", 5, 1)
824                 .WithTag("BCDF", 4, 1)
825                 .WithTag("PIBDF", 3, 1)
826                 .WithTag("CF1MF", 2, 1)
827                 .WithTag("CF0MF", 1, 1)
828                 .WithTag("BFDF", 0, 1)
829                 .WithReservedBits(8, 8);
830 
831             Registers.StatusClear.Define(this)
832                 .WithReservedBits(6, 2)
833                 .WithTag("AEDCL", 5, 1)
834                 .WithTag("BCDCL", 4, 1)
835                 .WithTag("PIBDCL", 3, 1)
836                 .WithTag("CF1MCL", 2, 1)
837                 .WithTag("CF0MCL", 1, 1)
838                 .WithTag("BFDCL", 0, 1)
839                 .WithReservedBits(8, 8);
840 
841             Registers.ControlField0Data.Define(this)
842                 .WithReservedBits(0, 8)
843                 .WithReservedBits(8, 8);
844 
845             Registers.ControlField0CompareEnable.Define(this)
846                 .WithTag("CF0CE7", 7, 1)
847                 .WithTag("CF0CE6", 6, 1)
848                 .WithTag("CF0CE5", 5, 1)
849                 .WithTag("CF0CE4", 4, 1)
850                 .WithTag("CF0CE3", 3, 1)
851                 .WithTag("CF0CE2", 2, 1)
852                 .WithTag("CF0CE1", 1, 1)
853                 .WithTag("CF0CE0", 0, 1)
854                 .WithReservedBits(8, 8);
855 
856             Registers.ControlField0RecieveData.Define(this)
857                 .WithReservedBits(0, 8)
858                 .WithReservedBits(8, 8);
859 
860             Registers.PrimaryControlField1Data.Define(this)
861                 .WithReservedBits(0, 8)
862                 .WithReservedBits(8, 8);
863 
864             Registers.SecondaryControlField1Data.Define(this)
865                 .WithReservedBits(0, 8)
866                 .WithReservedBits(8, 8);
867 
868             Registers.ControlField1CompareEnable.Define(this)
869                 .WithTag("CF1CE7", 7, 1)
870                 .WithTag("CF1CE6", 6, 1)
871                 .WithTag("CF1CE5", 5, 1)
872                 .WithTag("CF1CE4", 4, 1)
873                 .WithTag("CF1CE3", 3, 1)
874                 .WithTag("CF1CE2", 2, 1)
875                 .WithTag("CF1CE1", 1, 1)
876                 .WithTag("CF1CE0", 0, 1)
877                 .WithReservedBits(8, 8);
878 
879             Registers.ControlField1ReceiveData.Define(this)
880                 .WithReservedBits(0, 8)
881                 .WithReservedBits(8, 8);
882 
883             Registers.TimerControl.Define(this)
884                 .WithReservedBits(1, 7)
885                 .WithTag("TCST", 0, 1)
886                 .WithReservedBits(8, 8);
887 
888             Registers.TimerMode.Define(this)
889                 .WithReservedBits(7, 1)
890                 .WithTag("TCSS", 4, 3)
891                 .WithTag("TWRC", 3, 1)
892                 .WithReservedBits(2, 1)
893                 .WithTag("TOMS", 0, 2)
894                 .WithReservedBits(8, 8);
895 
896             Registers.TimerPrescaler.Define(this)
897                 .WithReservedBits(0, 8)
898                 .WithReservedBits(8, 8);
899 
900             Registers.TimerCount.Define(this)
901                 .WithReservedBits(0, 8)
902                 .WithReservedBits(8, 8);
903         }
904 
TryReadFromIICSlave()905         private ulong TryReadFromIICSlave()
906         {
907             ushort readByte;
908             if(selectedIICSlave == null)
909             {
910                 this.WarningLog("No peripheral selected. Will not perform read");
911                 return 0UL;
912             }
913             if(!receiveQueue.TryDequeue(out readByte))
914             {
915                 // 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
916                 receiveQueue.EnqueueRange(selectedIICSlave.Read(IICReadBufferCount).Select(element => (ushort)element));
917 
918                 if(!receiveQueue.TryDequeue(out readByte))
919                 {
920                     this.ErrorLog("Unable to get bytes from the peripheral");
921                     return 0ul;
922                 }
923             }
924             return readByte;
925         }
926 
TransmitUARTData(byte value)927         private void TransmitUARTData(byte value)
928         {
929             CharReceived?.Invoke(value);
930         }
931 
TransmitIICData(byte value)932         private void TransmitIICData(byte value)
933         {
934             DebugHelper.Assert((iicState == IICState.Idle) || (iicDirection != IICTransactionDirection.Unset), $"Incorrect communication direction {iicDirection} in state {iicState}");
935             switch(iicState)
936             {
937                 case IICState.Idle:
938                     // Addressing frame
939                     var rwBit = (value & 0x1);
940                     var slaveAddress = value >> 1;
941                     iicDirection = (rwBit == 1) ? IICTransactionDirection.Read : IICTransactionDirection.Write;
942                     if(!i2cContainer.TryGetByAddress((int)slaveAddress, out selectedIICSlave))
943                     {
944                         this.WarningLog("Selecting unconnected IIC slave address: 0x{0:X}", slaveAddress);
945                     }
946                     this.DebugLog("Selected slave address 0x{0:X} for {1}", slaveAddress, iicDirection);
947                     iicState = IICState.InTransaction;
948                     conditionCompletedFlag.Value = false;
949                     BlinkTxIRQ();
950                     break;
951                 case IICState.InTransaction:
952                     if(iicDirection == IICTransactionDirection.Write)
953                     {
954                         iicTransmitQueue.Enqueue(value);
955                         BlinkTxIRQ();
956                     }
957                     else
958                     {
959                         if(value == DummyTransmitByte)
960                         {
961                             this.DebugLog("Ignoring the dummy transmission");
962                             BlinkTxIRQ();
963                         }
964                     }
965                     break;
966                  default:
967                     throw new Exception("Unreachable");
968             }
969         }
970 
TransmitSPIData(byte value)971         private void TransmitSPIData(byte value)
972         {
973             if(RegisteredPeripheral == null)
974             {
975                 this.WarningLog("No SPI peripheral connected");
976                 return;
977             }
978             receiveQueue.Enqueue(RegisteredPeripheral.Transmit((byte)value));
979         }
980 
981         // This peripheral might work in a 9-bit mode,
982         private readonly Queue<ushort> receiveQueue;
983         private readonly Queue<byte> iicTransmitQueue;
984         private readonly ulong frequency;
985         private readonly IMachine machine;
986         private readonly SimpleContainerHelper<II2CPeripheral> i2cContainer;
987         private Parity parityBit = Parity.Even;
988 
989         private IUART registeredUartPeripheral;
990 
991         private bool manchesterMode;
992         private bool fifoMode;
993         private IICState iicState;
994         private II2CPeripheral selectedIICSlave;
995         private IICTransactionDirection iicDirection;
996         private PeripheralMode peripheralMode;
997 
998         private IFlagRegisterField transmitEnabled;
999         private IFlagRegisterField hasTwoStopBits;
1000         private IFlagRegisterField parityEnabled;
1001         private IFlagRegisterField transmitEndInterruptEnabled;
1002         private IFlagRegisterField transmitEnd;
1003         private IFlagRegisterField receiveEnabled;
1004         private IFlagRegisterField receiveInterruptEnabled;
1005         private IFlagRegisterField transmitInterruptEnabled;
1006         private IFlagRegisterField smartCardMode;
1007         private IFlagRegisterField transmitFIFOEmpty;
1008         private IFlagRegisterField conditionCompletedFlag;
1009         private IFlagRegisterField i2cMode;
1010         private IValueRegisterField receiveFIFOTriggerCount;
1011         private IValueRegisterField bitRate;
1012         private IValueRegisterField clockSource;
1013         private IEnumRegisterField<DataTransferDirection> dataTransferDirection;
1014         private IEnumRegisterField<CommunicationMode> nonSmartCommunicationMode;
1015 
1016 
1017         private const ulong MaxFIFOSize = 16;
1018         private const int InterruptDelay = 1;
1019         private const int IICReadBufferCount = 24;
1020         // This byte is used to trigger reception on IIC bus. It should not be transmitted
1021         private const byte DummyTransmitByte = 0xFF;
1022 
1023         private enum DataTransferDirection
1024         {
1025             LSBFirst = 0,
1026             MSBFirst = 1,
1027         }
1028 
1029         private enum IICCondition
1030         {
1031             Start,
1032             Stop,
1033             Restart,
1034         }
1035 
1036         private enum CommunicationMode
1037         {
1038             AsynchOrSimpleIIC = 0,
1039             SynchOrSimpleSPI = 1,
1040         }
1041 
1042         private enum IICState
1043         {
1044             Idle = 0,
1045             InTransaction = 1,
1046         }
1047 
1048         private enum IICTransactionDirection
1049         {
1050             Unset,
1051             Read,
1052             Write,
1053         }
1054 
1055         private enum PeripheralMode
1056         {
1057             UART,
1058             SPI,
1059             IIC,
1060             SmartCardInterface,
1061         }
1062 
1063         private enum Registers
1064         {
1065             SerialModeNonSmartCard = 0x00,  // SMR
1066             SerialModeSmartCard = 0x00,  // SMR_SMCI
1067             BitRate = 0x01,  // BRR
1068             SerialControlNonSmartCard = 0x02,  // SCR
1069             SerialControlSmartCard = 0x02,  // SCR_SMCI
1070             TransmitData = 0x03,  // TDR
1071             SerialStatusNonSmartCardNonFIFO = 0x04,  // SSR
1072             SerialStatusNonSmartCardFIFO = 0x04,  // SSR_FIFO
1073             SerialStatusSmartCard = 0x04,  // SSR_SMCI
1074             SerialStatusManchesterMode = 0x04,  // SSR_MANC
1075             ReceiveData = 0x05,  // RDR
1076             SmartCardMode = 0x06,  // SCMR
1077             SerialExtendedMode = 0x07,  // SEMR
1078             NoiseFilterSetting = 0x08,  // SNFR
1079             IICMode1 = 0x09,  // SIMR1
1080             IICMode2 = 0x0A,  // SIMR2
1081             IICMode3 = 0x0B,  // SIMR3
1082             IICStatus = 0x0C,  // SISR
1083             SPIMode = 0x0D,  // SPMR
1084             TransmitDataNonManchesterMode = 0xE,  // TDRHL
1085             TransmitDataManchesterMode = 0xE,  // TDRHL_MAN
1086             TransmitFIFOData = 0xE,  // FTDRHL
1087             TransmitFIFODataLowByte = 0xF,  // FTDRL
1088             ReceiveDataNonManchesterMode = 0x10,  // RDRHL
1089             ReceiveDataManchesterMode = 0x10,  // RDRHL_MAN
1090             ReceiveFIFOData = 0x10,  // FRDRHL
1091             ModulationDuty = 0x12,  // MDDR
1092             DataCompareMatchControl = 0x13,  // DCCR
1093             FIFOControl = 0x14,  // FCR
1094             FIFODataCount = 0x16,  // FDR
1095             LineStatus = 0x18,  // LSR
1096             CompareMatchData = 0x1A,  // CDR
1097             SerialPort = 0x1C,  // SPTR
1098             AdjustmentCommunicationTiming = 0x1D,  // ACTR
1099             ExtendedSerialModuleEnable = 0x20,  // ESMER
1100             ManchesterMode = 0x20,  // MMR
1101             Control0 = 0x21,  // CR0
1102             Control1 = 0x22,  // CR1
1103             TransmitManchesterPrefaceSetting = 0x22,  // TMPR
1104             Control2 = 0x23,  // CR2
1105             ReceiveManchesterPrefaceSetting = 0x23,  // RMPR
1106             Control3 = 0x24,  // CR3
1107             ManchesterExtendedErrorStatus = 0x24,  // MESR
1108             PortControl = 0x25,  // PCR
1109             ManchesterExtendedErrorControl = 0x25,  // MECR
1110             InterruptControl = 0x26,  // ICR
1111             Status = 0x27,  // STR
1112             StatusClear = 0x28,  // STCR
1113             ControlField0Data = 0x29,  // CF0DR
1114             ControlField0CompareEnable = 0x2A,  // CF0CR
1115             ControlField0RecieveData = 0x2B,  // CF0RR
1116             PrimaryControlField1Data = 0x2C,  // PCF1DR
1117             SecondaryControlField1Data = 0x2D,  // SCF1DR
1118             ControlField1CompareEnable = 0x2E,  // CF1CR
1119             ControlField1ReceiveData = 0x2F,  // CF1RR
1120             TimerControl = 0x30,  // TCR
1121             TimerMode = 0x31,  // TMR
1122             TimerPrescaler = 0x32,  // TPRE
1123             TimerCount = 0x33,  // TCNT
1124         }
1125     }
1126 }
1127