1 // 2 // Copyright (c) 2010-2025 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.Collections.Generic; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Time; 13 using TimeDirection = Antmicro.Renode.Time.Direction; 14 15 namespace Antmicro.Renode.Peripherals.Timers 16 { 17 public class RenesasRZG_Watchdog : IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize 18 { RenesasRZG_Watchdog(IMachine machine, long clockFrequency)19 public RenesasRZG_Watchdog(IMachine machine, long clockFrequency) 20 { 21 this.machine = machine; 22 23 IRQ = new GPIO(); 24 25 this.timer = new LimitTimer(machine.ClockSource, clockFrequency, this, "Watchdog Timer", 26 DefaultCycle, TimeDirection.Ascending, workMode: WorkMode.Periodic, eventEnabled: true 27 ); 28 this.timer.LimitReached += OnLimitReached; 29 30 RegistersCollection = new DoubleWordRegisterCollection(this, BuildRegisterMap()); 31 32 Reset(); 33 } 34 Reset()35 public void Reset() 36 { 37 RegistersCollection.Reset(); 38 IRQ.Unset(); 39 timer.Reset(); 40 forceStop = false; 41 timerEnabled = false; 42 SystemResetEnabled = false; 43 if(!keepGeneratedResetValue) 44 { 45 generatedReset = false; 46 } 47 keepGeneratedResetValue = false; 48 } 49 ReadDoubleWord(long offset)50 public uint ReadDoubleWord(long offset) 51 { 52 return RegistersCollection.Read(offset); 53 } 54 WriteDoubleWord(long offset, uint value)55 public void WriteDoubleWord(long offset, uint value) 56 { 57 RegistersCollection.Write(offset, value); 58 } 59 60 public GPIO IRQ { get; } 61 public long Size => 0x400; 62 public DoubleWordRegisterCollection RegistersCollection { get; } 63 public bool ForceStop 64 { 65 get => forceStop; 66 set 67 { 68 forceStop = value; 69 UpdateTimerStatus(); 70 } 71 } 72 public bool SystemResetEnabled { get; set; } = false; 73 public bool GeneratedReset 74 { 75 get => generatedReset; 76 set 77 { 78 // Only allow to reset the flag, not set it 79 if(!value) 80 { 81 generatedReset = false; 82 } 83 } 84 } 85 OnLimitReached()86 private void OnLimitReached() 87 { 88 if(IRQ.IsSet && SystemResetEnabled) 89 { 90 keepGeneratedResetValue = true; 91 generatedReset = true; 92 machine.RequestReset(); 93 } 94 else 95 { 96 IRQ.Set(); 97 } 98 } 99 BuildRegisterMap()100 private Dictionary<long, DoubleWordRegister> BuildRegisterMap() 101 { 102 var registerMap = new Dictionary<long, DoubleWordRegister> 103 { 104 {(long)Registers.Control, new DoubleWordRegister(this) 105 .WithFlag(0, name: "WDTEN", 106 valueProviderCallback: _ => timerEnabled, 107 writeCallback: (_, value) => 108 { 109 timerEnabled = value; 110 UpdateTimerStatus(); 111 } 112 ) 113 .WithReservedBits(1, 31) 114 }, 115 {(long)Registers.PeriodSetting, new DoubleWordRegister(this) 116 .WithReservedBits(0, 20) 117 .WithValueField(20, 12, name: "WDTTIME", 118 valueProviderCallback: _ => (timer.Limit >> 20) - 1, 119 writeCallback: (_, value) => 120 { 121 if(timer.Enabled) 122 { 123 this.Log(LogLevel.Warning, "Setting WDTTIME while the timer is running. Ignoring"); 124 return; 125 } 126 timer.Limit = (value + 1) << 20; 127 } 128 ) 129 }, 130 {(long)Registers.ElapsedTime, new DoubleWordRegister(this) 131 .WithValueField(0, 32, name: "CRTTIME", 132 valueProviderCallback: _ => timer.Value, 133 writeCallback: (_, value) => 134 { 135 if(timer.Enabled) 136 { 137 this.Log(LogLevel.Warning, "Setting CRTTIME while the timer is running. Ignoring"); 138 return; 139 } 140 timer.Value = value; 141 } 142 ) 143 }, 144 {(long)Registers.InterruptControl, new DoubleWordRegister(this) 145 .WithFlag(0, FieldMode.WriteOneToClear | FieldMode.Read, name: "INTDISP", 146 valueProviderCallback: _ => IRQ.IsSet, 147 writeCallback: (_, value) => 148 { 149 if(value) 150 { 151 IRQ.Unset(); 152 } 153 } 154 ) 155 .WithReservedBits(1, 31) 156 }, 157 {(long)Registers.ParityErrorControl, new DoubleWordRegister(this) 158 .WithTaggedFlags("PECR", 0, 32) 159 }, 160 {(long)Registers.ParityErrorForcedEnable, new DoubleWordRegister(this) 161 .WithTaggedFlag("PEEN", 0) 162 .WithReservedBits(1, 31) 163 }, 164 {(long)Registers.ParityStatus, new DoubleWordRegister(this) 165 .WithTaggedFlags("PESR", 0, 32) 166 }, 167 {(long)Registers.ParityErrorEnable, new DoubleWordRegister(this) 168 .WithTaggedFlags("PEER", 0, 32) 169 }, 170 {(long)Registers.ParityErrorPolarity, new DoubleWordRegister(this) 171 .WithTaggedFlags("PEPO", 0, 32) 172 }, 173 }; 174 175 return registerMap; 176 } 177 UpdateTimerStatus()178 private void UpdateTimerStatus() 179 { 180 timer.Enabled = timerEnabled && !forceStop; 181 } 182 183 private bool forceStop = false; 184 private bool timerEnabled = false; 185 private bool generatedReset = false; 186 private bool keepGeneratedResetValue = false; 187 188 private readonly IMachine machine; 189 private readonly LimitTimer timer; 190 191 private const ulong DefaultCycle = 1ul << 20; 192 193 public enum Registers : long 194 { 195 Control = 0x00, 196 PeriodSetting = 0x04, 197 ElapsedTime = 0x08, 198 InterruptControl = 0x0C, 199 ParityErrorControl = 0x10, 200 ParityErrorForcedEnable = 0x14, 201 ParityStatus = 0x18, 202 ParityErrorEnable = 0x1C, 203 ParityErrorPolarity = 0x20, 204 } 205 } 206 } 207