1 //
2 // Copyright (c) 2010-2019 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.Logging;
10 using Antmicro.Renode.Utilities;
11 
12 namespace Antmicro.Renode.Peripherals.Timers
13 {
14     public class LiteX_CPUTimer : BasicDoubleWordPeripheral, IKnownSize, IRiscVTimeProvider
15     {
LiteX_CPUTimer(IMachine machine, long frequency)16         public LiteX_CPUTimer(IMachine machine, long frequency) : base(machine)
17         {
18             IRQ = new GPIO();
19 
20             innerTimer = new ComparingTimer(machine.ClockSource, frequency, this, "cpu timer", enabled: true, eventEnabled: true);
21             innerTimer.CompareReached += () =>
22             {
23                 this.Log(LogLevel.Noisy, "Limit reached, setting IRQ");
24                 IRQ.Set(true);
25             };
26             DefineRegisters();
27         }
28 
29         public long Size => 0x100;
30 
31         public GPIO IRQ {get;}
32 
33         public ulong TimerValue => innerTimer.Value;
34 
Reset()35         public override void Reset()
36         {
37             base.Reset();
38 
39             innerTimer.Reset();
40             latchedValue = 0;
41             IRQ.Set(false);
42         }
43 
DefineRegisters()44         private void DefineRegisters()
45         {
46             Register.Latch.Define(this)
47                 .WithFlag(0, name: "latch_bit", writeCallback: (_, val) =>
48                 {
49                     if(!val)
50                     {
51                         return;
52                     }
53 
54                     latchedValue = innerTimer.Value;
55                 })
56             ;
57 
58             Register.Time.DefineMany(this, 8, stepInBytes: 4, setup: (reg, idx) =>
59             {
60                 // idx=0 - most significant byte
61                 // ...
62                 // idx=7 - least significant byte
63                 reg.WithValueField(0, 8, valueProviderCallback: (_) =>
64                 {
65                     return (uint)(latchedValue >> ((7 - idx) * 8) & 0xff);
66                 });
67             });
68 
69             Register.TimeCompare.DefineMany(this, 8, stepInBytes: 4, setup: (reg, idx) =>
70             {
71                 // idx=0 - most significant byte
72                 // ...
73                 // idx=7 - least significant byte
74 
75                 // this field should by 8-bits long, but it's defined as 32-bits (and the value is ANDed with 0xFF) to avoid unhandled bits warnings
76                 reg.WithValueField(0, 32, writeCallback: (_, val) =>
77                 {
78                     innerTimer.Compare = innerTimer.Compare.ReplaceBits((ulong)(val & 0xFF), 8, (7 - idx) * 8);
79                     this.Log(LogLevel.Noisy, "Compare value set to 0x{0:X}, dpos: {1}", innerTimer.Compare, (7 - idx) * 8);
80                     if(innerTimer.Value < innerTimer.Compare)
81                     {
82                         this.Log(LogLevel.Noisy, "Current timer value is 0x{0:X} - clearing IRQ", innerTimer.Value);
83                         IRQ.Set(false);
84                     }
85                 });
86             });
87         }
88 
89         private readonly ComparingTimer innerTimer;
90         private ulong latchedValue;
91 
92         private enum Register
93         {
94             Latch = 0x0,
95             Time = 0x4,
96             TimeCompare = 0x24,
97         }
98     }
99 }
100