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 System;
8 using System.Linq;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Time;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 
14 namespace Antmicro.Renode.Peripherals.Timers
15 {
16     public class Murax_Timer : BasicDoubleWordPeripheral, IKnownSize
17     {
Murax_Timer(IMachine machine, long frequency = 12000000)18         public Murax_Timer(IMachine machine, long frequency = 12000000) : base(machine)
19         {
20             DefineRegisters();
21             for(var i = 0; i < NumberOfTimers; i++)
22             {
23                 var j = i;
24                 innerTimers[j] = new LimitTimer(machine.ClockSource, frequency, this, ((Timer)j).ToString(), limit: ushort.MaxValue, eventEnabled: true, direction: Direction.Ascending, autoUpdate: true, workMode: WorkMode.OneShot);
25                 innerTimers[j].LimitReached += delegate
26                 {
27                     this.Log(LogLevel.Noisy, "{0}: limit reached", (Timer)j);
28                     interruptPending[j].Value = true;
29                     UpdateInterrupts();
30                 };
31             }
32         }
33 
Reset()34         public override void Reset()
35         {
36             base.Reset();
37             foreach(var timer in innerTimers)
38             {
39                 timer.Reset();
40             }
41             UpdateInterrupts();
42         }
43 
44         public long Size => 0x5C;
45 
46         public GPIO IRQ { get; } = new GPIO();
47 
DefineRegisters()48         private void DefineRegisters()
49         {
50             Registers.Prescaler.Define(this)
51                 .WithValueField(0, 32, out prescaler, name: "prescaler", writeCallback: (_, val) =>
52                     {
53                         for(var i = 0; i < NumberOfTimers; i++)
54                         {
55                             UpdatePrescaler(i);
56                         }
57                     })
58             ;
59 
60             Registers.InterruptStatus.Define(this)
61                 .WithFlag(0, out interruptPending[(int)Timer.TimerA], FieldMode.Read | FieldMode.WriteOneToClear, name: "timerA pending")
62                 .WithFlag(1, out interruptPending[(int)Timer.TimerB], FieldMode.Read | FieldMode.WriteOneToClear, name: "timerB pending")
63                 .WithWriteCallback((_, __) => UpdateInterrupts())
64             ;
65 
66             Registers.InterruptMask.Define(this)
67                 .WithFlag(0, out interruptEnable[(int)Timer.TimerA], name: "timerA interrupt enable")
68                 .WithFlag(1, out interruptEnable[(int)Timer.TimerB], name: "timerB interrupt enable")
69                 .WithWriteCallback((_, __) => UpdateInterrupts())
70             ;
71 
72             Registers.TimerAClearTicks.DefineMany(this, NumberOfTimers, stepInBytes: TimersRegistersOffset, setup: (reg, idx) =>
73             {
74                 reg.WithEnumField<DoubleWordRegister, EnableMode>(0, 2, out enableMode[idx], name: "timerEnable",
75                     writeCallback: (_, val) =>
76                     {
77                         UpdatePrescaler(idx);
78                         innerTimers[idx].Enabled = (val != EnableMode.Disabled);
79                     });
80                 reg.WithFlag(16, name: "periodic",
81                     writeCallback: (_, val) =>
82                     {
83                         innerTimers[idx].Mode = val ? WorkMode.Periodic : WorkMode.OneShot;
84                     });
85             });
86 
87             Registers.TimerALimit.DefineMany(this, NumberOfTimers, stepInBytes: TimersRegistersOffset, setup: (reg, idx) =>
88             {
89                 reg.WithValueField(0, 32,
90                     valueProviderCallback: _ => (uint)innerTimers[(int)Timer.TimerA].Limit,
91                     writeCallback: (_, value) =>
92                     {
93                         // the effective limit value is 1 higher than the value written to the register
94                         innerTimers[idx].Limit = value + 1;
95                     }
96                 );
97             });
98 
99             Registers.TimerAValue.DefineMany(this, NumberOfTimers, stepInBytes: TimersRegistersOffset, setup: (reg, idx) =>
100             {
101                 reg.WithValueField(0, 32,
102                     valueProviderCallback: _ => (uint)innerTimers[(int)Timer.TimerA].Value,
103                     writeCallback: (_, value) =>
104                     {
105                         // writing any value to this register clears the value
106                         innerTimers[idx].Value = 0;
107                     }
108                 );
109             });
110         }
111 
UpdateInterrupts()112         private void UpdateInterrupts()
113         {
114             var anyPending = interruptEnable.Select(x => x.Value)
115                 .Zip(interruptPending.Select(x => x.Value), (enabled, pending) => enabled && pending)
116                 .Any(x => x);
117 
118             this.Log(LogLevel.Noisy, "Setting IRQ to: {0}", anyPending);
119             IRQ.Set(anyPending);
120         }
121 
UpdatePrescaler(int timerIdx)122         private void UpdatePrescaler(int timerIdx)
123         {
124             // the effective prescaler's value is one higher than the value written to the register
125             innerTimers[timerIdx].Divider = (enableMode[timerIdx].Value == EnableMode.Prescaler) ? (int)(prescaler.Value + 1) : 1;
126         }
127 
128         private IValueRegisterField prescaler;
129         private IEnumRegisterField<EnableMode>[] enableMode = new IEnumRegisterField<EnableMode>[NumberOfTimers];
130 
131         private readonly IFlagRegisterField[] interruptEnable = new IFlagRegisterField[NumberOfTimers];
132         private readonly IFlagRegisterField[] interruptPending = new IFlagRegisterField[NumberOfTimers];
133         private readonly LimitTimer[] innerTimers = new LimitTimer[NumberOfTimers];
134 
135         private const int NumberOfTimers = 2;
136         private const int TimersRegistersOffset = 0x10;
137 
138         private enum Timer
139         {
140             TimerA,
141             TimerB
142         }
143 
144         // interpret this as two bits indicating if:
145         // * direct clock is enabled
146         // * clock routed through prescaler is enabled
147         //
148         // In case both are set, direct clock wins.
149         private enum EnableMode
150         {
151             Disabled,
152             NoPrescaler,
153             Prescaler,
154             BothPrescalerAndNoPrescaler
155         }
156 
157         private enum Registers
158         {
159             Prescaler = 0x0,
160             InterruptStatus = 0x10,
161             InterruptMask = 0x14,
162 
163             TimerAClearTicks = 0x40,
164             TimerALimit = 0x44,
165             TimerAValue = 0x48,
166 
167             TimerBClearTicks = 0x50,
168             TimerBLimit = 0x54,
169             TimerBValue = 0x58
170         }
171     }
172 }
173