1 //
2 // Copyright (c) 2010-2019 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.Logging;
10 using Antmicro.Renode.Time;
11 using Antmicro.Renode.Utilities;
12 using System;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class EFR32_Timer : BasicDoubleWordPeripheral, IKnownSize
17     {
EFR32_Timer(IMachine machine, long frequency, TimerWidth width)18         public EFR32_Timer(IMachine machine, long frequency, TimerWidth width) : base(machine)
19         {
20             IRQ = new GPIO();
21             this.width = width;
22             interruptManager = new InterruptManager<Interrupt>(this);
23 
24             innerTimer = new LimitTimer(machine.ClockSource, frequency, this, "timer", limit: (1UL << (int)width) - 1, direction: Direction.Ascending, eventEnabled: true, autoUpdate: true);
25             innerTimer.LimitReached += LimitReached;
26             DefineRegisters();
27         }
28 
Reset()29         public override void Reset()
30         {
31             base.Reset();
32             interruptManager.Reset();
33             innerTimer.Reset();
34         }
35 
36         public long Size => 0x400;
37 
38         [IrqProvider]
39         public GPIO IRQ { get; }
40 
DefineRegisters()41         private void DefineRegisters()
42         {
43             Registers.Control.Define(this)
44                 .WithEnumField(0, 2, changeCallback: (Mode _, Mode value) => SetMode(value), name: "MODE")
45                 .WithReservedBits(2, 1)
46                 .WithTaggedFlag("SYNC", 3)
47                 .WithFlag(4, changeCallback: (_, value) => innerTimer.Mode = value ? WorkMode.OneShot : WorkMode.Periodic, name: "OSMEN")
48                 .WithTaggedFlag("QDM", 5)
49                 .WithTaggedFlag("DEBUGRUN", 6)
50                 .WithTaggedFlag("DMACLRACT", 7)
51                 .WithTag("RISEA", 8, 2)
52                 .WithTag("FALLA", 10, 2)
53                 .WithReservedBits(12, 1)
54                 .WithTaggedFlag("X2CNT", 13)
55                 .WithTaggedFlag("DISSYNCOUT", 14)
56                 .WithReservedBits(15, 1)
57                 .WithTag("CLKSEL", 16, 2)
58                 .WithReservedBits(18, 6)
59                 .WithValueField(24, 4, changeCallback: (_, value) => {
60                     if(value <= 10)
61                     {
62                         innerTimer.Divider = 2 << (int)value;
63                     }
64                     else
65                     {
66                         this.Log(LogLevel.Warning, "Trying to set the prescaler to an invalid value: {0}, ignoring.", 1 << (int)value);
67                     }
68                 }, name: "PRESC")
69                 .WithTaggedFlag("ATI", 28)
70                 .WithTaggedFlag("RSSCOIST", 29)
71                 .WithReservedBits(30, 2)
72             ;
73 
74             Registers.Command.Define(this)
75                 .WithFlag(0, FieldMode.Set, changeCallback: (_, __) => innerTimer.Enabled = false)
76                 .WithFlag(1, FieldMode.Set, changeCallback: (_, __) => innerTimer.Enabled = true)
77             ;
78 
79             Registers.Status.Define(this)
80                 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => innerTimer.Enabled)
81                 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => innerTimer.Direction == Direction.Descending)
82                 .WithTaggedFlag("TOPBV", 2)
83                 .WithReservedBits(3, 5)
84                 .WithTaggedFlag("CCVBV0", 8)
85                 .WithTaggedFlag("CCVBV1", 9)
86                 .WithTaggedFlag("CCVBV2", 10)
87                 .WithTaggedFlag("CCVBV2", 11)
88                 .WithReservedBits(12, 4)
89                 .WithTaggedFlag("ICV0", 16)
90                 .WithTaggedFlag("ICV1", 17)
91                 .WithTaggedFlag("ICV2", 18)
92                 .WithTaggedFlag("ICV3", 19)
93                 .WithReservedBits(20, 4)
94                 .WithTaggedFlag("CCPOL0", 24)
95                 .WithTaggedFlag("CCPOL1", 25)
96                 .WithTaggedFlag("CCPOL2", 26)
97                 .WithTaggedFlag("CCPOL3", 27)
98                 .WithReservedBits(28, 4)
99             ;
100 
101             RegistersCollection.AddRegister((long)Registers.InterruptFlag, interruptManager.GetMaskedInterruptFlagRegister<DoubleWordRegister>());
102             RegistersCollection.AddRegister((long)Registers.InterruptFlagSet, interruptManager.GetInterruptSetRegister<DoubleWordRegister>());
103             RegistersCollection.AddRegister((long)Registers.InterruptFlagClear, interruptManager.GetInterruptClearRegister<DoubleWordRegister>());
104             RegistersCollection.AddRegister((long)Registers.InterruptEnable, interruptManager.GetInterruptEnableRegister<DoubleWordRegister>());
105 
106             Registers.CounterTopValue.Define(this)
107                 .WithValueField(0, (int)width, writeCallback: (_, value) => innerTimer.Limit = value, valueProviderCallback: _ => (uint)innerTimer.Limit, name: "TOP")
108             ;
109 
110             Registers.CounterValue.Define(this)
111                 .WithValueField(0, (int)width, writeCallback: (_, value) => innerTimer.Value = value, valueProviderCallback: _ => (uint)innerTimer.Value, name: "CNT")
112             ;
113 
114         }
115 
LimitReached()116         private void LimitReached()
117         {
118             if(innerTimer.Direction == Direction.Descending)
119             {
120                 interruptManager.SetInterrupt(Interrupt.Underflow);
121             }
122             else
123             {
124                 interruptManager.SetInterrupt(Interrupt.Overflow);
125             }
126         }
127 
SetMode(Mode value)128         private void SetMode(Mode value)
129         {
130             if(mode == Mode.QuadratureDecoder || mode == Mode.UpDown)
131             {
132                 this.Log(LogLevel.Warning, "Unsupported mode {0}", mode);
133                 return;
134             }
135             mode = value;
136             innerTimer.Direction = mode == Mode.Up ? Direction.Ascending : Direction.Descending;
137         }
138 
139         private LimitTimer innerTimer;
140         private Mode mode;
141         private TimerWidth width;
142         private InterruptManager<Interrupt> interruptManager;
143 
144         public enum TimerWidth
145         {
146             Bit16 = 16,
147             Bit32 = 32,
148         }
149 
150         private enum Mode
151         {
152             Up,
153             Down,
154             UpDown,
155             QuadratureDecoder,
156         }
157 
158         private enum Interrupt
159         {
160             Overflow,
161             Underflow,
162             DirectionChanged,
163             [NotSettable]
164             Reserved,
165             CompareCaptureChannel0,
166             CompareCaptureChannel1,
167             CompareCaptureChannel2,
168             CompareCaptureChannel3,
169             InputCaptureBufferOverflow0,
170             InputCaptureBufferOverflow1,
171             InputCaptureBufferOverflow2,
172             InputCaptureBufferOverflow3,
173         }
174 
175         private enum Registers
176         {
177             Control = 0x0,
178             Command = 0x4,
179             Status = 0x8,
180             InterruptFlag = 0xC,
181             InterruptFlagSet = 0x10,
182             InterruptFlagClear = 0x14,
183             InterruptEnable = 0x18,
184             CounterTopValue = 0x1C,
185             CounterTopValueBuffer = 0x20,
186             CounterValue = 0x24,
187             ConfigurationLock = 0x2C,
188             IORoutingPinEnable = 0x30,
189             IORoutingLocation0 = 0x34,
190             IORoutingLocation2 = 0x3C,
191             CCChannelControl0 = 0x60,
192             CCChannelValue0 = 0x64,
193             CCChannelValuePeek0 = 0x68,
194             CCChannelBuffer0 = 0x6C,
195             CCChannelControl1 = 0x70,
196             CCChannelValue1 = 0x74,
197             CCChannelValuePeek1 = 0x78,
198             CCChannelBuffer1 = 0x7C,
199             CCChannelControl2 = 0x80,
200             CCChannelValue2 = 0x84,
201             CCChannelValuePeek2 = 0x88,
202             CCChannelBuffer2 = 0x8C,
203             CCChannelControl3 = 0x90,
204             CCChannelValue3 = 0x94,
205             CCChannelValuePeek3 = 0x98,
206             CCChannelBuffer3 = 0x9C,
207             DTIControl = 0xA0,
208             DTITimeControl = 0xA4,
209             DTIFaultConfiguration = 0xA8,
210             DTIOutputGenerationEnable = 0xAC,
211             DTIFault = 0xB0,
212             DTIFaultClear = 0xB4,
213             DTIConfigurationLock = 0xB8,
214         }
215     }
216 }
217