1 //
2 // Copyright (c) 2010-2022 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;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 
14 namespace Antmicro.Renode.Peripherals.UART
15 {
16     // This model currently does not support timeout feature, rx break detection and software tx pin override
17     public class OpenTitan_UART : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IKnownSize
18     {
OpenTitan_UART(IMachine machine)19         public OpenTitan_UART(IMachine machine) : base(machine)
20         {
21             TxWatermarkIRQ = new GPIO();
22             RxWatermarkIRQ = new GPIO();
23             TxEmptyIRQ = new GPIO();
24             RxOverflowIRQ = new GPIO();
25             RxFrameErrorIRQ = new GPIO();
26             RxBreakErrorIRQ = new GPIO();
27             RxTimeoutIRQ = new GPIO();
28             RxParityErrorIRQ = new GPIO();
29 
30             FatalAlert = new GPIO();
31 
32             registers = new DoubleWordRegisterCollection(this, BuildRegisterMap());
33             txQueue = new Queue<byte>();
34         }
35 
ReadDoubleWord(long offset)36         public uint ReadDoubleWord(long offset)
37         {
38             return registers.Read(offset);
39         }
40 
WriteDoubleWord(long offset, uint value)41         public void WriteDoubleWord(long offset, uint value)
42         {
43             registers.Write(offset, value);
44         }
45 
WriteChar(byte value)46         public override void WriteChar(byte value)
47         {
48             if(lineLoopbackEnabled.Value)
49             {
50                 txOngoing = true;
51                 TransmitCharacter(value);
52                 this.Log(LogLevel.Noisy, "Line Loopback Enabled, byte echoed by hardware.");
53             }
54 
55             if(systemLoopbackEnabled.Value)
56             {
57                 this.Log(LogLevel.Warning, "Sytem Loopback Enabled, incoming byte not queued.");
58                 return;
59             }
60 
61             if(!rxEnabled.Value)
62             {
63                 this.Log(LogLevel.Warning, "CTRL.RX is unset, incoming byte not queued.");
64                 return;
65             }
66 
67             if(Count < rxFIFOCapacity)
68             {
69                 base.WriteChar(value);
70             }
71             else
72             {
73                 rxOverflowPending.Value = true;
74                 this.Log(LogLevel.Warning, "RX FIFO overflowed, incoming byte not queued.");
75             }
76             UpdateBufferState();
77             UpdateInterrupts();
78         }
79 
Reset()80         public override void Reset()
81         {
82             base.Reset();
83             registers.Reset();
84             txQueue.Clear();
85             UpdateInterrupts();
86             FatalAlert.Unset();
87 
88             txOngoing = false;
89             txWatermarkCrossed = false;
90         }
91 
92         public long Size => 0x30;
93         public BufferState BufferState => bufferState;
94 
95         public GPIO TxWatermarkIRQ { get; }
96         public GPIO RxWatermarkIRQ { get; }
97         public GPIO TxEmptyIRQ { get; }
98         public GPIO RxOverflowIRQ { get; }
99         public GPIO RxFrameErrorIRQ { get; }
100         public GPIO RxBreakErrorIRQ { get; }
101         public GPIO RxTimeoutIRQ { get; }
102         public GPIO RxParityErrorIRQ { get; }
103         public GPIO FatalAlert { get; }
104 
105         public event Action<BufferState> BufferStateChanged;
106 
107         public override Bits StopBits => Bits.One;
108 
109         public override Parity ParityBit => parityTypeField.Value == ParityType.Odd ? Parity.Odd : Parity.Even;
110 
111         public override uint BaudRate => (uint)((baudClockRate.Value * fixedClockFrequency) >> 20);
112 
CharWritten()113         protected override void CharWritten()
114         {
115             // intentionally left empty
116         }
117 
QueueEmptied()118         protected override void QueueEmptied()
119         {
120             // intentionally left empty
121         }
122 
BuildRegisterMap()123         private Dictionary<long, DoubleWordRegister> BuildRegisterMap()
124         {
125             return new Dictionary<long, DoubleWordRegister>
126             {
127                 {(long)Registers.InterruptState, new DoubleWordRegister(this)
128                     .WithFlag(0, out txWatermarkPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.tx_watermark")
129                     .WithFlag(1, out rxWatermarkPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_watermark")
130                     .WithFlag(2, out txEmptyPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.tx_empty")
131                     .WithFlag(3, out rxOverflowPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_overflow")
132                     .WithFlag(4, out rxFrameErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_frame_err")
133                     .WithFlag(5, out rxBreakErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_break_err")
134                     .WithFlag(6, out rxTimeoutPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_timeout")
135                     .WithFlag(7, out rxParityErrorPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "INTR_STATE.rx_parity_err")
136                     .WithReservedBits(8, 24)
137                     .WithWriteCallback((_, __) => UpdateInterrupts())
138                 },
139                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
140                     .WithFlag(0, out txWatermarkEnabled, name: "INTR_ENABLE.tx_watermark")
141                     .WithFlag(1, out rxWatermarkEnabled, name: "INTR_ENABLE.rx_watermark")
142                     .WithFlag(2, out txEmptyEnabled, name: "INTR_ENABLE.tx_empty")
143                     .WithFlag(3, out rxOverflowEnabled, name: "INTR_ENABLE.rx_overflow")
144                     .WithFlag(4, out rxFrameErrorEnabled, name: "INTR_ENABLE.rx_frame_err")
145                     .WithFlag(5, out rxBreakErrorEnabled, name: "INTR_ENABLE.rx_break_err")
146                     .WithFlag(6, out rxTimeoutEnabled, name: "INTR_ENABLE.rx_timeout")
147                     .WithFlag(7, out rxParityErrorEnabled, name: "INTR_ENABLE.rx_parity_err")
148                     .WithReservedBits(8, 24)
149                     .WithWriteCallback((_, __) => UpdateInterrupts())
150                 },
151                 {(long)Registers.InterruptTest, new DoubleWordRegister(this)
152                     .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { txWatermarkPending.Value |= val; },  name: "INTR_TEST.tx_watermark")
153                     .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { rxWatermarkPending.Value |= val; },  name: "INTR_TEST.rx_watermark")
154                     .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { txEmptyPending.Value |= val; },  name: "INTR_TEST.tx_empty")
155                     .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { rxOverflowPending.Value |= val; },  name: "INTR_TEST.rx_overflow")
156                     .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { rxFrameErrorPending.Value |= val; },  name: "INTR_TEST.rx_frame_err")
157                     .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { rxBreakErrorPending.Value |= val; },  name: "INTR_TEST.rx_break_err")
158                     .WithFlag(6, FieldMode.Write, writeCallback: (_, val) => { rxTimeoutPending.Value |= val; },  name: "INTR_TEST.rx_timeout")
159                     .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { rxParityErrorPending.Value |= val; },  name: "INTR_TEST.rx_parity_err")
160                     .WithReservedBits(8, 24)
161                     .WithWriteCallback((_, __) => UpdateInterrupts())
162                 },
163                 {(long)Registers.AlertTest, new DoubleWordRegister(this)
164                     .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
165                     .WithIgnoredBits(1, 31)
166                 },
167                 {(long)Registers.Control, new DoubleWordRegister(this)
168                     .WithFlag(0, out txEnabled, name: "CTRL.TX", writeCallback: (_, val) =>
169                     {
170                         if(val)
171                         {
172                             if(!lineLoopbackEnabled.Value)
173                             {
174                                 foreach(byte value in txQueue)
175                                 {
176                                     txOngoing = true;
177                                     TransmitCharacter(value);
178                                 }
179                             }
180                             txQueue.Clear();
181                             UpdateInterrupts();
182                         }
183                     })
184                     .WithFlag(1, out rxEnabled, name: "CTRL.RX")
185                     .WithFlag(2, out noiseFilterEnabled, name: "CTRL.NF")
186                     .WithReservedBits(3, 1)
187                     .WithFlag(4, out systemLoopbackEnabled, name: "CTRL.SLPBK")
188                     .WithFlag(5, out lineLoopbackEnabled, name: "CTRL.LLPBK")
189                     .WithFlag(6, out parityEnabled, name: "CTRL.PARITY_EN")
190                     .WithEnumField(7, 1, out parityTypeField, name: "CTRL.PARITY_ODD")
191                     .WithTag("CTRL.RXBLVL", 8, 2)
192                     .WithReservedBits(10, 6)
193                     .WithValueField(16, 16, out baudClockRate, name: "CTRL.NCO")
194                 },
195                 {(long)Registers.LiveStatus, new DoubleWordRegister(this)
196                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == txFIFOCapacity, name: "STATUS.TXFULL")
197                     .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => Count == rxFIFOCapacity, name: "STATUS.RXFULL")
198                     .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "STATUS.TXEMPTY")
199                     .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => txQueue.Count == 0, name: "STATUS.TXIDLE")
200                     .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => true, name: "STATUS.RXIDLE")
201                     .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => Count == 0, name: "STATUS.RXEMPTY")
202                     .WithReservedBits(6, 26)
203                 },
204                 {(long)Registers.ReadData, new DoubleWordRegister(this)
205                     .WithValueField(0, 8, FieldMode.Read, name: "RDATA", valueProviderCallback: _ =>
206                     {
207                         if(!TryGetCharacter(out var character))
208                         {
209                             this.Log(LogLevel.Warning, "Trying to read from an empty Rx FIFO.");
210                         }
211                         UpdateBufferState();
212                         return character;
213                     })
214                     .WithReservedBits(8, 24)
215                     .WithWriteCallback((_, __) => UpdateInterrupts())
216                 },
217                 {(long)Registers.WriteData, new DoubleWordRegister(this)
218                     .WithValueField(0, 8, FieldMode.Write, name: "WDATA", writeCallback: (_, val) =>
219                     {
220                         if(systemLoopbackEnabled.Value)
221                         {
222                             base.WriteChar((byte)val);
223                             UpdateBufferState();
224                             return;
225                         }
226 
227                         if(txEnabled.Value)
228                         {
229                             txOngoing = true;
230                             TransmitCharacter((byte)val);
231                         }
232                         else if(txQueue.Count < txFIFOCapacity)
233                         {
234                             txQueue.Enqueue((byte)val);
235                             if(txQueue.Count >= TxWatermarkValue) {
236                                 txWatermarkCrossed = true;
237                             }
238                         }
239                         else
240                         {
241                             this.Log(LogLevel.Warning, "Trying to write to a full Tx FIFO.");
242                         }
243                     })
244                     .WithReservedBits(8, 24)
245                     .WithWriteCallback((_, __) => UpdateInterrupts())
246                 },
247                 {(long)Registers.FIFOControl, new DoubleWordRegister(this)
248                     .WithFlag(0, FieldMode.Write, name: "FIFO_CTRL.RXRST", writeCallback: (_, val) =>
249                     {
250                         if(val)
251                         {
252                             ClearBuffer();
253                         }
254                     })
255                     .WithFlag(1, FieldMode.Write, name: "FIFO_CTRL.TXRST", writeCallback: (_, val) =>
256                     {
257                         if(val)
258                         {
259                             txQueue.Clear();
260                             txWatermarkCrossed = false;
261                         }
262                     })
263                     .WithEnumField(2, 3, out rxWatermarkField, name: "FIFO_CTRL.RXILVL")
264                     .WithEnumField(5, 2, out txWatermarkField, name: "FIFO_CTRL.TXILVL")
265                     .WithReservedBits(7, 25)
266                     .WithWriteCallback((_, __) => UpdateInterrupts())
267                 },
268                 {(long)Registers.FIFOStatus, new DoubleWordRegister(this)
269                     .WithValueField(0, 6, FieldMode.Read, valueProviderCallback: _ => (uint)txQueue.Count, name: "FIFO_STATUS.TXLVL")
270                     .WithReservedBits(6, 10)
271                     .WithValueField(16, 6, FieldMode.Read, valueProviderCallback: _ => (uint)Count, name: "FIFO_STATUS.RXLVL")
272                     .WithReservedBits(22, 10)
273                 },
274                 {(long)Registers.TxPinOverrideControl, new DoubleWordRegister(this)
275                     .WithTaggedFlag("OVRD.TXEN", 0)
276                     .WithTaggedFlag("OVRD.TXVAL", 1)
277                     .WithReservedBits(2, 30)
278                 },
279                 {(long)Registers.OversampledValues, new DoubleWordRegister(this)
280                     .WithTag("VAL.RX", 0, 16)
281                     .WithReservedBits(16, 16)
282                 },
283                 {(long)Registers.RxTimeoutControl, new DoubleWordRegister(this)
284                     .WithTag("TIMEOUT_CTRL.VAL", 0, 24)
285                     .WithReservedBits(24, 7)
286                     .WithTaggedFlag("TIMEOUT_CTRL.EN", 31)
287                 }
288             };
289         }
290 
UpdateInterrupts()291         private void UpdateInterrupts()
292         {
293             rxWatermarkPending.Value |= RxWatermarkValue <= Count;
294 
295             if (txWatermarkCrossed && txQueue.Count < TxWatermarkValue) {
296                 txWatermarkPending.Value = true;
297                 txWatermarkCrossed = false;
298             }
299 
300             if(txOngoing && txQueue.Count == 0)
301             {
302                 txOngoing = false;
303                 txEmptyPending.Value = true;
304             }
305 
306             TxWatermarkIRQ.Set(txWatermarkPending.Value && txWatermarkEnabled.Value);
307             RxWatermarkIRQ.Set(rxWatermarkPending.Value && rxWatermarkEnabled.Value);
308             TxEmptyIRQ.Set(txEmptyPending.Value && txEmptyEnabled.Value);
309             RxOverflowIRQ.Set(rxOverflowPending.Value && rxOverflowEnabled.Value);
310             RxFrameErrorIRQ.Set(rxFrameErrorPending.Value && rxFrameErrorEnabled.Value);
311             RxBreakErrorIRQ.Set(rxBreakErrorPending.Value && rxBreakErrorEnabled.Value);
312             RxTimeoutIRQ.Set(rxTimeoutPending.Value && rxTimeoutEnabled.Value);
313             RxParityErrorIRQ.Set(rxParityErrorPending.Value && rxParityErrorEnabled.Value);
314         }
315 
UpdateBufferState()316         private void UpdateBufferState()
317         {
318             if((Count < rxFIFOCapacity && bufferState == BufferState.Full) ||
319                (Count != 0 && bufferState == BufferState.Empty) ||
320                ((Count == 0 || Count >= rxFIFOCapacity) && bufferState == BufferState.Ready))
321             {
322                 if(Count == 0)
323                 {
324                     bufferState = BufferState.Empty;
325                 }
326                 else if(Count >= rxFIFOCapacity)
327                 {
328                     bufferState = BufferState.Full;
329                 }
330                 else
331                 {
332                     bufferState = BufferState.Ready;
333                 }
334 
335                 BufferStateChanged?.Invoke(bufferState);
336             }
337         }
338 
339         private int RxWatermarkValue
340         {
341             get
342             {
343                 switch(rxWatermarkField.Value)
344                 {
345                     default:
346                         this.Log(LogLevel.Error, "Unexpected state of rxWatermarkField ({0})", rxWatermarkField.Value);
347                         return 1;
348                     case RxWatermarkLevel.Level1:
349                         return 1;
350                     case RxWatermarkLevel.Level4:
351                         return 4;
352                     case RxWatermarkLevel.Level8:
353                         return 8;
354                     case RxWatermarkLevel.Level16:
355                         return 16;
356                     case RxWatermarkLevel.Level30:
357                         return 30;
358                 }
359             }
360         }
361 
362         private int TxWatermarkValue
363         {
364             get
365             {
366                 switch(txWatermarkField.Value)
367                 {
368                     default:
369                         this.Log(LogLevel.Error, "Unexpected state of txWatermarkField ({0})", txWatermarkField.Value);
370                         return 2;
371                     case TxWatermarkLevel.Level1:
372                         return 2;
373                     case TxWatermarkLevel.Level4:
374                         return 4;
375                     case TxWatermarkLevel.Level8:
376                         return 8;
377                     case TxWatermarkLevel.Level16:
378                         return 16;
379                 }
380             }
381         }
382 
383         private readonly DoubleWordRegisterCollection registers;
384         private readonly Queue<byte> txQueue;
385         // InterruptState
386         private IFlagRegisterField txWatermarkPending;
387         private IFlagRegisterField rxWatermarkPending;
388         private IFlagRegisterField txEmptyPending;
389         private IFlagRegisterField rxOverflowPending;
390         private IFlagRegisterField rxFrameErrorPending;
391         private IFlagRegisterField rxBreakErrorPending;
392         private IFlagRegisterField rxTimeoutPending;
393         private IFlagRegisterField rxParityErrorPending;
394         // InterruptEnable
395         private IFlagRegisterField txWatermarkEnabled;
396         private IFlagRegisterField rxWatermarkEnabled;
397         private IFlagRegisterField txEmptyEnabled;
398         private IFlagRegisterField rxOverflowEnabled;
399         private IFlagRegisterField rxFrameErrorEnabled;
400         private IFlagRegisterField rxBreakErrorEnabled;
401         private IFlagRegisterField rxTimeoutEnabled;
402         private IFlagRegisterField rxParityErrorEnabled;
403         // Control
404         private IFlagRegisterField txEnabled;
405         private IFlagRegisterField rxEnabled;
406         private IFlagRegisterField noiseFilterEnabled;
407         private IFlagRegisterField systemLoopbackEnabled;
408         private IFlagRegisterField lineLoopbackEnabled;
409         private IFlagRegisterField parityEnabled;
410         private IEnumRegisterField<ParityType> parityTypeField;
411         private IValueRegisterField baudClockRate;
412         // FIFOControl
413         private IEnumRegisterField<RxWatermarkLevel> rxWatermarkField;
414         private IEnumRegisterField<TxWatermarkLevel> txWatermarkField;
415 
416         private bool txOngoing;
417         private bool txWatermarkCrossed;
418         private BufferState bufferState;
419 
420         private const int rxFIFOCapacity = 32;
421         private const int txFIFOCapacity = 32;
422         private const ulong fixedClockFrequency = 50000000;
423 
424         private enum ParityType
425         {
426             Even = 0,
427             Odd  = 1
428         }
429 
430         private enum RxWatermarkLevel
431         {
432             Level1  = 0,
433             Level4  = 1,
434             Level8  = 2,
435             Level16 = 3,
436             Level30 = 4
437         }
438 
439         private enum TxWatermarkLevel
440         {
441             Level1  = 0,
442             Level4  = 1,
443             Level8  = 2,
444             Level16 = 3
445         }
446 
447         private enum Registers : long
448         {
449             InterruptState       = 0x0,
450             InterruptEnable      = 0x4,
451             InterruptTest        = 0x8,
452             AlertTest            = 0xC,
453             Control              = 0x10,
454             LiveStatus           = 0x14,
455             ReadData             = 0x18,
456             WriteData            = 0x1C,
457             FIFOControl          = 0x20,
458             FIFOStatus           = 0x24,
459             TxPinOverrideControl = 0x28,
460             OversampledValues    = 0x2C,
461             RxTimeoutControl     = 0x30,
462         }
463     }
464 }
465