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 
8 using Antmicro.Migrant;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Peripherals.UART;
14 using Antmicro.Renode.Time;
15 using System;
16 using System.Collections.Generic;
17 using System.Linq;
18 
19 namespace Antmicro.Renode.Peripherals.SCI
20 {
21     public class RenesasRZG_SCIFA : BasicWordPeripheral, IBytePeripheral, IUART, IHasFrequency, IKnownSize, INumberedGPIOOutput
22     {
RenesasRZG_SCIFA(IMachine machine, long frequency)23         public RenesasRZG_SCIFA(IMachine machine, long frequency): base(machine)
24         {
25             Frequency = frequency;
26 
27             Connections = Enumerable
28                 .Range(0, NrOfInterrupts)
29                 .ToDictionary<int, int, IGPIO>(idx => idx, _ => new GPIO());
30 
31             DefineRegisters();
32             Reset();
33         }
34 
Reset()35         public override void Reset()
36         {
37             base.Reset();
38             parityBit = Parity.Even;
39             receiveQueue.Clear();
40             UpdateInterrupts();
41         }
42 
43         // Most registers are 16 bit wide, but some are 8 bit.
44         // The shorter ones are artificially extended to 16 bits (WithIgnoredBits).
45         // We don't use translation to prevent valueProviderCallback from being triggered during writes.
ReadByte(long offset)46         public byte ReadByte(long offset)
47         {
48             switch((Registers)offset)
49             {
50                 case Registers.BitRate: // ModulationDuty
51                 case Registers.FifoDataReceive:
52                 case Registers.FifoDataTransmit:
53                 case Registers.SerialExtendedMode:
54                     return (byte)RegistersCollection.Read(offset);
55                 default:
56                     this.ErrorLog(
57                         "Trying to read byte from word register at offset 0x{0:X}. Returning 0x0",
58                         offset
59                     );
60                     return 0;
61             }
62         }
63 
WriteByte(long offset, byte value)64         public void WriteByte(long offset, byte value)
65         {
66             switch((Registers)offset)
67             {
68                 case Registers.BitRate: // ModulationDuty
69                 case Registers.FifoDataReceive:
70                 case Registers.FifoDataTransmit:
71                 case Registers.SerialExtendedMode:
72                     RegistersCollection.Write(offset, (ushort)value);
73                     break;
74                 default:
75                     this.ErrorLog(
76                         "Trying to write byte 0x{0:X} to word register at offset 0x{1:X}. Register won't be updated",
77                         value,
78                         offset
79                     );
80                     break;
81             }
82         }
83 
WriteChar(byte value)84         public void WriteChar(byte value)
85         {
86             if(!receiveEnabled.Value)
87             {
88                 this.ErrorLog("Receiver is not enabled, dropping byte: 0x{0:x}", value);
89                 return;
90             }
91             receiveQueue.Enqueue(value);
92             if(receiveQueue.Count > 0 && receiveQueue.Count < ReceiveFIFOTriggerCount)
93             {
94                 receiveDataReady.Value = true;
95             }
96             if(receiveQueue.Count >= ReceiveFIFOTriggerCount)
97             {
98                 receiveFifoFull.Value = true;
99             }
100             UpdateInterrupts();
101         }
102 
103         public long Size => 0x400;
104 
105         // IRQs are bundled into 5 signals per channel in the following order:
106         // 0: ERI - Receive error
107         // 1: BRI - Break detection or overrun
108         // 2: RXI - Receive FIFO data full
109         // 3: TXI - Transmit FIFO data empty
110         // 4: TEI_DRI - Transmit end / Receive data ready
111         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
112 
113         public Bits StopBits => hasTwoStopBits.Value ? Bits.Two : Bits.One;
114 
115         public Parity ParityBit => parityEnabled.Value ? parityBit : Parity.None;
116 
117         public uint BaudRate
118         {
119             get
120             {
121                 // We can't perform a shift if the exponent is negative
122                 var n = clockSource.Value == 0 ?
123                     0.5 : 1UL << (2 * (ushort)clockSource.Value - 1);
124 
125                 var prefix = 64UL;
126                 if(doubleSpeedMode.Value)
127                 {
128                     prefix /= 2;
129                 }
130                 if(asynchronousBaseClock8Times.Value)
131                 {
132                     prefix /= 2;
133                 }
134 
135                 return (uint)((Frequency * Math.Pow(10, 6)) / (prefix * n * bitRate.Value)) - 1;
136             }
137         }
138 
139         public long Frequency { get; set; }
140 
141         [field: Transient]
142         public event Action<byte> CharReceived;
143 
DefineRegisters()144         private void DefineRegisters()
145         {
146             Registers.SerialMode.Define(this)
147                 .WithValueField(0, 2, out clockSource, name: "CKS")
148                 .WithReservedBits(2, 1)
149                 .WithFlag(3, out hasTwoStopBits, name: "STOP")
150                 .WithFlag(4, name: "PM",
151                     valueProviderCallback: _ => parityBit == Parity.Odd,
152                     writeCallback: (_, value) => parityBit = value ? Parity.Odd : Parity.Even)
153                 .WithFlag(5, out parityEnabled, name: "PE")
154                 .WithTaggedFlag("CHR", 6)   // Character length, might be 8 or 7 bit
155                 .WithEnumField(7, 1, out communicationMode,
156                     writeCallback: (_, val) =>
157                     {
158                         if(val == CommunicationMode.ClockSynchronous)
159                         {
160                             this.ErrorLog(
161                                 "{0} is not yet supported. Switching to {1}",
162                                 nameof(CommunicationMode.ClockSynchronous),
163                                 nameof(CommunicationMode.Asynchronous)
164                             );
165                             communicationMode.Value = CommunicationMode.Asynchronous;
166                         }
167                     },
168                     name: "CM")
169                 .WithReservedBits(8, 8);
170 
171             Registers.BitRate.DefineConditional(this, () => registerSelect.Value == ModulationDutyRegisterSelect.BitRate, 0xff)
172                 .WithValueField(0, 8, out bitRate,
173                     writeCallback: (oldVal, newVal) => bitRate.Value = (!transmitEnabled.Value && !receiveEnabled.Value) ? newVal : oldVal,
174                     name: "BRR")
175                 .WithIgnoredBits(8, 8);
176 
177             // Conditional, exclusive with BitRate
178             Registers.ModulationDuty.DefineConditional(this, () => registerSelect.Value == ModulationDutyRegisterSelect.ModulationDuty, 0xff)
179                 .WithTag("MDDR", 0, 8)
180                 .WithIgnoredBits(8, 8);
181 
182             Registers.SerialControl.Define(this)
183                 .WithTag("CKE", 0, 2)
184                 .WithFlag(2, out transmitEndInterruptEnabled, name: "TEIE")
185                 .WithTaggedFlag("REIE", 3)
186                 .WithFlag(4, out receiveEnabled, name: "RE")
187                 .WithFlag(5, out transmitEnabled, name: "TE",
188                     changeCallback: (_, value) =>
189                     {
190                         if(!value)
191                         {
192                             transmitFIFOEmpty.Value = true;
193                         }
194                     })
195                 .WithFlag(6, out receiveInterruptEnabled, name: "RIE")
196                 .WithFlag(7, out transmitInterruptEnabled, name: "TIE",
197                     // We always have empty transmit FIFO
198                     changeCallback: (_, __) => transmitFIFOEmpty.Value = true)
199                 .WithReservedBits(8, 8)
200                 .WithChangeCallback((_, __) => UpdateInterrupts());
201 
202             Registers.FifoDataReceive.Define(this)
203                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ =>
204                     {
205                         if(receiveQueue.Count == 0)
206                         {
207                             this.WarningLog("Trying to read from an empty receive FIFO, returning 0x0.");
208                             return 0;
209                         }
210                         var ret = receiveQueue.Dequeue();
211                         receiveFifoFull.Value = false;
212                         if(receiveQueue.Count == 0)
213                         {
214                             receiveDataReady.Value = false;
215                         }
216                         UpdateInterrupts();
217                         return ret;
218                     },
219                     name: "FRDR")
220                 .WithIgnoredBits(8, 8);
221 
222             Registers.FifoDataTransmit.Define(this)
223                 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, val) =>
224                     {
225                         if(!transmitEnabled.Value)
226                         {
227                             this.ErrorLog("Transmitter is not enabled, dropping byte: 0x{0:x}", (byte)val);
228                             return;
229                         }
230                         CharReceived?.Invoke((byte)val);
231                         // RZ/G2L Group, RZ/G2LC Group User's Manual: Hardware, states that
232                         // TDFE and TEND flags are cleared when data is written to FTDR register.
233                         // But TDFE is set again when quantity of data written FTDR is less than
234                         // specified threshold, and TEND is set when FTDR becomes empty.
235                         // Both actions take some time on real hardware, but happen immediately in Renode.
236                         // Hence we use delay to prevent interrupts from being triggered too soon.
237                         transmitFIFOEmpty.Value = false;
238                         transmitEnd.Value = false;
239                         UpdateInterrupts();
240                         machine.ScheduleAction(TimeInterval.FromMicroseconds(TransmitInterruptDelay), ___ =>
241                         {
242                             transmitFIFOEmpty.Value = true;
243                             transmitEnd.Value = true;
244                             UpdateInterrupts();
245                         });
246                     },
247                     name: "FTDR")
248                 .WithIgnoredBits(8, 8);
249 
250             // According to the documentation this register should have a reset value of 0x20.
251             // Some software expects the TEND flag to be set even before transmitting the first character.
252             // Error status flags are modeled as fields to reduce the amount of logs generated during the simulation.
253             Registers.SerialStatus.Define(this, 0x60)
254                 .WithFlag(0, out receiveDataReady, FieldMode.Read | FieldMode.WriteZeroToClear, name: "DR")
255                 .WithFlag(1, out receiveFifoFull, FieldMode.Read | FieldMode.WriteZeroToClear, name: "RDF")
256                 .WithFlag(2, FieldMode.Read | FieldMode.WriteZeroToClear, name: "PER")
257                 .WithFlag(3, FieldMode.Read | FieldMode.WriteZeroToClear, name: "FER")
258                 .WithFlag(4, FieldMode.Read | FieldMode.WriteZeroToClear, name: "BRK")
259                 .WithFlag(5, out transmitFIFOEmpty, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TDFE")
260                 .WithFlag(6, out transmitEnd, FieldMode.Read | FieldMode.WriteZeroToClear, name: "TEND")
261                 .WithFlag(7, FieldMode.Read | FieldMode.WriteZeroToClear, name: "ER")
262                 .WithReservedBits(8, 8)
263                 .WithWriteCallback((_, __) => UpdateInterrupts());
264 
265             Registers.FifoControl.Define(this)
266                 .WithTaggedFlag("LOOP", 0)
267                 .WithFlag(1, FieldMode.Read | FieldMode.WriteOneToClear, name: "RFRST", writeCallback: (_, __) => receiveQueue.Clear())
268                 .WithTaggedFlag("TFRST", 2)
269                 .WithTaggedFlag("MCE", 3)
270                 .WithTag("TTRG", 4, 2)
271                 .WithValueField(6, 2, out receiveFifoDataTriggerNumberSelect, name: "RTRG")
272                 .WithTag("RSTRG", 8, 3)
273                 .WithReservedBits(11, 5)
274                 .WithWriteCallback((_, __) => UpdateInterrupts());
275 
276             Registers.FifoDataCount.Define(this)
277                 .WithValueField(0, 5, FieldMode.Read, name: "R",
278                     valueProviderCallback: _ => (ulong)receiveQueue.Count >= MaxFIFOSize ? MaxFIFOSize : (ulong)receiveQueue.Count)
279                 .WithReservedBits(5, 3)
280                 // Transmission is instantaneous, so it will always be empty
281                 .WithValueField(8, 5, name: "T", valueProviderCallback: _ => 0x0)
282                 .WithReservedBits(13, 3);
283 
284             Registers.SerialPort.Define(this)
285                 .WithTaggedFlag("SPB2DT", 0)
286                 .WithTaggedFlag("SPB2IO", 1)
287                 .WithTaggedFlag("SCKDT", 2)
288                 .WithTaggedFlag("SCKIO", 3)
289                 .WithTaggedFlag("CTS2DT", 4)
290                 .WithTaggedFlag("CTS2IO", 5)
291                 .WithTaggedFlag("RTS2DT", 6)
292                 .WithTaggedFlag("RTS2IO", 7)
293                 .WithReservedBits(8, 8);
294 
295             Registers.LineStatus.Define(this)
296                 .WithTaggedFlag("ORER", 0)
297                 .WithReservedBits(1, 1)
298                 // We don't model parity errors
299                 .WithTag("FER", 2, 5)
300                 .WithReservedBits(7, 1)
301                 .WithTag("PER", 8, 5)
302                 .WithReservedBits(13, 3);
303 
304             Registers.SerialExtendedMode.Define(this)
305                 .WithFlag(0, out asynchronousBaseClock8Times, name: "ABCS0")
306                 .WithReservedBits(1, 1)
307                 .WithTaggedFlag("NFEN", 2)
308                 .WithTaggedFlag("DIR", 3)
309                 .WithEnumField(4, 1, out registerSelect, name: "MDDRS")
310                 .WithTaggedFlag("BRME", 5)
311                 .WithReservedBits(6, 1)
312                 .WithFlag(7, out doubleSpeedMode, name: "BGDM")
313                 .WithIgnoredBits(8, 8);
314 
315             // We don't update interrupts here as docs don't specify that we should do it.
316             // They seem to indicate that interrupt should only be triggered when FIFO count changes.
317             // From RZ/G2L Group, RZ/G2LC Group User's Manual: Hardware, chapter 22:
318             // "When the quantity of transmit data written in the FTDR register as a result of transmission
319             // is equal to or less than the specified transmission trigger number ... interrupt request is generated"
320             // or
321             // "When the number of entries in the reception FIFO ... rises to or above the specified trigger number for reception,
322             //  the RDF flag is set to 1 and a receive FIFO data full interrupt (RXI) request is generated"
323             Registers.FifoTriggerControl.Define(this, 0x1f1f)
324                 .WithTag("TFTC", 0, 5)
325                 .WithReservedBits(5, 2)
326                 .WithTaggedFlag("TTRGS", 7)
327                 .WithValueField(8, 5, out receiveFifoDataTriggerNumber, name: "RFTC")
328                 .WithReservedBits(13, 2)
329                 .WithFlag(15, out receiveTriggerSelect, name: "RTRGS");
330         }
331 
332         private int ReceiveFIFOTriggerCount
333         {
334             get
335             {
336                 if(receiveTriggerSelect.Value)
337                 {
338                     return (int)receiveFifoDataTriggerNumber.Value;
339                 }
340                 else
341                 {
342                     switch(receiveFifoDataTriggerNumberSelect.Value)
343                     {
344                         case 0:
345                             return 1;
346                         case 1:
347                             return 4;
348                         case 2:
349                             return 8;
350                         case 3:
351                             return 14;
352                         default:
353                             this.ErrorLog(
354                                 "{0} has invalid value {1}. Defaulting to 0x1.",
355                                 nameof(receiveFifoDataTriggerNumberSelect),
356                                 receiveFifoDataTriggerNumberSelect.Value
357                             );
358                             return 1;
359                     }
360                 }
361             }
362         }
363 
UpdateInterrupts()364         private void UpdateInterrupts()
365         {
366             Connections[ReceiveFifoFullIrqIdx].Set(receiveInterruptEnabled.Value && receiveFifoFull.Value);
367             // Transmit is always instant, so if the transmit interrupt is enabled
368             // and we have written some char, the IRQ triggers.
369             Connections[TransmitFifoEmptyIrqIdx].Set(transmitInterruptEnabled.Value && transmitFIFOEmpty.Value);
370             Connections[TransmitEndReceiveReadyIrqIdx].Set((receiveInterruptEnabled.Value && receiveDataReady.Value) ||
371                                                            (transmitEndInterruptEnabled.Value && transmitEnd.Value));
372             // We don't implement these interrupts
373             Connections[ReceiveErrorIrqIdx].Set(false);
374             Connections[BreakOrOverrunIrqIdx].Set(false);
375         }
376 
377         private Parity parityBit;
378 
379         private IFlagRegisterField hasTwoStopBits;
380         private IFlagRegisterField parityEnabled;
381         private IFlagRegisterField doubleSpeedMode;
382         private IFlagRegisterField transmitEnabled;
383         private IFlagRegisterField transmitEndInterruptEnabled;
384         private IFlagRegisterField receiveEnabled;
385         private IFlagRegisterField receiveInterruptEnabled;
386         private IFlagRegisterField transmitInterruptEnabled;
387         private IFlagRegisterField transmitFIFOEmpty;
388         private IFlagRegisterField transmitEnd;
389         private IFlagRegisterField receiveDataReady;
390         private IFlagRegisterField receiveFifoFull;
391         private IValueRegisterField bitRate;
392         private IValueRegisterField clockSource;
393         private IValueRegisterField receiveFifoDataTriggerNumber;
394         private IFlagRegisterField receiveTriggerSelect;
395         private IValueRegisterField receiveFifoDataTriggerNumberSelect;
396         private IFlagRegisterField asynchronousBaseClock8Times;
397         private IEnumRegisterField<ModulationDutyRegisterSelect> registerSelect;
398         private IEnumRegisterField<CommunicationMode> communicationMode;
399 
400         private readonly Queue<byte> receiveQueue = new Queue<byte>();
401 
402         private const int MaxFIFOSize = 16;
403         private const int NrOfInterrupts = 5;
404         private const int ReceiveErrorIrqIdx = 0;
405         private const int BreakOrOverrunIrqIdx = 1;
406         private const int ReceiveFifoFullIrqIdx = 2;
407         private const int TransmitFifoEmptyIrqIdx = 3;
408         private const int TransmitEndReceiveReadyIrqIdx = 4;
409         private const int TransmitInterruptDelay = 5;
410 
411         private enum CommunicationMode
412         {
413             Asynchronous = 0,
414             ClockSynchronous = 1,
415         }
416 
417         private enum ModulationDutyRegisterSelect
418         {
419             BitRate,
420             ModulationDuty
421         }
422 
423         private enum Registers
424         {
425             SerialMode          = 0x0,  // SMR
426             // BitRate and ModulationDuty exist at the same address
427             // but are switchable at runtime via SEMR.MDDRS
428             BitRate             = 0x2,  // BRR
429             ModulationDuty      = 0x2,  // MDDR
430             SerialControl       = 0x4,  // SCR
431             FifoDataTransmit    = 0x6,  // FTDR
432             SerialStatus        = 0x8,  // FSR
433             FifoDataReceive     = 0xA,  // FRDR
434             FifoControl         = 0xC,  // FCR
435             FifoDataCount       = 0xE,  // FDR
436             SerialPort          = 0x10, // SPTR
437             LineStatus          = 0x12, // LSR
438             SerialExtendedMode  = 0x14,  // SEMR
439             FifoTriggerControl  = 0x16,  // FTCR
440         }
441     }
442 }
443