1 //
2 // Copyright (c) 2010-2022 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 using Antmicro.Renode.Time;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public sealed class TegraTimer : IDoubleWordPeripheral, IKnownSize
17     {
TegraTimer(IMachine machine)18         public TegraTimer(IMachine machine)
19         {
20             IRQ = new GPIO();
21             sync = new object();
22             clockSource = machine.ClockSource;
23             Reset();
24         }
25 
26         public GPIO IRQ { get; private set; }
27 
ReadDoubleWord(long offset)28         public uint ReadDoubleWord(long offset)
29         {
30             lock(sync)
31             {
32                 var clockEntry = clockSource.GetClockEntry(OnLimitReached);
33                 var value = (uint)clockEntry.Period;
34                 switch((Registers)offset)
35                 {
36                 case Registers.Ptv:
37                     if(clockEntry.Enabled)
38                     {
39                         value |= 0x80000000;
40                     }
41                     if(clockEntry.WorkMode == WorkMode.Periodic)
42                     {
43                         value |= 0x40000000;
44                     }
45                     this.NoisyLog("Read at Ptv, 0x{1:X}, 0x{2:X}, {0}%.", value * 100 / clockEntry.Period, value, clockEntry.Period);
46                     return value;
47                 case Registers.Pcr:
48                     this.NoisyLog("Read at Pcr, 0x{1:X}, 0x{2:X}, {0}%.", value * 100 / clockEntry.Period, value, clockEntry.Period);
49                     return (uint)clockEntry.Value;
50                 default:
51                     this.LogUnhandledRead(offset);
52                     return 0;
53                 }
54             }
55         }
56 
WriteDoubleWord(long offset, uint value)57         public void WriteDoubleWord(long offset, uint value)
58         {
59             lock(sync)
60             {
61                 switch((Registers)offset)
62                 {
63                 case Registers.Ptv:
64                     clockSource.ExchangeClockEntryWith(OnLimitReached, oldEntry => oldEntry.With(period: (value & ((1 << 29) - 1)) + 1,
65                         workMode: (0x40000000 & value) != 0 ? WorkMode.Periodic : WorkMode.OneShot,
66                         enabled: (0x80000000 & value) != 0));
67                     break;
68                 case Registers.Pcr:
69                     if((0x40000000 & value) != 0)
70                     {
71                         IRQ.Unset();
72                     }
73                     break;
74                 default:
75                     this.LogUnhandledWrite(offset, value);
76                     break;
77                 }
78             }
79         }
80 
81         public long Size
82         {
83             get
84             {
85                 return 8;
86             }
87         }
88 
OnLimitReached()89         private void OnLimitReached()
90         {
91             this.Log(LogLevel.Noisy, "Alarm on tmr, value 0x{0:X}", clockSource.GetClockEntry(OnLimitReached).Value);
92             IRQ.Set();
93         }
94 
Reset()95         public void Reset()
96         {
97             var clockEntry = new ClockEntry((1 << 29) - 1, 1000000, OnLimitReached, this, string.Empty, enabled: false) { Value = 0 };
98             clockSource.ExchangeClockEntryWith(OnLimitReached, x => clockEntry, () => clockEntry);
99         }
100 
101         private readonly IClockSource clockSource;
102 
103         private enum Registers
104         {
105             Ptv = 0x0,
106             Pcr = 0x4
107         }
108 
109         private readonly object sync;
110     }
111 }
112 
113