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.Peripherals.Bus;
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Core.Structure.Registers;
11 
12 namespace Antmicro.Renode.Peripherals.UART
13 {
14     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
15     public class PL011 : UARTBase, IDoubleWordPeripheral, IKnownSize, IProvidesRegisterCollection<DoubleWordRegisterCollection>
16     {
PL011(IMachine machine, uint fifoSize = 1, uint frequency = 24000000)17         public PL011(IMachine machine, uint fifoSize = 1, uint frequency = 24000000) : base(machine)
18         {
19             hardwareFifoSize = fifoSize;
20             uartClockFrequency = frequency;
21 
22             IRQ = new GPIO();
23             interruptRawStatuses = new bool[InterruptsCount];
24             interruptMasks = new bool[InterruptsCount];
25 
26             RegistersCollection = new DoubleWordRegisterCollection(this);
27             DefineRegisters();
28 
29             Reset();
30         }
31 
ReadDoubleWord(long offset)32         public uint ReadDoubleWord(long offset)
33         {
34             lock(innerLock)
35             {
36                 return RegistersCollection.Read(offset);
37             }
38         }
39 
Reset()40         public override void Reset()
41         {
42             base.Reset();
43             lock(innerLock)
44             {
45                 RegistersCollection.Reset();
46 
47                 // receiveFifoSize and receiveInterruptTriggerPoint depend on register values.
48                 UpdateReceiveFifoSize();
49                 UpdateReceiveInterruptTriggerPoint();
50 
51                 System.Array.ForEach(interruptRawStatuses, status => status = false);
52                 System.Array.ForEach(interruptMasks, mask => mask = false);
53                 UpdateInterrupts();
54             }
55         }
56 
WriteDoubleWord(long offset, uint value)57         public void WriteDoubleWord(long offset, uint value)
58         {
59             lock(innerLock)
60             {
61                 RegistersCollection.Write(offset, value);
62             }
63         }
64 
65         public override uint BaudRate
66         {
67             get
68             {
69                 var divisor = 16 * (integerBaudRate.Value + (fractionalBaudRate.Value / 64));
70                 return (divisor > 0) ? (uartClockFrequency / (uint)divisor) : 0;
71             }
72         }
73 
74         public GPIO IRQ { get; }
75 
76         public override Parity ParityBit
77         {
78             get
79             {
80                 if(!parityEnable.Value)
81                 {
82                     return Parity.None;
83                 }
84                 else
85                 {
86                     if(!evenParitySelect.Value)
87                     {
88                         return stickParitySelect.Value ? Parity.Forced1 : Parity.Odd;
89                     }
90                     else
91                     {
92                         return stickParitySelect.Value ? Parity.Forced0 : Parity.Even;
93                     }
94                 }
95             }
96         }
97 
98         public DoubleWordRegisterCollection RegistersCollection { get; }
99 
100         public long Size => 0x1000;
101 
102         public override Bits StopBits => twoStopBitsSelect.Value ? Bits.Two : Bits.One;
103 
CharWritten()104         protected override void CharWritten()
105         {
106             UpdateInterrupts();
107         }
108 
109         protected override bool IsReceiveEnabled
110         {
111             get
112             {
113                 return AssertFlagEnabled(uartEnable, "Character cannot be received by UART; UARTEN is disabled!")
114                     && AssertFlagEnabled(receiveEnable, "Character cannot be received by UART; RXE is disabled!");
115             }
116         }
117 
QueueEmptied()118         protected override void QueueEmptied()
119         {
120             UpdateInterrupts();
121         }
122 
AssertFlagEnabled(IFlagRegisterField flag, string errorMessage)123         private bool AssertFlagEnabled(IFlagRegisterField flag, string errorMessage)
124         {
125             if(!flag.Value)
126             {
127                 this.Log(LogLevel.Error, errorMessage);
128                 return false;
129             }
130             return true;
131         }
132 
ClearInterrupt(int interrupt)133         private void ClearInterrupt(int interrupt)
134         {
135             this.Log(LogLevel.Noisy, "Clearing {0} interrupt.", (Interrupts)interrupt);
136             interruptRawStatuses[interrupt] = false;
137             UpdateInterrupts();
138         }
139 
DefineRegisters()140         private void DefineRegisters()
141         {
142             Registers.Data.Define(this)
143                 .WithValueField(0, 8, name: "DATA - Receive (read) / Transmit (write) data character",
144                         valueProviderCallback: _ => ReadDataRegister(),
145                         writeCallback: (_, newValue) => WriteDataRegister((uint)newValue))
146                 .WithTaggedFlag("FE - Framing error", 8)
147                 .WithTaggedFlag("PE - Parity error", 9)
148                 .WithTaggedFlag("BE - Break error", 10)
149                 .WithTaggedFlag("OE - Overrun error", 11)
150                 .WithReservedBits(12, 4)
151                 ;
152 
153             Registers.Control.Define(this, 0x300)
154                 .WithFlag(0, out uartEnable, name: "UARTEN - UART enable",
155                     changeCallback: (_, value) =>
156                     {
157                         if(value)
158                         {
159                             // Documentation states that the Transmit interrupt should be only set upon
160                             // crossing the threshold and enabling/disabling FIFO, but some software
161                             // requires it to be set after enabling UART
162                             interruptRawStatuses[(int)Interrupts.Transmit] = true;
163                             UpdateInterrupts();
164                         }
165                     })
166                 .WithTaggedFlag("SIREN - SIR enable", 1)
167                 .WithTaggedFlag("SIRLP - IrDA SIR low power mode", 2)
168                 // These 4 bits can be written/read by software but there's no logic associated.
169                 .WithFlags(3, 4, name: "Vendor specific")
170                 .WithFlag(7, out loopbackEnable, name: "LBE - Loop back enable")
171                 .WithFlag(8, out transmitEnable, name: "TXE - Transmit enable")
172                 .WithFlag(9, out receiveEnable, name: "RXE - Receive enable")
173                 // No logic needed for DTR/RTS so these are flags just to hush write warnings.
174                 .WithFlag(10, name: "DTR - Data transmit ready")
175                 .WithFlag(11, name: "RTS - Request to send")
176                 .WithTaggedFlag("Out1", 12)
177                 .WithTaggedFlag("Out2", 13)
178                 .WithTaggedFlag("RTSEn - RTS hardware flow control enable", 14)
179                 .WithTaggedFlag("CTSEn - CTS hardware flow control enable", 15)
180                 ;
181 
182             Registers.Flag.Define(this)  // Doesn't need to have a reset value; it's 0b10010000 nevertheless.
183                 .WithTaggedFlag("CTS - Clear to send", 0)
184                 .WithTaggedFlag("DSR - Data set ready", 1)
185                 .WithTaggedFlag("DCD - Data carrier detect", 2)
186                 .WithTaggedFlag("BUSY - UART busy", 3)
187                 .WithFlag(4, FieldMode.Read, name: "RXFE - Receive FIFO empty", valueProviderCallback: _ => Count == 0)
188                 .WithTaggedFlag("TXFF - Transmit FIFO full", 5)
189                 .WithFlag(6, FieldMode.Read, name: "RXFF - Receive FIFO full", valueProviderCallback: _ => Count >= receiveFifoSize)
190                 .WithFlag(7, FieldMode.Read, name: "TXFE - Transmit FIFO empty", valueProviderCallback: _ => true)  // Always set.
191                 .WithTaggedFlag("RI - Ring indicator", 8)
192                 .WithReservedBits(9, 7)
193                 ;
194 
195             Registers.RawInterruptStatus.Define(this)
196                 .WithFlags(0, 11, FieldMode.Read, valueProviderCallback: (interrupt, _) => interruptRawStatuses[interrupt])
197                 .WithReservedBits(11, 5)
198                 ;
199 
200             Registers.LineControl.Define(this)
201                 .WithTaggedFlag("BRK - Send break", 0)
202                 .WithFlag(1, out parityEnable, name: "PEN - Parity enable")
203                 .WithFlag(2, out evenParitySelect, name: "EPS - Even parity select")
204                 .WithFlag(3, out twoStopBitsSelect, name: "STP2 - Two stop bits select")
205                 .WithFlag(4, out enableFifoBuffers, name: "FEN - Enable FIFOs", changeCallback: (_, __) => UpdateReceiveFifoSize())
206                 .WithEnumField(5, 2, out wordLength, name: "WLEN - Word length")
207                 .WithFlag(7, out stickParitySelect, name: "SPS - Stick parity select")
208                 .WithReservedBits(8, 8)
209                 ;
210 
211             Registers.IrDALowPowerCounter.Define(this)
212                 .WithTag("ILPDVSR - 8-bit low-power divisor value.", 0, 8)
213                 .WithReservedBits(8, 24)
214                 ;
215 
216             Registers.InterruptMask.Define(this)
217                 .WithFlags(0, 11, changeCallback: (interrupt, _, newValue) => { interruptMasks[interrupt] = newValue; UpdateInterrupts(); })
218                 .WithReservedBits(11, 5)
219                 ;
220 
221             Registers.IntegerBaudRate.Define(this)
222                 .WithValueField(0, 16, out integerBaudRate, name: "BAUD DIVINT - The integer baud rate divisor.")
223                 ;
224 
225             Registers.FractionalBaudRate.Define(this)
226                 .WithValueField(0, 6, out fractionalBaudRate, name: "BAUD DIVFRAC - The fractional baud rate divisor")
227                 .WithReservedBits(6, 10)
228                 ;
229 
230             Registers.DMAControl.Define(this)
231                 .WithTaggedFlag("RXDMAE - Receive DMA enable", 0)
232                 .WithTaggedFlag("TXDMAE - Transmit DMA enable", 1)
233                 .WithTaggedFlag("DMAONERR - DMA on error", 2)
234                 .WithReservedBits(3, 13)
235                 ;
236 
237             Registers.InterruptFIFOLevel.Define(this, 0b010010)  // The reset value is 2 for both fields.
238                 .WithValueField(0, 3, name: "TXIFLSEL - Transmit interrupt FIFO level select")  // Hush write warnings. Transmit interrupts are never triggered.
239                 .WithValueField(3, 3, out receiveInterruptFifoLevelSelect, name: "RXIFLSEL - Receive interrupt FIFO level select",
240                         changeCallback: (_, __) => UpdateReceiveInterruptTriggerPoint())
241                 .WithReservedBits(6, 10)
242                 ;
243 
244             Registers.InterruptClear.Define(this)
245                 .WithFlags(0, 11, FieldMode.Write, writeCallback: (interrupt, _, newValue) => { if(newValue) ClearInterrupt(interrupt); })
246                 .WithReservedBits(11, 5)
247                 ;
248 
249             // Any write to this 8-bit register should clear all the errors if they're ever set.
250             Registers.ReceiveStatus.Define(this)
251                 .WithFlag(0, name: "FE - Framing error", valueProviderCallback: _ => false)
252                 .WithFlag(1, name: "PE - Parity error", valueProviderCallback: _ => false)
253                 .WithFlag(2, name: "BE - Break error", valueProviderCallback: _ => false)
254                 .WithFlag(3, name: "OE - Overrun error", valueProviderCallback: _ => false)
255                 .WithFlags(4, 4, FieldMode.Write)
256                 ;
257 
258             Registers.MaskedInterruptStatus.Define(this)
259                 .WithValueField(0, 11, FieldMode.Read, name: "Masked interrupt status", valueProviderCallback: _ => MaskedInterruptStatus)
260                 .WithReservedBits(11, 5)
261                 ;
262 
263             Registers.UARTPeriphID0.DefineMany(this, 4, (register, idx) =>
264             {
265                 register.WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => peripheralID[idx])
266                     .WithReservedBits(8, 8);
267             }, name: "Peripheral identification registers n");
268 
269             Registers.UARTPCellID0.DefineMany(this, 4, (register, idx) =>
270             {
271                 register.WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => primeCellID[idx])
272                     .WithReservedBits(8, 8);
273             }, name: "PrimeCell identification registers n");
274         }
275 
ReadDataRegister()276         private byte ReadDataRegister()
277         {
278             // DATA register can be read to check errors so reading from an empty queue isn't a problem.
279             if(TryGetCharacter(out byte character))
280             {
281                 WarnIfWordLengthIncorrect();
282                 UpdateInterrupts();
283             }
284             return character;
285         }
286 
UpdateReceiveInterruptTriggerPoint()287         private void UpdateReceiveInterruptTriggerPoint()
288         {
289             var levelSelect = receiveInterruptFifoLevelSelect.Value;
290             switch(levelSelect)
291             {
292                 case 0b000: receiveInterruptTriggerPoint = 1d / 8d * receiveFifoSize; break;
293                 case 0b001: receiveInterruptTriggerPoint = 1d / 4d * receiveFifoSize; break;
294                 case 0b010: receiveInterruptTriggerPoint = 1d / 2d * receiveFifoSize; break;
295                 case 0b011: receiveInterruptTriggerPoint = 3d / 4d * receiveFifoSize; break;
296                 case 0b100: receiveInterruptTriggerPoint = 7d / 8d * receiveFifoSize; break;
297                 default:
298                     this.Log(LogLevel.Warning, "Receive interrupt FIFO level select written with invalid value: {0}", levelSelect);
299                     return;
300             }
301             this.Log(LogLevel.Debug, "Receive Interrupt Trigger Point set to: {0} (level select = {1}; fifo size = {2}{3})",
302                 receiveInterruptTriggerPoint, levelSelect, receiveFifoSize, enableFifoBuffers.Value ? "" : " (FIFO buffers disabled)");
303 
304             UpdateInterrupts();
305         }
306 
UpdateInterrupts()307         private void UpdateInterrupts()
308         {
309             interruptRawStatuses[(int)Interrupts.Receive] = Count >= receiveInterruptTriggerPoint;
310             IRQ.Set(MaskedInterruptStatus != 0);
311         }
312 
UpdateReceiveFifoSize()313         private void UpdateReceiveFifoSize()
314         {
315             if(enableFifoBuffers.Value)
316             {
317                 receiveFifoSize = hardwareFifoSize;
318                 this.Log(LogLevel.Debug, "FIFO buffers enabled.");
319             }
320             else
321             {
322                 receiveFifoSize = 1;
323                 this.Log(LogLevel.Debug, "FIFO buffers disabled.");
324                 interruptRawStatuses[(int)Interrupts.Transmit] = true;
325                 UpdateInterrupts();
326             }
327             UpdateReceiveInterruptTriggerPoint();
328         }
329 
WarnIfWordLengthIncorrect()330         private void WarnIfWordLengthIncorrect()
331         {
332             if(wordLength.Value != WordLength.EightBits && wordLength.Value != WordLength.SevenBits)
333             {
334                 this.Log(LogLevel.Warning, "DATA read or written while {0}-bit word length is set (WLEN={1}). Only 7-bit and 8-bit words are fully supported.",
335                     wordLength.Value == WordLength.FiveBits ? "5" : "6", (uint)wordLength.Value);
336             }
337         }
338 
WriteDataRegister(uint value)339         private void WriteDataRegister(uint value)
340         {
341             if(!AssertFlagEnabled(uartEnable, "DATA register cannot be written to; UARTEN is disabled!")
342                 || !AssertFlagEnabled(transmitEnable, "DATA register cannot be written to; TXE is disabled!"))
343             {
344                 return;
345             }
346             WarnIfWordLengthIncorrect();
347 
348             if(!loopbackEnable.Value)
349             {
350                 TransmitCharacter((byte)value);
351             }
352             interruptRawStatuses[(int)Interrupts.Transmit] = true;
353             UpdateInterrupts();
354         }
355 
356         private uint InterruptMask => Renode.Utilities.BitHelper.GetValueFromBitsArray(interruptMasks);
357 
358         private uint MaskedInterruptStatus => RawInterruptStatus & InterruptMask;
359 
360         private uint RawInterruptStatus => Renode.Utilities.BitHelper.GetValueFromBitsArray(interruptRawStatuses);
361 
362         private IFlagRegisterField enableFifoBuffers;
363         private IFlagRegisterField evenParitySelect;
364         private IValueRegisterField fractionalBaudRate;
365         private IValueRegisterField integerBaudRate;
366         private IFlagRegisterField loopbackEnable;
367         private IFlagRegisterField parityEnable;
368         private IFlagRegisterField receiveEnable;
369         private IValueRegisterField receiveInterruptFifoLevelSelect;
370         private IFlagRegisterField stickParitySelect;
371         private IFlagRegisterField transmitEnable;
372         private IFlagRegisterField twoStopBitsSelect;
373         private IFlagRegisterField uartEnable;
374         private IEnumRegisterField<WordLength> wordLength;
375 
376         private readonly uint hardwareFifoSize;
377         private readonly bool[] interruptMasks;
378         private readonly bool[] interruptRawStatuses;
379         private readonly uint[] peripheralID = { 0x11, 0x10, 0x34, 0x0 };
380         private readonly uint[] primeCellID = { 0x0D, 0xF0, 0x05, 0xB1 };
381         private readonly uint uartClockFrequency;
382 
383         private uint receiveFifoSize;
384         private double receiveInterruptTriggerPoint;
385 
386         private const uint InterruptsCount = 11;
387 
388         private enum Interrupts
389         {
390             ModemRingIndicator,
391             ModemClearToSend,
392             ModemDataCarrierDetect,
393             ModemDataSetReady,
394             Receive,
395             Transmit,
396             ReceiveTimeout,
397             FramingError,
398             ParityError,
399             BreakError,
400             OverrunError,
401         }
402 
403         private enum Registers : long
404         {
405             Data                            = 0x000,
406             ReceiveStatus                   = 0x004, //aka ErrorClear
407             Flag                            = 0x018,
408             IrDALowPowerCounter             = 0x020,
409             IntegerBaudRate                 = 0x024,
410             FractionalBaudRate              = 0x028,
411             LineControl                     = 0x02c,
412             Control                         = 0x030,
413             InterruptFIFOLevel              = 0x034,
414             InterruptMask                   = 0x038,
415             RawInterruptStatus              = 0x03c,
416             MaskedInterruptStatus           = 0x040,
417             InterruptClear                  = 0x044,
418             DMAControl                      = 0x048,
419             UARTPeriphID0                   = 0xFE0,
420             UARTPeriphID1                   = 0xFE4,
421             UARTPeriphID2                   = 0xFE8,
422             UARTPeriphID3                   = 0xFEC,
423             UARTPCellID0                    = 0xFF0,
424             UARTPCellID1                    = 0xFF4,
425             UARTPCellID2                    = 0xFF8,
426             UARTPCellID3                    = 0xFFC
427         }
428 
429         private enum WordLength
430         {
431             FiveBits,
432             SixBits,
433             SevenBits,
434             EightBits,
435         }
436     }
437 }
438 
439