1 //
2 // Copyright (c) 2010-2022 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.Collections.Generic;
8 using Antmicro.Renode.Peripherals.Bus;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Time;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class IMX_GPTimer : BasicDoubleWordPeripheral, IKnownSize
17     {
IMX_GPTimer(IMachine machine, int frequency = DefaultFrequency)18         public IMX_GPTimer(IMachine machine, int frequency = DefaultFrequency) : base(machine)
19         {
20             timers = new ComparingTimer[NumberOfCaptures];
21             capturesPending = new IFlagRegisterField[NumberOfCaptures];
22             capturesEnabled = new IFlagRegisterField[NumberOfCaptures];
23             for(int i = 0; i < NumberOfCaptures; i++)
24             {
25                 var j = i;
26                 timers[j] = new ComparingTimer(machine.ClockSource, frequency, this, $"compare{j}", eventEnabled: true);
27                 timers[j].CompareReached += () =>
28                 {
29                     this.Log(LogLevel.Noisy, "Compare reached on Compare {0}. Compare Value {1}", j, timers[j].Compare);
30                     capturesPending[j].Value = true;
31                     UpdateInterrupts();
32                 };
33             }
34 
35             DefineRegisters();
36         }
37 
DefineRegisters()38         private void DefineRegisters()
39         {
40             Registers.Control.Define(this)
41                 .WithFlag(0, name: "EN", writeCallback: (_, value) =>
42                     {
43                         foreach(var timer in timers)
44                         {
45                            timer.Enabled = value;
46                         }
47                     }
48                 )
49                 .WithTag("ENMOD", 1, 1)
50                 .WithTag("DBGEN", 2, 1)
51                 .WithTag("WAITEN", 3, 1)
52                 .WithTag("DOZEEN", 4, 1)
53                 .WithTag("STOPEN", 5, 1)
54                 .WithTag("CLKSRC", 6, 3)
55                 .WithFlag(9, out freeRunModeEnabled, name: "FRR")
56                 .WithReservedBits(10, 5)
57                 .WithFlag(15, writeCallback: (_, value) =>
58                 {
59                     if(value)
60                     {
61                         Reset();
62                     }
63                 }, name: "SWR")
64                 .WithTag("IM1", 16, 2)
65                 .WithTag("IM2", 18, 2)
66                 .WithTag("OM1", 20, 3)
67                 .WithTag("OM2", 23, 3)
68                 .WithTag("OM3", 26, 3)
69                 .WithTaggedFlag("FO1", 29)
70                 .WithTaggedFlag("FO2", 30)
71                 .WithTaggedFlag("FO3", 31)
72             ;
73 
74             Registers.Prescaler.Define(this)
75                 .WithTag("PRESCALER", 0, 12)
76                 .WithReservedBits(12, 20)
77             ;
78 
79             Registers.Status.Define(this)
80                 .WithFlags(0, NumberOfCaptures, out capturesPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "OFn",
81                     writeCallback: (_,__,___) => UpdateInterrupts())
82                 .WithFlag(3, FieldMode.Read | FieldMode.WriteOneToClear, name: "IF1")
83                 .WithFlag(4, FieldMode.Read | FieldMode.WriteOneToClear, name: "IF2")
84                 .WithFlag(5, FieldMode.Read | FieldMode.WriteOneToClear, name: "ROV")
85                 .WithReservedBits(6, 26)
86             ;
87 
88             Registers.Interrupt.Define(this)
89                 .WithFlags(0, NumberOfCaptures, out capturesEnabled, name: "OFnIE",
90                     writeCallback: (_,__,___) => UpdateInterrupts())
91                 .WithTaggedFlag("IF1IE", 3)
92                 .WithTaggedFlag("IF2IE", 4)
93                 .WithTaggedFlag("ROVIE", 5)
94                 .WithReservedBits(6, 26)
95             ;
96 
97             Registers.OutputCompare1.DefineMany(this, NumberOfCaptures, setup: (register, idx) =>
98             {
99                 register
100                     .WithValueField(0, 32, name: $"COMP{idx+1}", writeCallback: (_, value) =>
101                         {
102                             timers[idx].Compare = value;
103                             // According to documentation, when timer is in Reset mode (FRR flag is set to 0),
104                             // then counter value should be set to 0 after every write operation on output capture register 1 (i.e., idx == 0 in this model).
105                             // We use separate timers for output channels, so it's necessary to reset all timers.
106                             if(idx == 0 && freeRunModeEnabled.Value == false)
107                             {
108                                 foreach(var timer in timers)
109                                 {
110                                     timer.Value = 0;
111                                 }
112                             }
113                         },
114                         valueProviderCallback: _ => (uint)timers[idx].Compare);
115             });
116 
117             Registers.InputCapture1.Define(this)
118                 .WithTag("CAPT", 0, 32)
119             ;
120 
121             Registers.InputCapture2.Define(this)
122                 .WithTag("CAPT", 0, 32)
123             ;
124 
125             Registers.Count.Define(this)
126                 .WithValueField(0, 32, FieldMode.Read,  name: "COUNT", valueProviderCallback: _ => (uint)timers[0].Value)
127             ;
128         }
129 
Reset()130         public override void Reset()
131         {
132             base.Reset();
133             UpdateInterrupts();
134         }
135 
136         public long Size => 0x1000;
137 
UpdateInterrupts()138         public void UpdateInterrupts()
139         {
140             var status = false;
141             for(int i = 0; i < NumberOfCaptures; i++)
142             {
143                 status |= capturesEnabled[i].Value && capturesPending[i].Value;
144             }
145             IRQ.Set(status);
146         }
147 
148         public GPIO IRQ { get; } = new GPIO();
149 
150         private IFlagRegisterField freeRunModeEnabled;
151         private IFlagRegisterField[] capturesEnabled;
152         private IFlagRegisterField[] capturesPending;
153         private readonly ComparingTimer[] timers;
154         private const int NumberOfCaptures = 3;
155         private const int DefaultFrequency = 32000;
156 
157         private enum Registers : long
158         {
159             Control = 0x00,
160             Prescaler = 0x04,
161             Status = 0x08,
162             Interrupt = 0x0c,
163             OutputCompare1 = 0x10,
164             OutputCompare2 = 0x14,
165             OutputCompare3 = 0x18,
166             InputCapture1 = 0x1c,
167             InputCapture2 = 0x20,
168             Count = 0x24,
169         }
170     }
171 }
172