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 System.Linq;
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Peripherals.Bus;
11 using Antmicro.Renode.Time;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class S32K3XX_SystemTimerModule : LimitTimer, IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
17     {
S32K3XX_SystemTimerModule(IMachine machine, uint clockFrequency)18         public S32K3XX_SystemTimerModule(IMachine machine, uint clockFrequency) : base(machine.ClockSource, clockFrequency, uint.MaxValue)
19         {
20             IRQ = new GPIO();
21 
22             RegistersCollection = new DoubleWordRegisterCollection(this);
23             DefineRegisters();
24 
25             channelTimer = new LimitTimer[ChannelCount];
26             for(var i = 0; i < ChannelCount; ++i)
27             {
28                 var j = i;
29                 channelTimer[i] = new LimitTimer(machine.ClockSource, clockFrequency, this, $"channel#{j}", workMode: WorkMode.OneShot);
30                 channelTimer[i].LimitReached += UpdateInterrupts;
31             }
32 
33             LimitReached += () =>
34             {
35                 for(var i = 0; i < ChannelCount; ++i)
36                 {
37                     channelTimer[i].Value = channelTimer[i].Limit;
38                     channelTimer[i].Enabled = channelTimer[i].EventEnabled;
39                 }
40             };
41         }
42 
ReadDoubleWord(long offset)43         public uint ReadDoubleWord(long offset)
44         {
45             return RegistersCollection.Read(offset);
46         }
47 
WriteDoubleWord(long offset, uint value)48         public void WriteDoubleWord(long offset, uint value)
49         {
50             RegistersCollection.Write(offset, value);
51         }
52 
Reset()53         public override void Reset()
54         {
55             base.Reset();
56             RegistersCollection.Reset();
57 
58             for(var i = 0; i < ChannelCount; ++i)
59             {
60                 channelTimer[i].Reset();
61             }
62         }
63 
64         public long Size => 0x4000;
65         public GPIO IRQ { get; }
66         public DoubleWordRegisterCollection RegistersCollection { get; }
67 
UpdateInterrupts()68         private void UpdateInterrupts()
69         {
70             var interrupt = channelTimer.Any(timer => timer.RawInterrupt);
71             IRQ.Set(interrupt);
72         }
73 
DefineRegisters()74         private void DefineRegisters()
75         {
76             Registers.Control.Define(this)
77                 .WithFlag(0, name: "TimerEnable",
78                     valueProviderCallback: _ => Enabled,
79                     writeCallback: (_, value) => Enabled = value)
80                 .WithTaggedFlag("Freeze", 1)
81                 .WithReservedBits(2, 6)
82                 .WithValueField(8, 8, name: "CounterPrescaler",
83                     valueProviderCallback: _ => (uint)(Divider - 1),
84                     writeCallback: (_, value) =>
85                     {
86                         Divider = (int)value + 1;
87                         for(var i = 0; i < ChannelCount; ++i)
88                         {
89                             channelTimer[i].Divider = Divider;
90                         }
91                     })
92                 .WithReservedBits(16, 16);
93             ;
94 
95             Registers.Count.Define(this)
96                 .WithValueField(0, 32, FieldMode.Read, name: "TimerCount",
97                     valueProviderCallback: _ => Value)
98             ;
99 
100             var channelSize = (uint)(Registers.ChannelControl1 - Registers.ChannelControl0);
101             Registers.ChannelControl0.DefineMany(this, ChannelCount, (register, index) =>
102             {
103                 register
104                     .WithFlag(0, name: "ChannelEnable",
105                         valueProviderCallback: _ => channelTimer[index].EventEnabled,
106                         changeCallback: (_, value) =>
107                         {
108                             channelTimer[index].EventEnabled = value;
109                             if(!value)
110                             {
111                                 return;
112                             }
113 
114                             if(channelTimer[index].Limit > Value)
115                             {
116                                 channelTimer[index].Value = Value;
117                                 channelTimer[index].Enabled = true;
118                             }
119                             else
120                             {
121                                 this.Log(LogLevel.Debug, "Channel#{0} has been enabled, but it will be started after counter underflows.");
122                             }
123                         })
124                     .WithReservedBits(1, 31)
125                 ;
126             }, stepInBytes: channelSize);
127 
128             Registers.ChannelInterrupt0.DefineMany(this, ChannelCount, (register, index) =>
129             {
130                 register
131                     .WithFlag(0, name: "ChannelInterruptFlag",
132                         valueProviderCallback: _ => channelTimer[index].RawInterrupt,
133                         writeCallback: (_, value) =>
134                         {
135                             if(value)
136                             {
137                                 channelTimer[index].ClearInterrupt();
138                                 UpdateInterrupts();
139                             }
140                         })
141                     .WithReservedBits(1, 31)
142                 ;
143             }, stepInBytes: channelSize);
144 
145             Registers.ChannelCompare0.DefineMany(this, ChannelCount, (register, index) =>
146             {
147                 register
148                     .WithValueField(0, 32, name: "ChannelCompare",
149                         valueProviderCallback: _ => channelTimer[index].Limit,
150                         writeCallback: (_, value) => channelTimer[index].Limit = value)
151                 ;
152             }, stepInBytes: channelSize);
153         }
154 
155         private const uint ChannelCount = 4;
156 
157         private readonly LimitTimer[] channelTimer;
158 
159         private enum Registers
160         {
161             Control = 0x0, // CR
162             Count = 0x4, // CNT
163             ChannelControl0 = 0x10, // CCR0
164             ChannelInterrupt0 = 0x14, // CIR0
165             ChannelCompare0 = 0x18, // CMP0
166             ChannelControl1 = 0x20, // CCR1
167             ChannelInterrupt1 = 0x24, // CIR1
168             ChannelCompare1 = 0x28, // CMP1
169             ChannelControl2 = 0x30, // CCR2
170             ChannelInterrupt2 = 0x34, // CIR2
171             ChannelCompare2 = 0x38, // CMP2
172             ChannelControl3 = 0x40, // CCR3
173             ChannelInterrupt3 = 0x44, // CIR3
174             ChannelCompare3 = 0x48 // CMP3
175         }
176     }
177 }
178