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