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;
8 
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities;
14 
15 namespace Antmicro.Renode.Peripherals.Timers
16 {
17     public class SAMD21_RTC : LimitTimer, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize
18     {
SAMD21_RTC(IMachine machine)19         public SAMD21_RTC(IMachine machine) : base(machine.ClockSource, 1, eventEnabled: true)
20         {
21             RegistersCollection = new ByteRegisterCollection(this);
22 
23             DefineRegisters();
24         }
25 
26         public ByteRegisterCollection RegistersCollection { get; }
27 
28         public GPIO IRQ { get; } = new GPIO();
29 
30         public long Size => 0x20;
31 
ReadByte(long offset)32         public byte ReadByte(long offset)
33         {
34             return RegistersCollection.Read(offset);
35         }
36 
WriteByte(long offset, byte value)37         public void WriteByte(long offset, byte value)
38         {
39             RegistersCollection.Write(offset, value);
40         }
41 
OnLimitReached()42         protected override void OnLimitReached()
43         {
44             base.OnLimitReached();
45 
46             var dateTime = new DateTime(
47                 (int)clock.year,
48                 (int)clock.month,
49                 (int)clock.day,
50                 (int)clock.hours,
51                 (int)clock.minutes,
52                 (int)clock.seconds
53             ).AddSeconds(1);
54 
55             clock.year = (uint)dateTime.Year;
56             clock.month = (uint)dateTime.Month;
57             clock.day = (uint)dateTime.Day;
58             clock.hours = (uint)dateTime.Hour;
59             clock.minutes = (uint)dateTime.Minute;
60             clock.seconds = (uint)dateTime.Second;
61 
62             if(clock.Equals(alarm))
63             {
64                 interruptAlarmPending.Value = true;
65                 UpdateInterrupts();
66             }
67         }
68 
UpdateInterrupts()69         private void UpdateInterrupts()
70         {
71             IRQ.Set(interruptAlarmEnabled && interruptAlarmPending.Value);
72             this.Log(LogLevel.Debug, "Changed IRQ to {0}", IRQ.IsSet);
73         }
74 
DefineRegisters()75         private void DefineRegisters()
76         {
77             Registers.Control0.Define(this)
78                 .WithTaggedFlag("SWRST", 0)
79                 .WithFlag(1, name: "ENABLE",
80                     valueProviderCallback: _ => Enabled,
81                     changeCallback: (_, value) => Enabled = value)
82                 .WithEnumField<ByteRegister, RTCMode>(2, 2, name: "MODE",
83                     valueProviderCallback: _ => RTCMode.RTC,
84                     changeCallback: (_, value) =>
85                     {
86                         if(value != RTCMode.RTC)
87                         {
88                             this.Log(LogLevel.Warning, "Tried to change mode to {0}, but only RTC mode is supported; ignoring", value);
89                             return;
90                         }
91                     })
92                 .WithReservedBits(4, 2)
93                 .WithTaggedFlag("CLKREP", 6)
94                 .WithTaggedFlag("MATCHCLR", 7)
95             ;
96 
97             Registers.Control1.Define(this)
98                 .WithTag("PRESCALER", 0, 4)
99                 .WithReservedBits(4, 4)
100             ;
101 
102             Registers.InterruptClear.Define(this)
103                 .WithFlag(0, name: "ALARM0",
104                     valueProviderCallback: _ => interruptAlarmEnabled,
105                     writeCallback: (_, value) => { if(value) interruptAlarmEnabled = false; })
106                 .WithReservedBits(1, 5)
107                 .WithTaggedFlag("SYNCRDY", 6)
108                 .WithTaggedFlag("OVF", 7)
109                 .WithChangeCallback((_, __) => UpdateInterrupts())
110             ;
111 
112             Registers.InterruptSet.Define(this)
113                 .WithFlag(0, name: "ALARM0",
114                     valueProviderCallback: _ => interruptAlarmEnabled,
115                     writeCallback: (_, value) => { if(value) interruptAlarmEnabled = true; })
116                 .WithReservedBits(1, 5)
117                 .WithTaggedFlag("SYNCRDY", 6)
118                 .WithTaggedFlag("OVF", 7)
119                 .WithChangeCallback((_, __) => UpdateInterrupts())
120             ;
121 
122             Registers.InterruptFlags.Define(this)
123                 .WithFlag(0, out interruptAlarmPending, FieldMode.WriteOneToClear | FieldMode.Read, name: "ALARM0")
124                 .WithReservedBits(1, 5)
125                 .WithTaggedFlag("SYNCRDY", 6)
126                 .WithTaggedFlag("OVF", 7)
127                 .WithChangeCallback((_, __) => UpdateInterrupts())
128             ;
129 
130             Registers.Clock0.Define(this)
131                 .WithValueField(0, 6, name: "SECONDS[5:0]",
132                     valueProviderCallback: _ => clock.seconds,
133                     writeCallback: (_, value) => clock.seconds = (uint)value)
134                 .WithValueField(6, 2, name: "MINUTES[1:0]",
135                     valueProviderCallback: _ => BitHelper.GetValue(clock.minutes, 0, 2),
136                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.minutes, (uint)value, 0, 2))
137             ;
138 
139             Registers.Clock1.Define(this)
140                 .WithValueField(0, 4, name: "MINUTES[5:2]",
141                     valueProviderCallback: _ => BitHelper.GetValue(clock.minutes, 2, 4),
142                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.minutes, (uint)value, 2, 4))
143                 .WithValueField(4, 4, name: "HOURS[3:0]",
144                     valueProviderCallback: _ => BitHelper.GetValue(clock.hours, 0, 2),
145                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.hours, (uint)value, 0, 4))
146             ;
147 
148             Registers.Clock2.Define(this)
149                 .WithValueField(0, 1, name: "HOURS[4]",
150                     valueProviderCallback: _ => BitHelper.GetValue(clock.hours, 4, 1),
151                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.hours, (uint)value, 4, 1))
152                 .WithValueField(1, 5, name: "DAY[4:0]",
153                     valueProviderCallback: _ => clock.day,
154                     writeCallback: (_, value) => clock.day = (uint)value)
155                 .WithValueField(6, 2, name: "MONTH[1:0]",
156                     valueProviderCallback: _ => BitHelper.GetValue(clock.month, 0, 2),
157                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.month, (uint)value, 0, 2))
158             ;
159 
160             Registers.Clock3.Define(this)
161                 .WithValueField(0, 2, name: "MONTH[3:2]",
162                     valueProviderCallback: _ => BitHelper.GetValue(clock.month, 2, 2),
163                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref clock.month, (uint)value, 2, 2))
164                 .WithValueField(2, 6, name: "YEAR[3:2]",
165                     valueProviderCallback: _ => clock.year,
166                     writeCallback: (_, value) => clock.year = (uint)value)
167             ;
168 
169             Registers.Alarm0.Define(this)
170                 .WithValueField(0, 6, name: "SECONDS[5:0]",
171                     valueProviderCallback: _ => alarm.seconds,
172                     writeCallback: (_, value) => alarm.seconds = (uint)value)
173                 .WithValueField(6, 2, name: "MINUTES[1:0]",
174                     valueProviderCallback: _ => BitHelper.GetValue(alarm.minutes, 0, 2),
175                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.minutes, (uint)value, 0, 2))
176             ;
177 
178             Registers.Alarm1.Define(this)
179                 .WithValueField(0, 4, name: "MINUTES[5:2]",
180                     valueProviderCallback: _ => BitHelper.GetValue(alarm.minutes, 2, 4),
181                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.minutes, (uint)value, 2, 4))
182                 .WithValueField(4, 4, name: "HOURS[3:0]",
183                     valueProviderCallback: _ => BitHelper.GetValue(alarm.hours, 0, 2),
184                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.hours, (uint)value, 0, 4))
185             ;
186 
187             Registers.Alarm2.Define(this)
188                 .WithValueField(0, 1, name: "HOURS[4]",
189                     valueProviderCallback: _ => BitHelper.GetValue(alarm.hours, 4, 1),
190                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.hours, (uint)value, 4, 1))
191                 .WithValueField(1, 5, name: "DAY[4:0]",
192                     valueProviderCallback: _ => alarm.day,
193                     writeCallback: (_, value) => alarm.day = (uint)value)
194                 .WithValueField(6, 2, name: "MONTH[1:0]",
195                     valueProviderCallback: _ => BitHelper.GetValue(alarm.month, 0, 2),
196                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.month, (uint)value, 0, 2))
197             ;
198 
199             Registers.Alarm3.Define(this)
200                 .WithValueField(0, 2, name: "MONTH[3:2]",
201                     valueProviderCallback: _ => BitHelper.GetValue(alarm.month, 2, 2),
202                     writeCallback: (_, value) => BitHelper.SetMaskedValue(ref alarm.month, (uint)value, 2, 2))
203                 .WithValueField(2, 6, name: "YEAR[3:2]",
204                     valueProviderCallback: _ => alarm.year,
205                     writeCallback: (_, value) => alarm.year = (uint)value)
206             ;
207         }
208 
209         private bool interruptAlarmEnabled;
210 
211         private IFlagRegisterField interruptAlarmPending;
212 
213         private Time clock = new Time();
214         private Time alarm = new Time();
215 
216         private struct Time
217         {
218             public uint seconds;
219             public uint minutes;
220             public uint hours;
221             public uint day;
222             public uint month;
223             public uint year;
224         }
225 
226         private enum RTCMode
227         {
228             Timer32,
229             Timer16,
230             RTC,
231         }
232 
233         private enum Registers
234         {
235             Control0 = 0x00,
236             Control1 = 0x01,
237             ReadRequest0 = 0x02,
238             ReadRequest1 = 0x03,
239             EventControl0 = 0x04,
240             EventControl1 = 0x05,
241             InterruptClear = 0x06,
242             InterruptSet = 0x07,
243             InterruptFlags = 0x08,
244 
245             Status = 0x0A,
246             DebugControl = 0xB,
247             FrequencyCorrection = 0x0C,
248 
249             Clock0 = 0x10,
250             Clock1 = 0x11,
251             Clock2 = 0x12,
252             Clock3 = 0x13,
253 
254             Alarm0 = 0x18,
255             Alarm1 = 0x19,
256             Alarm2 = 0x1A,
257             Alarm3 = 0x1B,
258 
259             Mask,
260         }
261     }
262 }
263