1 //
2 // Copyright (c) 2010-2021 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.Core.Structure.Registers;
9 using Antmicro.Renode.Utilities;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 
13 namespace Antmicro.Renode.Peripherals.Timers
14 {
15     // this is a model of LiteX timer in the default configuration:
16     // * width: 32 bits
17     // * csr data width: 32 bit
18     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
19     public class LiteX_Timer_CSR32 : BasicDoubleWordPeripheral, IKnownSize
20     {
LiteX_Timer_CSR32(IMachine machine, long frequency)21         public LiteX_Timer_CSR32(IMachine machine, long frequency) : base(machine)
22         {
23             uptimeTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(uptimeTimer), direction: Antmicro.Renode.Time.Direction.Ascending, enabled: true);
24             innerTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(innerTimer), eventEnabled: true, autoUpdate: true);
25             innerTimer.LimitReached += delegate
26             {
27                 this.Log(LogLevel.Noisy, "Limit reached");
28                 irqPending.Value = true;
29                 UpdateInterrupts();
30 
31                 if(reloadValue.Value == 0)
32                 {
33                     this.Log(LogLevel.Noisy, "No realod value - disabling the timer");
34                     innerTimer.Enabled = false;
35                 }
36                 innerTimer.Limit = reloadValue.Value;
37             };
38             DefineRegisters();
39         }
40 
Reset()41         public override void Reset()
42         {
43             base.Reset();
44             innerTimer.Reset();
45             uptimeTimer.Reset();
46 
47             latchedValue = 0;
48             uptimeLatchedValue = 0;
49 
50             UpdateInterrupts();
51         }
52 
53         public GPIO IRQ { get; } = new GPIO();
54 
55         public long Size => 0x2c;
56 
DefineRegisters()57         private void DefineRegisters()
58         {
59             Registers.Load.Define(this)
60                 .WithValueField(0, 32, out loadValue, name: "LOAD")
61             ;
62 
63             Registers.Reload.Define(this)
64                 .WithValueField(0, 32, out reloadValue, name: "RELOAD")
65             ;
66 
67             Registers.TimerEnable.Define32(this)
68                 .WithFlag(0, name: "ENABLE", writeCallback: (_, val) =>
69                 {
70                     if(innerTimer.Enabled == val)
71                     {
72                         return;
73                     }
74 
75                     if(val)
76                     {
77                         innerTimer.Limit = loadValue.Value;
78                         this.Log(LogLevel.Noisy, "Enabling timer. Load value: 0x{0:X}, reload value: 0x{1:X}", loadValue.Value, reloadValue.Value);
79                     }
80 
81                     innerTimer.Enabled = val;
82                 })
83             ;
84 
85             Registers.TimerUpdateValue.Define32(this)
86                 .WithFlag(0, FieldMode.WriteOneToClear, name: "UPDATE_VALUE", writeCallback: (_, val) =>
87                 {
88                     if(val)
89                     {
90                         if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
91                         {
92                             // being here means we are on the CPU thread
93                             cpu.SyncTime();
94                         }
95 
96                         latchedValue = (uint)innerTimer.Value;
97                     }
98                 });
99             ;
100 
101             Registers.Value.Define(this)
102                 .WithValueField(0, 32, FieldMode.Read, name: $"VALUE", valueProviderCallback: _ => latchedValue)
103             ;
104 
105             Registers.EventStatus.Define32(this)
106                 .WithFlag(0, FieldMode.Read, name: "EV_STATUS", valueProviderCallback: _ => innerTimer.Value == 0)
107             ;
108 
109             Registers.EventPending.Define32(this)
110                 .WithFlag(0, out irqPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "EV_PENDING", changeCallback: (_, __) => UpdateInterrupts())
111             ;
112 
113             Registers.EventEnable.Define32(this)
114                 .WithFlag(0, out irqEnabled, name: "EV_ENABLE", changeCallback: (_, __) => UpdateInterrupts())
115             ;
116 
117             Registers.UptimeLatch.Define32(this)
118                 .WithFlag(0, FieldMode.WriteOneToClear, name: "UPTIME_LATCH", writeCallback: (_, val) =>
119                 {
120                     if(val)
121                     {
122                         if(machine.SystemBus.TryGetCurrentCPU(out var cpu))
123                         {
124                             // being here means we are on the CPU thread
125                             cpu.SyncTime();
126                         }
127 
128                         uptimeLatchedValue = uptimeTimer.Value;
129                     }
130                 });
131 
132 
133              // UPTIME_CYCLES0 contains most significant 32 bits
134              // UPTIME_CYCLES1 contains least significant 32 bits
135              Registers.UptimeCycles0.DefineMany(this, 2, (reg, idx) =>
136              {
137                  reg.WithValueField(0, 32, FieldMode.Read, name: $"UPTIME_CYCLES{idx}", valueProviderCallback: _ =>
138                  {
139                      return (uint)BitHelper.GetValue(uptimeLatchedValue, 32 - idx * 32, 32);
140                  });
141              });
142         }
143 
UpdateInterrupts()144         private void UpdateInterrupts()
145         {
146             this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irqPending.Value && irqEnabled.Value);
147             IRQ.Set(irqPending.Value && irqEnabled.Value);
148         }
149 
150         private IFlagRegisterField irqEnabled;
151         private IFlagRegisterField irqPending;
152         private IValueRegisterField loadValue;
153         private IValueRegisterField reloadValue;
154 
155         private uint latchedValue;
156         private ulong uptimeLatchedValue;
157 
158         private readonly LimitTimer innerTimer;
159         private readonly LimitTimer uptimeTimer;
160 
161         private enum Registers
162         {
163             Load = 0x0,
164             Reload = 0x4,
165             TimerEnable = 0x08,
166             TimerUpdateValue = 0x0C,
167             Value = 0x10,
168             EventStatus = 0x14,
169             EventPending = 0x18,
170             EventEnable = 0x1C,
171 
172             UptimeLatch = 0x20,
173 
174             UptimeCycles0 = 0x24,
175             UptimeCycles1 = 0x28,
176         }
177     }
178 }
179