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 Antmicro.Renode.Core; 8 using Antmicro.Renode.Core.Structure.Registers; 9 using Antmicro.Renode.Exceptions; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Time; 13 using Antmicro.Renode.Utilities; 14 using System; 15 using System.Collections.Generic; 16 using System.Collections.ObjectModel; 17 using static Antmicro.Renode.Peripherals.Bus.GaislerAPBPlugAndPlayRecord; 18 19 namespace Antmicro.Renode.Peripherals.Timers 20 { 21 public class Gaisler_GPTimer : BasicDoubleWordPeripheral, IKnownSize, IGaislerAPB, INumberedGPIOOutput 22 { Gaisler_GPTimer(IMachine machine, uint numberOfTimers = 4, int scalerWidth = 8, int frequency = DefaultTimerFrequency, bool supportsTimeLatch = false, bool separateInterrupts = true)23 public Gaisler_GPTimer(IMachine machine, uint numberOfTimers = 4, int scalerWidth = 8, 24 int frequency = DefaultTimerFrequency, bool supportsTimeLatch = false, bool separateInterrupts = true) : base(machine) 25 { 26 if(numberOfTimers < 1 || numberOfTimers > MaximumNumberOfTimers) 27 { 28 throw new ConstructionException($"Unsupported number of timers {numberOfTimers}, must be in range [1; {MaximumNumberOfTimers}]"); 29 } 30 if(scalerWidth < 1 || scalerWidth > 32) 31 { 32 throw new ConstructionException($"Unsupported scaler width {scalerWidth}, must be in range [1; 32]"); 33 } 34 this.numberOfTimers = numberOfTimers; 35 this.scalerWidth = scalerWidth; 36 scalerResetValue = (uint)BitHelper.Bits(0, scalerWidth); 37 this.supportsTimeLatch = supportsTimeLatch; 38 this.separateInterrupts = separateInterrupts; 39 40 timers = new TimerUnit[numberOfTimers]; 41 var connections = new Dictionary<int, IGPIO>(); 42 for(var i = 0; i < numberOfTimers; i++) 43 { 44 timers[i] = new TimerUnit(machine.ClockSource, frequency, this, i); 45 connections[i] = new GPIO(); 46 } 47 Connections = new ReadOnlyDictionary<int, IGPIO>(connections); 48 49 DefineRegisters(); 50 Reset(); 51 } 52 Reset()53 public override void Reset() 54 { 55 base.Reset(); 56 foreach(var timer in timers) 57 { 58 timer.Reset(); 59 } 60 ScalerReloadValue = (int)scalerResetValue + 1; 61 } 62 GetVendorID()63 public uint GetVendorID() => VendorID; 64 GetDeviceID()65 public uint GetDeviceID() => supportsTimeLatch ? DeviceIDWithLatch : DeviceID; 66 GetSpaceType()67 public SpaceType GetSpaceType() => SpaceType.APBIOSpace; 68 GetInterruptNumber()69 public uint GetInterruptNumber() => this.GetCpuInterruptNumber(Connections[0]); 70 71 public long Size => 0x100; 72 73 public IReadOnlyDictionary<int, IGPIO> Connections { get; } 74 DefineRegisters()75 private void DefineRegisters() 76 { 77 Registers.ScalerValue.Define(this, scalerResetValue) 78 .WithValueField(0, scalerWidth, name: "scalerValue", 79 readCallback: (_, __) => this.WarningLog("Reading the scaler value is not supported"), 80 writeCallback: (_, __) => this.WarningLog("Setting the scaler value is not supported")) 81 .WithReservedBits(scalerWidth, 32 - scalerWidth); 82 83 Registers.ScalerReloadValue.Define(this, scalerResetValue) 84 .WithValueField(0, scalerWidth, name: "scalerReloadValue", 85 valueProviderCallback: _ => (ulong)ScalerReloadValue - 1, changeCallback: (_, v) => ScalerReloadValue = (int)v + 1) 86 .WithReservedBits(scalerWidth, 32 - scalerWidth); 87 88 Registers.Configuration.Define(this) 89 .WithValueField(0, 3, FieldMode.Read, name: "timers", valueProviderCallback: _ => numberOfTimers) 90 .WithValueField(3, 5, FieldMode.Read, name: "firstIrq", valueProviderCallback: _ => GetInterruptNumber()) 91 .WithFlag(8, FieldMode.Read, name: "separateInterrupts", valueProviderCallback: _ => separateInterrupts) 92 .WithTaggedFlag("disableFreeze", 9) 93 .WithReservedBits(10, 1) 94 .WithTaggedFlag("enableLatching", 11) 95 .WithReservedBits(12, 20); 96 97 if(supportsTimeLatch) 98 { 99 Registers.LatchConfiguration.Define(this) 100 .WithTag("latchSelect", 0, 32); 101 } 102 103 // Each timer unit has 3 or 4 registers depending on time latch support 104 Registers.Timer1CounterValue.DefineMany(this, numberOfTimers, stepInBytes: TimerStride, setup: (register, timerIndex) => register 105 .WithValueField(0, 32, name: "counterValue", 106 valueProviderCallback: _ => timers[timerIndex].Value, 107 writeCallback: (_, value) => timers[timerIndex].Value = value) 108 ); 109 110 // Normally a reload value of 9 means the interrupt will fire every 10 ticks, but 111 // the GRLIB BSP writes 0xffffffff here when resetting the timer, so we clamp the limit. 112 Registers.Timer1ReloadValue.DefineMany(this, numberOfTimers, stepInBytes: TimerStride, setup: (register, timerIndex) => register 113 .WithValueField(0, 32, name: "reloadValue", 114 valueProviderCallback: _ => timers[timerIndex].Limit - 1, 115 changeCallback: (_, value) => timers[timerIndex].Limit = Math.Min(value + 1, uint.MaxValue)) 116 ); 117 118 Registers.Timer1Control.DefineMany(this, numberOfTimers, stepInBytes: TimerStride, setup: (register, timerIndex) => register 119 .WithFlag(0, name: "enable", 120 valueProviderCallback: _ => timers[timerIndex].Enabled, 121 changeCallback: (_, v) => timers[timerIndex].Enabled = v) 122 .WithFlag(1, name: "restart", 123 valueProviderCallback: _ => timers[timerIndex].AutoReload, 124 changeCallback: (_, v) => timers[timerIndex].AutoReload = v) 125 .WithFlag(2, FieldMode.WriteOneToClear, name: "load", writeCallback: (_, v) => 126 { 127 if(v) 128 { 129 timers[timerIndex].Value = timers[timerIndex].Limit; 130 } 131 }) 132 .WithFlag(3, out timers[timerIndex].interruptEnable, name: "interruptEnable", 133 changeCallback: (_, __) => UpdateInterrupt(timerIndex)) 134 .WithFlag(4, out timers[timerIndex].interruptPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "interruptPending", 135 changeCallback: (_, __) => UpdateInterrupt(timerIndex)) // Cleared by writing '1' as in the newer hardware revision 136 .WithTaggedFlag("chain", 5) 137 .WithTaggedFlag("debugHalt", 6) 138 .WithReservedBits(7, 25) 139 ); 140 141 if(supportsTimeLatch) 142 { 143 Registers.Timer1Latch.DefineMany(this, numberOfTimers, stepInBytes: TimerStride, setup: (register, timerIndex) => register 144 .WithTag("latchedTimerCounterValue", 0, 32) 145 ); 146 } 147 } 148 UpdateInterrupt(int index)149 private void UpdateInterrupt(int index) 150 { 151 if(!separateInterrupts) 152 { 153 var timer = timers[index]; 154 var state = timer.interruptEnable.Value && timer.interruptPending.Value; 155 if(state) 156 { 157 this.NoisyLog("Signaling IRQ"); 158 Connections[0].Blink(); 159 } 160 return; 161 } 162 163 if(timers[index].interruptEnable.Value && timers[index].interruptPending.Value) 164 { 165 this.NoisyLog("Signaling IRQ {0}", index); 166 Connections[index].Blink(); 167 } 168 } 169 170 private int ScalerReloadValue 171 { 172 get 173 { 174 // All timers share the same scaler so we just take the first one here 175 return timers[0].Divider; 176 } 177 set 178 { 179 foreach(var timer in timers) 180 { 181 timer.Divider = value; 182 } 183 } 184 } 185 186 private readonly TimerUnit[] timers; 187 private readonly uint scalerResetValue; 188 private readonly uint numberOfTimers; 189 private readonly int scalerWidth; 190 private readonly bool supportsTimeLatch; 191 private readonly bool separateInterrupts; 192 193 private const uint VendorID = 0x01; // Gaisler Research 194 private const uint DeviceID = 0x011; // GPTIMER 195 private const uint DeviceIDWithLatch = 0x038; // GRTIMER 196 private const int DefaultTimerFrequency = 1000000; 197 private const int MaximumNumberOfTimers = 7; 198 private const uint TimerStride = Registers.Timer2CounterValue - Registers.Timer1CounterValue; 199 200 private class TimerUnit : ITimer 201 { TimerUnit(IClockSource clockSource, long frequency, Gaisler_GPTimer parent, int index)202 public TimerUnit(IClockSource clockSource, long frequency, Gaisler_GPTimer parent, int index) 203 { 204 this.parent = parent; 205 this.index = index; 206 timer = new LimitTimer(clockSource, frequency, parent, $"timer{index}", limit: uint.MaxValue, eventEnabled: true); 207 timer.LimitReached += OnLimitReached; 208 } 209 Reset()210 public void Reset() 211 { 212 timer.Reset(); 213 parent.UpdateInterrupt(index); 214 } 215 216 public ulong Value 217 { 218 get => timer.Value; 219 set => timer.Value = value; 220 } 221 222 public bool Enabled 223 { 224 get => timer.Enabled; 225 set => timer.Enabled = value; 226 } 227 228 public long Frequency 229 { 230 get => timer.Frequency; 231 set => timer.Frequency = value; 232 } 233 234 public ulong Limit 235 { 236 get => timer.Limit; 237 set => timer.Limit = value; 238 } 239 240 public int Divider 241 { 242 get => timer.Divider; 243 set => timer.Divider = value; 244 } 245 246 public bool AutoReload 247 { 248 get => timer.Mode == WorkMode.Periodic; 249 set => timer.Mode = value ? WorkMode.Periodic : WorkMode.OneShot; 250 } 251 OnLimitReached()252 private void OnLimitReached() 253 { 254 if(interruptEnable.Value) 255 { 256 interruptPending.Value = true; 257 parent.UpdateInterrupt(index); 258 } 259 } 260 261 public IFlagRegisterField interruptEnable; 262 public IFlagRegisterField interruptPending; 263 264 private readonly Gaisler_GPTimer parent; 265 private readonly LimitTimer timer; 266 private readonly int index; 267 } 268 269 private enum Registers : uint 270 { 271 ScalerValue = 0x00, 272 ScalerReloadValue = 0x04, 273 Configuration = 0x08, 274 LatchConfiguration = 0x0c, 275 Timer1CounterValue = 0x10, 276 Timer1ReloadValue = 0x14, 277 Timer1Control = 0x18, 278 Timer1Latch = 0x1c, 279 Timer2CounterValue = 0x20, 280 Timer2ReloadValue = 0x24, 281 Timer2Control = 0x28, 282 Timer2Latch = 0x2c, 283 Timer3CounterValue = 0x30, 284 Timer3ReloadValue = 0x34, 285 Timer3Control = 0x38, 286 Timer3Latch = 0x3c, 287 Timer4CounterValue = 0x40, 288 Timer4ReloadValue = 0x44, 289 Timer4Control = 0x48, 290 Timer4Latch = 0x4c, 291 Timer5CounterValue = 0x50, 292 Timer5ReloadValue = 0x54, 293 Timer5Control = 0x58, 294 Timer5Latch = 0x5c, 295 Timer6CounterValue = 0x60, 296 Timer6ReloadValue = 0x64, 297 Timer6Control = 0x68, 298 Timer6Latch = 0x6c, 299 Timer7CounterValue = 0x70, 300 Timer7ReloadValue = 0x74, 301 Timer7Control = 0x78, 302 Timer7Latch = 0x7c, 303 } 304 } 305 } 306