1 // 2 // Copyright (c) 2010-2024 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 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 13 namespace Antmicro.Renode.Peripherals.Timers 14 { 15 public class Cadence_WDT : BasicDoubleWordPeripheral, IKnownSize 16 { Cadence_WDT(IMachine machine, long frequency)17 public Cadence_WDT(IMachine machine, long frequency) : base(machine) 18 { 19 IRQ = new GPIO(); 20 21 watchdogTimer = new LimitTimer(machine.ClockSource, frequency, this, "watchdog", enabled: false, eventEnabled: true); 22 watchdogTimer.LimitReached += () => 23 { 24 this.Log(LogLevel.Noisy, "Limit reached"); 25 if(interruptRequestEnable.Value) 26 { 27 IRQ.Blink(); 28 } 29 30 if(resetEnable.Value) 31 { 32 this.Log(LogLevel.Info, "Watchdog timed out. Resetting..."); 33 machine.RequestReset(); 34 } 35 LimitReached?.Invoke(this); 36 }; 37 DefineRegisters(); 38 } 39 Reset()40 public override void Reset() 41 { 42 base.Reset(); 43 watchdogTimer.Reset(); 44 } 45 46 public GPIO IRQ { get; } 47 public long Size => 0x1000; 48 49 public event Action<Cadence_WDT> LimitReached; 50 DefineRegisters()51 private void DefineRegisters() 52 { 53 Register.ZeroMode.Define(this, resetValue: 0x1C3) 54 .WithFlag(0, out watchdogEnable, writeCallback: (oldVal, newVal) => 55 { 56 if(zeroAccessKey.Value != ZeroAccessKey) 57 { 58 watchdogEnable.Value = oldVal; 59 return; 60 } 61 watchdogTimer.Enabled = newVal; 62 }, name: "WDEN") 63 .WithFlag(1, out resetEnable, writeCallback: (oldVal, newVal) => 64 { 65 if(zeroAccessKey.Value != ZeroAccessKey) 66 { 67 resetEnable.Value = oldVal; 68 return; 69 } 70 }, name: "RSTEN") 71 .WithFlag(2, out interruptRequestEnable, writeCallback: (oldVal, newVal) => 72 { 73 if(zeroAccessKey.Value != ZeroAccessKey) 74 { 75 interruptRequestEnable.Value = oldVal; 76 return; 77 } 78 }, name: "IRQEN") 79 .WithTaggedFlag("EXTEN", 3) 80 .WithTag("RSTLN", 4, 3) 81 .WithTag("IRQLN", 7, 2) 82 .WithTag("EXLN", 9, 3) 83 .WithValueField(12, 12, out zeroAccessKey, FieldMode.Write, name: "ZKEY") 84 .WithReservedBits(24, 8) 85 .WithWriteCallback((_, __) => 86 { 87 if(zeroAccessKey.Value != ZeroAccessKey) 88 { 89 this.Log(LogLevel.Warning, "Write to the register is invalid because of the wrong access key"); 90 } 91 }); 92 93 Register.CounterControl.Define(this, resetValue: 0b111100) 94 .WithValueField(0, 2, out counterClockPrescale, writeCallback: (oldVal, newVal) => 95 { 96 if(counterAccessKey.Value != CounterAccessKey) 97 { 98 counterClockPrescale.Value = oldVal; 99 return; 100 } 101 watchdogTimer.Divider = 1 << (int)(3 * (newVal + 1)); 102 }, name: "CLKSEL") 103 .WithValueField(2, 12, out counterRestartValue, writeCallback: (oldVal, newVal) => 104 { 105 if(counterAccessKey.Value != CounterAccessKey) 106 { 107 counterRestartValue.Value = oldVal; 108 return; 109 } 110 }, name: "CRV") 111 .WithValueField(14, 12, out counterAccessKey, FieldMode.Write, name: "CKEY") 112 .WithReservedBits(26, 6) 113 .WithWriteCallback((_, __) => 114 { 115 if(counterAccessKey.Value != CounterAccessKey) 116 { 117 this.Log(LogLevel.Warning, "Write to the register is invalid because of the wrong access key"); 118 } 119 }); 120 121 Register.Restart.Define(this) 122 .WithValueField(0, 16, FieldMode.Write, writeCallback: (_, val) => 123 { 124 if(val != RestartKey) 125 { 126 this.Log(LogLevel.Warning, "Write to the register is invalid because of the wrong access key"); 127 return; 128 } 129 watchdogTimer.Value = (counterRestartValue.Value << 12) | 0xFFF; 130 }) 131 .WithReservedBits(16, 16); 132 133 Register.Status.Define(this) 134 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => WatchdogZero) 135 .WithReservedBits(1, 31); 136 } 137 138 private bool WatchdogZero => watchdogTimer.Value == watchdogTimer.Limit; 139 140 private readonly LimitTimer watchdogTimer; 141 142 private IFlagRegisterField watchdogEnable; 143 private IFlagRegisterField resetEnable; 144 private IFlagRegisterField interruptRequestEnable; 145 private IValueRegisterField zeroAccessKey; 146 private IValueRegisterField counterClockPrescale; 147 private IValueRegisterField counterRestartValue; 148 private IValueRegisterField counterAccessKey; 149 150 private const ushort ZeroAccessKey = 0xABC; 151 private const ushort CounterAccessKey = 0x248; 152 private const ushort RestartKey = 0x1999; 153 154 private enum Register 155 { 156 ZeroMode = 0x0, 157 CounterControl = 0x4, 158 Restart = 0x8, 159 Status = 0xC, 160 } 161 } 162 } 163