1 //
2 // Copyright (c) 2010-2018 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 Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Peripherals.Bus;
12 using Antmicro.Renode.Time;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class MPFS_Timer : IDoubleWordPeripheral, IKnownSize
17     {
MPFS_Timer(IMachine machine, long frequency = 100000000)18         public MPFS_Timer(IMachine machine, long frequency = 100000000)
19         {
20             Timer1IRQ = new GPIO();
21             Timer2IRQ = new GPIO();
22 
23             timerInterruptEnable = new IFlagRegisterField[NumberOfInternalTimers];
24             rawInterruptStatus = new IFlagRegisterField[NumberOfInternalTimers];
25             backgroundLoadValue = new ulong[NumberOfInternalTimers];
26             backgroundLoadValueIsValid = new bool[NumberOfInternalTimers];
27 
28             timer = new LimitTimer[NumberOfInternalTimers]
29             {
30                 new LimitTimer(machine.ClockSource, frequency, this, "0", uint.MaxValue, autoUpdate: true, eventEnabled: true),
31                 new LimitTimer(machine.ClockSource, frequency, this, "1", uint.MaxValue, autoUpdate: true, eventEnabled: true),
32                 new LimitTimer(machine.ClockSource, frequency, this, "2", autoUpdate: true, eventEnabled: true)
33             };
34 
35             for (var i = 0; i < NumberOfInternalTimers; i++)
36             {
37                 var j = i;
38                 timer[i].LimitReached += delegate
39                 {
40                     rawInterruptStatus[j].Value = true;
41                     lock(timer[j])
42                     {
43                         if(backgroundLoadValueIsValid[j])
44                         {
45                             backgroundLoadValueIsValid[j]= false;
46                             timer[j].Limit = backgroundLoadValue[j];
47                             // TODO: doesn't it reduce the tick count by one (I mean shouldn't we put the new value AFTER this tick is finished?)
48                         }
49                     }
50                     UpdateInterrupt();
51                 };
52             }
53 
54             var registersMap = new Dictionary<long, DoubleWordRegister>
55             {
56                 // the rest of registers is generated using `GenerateRegistersForTimer` method calls located below
57 
58                 {(long)Registers.Timer64ValueHigh, new DoubleWordRegister(this)
59                     .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEU", valueProviderCallback: _ => (uint)(timer[Timer.Timer64].Value >> 32))
60                 },
61 
62                 {(long)Registers.Timer64ValueLow, new DoubleWordRegister(this)
63                     .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEL", valueProviderCallback: _ => (uint)timer[Timer.Timer64].Value)
64                 },
65 
66                 {(long)Registers.Timer64LoadValueHigh, new DoubleWordRegister(this)
67                     .WithValueField(0, 32, out var timer64LoadValueHigh, name: "TIM64LOADVALU")
68                 },
69 
70                 {(long)Registers.Timer64LoadValueLow, new DoubleWordRegister(this)
71                     .WithValueField(0, 32, name: "TIM64LOADVALL", writeCallback: (_, valueLow) => timer[Timer.Timer64].Limit = (timer64LoadValueHigh.Value << 32) | valueLow)
72                 },
73 
74                 {(long)Registers.Timer64BackgroundLoadValueHigh, new DoubleWordRegister(this)
75                         .WithValueField(0, 32, out var timer64BackgroundLoadValueHigh, name: "TIM64BGLOADVAU")
76                 },
77 
78                 {(long)Registers.Timer64BackgroundLoadValueLow, new DoubleWordRegister(this)
79                         .WithValueField(0, 32, name: "TIM64BGLOADVAL", writeCallback: (_, val) =>
80                         {
81                             lock(timer[Timer.Timer64])
82                             {
83                                 backgroundLoadValue[Timer.Timer64] = ((ulong)timer64BackgroundLoadValueHigh.Value << 32) | val;
84                                 backgroundLoadValueIsValid[Timer.Timer64] = true;
85                             }
86                         })
87                 },
88 
89                 {(long)Registers.TimerMode, new DoubleWordRegister(this)
90                     .WithEnumField<DoubleWordRegister, TimerMode>(0, 1, out timerMode, name: "TIM64MODE", writeCallback: (_, val) => InternalSoftReset(val))}
91             };
92 
93             GenerateRegistersForTimer("TIM1", Timer.Timer32_1, registersMap);
94             GenerateRegistersForTimer("TIM2", Timer.Timer32_2, registersMap, offset: Registers.Timer2Value - Registers.Timer1Value);
95             // 64-bit timer has different value/load_value/load_background_value registers that are defined directly when creating registersMap dictionary; the rest are common ones
96             GenerateRegistersForTimer("TIM64", Timer.Timer64, registersMap, offset: Registers.Timer64Control - Registers.Timer1Control, includeValueRegisters: false);
97 
98             registers = new DoubleWordRegisterCollection(this, registersMap);
99         }
100 
Reset()101         public void Reset()
102         {
103             registers.Reset();
104             foreach(var eachTimer in timer)
105             {
106                 eachTimer.Reset();
107             }
108             UpdateInterrupt();
109         }
110 
ReadDoubleWord(long offset)111         public uint ReadDoubleWord(long offset)
112         {
113             return registers.Read(offset);
114         }
115 
WriteDoubleWord(long offset, uint value)116         public void WriteDoubleWord(long offset, uint value)
117         {
118             registers.Write(offset, value);
119         }
120 
121         public long Size => 0x1000;
122 
123         public GPIO Timer1IRQ { get; private set; }
124         public GPIO Timer2IRQ { get; private set; }
125 
InternalSoftReset(TimerMode mode)126         private void InternalSoftReset(TimerMode mode)
127         {
128             Reset();
129             // reset will force `timerMode` value to 0, so we must set its value manually
130             timerMode.Value = mode;
131         }
132 
UpdateInterrupt()133         private void UpdateInterrupt()
134         {
135             if(timerMode.Value == TimerMode.One64BitTimer)
136             {
137                 Timer1IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer64));
138                 Timer2IRQ.Unset();
139             }
140             else
141             {
142                 Timer1IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer32_1));
143                 Timer2IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer32_2));
144             }
145         }
146 
CalculateTimerMaskedInterruptValue(int timerId)147         private bool CalculateTimerMaskedInterruptValue(int timerId)
148         {
149             return rawInterruptStatus[timerId].Value && timerInterruptEnable[timerId].Value;
150         }
151 
GenerateRegistersForTimer(string name, int timerId, Dictionary<long, DoubleWordRegister> registersMap, long offset = 0, bool includeValueRegisters = true)152         private void GenerateRegistersForTimer(string name, int timerId, Dictionary<long, DoubleWordRegister> registersMap, long offset = 0, bool includeValueRegisters = true)
153         {
154             if(includeValueRegisters)
155             {
156                 registersMap.Add((long)Registers.Timer1Value + offset, new DoubleWordRegister(this)
157                         .WithValueField(0, 32, FieldMode.Read, name: $"{name}VALUE", valueProviderCallback: _ => (uint)timer[timerId].Value)
158                 );
159 
160                 registersMap.Add((long)Registers.Timer1LoadValue + offset, new DoubleWordRegister(this)
161                         .WithValueField(0, 32, name: $"{name}LOADVAL", writeCallback: (_, val) => timer[timerId].Limit = val)
162                 );
163 
164                 registersMap.Add((long)Registers.Timer1BackgroundLoadValue + offset, new DoubleWordRegister(this)
165                         .WithValueField(0, 32, name: $"{name}BGLOADVAL", writeCallback: (_, val) =>
166                         {
167                             lock(timer[timerId])
168                             {
169                                 backgroundLoadValue[timerId] = val;
170                                 backgroundLoadValueIsValid[timerId] = true;
171                             }
172                         })
173                 );
174             }
175 
176             registersMap.Add((long)Registers.Timer1Control + offset, new DoubleWordRegister(this)
177                     .WithFlag(0, name: $"{name}ENABLE", writeCallback: (_, val) => timer[timerId].Enabled = val)
178                     .WithEnumField<DoubleWordRegister, OperatingMode>(1, 1, name: $"{name}MODE", writeCallback: (_, val) => timer[timerId].Mode = (val == OperatingMode.OneShot ? WorkMode.OneShot : WorkMode.Periodic))
179                     .WithFlag(2, out timerInterruptEnable[timerId], name: $"{name}INTEN", writeCallback: (_, __) => UpdateInterrupt())
180             );
181 
182             registersMap.Add((long)Registers.Timer1RawInterruptStatus + offset, new DoubleWordRegister(this)
183                     .WithFlag(0, out rawInterruptStatus[timerId], FieldMode.Read | FieldMode.WriteOneToClear, name: $"{name}RIS", writeCallback: (_, __) => UpdateInterrupt())
184             );
185 
186             registersMap.Add((long)Registers.Timer1MaskedInterruptStatus + offset, new DoubleWordRegister(this)
187                     .WithFlag(0, FieldMode.Read, name: $"{name}MIS", valueProviderCallback: _ => CalculateTimerMaskedInterruptValue(timerId))
188             );
189         }
190 
191 
192         private readonly DoubleWordRegisterCollection registers;
193 
194         private readonly IEnumRegisterField<TimerMode> timerMode;
195         private readonly IFlagRegisterField[]  timerInterruptEnable;
196         private readonly IFlagRegisterField[] rawInterruptStatus;
197 
198         private readonly bool[] backgroundLoadValueIsValid;
199         private readonly ulong[] backgroundLoadValue;
200         private readonly LimitTimer[] timer;
201 
202         private const int NumberOfInternalTimers = 3;
203 
204         private static class Timer
205         {
206             public const int Timer32_1 = 0;
207             public const int Timer32_2 = 1;
208             public const int Timer64 = 2;
209         }
210 
211         private enum TimerMode
212         {
213             Two32BitTimers = 0,
214             One64BitTimer = 1
215         }
216 
217         private enum OperatingMode
218         {
219             Periodic = 0,
220             OneShot = 1
221         }
222 
223         private enum Registers
224         {
225             Timer1Value = 0x0,
226             Timer1LoadValue = 0x4,
227             Timer1BackgroundLoadValue = 0x8,
228             Timer1Control = 0xC,
229             Timer1RawInterruptStatus = 0x10,
230             Timer1MaskedInterruptStatus = 0x14,
231 
232             Timer2Value = 0x18,
233             Timer2LoadValue = 0x1C,
234             Timer2BackgroundLoadValue = 0x20,
235             Timer2Control = 0x24,
236             Timer2RawInterruptStatus = 0x28,
237             Timer2MaskedInterruptStatus = 0x2C,
238 
239             Timer64ValueHigh = 0x30,
240             Timer64ValueLow = 0x34,
241             Timer64LoadValueHigh = 0x38,
242             Timer64LoadValueLow = 0x3C,
243             Timer64BackgroundLoadValueHigh = 0x40,
244             Timer64BackgroundLoadValueLow = 0x44,
245             Timer64Control = 0x48,
246             Timer64RawInterruptStatus = 0x4C,
247             Timer64MaskedInterruptStatus = 0x50,
248             TimerMode = 0x54
249         }
250     }
251 }
252