1 //
2 // Copyright (c) 2010-2024 Antmicro
3 // Copyright (c) 2024 Sean "xobs" Cross
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System.Collections.Generic;
9 using Antmicro.Renode.Peripherals.Bus;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.UART
15 {
16     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
17     public class ESP32_UART : UARTBase, IDoubleWordPeripheral, IKnownSize
18     {
ESP32_UART(IMachine machine)19         public ESP32_UART(IMachine machine) : base(machine)
20         {
21             IRQ = new GPIO();
22             interruptRawStatuses = new bool[InterruptsCount];
23             interruptMasks = new bool[InterruptsCount];
24 
25             var registersMap = new Dictionary<long, DoubleWordRegister>
26             {
27                 {(long)Registers.Fifo, new DoubleWordRegister(this)
28                     .WithValueField(0, 8, writeCallback: (_, value) => this.TransmitCharacter((byte)value),
29                         valueProviderCallback: _ => {
30                             if(!TryGetCharacter(out var character))
31                             {
32                                 this.Log(LogLevel.Warning, "Trying to read from an empty FIFO.");
33                             }
34                             return character;
35                         })
36                     .WithReservedBits(8, 24)
37                 },
38                 {(long)Registers.RxFilter, new DoubleWordRegister(this)
39                     .WithTag("GLITCH_FILT", 0, 8) // when input pulse width is lower than this value, the pulse is ignored.
40                     .WithTaggedFlag("GLITCH_FILT_EN", 8) // Set this bit to enable Rx signal filter.
41                     .WithReservedBits(9, 23)
42                 },
43                 {(long)Registers.RawInterruptStatus, new DoubleWordRegister(this)
44                     .WithFlags(0, 20, FieldMode.Read, valueProviderCallback: (interrupt, _) => interruptRawStatuses[interrupt])
45                     .WithReservedBits(20, 12)
46                 },
47                 {(long)Registers.InterruptEnable, new DoubleWordRegister(this)
48                     .WithFlags(0, 20, changeCallback: (interrupt, _, newValue) => { interruptMasks[interrupt] = newValue; UpdateInterrupts(); })
49                     .WithReservedBits(20, 12)
50                 },
51                 {(long)Registers.InterruptClear, new DoubleWordRegister(this)
52                     .WithFlags(0, 20, FieldMode.Write, writeCallback: (interrupt, _, newValue) => { if(newValue) ClearInterrupt(interrupt); })
53                     .WithReservedBits(20, 12)
54                 },
55                 {(long)Registers.Status, new DoubleWordRegister(this)
56                     .WithTag("RXFIFO_CNT", 0, 10)
57                     .WithTaggedFlag("UART_DSRN", 13)
58                     .WithFlag(14, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_CTSN")
59                     .WithFlag(15, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_RXD")
60                     .WithTag("TXFIFO_CNT", 16, 10)
61                     .WithFlag(29, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_DTRN")
62                     .WithFlag(30, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_RTSN")
63                     .WithFlag(31, FieldMode.Read, valueProviderCallback: (_) => true, name: "UART_TXD")
64                 },
65                 {(long)Registers.Config0, new DoubleWordRegister(this)
66                     .WithTaggedFlag("UART_PARITY", 0)
67                     .WithTaggedFlag("UART_PARITY_EN", 1)
68                     .WithTag("UART_BIT_NUM", 2, 2)
69                     .WithTag("UART_STOPBIT_NUM", 4, 2)
70                     .WithTaggedFlag("UART_RXFIFO_RST", 17)
71                     .WithTaggedFlag("UART_TXFIFO_RST", 18)
72                     .WithTaggedFlag("UART_ERR_WR_MASK", 26)
73                     .WithTaggedFlag("UART_AUTOBAUD_EN", 27)
74                 },
75                 {(long)Registers.Config1, new DoubleWordRegister(this)
76                     .WithTag("RXFIFO_FULL_THRHD", 0, 10) // It will produce rxfifo_full_int interrupt when receiver receives more data than this register value.
77                     .WithTag("TXFIFO_EMPTY_THRHD", 10, 10) // It will produce txfifo_empty_int interrupt when the data amount in Tx-FIFO is less than this register value.
78                     .WithTaggedFlag("DIS_RX_DAT_OVF", 20) // Disable UART Rx data overflow detect.
79                     .WithTaggedFlag("RX_TOUT_FLOW_DIS", 21) // Set this bit to stop accumulating idle_cnt when hardware flow control works.
80                     .WithTaggedFlag("RX_FLOW_EN", 22) // This is the flow enable bit for UART receiver.
81                     .WithTaggedFlag("RX_TOUT_EN", 23) // This is the enble bit for uart receiver's timeout function.
82                 },
83                 {(long)Registers.EdgeChangeCount, new DoubleWordRegister(this)
84                     .WithTag("RXD_EDGE_CNT", 0, 10) // This register stores the count of rxd edge change. It is used in baud rate-detect process.
85                     .WithReservedBits(10, 22)
86                 },
87                 {(long)Registers.ClockDivider, new DoubleWordRegister(this)
88                     .WithTag("CLKDIV", 0, 12) // Clock divider configuration
89                     .WithReservedBits(12, 8)
90                     .WithTag("FRAG", 20, 4) // The decimal part of the frequency divider factor.
91                     .WithReservedBits(24, 8)
92                 },
93                 {(long)Registers.CoreClock, new DoubleWordRegister(this)
94                     .WithTag("SCLK_DIV_B", 0, 6) // The  denominator of the frequency divider factor.
95                     .WithTag("SCLK_DIV_A", 6, 6) // The numerator of the frequency divider factor.
96                     .WithTag("SCLK_DIV_NUM", 12, 8) // The integral part of the frequency divider factor.
97                     .WithTag("SCLK_SEL", 20, 2) // UART clock source select. 1: 80Mhz, 2: 8Mhz, 3: XTAL.
98                     .WithTaggedFlag("SCLK_EN", 22) // Set this bit to enable UART Tx/Rx clock.
99                     .WithTaggedFlag("RST_CORE", 23) // Write 1 then write 0 to this bit, reset UART Tx/Rx.
100                     .WithTaggedFlag("TX_SCLK_EN", 24) // Set this bit to enable UART Tx clock.
101                     .WithTaggedFlag("RX_SCLK_EN", 25) // Set this bit to enable UART Rx clock.
102                     .WithReservedBits(26, 6)
103                 },
104             };
105 
106             registers = new DoubleWordRegisterCollection(this, registersMap);
107         }
108 
ReadDoubleWord(long offset)109         public uint ReadDoubleWord(long offset)
110         {
111             return registers.Read(offset);
112         }
113 
Reset()114         public override void Reset()
115         {
116             base.Reset();
117             registers.Reset();
118             UpdateInterrupts();
119         }
120 
WriteDoubleWord(long offset, uint value)121         public void WriteDoubleWord(long offset, uint value)
122         {
123             registers.Write(offset, value);
124         }
125 
126         public long Size => 0x100;
127 
128         public GPIO IRQ { get; }
129 
130         public override Bits StopBits => Bits.One;
131 
132         public override Parity ParityBit => Parity.None;
133 
134         public override uint BaudRate => 115200;
135 
CharWritten()136         protected override void CharWritten()
137         {
138             UpdateInterrupts();
139         }
140 
QueueEmptied()141         protected override void QueueEmptied()
142         {
143             UpdateInterrupts();
144         }
145 
ClearInterrupt(int interrupt)146         private void ClearInterrupt(int interrupt)
147         {
148             this.Log(LogLevel.Noisy, "Clearing {0} interrupt.", (Interrupts)interrupt);
149             interruptRawStatuses[interrupt] = false;
150             UpdateInterrupts();
151         }
152 
UpdateInterrupts()153         private void UpdateInterrupts()
154         {
155             bool flag = MaskedInterruptStatus != 0;
156             this.Log(LogLevel.Debug, "Setting IRQ to {0}", flag);
157             IRQ.Set(flag);
158         }
159 
160         private uint InterruptMask => Renode.Utilities.BitHelper.GetValueFromBitsArray(interruptMasks);
161 
162         private uint RawInterruptStatus => Renode.Utilities.BitHelper.GetValueFromBitsArray(interruptRawStatuses);
163 
164         private uint MaskedInterruptStatus => RawInterruptStatus & InterruptMask;
165 
166         private readonly bool[] interruptMasks;
167         private readonly bool[] interruptRawStatuses;
168         private readonly DoubleWordRegisterCollection registers;
169 
170         private const uint InterruptsCount = 20;
171 
172         private enum Interrupts
173         {
174             RxFifoFull,
175             TxFifoEmpty,
176             ParityError,
177             DataFrameError,
178             RxFifoOverflow,
179             DSREdgeChange,
180             CTSEdgeChange,
181             BreakDetected,
182             ReceiverTimeout,
183             SWFlowXON,
184             SWFlowXOFF,
185             GlitchDetected,
186             TxDone,
187             TxIdleDone,
188             TxSentAllData,
189             RS485ParityError,
190             RS485DataFrameError,
191             RS485Clash,
192             CMDCharDetected,
193             Wakeup,
194         }
195 
196         private enum Registers : long
197         {
198             // FIFO Configuration
199             Fifo                     = 0x00,
200             ThresholdAndAllocation   = 0x60,
201 
202             // UART interrupt register
203             RawInterruptStatus       = 0x04,
204             MaskedInterruptStatus    = 0x08,
205             InterruptEnable          = 0x0c,
206             InterruptClear           = 0x10,
207 
208             // Configuration register
209             ClockDivider             = 0x14,
210             RxFilter                 = 0x18,
211             Config0                  = 0x20,
212             Config1                  = 0x24,
213             SoftwareFlowControl      = 0x34,
214             SleepMode                = 0x38,
215             SoftwareFlowControlChar0 = 0x3c,
216             SoftwareFlowControlChar1 = 0x40,
217             TxBreakCharacter         = 0x44,
218             IdleTime                 = 0x48,
219             RS485Mode                = 0x4c,
220             CoreClock                = 0x78,
221 
222             // Status register
223             Status = 0x1c,
224             TxFifoOffsetAddress      = 0x64,
225             RxFifoOffsetAddress      = 0x68,
226             TxRxStatus               = 0x6c,
227 
228             // Autobaud register
229             MinLowPulseDuration      = 0x28,
230             MinHighPulseDuration     = 0x2c,
231             EdgeChangeCount          = 0x30,
232             HighPulse                = 0x70,
233             LowPulse                 = 0x74,
234 
235             // Escape sequence selection configuration
236             PreSequenceTiming        = 0x50,
237             PostSequenceTiming       = 0x54,
238             Timeout                  = 0x58,
239             ATEscapeSequenceDetect   = 0x5c,
240 
241             // Version
242             Version = 0x7c,
243             ID = 0x80,
244         }
245     }
246 }
247