1 //
2 // Copyright (c) 2010-2024 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 Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Peripherals.UART;
14 using Antmicro.Renode.Utilities;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)]
19     public class RenesasDA14_UART : UARTBase, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
20     {
RenesasDA14_UART(IMachine machine, uint systemClockFrequency = 32000000)21         public RenesasDA14_UART(IMachine machine, uint systemClockFrequency = 32000000) : base(machine)
22         {
23             IRQ = new GPIO();
24             this.systemClockFrequency = systemClockFrequency;
25             RegistersCollection = new DoubleWordRegisterCollection(this);
26 
27             DefineRegisters();
28             Reset();
29         }
30 
Reset()31         public override void Reset()
32         {
33             divider = 0x0;
34             dividerFraction = 0x0;
35             readMode = false;
36 
37             interruptIdentification = InterruptLevel.NoInterruptsPending;
38 
39             base.Reset();
40             RegistersCollection.Reset();
41             IRQ.Unset();
42         }
43 
ReadDoubleWord(long offset)44         public uint ReadDoubleWord(long offset)
45         {
46             readMode = true;
47             return RegistersCollection.Read(offset);
48         }
49 
WriteDoubleWord(long offset, uint value)50         public void WriteDoubleWord(long offset, uint value)
51         {
52             readMode = false;
53             RegistersCollection.Write(offset, value);
54         }
55 
56         public GPIO IRQ { get; }
57 
58         public long Size => 0x100;
59 
60         public override Bits StopBits
61         {
62             get
63             {
64                 if(!stopBits.Value)
65                 {
66                     return Bits.One;
67                 }
68                 // is word length is equal to 5? then 1.5 else 2
69                 return dataLength.Value == LineControlDataLength.FiveBits ? Bits.OneAndAHalf : Bits.Two;
70             }
71         }
72 
73         public override Parity ParityBit
74         {
75             get
76             {
77                 if(!enableParity.Value)
78                 {
79                     return Parity.None;
80                 }
81                 if(!forceParity.Value)
82                 {
83                     return !evenParity.Value ? Parity.Odd : Parity.Even;
84                 }
85                 return !evenParity.Value ? Parity.Forced1 : Parity.Forced0;
86             }
87         }
88 
89         public override uint BaudRate
90         {
91             get
92             {
93                 float divisor = (16 * divider) + (dividerFraction / 16);
94                 return divisor == 0 ? 0 : (uint)(systemClockFrequency / divisor);
95             }
96         }
97 
98         public DoubleWordRegisterCollection RegistersCollection { get; }
99 
QueueEmptied()100         protected override void QueueEmptied()
101         {
102             interruptIndicator &= ~(InterruptIndicator.DataReady);
103             UpdateInterrupts();
104         }
105 
CharWritten()106         protected override void CharWritten()
107         {
108             UpdateInterrupts();
109         }
110 
ReadFifo()111         private byte ReadFifo()
112         {
113             if(!TryGetCharacter(out var character))
114             {
115                 this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO.");
116             }
117             ClearLineStatusIndicators();
118             UpdateInterrupts();
119 
120             return character;
121         }
122 
WriteFifo(byte value)123         private void WriteFifo(byte value)
124         {
125             if(fifoEnable.Value)
126             {
127                 TransmitCharacter(value);
128                 interruptIndicator |= InterruptIndicator.DataReady;
129             }
130             else
131             {
132                 if(interruptIndicator.HasFlag(InterruptIndicator.DataReady))
133                 {
134                     interruptIndicator |= InterruptIndicator.OverrunError;
135                     // FIFO is disabled, in this mode, if we still have data, it is overwritten
136                     ClearBuffer();
137                 }
138                 TransmitCharacter(value);
139                 interruptIndicator |= (InterruptIndicator.DataReady | InterruptIndicator.Break);
140             }
141             UpdateInterrupts();
142         }
143 
ClearLineStatusIndicators()144         private void ClearLineStatusIndicators()
145         {
146             if(!fifoEnable.Value)
147             {
148                 interruptIndicator &= ~InterruptIndicator.DataReady;
149                 interruptIndicator |= InterruptIndicator.Break;
150             }
151             else
152             {
153                 interruptIndicator &= ~InterruptIndicator.Break;
154             }
155             interruptIndicator &= ~(InterruptIndicator.OverrunError | InterruptIndicator.ParityError | InterruptIndicator.FramingError);
156         }
157 
UpdateInterrupts()158         private void UpdateInterrupts()
159         {
160             var interruptId = InterruptLevel.NoInterruptsPending;
161             if(interruptRLSFlagEnable.Value && interruptIndicator > InterruptIndicator.DataReady)
162             {
163                 interruptId = InterruptLevel.ReceiverLineStatusIrq;
164             }
165             else if(InterriuptReceiverDataFlagEnable.Value && (interruptIndicator.HasFlag(InterruptIndicator.DataReady)) && RecvTriggerThresholdReached)
166             {
167                 interruptId = InterruptLevel.ReceiverDataIrq;
168             }
169 
170             interruptIdentification = interruptId;
171 
172             IRQ.Set(interruptId != InterruptLevel.NoInterruptsPending);
173         }
174 
DefineRegisters()175         private void DefineRegisters()
176         {
177             Registers.Data.DefineConditional(this, () => !divisorLatchAccess.Value)
178                 .WithValueField(0, 8, name: "RBR_THR_DLL",
179                         valueProviderCallback: _ => ReadFifo(),
180                         writeCallback: (_, value) =>
181                         {
182                             if(loopback.Value)
183                             {
184                                 base.WriteChar((byte)value);
185                                 return;
186                             }
187                             WriteFifo((byte)value);
188                         })
189                 .WithReservedBits(8, 24);
190 
191             Registers.DivisorLatchL.DefineConditional(this, () => divisorLatchAccess.Value, 0xc)
192                 .WithValueField(0, 8, name: "RBR_THR_DLL",
193                         valueProviderCallback: _ => BitHelper.GetValue(divider, 0, 8),
194                         writeCallback: (_, value) => BitHelper.SetBitsFrom(divider, value, 0, 8))
195                 .WithReservedBits(8, 24);
196 
197             Registers.InterruptEnable.DefineConditional(this, () => !divisorLatchAccess.Value)
198                 .WithFlag(0, out InterriuptReceiverDataFlagEnable, name: "ERBFI_DLH0")
199                 .WithTaggedFlag("ETBEI_DLH1", 1)
200                 .WithFlag(2, out interruptRLSFlagEnable, name: "ELSI_DLH2")
201                 .WithTaggedFlag("ELSI_DLH2", 3)
202                 .WithTaggedFlag("ELCOLR_DLH4", 4)
203                 .WithReservedBits(5, 2)
204                 .WithTaggedFlag("PTIME_DLH7", 7)
205                 .WithReservedBits(8, 24)
206                 .WithWriteCallback((_, __) => UpdateInterrupts());
207 
208             Registers.DivisorLatchH.DefineConditional(this, () => divisorLatchAccess.Value)
209                 .WithValueField(0, 8, name: "ERBFI_DLH0",
210                         valueProviderCallback: _ => BitHelper.GetValue(divider, 8, 8),
211                         writeCallback: (_, value) => BitHelper.SetBitsFrom(divider, value, 8, 8))
212                 .WithReservedBits(8, 24);
213 
214             Registers.FIFOControl.DefineConditional(this, () => readMode)
215                 .WithValueField(0, 4, FieldMode.Read, name: "IID",
216                         valueProviderCallback: _ => (ulong)interruptIndicator)
217                 .WithReservedBits(4, 2)
218                 .WithValueField(6, 2, FieldMode.Read, name: "FIFOSE",
219                         valueProviderCallback: _ => (ulong)(fifoEnable.Value ? 0b11 : 0b00))
220                 .WithReservedBits(8, 24);
221 
222             Registers.FIFOControl.DefineConditional(this, () => !readMode)
223                 .WithFlag(0, out fifoEnable, FieldMode.Write, name: "FIFOE")
224                 .WithFlag(1, FieldMode.Write, name: "RFIFOR",
225                         writeCallback: (_, value) =>
226                         {
227                             if(value)
228                             {
229                                 ClearBuffer();
230                             }
231                         })
232                 .WithFlag(2, FieldMode.Write, name: "XFIFOR")
233                 .WithFlag(3, out dmaMode, FieldMode.Write, name: "DMAM")
234                 .WithEnumField<DoubleWordRegister, TriggerLevel>(4, 2, out txEmptyTrigger, FieldMode.Write, name: "TET")
235                 .WithEnumField<DoubleWordRegister, TriggerLevel>(6, 2, out recvTrigger, FieldMode.Write, name: "RT")
236                 .WithReservedBits(8, 24);
237 
238             Registers.LineControl.Define(this)
239                 .WithEnumField<DoubleWordRegister, LineControlDataLength>(0, 2, out dataLength, name: "UART_DLS")
240                 .WithFlag(2, out stopBits, name: "UART_STOP")
241                 .WithFlag(3, out enableParity, name: "UART_PEN")
242                 .WithFlag(4, out evenParity, name: "UART_EPS")
243                 .WithReservedBits(5, 1)
244                 .WithFlag(6, out forceParity, name: "UART_BC")
245                 .WithFlag(7, out divisorLatchAccess, name: "UART_DLAB")
246                 .WithReservedBits(8, 24);
247 
248             Registers.ModemControl.Define(this)
249                 .WithReservedBits(0, 4)
250                 .WithFlag(4, out loopback, name: "UART_LB")
251                 .WithReservedBits(5, 27);
252 
253             Registers.LineStatus.Define(this)
254                 .WithFlag(0, FieldMode.Read, name: "UART_DR",
255                         valueProviderCallback: _ => interruptIndicator.HasFlag(InterruptIndicator.DataReady))
256                 .WithFlag(1, FieldMode.ReadToClear, name: "UART_OE",
257                         valueProviderCallback: _ => interruptIndicator.HasFlag(InterruptIndicator.OverrunError))
258                 .WithFlag(2, FieldMode.ReadToClear, name: "UART_PE",
259                         valueProviderCallback: _ => interruptIndicator.HasFlag(InterruptIndicator.ParityError))
260                 .WithFlag(3, FieldMode.ReadToClear, name: "UART_FE",
261                         valueProviderCallback: _ => interruptIndicator.HasFlag(InterruptIndicator.FramingError))
262                 .WithFlag(4, FieldMode.ReadToClear, name: "UART_BI",
263                         valueProviderCallback: _ => interruptIndicator.HasFlag(InterruptIndicator.Break))
264                 .WithFlag(5, FieldMode.Read, name: "UART_THRE",
265                         valueProviderCallback: _ => true)
266                 .WithFlag(6, FieldMode.Read, name: "UART_TEMT",
267                         valueProviderCallback: _ => true)
268                 .WithFlag(7, FieldMode.Read, name: "UART_RFE",
269                         valueProviderCallback: _ => false)
270                 .WithTaggedFlag("UART_ADDR_RCVD", 8)
271                 .WithReservedBits(9, 23)
272                 .WithReadCallback((_, __) =>
273                         {
274                             interruptIndicator = InterruptIndicator.None | (interruptIndicator & InterruptIndicator.DataReady);
275                             if(!fifoEnable.Value)
276                             {
277                                 interruptIndicator |= InterruptIndicator.Break;
278                             }
279                         });
280 
281             Registers.ModemStatus.Define(this, 0x4)
282                 .WithFlag(0, out deltaClearToSend, name: "UART_DCTS")
283                 .WithReservedBits(1, 3)
284                 .WithFlag(4, out clearToSend, name: "UART_CTS")
285                 .WithReservedBits(5, 27);
286 
287             Registers.Scratchpad.Define(this)
288                 .WithValueField(0, 8, name: "UART_SCRATCH_PAD")
289                 .WithReservedBits(8, 24);
290 
291             Registers.Status.Define(this, 0x6)
292                 .WithFlag(0, FieldMode.Read, name: "UART_BUSY",
293                         valueProviderCallback: _ => false) // Operations are instantaneous
294                 .WithFlag(1, FieldMode.Read, name: "UART_TFNF",
295                         valueProviderCallback: _ => true) // Transmit fifo not full
296                 .WithFlag(2, FieldMode.Read, name: "UART_TFE",
297                         valueProviderCallback: _ => true) // Transmit fifo empty
298                 .WithFlag(3, FieldMode.Read, name: "UART_RFNE",
299                         valueProviderCallback: _ => Count != 0) // 0 FIFO is empty, 1 FIFO is not empty
300                 .WithFlag(4, FieldMode.Read, name: "UART_RFF",
301                         valueProviderCallback: _ => Count >= ReceiveFIFOSize) // 0 FIFO is not full, 1 FIFO is full
302                 .WithReservedBits(5, 27);
303 
304             Registers.TransmitFifoLevel.Define(this)
305                 .WithValueField(0, 5, FieldMode.Read, name: "UART_TRANSMIT_FIFO_LEVEL",
306                         valueProviderCallback: _ => 0)
307                 .WithReservedBits(5, 27);
308 
309             Registers.ReceiveFifoLevel.Define(this)
310                 .WithValueField(0, 5, FieldMode.Read, name: "UART_RECEIVE_FIFO_LEVEL",
311                         valueProviderCallback: _ => (ulong)Count)
312                 .WithReservedBits(5, 27);
313 
314             Registers.SoftwareReset.Define(this)
315                 .WithFlag(0, FieldMode.WriteOneToClear, name: "UART_UR",
316                         changeCallback: (_, __) => Reset())
317                 .WithFlag(1, FieldMode.WriteOneToClear, name: "UART_RFR",
318                         changeCallback: (_, __) => ClearBuffer())
319                 .WithFlag(2, FieldMode.WriteOneToClear, name: "UART_XFR")
320                 .WithReservedBits(3, 28);
321 
322             Registers.DmaModeShadow.Define(this)
323                 .WithFlag(0, out dmaMode, name: "UART_SHADOW_DMA_MODE")
324                 .WithReservedBits(1, 31);
325 
326             Registers.FIFOEnableShadow.Define(this)
327                 .WithFlag(0, out fifoEnable, name: "UART_SHADOW_FIFO_ENABLE")
328                 .WithReservedBits(1, 31);
329 
330             Registers.RCVRTriggerShadow.Define(this)
331                 .WithEnumField<DoubleWordRegister, TriggerLevel>(0, 2, out recvTrigger, name: "UART_SHADOW_RCVR_TRIGGER")
332                 .WithReservedBits(2, 30);
333 
334             Registers.TXEmptyTriggerShadow.Define(this)
335                 .WithEnumField<DoubleWordRegister, TriggerLevel>(0, 2, out txEmptyTrigger, name: "UART_SHADOW_TX_EMPTY_TRIGGER")
336                 .WithReservedBits(2, 30);
337 
338             Registers.DivisorLatchFraction.Define(this)
339                 .WithValueField(0, 4, name: "UART_DLF",
340                         writeCallback: (_, value) => dividerFraction = (byte)value)
341                 .WithReservedBits(5, 27);
342 
343             Registers.ComponentVersion.Define(this, 0x3430312A)
344                 .WithValueField(0, 32, FieldMode.Read, name: "UART_UCV");
345 
346             Registers.ComponentType.Define(this, 0x44570110)
347                 .WithValueField(0, 32, FieldMode.Read, name: "UART_CTR");
348 
349             Registers.DataShadow0.DefineMany(this, DataShadowRegistersCount, (register, idx) =>
350             {
351                 // Datasheet states that reading/writing to these registers is the same as reading/writing to the head of FIFO
352                 register
353                     .WithValueField(0, 8, name: $"SRBR_STHR{idx}",
354                             valueProviderCallback: _ => ReadFifo(),
355                             writeCallback: (_, value) => WriteFifo((byte)value))
356                     .WithReservedBits(8, 24);
357             });
358         }
359 
360         private uint RecvTriggerThreshold
361         {
362             get
363             {
364                 switch(recvTrigger.Value)
365                 {
366                     case TriggerLevel.FifoEmpty:
367                         return 0;
368                     case TriggerLevel.OneFourthFull:
369                         return ReceiveFIFOSize / 4;
370                     case TriggerLevel.OneHalfFull:
371                         return ReceiveFIFOSize / 2;
372                     case TriggerLevel.TwoLessThanFull:
373                         return ReceiveFIFOSize - 2;
374                     default:
375                         throw new Exception("Unreachable");
376                 }
377             }
378         }
379 
380         private bool RecvTriggerThresholdReached => !fifoEnable.Value || Count > RecvTriggerThreshold;
381 
382         /* Flag used to determine FIFOControl register mode */
383         private bool readMode;
384         /* Interrupt Enable Flags */
385         private IFlagRegisterField InterriuptReceiverDataFlagEnable;
386         private IFlagRegisterField interruptRLSFlagEnable;
387         /* Line Control Flags */
388         private IEnumRegisterField<LineControlDataLength> dataLength;
389         private IFlagRegisterField stopBits;
390         private IFlagRegisterField forceParity;
391         private IFlagRegisterField evenParity;
392         private IFlagRegisterField enableParity;
393         private IFlagRegisterField divisorLatchAccess;
394         /* Modem Control Flags */
395         private IFlagRegisterField loopback;
396         /* Line Status Flags */
397         private InterruptIndicator interruptIndicator;
398         /* Modem Status Flags */
399         private IFlagRegisterField deltaClearToSend;
400         private IFlagRegisterField clearToSend;
401         /* Fifo Control Flags */
402         private IFlagRegisterField fifoEnable;
403         private IFlagRegisterField dmaMode;
404         private IEnumRegisterField<TriggerLevel> txEmptyTrigger;
405         private IEnumRegisterField<TriggerLevel> recvTrigger;
406         private ushort divider;
407         private ushort dividerFraction;
408         private InterruptLevel interruptIdentification;
409         private readonly uint systemClockFrequency;
410 
411         private const int ReceiveFIFOSize = 16;
412         private const int DataShadowRegistersCount = 16;
413 
414         private enum Registers
415         {
416             Data = 0x00,
417             DivisorLatchL = 0x00,
418             // the same as Data but accessible only when DLAB bit is set
419             InterruptEnable = 0x04,
420             DivisorLatchH = 0x04,
421             // the same as Interrupt enable but accessible only when DLAB bit is set
422             FIFOControl = 0x08,
423             LineControl = 0x0C,
424             ModemControl = 0x10,
425             LineStatus = 0x14,
426             ModemStatus = 0x18,
427             Scratchpad = 0x1C,
428             DataShadow0 = 0x30,
429             DataShadow1 = 0x34,
430             DataShadow2 = 0x38,
431             DataShadow3 = 0x3C,
432             DataShadow4 = 0x40,
433             DataShadow5 = 0x44,
434             DataShadow6 = 0x48,
435             DataShadow7 = 0x4C,
436             DataShadow8 = 0x50,
437             DataShadow9 = 0x54,
438             DataShadow10 = 0x58,
439             DataShadow11 = 0x5C,
440             DataShadow12 = 0x60,
441             DataShadow13 = 0x64,
442             DataShadow14 = 0x68,
443             DataShadow15 = 0x6C,
444             Status = 0x7C,
445             TransmitFifoLevel = 0x80,
446             ReceiveFifoLevel = 0x84,
447             SoftwareReset = 0x88,
448             BreakControlShadow = 0x90,
449             DmaModeShadow = 0x94,
450             FIFOEnableShadow = 0x98,
451             RCVRTriggerShadow = 0x9C,
452             TXEmptyTriggerShadow = 0xA0,
453             TXHalt = 0xA4,
454             DMAAck = 0xA8,
455             DivisorLatchFraction = 0xC0,
456             ComponentVersion = 0xF8,
457             ComponentType = 0xFC,
458         }
459 
460         [Flags]
461         private enum InterruptLevel : byte
462         {
463             NoInterruptsPending         = 0b0001,
464             TransmitterHoldingRegEmpty  = 0b0010,
465             ReceiverDataIrq             = 0b0100,
466             ReceiverLineStatusIrq       = 0b0110,
467             BusyDetect                  = 0b0111,
468             CharacterTimeoutIndication  = 0b1100,
469         }
470 
471         [Flags]
472         private enum InterruptIndicator : byte
473         {
474             None            = 0b00000,
475             DataReady       = 0b00001,
476             OverrunError    = 0b00010,
477             ParityError     = 0b00100,
478             FramingError    = 0b01000,
479             Break           = 0b10000,
480         }
481 
482         private enum LineControlDataLength : byte
483         {
484             FiveBits = 0x0,
485             SixBits,
486             SevenBits,
487             EightBits,
488         }
489 
490         private enum TriggerLevel : byte
491         {
492             FifoEmpty = 0x0,
493             OneFourthFull,
494             OneHalfFull,
495             TwoLessThanFull,
496         }
497     }
498 }
499 
500