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