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.Utilities;
10 using Antmicro.Renode.Time;
11 
12 namespace Antmicro.Renode.Peripherals.Timers
13 {
14     public class EFR32xG24_SYSRTC : BasicDoubleWordPeripheral, IKnownSize
15     {
EFR32xG24_SYSRTC(Machine machine, long frequency = 32768)16         public EFR32xG24_SYSRTC(Machine machine, long frequency = 32768) : base(machine)
17         {
18             AppIRQ = new GPIO();
19             interruptManager = new InterruptManager<Interrupt>(this, AppIRQ);
20 
21             limitTimer = new LimitTimer(machine.ClockSource, frequency, this, "limitTimer", uint.MaxValue, direction: Direction.Ascending, autoUpdate: true, eventEnabled: true);
22             limitTimer.LimitReached += () => interruptManager.SetInterrupt(Interrupt.Overflow);
23 
24             compare0Timer = new ComparingTimer(machine.ClockSource, frequency, this, "compare0Timer",
25                 limit: uint.MaxValue, compare: uint.MaxValue, workMode: WorkMode.Periodic, eventEnabled: true);
26             compare0Timer.CompareReached += HandleCompare0TimerCompareReached;
27 
28             compare1Timer = new ComparingTimer(machine.ClockSource, frequency, this, "compare1Timer",
29                 limit: uint.MaxValue, compare: uint.MaxValue, workMode: WorkMode.Periodic, eventEnabled: true);
30             compare1Timer.CompareReached += HandleCompare1TimerCompareReached;
31 
32             capture0Timer = new ComparingTimer(machine.ClockSource, frequency, this, "capture0Timer",
33                 limit: uint.MaxValue, compare: uint.MaxValue, workMode: WorkMode.Periodic, eventEnabled: true);
34             capture0Timer.CompareReached += HandleCapture0TimerCompareReached;
35 
36             DefineRegisters();
37         }
38 
Reset()39         public override void Reset()
40         {
41             base.Reset();
42             limitTimer.Reset();
43             compare0Timer.Reset();
44             compare1Timer.Reset();
45             capture0Timer.Reset();
46             interruptManager.Reset();
47             AppIRQ.Unset();
48         }
49 
50         public long Size => 0x4000;
51 
52         public GPIO AppIRQ { get; }
53 
DefineRegisters()54         private void DefineRegisters()
55         {
56             Register.IpVersion.Define(this, 0x1)
57                 .WithTag("IPVERSION", 0, 32);
58 
59             Register.Enable.Define(this)
60                 .WithTaggedFlag("EN", 0)
61                 .WithTaggedFlag("DISABLING", 1)
62                 .WithReservedBits(2, 30);
63 
64             Register.SoftwareReset.Define(this)
65                 .WithTaggedFlag("SWRST", 0)
66                 .WithTaggedFlag("RESETTING", 1)
67                 .WithReservedBits(2, 30);
68 
69             Register.Config.Define(this)
70                 .WithTaggedFlag("DEBUGRUN", 0)
71                 .WithReservedBits(1, 31);
72 
73             Register.Command.Define(this)
74                 .WithFlag(0, FieldMode.Write,
75                     writeCallback: (_, value) =>
76                     {
77                         if(!value)
78                         {
79                             return;
80                         }
81                         limitTimer.Enabled = true;
82                         compare0Timer.Enabled = true;
83                         compare1Timer.Enabled = true;
84                         capture0Timer.Enabled = true;
85                     },
86                     name: "START")
87                 .WithFlag(1, FieldMode.Write,
88                     writeCallback: (_, value) =>
89                     {
90                         if(!value)
91                         {
92                             return;
93                         }
94                         limitTimer.Enabled = false;
95                         compare0Timer.Enabled = false;
96                         compare1Timer.Enabled = false;
97                         capture0Timer.Enabled = false;
98                     },
99                     name: "STOP")
100                 .WithReservedBits(2, 30);
101 
102             Register.Status.Define(this)
103                 .WithFlag(0, FieldMode.Read,
104                     valueProviderCallback: _ => compare0Timer.Enabled,
105                     name: "RUNNING")
106                 .WithTaggedFlag("LOCKSTATUS", 1)
107                 .WithReservedBits(2, 30);
108 
109             Register.Counter.Define(this)
110                 .WithValueField(0, 32,
111                     valueProviderCallback: _ =>  compare0Timer.Value,
112                     writeCallback: (_, value) =>
113                     {
114                         limitTimer.Value = value;
115                         compare0Timer.Value = value;
116                         compare1Timer.Value = value;
117                         capture0Timer.Value = value;
118                     },
119                     name: "CNT");
120 
121             Register.SyncBusy.Define(this)
122                 .WithTaggedFlag("START", 0)
123                 .WithTaggedFlag("STOP", 1)
124                 .WithTaggedFlag("CNT", 2)
125                 .WithReservedBits(3, 29);
126 
127             Register.Lock.Define(this)
128                 .WithTag("LOCKKEY", 0, 16)
129                 .WithReservedBits(16, 16);
130 
131             Register.Group0Control.Define(this)
132                 .WithFlag(0, out group0Compare0Enable, name: "CMP0EN")
133                 .WithFlag(1, out group0Compare1Enable, name: "CMP1EN")
134                 .WithFlag(2, out group0Capture0Enable, name: "CAP0EN")
135                 .WithTag("CMP0CMOA", 3, 3)
136                 .WithTag("CMP1CMOA", 6, 3)
137                 .WithTag("CAP0EDGE", 9, 2)
138                 .WithReservedBits(11, 21)
139                 .WithChangeCallback((_, __) =>
140                 {
141                     compare0Timer.Enabled = group0Compare0Enable.Value;
142                     compare1Timer.Enabled = group0Compare1Enable.Value;
143                     capture0Timer.Enabled = group0Capture0Enable.Value;
144                     limitTimer.Enabled = compare0Timer.Enabled | compare1Timer.Enabled | capture0Timer.Enabled;
145                 });
146 
147             Register.Group0Compare0.Define(this)
148                 .WithValueField(0, 32, out group0Compare0Value,
149                     writeCallback: (_, val) => compare0Timer.Compare = group0Compare0Value.Value,
150                     name: "CMP0VALUE");
151 
152             Register.Group0Compare1.Define(this)
153                 .WithValueField(0, 32, out group0Compare1Value,
154                     writeCallback: (_, val) => compare1Timer.Compare = group0Compare1Value.Value,
155                     name: "CMP1VALUE");
156 
157             Register.Group0Capture0.Define(this)
158                 .WithValueField(0, 32, out group0Capture0Value,
159                     writeCallback: (_, val) => capture0Timer.Compare = group0Capture0Value.Value,
160                     name: "CAP0VALUE");
161 
162             Register.Group0SyncBusy.Define(this)
163                 .WithTaggedFlag("CTRL", 0)
164                 .WithTaggedFlag("CMP0VALUE", 1)
165                 .WithTaggedFlag("CMP1VALUE", 2)
166                 .WithReservedBits(3, 29);
167 
168             RegistersCollection.AddRegister((long)Register.Group0InterruptFlags, interruptManager.GetRegister<DoubleWordRegister>(
169                 valueProviderCallback: (irq, _) => interruptManager.IsSet(irq),
170                 writeCallback: (irq, _, newValue) => interruptManager.SetInterrupt(irq, newValue)));
171 
172             RegistersCollection.AddRegister((long)Register.Group0InterruptEnable, interruptManager.GetInterruptEnableRegister<DoubleWordRegister>());
173 
174             RegistersCollection.AddRegister((long)Register.Group0InterruptEnable_Set, interruptManager.GetInterruptEnableSetRegister<DoubleWordRegister>());
175 
176             RegistersCollection.AddRegister((long)Register.Group0InterruptFlags_Clear, interruptManager.GetInterruptClearRegister<DoubleWordRegister>());
177 
178             RegistersCollection.AddRegister((long)Register.Group0InterruptEnable_Clear, interruptManager.GetInterruptEnableClearRegister<DoubleWordRegister>());
179         }
180 
HandleCompare0TimerCompareReached()181         private void HandleCompare0TimerCompareReached()
182         {
183             if(group0Compare0Enable.Value)
184             {
185                 interruptManager.SetInterrupt(Interrupt.Compare0Match);
186             }
187         }
188 
HandleCompare1TimerCompareReached()189         private void HandleCompare1TimerCompareReached()
190         {
191             if(group0Compare1Enable.Value)
192             {
193                 interruptManager.SetInterrupt(Interrupt.Compare1Match);
194             }
195         }
196 
HandleCapture0TimerCompareReached()197         private void HandleCapture0TimerCompareReached()
198         {
199             if(group0Capture0Enable.Value)
200             {
201                 interruptManager.SetInterrupt(Interrupt.Capture0);
202             }
203         }
204 
205         private readonly InterruptManager<Interrupt> interruptManager;
206         private readonly LimitTimer limitTimer;
207         private readonly ComparingTimer compare0Timer;
208         private readonly ComparingTimer compare1Timer;
209         private readonly ComparingTimer capture0Timer;
210 
211         private IFlagRegisterField group0Compare0Enable;
212         private IFlagRegisterField group0Compare1Enable;
213         private IFlagRegisterField group0Capture0Enable;
214         private IValueRegisterField group0Compare0Value;
215         private IValueRegisterField group0Compare1Value;
216         private IValueRegisterField group0Capture0Value;
217 
218         private enum Interrupt
219         {
220             Overflow,
221             Compare0Match,
222             Compare1Match,
223             Capture0
224         }
225 
226         private enum Register
227         {
228             IpVersion                       = 0x0000,
229             Enable                          = 0x0004,
230             SoftwareReset                   = 0x0008,
231             Config                          = 0x000C,
232             Command                         = 0x0010,
233             Status                          = 0x0014,
234             Counter                         = 0x0018,
235             SyncBusy                        = 0x001C,
236             Lock                            = 0x0020,
237             Group0InterruptFlags            = 0x0040,
238             Group0InterruptEnable           = 0x0044,
239             Group0Control                   = 0x0048,
240             Group0Compare0                  = 0x004C,
241             Group0Compare1                  = 0x0050,
242             Group0Capture0                  = 0x0054,
243             Group0SyncBusy                  = 0x0058,
244 
245             IpVersion_Set                   = 0x1000,
246             Enable_Set                      = 0x1004,
247             SoftwareReset_Set               = 0x1008,
248             Config_Set                      = 0x100C,
249             Command_Set                     = 0x1010,
250             Status_Set                      = 0x1014,
251             Counter_Set                     = 0x1018,
252             SyncBusy_Set                    = 0x101C,
253             Lock_Set                        = 0x1020,
254             Group0InterruptFlags_Set        = 0x1040,
255             Group0InterruptEnable_Set       = 0x1044,
256             Group0Control_Set               = 0x1048,
257             Group0Compare0_Set              = 0x104C,
258             Group0Compare1_Set              = 0x1050,
259             Group0Capture0_Set              = 0x1054,
260             Group0SyncBusy_Set              = 0x1058,
261 
262             IpVersion_Clear                 = 0x2000,
263             Enable_Clear                    = 0x2004,
264             SoftwareReset_Clear             = 0x2008,
265             Config_Clear                    = 0x200C,
266             Command_Clear                   = 0x2010,
267             Status_Clear                    = 0x2014,
268             Counter_Clear                   = 0x2018,
269             SyncBusy_Clear                  = 0x201C,
270             Lock_Clear                      = 0x2020,
271             Group0InterruptFlags_Clear      = 0x2040,
272             Group0InterruptEnable_Clear     = 0x2044,
273             Group0Control_Clear             = 0x2048,
274             Group0Compare0_Clear            = 0x204C,
275             Group0Compare1_Clear            = 0x2050,
276             Group0Capture0_Clear            = 0x2054,
277             Group0SyncBusy_Clear            = 0x2058,
278 
279             IpVersion_Toggle                = 0x3000,
280             Enable_Toggle                   = 0x3004,
281             SoftwareReset_Toggle            = 0x3008,
282             Config_Toggle                   = 0x300C,
283             Command_Toggle                  = 0x3010,
284             Status_Toggle                   = 0x3014,
285             Counter_Toggle                  = 0x3018,
286             SyncBusy_Toggle                 = 0x301C,
287             Lock_Toggle                     = 0x3020,
288             Group0InterruptFlags_Toggle     = 0x3040,
289             Group0InterruptEnable_Toggle    = 0x3044,
290             Group0Control_Toggle            = 0x3048,
291             Group0Compare0_Toggle           = 0x304C,
292             Group0Compare1_Toggle           = 0x3050,
293             Group0Capture0_Toggle           = 0x3054,
294             Group0SyncBusy_Toggle           = 0x3058,
295         }
296     }
297 }
298