1 // 2 // Copyright (c) 2010-2020 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.Collections.Generic; 9 using System.IO; 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.Peripherals.Bus; 15 16 namespace Antmicro.Renode.Peripherals.Sound 17 { 18 // this model lack support for concatenated channels 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 20 public abstract class LiteX_I2S : BasicDoubleWordPeripheral, IKnownSize 21 { LiteX_I2S(IMachine machine, DataFormat format, uint sampleWidth, uint samplingRate, uint fifoIrqThreshold = 256)22 protected LiteX_I2S(IMachine machine, DataFormat format, uint sampleWidth, uint samplingRate, uint fifoIrqThreshold = 256) : base(machine) 23 { 24 if(format != DataFormat.Standard) 25 { 26 throw new ConstructionException("Only Standard format is supported at the moment"); 27 } 28 29 if(fifoIrqThreshold > fifoDepth) 30 { 31 throw new ConstructionException($"Wrong fifo IRQ threshold value: {fifoIrqThreshold}. Should be in range 0 - {fifoDepth}"); 32 } 33 34 this.fifoIrqThreshold = fifoIrqThreshold; 35 this.dataFormat = format; 36 this.samplingRate = samplingRate; 37 this.sampleWidth = sampleWidth; 38 39 buffer = new Queue<uint>(); 40 IRQ = new GPIO(); 41 DefineRegisters(); 42 UpdateInterrupts(); 43 } 44 Reset()45 public override void Reset() 46 { 47 base.Reset(); 48 buffer.Clear(); 49 50 UpdateInterrupts(); 51 } 52 53 [ConnectionRegion("buffer")] WriteToBuffer(long offset, uint value)54 public void WriteToBuffer(long offset, uint value) 55 { 56 // HW allows to access FIFO from any offset 57 TryEnqueueSample(value); 58 } 59 60 [ConnectionRegion("buffer")] ReadFromBuffer(long offset)61 public uint ReadFromBuffer(long offset) 62 { 63 // HW allows to access FIFO from any offset 64 if(!TryDequeueSample(out var res)) 65 { 66 this.Log(LogLevel.Warning, "Tried to read from an empty FIFO"); 67 } 68 69 return res; 70 } 71 72 public long Size => 0x100; 73 74 public GPIO IRQ { get; } 75 TryEnqueueSample(uint sample)76 protected bool TryEnqueueSample(uint sample) 77 { 78 this.Log(LogLevel.Noisy, "Trying to enqueue a sample: 0x{0:X}", sample); 79 80 lock(buffer) 81 { 82 if(buffer.Count >= fifoDepth) 83 { 84 this.Log(LogLevel.Warning, "FIFO overflow, a sample will be lost"); 85 86 errorEventPending.Value = true; 87 UpdateInterrupts(); 88 89 return false; 90 } 91 92 EnqueueSampleInner(sample); 93 UpdateInterrupts(); 94 95 return true; 96 } 97 } 98 TryDequeueSample(out uint sample)99 protected bool TryDequeueSample(out uint sample) 100 { 101 this.Log(LogLevel.Noisy, "Trying to dequeue a sample"); 102 lock(buffer) 103 { 104 if(buffer.Count == 0) 105 { 106 this.Log(LogLevel.Noisy, "Tried to read from an empty FIFO, returned 0 by default"); 107 sample = 0; 108 109 errorEventPending.Value = true; 110 UpdateInterrupts(); 111 112 return false; 113 } 114 115 sample = buffer.Dequeue(); 116 this.Log(LogLevel.Noisy, "Dequeued 0x{0:X}, buffer is now {1} bytes long", sample, buffer.Count); 117 118 UpdateInterrupts(); 119 120 return true; 121 } 122 } 123 IsReady()124 protected virtual bool IsReady() 125 { 126 return false; 127 } 128 EnqueueSampleInner(uint sample)129 protected virtual void EnqueueSampleInner(uint sample) 130 { 131 buffer.Enqueue(sample); 132 this.Log(LogLevel.Noisy, "Sample enqueued, buffer is now {0} bytes long", buffer.Count); 133 } 134 UpdateInterrupts()135 protected void UpdateInterrupts() 136 { 137 lock(buffer) 138 { 139 var state = false; 140 141 readyEventPending.Value = IsReady(); 142 143 state |= readyEventEnabled.Value && readyEventPending.Value; 144 state |= errorEventEnabled.Value && errorEventPending.Value; 145 146 state &= enabled.Value; 147 148 this.Log(LogLevel.Noisy, "Setting IRQ to {0}", state); 149 IRQ.Set(state); 150 } 151 } 152 HandleEnable(bool enabled)153 protected virtual void HandleEnable(bool enabled) 154 { 155 // by default do nothing 156 } 157 158 protected readonly uint fifoIrqThreshold; 159 protected readonly Queue<uint> buffer; 160 DefineRegisters()161 private void DefineRegisters() 162 { 163 Registers.EventPending.Define32(this) 164 .WithFlag(0, out readyEventPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "ready") 165 .WithFlag(1, out errorEventPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "error") 166 .WithReservedBits(2, 30) 167 .WithWriteCallback((_, __) => UpdateInterrupts()) 168 ; 169 170 Registers.EventEnable.Define(this) 171 .WithFlag(0, out readyEventEnabled, name: "ready") 172 .WithFlag(1, out errorEventEnabled, name: "error") 173 .WithReservedBits(2, 30) 174 .WithWriteCallback((_, __) => UpdateInterrupts()) 175 ; 176 177 Registers.Control.Define(this) 178 .WithFlag(0, out enabled, name: "enable", writeCallback: (_, v) => HandleEnable(v)) 179 .WithFlag(1, FieldMode.Write, name: "fifo_reset", writeCallback: (_, v) => 180 { 181 if(!v) 182 { 183 return; 184 } 185 186 this.Log(LogLevel.Noisy, "Flushing FIFO"); 187 buffer.Clear(); 188 UpdateInterrupts(); 189 }) 190 .WithReservedBits(2, 30) 191 ; 192 193 Registers.Config0.Define(this) 194 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)(samplingRate >> 16), name: "sampling_rate") 195 ; 196 197 Registers.Config1.Define(this) 198 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)(samplingRate >> 8), name: "sampling_rate") 199 ; 200 201 Registers.Config2.Define(this) 202 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => (byte)(samplingRate >> 0), name: "sampling_rate") 203 ; 204 205 Registers.Config3.Define(this) 206 .WithEnumField<DoubleWordRegister, DataFormat>(0, 2, FieldMode.Read, valueProviderCallback: _ => dataFormat, name: "format") 207 .WithValueField(2, 6, FieldMode.Read, valueProviderCallback: _ => sampleWidth, name: "sample_width") 208 ; 209 } 210 211 private IFlagRegisterField enabled; 212 private IFlagRegisterField readyEventEnabled; 213 private IFlagRegisterField errorEventEnabled; 214 private IFlagRegisterField readyEventPending; 215 private IFlagRegisterField errorEventPending; 216 217 private readonly DataFormat dataFormat; 218 private readonly uint sampleWidth; 219 private readonly uint samplingRate; 220 221 private const int fifoDepth = 512; 222 223 public enum DataFormat 224 { 225 Standard = 1, 226 LeftJustified = 2 227 } 228 229 protected enum Registers 230 { 231 EventStatus = 0x000, 232 EventPending = 0x004, 233 EventEnable = 0x008, 234 Control = 0x00C, 235 Status = 0x010, 236 237 // this is a single 32-bit LiteX CSR 238 // scattered accross 4 regular 32-bit registers 239 Config0 = 0x020, 240 Config1 = 0x020 + 0x4, 241 Config2 = 0x020 + 0x8, 242 Config3 = 0x020 + 0xC 243 } 244 } 245 } 246