1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2021 Google LLC
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure.Registers;
10 using Antmicro.Renode.Peripherals.Bus;
11 
12 namespace Antmicro.Renode.Peripherals.Timers
13 {
14     // OpenTitan rv_timer has a configurable number of timers and harts/Harts, but this implementation is limited to 1 hart and 1 timer.
15     // It is compliant with the v1.11 RISC-V privilege specification.
16     // The counters are all 64-bit and each timer has a configurable prescaler and step.
17     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
18     public class OpenTitan_Timer : BasicDoubleWordPeripheral, IKnownSize, IRiscVTimeProvider
19     {
OpenTitan_Timer(IMachine machine, long frequency = 24000000)20         public OpenTitan_Timer(IMachine machine, long frequency = 24000000) : base(machine)
21         {
22             IRQ = new GPIO();
23             FatalAlert = new GPIO();
24             underlyingTimer = new ComparingTimer(machine.ClockSource, frequency, this, "timer", workMode: Time.WorkMode.Periodic, eventEnabled: true);
25 
26             underlyingTimer.CompareReached += UpdateInterrupts;
27 
28             DefineRegisters();
29         }
30 
Reset()31         public override void Reset()
32         {
33             base.Reset();
34             FatalAlert.Unset();
35 
36             underlyingTimer.Reset();
37             UpdateInterrupts();
38         }
39 
40         public long Size => 0x120;
41 
42         public ulong TimerValue => underlyingTimer.Value;
43 
44         public GPIO IRQ { get; }
45         public GPIO FatalAlert { get; }
46 
DefineRegisters()47         private void DefineRegisters()
48         {
49             Registers.AlertTest.Define(this, 0x0)
50                 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
51                 .WithReservedBits(1, 31);
52 
53             Registers.Control0.Define(this)
54                 .WithFlag(0, name: "CONTROL0", writeCallback: (_, val) =>
55                 {
56                     underlyingTimer.Enabled = val;
57                     UpdateInterrupts();
58                 })
59                 .WithReservedBits(1, 31)
60             ;
61 
62             Registers.CompareLowHart0.Define(this, 0xFFFFFFFF)
63                  .WithValueField(0, 32, name: "COMPARELOW",
64                     valueProviderCallback: _ => (uint)(underlyingTimer.Compare),
65                     writeCallback: (_, val) =>
66                     {
67                         underlyingTimer.Compare = (underlyingTimer.Compare & 0xFFFFFFFF00000000uL) | val;
68                         UpdateInterrupts();
69                     })
70             ;
71 
72             Registers.CompareHighHart0.Define(this, 0xFFFFFFFF)
73                  .WithValueField(0, 32, name: "COMPAREHI",
74                     valueProviderCallback: _ => (uint)(underlyingTimer.Compare >> 32),
75                     writeCallback: (_, val) =>
76                     {
77                         underlyingTimer.Compare = (underlyingTimer.Compare & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32);
78                         UpdateInterrupts();
79                     })
80             ;
81 
82             Registers.ConfigurationHart0.Define(this, 0x10000)
83                 .WithValueField(0, 12, out prescaler, name: "PRESCALE")
84                 .WithValueField(16, 8, out step, name: "STEP")
85                 .WithWriteCallback((_, __) => TimerUpdateConfiguration())
86                 .WithReservedBits(24, 8)
87             ;
88 
89             Registers.ValueLowHart0.Define(this)
90                 .WithValueField(0, 32, name: "VALUELOW",
91                     valueProviderCallback: _ => (uint)(underlyingTimer.Value),
92                     writeCallback: (_, val) =>
93                     {
94                         underlyingTimer.Value = (underlyingTimer.Value & 0xFFFFFFFF00000000uL) | val;
95                         UpdateInterrupts();
96                     })
97             ;
98 
99             Registers.ValueHighHart0.Define(this)
100                 .WithValueField(0, 32, name: "VALUEHI",
101                     valueProviderCallback: _ => (uint)(underlyingTimer.Value >> 32),
102                     writeCallback: (_, val) =>
103                     {
104                         underlyingTimer.Value = (underlyingTimer.Value & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32);
105                         UpdateInterrupts();
106                     })
107             ;
108 
109             Registers.InterruptEnableHart0.Define(this)
110                 .WithFlag(0, out interruptEnabled, name: "IE")
111                 .WithReservedBits(1, 31)
112                 .WithWriteCallback((_, __) => UpdateInterrupts())
113             ;
114 
115             Registers.InterruptStatusHart0.Define(this)
116                 .WithFlag(0, FieldMode.Read, name: "IS", valueProviderCallback: _ => IRQ.IsSet)
117                 .WithReservedBits(1, 31)
118                 .WithWriteCallback((_, __) => UpdateInterrupts())
119             ;
120 
121             Registers.InterruptTestHart0.Define(this)
122                 .WithFlag(0, FieldMode.Write, name: "T",
123                     writeCallback: (_, newValue) =>
124                     {
125                         if(newValue)
126                         {
127                             IRQ.Set(true);
128                         }
129                     }
130                 )
131             ;
132         }
133 
TimerUpdateConfiguration()134         private void TimerUpdateConfiguration()
135         {
136             var divider = (uint)(prescaler.Value + 1u);
137             underlyingTimer.Divider = (divider == 0) ? 1 : divider;
138             underlyingTimer.Step = (uint)step.Value;
139         }
140 
UpdateInterrupts()141         private void UpdateInterrupts()
142         {
143             IRQ.Set(
144                 underlyingTimer.Enabled
145                 && interruptEnabled.Value
146                 && (underlyingTimer.Value >= underlyingTimer.Compare));
147         }
148 
149         private IFlagRegisterField interruptEnabled;
150         private IValueRegisterField prescaler;
151         private IValueRegisterField step;
152 
153         private readonly ComparingTimer underlyingTimer;
154 
155         private enum Registers
156         {
157             AlertTest = 0x0,
158             Control0 = 0x4,
159             InterruptEnableHart0 = 0x100,
160             InterruptStatusHart0 = 0x104,
161             InterruptTestHart0 = 0x108,
162             ConfigurationHart0 = 0x10c,
163             ValueLowHart0 = 0x110,
164             ValueHighHart0 = 0x114,
165             CompareLowHart0 = 0x118,
166             CompareHighHart0 = 0x11c,
167         }
168     }
169 }
170