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.Collections.Generic;
9 using System.Runtime.CompilerServices;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Time;
14 
15 namespace Antmicro.Renode.Peripherals.Timers
16 {
17     public class RenesasDA14_GPT : BasicDoubleWordPeripheral, IKnownSize, IGPIOReceiver
18     {
RenesasDA14_GPT(IMachine machine, long lowPowerFrequency = DefaultLowPowerFrequency, bool extendedTimer = false)19         public RenesasDA14_GPT(IMachine machine, long lowPowerFrequency = DefaultLowPowerFrequency,
20             bool extendedTimer = false) : base(machine)
21         {
22             this.lowPowerFrequency = lowPowerFrequency;
23             this.extendedTimer = extendedTimer;
24 
25             timer = new LimitTimer(machine.ClockSource, lowPowerFrequency, this, "timer", FreeRunLimit, direction: Direction.Ascending, workMode: WorkMode.Periodic, eventEnabled: true);
26             timer.LimitReached += () =>
27             {
28                 var currentValue = timer.Limit;
29                 var triggerInterrupt = true;
30 
31                 if(freeRunEnabled.Value && timer.Direction == Direction.Ascending && currentValue != FreeRunLimit)
32                 {
33                     timer.Limit = FreeRunLimit;
34                     timer.Value = currentValue;
35                 }
36                 else
37                 {
38                     triggerInterrupt = currentValue != FreeRunLimit;
39                     timer.Limit = timerLimit.Value;
40                     timer.ResetValue();
41                 }
42 
43                 interruptTriggered = triggerInterrupt;
44                 UpdateInterrupts();
45             };
46 
47             IRQ = new GPIO();
48             CaptureIRQ = new GPIO();
49 
50             connections = new GPIOConnection[extendedTimer ? ExtendedGPIOConnections : DefaultGPIOConnections];
51             for(var i = 0; i < connections.Length; i++)
52             {
53                 connections[i] = new GPIOConnection(this);
54             }
55 
56             DefineRegisters();
57             Reset();
58         }
59 
Reset()60         public override void Reset()
61         {
62             base.Reset();
63             interruptTriggered = false;
64             foreach(var connection in connections)
65             {
66                 connection.Reset();
67             }
68 
69             timer.Reset();
70             IRQ.Unset();
71             CaptureIRQ.Unset();
72         }
73 
OnGPIO(int number, bool value)74         public void OnGPIO(int number, bool value)
75         {
76             if(!IsValidConnection(number))
77             {
78                 return;
79             }
80 
81             connections[number].SetValue(value);
82         }
83 
84         [DefaultInterrupt]
85         public GPIO IRQ { get; }
86         public GPIO CaptureIRQ { get; }
87 
88         public long Size => 0x100;
89 
DefineRegisters()90         private void DefineRegisters()
91         {
92             Registers.Control.Define(this)
93                 .WithFlag(0, out timerEnabled, name: "TIM_EN",
94                     writeCallback: (_, __) => SetTimerEnabled())
95                 .WithTaggedFlag("TIM_ONESHOT_MODE_EN", 1)
96                 .WithFlag(2, name: "TIM_COUNT_DOWN_EN",
97                     valueProviderCallback: _ => timer.Direction == Direction.Descending,
98                     changeCallback: (_, value) => timer.Direction = value ? Direction.Descending : Direction.Ascending)
99                 .WithFlag(3, name: "TIM_IN1_EVENT_FALL_EN",
100                     valueProviderCallback: _ => CallForConnection(0, con => con.UseFallingEdge),
101                     writeCallback: (_, value) => CallForConnection(0, con => con.UseFallingEdge = value))
102                 .WithFlag(4, name: "TIM_IN2_EVENT_FALL_EN",
103                     valueProviderCallback: _ => CallForConnection(1, con => con.UseFallingEdge),
104                     writeCallback: (_, value) => CallForConnection(1, con => con.UseFallingEdge = value))
105                 .WithFlag(5, out interruptEnabled, name: "TIM_IRQ_EN",
106                     writeCallback: (_, __) => UpdateInterrupts())
107                 .WithFlag(6, out freeRunEnabled, name: "TIM_FREE_RUN_MODE_EN")
108                 .WithFlag(7, name: "TIM_SYS_CLK_EN",
109                     valueProviderCallback: _ => timer.Frequency == DivNClockFrequency,
110                     changeCallback: (_, value) => timer.Frequency = value ? DivNClockFrequency : lowPowerFrequency)
111                 .WithFlag(8, out timerClockEnabled, name: "TIM_CLK_EN",
112                     writeCallback: (_, __) => SetTimerEnabled())
113                 .If(extendedTimer)
114                     .Then(r => r
115                         .WithFlag(9, name: "TIM_IN3_EVENT_FALL_EN",
116                             valueProviderCallback: _ => CallForConnection(2, con => con.UseFallingEdge),
117                             writeCallback: (_, value) => CallForConnection(2, con => con.UseFallingEdge = value))
118                         .WithFlag(10, name: "TIM_IN4_EVENT_FALL_EN",
119                             valueProviderCallback: _ => CallForConnection(3, con => con.UseFallingEdge),
120                             writeCallback: (_, value) => CallForConnection(3, con => con.UseFallingEdge = value))
121                         .WithFlag(11, name: "TIM_CAP_GPIO1_IRQ_EN",
122                             valueProviderCallback: _ => CallForConnection(0, con => con.InterruptEnabled),
123                             writeCallback: (_, value) => CallForConnection(0, con => con.InterruptEnabled = value))
124                         .WithFlag(12, name: "TIM_CAP_GPIO2_IRQ_EN",
125                             valueProviderCallback: _ => CallForConnection(1, con => con.InterruptEnabled),
126                             writeCallback: (_, value) => CallForConnection(1, con => con.InterruptEnabled = value))
127                         .WithFlag(13, name: "TIM_CAP_GPIO3_IRQ_EN",
128                             valueProviderCallback: _ => CallForConnection(2, con => con.InterruptEnabled),
129                             writeCallback: (_, value) => CallForConnection(2, con => con.InterruptEnabled = value))
130                         .WithFlag(14, name: "TIM_CAP_GPIO4_IRQ_EN",
131                             valueProviderCallback: _ => CallForConnection(3, con => con.InterruptEnabled),
132                             writeCallback: (_, value) => CallForConnection(3, con => con.InterruptEnabled = value))
133                         .WithReservedBits(15, 17))
134                     .Else(r => r.WithReservedBits(9, 23));
135 
136             Registers.CounterValue.Define(this)
137                 .WithValueField(0, 24, FieldMode.Read, name: "TIM_TIMER_VALUE",
138                     valueProviderCallback: _ => GetTimerValue())
139                 .WithReservedBits(24, 8);
140 
141             Registers.Status.Define(this)
142                 .WithFlag(0, FieldMode.Read, name: "TIM_IN1_STATE",
143                     valueProviderCallback: _ => CallForConnection(0, con => con.Value))
144                 .WithFlag(1, FieldMode.Read, name: "TIM_IN2_STATE",
145                     valueProviderCallback: _ => CallForConnection(1, con => con.Value))
146                 .WithTag("TIM_ONESHOT_PHASE", 2, 2)
147                 .If(extendedTimer)
148                     .Then(r => r
149                         .WithFlag(4, FieldMode.Read, name: "TIM_GPIO1_EVENT_PENDING",
150                             valueProviderCallback: _ => CallForConnection(0, con => con.EventTriggered))
151                         .WithFlag(5, FieldMode.Read, name: "TIM_GPIO2_EVENT_PENDING",
152                             valueProviderCallback: _ => CallForConnection(1, con => con.EventTriggered))
153                         .WithFlag(6, FieldMode.Read, name: "TIM_GPIO3_EVENT_PENDING",
154                             valueProviderCallback: _ => CallForConnection(2, con => con.EventTriggered))
155                         .WithFlag(7, FieldMode.Read, name: "TIM_GPIO4_EVENT_PENDING",
156                             valueProviderCallback: _ => CallForConnection(3, con => con.EventTriggered)))
157                     .Else(r => r.WithReservedBits(4, 4))
158                 .WithFlag(8, FieldMode.Read, name: "TIM_IRQ_STATUS",
159                     valueProviderCallback: _ => interruptTriggered)
160                 .WithTaggedFlag("TIM_TIMER_BUSY", 9)
161                 .WithTaggedFlag("TIM_PWM_BUSY", 10)
162                 .WithFlag(11, FieldMode.Read, name: "TIM_SWITCHED_TO_DIVN_CLK",
163                     valueProviderCallback: _ => timer.Frequency == DivNClockFrequency)
164                 .If(extendedTimer)
165                     .Then(r => r
166                         .WithFlag(12, FieldMode.Read, name: "TIM_IN3_STATE",
167                             valueProviderCallback: _ => CallForConnection(2, con => con.Value))
168                         .WithFlag(13, FieldMode.Read, name: "TIM_IN4_STATE",
169                             valueProviderCallback: _ => CallForConnection(3, con => con.Value))
170                         .WithReservedBits(14, 18))
171                     .Else(r => r.WithReservedBits(12, 20));
172 
173             Registers.GPIO1Selection.Define(this)
174                 .WithTag("TIM_GPIO1_CONF", 0, 6)
175                 .WithReservedBits(6, 26);
176 
177             Registers.GPIO2Selection.Define(this)
178                 .WithTag("TIM_GPIO2_CONF", 0, 6)
179                 .WithReservedBits(6, 26);
180 
181             Registers.Settings.Define(this)
182                 .WithValueField(0, 24, out timerLimit, name: "TIM_RELOAD",
183                     writeCallback: (_, value) =>
184                     {
185                         timer.Limit = value;
186                         if(timer.Direction == Direction.Descending)
187                         {
188                             timer.ResetValue();
189                         }
190                     })
191                 .WithValueField(24, 5, name: "TIM_PRESCALER",
192                     valueProviderCallback: _ => (ulong)timer.Divider - 1,
193                     writeCallback: (_, value) => timer.Divider = (int)value + 1)
194                 .WithReservedBits(29, 3);
195 
196             Registers.ShotDuration.Define(this)
197                 .WithTag("TIM_SHOTWIDTH", 0, 24)
198                 .WithReservedBits(24, 8);
199 
200             Registers.EventValueGPIO1.Define(this)
201                 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO1",
202                     valueProviderCallback: _ => CallForConnection(0, con => con.CaptureTimestamp))
203                 .WithReservedBits(24, 8);
204 
205             Registers.EventValueGPIO2.Define(this)
206                 .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO2",
207                     valueProviderCallback: _ => CallForConnection(1, con => con.CaptureTimestamp))
208                 .WithReservedBits(24, 8);
209 
210             Registers.Prescaler.Define(this)
211                 .WithValueField(0, 5, FieldMode.Read, name: "TIM_PRESCALER_VAL",
212                     valueProviderCallback: _ => (ulong)timer.Divider - 1)
213                 .WithReservedBits(5, 27);
214 
215             Registers.PWMControl.Define(this)
216                 .WithTag("TIM_PWM_FREQ", 0, 16)
217                 .WithTag("TIM_PWM_DC", 16, 16);
218 
219             if(extendedTimer)
220             {
221                 Registers.GPIO3Selection.Define(this)
222                     .WithTag("TIM_GPIO3_CONF", 0, 6)
223                     .WithReservedBits(6, 26);
224 
225                 Registers.GPIO4Selection.Define(this)
226                     .WithTag("TIM_GPIO4_CONF", 0, 6)
227                     .WithReservedBits(6, 26);
228 
229                 Registers.EventValueGPIO3.Define(this)
230                     .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO3",
231                         valueProviderCallback: _ => CallForConnection(2, con => con.CaptureTimestamp))
232                     .WithReservedBits(24, 8);
233 
234                 Registers.EventValueGPIO4.Define(this)
235                     .WithValueField(0, 24, FieldMode.Read, name: "TIM_CAPTURE_GPIO4",
236                         valueProviderCallback: _ => CallForConnection(3, con => con.CaptureTimestamp))
237                     .WithReservedBits(24, 8);
238 
239                 Registers.GPIOEventClear.Define(this)
240                     .WithFlag(0, FieldMode.Write, name: "TIM_CLEAR_GPIO1_EVENT",
241                         writeCallback: (_, value) => CallForConnection(0, con => ClearGPIOEvent(con, value)))
242                     .WithFlag(1, FieldMode.Write, name: "TIM_CLEAR_GPIO2_EVENT",
243                         writeCallback: (_, value) => CallForConnection(1, con => ClearGPIOEvent(con, value)))
244                     .WithFlag(2, FieldMode.Write, name: "TIM_CLEAR_GPIO3_EVENT",
245                         writeCallback: (_, value) => CallForConnection(2, con => ClearGPIOEvent(con, value)))
246                     .WithFlag(3, FieldMode.Write, name: "TIM_CLEAR_GPIO4_EVENT",
247                         writeCallback: (_, value) => CallForConnection(3, con => ClearGPIOEvent(con, value)))
248                     .WithReservedBits(4, 28);
249             }
250 
251             (extendedTimer ? Registers.InterruptClearExtended : Registers.InterruptClear).Define(this)
252                 .WithFlag(0, FieldMode.Write, name: "TIM_CLEAR_IRQ",
253                     writeCallback: (_, __) =>
254                     {
255                         interruptTriggered = false;
256                         UpdateInterrupts();
257                     })
258                 .WithReservedBits(1, 31);
259         }
260 
GetTimerValue()261         private ulong GetTimerValue()
262         {
263             if(machine.GetSystemBus(this).TryGetCurrentCPU(out var cpu))
264             {
265                 cpu.SyncTime();
266             }
267 
268             return timer.Value;
269         }
270 
UpdateInterrupts()271         private void UpdateInterrupts()
272         {
273             if(!timer.Enabled)
274             {
275                 IRQ.Unset();
276                 CaptureIRQ.Unset();
277                 return;
278             }
279 
280             var timerIrqValue = interruptEnabled.Value && interruptTriggered;
281             this.DebugLog("{0} interrupt", timerIrqValue ? "Setting" : "Unsetting");
282             IRQ.Set(timerIrqValue);
283 
284             if(extendedTimer)
285             {
286                 var gpioIrqValue = false;
287                 foreach(var connection in connections)
288                 {
289                     gpioIrqValue |= connection.InterruptEnabled && connection.EventTriggered;
290                 }
291 
292                 this.DebugLog("{0} capture interrupt", gpioIrqValue ? "Setting" : "Unsetting");
293                 CaptureIRQ.Set(gpioIrqValue);
294             }
295             else
296             {
297                 CaptureIRQ.Unset();
298             }
299         }
300 
SetTimerEnabled()301         private void SetTimerEnabled()
302         {
303             var enabled = timerEnabled.Value && timerClockEnabled.Value;
304             timer.Enabled = enabled;
305         }
306 
CallForConnection(int index, Action<GPIOConnection> callback, bool logMessage = false)307         private void CallForConnection(int index, Action<GPIOConnection> callback, bool logMessage = false)
308         {
309             if(!IsValidConnection(index, logMessage))
310             {
311                 return;
312             }
313 
314             callback(connections[index]);
315         }
316 
CallForConnection(int index, Func<GPIOConnection, T> callback, bool logMessage = false)317         private T CallForConnection<T>(int index, Func<GPIOConnection, T> callback, bool logMessage = false)
318         {
319             if(!IsValidConnection(index, logMessage))
320             {
321                 return default(T);
322             }
323 
324             return callback(connections[index]);
325         }
326 
327         [MethodImpl(MethodImplOptions.AggressiveInlining)]
IsValidConnection(int index, bool logMessage = true)328         private bool IsValidConnection(int index, bool logMessage = true)
329         {
330             if(index < 0 || index >= connections.Length)
331             {
332                 if(logMessage)
333                 {
334                     this.WarningLog("GPIO connection {0} is out of range of [0;{1})", index, connections.Length);
335                 }
336 
337                 return false;
338             }
339             return true;
340         }
341 
ClearGPIOEvent(GPIOConnection connection, bool value)342         private void ClearGPIOEvent(GPIOConnection connection, bool value)
343         {
344             if(!value)
345             {
346                 return;
347             }
348 
349             connection.EventTriggered = false;
350             UpdateInterrupts();
351         }
352 
353         private readonly LimitTimer timer;
354         private readonly GPIOConnection[] connections;
355 
356         private readonly long lowPowerFrequency;
357         private readonly bool extendedTimer;
358 
359         private bool interruptTriggered;
360 
361         private IFlagRegisterField interruptEnabled;
362         private IFlagRegisterField timerEnabled;
363         private IFlagRegisterField timerClockEnabled;
364         private IFlagRegisterField freeRunEnabled;
365 
366         private IValueRegisterField timerLimit;
367 
368         private const long DefaultLowPowerFrequency = 32000;
369         private const long DivNClockFrequency = 32000000;
370         private const long FreeRunLimit = (1 << 24) - 1;
371 
372         private const int DefaultGPIOConnections = 2;
373         private const int ExtendedGPIOConnections = 4;
374 
375         private enum Registers
376         {
377             Control                 = 0x00, // TIMER_CTRL_REG
378             CounterValue            = 0x04, // TIMER_TIMER_VAL_REG
379             Status                  = 0x08, // TIMER_STATUS_REG
380             GPIO1Selection          = 0x0C, // TIMER_GPIO1_CONF_REG
381             GPIO2Selection          = 0x10, // TIMER_GPIO2_CONF_REG
382             Settings                = 0x14, // TIMER_SETTINGS_REG
383             ShotDuration            = 0x18, // TIMER_SHOTWIDTH_REG
384             // Gap
385             EventValueGPIO1         = 0x20, // TIMER_CAPTURE_GPIO1_REG
386             EventValueGPIO2         = 0x24, // TIMER_CAPTURE_GPIO2_REG
387             Prescaler               = 0x28, // TIMER_PRESCALER_VAL_REG
388             PWMControl              = 0x2C, // TIMER_PWM_CTRL_REG
389             // Gap
390             InterruptClear          = 0x34, // TIMER_CLEAR_IRQ_REG
391 
392             // Registers for extended timer version
393             GPIO3Selection          = 0x34, // TIMER_GPIO3_CONF_REG
394             GPIO4Selection          = 0x38, // TIMER_GPIO4_CONF_REG
395             EventValueGPIO3         = 0x3C, // TIMER_CAPTURE_GPIO3_REG
396             EventValueGPIO4         = 0x40, // TIMER_CAPTURE_GPIO4_REG
397             GPIOEventClear          = 0x44, // TIMER_CLEAR_GPIO_EVENT_REG
398             InterruptClearExtended  = 0x48, // TIMER_CLEAR_IRQ_REG
399         }
400 
401         private class GPIOConnection
402         {
GPIOConnection(RenesasDA14_GPT owner)403             public GPIOConnection(RenesasDA14_GPT owner)
404             {
405                 this.owner = owner;
406             }
407 
Reset()408             public void Reset()
409             {
410                 Enabled = false;
411                 InterruptEnabled = false;
412                 EventTriggered = false;
413                 Value = false;
414                 UseFallingEdge = false;
415                 CaptureTimestamp = 0;
416             }
417 
SetValue(bool value)418             public void SetValue(bool value)
419             {
420                 if(!Enabled)
421                 {
422                     return;
423                 }
424 
425                 if(UseFallingEdge)
426                 {
427                     EventTriggered = Value && !value;
428                 }
429                 else
430                 {
431                     EventTriggered = !Value && value;
432                 }
433 
434                 Value = value;
435                 if(EventTriggered)
436                 {
437                     CaptureTimestamp = owner.GetTimerValue();
438                 }
439                 owner.UpdateInterrupts();
440             }
441 
442             public bool Enabled { get; set; }
443 
444             public bool EventTriggered { get; set; }
445 
446             public bool Value { get; private set; }
447             public ulong CaptureTimestamp { get; private set; }
448 
449             public bool InterruptEnabled { get; set; }
450             public bool UseFallingEdge { get; set; }
451 
452             private readonly RenesasDA14_GPT owner;
453         }
454     }
455 }
456