1 // 2 // Copyright (c) 2010-2018 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.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Time; 13 14 namespace Antmicro.Renode.Peripherals.Timers 15 { 16 public class MPFS_Timer : IDoubleWordPeripheral, IKnownSize 17 { MPFS_Timer(IMachine machine, long frequency = 100000000)18 public MPFS_Timer(IMachine machine, long frequency = 100000000) 19 { 20 Timer1IRQ = new GPIO(); 21 Timer2IRQ = new GPIO(); 22 23 timerInterruptEnable = new IFlagRegisterField[NumberOfInternalTimers]; 24 rawInterruptStatus = new IFlagRegisterField[NumberOfInternalTimers]; 25 backgroundLoadValue = new ulong[NumberOfInternalTimers]; 26 backgroundLoadValueIsValid = new bool[NumberOfInternalTimers]; 27 28 timer = new LimitTimer[NumberOfInternalTimers] 29 { 30 new LimitTimer(machine.ClockSource, frequency, this, "0", uint.MaxValue, autoUpdate: true, eventEnabled: true), 31 new LimitTimer(machine.ClockSource, frequency, this, "1", uint.MaxValue, autoUpdate: true, eventEnabled: true), 32 new LimitTimer(machine.ClockSource, frequency, this, "2", autoUpdate: true, eventEnabled: true) 33 }; 34 35 for (var i = 0; i < NumberOfInternalTimers; i++) 36 { 37 var j = i; 38 timer[i].LimitReached += delegate 39 { 40 rawInterruptStatus[j].Value = true; 41 lock(timer[j]) 42 { 43 if(backgroundLoadValueIsValid[j]) 44 { 45 backgroundLoadValueIsValid[j]= false; 46 timer[j].Limit = backgroundLoadValue[j]; 47 // TODO: doesn't it reduce the tick count by one (I mean shouldn't we put the new value AFTER this tick is finished?) 48 } 49 } 50 UpdateInterrupt(); 51 }; 52 } 53 54 var registersMap = new Dictionary<long, DoubleWordRegister> 55 { 56 // the rest of registers is generated using `GenerateRegistersForTimer` method calls located below 57 58 {(long)Registers.Timer64ValueHigh, new DoubleWordRegister(this) 59 .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEU", valueProviderCallback: _ => (uint)(timer[Timer.Timer64].Value >> 32)) 60 }, 61 62 {(long)Registers.Timer64ValueLow, new DoubleWordRegister(this) 63 .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEL", valueProviderCallback: _ => (uint)timer[Timer.Timer64].Value) 64 }, 65 66 {(long)Registers.Timer64LoadValueHigh, new DoubleWordRegister(this) 67 .WithValueField(0, 32, out var timer64LoadValueHigh, name: "TIM64LOADVALU") 68 }, 69 70 {(long)Registers.Timer64LoadValueLow, new DoubleWordRegister(this) 71 .WithValueField(0, 32, name: "TIM64LOADVALL", writeCallback: (_, valueLow) => timer[Timer.Timer64].Limit = (timer64LoadValueHigh.Value << 32) | valueLow) 72 }, 73 74 {(long)Registers.Timer64BackgroundLoadValueHigh, new DoubleWordRegister(this) 75 .WithValueField(0, 32, out var timer64BackgroundLoadValueHigh, name: "TIM64BGLOADVAU") 76 }, 77 78 {(long)Registers.Timer64BackgroundLoadValueLow, new DoubleWordRegister(this) 79 .WithValueField(0, 32, name: "TIM64BGLOADVAL", writeCallback: (_, val) => 80 { 81 lock(timer[Timer.Timer64]) 82 { 83 backgroundLoadValue[Timer.Timer64] = ((ulong)timer64BackgroundLoadValueHigh.Value << 32) | val; 84 backgroundLoadValueIsValid[Timer.Timer64] = true; 85 } 86 }) 87 }, 88 89 {(long)Registers.TimerMode, new DoubleWordRegister(this) 90 .WithEnumField<DoubleWordRegister, TimerMode>(0, 1, out timerMode, name: "TIM64MODE", writeCallback: (_, val) => InternalSoftReset(val))} 91 }; 92 93 GenerateRegistersForTimer("TIM1", Timer.Timer32_1, registersMap); 94 GenerateRegistersForTimer("TIM2", Timer.Timer32_2, registersMap, offset: Registers.Timer2Value - Registers.Timer1Value); 95 // 64-bit timer has different value/load_value/load_background_value registers that are defined directly when creating registersMap dictionary; the rest are common ones 96 GenerateRegistersForTimer("TIM64", Timer.Timer64, registersMap, offset: Registers.Timer64Control - Registers.Timer1Control, includeValueRegisters: false); 97 98 registers = new DoubleWordRegisterCollection(this, registersMap); 99 } 100 Reset()101 public void Reset() 102 { 103 registers.Reset(); 104 foreach(var eachTimer in timer) 105 { 106 eachTimer.Reset(); 107 } 108 UpdateInterrupt(); 109 } 110 ReadDoubleWord(long offset)111 public uint ReadDoubleWord(long offset) 112 { 113 return registers.Read(offset); 114 } 115 WriteDoubleWord(long offset, uint value)116 public void WriteDoubleWord(long offset, uint value) 117 { 118 registers.Write(offset, value); 119 } 120 121 public long Size => 0x1000; 122 123 public GPIO Timer1IRQ { get; private set; } 124 public GPIO Timer2IRQ { get; private set; } 125 InternalSoftReset(TimerMode mode)126 private void InternalSoftReset(TimerMode mode) 127 { 128 Reset(); 129 // reset will force `timerMode` value to 0, so we must set its value manually 130 timerMode.Value = mode; 131 } 132 UpdateInterrupt()133 private void UpdateInterrupt() 134 { 135 if(timerMode.Value == TimerMode.One64BitTimer) 136 { 137 Timer1IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer64)); 138 Timer2IRQ.Unset(); 139 } 140 else 141 { 142 Timer1IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer32_1)); 143 Timer2IRQ.Set(CalculateTimerMaskedInterruptValue(Timer.Timer32_2)); 144 } 145 } 146 CalculateTimerMaskedInterruptValue(int timerId)147 private bool CalculateTimerMaskedInterruptValue(int timerId) 148 { 149 return rawInterruptStatus[timerId].Value && timerInterruptEnable[timerId].Value; 150 } 151 GenerateRegistersForTimer(string name, int timerId, Dictionary<long, DoubleWordRegister> registersMap, long offset = 0, bool includeValueRegisters = true)152 private void GenerateRegistersForTimer(string name, int timerId, Dictionary<long, DoubleWordRegister> registersMap, long offset = 0, bool includeValueRegisters = true) 153 { 154 if(includeValueRegisters) 155 { 156 registersMap.Add((long)Registers.Timer1Value + offset, new DoubleWordRegister(this) 157 .WithValueField(0, 32, FieldMode.Read, name: $"{name}VALUE", valueProviderCallback: _ => (uint)timer[timerId].Value) 158 ); 159 160 registersMap.Add((long)Registers.Timer1LoadValue + offset, new DoubleWordRegister(this) 161 .WithValueField(0, 32, name: $"{name}LOADVAL", writeCallback: (_, val) => timer[timerId].Limit = val) 162 ); 163 164 registersMap.Add((long)Registers.Timer1BackgroundLoadValue + offset, new DoubleWordRegister(this) 165 .WithValueField(0, 32, name: $"{name}BGLOADVAL", writeCallback: (_, val) => 166 { 167 lock(timer[timerId]) 168 { 169 backgroundLoadValue[timerId] = val; 170 backgroundLoadValueIsValid[timerId] = true; 171 } 172 }) 173 ); 174 } 175 176 registersMap.Add((long)Registers.Timer1Control + offset, new DoubleWordRegister(this) 177 .WithFlag(0, name: $"{name}ENABLE", writeCallback: (_, val) => timer[timerId].Enabled = val) 178 .WithEnumField<DoubleWordRegister, OperatingMode>(1, 1, name: $"{name}MODE", writeCallback: (_, val) => timer[timerId].Mode = (val == OperatingMode.OneShot ? WorkMode.OneShot : WorkMode.Periodic)) 179 .WithFlag(2, out timerInterruptEnable[timerId], name: $"{name}INTEN", writeCallback: (_, __) => UpdateInterrupt()) 180 ); 181 182 registersMap.Add((long)Registers.Timer1RawInterruptStatus + offset, new DoubleWordRegister(this) 183 .WithFlag(0, out rawInterruptStatus[timerId], FieldMode.Read | FieldMode.WriteOneToClear, name: $"{name}RIS", writeCallback: (_, __) => UpdateInterrupt()) 184 ); 185 186 registersMap.Add((long)Registers.Timer1MaskedInterruptStatus + offset, new DoubleWordRegister(this) 187 .WithFlag(0, FieldMode.Read, name: $"{name}MIS", valueProviderCallback: _ => CalculateTimerMaskedInterruptValue(timerId)) 188 ); 189 } 190 191 192 private readonly DoubleWordRegisterCollection registers; 193 194 private readonly IEnumRegisterField<TimerMode> timerMode; 195 private readonly IFlagRegisterField[] timerInterruptEnable; 196 private readonly IFlagRegisterField[] rawInterruptStatus; 197 198 private readonly bool[] backgroundLoadValueIsValid; 199 private readonly ulong[] backgroundLoadValue; 200 private readonly LimitTimer[] timer; 201 202 private const int NumberOfInternalTimers = 3; 203 204 private static class Timer 205 { 206 public const int Timer32_1 = 0; 207 public const int Timer32_2 = 1; 208 public const int Timer64 = 2; 209 } 210 211 private enum TimerMode 212 { 213 Two32BitTimers = 0, 214 One64BitTimer = 1 215 } 216 217 private enum OperatingMode 218 { 219 Periodic = 0, 220 OneShot = 1 221 } 222 223 private enum Registers 224 { 225 Timer1Value = 0x0, 226 Timer1LoadValue = 0x4, 227 Timer1BackgroundLoadValue = 0x8, 228 Timer1Control = 0xC, 229 Timer1RawInterruptStatus = 0x10, 230 Timer1MaskedInterruptStatus = 0x14, 231 232 Timer2Value = 0x18, 233 Timer2LoadValue = 0x1C, 234 Timer2BackgroundLoadValue = 0x20, 235 Timer2Control = 0x24, 236 Timer2RawInterruptStatus = 0x28, 237 Timer2MaskedInterruptStatus = 0x2C, 238 239 Timer64ValueHigh = 0x30, 240 Timer64ValueLow = 0x34, 241 Timer64LoadValueHigh = 0x38, 242 Timer64LoadValueLow = 0x3C, 243 Timer64BackgroundLoadValueHigh = 0x40, 244 Timer64BackgroundLoadValueLow = 0x44, 245 Timer64Control = 0x48, 246 Timer64RawInterruptStatus = 0x4C, 247 Timer64MaskedInterruptStatus = 0x50, 248 TimerMode = 0x54 249 } 250 } 251 } 252