1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2022-2025 Silicon Labs
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using System;
10 using System.Collections.Generic;
11 using System.IO;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Exceptions;
15 using Antmicro.Renode.Logging;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Peripherals.Timers;
18 using Antmicro.Renode.Time;
19 using Antmicro.Renode.Peripherals.CPU;
20 
21 namespace Antmicro.Renode.Peripherals.Miscellaneous.SiLabs
22 {
23     // Allows for the viewing of register contents when debugging
24     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
25     public class EFR32xG2_SYSRTC_1 : IDoubleWordPeripheral, IKnownSize
26     {
EFR32xG2_SYSRTC_1(Machine machine, uint frequency)27         public EFR32xG2_SYSRTC_1(Machine machine, uint frequency)
28         {
29             this.machine = machine;
30             this.timerFrequency = frequency;
31 
32             timer = new LimitTimer(machine.ClockSource, timerFrequency, this, "sysrtctimer", 0xFFFFFFFFUL, direction: Direction.Ascending,
33                                    enabled: false, workMode: WorkMode.OneShot, eventEnabled: true, autoUpdate: true);
34             timer.LimitReached += TimerLimitReached;
35 
36             IRQ = new GPIO();
37             registersCollection = BuildRegistersCollection();
38         }
39 
Reset()40         public void Reset()
41         {
42             timerIsRunning = false;
43             timer.Enabled = false;
44         }
45 
ReadDoubleWord(long offset)46         public uint ReadDoubleWord(long offset)
47         {
48             return ReadRegister(offset);
49         }
50 
ReadByte(long offset)51         public byte ReadByte(long offset)
52         {
53             int byteOffset = (int)(offset & 0x3);
54             uint registerValue = ReadRegister(offset, true);
55             byte result = (byte)((registerValue >> byteOffset*8) & 0xFF);
56             return result;
57         }
58 
ReadRegister(long offset, bool internal_read = false)59         private uint ReadRegister(long offset, bool internal_read = false)
60         {
61             var result = 0U;
62             long internal_offset = offset;
63 
64             // Set, Clear, Toggle registers should only be used for write operations. But just in case we convert here as well.
65             if (offset >= SetRegisterOffset && offset < ClearRegisterOffset)
66             {
67                 // Set register
68                 internal_offset = offset - SetRegisterOffset;
69                 if(!internal_read)
70                 {
71                     this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", (Registers)internal_offset, offset, internal_offset);
72                 }
73             } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset)
74             {
75                 // Clear register
76                 internal_offset = offset - ClearRegisterOffset;
77                 if(!internal_read)
78                 {
79                     this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", (Registers)internal_offset, offset, internal_offset);
80                 }
81             } else if (offset >= ToggleRegisterOffset)
82             {
83                 // Toggle register
84                 internal_offset = offset - ToggleRegisterOffset;
85                 if(!internal_read)
86                 {
87                     this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}", (Registers)internal_offset, offset, internal_offset);
88                 }
89             }
90 
91             if(!registersCollection.TryRead(internal_offset, out result))
92             {
93                 if(!internal_read)
94                 {
95                     this.Log(LogLevel.Noisy, "Unhandled read at offset 0x{0:X} ({1}).", internal_offset, (Registers)internal_offset);
96                 }
97             }
98             else
99             {
100                 if(!internal_read)
101                 {
102                     this.Log(LogLevel.Noisy, "Read at offset 0x{0:X} ({1}), returned 0x{2:X}.", internal_offset, (Registers)internal_offset, result);
103                 }
104             }
105 
106             return result;
107         }
108 
WriteDoubleWord(long offset, uint value)109         public void WriteDoubleWord(long offset, uint value)
110         {
111             WriteRegister(offset, value);
112         }
113 
WriteRegister(long offset, uint value, bool internal_write = false)114         private void WriteRegister(long offset, uint value, bool internal_write = false)
115         {
116             machine.ClockSource.ExecuteInLock(delegate {
117                 long internal_offset = offset;
118                 uint internal_value = value;
119 
120                 if (offset >= SetRegisterOffset && offset < ClearRegisterOffset)
121                 {
122                     // Set register
123                     internal_offset = offset - SetRegisterOffset;
124                     uint old_value = ReadRegister(internal_offset, true);
125                     internal_value = old_value | value;
126                     this.Log(LogLevel.Noisy, "SET Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, SET_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", (Registers)internal_offset, offset, internal_offset, value, old_value, internal_value);
127                 } else if (offset >= ClearRegisterOffset && offset < ToggleRegisterOffset)
128                 {
129                     // Clear register
130                     internal_offset = offset - ClearRegisterOffset;
131                     uint old_value = ReadRegister(internal_offset, true);
132                     internal_value = old_value & ~value;
133                     this.Log(LogLevel.Noisy, "CLEAR Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, CLEAR_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", (Registers)internal_offset, offset, internal_offset, value, old_value, internal_value);
134                 } else if (offset >= ToggleRegisterOffset)
135                 {
136                     // Toggle register
137                     internal_offset = offset - ToggleRegisterOffset;
138                     uint old_value = ReadRegister(internal_offset, true);
139                     internal_value = old_value ^ value;
140                     this.Log(LogLevel.Noisy, "TOGGLE Operation on {0}, offset=0x{1:X}, internal_offset=0x{2:X}, TOGGLE_value=0x{3:X}, old_value=0x{4:X}, new_value=0x{5:X}", (Registers)internal_offset, offset, internal_offset, value, old_value, internal_value);
141                 }
142 
143                 this.Log(LogLevel.Noisy, "Write at offset 0x{0:X} ({1}), value 0x{2:X}.", internal_offset, (Registers)internal_offset, internal_value);
144 
145                 if(!registersCollection.TryWrite(internal_offset, internal_value))
146                 {
147                     this.Log(LogLevel.Noisy, "Unhandled write at offset 0x{0:X} ({1}), value 0x{2:X}.", internal_offset, (Registers)internal_offset, internal_value);
148                     return;
149                 }
150             });
151         }
152 
BuildRegistersCollection()153         private DoubleWordRegisterCollection BuildRegistersCollection()
154         {
155             var registerDictionary = new Dictionary<long, DoubleWordRegister>
156             {
157                 {(long)Registers.Enable, new DoubleWordRegister(this)
158                     .WithFlag(0, out enable, name: "EN")
159                     .WithTaggedFlag("DISABLING", 1)
160                     .WithReservedBits(2, 30)
161                 },
162                 {(long)Registers.SoftwareReset, new DoubleWordRegister(this)
163                     .WithFlag(0, out swrst_swrst_bit, FieldMode.Write,
164                         writeCallback: (_, __) => Swrst_Swrst_Write(_, __),
165                         name: "Swrst")
166                     .WithFlag(1, out swrst_resetting_bit, FieldMode.Read,
167                             valueProviderCallback: (_) => {
168                                 return swrst_resetting_bit.Value;
169                             },
170                             name: "Resetting")
171                     .WithReservedBits(2, 30)
172                 },
173                 {(long)Registers.Config, new DoubleWordRegister(this)
174                     .WithEnumField<DoubleWordRegister, CFG_DEBUGRUN>(0, 1, out cfg_debugrun_bit,
175                     valueProviderCallback: (_) => {
176                         return cfg_debugrun_bit.Value;
177                     },
178                     writeCallback: (_, __) => {
179                         WriteWSTATIC();
180                     },
181                     name: "Debugrun")
182                     .WithReservedBits(1, 31)
183                 },
184                 {(long)Registers.Status, new DoubleWordRegister(this)
185                     .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => timerIsRunning, name: "RUNNING")
186                     .WithEnumField<DoubleWordRegister, STATUS_LOCKSTATUS>(1, 1, out status_lockstatus_bit, FieldMode.Read,
187                     valueProviderCallback: (_) => {
188                         return status_lockstatus_bit.Value;
189                     },
190                     name: "Lockstatus")
191                     .WithTaggedFlag("FAILDETLOCKSTATUS", 2)
192                     .WithReservedBits(3, 29)
193                 },
194                 {(long)Registers.Lock, new DoubleWordRegister(this)
195                     .WithValueField(0, 16, out lock_lockkey_field, FieldMode.Write,
196                         writeCallback: (_, __) => Lock_Lockkey_Write(_, __),
197                         name: "Lockkey")
198                     .WithReservedBits(16, 16)
199                 },
200                 {(long)Registers.Command, new DoubleWordRegister(this)
201                   .WithFlag(0, FieldMode.Write, writeCallback: (_, value) => { if (value) { StartCommand(); } }, name: "START")
202                   .WithFlag(1, FieldMode.Write, writeCallback: (_, value) => { if (value) { StopCommand(); } }, name: "STOP")
203                   .WithReservedBits(2, 30)
204                 },
205                 {(long)Registers.Counter, new DoubleWordRegister(this)
206                     .WithValueField(0, 32, valueProviderCallback: _ =>  TimerCounter, writeCallback: (_, value) => TimerCounter = (uint)value, name: "CNT")
207                 },
208                 {(long)Registers.Group0InterruptFlags, new DoubleWordRegister(this)
209                     .WithFlag(0, out overflowInterrupt, name: "OVFIF")
210                     .WithFlag(1, out compare0Interrupt, name: "COMP0IF")
211                     .WithFlag(2, out compare1Interrupt, name: "COMP1IF")
212                     .WithFlag(3, out capture0Interrupt, name: "CAP0IF")
213                     .WithReservedBits(4, 28)
214                     .WithChangeCallback((_, __) => UpdateInterrupts())
215                 },
216                 {(long)Registers.Group0InterruptEnable, new DoubleWordRegister(this)
217                     .WithFlag(0, out overflowInterruptEnable, name: "OVFIEN")
218                     .WithFlag(1, out compare0InterruptEnable, name: "COMP0IEN")
219                     .WithFlag(2, out compare1InterruptEnable, name: "COMP1IEN")
220                     .WithFlag(3, out capture0InterruptEnable, name: "CAP0IEN")
221                     .WithReservedBits(4, 28)
222                     .WithChangeCallback((_, __) => UpdateInterrupts())
223                 },
224                 {(long)Registers.Group0Control, new DoubleWordRegister(this)
225                     .WithFlag(0, out compare0Enable, name: "CMP0EN")
226                     .WithFlag(1, out compare1Enable, name: "CMP1EN")
227                     .WithFlag(2, out capture0Enable, name: "CAP0EN")
228                     .WithEnumField<DoubleWordRegister, CTRL_GROUP0_CMP0CMOA>(3, 3, out ctrl_group0_cmp0cmoa_field,
229                         valueProviderCallback: (_) => {
230                             return ctrl_group0_cmp0cmoa_field.Value;
231                         },
232                         name: "Cmp0cmoa")
233                     .WithEnumField<DoubleWordRegister, CTRL_GROUP0_CMP1CMOA>(6, 3, out ctrl_group0_cmp1cmoa_field,
234                         valueProviderCallback: (_) => {
235                             return ctrl_group0_cmp1cmoa_field.Value;
236                         },
237                         name: "Cmp1cmoa")
238                     .WithEnumField<DoubleWordRegister, CTRL_GROUP0_CAP0EDGE>(9, 2, out ctrl_group0_cap0edge_field,
239                         valueProviderCallback: (_) => {
240                             return ctrl_group0_cap0edge_field.Value;
241                         },
242                         name: "Cap0edge")
243                     .WithReservedBits(11, 21)
244                     .WithChangeCallback((_, __) => RestartTimer())
245                 },
246                 {(long)Registers.Group0Compare0, new DoubleWordRegister(this)
247                     .WithValueField(0, 32, out compare0Value, name: "CMP0VALUE")
248                     .WithChangeCallback((_, __) => RestartTimer())
249                 },
250                 {(long)Registers.Group0Compare1, new DoubleWordRegister(this)
251                     .WithValueField(0, 32, out compare1Value, name: "CMP1VALUE")
252                     .WithChangeCallback((_, __) => RestartTimer())
253                 },
254                 {(long)Registers.Group0Capture0, new DoubleWordRegister(this)
255                     .WithValueField(0, 32, out capture0Value, name: "CAP0VALUE")
256                     .WithChangeCallback((_, __) => RestartTimer())
257                 },
258             };
259             return new DoubleWordRegisterCollection(this, registerDictionary);
260         }
261 
262         public long Size => 0x4000;
263         public GPIO IRQ { get; }
264         private readonly Machine machine;
265         private readonly DoubleWordRegisterCollection registersCollection;
266         private LimitTimer timer;
267         private uint timerFrequency;
268         public bool timerIsRunning = false;
269         private const uint SetRegisterOffset = 0x1000;
270         private const uint ClearRegisterOffset = 0x2000;
271         private const uint ToggleRegisterOffset = 0x3000;
272         public event Action CompareMatchGroup0Channel0;
273         public event Action CompareMatchGroup0Channel1;
274         public bool Group0_Capture_Enabled
275         {
276             get
277             {
278                 return capture0Enable.Value;
279             }
280         }
281 
282 #region register fields
283         private IFlagRegisterField enable;
284         private IFlagRegisterField swrst_swrst_bit;
285         private IFlagRegisterField swrst_resetting_bit;
286         private IEnumRegisterField<CFG_DEBUGRUN> cfg_debugrun_bit;
287         private IValueRegisterField lock_lockkey_field;
288         private IEnumRegisterField<STATUS_LOCKSTATUS> status_lockstatus_bit;
289         private IFlagRegisterField compare0Enable;
290         private IEnumRegisterField<CTRL_GROUP0_CMP0CMOA> ctrl_group0_cmp0cmoa_field;
291         private IFlagRegisterField compare1Enable;
292         private IEnumRegisterField<CTRL_GROUP0_CMP1CMOA> ctrl_group0_cmp1cmoa_field;
293         private IFlagRegisterField capture0Enable;
294         protected IEnumRegisterField<CTRL_GROUP0_CAP0EDGE> ctrl_group0_cap0edge_field;
295         private IValueRegisterField compare0Value;
296         private IValueRegisterField compare1Value;
297         private IValueRegisterField capture0Value;
298         // Interrupts
299         private IFlagRegisterField overflowInterrupt;
300         private IFlagRegisterField compare0Interrupt;
301         private IFlagRegisterField compare1Interrupt;
302         private IFlagRegisterField capture0Interrupt;
303         private IFlagRegisterField overflowInterruptEnable;
304         private IFlagRegisterField compare0InterruptEnable;
305         private IFlagRegisterField compare1InterruptEnable;
306         private IFlagRegisterField capture0InterruptEnable;
307 #endregion
308 
309 #region methods
GetTime()310         private TimeInterval GetTime() => machine.LocalTimeSource.ElapsedVirtualTime;
311         public uint TimerCounter
312         {
313             get
314             {
315                 if (timerIsRunning)
316                 {
317                     if (timer.Enabled)
318                     {
319                         TrySyncTime();
320                         return (uint)timer.Value;
321                     }
322                     else
323                     {
324                         return (uint)timer.Limit;
325                     }
326                 }
327                 return 0;
328             }
329 
330             set
331             {
332                 timer.Value = value;
333                 RestartTimer();
334             }
335         }
336 
StartCommand()337         private void StartCommand()
338         {
339             timerIsRunning = true;
340             RestartTimer(true);
341         }
342 
StopCommand()343         private void StopCommand()
344         {
345             timerIsRunning = false;
346             timer.Enabled = false;
347         }
348 
TimerLimitReached()349         private void TimerLimitReached()
350         {
351             bool restartFromZero = false;
352 
353             if (timer.Limit == 0xFFFFFFFF)
354             {
355                 overflowInterrupt.Value = true;
356                 restartFromZero = true;
357             }
358             if (timer.Limit == compare0Value.Value + 1)
359             {
360                 compare0Interrupt.Value = true;
361                 //Invoke event (simulated hardware signal)
362                 CompareMatchGroup0Channel0?.Invoke();
363 
364             }
365             if (timer.Limit == compare1Value.Value + 1)
366             {
367                 compare1Interrupt.Value = true;
368                 // Invoke event (simulated hardware signal)
369                 CompareMatchGroup0Channel1?.Invoke();
370             }
371 
372             // RENODE-65: add support for capture functionality
373             UpdateInterrupts();
374             RestartTimer(restartFromZero);
375         }
376 
RestartTimer(bool restartFromZero = false)377         private void RestartTimer(bool restartFromZero = false)
378         {
379             if (!timerIsRunning)
380             {
381                 return;
382             }
383 
384             uint currentValue = restartFromZero ? 0 : TimerCounter;
385 
386             timer.Enabled = false;
387             uint limit = 0xFFFFFFFF;
388 
389             // Compare interrupt fires "on the next cycle", therefore we just set
390             // the timer to the +1 value and fire the interrupt right away when
391             // we hit the limit.
392 
393             if (compare0Enable.Value
394                 && currentValue < (compare0Value.Value + 1)
395                 && (compare0Value.Value + 1) < limit)
396             {
397                 limit = (uint)compare0Value.Value + 1;
398             }
399 
400             if (compare1Enable.Value
401                 && currentValue < (compare1Value.Value + 1)
402                 && (compare1Value.Value + 1) < limit)
403             {
404                 limit = (uint)compare1Value.Value + 1;
405             }
406 
407             // RENODE-65: add support for capture functionality
408 
409             timer.Limit = limit;
410             timer.Enabled = true;
411             timer.Value = currentValue;
412         }
413 
UpdateInterrupts()414         private void UpdateInterrupts()
415         {
416             machine.ClockSource.ExecuteInLock(delegate {
417                 var irq = ((overflowInterruptEnable.Value && overflowInterrupt.Value)
418                             || (compare0InterruptEnable.Value && compare0Interrupt.Value)
419                             || (compare1InterruptEnable.Value && compare1Interrupt.Value)
420                             || (capture0InterruptEnable.Value && capture0Interrupt.Value));
421                 IRQ.Set(irq);
422             });
423         }
424 
TrySyncTime()425         private bool TrySyncTime()
426         {
427             if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
428             {
429                 cpu.SyncTime();
430                 return true;
431             }
432             return false;
433         }
434 
WriteWSTATIC()435         private void WriteWSTATIC()
436         {
437             if(enable.Value)
438             {
439                 this.Log(LogLevel.Error, "Trying to write to a WSTATIC register while peripheral is enabled EN = {0}", enable);
440             }
441         }
442 
Swrst_Swrst_Write(bool a, bool b)443         protected void Swrst_Swrst_Write(bool a, bool b)
444         {
445             if (b == true)
446             {
447                 swrst_resetting_bit.Value = true;
448                 Reset();
449                 ResetRegisters();
450                 swrst_resetting_bit.Value = false;
451             }
452         }
453 
ResetRegisters()454         protected void ResetRegisters()
455         {
456             foreach (Registers reg in System.Enum.GetValues(typeof(Registers)))
457             {
458                 if (reg != (Registers)0x2008 && (uint)reg >= ClearRegisterOffset && (uint)reg < ToggleRegisterOffset)
459                 {
460                     WriteDoubleWord((long)reg, 0xFFFFFFFF);
461                 }
462                 Lock_Lockkey_Write(0, 0x4776);
463             }
464         }
465 
Lock_Lockkey_Write(ulong a, ulong b)466         protected void Lock_Lockkey_Write(ulong a, ulong b)
467         {
468             if (b == 0x4776)
469             {
470                 status_lockstatus_bit.Value = STATUS_LOCKSTATUS.UNLOCKED;
471             }
472             else
473             {
474                 status_lockstatus_bit.Value = STATUS_LOCKSTATUS.LOCKED;
475             }
476         }
477 
CaptureGroup0()478         public void CaptureGroup0()
479         {
480             this.Log(LogLevel.Debug, "Capturing SYSRTC Group 0");
481             WriteDoubleWord((long)Registers.Group0Capture0, TimerCounter);
482             capture0Interrupt.Value = true;
483         }
484 
485 #endregion
486 
487 #region enums
488         private enum Registers
489         {
490             IpVersion                 = 0x0000,
491             Enable                    = 0x0004,
492             SoftwareReset             = 0x0008,
493             Config                    = 0x000C,
494             Command                   = 0x0010,
495             Status                    = 0x0014,
496             Counter                   = 0x0018,
497             SyncBusy                  = 0x001C,
498             Lock                      = 0x0020,
499             FailureDetection          = 0x0030,
500             FailureDetectionLock      = 0x0034,
501             Group0InterruptFlags      = 0x0040,
502             Group0InterruptEnable     = 0x0044,
503             Group0Control             = 0x0048,
504             Group0Compare0            = 0x004C,
505             Group0Compare1            = 0x0050,
506             Group0Capture0            = 0x0054,
507             Group0SyncBusy            = 0x0058,
508             // Set registers
509             IpVersion_Set             = 0x1000,
510             Enable_Set                = 0x1004,
511             SoftwareReset_Set         = 0x1008,
512             Config_Set                = 0x100C,
513             Command_Set               = 0x1010,
514             Status_Set                = 0x1014,
515             Counter_Set               = 0x1018,
516             SyncBusy_Set              = 0x101C,
517             Lock_Set                  = 0x1020,
518             FailureDetection_Set      = 0x1030,
519             FailureDetectionLock_Set  = 0x1034,
520             Group0InterruptFlags_Set  = 0x1040,
521             Group0InterruptEnable_Set = 0x1044,
522             Group0Control_Set         = 0x1048,
523             Group0Compare0_Set        = 0x104C,
524             Group0Compare1_Set        = 0x1050,
525             Group0Capture0_Set        = 0x1054,
526             Group0SyncBusy_Set        = 0x1058,
527             // Clear registers
528             IpVersion_Clr             = 0x2000,
529             Enable_Clr                = 0x2004,
530             SoftwareReset_Clr         = 0x2008,
531             Config_Clr                = 0x200C,
532             Command_Clr               = 0x2010,
533             Status_Clr                = 0x2014,
534             Counter_Clr               = 0x2018,
535             SyncBusy_Clr              = 0x201C,
536             Lock_Clr                  = 0x2020,
537             FailureDetection_Clr      = 0x2030,
538             FailureDetectionLock_Clr  = 0x2034,
539             Group0InterruptFlags_Clr  = 0x2040,
540             Group0InterruptEnable_Clr = 0x2044,
541             Group0Control_Clr         = 0x2048,
542             Group0Compare0_Clr        = 0x204C,
543             Group0Compare1_Clr        = 0x2050,
544             Group0Capture0_Clr        = 0x2054,
545             Group0SyncBusy_Clr        = 0x2058,
546             // Toggle registers
547             IpVersion_Tgl             = 0x3000,
548             Enable_Tgl                = 0x3004,
549             SoftwareReset_Tgl         = 0x3008,
550             Config_Tgl                = 0x300C,
551             Command_Tgl               = 0x3010,
552             Status_Tgl                = 0x3014,
553             Counter_Tgl               = 0x3018,
554             SyncBusy_Tgl              = 0x301C,
555             Lock_Tgl                  = 0x3020,
556             FailureDetection_Tgl      = 0x3030,
557             FailureDetectionLock_Tgl  = 0x3034,
558             Group0InterruptFlags_Tgl  = 0x3040,
559             Group0InterruptEnable_Tgl = 0x3044,
560             Group0Control_Tgl         = 0x3048,
561             Group0Compare0_Tgl        = 0x304C,
562             Group0Compare1_Tgl        = 0x3050,
563             Group0Capture0_Tgl        = 0x3054,
564             Group0SyncBusy_Tgl        = 0x3058,
565         }
566         protected enum CFG_DEBUGRUN
567         {
568             DISABLE = 0, // SYSRTC is frozen in debug mode
569             ENABLE = 1, // SYSRTC is running in debug mode
570         }
571         protected enum STATUS_LOCKSTATUS
572         {
573             UNLOCKED = 0, // SYSRTC registers are unlocked
574             LOCKED = 1, // SYSRTC registers are locked
575         }
576         protected enum CTRL_GROUP0_CMP0CMOA
577         {
578             CLEAR = 0, // Cleared on the next cycle
579             SET = 1, // Set on the next cycle
580             PULSE = 2, // Set on the next cycle, cleared on the cycle after
581             TOGGLE = 3, // Inverted on the next cycle
582             CMPIF = 4, // Export this channel's CMP IF
583         }
584         protected enum CTRL_GROUP0_CMP1CMOA
585         {
586             CLEAR = 0, // Cleared on the next cycle
587             SET = 1, // Set on the next cycle
588             PULSE = 2, // Set on the next cycle, cleared on the cycle after
589             TOGGLE = 3, // Inverted on the next cycle
590             CMPIF = 4, // Export this channel's CMP IF
591         }
592         protected enum CTRL_GROUP0_CAP0EDGE
593         {
594             RISING = 0, // Rising edges detected
595             FALLING = 1, // Falling edges detected
596             BOTH = 2, // Both edges detected
597         }
598 #endregion
599     }
600 }