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