1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.Analog 17 { 18 public class Xilinx_XADC : BasicDoubleWordPeripheral, IKnownSize 19 { Xilinx_XADC(IMachine machine)20 public Xilinx_XADC(IMachine machine) : base(machine) 21 { 22 DefineRegisters(); 23 24 IRQ = new GPIO(); 25 dataFifo = new Queue<uint>(); 26 channelValues = new ushort[NUMBER_OF_CHANNELS]; 27 28 Reset(); 29 } 30 Reset()31 public override void Reset() 32 { 33 base.Reset(); 34 35 dataFifo.Clear(); 36 Array.Clear(channelValues, 0, NUMBER_OF_CHANNELS); 37 IRQ.Unset(); 38 readDataValue = 0; 39 } 40 SetChannelValue(ushort channel, ushort value)41 public void SetChannelValue(ushort channel, ushort value) 42 { 43 var channelIndex = ValidateChannelNumber(channel); 44 channelValues[channelIndex] = value; 45 } 46 GetChannelValue(ushort channel)47 public ushort GetChannelValue(ushort channel) 48 { 49 var channelIndex = ValidateChannelNumber(channel); 50 return channelValues[channelIndex]; 51 } 52 53 public long Size => 0x1C; 54 public GPIO IRQ { get; } 55 DefineRegisters()56 private void DefineRegisters() 57 { 58 Register.Configuration.Define(this, resetValue: 0x00001114) 59 .WithTag("IGAP", 0, 5) 60 .WithReservedBits(5, 3) 61 .WithTag("TCKRATE", 8, 2) 62 .WithReservedBits(10, 2) 63 .WithTag("REDGE", 12, 1) 64 .WithTag("WEDGE", 13, 1) 65 .WithReservedBits(14, 2) 66 .WithValueField(16, 4, out dataFifoThreshold, name: "DFIFOTH") 67 .WithTag("CFIFOTH", 20, 4) 68 .WithReservedBits(24, 7) 69 .WithTag("ENABLE", 31, 1); 70 71 interruptStatus = Register.InterruptStatus.Define(this, resetValue: 0x00000200) 72 .WithTag("ALM", 0, 7) 73 .WithTag("OT", 7, 1) 74 .WithFlag(8, out intStatusDfifoGth, FieldMode.Read | FieldMode.WriteOneToClear, name: "DFIFO_GTH") 75 .WithTag("CFIFO_LTH", 9, 1) 76 .WithReservedBits(10, 22) 77 .WithChangeCallback((oldValue, newValue) => UpdateInterrupts()); 78 79 interruptMask = Register.InterruptMask.Define(this, resetValue: 0xFFFFFFFF) 80 .WithTag("M_ALM", 0, 7) 81 .WithTag("M_OT", 7, 1) 82 .WithFlag(8, name: "M_DFIFO_GTH") 83 .WithTag("M_CFIFO_LTH", 9, 1) 84 .WithReservedBits(10, 22) 85 .WithWriteCallback((oldValue, newValue) => UpdateInterrupts()); 86 87 Register.MiscStatus.Define(this, resetValue: 0x00000500) 88 .WithTag("ALM", 0, 7) 89 .WithTag("OT", 7, 1) 90 .WithFlag(8, FieldMode.Read, valueProviderCallback: (_) => dataFifo.Count == 0, name: "DFIFOE") 91 .WithFlag(9, FieldMode.Read, valueProviderCallback: (_) => dataFifo.Count == DATA_FIFO_CAPACITY, name: "DFIFOF") 92 // Command FIFO empty - always true because we execute commands immediately after they're written to the FIFO 93 .WithFlag(10, FieldMode.Read, valueProviderCallback: (_) => true, name: "CFIFOE") 94 // Command FIFO full - always false, see above 95 .WithFlag(11, FieldMode.Read, valueProviderCallback: (_) => false, name: "CFIFOF") 96 .WithValueField(12, 4, FieldMode.Read, valueProviderCallback: (_) => (uint)dataFifo.Count, name: "DFIFO_LVL") 97 .WithTag("CFIFO_LVL", 16, 4) 98 .WithReservedBits(20, 12); 99 100 Register.CommmandFifo.Define(this) 101 .WithValueField(0, 32, FieldMode.Write, writeCallback: (oldValue, newValue) => 102 { 103 this.DebugLog($"Command FIFO write: 0x{newValue:x}"); 104 HandleCommand((uint)newValue); 105 }); 106 107 Register.DataFifo.Define(this) 108 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: (oldValue) => 109 { 110 if(!dataFifo.TryDequeue(out var value)) 111 { 112 this.Log(LogLevel.Warning, "Read from empty data FIFO"); 113 } 114 115 this.DebugLog($"Data FIFO read returning 0x{value:x}"); 116 return value; 117 }); 118 119 Register.MiscControl.Define(this) 120 .WithReservedBits(0, 1, 0) 121 .WithReservedBits(1, 3) 122 .WithTag("RESET", 4, 1) 123 .WithReservedBits(5, 27); 124 } 125 HandleCommand(uint command)126 private void HandleCommand(uint command) 127 { 128 var cmd = (command >> 26) & 0xF; 129 var drpAddress = (ushort)((command >> 16) & 0x3FF); 130 var drpData = (ushort)((command >> 0) & 0x7FFF); 131 132 switch((PsXadcCommand)cmd) 133 { 134 case PsXadcCommand.NoOperation: 135 DataFifoSend(readDataValue); 136 readDataValue = 0; 137 break; 138 case PsXadcCommand.DrpRead: 139 DataFifoSend(0); 140 readDataValue = HandleDrpRead(drpAddress); 141 break; 142 case PsXadcCommand.DrpWrite: 143 DataFifoSend(HandleDrpWrite(drpAddress, drpData)); 144 break; 145 default: 146 this.Log(LogLevel.Warning, $"Unknown DRP command 0x{cmd:x}"); 147 break; 148 } 149 } 150 AdcChannelNumberToIndex(ushort address)151 private uint? AdcChannelNumberToIndex(ushort address) 152 { 153 if(address >= (ushort)DrpRegister.Temperature && address <= (ushort)DrpRegister.VccBram) 154 { 155 return (uint)(address - (ushort)DrpRegister.Temperature); 156 } 157 158 if(address >= (ushort)DrpRegister.VccPint && address <= (ushort)DrpRegister.VauxpVauxn15) 159 { 160 return (uint)(address - (ushort)DrpRegister.VccPint) 161 + ((ushort)DrpRegister.VccBram - (ushort)DrpRegister.Temperature + 1); 162 } 163 164 return null; 165 } 166 ValidateChannelNumber(ushort channel)167 private uint ValidateChannelNumber(ushort channel) 168 { 169 if(!(AdcChannelNumberToIndex(channel) is uint channelIndex)) 170 { 171 throw new RecoverableException($"Invalid channel number {channel}"); 172 } 173 return channelIndex; 174 } 175 HandleDrpRead(ushort address)176 private ushort HandleDrpRead(ushort address) 177 { 178 // The DRP register addresses match the ADC channel numbers used in the datasheet. 179 if(AdcChannelNumberToIndex(address) is uint channelIndex) 180 { 181 var rawValue = channelValues[channelIndex]; 182 this.DebugLog($"Read ADC channel {address} with value {rawValue}"); 183 return (ushort)(rawValue << 4); // MSB-justify 12-bit value in 16-bit register 184 } 185 else 186 { 187 this.Log(LogLevel.Warning, $"Unhandled DRP register read: 0x{address:x}"); 188 return 0; 189 } 190 } 191 HandleDrpWrite(ushort address, ushort value)192 private ushort HandleDrpWrite(ushort address, ushort value) 193 { 194 this.Log(LogLevel.Warning, $"Unhandled DRP register write: 0x{address:x}, value: 0x{value:x}"); 195 return 0; 196 } 197 DataFifoSend(uint value)198 private void DataFifoSend(uint value) 199 { 200 if(dataFifo.Count == DATA_FIFO_CAPACITY) 201 { 202 this.Log(LogLevel.Warning, $"Tried to enqueue onto a full data FIFO, value: 0x{value:x}"); 203 return; 204 } 205 206 dataFifo.Enqueue(value); 207 UpdateInterrupts(); 208 } 209 UpdateInterrupts()210 private void UpdateInterrupts() 211 { 212 intStatusDfifoGth.Value |= dataFifo.Count > (int)dataFifoThreshold.Value; 213 214 var interruptFlag = (interruptStatus.Value & ~interruptMask.Value) != 0; 215 IRQ.Set(interruptFlag); 216 } 217 218 private uint readDataValue; 219 220 private IValueRegisterField dataFifoThreshold; 221 222 private DoubleWordRegister interruptStatus; 223 private IFlagRegisterField intStatusDfifoGth; 224 225 private DoubleWordRegister interruptMask; 226 227 private readonly Queue<uint> dataFifo; 228 private readonly ushort[] channelValues; 229 230 private const int NUMBER_OF_CHANNELS = 1 + 231 (int)DrpRegister.VccBram - (int)DrpRegister.Temperature + 232 (int)DrpRegister.VauxpVauxn15 - (int)DrpRegister.VccPint; 233 private const int DATA_FIFO_CAPACITY = 15; 234 235 private enum PsXadcCommand 236 { 237 NoOperation = 0x0, 238 DrpRead = 0x1, 239 DrpWrite = 0x2, 240 } 241 242 private enum Register: long 243 { 244 Configuration = 0x00, // XADCIF_CFG 245 InterruptStatus = 0x04, // XADCIF_INT_STS 246 InterruptMask = 0x08, // XADCIF_INT_MASK 247 MiscStatus = 0x0C, // XADCIF_MSTS 248 CommmandFifo = 0x10, // XADCIF_CMDFIFO 249 DataFifo = 0x14, // XADCIF_RDFIFO 250 MiscControl = 0x18, // XADCIF_MCTL 251 } 252 253 private enum DrpRegister: ushort 254 { 255 /* ADC conversion result registers. Each of these is a 12-bit value MSB-justified to 16 bits. */ 256 Temperature = 0x00, 257 VccInt = 0x01, 258 VccAux = 0x02, 259 VpVn = 0x03, 260 Vrefp = 0x04, 261 Vrefn = 0x05, 262 VccBram = 0x06, 263 VccPint = 0x0D, 264 VccPaux = 0x0E, 265 VccoDdr = 0x0F, 266 VauxpVauxn0 = 0x10, 267 VauxpVauxn15 = 0x1F, 268 /* End of ADC conversion result registers. */ 269 } 270 } 271 } 272