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