1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Linq;
10 
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Logging;
14 using Antmicro.Renode.Utilities;
15 using Antmicro.Renode.Time;
16 
17 namespace Antmicro.Renode.Peripherals.Timers
18 {
19     public class EFR32xG2_BURTC : BasicDoubleWordPeripheral, IKnownSize
20     {
EFR32xG2_BURTC(Machine machine, long frequency = 32768)21         public EFR32xG2_BURTC(Machine machine, long frequency = 32768) : base(machine)
22         {
23             IRQ = new GPIO();
24             interruptManager = new InterruptManager<Interrupt>(this);
25 
26             innerTimer = new ComparingTimer(machine.ClockSource, frequency, this, "burtc", limit: uint.MaxValue, compare: uint.MaxValue, workMode: WorkMode.Periodic, eventEnabled: true);
27 
28             // TODO: add support for the overflow exception
29             innerTimer.CompareReached += delegate
30             {
31                 interruptManager.SetInterrupt(Interrupt.CompareMatch);
32             };
33 
34             DefineRegisters();
35         }
36 
Reset()37         public override void Reset()
38         {
39             base.Reset();
40             innerTimer.Reset();
41             interruptManager.Reset();
42         }
43 
44         public long Size => 0x3034;
45 
46         [IrqProvider]
47         public GPIO IRQ { get; }
48 
DefineRegisters()49         private void DefineRegisters()
50         {
51             Register.IpVersion.Define(this)
52                 .WithTag("IPVERSION", 0, 32);
53 
54             Register.ModuleEnable.Define(this)
55                 .WithTaggedFlag("EN", 0)
56                 .WithReservedBits(1, 31);
57 
58             Register.Configuration.Define(this)
59                 .WithTaggedFlag("DEBUGRUN", 0)
60                 .WithTaggedFlag("COMPTOP", 1)
61                 .WithReservedBits(2, 2)
62                 .WithValueField(4, 4,
63                     writeCallback: (_, value) => innerTimer.Divider = (uint)Math.Pow(2, value),
64                     valueProviderCallback: _ => (uint)Math.Log(innerTimer.Divider, 2),
65                     name: "CNTPRESC")
66                 .WithReservedBits(8, 24);
67 
68             Register.Command.Define(this)
69                 .WithEnumField<DoubleWordRegister, Command>(0, 2, FieldMode.Write, writeCallback: (_, value) =>
70                 {
71                     switch(value)
72                     {
73                         case Command.None:
74                             break;
75                         case Command.Start:
76                             innerTimer.Enabled = true;
77                             break;
78                         case Command.Stop:
79                             innerTimer.Enabled = false;
80                             break;
81                         default:
82                             this.Log(LogLevel.Warning, "Unsupported command combination: {0}", value);
83                             break;
84                     }
85                 }, name: "START/STOP")
86                 .WithReservedBits(2, 30);
87 
88             Register.Status.Define(this)
89                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => innerTimer.Enabled, name: "RUNNING")
90                 .WithTaggedFlag("LOCK", 1)
91                 .WithReservedBits(2, 30);
92 
93             RegistersCollection.AddRegister((long)Register.InterruptFlags, interruptManager.GetRegister<DoubleWordRegister>(
94                 valueProviderCallback: (irq, _) => interruptManager.IsSet(irq),
95                 writeCallback: (irq, _, newValue) => interruptManager.SetInterrupt(irq, newValue)));
96 
97             RegistersCollection.AddRegister((long)Register.InterruptEnable, interruptManager.GetInterruptEnableRegister<DoubleWordRegister>());
98 
99             Register.CounterValue.Define(this)
100                 .WithValueField(0, 32,
101                     writeCallback: (_, value) => innerTimer.Value = value,
102                     valueProviderCallback: _ => innerTimer.Value,
103                     name: "CNT");
104 
105             Register.SynchronizationBusy.Define(this)
106                 .WithTaggedFlag("START", 0)
107                 .WithTaggedFlag("STOP", 1)
108                 .WithTaggedFlag("PRECNT", 2)
109                 .WithTaggedFlag("CNT", 3)
110                 .WithTaggedFlag("COMP", 4)
111                 .WithTaggedFlag("EN", 5)
112                 .WithReservedBits(6, 26);
113 
114             Register.ConfigurationLock.Define(this)
115                 .WithTag("LOCK", 0, 15)
116                 .WithReservedBits(15, 17);
117 
118             Register.CompareValue.Define(this)
119                 .WithValueField(0, 32,
120                     writeCallback: (_, value) => innerTimer.Compare = value,
121                     valueProviderCallback: _ => (uint)innerTimer.Compare,
122                     name: "COMP");
123 
124             RegistersCollection.AddRegister((long)Register.InterruptEnableSet, interruptManager.GetInterruptEnableSetRegister<DoubleWordRegister>());
125 
126             RegistersCollection.AddRegister((long)Register.InterruptFlagsClear, interruptManager.GetInterruptClearRegister<DoubleWordRegister>());
127         }
128 
129         private readonly InterruptManager<Interrupt> interruptManager;
130         private readonly ComparingTimer innerTimer;
131 
132         private enum Interrupt
133         {
134             Overflow,
135             CompareMatch,
136         }
137 
138         private enum Command
139         {
140             None = 0b00,
141             Start = 0b01,
142             Stop = 0b10,
143         }
144 
145         private enum Register
146         {
147             IpVersion = 0x0,
148             ModuleEnable = 0x4,
149             Configuration = 0x8,
150             Command = 0xC,
151             Status = 0x10,
152             InterruptFlags = 0x14,
153             InterruptEnable = 0x18,
154             PreCounterValue = 0x1C,
155             CounterValue = 0x20,
156             EM4WakeupRequest = 0x24,
157             SynchronizationBusy = 0x28,
158             ConfigurationLock = 0x2C,
159             CompareValue = 0x30,
160 
161             IpVersionSet = 0x1000,
162             ModuleEnableSet = 0x1004,
163             ConfigurationSet = 0x1008,
164             CommandSet = 0x100C,
165             StatusSet = 0x1010,
166             InterruptFlagsSet = 0x1014,
167             InterruptEnableSet = 0x1018,
168             PreCounterValueSet = 0x101C,
169             CounterValueSet = 0x1020,
170             EM4WakeupRequestSet = 0x1024,
171             SynchronizationBusySet = 0x1028,
172             ConfigurationLockSet = 0x102C,
173             CompareValueSet = 0x1030,
174 
175             IpVersionClear = 0x2000,
176             ModuleEnableClear = 0x2004,
177             ConfigurationClear = 0x2008,
178             CommandClear = 0x200C,
179             StatusClear = 0x2010,
180             InterruptFlagsClear = 0x2014,
181             InterruptEnableClear = 0x2018,
182             PreCounterValueClear = 0x201C,
183             CounterValueClear = 0x2020,
184             EM4WakeupRequestClear = 0x2024,
185             SynchronizationBusyClear = 0x2028,
186             ConfigurationLockClear = 0x202C,
187             CompareValueClear = 0x2030,
188 
189             IpVersionToggle = 0x3000,
190             ModuleEnableToggle = 0x3004,
191             ConfigurationToggle = 0x3008,
192             CommandToggle = 0x300C,
193             StatusToggle = 0x3010,
194             InterruptFlagsToggle = 0x3014,
195             InterruptEnableToggle = 0x3018,
196             PreCounterValueToggle = 0x301C,
197             CounterValueToggle = 0x3020,
198             EM4WakeupRequestToggle = 0x3024,
199             SynchronizationBusyToggle = 0x3028,
200             ConfigurationLockToggle = 0x302C,
201             CompareValueToggle = 0x3030
202         }
203     }
204 }
205