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