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 Antmicro.Renode.Core;
8 using Antmicro.Renode.Peripherals.CPU;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Time;
12 using System;
13 using System.Linq;
14 using System.Collections.Generic;
15 using System.Collections.ObjectModel;
16 
17 namespace Antmicro.Renode.Peripherals.Timers
18 {
19     public class AmbiqApollo4_Timer : BasicDoubleWordPeripheral, INumberedGPIOOutput, IKnownSize
20     {
AmbiqApollo4_Timer(IMachine machine)21         public AmbiqApollo4_Timer(IMachine machine) : base(machine)
22         {
23             var innerConnections = new Dictionary<int, IGPIO>();
24             internalTimers = new InternalTimer[TimersCount];
25             for(var i = 0; i < TimersCount; ++i)
26             {
27                 internalTimers[i] = new InternalTimer(this, machine.ClockSource, i);
28                 internalTimers[i].OnCompare += UpdateInterrupts;
29                 innerConnections[i] = new GPIO();
30             }
31 
32             padOutput = new IEnumRegisterField<PadOutput>[OutputConfigRegisters * OutputConfigFieldsPerRegister];
33             timerEnabled = new IFlagRegisterField[TimersCount];
34             functionSelect = new IEnumRegisterField<FunctionSelect>[TimersCount];
35             triggerMode = new IEnumRegisterField<TriggerMode>[TimersCount];
36             triggerSource = new IEnumRegisterField<TriggerSource>[TimersCount];
37 
38             Connections = new ReadOnlyDictionary<int, IGPIO>(innerConnections);
39 
40             DefineRegisters();
41             Reset();
42         }
43 
Reset()44         public override void Reset()
45         {
46             base.Reset();
47             for(var i = 0; i < TimersCount; ++i)
48             {
49                 internalTimers[i].Reset();
50                 Connections[i].Unset();
51             }
52         }
53 
54         public IReadOnlyDictionary<int, IGPIO> Connections { get; }
55 
56         public long Size => 0x800;
57 
GetFrequencyAndDivider(ClockSelect clockSelect, out uint divider)58         private long GetFrequencyAndDivider(ClockSelect clockSelect, out uint divider)
59         {
60             divider = 1;
61             var frequency = 1L;
62 
63             switch(clockSelect)
64             {
65                 case ClockSelect.HFRCDiv16:
66                     frequency = HFRCFrequency;
67                     divider = 16;
68                     break;
69                 case ClockSelect.HFRCDiv64:
70                     frequency = HFRCFrequency;
71                     divider = 64;
72                     break;
73                 case ClockSelect.HFRCDiv256:
74                     frequency = HFRCFrequency;
75                     divider = 256;
76                     break;
77                 case ClockSelect.HFRCDiv1024:
78                     frequency = HFRCFrequency;
79                     divider = 1024;
80                     break;
81                 case ClockSelect.HFRCDiv4K:
82                     frequency = HFRCFrequency;
83                     divider = 4096;
84                     break;
85                 case ClockSelect.LFRC:
86                     frequency = LFRCFrequency;
87                     break;
88                 case ClockSelect.LFRCDiv2:
89                     frequency = LFRCFrequency;
90                     divider = 2;
91                     break;
92                 case ClockSelect.LFRCDiv32:
93                     frequency = LFRCFrequency;
94                     divider = 32;
95                     break;
96                 case ClockSelect.LFRCDiv1K:
97                     frequency = LFRCFrequency;
98                     divider = 1024;
99                     break;
100                 case ClockSelect.XT:
101                     frequency = XTFrequency;
102                     break;
103                 case ClockSelect.XTDiv2:
104                     frequency = XTFrequency;
105                     divider = 2;
106                     break;
107                 case ClockSelect.XTDiv4:
108                     frequency = XTFrequency;
109                     divider = 4;
110                     break;
111                 case ClockSelect.XTDiv8:
112                     frequency = XTFrequency;
113                     divider = 8;
114                     break;
115                 case ClockSelect.XTDiv16:
116                     frequency = XTFrequency;
117                     divider = 16;
118                     break;
119                 case ClockSelect.XTDiv32:
120                     frequency = XTFrequency;
121                     divider = 32;
122                     break;
123                 case ClockSelect.XTDiv128:
124                     frequency = XTFrequency;
125                     divider = 128;
126                     break;
127                 case ClockSelect.RTC_100HZ:
128                     frequency = 100;
129                     break;
130                 default:
131                     this.Log(LogLevel.Warning, "{0} is not supported; set default frequency of 1Hz", clockSelect);
132                     break;
133             }
134             return frequency;
135         }
136 
UpdateTimerActiveStatus()137         private void UpdateTimerActiveStatus()
138         {
139             for(var i = 0 ; i < TimersCount; ++i)
140             {
141                 internalTimers[i].Enabled = timerEnabled[i].Value && globalTimerEnabled[i].Value;
142             }
143         }
144 
UpdateInterrupts()145         private void UpdateInterrupts()
146         {
147             for(var i = 0; i < TimersCount; ++i)
148             {
149                 var interrupt = false;
150                 interrupt |= internalTimers[i].Compare0Event && internalTimers[i].Compare0Interrupt;
151                 interrupt |= internalTimers[i].Compare1Event && internalTimers[i].Compare1Interrupt;
152 
153                 if(Connections[i].IsSet != interrupt)
154                 {
155                     this.NoisyLog("Changing Interrupt{0} from {1} to {2}", i, Connections[i].IsSet, interrupt);
156                 }
157 
158                 Connections[i].Set(interrupt);
159             }
160         }
161 
DefineRegisters()162         private void DefineRegisters()
163         {
164             Registers.Control.Define(this)
165                 .WithReservedBits(0, 31)
166                 .WithFlag(31, FieldMode.WriteOneToClear, name: "RESET",
167                     writeCallback: (_, value) => { if(value) Reset(); })
168             ;
169 
170             Registers.Status.Define(this)
171                 .WithValueField(0, 16, FieldMode.Read, name: "ACTIVE",
172                     valueProviderCallback: _ => (uint)internalTimers.Count(timer => timer.Enabled))
173                 .WithValueField(16, 5, FieldMode.Read, name: "NTIMERS",
174                     valueProviderCallback: _ => TimersCount)
175                 .WithReservedBits(21, 11)
176             ;
177 
178             Registers.GlobalEnable.Define(this, 0x7ff)
179                 .WithFlags(0, 16, out globalTimerEnabled, name: "ENB")
180                 .WithChangeCallback((_, __) => UpdateTimerActiveStatus())
181             ;
182 
183             {
184                 var interruptEnable = Registers.InterruptEnable.Define(this)
185                     .WithWriteCallback((_, __) => UpdateInterrupts());
186                 var interruptStatus = Registers.InterruptStatus.Define(this)
187                     .WithWriteCallback((_, __) => UpdateInterrupts());
188                 var interruptClear = Registers.InterruptClear.Define(this)
189                     .WithWriteCallback((_, __) => UpdateInterrupts());
190                 var interruptSet = Registers.InterruptSet.Define(this)
191                     .WithWriteCallback((_, __) => UpdateInterrupts());
192 
193                 for(var i = 0; i < TimersCount; ++i)
194                 {
195                     var index = i;
196 
197                     interruptEnable
198                         .WithFlag(2 * index, name: $"TMR{index}0INT",
199                             valueProviderCallback: _ => internalTimers[index].Compare0Interrupt,
200                             writeCallback: (_, value) => internalTimers[index].Compare0Interrupt = value)
201                         .WithFlag(2 * index + 1, name: $"TMR{index}1INT",
202                             valueProviderCallback: _ => internalTimers[index].Compare1Interrupt,
203                             writeCallback: (_, value) => internalTimers[index].Compare1Interrupt = value)
204                     ;
205 
206                     interruptStatus
207                         .WithFlag(2 * index, name: $"TMR{index}0INTSTAT",
208                             valueProviderCallback: _ => internalTimers[index].Compare0Event,
209                             writeCallback: (_, value) => internalTimers[index].Compare0Event = value)
210                         .WithFlag(2 * index + 1, name: $"TMR{index}1INTSTAT",
211                             valueProviderCallback: _ => internalTimers[index].Compare1Event,
212                             writeCallback: (_, value) => internalTimers[index].Compare1Event = value)
213                     ;
214 
215                     interruptClear
216                         .WithFlag(2 * index, name: $"TMR{index}0INTCLR",
217                             valueProviderCallback: _ => internalTimers[index].Compare0Event,
218                             writeCallback: (_, value) => { if(value) internalTimers[index].Compare0Event = false; })
219                         .WithFlag(2 * index + 1, name: $"TMR{index}1INTCLR",
220                             valueProviderCallback: _ => internalTimers[index].Compare1Event,
221                             writeCallback: (_, value) => { if(value) internalTimers[index].Compare1Event = false; })
222                     ;
223 
224                     interruptSet
225                         .WithFlag(2 * index, name: $"TMR{index}0INTSET",
226                             valueProviderCallback: _ => internalTimers[index].Compare0Event,
227                             writeCallback: (_, value) => { if(value) internalTimers[index].Compare0Event = true; })
228                         .WithFlag(2 * index + 1, name: $"TMR{index}1INTSET",
229                             valueProviderCallback: _ => internalTimers[index].Compare1Event,
230                             writeCallback: (_, value) => { if(value) internalTimers[index].Compare1Event = true; })
231                     ;
232                 }
233             }
234 
235             Registers.OutputConfig0.DefineMany(this, OutputConfigRegisters, (register, index) =>
236             {
237                 register
238                     .WithEnumField(0, 6, out padOutput[index * 4], name: $"OUTCFG{index * 4}")
239                     .WithReservedBits(6, 2)
240                     .WithEnumField(8, 6, out padOutput[index * 4 + 1], name: $"OUTCFG{index * 4 + 1}")
241                     .WithReservedBits(14, 2)
242                     .WithEnumField(16, 6, out padOutput[index * 4 + 2], name: $"OUTCFG{index * 4 + 2}")
243                     .WithReservedBits(22, 2)
244                     .WithEnumField(24, 6, out padOutput[index * 4 + 3], name: $"OUTCFG{index * 4 + 3}")
245                     .WithReservedBits(30, 2)
246                 ;
247             });
248 
249             Registers.Timer0Control.DefineMany(this, TimersCount, (register, index) =>
250             {
251                 register
252                     .WithFlag(0, out timerEnabled[index], name: $"TMR{index}EN",
253                         writeCallback: (_, value) =>
254                         {
255                             UpdateTimerActiveStatus();
256                         })
257                     .WithFlag(1, FieldMode.WriteOneToClear, name: $"TMR{index}CLR",
258                         writeCallback: (_, value) => { if(value) internalTimers[index].Reset(); })
259                     .WithTaggedFlag($"TMR{index}POL0", 2)
260                     .WithTaggedFlag($"TMR{index}POL1", 3)
261                     .WithEnumField(4, 4, out functionSelect[index], name: $"TMR{index}FN",
262                         writeCallback: (_, value) =>
263                         {
264                             switch(value)
265                             {
266                                 case FunctionSelect.Continous:
267                                     internalTimers[index].OneShot = false;
268                                     break;
269                                 case FunctionSelect.Upcount:
270                                     internalTimers[index].OneShot = true;
271                                     break;
272                                 default:
273                                     this.Log(LogLevel.Error, "Timer{0}: {1} function mode is not supported", index, value);
274                                     break;
275                             }
276                         })
277                     .WithEnumField<DoubleWordRegister, ClockSelect>(8, 8, name: $"TMR{index}CLK",
278                         changeCallback: (_, newValue) =>
279                         {
280                             var frequency = GetFrequencyAndDivider(newValue, out var divider);
281                             internalTimers[index].Frequency = frequency;
282                             internalTimers[index].Divider = divider;
283                         })
284                     .WithEnumField(16, 2, out triggerMode[index], name: $"TMR{index}TMODE")
285                     .WithReservedBits(18, 6)
286                     .WithTag($"TMR{index}LMT", 24, 8)
287                 ;
288             }, stepInBytes: TimerStructureSize);
289 
290             Registers.Timer0.DefineMany(this, TimersCount, (register, index) =>
291             {
292                 register
293                     .WithValueField(0, 32, name: $"TIMER{index}",
294                         valueProviderCallback: _ =>
295                         {
296                             if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
297                             {
298                                 cpu.SyncTime();
299                             }
300                             return (uint)internalTimers[index].Value;
301                         },
302                         writeCallback: (_, value) => internalTimers[index].Value = (ulong)value)
303                 ;
304             }, stepInBytes: TimerStructureSize);
305 
306             Registers.Timer0Compare0.DefineMany(this, TimersCount, (register, index) =>
307             {
308                 register
309                     .WithValueField(0, 32, name: $"TMR{index}CMP0",
310                         valueProviderCallback: _ => (uint)internalTimers[index].Compare0,
311                         writeCallback: (_, value) => internalTimers[index].Compare0 = (ulong)value)
312                 ;
313             }, stepInBytes: TimerStructureSize);
314 
315             Registers.Timer0Compare1.DefineMany(this, TimersCount, (register, index) =>
316             {
317                 register
318                     .WithValueField(0, 32, name: $"TMR{index}CMP1",
319                         valueProviderCallback: _ => (uint)internalTimers[index].Compare1,
320                         writeCallback: (_, value) => internalTimers[index].Compare1 = (ulong)value)
321                 ;
322             }, stepInBytes: TimerStructureSize);
323 
324             Registers.Timer0Mode.DefineMany(this, TimersCount, (register, index) =>
325             {
326                 register
327                     .WithReservedBits(0, 8)
328                     .WithEnumField(8, 8, out triggerSource[index], name: $"TMR{index}TRIGSEL")
329                     .WithReservedBits(16, 16)
330                 ;
331             }, stepInBytes: TimerStructureSize);
332         }
333 
334         private readonly InternalTimer[] internalTimers;
335 
336         private IFlagRegisterField[] timerEnabled;
337         private IFlagRegisterField[] globalTimerEnabled;
338 
339         private IEnumRegisterField<PadOutput>[] padOutput;
340 
341         private IEnumRegisterField<FunctionSelect>[] functionSelect;
342         private IEnumRegisterField<TriggerMode>[] triggerMode;
343         private IEnumRegisterField<TriggerSource>[] triggerSource;
344 
345         private const int TimerStructureSize = 0x20;
346         private const int TimersCount = 16;
347         private const long HFRCFrequency = 96000000;
348         private const long LFRCFrequency = 1000;
349         private const long XTFrequency = 32768;
350         private const int OutputConfigRegisters = 32;
351         private const int OutputConfigFieldsPerRegister = 4;
352 
353         private class InternalTimer
354         {
InternalTimer(IPeripheral parent, IClockSource clockSource, int index)355             public InternalTimer(IPeripheral parent, IClockSource clockSource, int index)
356             {
357                 compare0Timer = new ComparingTimer(clockSource, 1, parent, $"timer{index}cmp0", limit: 0xFFFFFFFF, compare: 0xFFFFFFFF, enabled: false);
358                 compare1Timer = new ComparingTimer(clockSource, 1, parent, $"timer{index}cmp1", limit: 0xFFFFFFFF, compare: 0xFFFFFFFF, enabled: false);
359 
360                 compare0Timer.CompareReached += () =>
361                 {
362                     Compare0Event = true;
363                     CompareReached();
364                 };
365                 compare1Timer.CompareReached += () =>
366                 {
367                     Compare1Event = true;
368                     CompareReached();
369                 };
370             }
371 
Reset()372             public void Reset()
373             {
374                 Enabled = false;
375                 Compare0Event = false;
376                 Compare1Event = false;
377             }
378 
379             public bool Enabled
380             {
381                 get => compare0Timer.Enabled;
382                 set
383                 {
384                     if(Enabled == value)
385                     {
386                         return;
387                     }
388 
389                     Value = 0;
390                     compare0Timer.Enabled = value;
391                     compare1Timer.Enabled = value;
392                 }
393             }
394 
395             public bool OneShot { get; set; }
396 
397             public ulong Value
398             {
399                 get => compare0Timer.Value;
400                 set
401                 {
402                     compare0Timer.Value = value;
403                     compare1Timer.Value = value;
404                 }
405             }
406 
407             public long Frequency
408             {
409                 get => compare0Timer.Frequency;
410                 set
411                 {
412                     compare0Timer.Frequency = value;
413                     compare1Timer.Frequency = value;
414                 }
415             }
416 
417             public uint Divider
418             {
419                 get => compare0Timer.Divider;
420                 set
421                 {
422                     compare0Timer.Divider = value;
423                     compare1Timer.Divider = value;
424                 }
425             }
426 
427             public ulong Compare0
428             {
429                 get => compare0Timer.Compare;
430                 set => compare0Timer.Compare = value;
431             }
432 
433             public ulong Compare1
434             {
435                 get => compare1Timer.Compare;
436                 set => compare1Timer.Compare = value;
437             }
438 
439             public bool Compare0Event { get; set; }
440             public bool Compare1Event { get; set; }
441 
442             public bool Compare0Interrupt
443             {
444                 get => compare0Timer.EventEnabled;
445                 set => compare0Timer.EventEnabled = value;
446             }
447 
448             public bool Compare1Interrupt
449             {
450                 get => compare1Timer.EventEnabled;
451                 set => compare1Timer.EventEnabled = value;
452             }
453 
454             public Action OnCompare;
455 
CompareReached()456             private void CompareReached()
457             {
458                 OnCompare?.Invoke();
459 
460                 if(OneShot)
461                 {
462                     Value = 0;
463                 }
464             }
465 
466             private readonly ComparingTimer compare0Timer;
467             private readonly ComparingTimer compare1Timer;
468         }
469 
470         private enum TriggerSource
471         {
472             Timer0Output0 = 0x00,  // Trigger source is TIMER 0 Output 0
473             Timer0Output1 = 0x01,  // Trigger source is TIMER 0 Output 1
474             Timer1Output0 = 0x02,  // Trigger source is TIMER 1 Output 0
475             Timer1Output1 = 0x03,  // Trigger source is TIMER 1 Output 1
476             Timer2Output0 = 0x04,  // Trigger source is TIMER 2 Output 0
477             Timer2Output1 = 0x05,  // Trigger source is TIMER 2 Output 1
478             Timer3Output0 = 0x06,  // Trigger source is TIMER 3 Output 0
479             Timer3Output1 = 0x07,  // Trigger source is TIMER 3 Output 1
480             Timer4Output0 = 0x08,  // Trigger source is TIMER 4 Output 0
481             Timer4Output1 = 0x09,  // Trigger source is TIMER 4 Output 1
482             Timer5Output0 = 0x0A,  // Trigger source is TIMER 5 Output 0
483             Timer5Output1 = 0x0B,  // Trigger source is TIMER 5 Output 1
484             Timer6Output0 = 0x0C,  // Trigger source is TIMER 6 Output 0
485             Timer6Output1 = 0x0D,  // Trigger source is TIMER 6 Output 1
486             Timer7Output0 = 0x0E,  // Trigger source is TIMER 7 Output 0
487             Timer7Output1 = 0x0F,  // Trigger source is TIMER 7 Output 1
488             Timer8Output0 = 0x10,  // Trigger source is TIMER 8 Output 0
489             Timer8Output1 = 0x11,  // Trigger source is TIMER 8 Output 1
490             Timer9Output0 = 0x12,  // Trigger source is TIMER 9 Output 0
491             Timer9Output1 = 0x13,  // Trigger source is TIMER 9 Output 1
492             Timer10Output0 = 0x14, // Trigger source is TIMER 10 Output 0
493             Timer10Output1 = 0x15, // Trigger source is TIMER 10 Output 1
494             Timer11Output0 = 0x16, // Trigger source is TIMER 11 Output 0
495             Timer11Output1 = 0x17, // Trigger source is TIMER 11 Output 1
496             Timer12Output0 = 0x18, // Trigger source is TIMER 12 Output 0
497             Timer12Output1 = 0x19, // Trigger source is TIMER 12 Output 1
498             Timer13Output0 = 0x1A, // Trigger source is TIMER 13 Output 0
499             Timer13Output1 = 0x1B, // Trigger source is TIMER 13 Output 1
500             Timer14Output0 = 0x1C, // Trigger source is TIMER 14 Output 0
501             Timer14Output1 = 0x1D, // Trigger source is TIMER 14 Output 1
502             Timer15Output0 = 0x1E, // Trigger source is TIMER 15 Output 0
503             Timer15Output1 = 0x1F, // Trigger source is TIMER 15 Output 1
504             STimerCompare0 = 0x30, // Trigger source is STIMER Compare 0
505             STimerCompare1 = 0x31, // Trigger source is STIMER Compare 1
506             STimerCompare2 = 0x32, // Trigger source is STIMER Compare 2
507             STimerCompare3 = 0x33, // Trigger source is STIMER Compare 3
508             STimerCompare4 = 0x34, // Trigger source is STIMER Compare 4
509             STimerCompare5 = 0x35, // Trigger source is STIMER Compare 5
510             STimerCompare6 = 0x36, // Trigger source is STIMER Compare 6
511             STimerCompare7 = 0x37, // Trigger source is STIMER Compare 7
512             STimerCapture0 = 0x38, // Trigger source is STIMER Capture 0
513             STimerCapture1 = 0x39, // Trigger source is STIMER Capture 1
514             STimerCapture2 = 0x3A, // Trigger source is STIMER Capture 2
515             STimerCapture3 = 0x3B, // Trigger source is STIMER Capture 3
516             STimerCapture4 = 0x3C, // Trigger source is STIMER Capture 4
517             STimerCapture5 = 0x3D, // Trigger source is STIMER Capture 5
518             STimerCapture6 = 0x3E, // Trigger source is STIMER Capture 6
519             STimerCapture7 = 0x3F, // Trigger source is STIMER Capture 7
520             GPIO0 = 0x80,          // Trigger source is GPIO #0
521             GPIO127 = 0xFF,        // Trigger source is GPIO #127
522         }
523 
524         private enum TriggerMode
525         {
526             Disable = 0x00,
527             RisingEdge = 0x01,
528             FallingEdge = 0x02,
529             EitherEdge = 0x03,
530         }
531 
532         private enum ClockSelect
533         {
534             HFRCDiv16 = 0x01,      // Clock source is HFRC / 16
535             HFRCDiv64 = 0x02,      // Clock source is HFRC / 64
536             HFRCDiv256 = 0x03,     // Clock source is HFRC / 256
537             HFRCDiv1024 = 0x04,    // Clock source is HFRC / 1024
538             HFRCDiv4K = 0x05,      // Clock source is HFRC / 4096
539             LFRC = 0x06,           // Clock source is LFRC
540             LFRCDiv2 = 0x07,       // Clock source is LFRC / 2
541             LFRCDiv32 = 0x08,      // Clock source is LFRC / 32
542             LFRCDiv1K = 0x09,      // Clock source is LFRC / 1024
543             XT = 0x0A,             // Clock source is the XT (uncalibrated).
544             XTDiv2 = 0x0B,         // Clock source is XT / 2
545             XTDiv4 = 0x0C,         // Clock source is XT / 4
546             XTDiv8 = 0x0D,         // Clock source is XT / 8
547             XTDiv16 = 0x0E,        // Clock source is XT / 16
548             XTDiv32 = 0x0F,        // Clock source is XT / 32
549             XTDiv128 = 0x10,       // Clock source is XT / 128
550             RTC_100HZ = 0x11,      // Clock source is 100 Hz from the current RTC oscillator.
551             BuckC = 0x1C,          // Clock source is Buck VDDC TON pulses.
552             BuckF = 0x1D,          // Clock source is Buck VDDF TON pulses.
553             BuckS = 0x1E,          // Clock source is Buck VDDS TON pulses.
554             BuckCLV = 0x1F,        // Clock source is Buck VDDC_LV TON pulses.
555             Timer0Output0 = 0x20,  // Clock source is TIMER 0 Output 0
556             Timer0Output1 = 0x21,  // Clock source is TIMER 0 Output 1
557             Timer1Output0 = 0x22,  // Clock source is TIMER 1 Output 0
558             Timer1Output1 = 0x23,  // Clock source is TIMER 1 Output 1
559             Timer2Output0 = 0x24,  // Clock source is TIMER 2 Output 0
560             Timer2Output1 = 0x25,  // Clock source is TIMER 2 Output 1
561             Timer3Output0 = 0x26,  // Clock source is TIMER 3 Output 0
562             Timer3Output1 = 0x27,  // Clock source is TIMER 3 Output 1
563             Timer4Output0 = 0x28,  // Clock source is TIMER 4 Output 0
564             Timer4Output1 = 0x29,  // Clock source is TIMER 4 Output 1
565             Timer5Output0 = 0x2A,  // Clock source is TIMER 5 Output 0
566             Timer5Output1 = 0x2B,  // Clock source is TIMER 5 Output 1
567             Timer6Output0 = 0x2C,  // Clock source is TIMER 6 Output 0
568             Timer6Output1 = 0x2D,  // Clock source is TIMER 6 Output 1
569             Timer7Output0 = 0x2E,  // Clock source is TIMER 7 Output 0
570             Timer7Output1 = 0x2F,  // Clock source is TIMER 7 Output 1
571             Timer8Output0 = 0x30,  // Clock source is TIMER 8 Output 0
572             Timer8Output1 = 0x31,  // Clock source is TIMER 8 Output 1
573             Timer9Output0 = 0x32,  // Clock source is TIMER 9 Output 0
574             Timer9Output1 = 0x33,  // Clock source is TIMER 9 Output 1
575             Timer10Output0 = 0x34, // Clock source is TIMER 10 Output 0
576             Timer10Output1 = 0x35, // Clock source is TIMER 10 Output 1
577             Timer11Output0 = 0x36, // Clock source is TIMER 11 Output 0
578             Timer11Output1 = 0x37, // Clock source is TIMER 11 Output 1
579             Timer12Output0 = 0x38, // Clock source is TIMER 12 Output 0
580             Timer12Output1 = 0x39, // Clock source is TIMER 12 Output 1
581             Timer13Output0 = 0x3A, // Clock source is TIMER 13 Output 0
582             Timer13Output1 = 0x3B, // Clock source is TIMER 13 Output 1
583             Timer14Output0 = 0x3C, // Clock source is TIMER 14 Output 0
584             Timer14Output1 = 0x3D, // Clock source is TIMER 14 Output 1
585             Timer15Output0 = 0x3E, // Clock source is TIMER 15 Output 0
586             Timer15Output1 = 0x3F, // Clock source is TIMER 15 Output 1
587             GPIO0 = 0x80,          // GPIO #0 is clock source
588             GPIO63 = 0xBF,         // GPIO #63 is clock source
589             GPIO95 = 0xDF,         // GPIO #95 is clock source
590             GPIO127 = 0xFF,        // GPIO #127 is clock source
591         }
592 
593         private enum FunctionSelect
594         {
595             Continous = 0x00,
596             Edge = 0x01,
597             Upcount = 0x02,
598             PWM = 0x04,
599             Downcount = 0x06,
600             SinglePattern = 0x0C,
601             RepeatPattern = 0x0D,
602             EventTimer = 0x0E,
603         }
604 
605         private enum PadOutput
606         {
607             Timer0Output0 = 0x00,  // Output is Timer 0, output 0
608             Timer0Output1 = 0x01,  // Output is Timer 0, output 1
609             Timer1Output0 = 0x02,  // Output is Timer 1, output 0
610             Timer1Output1 = 0x03,  // Output is Timer 1, output 1
611             Timer2Output0 = 0x04,  // Output is Timer 2, output 0
612             Timer2Output1 = 0x05,  // Output is Timer 2, output 1
613             Timer3Output0 = 0x06,  // Output is Timer 3, output 0
614             Timer3Output1 = 0x07,  // Output is Timer 3, output 1
615             Timer4Output0 = 0x08,  // Output is Timer 4, output 0
616             Timer4Output1 = 0x09,  // Output is Timer 4, output 1
617             Timer5Output0 = 0x0A,  // Output is Timer 5, output 0
618             Timer5Output1 = 0x0B,  // Output is Timer 5, output 1
619             Timer6Output0 = 0x0C,  // Output is Timer 6, output 0
620             Timer6Output1 = 0x0D,  // Output is Timer 6, output 1
621             Timer7Output0 = 0x0E,  // Output is Timer 7, output 0
622             Timer7Output1 = 0x0F,  // Output is Timer 7, output 1
623             Timer8Output0 = 0x10,  // Output is Timer 8, output 0
624             Timer8Output1 = 0x11,  // Output is Timer 8, output 1
625             Timer9Output0 = 0x12,  // Output is Timer 9, output 0
626             Timer9Output1 = 0x13,  // Output is Timer 9, output 1
627             Timer10Output0 = 0x14, // Output is Timer 10, output 0
628             Timer10Output1 = 0x15, // Output is Timer 10, output 1
629             Timer11Output0 = 0x16, // Output is Timer 11, output 0
630             Timer11Output1 = 0x17, // Output is Timer 11, output 1
631             Timer12Output0 = 0x18, // Output is Timer 12, output 0
632             Timer12Output1 = 0x19, // Output is Timer 12, output 1
633             Timer13Output0 = 0x1A, // Output is Timer 13, output 0
634             Timer13Output1 = 0x1B, // Output is Timer 13, output 1
635             Timer14Output0 = 0x1C, // Output is Timer 14, output 0
636             Timer14Output1 = 0x1D, // Output is Timer 14, output 1
637             Timer15Output0 = 0x1E, // Output is Timer 15, output 0
638             Timer15Output1 = 0x1F, // Output is Timer 15, output 1
639             STimer0 = 0x20,        // Output is STimer 0
640             STimer1 = 0x21,        // Output is STimer 1
641             STimer2 = 0x22,        // Output is STimer 2
642             STimer3 = 0x23,        // Output is STimer 3
643             STimer4 = 0x24,        // Output is STimer 4
644             STimer5 = 0x25,        // Output is STimer 5
645             STimer6 = 0x26,        // Output is STimer 6
646             STimer7 = 0x27,        // Output is STimer 7
647             Pattern0 = 0x20,       // Output is Pattern Output 0
648             Pattern1 = 0x21,       // Output is Pattern Output 1
649             Pattern2 = 0x22,       // Output is Pattern Output 2
650             Pattern3 = 0x23,       // Output is Pattern Output 3
651             Pattern4 = 0x24,       // Output is Pattern Output 4
652             Pattern5 = 0x25,       // Output is Pattern Output 5
653             Pattern6 = 0x26,       // Output is Pattern Output 6
654             Pattern7 = 0x27,       // Output is Pattern Output 7
655             Disabled = 0x3F,       // Output is disabled
656         }
657 
658         private enum Registers : long
659         {
660             Control = 0x000,         // Counter/Timer Control
661             Status = 0x004,          // Counter/Timer Status
662             GlobalEnable = 0x010,    // Counter/Timer Global Enable
663             InterruptEnable = 0x060, // Counter/Timer Interrupts: Enable
664             InterruptStatus = 0x064, // Counter/Timer Interrupts: Status
665             InterruptClear = 0x068,  // Counter/Timer Interrupts: Clear
666             InterruptSet = 0x06C,    // Counter/Timer Interrupts: Set
667             OutputConfig0 = 0x080,   // Counter/Timer Output Config 0
668             OutputConfig1 = 0x084,   // Counter/Timer Output Config 0
669             OutputConfig2 = 0x088,   // Counter/Timer Output Config 0
670             OutputConfig3 = 0x08C,   // Counter/Timer Output Config 0
671             OutputConfig4 = 0x090,   // Counter/Timer Output Config 0
672             OutputConfig5 = 0x094,   // Counter/Timer Output Config 0
673             OutputConfig6 = 0x098,   // Counter/Timer Output Config 0
674             OutputConfig7 = 0x09C,   // Counter/Timer Output Config 0
675             OutputConfig8 = 0x0A0,   // Counter/Timer Output Config 0
676             OutputConfig9 = 0x0A4,   // Counter/Timer Output Config 0
677             OutputConfig10 = 0x0A8,  // Counter/Timer Output Config 0
678             OutputConfig11 = 0x0AC,  // Counter/Timer Output Config 0
679             OutputConfig12 = 0x0B0,  // Counter/Timer Output Config 0
680             OutputConfig13 = 0x0B4,  // Counter/Timer Output Config 0
681             OutputConfig14 = 0x0B8,  // Counter/Timer Output Config 0
682             OutputConfig15 = 0x0BC,  // Counter/Timer Output Config 0
683             OutputConfig16 = 0x0C0,  // Counter/Timer Output Config 0
684             OutputConfig17 = 0x0C4,  // Counter/Timer Output Config 0
685             OutputConfig18 = 0x0C8,  // Counter/Timer Output Config 0
686             OutputConfig19 = 0x0CC,  // Counter/Timer Output Config 0
687             OutputConfig20 = 0x0D0,  // Counter/Timer Output Config 0
688             OutputConfig21 = 0x0D4,  // Counter/Timer Output Config 0
689             OutputConfig22 = 0x0D8,  // Counter/Timer Output Config 0
690             OutputConfig23 = 0x0DC,  // Counter/Timer Output Config 0
691             OutputConfig24 = 0x0E0,  // Counter/Timer Output Config 0
692             OutputConfig25 = 0x0E4,  // Counter/Timer Output Config 0
693             OutputConfig26 = 0x0E8,  // Counter/Timer Output Config 0
694             OutputConfig27 = 0x0EC,  // Counter/Timer Output Config 0
695             OutputConfig28 = 0x0F0,  // Counter/Timer Output Config 0
696             OutputConfig29 = 0x0F4,  // Counter/Timer Output Config 0
697             OutputConfig30 = 0x0F8,  // Counter/Timer Output Config 0
698             OutputConfig31 = 0x0FC,  // Counter/Timer Output Config 0
699             PatternAddress = 0x104,  // Pattern Address
700             Timer0Control = 0x200,   // Counter/Timer Control
701             Timer0 = 0x204,          // Counter/Timer
702             Timer0Compare0 = 0x208,  // Counter/Timer 0 Primary Comparator
703             Timer0Compare1 = 0x20C,  // Counter/Timer 0 Secondary Compare
704             Timer0Mode = 0x210,      // Counter/Timer 0 Mode
705             Timer1Control = 0x220,   // Counter/Timer Control
706             Timer1 = 0x224,          // Counter/Timer
707             Timer1Compare0 = 0x228,  // Counter/Timer 1 Primary Comparator
708             Timer1Compare1 = 0x22C,  // Counter/Timer 1 Secondary Compare
709             Timer1Mode = 0x230,      // Counter/Timer 1 Mode
710             Timer2Control = 0x240,   // Counter/Timer Control
711             Timer2 = 0x244,          // Counter/Timer
712             Timer2Compare0 = 0x248,  // Counter/Timer 2 Primary Comparator
713             Timer2Compare1 = 0x24C,  // Counter/Timer 2 Secondary Compare
714             Timer2Mode = 0x250,      // Counter/Timer 2 Mode
715             Timer3Control = 0x260,   // Counter/Timer Control
716             Timer3 = 0x264,          // Counter/Timer
717             Timer3Compare0 = 0x268,  // Counter/Timer 3 Primary Comparator
718             Timer3Compare1 = 0x26C,  // Counter/Timer 3 Secondary Compare
719             Timer3Mode = 0x270,      // Counter/Timer 3 Mode
720             Timer4Control = 0x280,   // Counter/Timer Control
721             Timer4 = 0x284,          // Counter/Timer
722             Timer4Compare0 = 0x288,  // Counter/Timer 4 Primary Comparator
723             Timer4Compare1 = 0x28C,  // Counter/Timer 4 Secondary Compare
724             Timer4Mode = 0x290,      // Counter/Timer 4 Mode
725             Timer5Control = 0x2A0,   // Counter/Timer Control
726             Timer5 = 0x2A4,          // Counter/Timer
727             Timer5Compare0 = 0x2A8,  // Counter/Timer 5 Primary Comparator
728             Timer5Compare1 = 0x2AC,  // Counter/Timer 5 Secondary Compare
729             Timer5Mode = 0x2B0,      // Counter/Timer 5 Mode
730             Timer6Control = 0x2C0,   // Counter/Timer Control
731             Timer6 = 0x2C4,          // Counter/Timer
732             Timer6Compare0 = 0x2C8,  // Counter/Timer 6 Primary Comparator
733             Timer6Compare1 = 0x2CC,  // Counter/Timer 6 Secondary Compare
734             Timer6Mode = 0x2D0,      // Counter/Timer 6 Mode
735             Timer7Control = 0x2E0,   // Counter/Timer Control
736             Timer7 = 0x2E4,          // Counter/Timer
737             Timer7Compare0 = 0x2E8,  // Counter/Timer 7 Primary Comparator
738             Timer7Compare1 = 0x2EC,  // Counter/Timer 7 Secondary Compare
739             Timer7Mode = 0x2F0,      // Counter/Timer 7 Mode
740             Timer8Control = 0x300,   // Counter/Timer Control
741             Timer8 = 0x304,          // Counter/Timer
742             Timer8Compare0 = 0x308,  // Counter/Timer 8 Primary Comparator
743             Timer8Compare1 = 0x30C,  // Counter/Timer 8 Secondary Compare
744             Timer8Mode = 0x310,      // Counter/Timer 8 Mode
745             Timer9Control = 0x320,   // Counter/Timer Control
746             Timer9 = 0x324,          // Counter/Timer
747             Timer9Compare0 = 0x328,  // Counter/Timer 9 Primary Comparator
748             Timer9Compare1 = 0x32C,  // Counter/Timer 9 Secondary Compare
749             Timer9Mode = 0x330,      // Counter/Timer 9 Mode
750             Timer10Control = 0x340,  // Counter/Timer Control
751             Timer10 = 0x344,         // Counter/Timer
752             Timer10Compare0 = 0x348, // Counter/Timer 10 Primary Comparator
753             Timer10Compare1 = 0x34C, // Counter/Timer 10 Secondary Compare
754             Timer10Mode = 0x350,     // Counter/Timer 10 Mode
755             Timer11Control = 0x360,  // Counter/Timer Control
756             Timer11 = 0x364,         // Counter/Timer
757             Timer11Compare0 = 0x368, // Counter/Timer 11 Primary Comparator
758             Timer11Compare1 = 0x36C, // Counter/Timer 11 Secondary Compare
759             Timer11Mode = 0x370,     // Counter/Timer 11 Mode
760             Timer12Control = 0x380,  // Counter/Timer Control
761             Timer12 = 0x384,         // Counter/Timer
762             Timer12Compare0 = 0x388, // Counter/Timer 12 Primary Comparator
763             Timer12Compare1 = 0x38C, // Counter/Timer 12 Secondary Compare
764             Timer12Mode = 0x390,     // Counter/Timer 12 Mode
765             Timer13Control = 0x3A0,  // Counter/Timer Control
766             Timer13 = 0x3A4,         // Counter/Timer
767             Timer13Compare0 = 0x3A8, // Counter/Timer 13 Primary Comparator
768             Timer13Compare1 = 0x3AC, // Counter/Timer 13 Secondary Compare
769             Timer13Mode = 0x3B0,     // Counter/Timer 13 Mode
770             Timer14Control = 0x3C0,  // Counter/Timer Control
771             Timer14 = 0x3C4,         // Counter/Timer
772             Timer14Compare0 = 0x3C8, // Counter/Timer 14 Primary Comparator
773             Timer14Compare1 = 0x3CC, // Counter/Timer 14 Secondary Compare
774             Timer14Mode = 0x3D0,     // Counter/Timer 14 Mode
775             Timer15Control = 0x3E0,  // Counter/Timer Control
776             Timer15 = 0x3E4,         // Counter/Timer
777             Timer15Compare0 = 0x3E8, // Counter/Timer 15 Primary Comparator
778             Timer15Compare1 = 0x3EC, // Counter/Timer 15 Secondary Compare
779             Timer15Mode = 0x3F0,     // Counter/Timer 15 Mode
780         }
781     }
782 }
783