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 Antmicro.Renode.Core;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Migrant;
13 using System;
14 using System.Collections.Generic;
15 
16 namespace Antmicro.Renode.Peripherals.UART
17 {
18     // Due to unusual register offsets we cannot use address translations
19     public class SAMD20_UART : IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral, IUART, IKnownSize
20     {
SAMD20_UART(IMachine machine)21         public SAMD20_UART(IMachine machine)
22         {
23             IRQ = new GPIO();
24 
25             var registersMap = new Dictionary<long, DoubleWordRegister>
26             {
27                 {(long)Registers.ControlA, new DoubleWordRegister(this)
28                     .WithFlag(0,
29                         writeCallback: (_, val) =>
30                         {
31                             if(!val)
32                             {
33                                 return;
34                             }
35                             // According to the docs writing '1' to this bit should reset all registers except Debug Control,
36                             // but since that register is a stub, we don't bother.
37                             Reset();
38                             enabled.Value = false;
39                         },
40                         valueProviderCallback: _ => false,
41                         name: "Software reset (SWRST)")
42                     .WithFlag(1, out enabled, name: "Enable (ENABLE)")
43                     .WithTag("Operating mode (MODE)", 2, 3)
44                     .WithReservedBits(5, 2)
45                     .WithTag("Run in standby (RUNSTDBY)", 7, 1)
46                     .WithTag("Immediate buffer overflow notification (IBON)", 8, 1)
47                     .WithReservedBits(9, 7)
48                     .WithTag("Transmit data pinout (TXPO)", 16, 1)
49                     .WithReservedBits(17, 3)
50                     .WithTag("Receive data pinout (RXPO)", 20, 2)
51                     .WithReservedBits(22, 2)
52                     .WithEnumField(24, 4, out frameFormat, name: "Frame format (FORM)")
53                     .WithTag("Communication mode (CMODE)", 28, 1)
54                     .WithTag("Clock polarity (CPOL)", 29, 1)
55                     .WithTag("Data order (DORD)", 30, 1)
56                     .WithReservedBits(31, 1)
57                 },
58 
59                 {(long)Registers.ControlB, new DoubleWordRegister(this)
60                     .WithTag("Character Size (CHSIZE)", 0, 3)
61                     .WithReservedBits(3, 3)
62                     .WithFlag(6, out stopBitMode, name: "Stop bit mode (SBMODE)")
63                     .WithReservedBits(7, 6)
64                     .WithFlag(13, out parityMode, name: "Parity mode (PMODE)")
65                     .WithReservedBits(14, 2)
66                     .WithFlag(16, out transmitterEnabled, name: "Transmitter enable (TXEN)")
67                     .WithFlag(17, out receiverEnabled, name: "Receiver enable (RXEN)")
68                     .WithReservedBits(18, 14)
69                 },
70 
71                 {(long)Registers.DebugControl, new DoubleWordRegister(this)
72                     .WithTag("Debug stop mode (DGBSTOP)", 0, 1)
73                     .WithReservedBits(1, 7)
74                     .WithIgnoredBits(8, 24)
75                 },
76 
77                 {(long)Registers.Baudrate, new DoubleWordRegister(this)
78                     .WithValueField(0, 16, out baudrate, name: "Baudrate (BAUD)")
79                     .WithIgnoredBits(16, 16)
80                 },
81 
82                 {(long)Registers.InterruptEnableClear, new DoubleWordRegister(this)
83                     .WithFlag(0, out dataRegisterEmptyInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Data register empty interrupt disabled (DRE)")
84                     .WithFlag(1, out transmitCompleteInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Transmit complete interrupt disabled (TXC)")
85                     .WithFlag(2, out receiveCompleteInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Receive complete interrupt disabled (RXC)")
86                     .WithFlag(3, out receiveStartedInterruptEnabled, FieldMode.Read | FieldMode.WriteOneToClear, name: "Receive start interrupt disabled (RXS)")
87                     .WithReservedBits(4, 4)
88                     .WithIgnoredBits(8, 24)
89                     .WithWriteCallback((_, __) => UpdateInterrupts())
90                 },
91 
92                 {(long)Registers.InterruptEnableSet, new DoubleWordRegister(this)
93                     .WithFlag(0,
94                         writeCallback: (_, val) => dataRegisterEmptyInterruptEnabled.Value |= val,
95                         valueProviderCallback: _ => dataRegisterEmptyInterruptEnabled.Value,
96                         name: "Data register empty interrupt enabled (DRE)")
97                     .WithFlag(1,
98                         writeCallback: (_, val) => transmitCompleteInterruptEnabled.Value |= val,
99                         valueProviderCallback: _ => transmitCompleteInterruptEnabled.Value,
100                         name: "Transmit complete interrupt enabled (TXC)")
101                     .WithFlag(2,
102                         writeCallback: (_, val) => receiveCompleteInterruptEnabled.Value |= val,
103                         valueProviderCallback: _ => receiveCompleteInterruptEnabled.Value,
104                         name: "Receive complete interrupt enabled (RXC)")
105                     .WithFlag(3,
106                         writeCallback: (_, val) => receiveStartedInterruptEnabled.Value |= val,
107                         valueProviderCallback: _ => receiveStartedInterruptEnabled.Value,
108                         name: "Receive start interrupt enabled (RXS)")
109                     .WithReservedBits(4, 4)
110                     .WithIgnoredBits(8, 24)
111                     .WithWriteCallback((_, __) => UpdateInterrupts())
112                 },
113 
114                 {(long)Registers.InterruptFlagStatusAndClear, new DoubleWordRegister(this)
115                     .WithFlag(0, FieldMode.Read,
116                         valueProviderCallback: _ => receiveQueue.Count == 0, name: "Data register empty (DRE)")
117                     .WithFlag(1, out transmitComplete, FieldMode.WriteOneToClear | FieldMode.Read, name: "Transmit complete (TXC)")
118                     .WithFlag(2, FieldMode.Read,
119                         valueProviderCallback: _ => receiveQueue.Count > 0, name: "Receive complete (RXC)")
120                     .WithTag("Receive start (RXS)", 3, 1)
121                     .WithReservedBits(4, 4)
122                     .WithIgnoredBits(8, 24)
123                 },
124 
125                 {(long)Registers.Status, new DoubleWordRegister(this)
126                     .WithTag("Parity error (PERR)", 0, 1)
127                     .WithTag("Frame error (FERR)", 1, 1)
128                     .WithTag("Buffer overflow (BUFOVF)", 2, 1)
129                     .WithReservedBits(3, 12)
130                     .WithTag("Synchronization busy (SYNCBUSY))", 15, 1)
131                     .WithIgnoredBits(16, 16)
132                 },
133 
134                 {(long)Registers.Data, new DoubleWordRegister(this)
135                     .WithValueField(0, 9,
136                         writeCallback: (_, val) => HandleTransmitData((uint)val),
137                         valueProviderCallback: _ => HandleReceiveData(),
138                         name: "DATA")
139                     .WithReservedBits(9, 7)
140                     .WithIgnoredBits(16, 16)
141                 }
142             };
143 
144             registers = new DoubleWordRegisterCollection(this, registersMap);
145             Reset();
146         }
147 
Reset()148         public void Reset()
149         {
150             registers.Reset();
151             receiveQueue.Clear();
152             UpdateInterrupts();
153         }
154 
ReadDoubleWord(long offset)155         public uint ReadDoubleWord(long offset)
156         {
157             return registers.Read(offset);
158         }
159 
WriteDoubleWord(long offset, uint value)160         public void WriteDoubleWord(long offset, uint value)
161         {
162             registers.Write(offset, value);
163         }
164 
ReadWord(long offset)165         public ushort ReadWord(long offset)
166         {
167             return (ushort)ReadDoubleWord(offset);
168         }
169 
WriteWord(long offset, ushort value)170         public void WriteWord(long offset, ushort value)
171         {
172             WriteDoubleWord(offset, value);
173         }
174 
ReadByte(long offset)175         public byte ReadByte(long offset)
176         {
177             return (byte) ReadDoubleWord(offset);
178         }
179 
WriteByte(long offset, byte value)180         public void WriteByte(long offset, byte value)
181         {
182             WriteDoubleWord(offset, value);
183         }
184 
WriteChar(byte value)185         public void WriteChar(byte value)
186         {
187             if(!enabled.Value || !receiverEnabled.Value)
188             {
189                 this.Log(LogLevel.Warning, "Char was received, but the receiver (or the whole USART) is not enabled. Ignoring.");
190                 return;
191             }
192             receiveQueue.Enqueue(value);
193             UpdateInterrupts();
194         }
195 
196         public uint BaudRate => (uint)baudrate.Value;
197 
198         public Bits StopBits => stopBitMode.Value ? Bits.Two : Bits.One;
199 
200         public Parity ParityBit
201         {
202             get
203             {
204                 if(frameFormat.Value == FrameFormat.WithParity)
205                 {
206                     return parityMode.Value ? Parity.Odd : Parity.Even;
207                 }
208                 return Parity.None;
209             }
210         }
211 
212         public GPIO IRQ { get; }
213 
214         [field: Transient]
215         public event Action<byte> CharReceived;
216 
217         public long Size => 0x100;
218 
HandleTransmitData(uint value)219         private void HandleTransmitData(uint value)
220         {
221             if(!enabled.Value || !transmitterEnabled.Value)
222             {
223                 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring.");
224                 return;
225             }
226             CharReceived?.Invoke((byte)value);
227             transmitComplete.Value = true;
228             UpdateInterrupts();
229         }
230 
HandleReceiveData()231         private uint HandleReceiveData()
232         {
233             if(receiveQueue.TryDequeue(out var result))
234             {
235                 UpdateInterrupts();
236             }
237             return result;
238         }
239 
UpdateInterrupts()240         private void UpdateInterrupts()
241         {
242             var value = (transmitComplete.Value && transmitCompleteInterruptEnabled.Value)
243                 || (receiveQueue.Count == 0 && dataRegisterEmptyInterruptEnabled.Value)
244                 || (receiveQueue.Count > 0 && receiveCompleteInterruptEnabled.Value);
245             IRQ.Set(value);
246         }
247 
248         private readonly IFlagRegisterField dataRegisterEmptyInterruptEnabled;
249         private readonly IFlagRegisterField transmitCompleteInterruptEnabled;
250         private readonly IFlagRegisterField receiveCompleteInterruptEnabled;
251         private readonly IFlagRegisterField receiveStartedInterruptEnabled;
252         private readonly IFlagRegisterField enabled;
253         private readonly IFlagRegisterField transmitterEnabled;
254         private readonly IFlagRegisterField receiverEnabled;
255         private readonly IFlagRegisterField transmitComplete;
256         private readonly IFlagRegisterField parityMode;
257         private readonly IEnumRegisterField<FrameFormat> frameFormat;
258         private readonly IFlagRegisterField stopBitMode;
259 
260         private readonly IValueRegisterField baudrate;
261 
262         private readonly DoubleWordRegisterCollection registers;
263         private readonly Queue<byte> receiveQueue = new Queue<byte>();
264 
265         private enum FrameFormat : int
266         {
267             NoParity = 0x0,
268             WithParity = 0x1
269             // 0x2-0xF Reserved
270         }
271 
272         private enum Registers : long
273         {
274             ControlA = 0x00,
275             ControlB = 0x04,
276             DebugControl = 0x08,
277             // 0x9 - reserved
278             Baudrate = 0x0A,
279             InterruptEnableClear = 0x0C,
280             InterruptEnableSet = 0x0D,
281             InterruptFlagStatusAndClear = 0x0E,
282             // 0xF - reserved
283             Status = 0x10,
284             // 0x11:0x17 - reserved
285             Data = 0x18
286         }
287     }
288 }
289