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.Time; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 13 namespace Antmicro.Renode.Peripherals.Timers 14 { 15 public class AmbiqApollo4_Watchdog : BasicDoubleWordPeripheral, IKnownSize 16 { AmbiqApollo4_Watchdog(IMachine machine)17 public AmbiqApollo4_Watchdog(IMachine machine) : base(machine) 18 { 19 resetTimer = new LimitTimer(machine.ClockSource, 1, this, "Reset", enabled: false, eventEnabled: true, direction: Direction.Ascending, workMode: WorkMode.OneShot); 20 resetTimer.LimitReached += () => 21 { 22 if(resetEnabled.Value) 23 { 24 this.Log(LogLevel.Warning, "Watchog reset triggered"); 25 machine.RequestReset(); 26 } 27 }; 28 29 DefineRegisters(); 30 } 31 DefineRegisters()32 private void DefineRegisters() 33 { 34 Registers.Configuration.Define(this, 0xFFFF00) 35 .WithFlag(0, out var timerEnabled, name: "WDTEN") 36 .WithTaggedFlag("INTEN", 1) 37 .WithFlag(2, out resetEnabled, name: "RESEN") 38 .WithTaggedFlag("DSPRESETINTEN", 3) 39 .WithReservedBits(4, 4) 40 .WithValueField(8, 8, out var resetLimit, name: "RESVAL") 41 .WithValueField(16, 8, out var interruptLimit, name: "INTVAL") 42 .WithEnumField<DoubleWordRegister, ClockSelect>(24, 3, out var clockSelect, name: "CLKSEL") 43 .WithReservedBits(27, 5) 44 .WithChangeCallback((_, __) => 45 { 46 var enableTimers = timerEnabled.Value; 47 long frequency = 1; 48 49 switch(clockSelect.Value) 50 { 51 case ClockSelect.Off: 52 enableTimers = false; 53 break; 54 case ClockSelect._128Hz: 55 frequency = 128 * FrequencyMultiplier; 56 break; 57 case ClockSelect._16Hz: 58 frequency = 16 * FrequencyMultiplier; 59 break; 60 case ClockSelect._1Hz: 61 frequency = 1 * FrequencyMultiplier; 62 break; 63 case ClockSelect._1_16Hz: 64 frequency = FrequencyMultiplier / 16; 65 break; 66 default: 67 this.Log(LogLevel.Error, "Invalid frequency value: {0}. Timer will be disabled", clockSelect.Value); 68 enableTimers = false; 69 break; 70 } 71 72 resetTimer.Frequency = frequency; 73 resetTimer.Limit = resetLimit.Value * FrequencyMultiplier; 74 resetTimer.Enabled = enableTimers && resetEnabled.Value; 75 }); 76 77 Registers.Restart.Define(this) 78 .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, value) => 79 { 80 if(value == WatchdogReloadValue) 81 { 82 resetTimer.ResetValue(); 83 } 84 }); 85 86 Registers.CounterValue.Define(this) 87 .WithValueField(0, 8, FieldMode.Read, name: "COUNT", valueProviderCallback: _ => TimerValue); 88 } 89 90 private ulong TimerValue 91 { 92 get 93 { 94 if(sysbus.TryGetCurrentCPU(out var cpu)) 95 { 96 cpu.SyncTime(); 97 } 98 return resetTimer.Value / FrequencyMultiplier; 99 } 100 } 101 102 public long Size => 0x400; 103 104 private IFlagRegisterField resetEnabled; 105 106 private readonly LimitTimer resetTimer; 107 108 private const ulong WatchdogReloadValue = 0xB2; 109 private const int FrequencyMultiplier = 16; 110 111 private enum ClockSelect 112 { 113 Off = 0x0, 114 _128Hz = 0x1, 115 _16Hz = 0x2, 116 _1Hz = 0x3, 117 _1_16Hz = 0x4, 118 } 119 120 private enum Registers 121 { 122 Configuration = 0x0, // CFG 123 Restart = 0x4, // RSTRT 124 Lock = 0x8, // LOCK 125 CounterValue = 0xC, // COUNT 126 DSP0Configuration = 0x10, // DPS0CFG 127 DSP0Restart = 0x14, // DSP0RSTRT 128 DSP0Lock = 0x18, // DSP0LOCK 129 DSP0CounterValue = 0x1C, // DSP1COUNT 130 DSP1Configuration = 0x20, // DPS1CFG 131 DSP1Restart = 0x24, // DSP1RSTRT 132 DSP1Lock = 0x28, // DSP1LOCK 133 DSP1CounterValue = 0x2C, // DSP1COUNT 134 InterruptEnable = 0x200, // WDTIEREN 135 InterruptStatus = 0x204, // WDTIERSTAT 136 InterruptClear = 0x208, // WDTIERCLR 137 InterruptSet = 0x20C, // WDTIERSET 138 DSP0InterruptEnable = 0x210, // DSP0IEREN 139 DSP0InterruptStatus = 0x214, // DSP0IERSTAT 140 DSP0InterruptClear = 0x218, // DSP0IERCLR 141 DSP0InterruptSet = 0x21C, // DSP0IERSET 142 DSP1InterruptEnable = 0x220, // DSP1IEREN 143 DSP1InterruptStatus = 0x224, // DSP1IERSTAT 144 DSP1InterruptClear = 0x228, // DSP1IERCLR 145 DSP1InterruptSet = 0x22C, // DSP1IERSET 146 } 147 } 148 } 149