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.Linq;
9 using System.Collections.Generic;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Utilities;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Migrant;
16 
17 namespace Antmicro.Renode.Peripherals.UART
18 {
19     public class GaislerAPBUART: BasicDoubleWordPeripheral, IUART, IGaislerAPB
20     {
GaislerAPBUART(IMachine machine, uint fifoDepth = 8, uint frequency = 25000000)21         public GaislerAPBUART(IMachine machine, uint fifoDepth = 8, uint frequency = 25000000) : base(machine)
22         {
23             this.fifoDepth = fifoDepth;
24             this.frequency = frequency;
25             DefineRegisters();
26         }
27 
WriteChar(byte value)28         public void WriteChar(byte value)
29         {
30             if(!receiverEnable.Value)
31             {
32                 this.Log(LogLevel.Warning, "Received byte 0x{0:X}, but the receiver is not enabled, dropping.", value);
33                 return;
34             }
35 
36             if(receiveFifo.Count == fifoDepth)
37             {
38                 this.Log(LogLevel.Debug, "Received data that would overflow the FIFO capacity. Enqueuing anyway.");
39             }
40 
41             receiveFifo.Enqueue(value);
42             UpdateInterrupt(rxFinished: true);
43         }
44 
Reset()45         public override void Reset()
46         {
47             base.Reset();
48             receiveFifo.Clear();
49         }
50 
51         public uint BaudRate
52         {
53             get
54             {
55                 var divisor = scaler.Value * 8;
56                 return divisor == 0 ? 0 : frequency / (uint) divisor;
57             }
58         }
59 
60         public Bits StopBits => Bits.One;
61 
62         public Parity ParityBit => parityEnable.Value ?
63                                     (paritySelect.Value == ParitySelect.Even ?
64                                         Parity.Even :
65                                         Parity.Odd) :
66                                     Parity.None;
67 
68         public GPIO IRQ { get; } = new GPIO();
69 
70         [field: Transient]
71         public event Action<byte> CharReceived;
72 
GetVendorID()73         public uint GetVendorID() => vendorID;
74 
GetDeviceID()75         public uint GetDeviceID() => deviceID;
76 
GetSpaceType()77         public GaislerAPBPlugAndPlayRecord.SpaceType GetSpaceType() => GaislerAPBPlugAndPlayRecord.SpaceType.APBIOSpace;
78 
GetInterruptNumber()79         public uint GetInterruptNumber() => this.GetCpuInterruptNumber(IRQ);
80 
DefineRegisters()81         private void DefineRegisters()
82         {
83             Registers.Data.Define(this, name: "DATA")
84                 .WithValueField(0, 8, valueProviderCallback: _ =>
85                     {
86                         if(!receiveFifo.TryDequeue(out byte value))
87                         {
88                             this.Log(LogLevel.Warning, "Trying to read data from empty receive fifo");
89                         }
90                         UpdateInterrupt();
91                         return value;
92                     }, writeCallback: (_, value) =>
93                     {
94                         if(!transmitterEnable.Value)
95                         {
96                             this.Log(LogLevel.Warning, "Tried to transmit byte 0x{0:X}, but the transmitter is not enabled. dropping.", value);
97                             return;
98                         }
99 
100                         CharReceived?.Invoke((byte)value);
101                         UpdateInterrupt(txFinished: true);
102                     }, name: "DATA"
103                 )
104                 .WithReservedBits(8, 24)
105             ;
106 
107             Registers.Status.Define(this, 0x86, name: "STATUS")
108                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => receiveFifo.Count > 0, name: "DR")
109                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => true, name: "TS")
110                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => true, name: "TE")
111                 .WithTaggedFlag("BR", 3)
112                 .WithFlag(4, valueProviderCallback: _ => false, name: "OV")
113                 .WithTaggedFlag("PE", 5)
114                 .WithTaggedFlag("FE", 6)
115                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => TxHalfEmpty, name: "TH")
116                 .WithFlag(8, FieldMode.Read, valueProviderCallback: _ => RxHalfFull, name: "RH")
117                 .WithFlag(9, FieldMode.Read, valueProviderCallback: _ => false, name: "TF")
118                 .WithFlag(10, FieldMode.Read, valueProviderCallback: _ => receiveFifo.Count >= fifoDepth, name: "RF")
119                 .WithReservedBits(11, 9)
120                 .WithValueField(20, 6, FieldMode.Read, valueProviderCallback: _ => 0, name: "TCNT")
121                 .WithValueField(26, 6, FieldMode.Read, valueProviderCallback: _ => (ulong) Math.Min(receiveFifo.Count, fifoDepth), name: "RCNT")
122             ;
123 
124             Registers.Control.Define(this, name: "CONTROL")
125                 .WithFlag(0, out receiverEnable, name: "RE")
126                 .WithFlag(1, out transmitterEnable, name: "TE")
127                 .WithFlag(2, out receiverInterruptEnable, name: "RI", softResettable: false)
128                 .WithFlag(3, out transmitterInterruptEnable, name: "TI", softResettable: false)
129                 .WithEnumField(4, 1, out paritySelect, name: "PS", softResettable: false)
130                 .WithFlag(5, out parityEnable, name: "PE", softResettable: false)
131                 .WithTaggedFlag("FL", 6)
132                 .WithFlag(7, name: "LB", softResettable: false)
133                 .WithFlag(8, name: "EC", valueProviderCallback: _ => false, writeCallback: (_, value) =>
134                         {
135                             if(value)
136                             {
137                                 this.Log(LogLevel.Error, "Attempted to set peripheral into external clock mode, which is unsupported!");
138                             }
139                         })
140                 .WithFlag(9,  out transmitterFifoInterruptEnable, name: "TF", softResettable: false)
141                 .WithFlag(10, out receiverFifoInterruptEnable, name: "RF", softResettable: false)
142                 .WithFlag(11, name: "DB", softResettable: false)
143                 .WithFlag(12, name: "BI", softResettable: false)
144                 .WithFlag(13, name: "DI", softResettable: false)
145                 .WithFlag(14, out transmitterShiftRegisterEmptyInterruptEnable, name: "SI", softResettable: false)
146                 .WithReservedBits(15, 16)
147                 .WithFlag(31, FieldMode.Read, valueProviderCallback: _ => true, name: "FA")
148                 .WithChangeCallback((_, __) => UpdateInterrupt())
149             ;
150 
151             Registers.Scaler.Define(this, name: "SCALER")
152                 .WithValueField(0, 12, out scaler, name: "SCALER")
153                 .WithReservedBits(12, 20)
154             ;
155 
156             Registers.FifoDebug.Define(this, name: "FIFO_DEBUG")
157                 .WithTag("SOFT_RESET", 0, 8)
158                 .WithReservedBits(8, 24)
159             ;
160         }
161 
UpdateInterrupt(bool rxFinished = false, bool txFinished = false)162         private void UpdateInterrupt(bool rxFinished = false, bool txFinished = false)
163         {
164             var txFifoIrq = TxHalfEmpty && transmitterFifoInterruptEnable.Value && transmitterEnable.Value;
165             var rxFifoIrq = RxHalfFull && receiverFifoInterruptEnable.Value && receiverInterruptEnable.Value;
166             var irq = txFifoIrq || rxFifoIrq;
167             this.Log(LogLevel.Noisy, "IRQ {0} (tx fifo {1}, rx fifo {2})", irq, txFifoIrq, rxFifoIrq);
168             IRQ.Set(irq);
169 
170             var rxIrq = rxFinished && receiverInterruptEnable.Value;
171             var txIrq = txFinished && (transmitterInterruptEnable.Value || transmitterShiftRegisterEmptyInterruptEnable.Value);
172             if(!irq && (rxIrq || txIrq))
173             {
174                 this.Log(LogLevel.Noisy, "IRQ blink (rx {0}, tx {1})", rxIrq, txIrq);
175                 IRQ.Blink();
176             }
177         }
178 
179         private bool TxHalfEmpty => true;
180         private bool RxHalfFull => receiveFifo.Count > (fifoDepth - 1) / 2;
181 
182         private IFlagRegisterField transmitterEnable;
183         private IFlagRegisterField receiverEnable;
184         private IFlagRegisterField transmitterFifoInterruptEnable;
185         private IFlagRegisterField receiverFifoInterruptEnable;
186         private IFlagRegisterField transmitterShiftRegisterEmptyInterruptEnable;
187         private IFlagRegisterField transmitterInterruptEnable;
188         private IFlagRegisterField receiverInterruptEnable;
189         private IValueRegisterField scaler;
190         private IFlagRegisterField parityEnable;
191         private IEnumRegisterField<ParitySelect> paritySelect;
192 
193         private readonly uint fifoDepth;
194         private readonly uint frequency;
195 
196         private readonly Queue<byte> receiveFifo = new Queue<byte>();
197 
198         private const uint vendorID = 0x01; // Aeroflex Gaisler
199         private const uint deviceID = 0x0c; // GRLIB APBUART
200 
201         private enum ParitySelect
202         {
203             Even = 0,
204             Odd = 1
205         }
206 
207         private enum Registers : long
208         {
209             Data = 0x00,
210             Status = 0x04,
211             Control = 0x08,
212             Scaler = 0x0c,
213             FifoDebug = 0x10
214         }
215     }
216 }
217