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 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Peripherals.Miscellaneous; 11 12 namespace Antmicro.Renode.Peripherals.Timers 13 { 14 public class MAX32650_WDT : BasicDoubleWordPeripheral, IKnownSize 15 { MAX32650_WDT(IMachine machine, MAX32650_GCR gcr)16 public MAX32650_WDT(IMachine machine, MAX32650_GCR gcr) : base(machine) 17 { 18 IRQ = new GPIO(); 19 20 interruptTimer = new LimitTimer(machine.ClockSource, gcr.SysClk / 2, this, "interrupt_timer", InitialLimit, eventEnabled: true); 21 interruptTimer.LimitReached += () => 22 { 23 interruptPending.Value = true; 24 UpdateInterrupts(); 25 }; 26 27 resetTimer = new LimitTimer(machine.ClockSource, gcr.SysClk / 2, this, "reset_timer", InitialLimit, eventEnabled: true); 28 resetTimer.LimitReached += () => 29 { 30 if(BeforeReset?.Invoke() ?? false) 31 { 32 return; 33 } 34 35 systemReset = true; 36 machine.RequestReset(); 37 }; 38 39 gcr.SysClkChanged += (newFrequency) => 40 { 41 interruptTimer.Frequency = newFrequency / 2; 42 resetTimer.Frequency = newFrequency / 2; 43 }; 44 45 DefineRegisters(); 46 } 47 Reset()48 public override void Reset() 49 { 50 base.Reset(); 51 interruptTimer.Reset(); 52 resetTimer.Reset(); 53 IRQ.Unset(); 54 55 resetSequence = ResetSequence.WaitForFirstByte; 56 57 // We are intentionally not clearing systemReset variable 58 // as it should persist after watchdog-triggered reset. 59 } 60 61 public long Size => 0x400; 62 63 public GPIO IRQ { get; } 64 65 public Func<bool> BeforeReset { get; set; } 66 UpdateInterrupts()67 private void UpdateInterrupts() 68 { 69 IRQ.Set(interruptTimer.EventEnabled && interruptPending.Value); 70 } 71 DefineRegisters()72 private void DefineRegisters() 73 { 74 Registers.Control.Define(this) 75 .WithValueField(0, 4, name: "CTRL.int_period", 76 changeCallback: (_, value) => 77 { 78 interruptTimer.Limit = 1UL << (31 - (int)value); 79 }) 80 .WithValueField(4, 4, name: "CTRL.rst_period", 81 changeCallback: (_, value) => 82 { 83 resetTimer.Limit = 1UL << (31 - (int)value); 84 }) 85 .WithFlag(8, name: "CTRL.wdt_en", 86 writeCallback: (_, value) => 87 { 88 interruptTimer.Enabled = value; 89 resetTimer.Enabled = value; 90 }) 91 .WithFlag(9, out interruptPending, FieldMode.WriteOneToClear, name: "CTRL.int_flag", 92 writeCallback: (_, __) => UpdateInterrupts()) 93 .WithFlag(10, name: "CTRL.int_en", 94 valueProviderCallback: _ => interruptTimer.EventEnabled, 95 writeCallback: (_, value) => 96 { 97 interruptTimer.EventEnabled = value; 98 UpdateInterrupts(); 99 }) 100 .WithFlag(11, name: "CTRL.rst_en", 101 valueProviderCallback: _ => resetTimer.EventEnabled, 102 changeCallback: (_, value) => resetTimer.EventEnabled = value) 103 .WithReservedBits(12, 19) 104 .WithFlag(31, name: "CTRL.rst_flag", 105 valueProviderCallback: _ => systemReset, 106 changeCallback: (_, value) => systemReset = value) 107 ; 108 109 Registers.Reset.Define(this) 110 .WithValueField(0, 8, name: "RST.wdt_rst", 111 writeCallback: (_, value) => 112 { 113 if(resetSequence == ResetSequence.WaitForFirstByte && value == FirstResetByte) 114 { 115 resetSequence = ResetSequence.WaitForSecondByte; 116 } 117 else if(resetSequence == ResetSequence.WaitForSecondByte && value == SecondResetByte) 118 { 119 resetSequence = ResetSequence.WaitForFirstByte; 120 interruptTimer.Value = interruptTimer.Limit; 121 resetTimer.Value = resetTimer.Limit; 122 } 123 else 124 { 125 resetSequence = ResetSequence.WaitForFirstByte; 126 } 127 }) 128 .WithReservedBits(8, 24) 129 ; 130 } 131 132 private ResetSequence resetSequence; 133 private bool systemReset; 134 135 private IFlagRegisterField interruptPending; 136 137 private readonly LimitTimer interruptTimer; 138 private readonly LimitTimer resetTimer; 139 140 private const ulong InitialLimit = (1UL << 31); 141 private const byte FirstResetByte = 0xA5; 142 private const byte SecondResetByte = 0x5A; 143 144 private enum ResetSequence 145 { 146 WaitForFirstByte, 147 WaitForSecondByte 148 } 149 150 private enum Registers 151 { 152 Control = 0x00, 153 Reset = 0x04, 154 } 155 } 156 } 157