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.Threading;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Core;
12 using System.Collections.Generic;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Migrant;
15 using Antmicro.Renode.Time;
16 
17 namespace Antmicro.Renode.Peripherals.UART
18 {
19     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
20     public sealed class STM32F7_USART : UARTBase, IUARTWithBufferState, IDoubleWordPeripheral, IKnownSize
21     {
STM32F7_USART(IMachine machine, uint frequency, bool lowPowerMode = false)22         public STM32F7_USART(IMachine machine, uint frequency, bool lowPowerMode = false) : base(machine)
23         {
24             IRQ = new GPIO();
25             ReceiveDmaRequest = new GPIO();
26             RegistersCollection = new DoubleWordRegisterCollection(this);
27             this.frequency = frequency;
28             this.lowPowerMode = lowPowerMode;
29             DefineRegisters();
30         }
31 
Reset()32         public override void Reset()
33         {
34             base.Reset();
35             RegistersCollection.Reset();
36             IRQ.Unset();
37             receiverTimeoutCancellationTokenSrc?.Cancel();
38             ReceiveDmaRequest.Unset();
39         }
40 
ReadDoubleWord(long offset)41         public uint ReadDoubleWord(long offset)
42         {
43             return RegistersCollection.Read(offset);
44         }
45 
WriteDoubleWord(long offset, uint value)46         public void WriteDoubleWord(long offset, uint value)
47         {
48             RegistersCollection.Write(offset, value);
49         }
50 
51         public override uint BaudRate => BaudRateMultiplier * frequency / (uint)baudRateDivisor.Value;
52 
53         public override Bits StopBits
54         {
55             get
56             {
57                 switch(stopBits.Value)
58                 {
59                 case 0:
60                     return Bits.One;
61                 case 1:
62                     return Bits.Half;
63                 case 2:
64                     return Bits.Two;
65                 case 3:
66                     return Bits.OneAndAHalf;
67                 default:
68                     throw new InvalidOperationException("Should not reach here.");
69                 }
70             }
71         }
72 
73         public override Parity ParityBit
74         {
75             get
76             {
77                 if(!parityControlEnabled.Value)
78                 {
79                     return Parity.None;
80                 }
81                 return paritySelection.Value ? Parity.Odd : Parity.Even;
82             }
83         }
84 
85         public BufferState BufferState
86         {
87             get
88             {
89                 return bufferState;
90             }
91 
92             private set
93             {
94                 if(bufferState == value)
95                 {
96                     return;
97                 }
98                 bufferState = value;
99                 UpdateInterrupt();
100                 BufferStateChanged?.Invoke(value);
101                 ReceiveDmaRequest.Set(receiveDmaEnabled.Value && value != BufferState.Empty);
102             }
103         }
104 
105         public event Action<BufferState> BufferStateChanged;
106 
107         public GPIO IRQ { get; }
108         public GPIO ReceiveDmaRequest { get; }
109 
110         public long Size => 0x400;
111 
112         public DoubleWordRegisterCollection RegistersCollection { get; }
113 
CharWritten()114         protected override void CharWritten()
115         {
116             BufferState = BufferState.Ready;
117             if(receiverTimeoutOccurred != null && receiverTimeoutInterruptEnable.Value)
118             {
119                 // We just got a character - cancel the previous action
120                 // If it has already executed - then it's alright, since the timeout held
121                 receiverTimeoutCancellationTokenSrc?.Cancel();
122                 // Set up a new action to fire after specified time if no characters are received
123                 // again, if it receives any, this should be cancelled too, in the exact same way
124                 receiverTimeoutCancellationTokenSrc = new CancellationTokenSource();
125                 // Receiver timeout is specified in bits of inactivity, so divide by the baud rate to calculate time
126                 // and multiply by 8 since it's a baud rate (measures bits), and by million to convert to microseconds
127                 var timeoutIn = (receiverTimeout.Value * 8000000) / BaudRate;
128                 Machine.ScheduleAction(TimeInterval.FromMicroseconds(timeoutIn), _ => ReportRxTimeout(receiverTimeoutCancellationTokenSrc.Token), name: $"{nameof(STM32F7_USART)} Receiver timeout");
129             }
130         }
131 
QueueEmptied()132         protected override void QueueEmptied()
133         {
134             BufferState = BufferState.Empty;
135         }
136 
137         protected override bool IsReceiveEnabled => receiveEnabled.Value && enabled.Value;
138 
DefineRegisters()139         private void DefineRegisters()
140         {
141             var cr1 = Registers.ControlRegister1.Define(RegistersCollection)
142                 .WithFlag(0, out enabled, name: "UE")
143                 .WithTaggedFlag("UESM", 1)
144                 .WithFlag(2, out receiveEnabled, name: "RE")
145                 .WithFlag(3, out transmitEnabled, writeCallback: (_, value) =>
146                 {
147                     if(!value)
148                     {
149                         transferComplete.Value = true;
150                     }
151                 }, name: "TE")
152                 .WithTaggedFlag("IDLEIE", 4)
153                 .WithFlag(5, out readRegisterNotEmptyInterruptEnabled, name: "RXNEIE")
154                 .WithFlag(6, out transferCompleteInterruptEnabled, name: "TCIE")
155                 .WithFlag(7, out transmitRegisterEmptyInterruptEnabled, name: "TXEIE")
156                 .WithFlag(8, name: "PEIE")
157                 .WithFlag(9, out paritySelection, name: "PS")
158                 .WithFlag(10, out parityControlEnabled, name: "PCE")
159                 .WithTaggedFlag("WAKE", 11)
160                 .WithTaggedFlag("MO", 12)
161                 .WithTaggedFlag("MME", 13)
162                 .WithTaggedFlag("CMIE", 14)
163                 .WithTag("DEDT", 16, 5)
164                 .WithTag("DEAT", 21, 5)
165                 .WithTaggedFlag("M1", 28)
166                 .WithReservedBits(29, 3)
167                 .WithWriteCallback((_, __) => UpdateInterrupt());
168 
169             var cr2 = Registers.ControlRegister2.Define(RegistersCollection)
170                 .WithReservedBits(0, 4)
171                 .WithTaggedFlag("ADDM7", 4)
172                 .WithReservedBits(7, 1)
173                 .WithValueField(12, 2, out stopBits)
174                 .WithTaggedFlag("SWAP", 15)
175                 .WithTaggedFlag("RXINV", 16)
176                 .WithTaggedFlag("TXINV", 17)
177                 .WithTaggedFlag("DATAINV", 18)
178                 .WithTaggedFlag("MSBFIRST", 19)
179                 .WithTag("ADD", 24, 8);
180 
181             var cr3 = Registers.ControlRegister3.Define(RegistersCollection)
182                 .WithTaggedFlag("EIE", 0)
183                 .WithTaggedFlag("HDSEL", 3)
184                 .WithFlag(6, out receiveDmaEnabled, name: "DMAR")
185                 .WithFlag(7, name: "DMAT")
186                 .WithTaggedFlag("RTSE", 8)
187                 .WithTaggedFlag("CTSE", 9)
188                 .WithTaggedFlag("CTSIE", 10)
189                 .WithTaggedFlag("OVRDIS", 12)
190                 .WithTaggedFlag("DDRE", 13)
191                 .WithTaggedFlag("DEM", 14)
192                 .WithTaggedFlag("DEP", 15)
193                 .WithReservedBits(16, 1)
194                 .WithTag("WUS", 20, 2)
195                 .WithTaggedFlag("WUFIE", 22)
196                 .WithTaggedFlag("UCESM", 23)
197                 .WithReservedBits(25, 7);
198 
199             if(lowPowerMode)
200             {
201                 Registers.BaudRate.Define(RegistersCollection)
202                     .WithValueField(0, 20, out baudRateDivisor, name: "BRR")
203                     .WithReservedBits(20, 12);
204             }
205             else
206             {
207                 Registers.BaudRate.Define(RegistersCollection)
208                     .WithValueField(0, 16, out baudRateDivisor, name: "BRR")
209                     .WithReservedBits(16, 16);
210             }
211 
212             var request = Registers.Request.Define(RegistersCollection)
213                 .WithFlag(1, FieldMode.Write, name: "SBKRQ")
214                 .WithFlag(2, FieldMode.Write, name: "MMRQ")
215                 .WithFlag(3, FieldMode.Write, writeCallback: (_, value) =>
216                 {
217                     if(value)
218                     {
219                         ClearBuffer();
220                     }
221                 }, name: "RXFRQ")
222                 .WithReservedBits(6, 26);
223 
224             var isr = Registers.InterruptAndStatus.Define(RegistersCollection, lowPowerMode ? 0xC0u : 0x200000C0u)
225                 .WithTaggedFlag("PE", 0)
226                 .WithTaggedFlag("FE", 1)
227                 .WithTaggedFlag("NF", 2)
228                 .WithTaggedFlag("ORE", 3)
229                 .WithTaggedFlag("IDLE", 4)
230                 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => (Count != 0), name: "RXNE")
231                 .WithFlag(6, out transferComplete, FieldMode.Read, name: "TC")
232                 .WithFlag(7, FieldMode.Read, name: "TXE", valueProviderCallback: _ => true)
233                 .WithTaggedFlag("CTSIF", 9)
234                 .WithTaggedFlag("CTS", 10)
235                 .WithReservedBits(13, 1)
236                 .WithTaggedFlag("BUSY", 16)
237                 .WithTaggedFlag("CMF", 17)
238                 .WithTaggedFlag("SBKF", 18)
239                 .WithTaggedFlag("RWU", 19)
240                 .WithTaggedFlag("WUF", 20)
241                 .WithFlag(21, FieldMode.Read, name: "TEACK", valueProviderCallback: _ => transmitEnabled.Value)
242                 .WithFlag(22, FieldMode.Read, name: "REACK", valueProviderCallback: _ => receiveEnabled.Value)
243                 .WithReservedBits(23, 2)
244                 .WithReservedBits(26, 6);
245 
246             var icr = Registers.InterruptFlagClear.Define(RegistersCollection)
247                 .WithTaggedFlag("PECF", 0)
248                 .WithTaggedFlag("FECF", 1)
249                 .WithTaggedFlag("NCF", 2)
250                 .WithTaggedFlag("ORECF", 3)
251                 .WithTaggedFlag("IDLECF", 4)
252                 .WithReservedBits(5, 1)
253                 // the TC flag is cleared by writing 1 to TCCF
254                 .WithFlag(6, FieldMode.Read | FieldMode.WriteOneToClear, name: "TCCF",
255                     writeCallback: (_, val) => { if(val) transferComplete.Value = false; })
256                 .WithTaggedFlag("CTSCF", 9)
257                 .WithReservedBits(10, 1)
258                 .WithReservedBits(13, 4)
259                 .WithTaggedFlag("CMCF", 17)
260                 .WithReservedBits(18, 2)
261                 .WithTaggedFlag("WUCF", 20)
262                 .WithReservedBits(21, 11)
263                 .WithWriteCallback((_, __) => UpdateInterrupt());
264 
265             Registers.ReceiveData.Define(RegistersCollection)
266                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => HandleReceiveData(), name: "RDR")
267                 .WithReservedBits(8, 24);
268 
269             Registers.TransmitData.Define(RegistersCollection)
270                 .WithValueField(0, 8,
271                     // reading this register will intentionally return the last written value
272                     writeCallback: (_, val) => HandleTransmitData((uint)val), name: "TDR")
273                 .WithReservedBits(8, 24);
274 
275             if(lowPowerMode)
276             {
277                 cr1
278                     .WithReservedBits(15, 1)
279                     .WithReservedBits(26, 2);
280 
281                 cr2
282                     .WithReservedBits(5, 2)
283                     .WithReservedBits(8, 4)
284                     .WithReservedBits(14, 1)
285                     .WithReservedBits(20, 4);
286 
287                 cr3
288                     .WithReservedBits(1, 2)
289                     .WithReservedBits(4, 2)
290                     .WithReservedBits(11, 1)
291                     .WithReservedBits(17, 3)
292                     .WithReservedBits(24, 1);
293 
294                 request
295                     .WithReservedBits(0, 1)
296                     .WithReservedBits(5, 1);
297 
298                 isr
299                     .WithReservedBits(8, 1)
300                     .WithReservedBits(11, 2)
301                     .WithReservedBits(14, 2)
302                     .WithReservedBits(25, 1);
303 
304                 icr
305                     .WithReservedBits(7, 2)
306                     .WithReservedBits(11, 2);
307             }
308             else
309             {
310                 Registers.ReceiverTimeout.Define(RegistersCollection)
311                     .WithValueField(0, 24, out receiverTimeout, name: "RTO (Receiver Timeout value)")
312                     .WithTag("BLEN (Block length)", 24, 8);
313 
314                 cr1
315                     .WithFlag(15, out over8, name: "OVER8")
316                     .WithFlag(26, out receiverTimeoutInterruptEnable, name: "RTOIE")
317                     .WithTaggedFlag("EOBIE", 27)
318                     .WithWriteCallback((_, __) =>
319                         {
320                             // Need to cancel the previous receiverTimeout here
321                             if(!enabled.Value || !receiveEnabled.Value || !receiverTimeoutInterruptEnable.Value)
322                             {
323                                 receiverTimeoutCancellationTokenSrc?.Cancel();
324                             }
325                         }
326                     );
327 
328                 cr2
329                     .WithTaggedFlag("LBDL", 5)
330                     .WithTaggedFlag("LBDIE", 6)
331                     .WithTaggedFlag("LBCL", 8)
332                     .WithTaggedFlag("CPHA", 9)
333                     .WithTaggedFlag("CPOL", 10)
334                     .WithTaggedFlag("CLKEN", 11)
335                     .WithTaggedFlag("LINEN", 14)
336                     .WithTaggedFlag("ABREN", 20)
337                     .WithTag("ABRMOD", 21, 2)
338                     .WithTaggedFlag("RTOEN", 23);
339 
340                 cr3
341                     .WithTaggedFlag("IREN", 1)
342                     .WithTaggedFlag("IRLP", 2)
343                     .WithTaggedFlag("NACK", 4)
344                     .WithTaggedFlag("SCEN", 5)
345                     .WithTaggedFlag("ONEBIT", 11)
346                     .WithTag("SCARCNT", 17, 3)
347                     .WithTaggedFlag("TCBGTIE", 24);
348 
349                 request
350                     .WithTaggedFlag("ABRRQ", 0)
351                     .WithTaggedFlag("TXFRQ", 5);
352 
353                 isr
354                     .WithTaggedFlag("LBDF", 8)
355                     .WithFlag(11, FieldMode.Read, valueProviderCallback: _ => receiverTimeoutInterruptEnable.Value && (receiverTimeoutOccurred?.Value ?? false), name: "RTOF")
356                     .WithTaggedFlag("EOBF", 12)
357                     .WithTaggedFlag("ABRE", 14)
358                     .WithTaggedFlag("ABRF", 15)
359                     .WithTaggedFlag("TCBGT", 25);
360 
361                 icr
362                     .WithTaggedFlag("TCBGTCF", 7)
363                     .WithTaggedFlag("LBDCF", 8)
364                     .WithFlag(11, out receiverTimeoutOccurred, FieldMode.WriteOneToClear, name: "RTOCF")
365                     .WithTaggedFlag("EOBCF", 12)
366                     .WithWriteCallback((_, __) => UpdateInterrupt());
367             }
368         }
369 
HandleTransmitData(uint value)370         private void HandleTransmitData(uint value)
371         {
372             if(transmitEnabled.Value && enabled.Value)
373             {
374                 base.TransmitCharacter((byte)value);
375                 transferComplete.Value = true;
376                 UpdateInterrupt();
377             }
378             else
379             {
380                 this.Log(LogLevel.Warning, "Char was to be sent, but the transmitter (or the whole USART) is not enabled. Ignoring.");
381             }
382         }
383 
HandleReceiveData()384         private uint HandleReceiveData()
385         {
386             if(!TryGetCharacter(out var result))
387             {
388                 this.Log(LogLevel.Warning, "No characters in queue.");
389             }
390             return result;
391         }
392 
UpdateInterrupt()393         private void UpdateInterrupt()
394         {
395             var transmitRegisterEmptyInterrupt = transmitRegisterEmptyInterruptEnabled.Value; // we assume that transmit register is always empty
396             var transferCompleteInterrupt = transferComplete.Value && transferCompleteInterruptEnabled.Value;
397             var readRegisterNotEmptyInterrupt = Count != 0 && readRegisterNotEmptyInterruptEnabled.Value;
398 
399             // This interrupt is expected to fire if there are not additional bits incoming after some specified time after last reception
400             var receiverTimeoutInterrupt = (receiverTimeoutOccurred?.Value ?? false) && receiverTimeoutInterruptEnable.Value;
401 
402             IRQ.Set(transmitRegisterEmptyInterrupt || transferCompleteInterrupt || readRegisterNotEmptyInterrupt || receiverTimeoutInterrupt);
403         }
404 
ReportRxTimeout(CancellationToken ct)405         private void ReportRxTimeout(CancellationToken ct)
406         {
407             if(!ct.IsCancellationRequested)
408             {
409                 receiverTimeoutOccurred.Value = true;
410                 UpdateInterrupt();
411             }
412         }
413 
414         private CancellationTokenSource receiverTimeoutCancellationTokenSrc;
415 
416         private IFlagRegisterField parityControlEnabled;
417         private IFlagRegisterField paritySelection;
418         private IFlagRegisterField transmitRegisterEmptyInterruptEnabled;
419         private IFlagRegisterField transferCompleteInterruptEnabled;
420         private IFlagRegisterField transferComplete;
421         private IFlagRegisterField readRegisterNotEmptyInterruptEnabled;
422         private IFlagRegisterField transmitEnabled;
423         private IFlagRegisterField receiveEnabled;
424         private IFlagRegisterField receiveDmaEnabled;
425         private IFlagRegisterField enabled;
426         private IValueRegisterField baudRateDivisor;
427         private IValueRegisterField stopBits;
428         private IFlagRegisterField over8;
429         private IFlagRegisterField receiverTimeoutInterruptEnable;
430         private IFlagRegisterField receiverTimeoutOccurred;
431         private IValueRegisterField receiverTimeout;
432 
433         private BufferState bufferState;
434 
435         private readonly uint frequency;
436         private readonly bool lowPowerMode;
437 
438         private uint BaudRateMultiplier => lowPowerMode ? 256u : over8.Value ? 2u : 1u;
439 
440         private enum Registers
441         {
442             ControlRegister1   = 0x0,
443             ControlRegister2   = 0x4,
444             ControlRegister3   = 0x8,
445             BaudRate           = 0xC,
446             ReceiverTimeout    = 0x14,
447             Request            = 0x18,
448             InterruptAndStatus = 0x1C,
449             InterruptFlagClear = 0x20,
450             ReceiveData        = 0x24,
451             TransmitData       = 0x28,
452         }
453     }
454 }
455 
456