1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // Copyright (c) 2021 Google LLC 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Peripherals.Bus; 11 12 namespace Antmicro.Renode.Peripherals.Timers 13 { 14 // OpenTitan rv_timer has a configurable number of timers and harts/Harts, but this implementation is limited to 1 hart and 1 timer. 15 // It is compliant with the v1.11 RISC-V privilege specification. 16 // The counters are all 64-bit and each timer has a configurable prescaler and step. 17 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)] 18 public class OpenTitan_Timer : BasicDoubleWordPeripheral, IKnownSize, IRiscVTimeProvider 19 { OpenTitan_Timer(IMachine machine, long frequency = 24000000)20 public OpenTitan_Timer(IMachine machine, long frequency = 24000000) : base(machine) 21 { 22 IRQ = new GPIO(); 23 FatalAlert = new GPIO(); 24 underlyingTimer = new ComparingTimer(machine.ClockSource, frequency, this, "timer", workMode: Time.WorkMode.Periodic, eventEnabled: true); 25 26 underlyingTimer.CompareReached += UpdateInterrupts; 27 28 DefineRegisters(); 29 } 30 Reset()31 public override void Reset() 32 { 33 base.Reset(); 34 FatalAlert.Unset(); 35 36 underlyingTimer.Reset(); 37 UpdateInterrupts(); 38 } 39 40 public long Size => 0x120; 41 42 public ulong TimerValue => underlyingTimer.Value; 43 44 public GPIO IRQ { get; } 45 public GPIO FatalAlert { get; } 46 DefineRegisters()47 private void DefineRegisters() 48 { 49 Registers.AlertTest.Define(this, 0x0) 50 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 51 .WithReservedBits(1, 31); 52 53 Registers.Control0.Define(this) 54 .WithFlag(0, name: "CONTROL0", writeCallback: (_, val) => 55 { 56 underlyingTimer.Enabled = val; 57 UpdateInterrupts(); 58 }) 59 .WithReservedBits(1, 31) 60 ; 61 62 Registers.CompareLowHart0.Define(this, 0xFFFFFFFF) 63 .WithValueField(0, 32, name: "COMPARELOW", 64 valueProviderCallback: _ => (uint)(underlyingTimer.Compare), 65 writeCallback: (_, val) => 66 { 67 underlyingTimer.Compare = (underlyingTimer.Compare & 0xFFFFFFFF00000000uL) | val; 68 UpdateInterrupts(); 69 }) 70 ; 71 72 Registers.CompareHighHart0.Define(this, 0xFFFFFFFF) 73 .WithValueField(0, 32, name: "COMPAREHI", 74 valueProviderCallback: _ => (uint)(underlyingTimer.Compare >> 32), 75 writeCallback: (_, val) => 76 { 77 underlyingTimer.Compare = (underlyingTimer.Compare & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32); 78 UpdateInterrupts(); 79 }) 80 ; 81 82 Registers.ConfigurationHart0.Define(this, 0x10000) 83 .WithValueField(0, 12, out prescaler, name: "PRESCALE") 84 .WithValueField(16, 8, out step, name: "STEP") 85 .WithWriteCallback((_, __) => TimerUpdateConfiguration()) 86 .WithReservedBits(24, 8) 87 ; 88 89 Registers.ValueLowHart0.Define(this) 90 .WithValueField(0, 32, name: "VALUELOW", 91 valueProviderCallback: _ => (uint)(underlyingTimer.Value), 92 writeCallback: (_, val) => 93 { 94 underlyingTimer.Value = (underlyingTimer.Value & 0xFFFFFFFF00000000uL) | val; 95 UpdateInterrupts(); 96 }) 97 ; 98 99 Registers.ValueHighHart0.Define(this) 100 .WithValueField(0, 32, name: "VALUEHI", 101 valueProviderCallback: _ => (uint)(underlyingTimer.Value >> 32), 102 writeCallback: (_, val) => 103 { 104 underlyingTimer.Value = (underlyingTimer.Value & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32); 105 UpdateInterrupts(); 106 }) 107 ; 108 109 Registers.InterruptEnableHart0.Define(this) 110 .WithFlag(0, out interruptEnabled, name: "IE") 111 .WithReservedBits(1, 31) 112 .WithWriteCallback((_, __) => UpdateInterrupts()) 113 ; 114 115 Registers.InterruptStatusHart0.Define(this) 116 .WithFlag(0, FieldMode.Read, name: "IS", valueProviderCallback: _ => IRQ.IsSet) 117 .WithReservedBits(1, 31) 118 .WithWriteCallback((_, __) => UpdateInterrupts()) 119 ; 120 121 Registers.InterruptTestHart0.Define(this) 122 .WithFlag(0, FieldMode.Write, name: "T", 123 writeCallback: (_, newValue) => 124 { 125 if(newValue) 126 { 127 IRQ.Set(true); 128 } 129 } 130 ) 131 ; 132 } 133 TimerUpdateConfiguration()134 private void TimerUpdateConfiguration() 135 { 136 var divider = (uint)(prescaler.Value + 1u); 137 underlyingTimer.Divider = (divider == 0) ? 1 : divider; 138 underlyingTimer.Step = (uint)step.Value; 139 } 140 UpdateInterrupts()141 private void UpdateInterrupts() 142 { 143 IRQ.Set( 144 underlyingTimer.Enabled 145 && interruptEnabled.Value 146 && (underlyingTimer.Value >= underlyingTimer.Compare)); 147 } 148 149 private IFlagRegisterField interruptEnabled; 150 private IValueRegisterField prescaler; 151 private IValueRegisterField step; 152 153 private readonly ComparingTimer underlyingTimer; 154 155 private enum Registers 156 { 157 AlertTest = 0x0, 158 Control0 = 0x4, 159 InterruptEnableHart0 = 0x100, 160 InterruptStatusHart0 = 0x104, 161 InterruptTestHart0 = 0x108, 162 ConfigurationHart0 = 0x10c, 163 ValueLowHart0 = 0x110, 164 ValueHighHart0 = 0x114, 165 CompareLowHart0 = 0x118, 166 CompareHighHart0 = 0x11c, 167 } 168 } 169 } 170