1 //
2 // Copyright (c) 2010-2025 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.Utilities;
11 using Antmicro.Renode.Peripherals.Bus;
12 
13 namespace Antmicro.Renode.Peripherals.UART
14 {
15     public class MAX32655_UART : UARTBase, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
16     {
MAX32655_UART(IMachine machine)17         public MAX32655_UART(IMachine machine) : base(machine)
18         {
19             RegistersCollection = new DoubleWordRegisterCollection(this);
20             IRQ = new GPIO();
21             DefineRegisters();
22         }
23 
ReadDoubleWord(long offset)24         public uint ReadDoubleWord(long offset)
25         {
26            return RegistersCollection.Read(offset);
27         }
28 
WriteDoubleWord(long offset, uint value)29         public void WriteDoubleWord(long offset, uint value)
30         {
31             RegistersCollection.Write(offset, value);
32         }
33 
Reset()34         public override void Reset()
35         {
36             base.Reset();
37             RegistersCollection.Reset();
38             IRQ.Unset();
39         }
40 
41         public override uint BaudRate => 9600;
42 
43         public override Bits StopBits => Bits.One;
44 
45         public override Parity ParityBit => Parity.Even;
46 
47         public GPIO IRQ { get; }
48 
49         public long Size => 0x1000;
50 
51         public DoubleWordRegisterCollection RegistersCollection { get; }
52 
CharWritten()53         protected override void CharWritten()
54         {
55             receiveFifoThresholdInterrupt.Value |= Count >= (int)receiveFifoThreshold.Value;
56             UpdateInterrupts();
57         }
58 
QueueEmptied()59         protected override void QueueEmptied()
60         {
61             // intentionally left empty
62         }
63 
DefineRegisters()64         private void DefineRegisters()
65         {
66             Registers.Control.Define(this)
67                 .WithValueField(0, 4, out receiveFifoThreshold, changeCallback: (_, __) =>
68                     {
69                         if(receiveFifoThreshold.Value < 1 || receiveFifoThreshold.Value > ReceiveFifoDepth)
70                         {
71                             this.WarningLog("Receive FIFO Threshold set to reserved value ({0})", receiveFifoThreshold.Value);
72                         }
73                     }, name: "rx_thd_val"
74                 )
75                 .WithTaggedFlag("par_en", 4)
76                 .WithTaggedFlag("par_eo", 5)
77                 .WithTaggedFlag("par_md", 6)
78                 .WithTaggedFlag("cts_dis", 7)
79                 .WithTaggedFlag("tx_flush", 8)
80                 .WithFlag(9, writeCallback: (_, value) => { if(value) ClearBuffer(); }, name: "rx_flush")
81                 .WithTag("char_size", 10, 2)
82                 .WithTaggedFlag("stopbits", 12)
83                 .WithTaggedFlag("hfc_en", 13)
84                 .WithTaggedFlag("rtsdc", 14)
85                 .WithFlag(15, out baudClockReady, name: "bclken")
86                 .WithTag("bclksrc", 16, 2)
87                 .WithTaggedFlag("dpfe_en", 18)
88                 .WithFlag(19, FieldMode.Read, valueProviderCallback: _ => baudClockReady.Value, name: "bclkrdy")
89                 .WithTaggedFlag("ucagm", 20)
90                 .WithTaggedFlag("fdm", 21)
91                 .WithTaggedFlag("desm", 22)
92                 .WithReservedBits(23, 9)
93             ;
94 
95             Registers.Status.Define(this)
96                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => false, name: "tx_busy")
97                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => false, name: "rx_busy")
98                 .WithReservedBits(2, 2)
99                 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => Count == 0, name: "rx_em")
100                 .WithFlag(5, FieldMode.Read, valueProviderCallback: _ => Count >= ReceiveFifoDepth, name: "rx_full")
101                 .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => true, name: "tx_em")
102                 .WithFlag(7, FieldMode.Read, valueProviderCallback: _ => false, name: "tx_full")
103                 .WithValueField(8, 4, FieldMode.Read, valueProviderCallback: _ => (ulong)Count.Clamp(0, ReceiveFifoDepth), name: "rx_lvl")
104                 .WithValueField(12, 4, FieldMode.Read, valueProviderCallback: _ => 0, name: "tx_lvl")
105                 .WithReservedBits(16, 16)
106             ;
107 
108             Registers.InterruptEnable.Define(this)
109                 .WithTaggedFlag("rx_ferr", 0)
110                 .WithTaggedFlag("rx_par", 1)
111                 .WithTaggedFlag("cts_ev", 2)
112                 .WithTaggedFlag("rx_ov", 3)
113                 .WithFlag(4, out receiveFifoThresholdInterruptEnable, name: "rx_thd")
114                 .WithReservedBits(5, 1)
115                 .WithTaggedFlag("tx_he", 6)
116                 .WithReservedBits(7, 25)
117                 .WithChangeCallback((_, __) => UpdateInterrupts())
118             ;
119 
120             Registers.InterruptFlag.Define(this)
121                 .WithTaggedFlag("rx_ferr", 0)
122                 .WithTaggedFlag("rx_par", 1)
123                 .WithTaggedFlag("cts_ev", 2)
124                 .WithTaggedFlag("rx_ov", 3)
125                 .WithFlag(4, out receiveFifoThresholdInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "rx_thd")
126                 .WithReservedBits(5, 1)
127                 .WithTaggedFlag("tx_he", 6)
128                 .WithReservedBits(7, 25)
129                 .WithChangeCallback((_, __) => UpdateInterrupts())
130             ;
131 
132             Registers.ClockDivisor.Define(this)
133                 .WithTag("clkdiv", 0, 20)
134                 .WithReservedBits(20, 12)
135             ;
136 
137             Registers.OversamplingControl.Define(this)
138                 .WithTag("osr", 0, 3)
139                 .WithReservedBits(3, 29)
140             ;
141 
142             Registers.TransmitFifo.Define(this)
143                 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => 0, name: "data")
144                 .WithReservedBits(8, 24)
145             ;
146 
147             Registers.PinControl.Define(this)
148                 .WithTaggedFlag("cts", 0)
149                 .WithTaggedFlag("rts", 1)
150                 .WithReservedBits(2, 30)
151             ;
152 
153             Registers.FifoData.Define(this)
154                 .WithValueField(0, 8, name: "data",
155                     valueProviderCallback: _ => TryGetCharacter(out var value) ? (ulong)value : 0,
156                     writeCallback: (_, value) => TransmitCharacter((byte)value)
157                 )
158                 .WithTaggedFlag("rx_par", 8)
159                 .WithReservedBits(9, 23)
160             ;
161 
162             Registers.DmaControl.Define(this)
163                 .WithTag("tx_thd_val", 0, 4)
164                 .WithTaggedFlag("tx_en", 4)
165                 .WithTag("rx_thd_val", 5, 4)
166                 .WithTaggedFlag("rx_en", 9)
167                 .WithReservedBits(10, 22)
168             ;
169 
170             Registers.WakeupInterruptEnable.Define(this)
171                 .WithTaggedFlag("rx_ne", 0)
172                 .WithTaggedFlag("rx_full", 1)
173                 .WithTaggedFlag("rx_thd", 2)
174                 .WithReservedBits(3, 29)
175             ;
176 
177             Registers.WakeupInterruptFlag.Define(this)
178                 .WithTaggedFlag("rx_ne", 0)
179                 .WithTaggedFlag("rx_full", 1)
180                 .WithTaggedFlag("rx_thd", 2)
181                 .WithReservedBits(3, 29)
182             ;
183         }
184 
UpdateInterrupts()185         private void UpdateInterrupts()
186         {
187             var state = false;
188             state |= receiveFifoThresholdInterrupt.Value && receiveFifoThresholdInterruptEnable.Value;
189             IRQ.Set(state);
190             this.NoisyLog("IRQ {0}", state ? "set" : "unset");
191         }
192 
193         private IValueRegisterField receiveFifoThreshold;
194         private IFlagRegisterField receiveFifoThresholdInterruptEnable;
195         private IFlagRegisterField receiveFifoThresholdInterrupt;
196         private IFlagRegisterField baudClockReady;
197 
198         private const int TransmitFifoDepth = 8;
199         private const int ReceiveFifoDepth = 8;
200 
201         private enum Registers
202         {
203             Control = 0x00,
204             Status = 0x04,
205             InterruptEnable = 0x08,
206             InterruptFlag = 0x0C,
207             ClockDivisor = 0x10,
208             OversamplingControl = 0x14,
209             TransmitFifo = 0x18,
210             PinControl = 0x1C,
211             FifoData = 0x20,
212             DmaControl = 0x30,
213             WakeupInterruptEnable = 0x34,
214             WakeupInterruptFlag = 0x38,
215         }
216     }
217 }
218