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