sim:config: Temporarily fork OpenTitan_Timer with the updated reg
Use the updated regmap to match the updated OT timer IP. Eventually we
should revert back to use the upstream renode model once it is updated.
Change-Id: I12eea596adf42c0ad4b3fdc62f18ebf54f069ca6
diff --git a/platforms/secure.repl b/platforms/secure.repl
index 1430f5a..aba132b 100644
--- a/platforms/secure.repl
+++ b/platforms/secure.repl
@@ -96,7 +96,8 @@
// PATGEN [‘h400E_0000 - ‘h400E_0FFF) 4KB PATGEN
// RV_TIMER [‘h4010_0000 - ‘h4010_0FFF) 4KB RV Timer for Security Core
-timer: Timers.OpenTitan_Timer@ sysbus 0x40100000
+// TODO(hcindyl): Use upstream OpenTitan_Timer model
+timer: Timers.OpenTitan2_Timer@ sysbus 0x40100000
frequency: 24000000
IRQ -> cpu0@7
diff --git a/platforms/smc.repl b/platforms/smc.repl
index f7b0e1c..805e070 100644
--- a/platforms/smc.repl
+++ b/platforms/smc.repl
@@ -58,12 +58,14 @@
RxParityErrorIRQ -> smc_plic@8
// RV_TIMER_SMC, timer for Cantrip kernel.
-timer_smc: Timers.OpenTitan_Timer@ sysbus 0x50010000
+// TODO(hcindyl): Use upstream OpenTitan_Timer model
+timer_smc: Timers.OpenTitan2_Timer@ sysbus 0x50010000
frequency: 24000000
IRQ -> cpu1@5
// Timer for Cantrip software timer service.
-timer_smc_sw: Timers.OpenTitan_Timer@ sysbus 0x50030000
+// TODO(hcindyl): Use upstream OpenTitan_Timer model
+timer_smc_sw: Timers.OpenTitan2_Timer@ sysbus 0x50030000
frequency: 24000000
IRQ -> smc_plic@31
diff --git a/shodan.resc b/shodan.resc
index eb307f1..0a2a01c 100644
--- a/shodan.resc
+++ b/shodan.resc
@@ -10,6 +10,7 @@
EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.SpringbokRiscV32"
EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.SpringbokRiscV32_ControlBlock"
include @sim/config/shodan_infrastructure/SmcRiscV32.cs
+include @sim/config/shodan_infrastructure/OpenTitan2_Timer.cs
include @sim/config/shodan_infrastructure/OpenTitan2_UART.cs
include @sim/config/shodan_infrastructure/Mailbox.cs
include @sim/renode/tools/sel4_extensions/seL4Extensions.cs
diff --git a/shodan_infrastructure/OpenTitan2_Timer.cs b/shodan_infrastructure/OpenTitan2_Timer.cs
new file mode 100644
index 0000000..ac43796
--- /dev/null
+++ b/shodan_infrastructure/OpenTitan2_Timer.cs
@@ -0,0 +1,169 @@
+//
+// Copyright (c) 2010-2023 Antmicro
+// Copyright (c) 2021 Google LLC
+//
+// This file is licensed under the MIT License.
+// Full license text is available in 'licenses/MIT.txt'.
+//
+using Antmicro.Renode.Core;
+using Antmicro.Renode.Core.Structure.Registers;
+using Antmicro.Renode.Peripherals.Bus;
+
+namespace Antmicro.Renode.Peripherals.Timers
+{
+ // OpenTitan rv_timer has a configurable number of timers and harts/Harts, but this implementation is limited to 1 hart and 1 timer.
+ // It is compliant with the v1.11 RISC-V privilege specification.
+ // The counters are all 64-bit and each timer has a configurable prescaler and step.
+ [AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
+ public class OpenTitan2_Timer : BasicDoubleWordPeripheral, IKnownSize, IRiscVTimeProvider
+ {
+ public OpenTitan2_Timer(Machine machine, long frequency = 24000000) : base(machine)
+ {
+ IRQ = new GPIO();
+ FatalAlert = new GPIO();
+ underlyingTimer = new ComparingTimer(machine.ClockSource, frequency, this, "timer", workMode: Time.WorkMode.Periodic, eventEnabled: true);
+
+ underlyingTimer.CompareReached += UpdateInterrupts;
+
+ DefineRegisters();
+ }
+
+ public override void Reset()
+ {
+ base.Reset();
+ FatalAlert.Unset();
+
+ underlyingTimer.Reset();
+ UpdateInterrupts();
+ }
+
+ public long Size => 0x120;
+
+ public ulong TimerValue => underlyingTimer.Value;
+
+ public GPIO IRQ { get; }
+ public GPIO FatalAlert { get; }
+
+ private void DefineRegisters()
+ {
+ Registers.AlertTest.Define(this, 0x0)
+ .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault")
+ .WithReservedBits(1, 31);
+
+ Registers.Control0.Define(this)
+ .WithFlag(0, name: "CONTROL0", writeCallback: (_, val) =>
+ {
+ underlyingTimer.Enabled = val;
+ UpdateInterrupts();
+ })
+ .WithReservedBits(1, 31)
+ ;
+
+ Registers.CompareLowHart0.Define(this, 0xFFFFFFFF)
+ .WithValueField(0, 32, name: "COMPARELOW",
+ valueProviderCallback: _ => (uint)(underlyingTimer.Compare),
+ writeCallback: (_, val) =>
+ {
+ underlyingTimer.Compare = (underlyingTimer.Compare & 0xFFFFFFFF00000000uL) | val;
+ UpdateInterrupts();
+ })
+ ;
+
+ Registers.CompareHighHart0.Define(this, 0xFFFFFFFF)
+ .WithValueField(0, 32, name: "COMPAREHI",
+ valueProviderCallback: _ => (uint)(underlyingTimer.Compare >> 32),
+ writeCallback: (_, val) =>
+ {
+ underlyingTimer.Compare = (underlyingTimer.Compare & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32);
+ UpdateInterrupts();
+ })
+ ;
+
+ Registers.ConfigurationHart0.Define(this, 0x10000)
+ .WithValueField(0, 12, out prescaler, name: "PRESCALE")
+ .WithValueField(16, 8, out step, name: "STEP")
+ .WithWriteCallback((_, __) => TimerUpdateConfiguration())
+ .WithReservedBits(24, 8)
+ ;
+
+ Registers.ValueLowHart0.Define(this)
+ .WithValueField(0, 32, name: "VALUELOW",
+ valueProviderCallback: _ => (uint)(underlyingTimer.Value),
+ writeCallback: (_, val) =>
+ {
+ underlyingTimer.Value = (underlyingTimer.Value & 0xFFFFFFFF00000000uL) | val;
+ UpdateInterrupts();
+ })
+ ;
+
+ Registers.ValueHighHart0.Define(this)
+ .WithValueField(0, 32, name: "VALUEHI",
+ valueProviderCallback: _ => (uint)(underlyingTimer.Value >> 32),
+ writeCallback: (_, val) =>
+ {
+ underlyingTimer.Value = (underlyingTimer.Value & 0x00000000FFFFFFFFuL) | (((ulong)val) << 32);
+ UpdateInterrupts();
+ })
+ ;
+
+ Registers.InterruptEnableHart0.Define(this)
+ .WithFlag(0, out interruptEnabled, name: "IE")
+ .WithReservedBits(1, 31)
+ .WithWriteCallback((_, __) => UpdateInterrupts())
+ ;
+
+ Registers.InterruptStatusHart0.Define(this)
+ .WithFlag(0, FieldMode.Read, name: "IS", valueProviderCallback: _ => IRQ.IsSet)
+ .WithReservedBits(1, 31)
+ .WithWriteCallback((_, __) => UpdateInterrupts())
+ ;
+
+ Registers.InterruptTestHart0.Define(this)
+ .WithFlag(0, FieldMode.Write, name: "T",
+ writeCallback: (_, newValue) =>
+ {
+ if(newValue)
+ {
+ IRQ.Set(true);
+ }
+ }
+ )
+ ;
+ }
+
+ private void TimerUpdateConfiguration()
+ {
+ var divider = (uint)(prescaler.Value + 1u);
+ underlyingTimer.Divider = (divider == 0) ? 1 : divider;
+ underlyingTimer.Step = (uint)step.Value;
+ }
+
+ private void UpdateInterrupts()
+ {
+ IRQ.Set(
+ underlyingTimer.Enabled
+ && interruptEnabled.Value
+ && (underlyingTimer.Value >= underlyingTimer.Compare));
+ }
+
+ private IFlagRegisterField interruptEnabled;
+ private IValueRegisterField prescaler;
+ private IValueRegisterField step;
+
+ private readonly ComparingTimer underlyingTimer;
+
+ private enum Registers
+ {
+ AlertTest = 0x0,
+ Control0 = 0x4,
+ ConfigurationHart0 = 0x10c,
+ ValueLowHart0 = 0x110,
+ ValueHighHart0 = 0x114,
+ CompareLowHart0 = 0x118,
+ CompareHighHart0 = 0x11c,
+ InterruptEnableHart0 = 0x100,
+ InterruptStatusHart0 = 0x104,
+ InterruptTestHart0 = 0x108
+ }
+ }
+}