1 //
2 // Copyright (c) 2010-2023 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 with register layout to simulate 64 bit bus read/write access
16     // * width: 64 bits
17     // * csr data width: 8 bit
18     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
19     public class LiteX_Timer64 : BasicDoubleWordPeripheral, IKnownSize
20     {
LiteX_Timer64(IMachine machine, long frequency)21         public LiteX_Timer64(IMachine machine, long frequency) : base(machine)
22         {
23             innerTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(innerTimer), eventEnabled: true, autoUpdate: true);
24             innerTimer.LimitReached += delegate
25             {
26                 this.Log(LogLevel.Noisy, "Limit reached");
27                 irqPending.Value = true;
28                 UpdateInterrupts();
29 
30                 if(reloadValue == 0)
31                 {
32                     this.Log(LogLevel.Noisy, "No reload value - disabling the timer");
33                     innerTimer.Enabled = false;
34                 }
35                 innerTimer.Limit = reloadValue;
36             };
37             DefineRegisters();
38         }
39 
Reset()40         public override void Reset()
41         {
42             base.Reset();
43             innerTimer.Reset();
44             latchedValue = 0;
45             loadValue = 0;
46             reloadValue = 0;
47 
48             UpdateInterrupts();
49         }
50 
51         public GPIO IRQ { get; } = new GPIO();
52 
53         public long Size => 0x88;
54 
DefineRegisters()55         private void DefineRegisters()
56         {
57             // LOAD0 contains most significant 8 bits
58             // LOAD3 contains least significant 8 bits
59             Registers.Load0.DefineMany(this, SubregistersCount, (reg, idx) =>
60             {
61                 reg.WithValueField(0, 8, name: $"LOAD{idx}", writeCallback: (_, val) =>
62                 {
63                     BitHelper.ReplaceBits(ref loadValue, width: 8, source: (uint)val, destinationPosition: 24 - idx * 8);
64                 });
65             }, stepInBytes: 8);
66 
67             // RELOAD0 contains most significant 8 bits
68             // RELOAD3 contains least significant 8 bits
69             Registers.Reload0.DefineMany(this, SubregistersCount, (reg, idx) =>
70             {
71                 reg.WithValueField(0, 8, name: $"RELOAD{idx}", writeCallback: (_, val) =>
72                 {
73                     BitHelper.ReplaceBits(ref reloadValue, width: 8, source: (uint)val, destinationPosition: 24 - idx * 8);
74                 });
75             }, stepInBytes: 8);
76 
77             Registers.TimerEnable.Define32(this)
78                 .WithFlag(0, name: "ENABLE", writeCallback: (_, val) =>
79                 {
80                     if(innerTimer.Enabled == val)
81                     {
82                         return;
83                     }
84 
85                     if(val)
86                     {
87                         innerTimer.Limit = loadValue;
88                         this.Log(LogLevel.Noisy, "Enabling timer. Load value: 0x{0:X}, reload value: 0x{1:X}", loadValue, reloadValue);
89                     }
90 
91                     innerTimer.Enabled = val;
92                 })
93             ;
94 
95             Registers.TimerUpdateValue.Define32(this)
96                 .WithFlag(0, FieldMode.WriteOneToClear, name: "UPDATE_VALUE", writeCallback: (_, val) =>
97                 {
98                     if(val)
99                     {
100                         latchedValue = (uint)innerTimer.Value;
101                     }
102                 });
103             ;
104 
105             // VALUE0 contains most significant 8 bits
106             // VALUE3 contains least significant 8 bits
107             Registers.Value0.DefineMany(this, SubregistersCount, (reg, idx) =>
108             {
109                 reg.WithValueField(0, 8, FieldMode.Read, name: $"VALUE{idx}", valueProviderCallback: _ =>
110                 {
111                     return BitHelper.GetValue(latchedValue, 24 - idx * 8, 8);
112                 });
113             }, stepInBytes: 8);
114 
115             Registers.EventStatus.Define32(this)
116                 .WithFlag(0, FieldMode.Read, name: "EV_STATUS", valueProviderCallback: _ => innerTimer.Value == 0)
117             ;
118 
119             Registers.EventPending.Define32(this)
120                 .WithFlag(0, out irqPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "EV_PENDING", changeCallback: (_, __) => UpdateInterrupts())
121             ;
122 
123             Registers.EventEnable.Define32(this)
124                 .WithFlag(0, out irqEnabled, name: "EV_ENABLE", changeCallback: (_, __) => UpdateInterrupts())
125             ;
126         }
127 
UpdateInterrupts()128         private void UpdateInterrupts()
129         {
130             this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irqPending.Value && irqEnabled.Value);
131             IRQ.Set(irqPending.Value && irqEnabled.Value);
132         }
133 
134         private IFlagRegisterField irqEnabled;
135         private IFlagRegisterField irqPending;
136 
137         private uint latchedValue;
138         private uint loadValue;
139         private uint reloadValue;
140 
141         private readonly LimitTimer innerTimer;
142 
143         private const int SubregistersCount = 4;
144 
145         private enum Registers
146         {
147             /*
148             LoadX, ReloadX, and ValueX are all 64 bit, but only 8 bits from these per register are affected by read/write operations.
149             So the only change in their implementation from the 'generic' LiteX Timer is the increase of stepInBytes.
150             The value they all hold with the current LiteX implementation of the timer will still not exceed 32 bits.
151             */
152             Load0 = 0x0,
153             Load1 = 0x8,
154             Load2 = 0x10,
155             Load3 = 0x18,
156 
157             Reload0 = 0x20,
158             Reload1 = 0x28,
159             Reload2 = 0x30,
160             Reload3 = 0x38,
161 
162             TimerEnable = 0x40,
163             TimerUpdateValue = 0x48,
164 
165             Value0 = 0x50,
166             Value1 = 0x58,
167             Value2 = 0x60,
168             Value3 = 0x68,
169 
170             EventStatus = 0x70,
171             EventPending = 0x78,
172             EventEnable = 0x80
173         }
174     }
175 }
176