1 //
2 // Copyright (c) 2010-2023 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     public class SiFive_UART : UARTBase, IDoubleWordPeripheral, IKnownSize
17     {
SiFive_UART(IMachine machine, long inputClockFrequency = 16000000)18         public SiFive_UART(IMachine machine, long inputClockFrequency = 16000000) : base(machine)
19         {
20             this.inputClockFrequency = inputClockFrequency;
21 
22             var registersMap = new Dictionary<long, DoubleWordRegister>
23             {
24                 {(long)Registers.TransmitData, new DoubleWordRegister(this)
25                     .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, b) =>
26                     {
27                         if(transmitEnable.Value)
28                         {
29                             this.TransmitCharacter((byte)b);
30                             UpdateInterrupts();
31                         }
32                         else
33                         {
34                             var c = (char)b;
35                             this.Log(LogLevel.Warning, "Trying to transmit '{1}' (0x{0}), but the transmitter is disabled", b, ' ' <= c ? c.ToString() : "<not a printable character>");
36                         }
37                     }, name: "DATA")
38                     .WithTag("RESERVED", 8, 23)
39                     .WithFlag(31, valueProviderCallback: _ => false, name: "FULL")
40                 },
41 
42                 {(long)Registers.ReceiveData, new DoubleWordRegister(this)
43                     // the "EMPTY" flag MUST be declared before "DATA" value field because 'Count' value
44                     // might change as a result of dequeuing a character; otherwise if the queue was of
45                     // length 1, the read of this register would return both the character and "EMPTY" flag
46                     .WithFlag(31, valueProviderCallback: _ => Count == 0, name: "EMPTY")
47                     .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ =>
48                     {
49                         if(!TryGetCharacter(out var character))
50                         {
51                             this.Log(LogLevel.Warning, "Trying to read data from empty receive fifo");
52                         }
53                         return character;
54                     }, name: "DATA")
55                     .WithTag("RESERVED", 8, 23)
56                  },
57 
58                 {(long)Registers.TransmitControl, new DoubleWordRegister(this)
59                     .WithFlag(0, out transmitEnable, name: "TXEN")
60                     .WithFlag(1, out numberOfStopBits, name: "NSTOP")
61                     .WithTag("RESERVED", 2, 14)
62                     .WithValueField(16, 3, out transmitWatermarkLevel, changeCallback: (_, __) => UpdateInterrupts(), name: "TXCNT")
63                     .WithTag("RESERVED", 19, 13)
64                 },
65 
66                 {(long)Registers.ReceiveControl, new DoubleWordRegister(this)
67                     .WithFlag(0, out receiveEnable, changeCallback: (_, val) =>
68                     {
69                         if(!val)
70                         {
71                             ClearBuffer();
72                         }
73                     }, name: "RXEN")
74                     .WithTag("RESERVED", 1, 15)
75                     .WithValueField(16, 3, out receiveWatermarkLevel, changeCallback: (_, __) => UpdateInterrupts(), name: "RXCNT")
76                     .WithTag("RESERVED", 19, 13)
77                 },
78 
79                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
80                     .WithFlag(0, out transmitWatermarkInterruptEnable, changeCallback: (_, __) => UpdateInterrupts(), name: "TXWM")
81                     .WithFlag(1, out receiveWatermarkInterruptEnable, changeCallback: (_, __) => UpdateInterrupts(), name: "RXWM")
82                     .WithTag("RESERVED", 2, 30)
83                 },
84 
85                 {(long)Registers.InterruptPending, new DoubleWordRegister(this)
86                     .WithFlag(0, out transmitWatermarkInterruptPending, FieldMode.Read, name: "TXWM")
87                     .WithFlag(1, out receiveWatermarkInterruptPending, FieldMode.Read, name: "RXWM")
88                     .WithTag("RESERVED", 2, 30)
89                 },
90 
91                 {(long)Registers.BaudrateDivisor, new DoubleWordRegister(this, 0xFFFF)
92                     .WithValueField(0, 16, out baudRateDivisor, name: "DIV")
93                     .WithTag("RESERVED", 16, 16)
94                 }
95             };
96 
97             registers = new DoubleWordRegisterCollection(this, registersMap);
98             IRQ = new GPIO();
99 
100             Reset();
101         }
102 
ReadDoubleWord(long offset)103         public uint ReadDoubleWord(long offset)
104         {
105             lock(innerLock)
106             {
107                 return registers.Read(offset);
108             }
109         }
110 
WriteDoubleWord(long offset, uint value)111         public void WriteDoubleWord(long offset, uint value)
112         {
113             lock(innerLock)
114             {
115                 registers.Write(offset, value);
116             }
117         }
118 
Reset()119         public override void Reset()
120         {
121             base.Reset();
122             registers.Reset();
123             UpdateInterrupts();
124         }
125 
126         public long Size => 0x100;
127         public GPIO IRQ { get; private set; }
128         public override Bits StopBits => numberOfStopBits.Value ? Bits.Two : Bits.One;
129         public override Parity ParityBit => Parity.None;
130         public override uint BaudRate => (uint)(inputClockFrequency / (uint)(1 + baudRateDivisor.Value));
131 
CharWritten()132         protected override void CharWritten()
133         {
134             if(!receiveEnable.Value)
135             {
136                 ClearBuffer();
137             }
138             else
139             {
140                 UpdateInterrupts();
141             }
142         }
143 
QueueEmptied()144         protected override void QueueEmptied()
145         {
146             if(receiveEnable.Value)
147             {
148                 UpdateInterrupts();
149             }
150         }
151 
UpdateInterrupts()152         private void UpdateInterrupts()
153         {
154             lock(innerLock)
155             {
156                 transmitWatermarkInterruptPending.Value = (transmitWatermarkLevel.Value > 0);
157                 receiveWatermarkInterruptPending.Value = (Count > (int)receiveWatermarkLevel.Value);
158 
159                 IRQ.Set(transmitWatermarkInterruptEnable.Value && transmitWatermarkInterruptPending.Value
160 			|| receiveWatermarkInterruptEnable.Value && receiveWatermarkInterruptPending.Value);
161             }
162         }
163 
164         private readonly IFlagRegisterField transmitEnable;
165         private readonly IFlagRegisterField receiveEnable;
166         private readonly IFlagRegisterField numberOfStopBits;
167         private readonly IValueRegisterField baudRateDivisor;
168         private readonly IValueRegisterField transmitWatermarkLevel;
169         private readonly IValueRegisterField receiveWatermarkLevel;
170         private readonly IFlagRegisterField transmitWatermarkInterruptPending;
171         private readonly IFlagRegisterField receiveWatermarkInterruptPending;
172         private readonly IFlagRegisterField transmitWatermarkInterruptEnable;
173         private readonly IFlagRegisterField receiveWatermarkInterruptEnable;
174 
175         private readonly long inputClockFrequency;
176         private readonly DoubleWordRegisterCollection registers;
177 
178         private enum Registers : long
179         {
180             TransmitData = 0x0,
181             ReceiveData = 0x04,
182             TransmitControl = 0x08,
183             ReceiveControl = 0x0C,
184             InterruptEnable = 0x10,
185             InterruptPending = 0x14,
186             BaudrateDivisor = 0x18
187         }
188     }
189 }
190