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 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.CPU; 12 13 namespace Antmicro.Renode.Peripherals.Miscellaneous 14 { 15 public class SAM4S_RSTC : BasicDoubleWordPeripheral, IGPIOReceiver, IKnownSize 16 { SAM4S_RSTC(IMachine machine)17 public SAM4S_RSTC(IMachine machine) : base(machine) 18 { 19 DefineRegisters(); 20 } 21 InvokeReset(ResetType reason, bool resetProcessor = false, bool resetPeripherals = false, bool assertPin = false)22 public void InvokeReset(ResetType reason, bool resetProcessor = false, bool resetPeripherals = false, bool assertPin = false) 23 { 24 if(!resetProcessor && !resetPeripherals && assertPin) 25 { 26 this.Log(LogLevel.Info, "Asserting IRQ pin"); 27 userResetStatus = true; 28 IRQ.Set(); 29 return; 30 } 31 32 string resetVector = null; 33 if(resetProcessor && resetPeripherals) 34 { 35 resetVector = "platform"; 36 } 37 else if(resetProcessor) 38 { 39 resetVector = "CPU"; 40 } 41 else if(resetPeripherals) 42 { 43 resetVector = "peripherals"; 44 } 45 else 46 { 47 return; 48 } 49 50 this.Log(LogLevel.Info, "Resetting {0}", resetVector); 51 lastResetReason.Value = reason; 52 53 if(machine.SystemBus.TryGetCurrentCPU(out var cpu) && resetProcessor) 54 { 55 if(!(cpu is CortexM cortexM)) 56 { 57 this.Log(LogLevel.Error, "CPU reset has been requested, but the CPU is not cortex-m; is platform configuration correct?"); 58 return; 59 } 60 61 machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => 62 { 63 var currentVectorBase = cortexM.VectorTableOffset; 64 cpu.Reset(); 65 cortexM.VectorTableOffset = currentVectorBase; 66 cpu.Resume(); 67 }); 68 } 69 70 if(resetPeripherals) 71 { 72 machine.RequestResetInSafeState(unresetable: new IPeripheral[] { this, cpu, machine.SystemBus }); 73 } 74 } 75 OnGPIO(int pin, bool state)76 public void OnGPIO(int pin, bool state) 77 { 78 if(pin != 0) 79 { 80 this.Log(LogLevel.Warning, "Tried to write to pin different than 0, ignoring"); 81 return; 82 } 83 84 if(!state && userResetEnabled) 85 { 86 InvokeReset(ResetType.UserReset, resetProcessor: true); 87 } 88 else if(previousPinState && !state) 89 { 90 InvokeReset(ResetType.UserReset, assertPin: !userResetEnabled && userResetInterrupt); 91 } 92 93 previousPinState = state; 94 } 95 Reset()96 public override void Reset() 97 { 98 base.Reset(); 99 IRQ.Unset(); 100 } 101 102 public GPIO IRQ { get; } = new GPIO(); 103 104 public long Size => 0x10; 105 DefineRegisters()106 private void DefineRegisters() 107 { 108 Registers.Control.Define(this) 109 .WithFlag(0, out var processorReset, name: "PROCRST", 110 valueProviderCallback: _ => false) 111 .WithReservedBits(1, 1) 112 .WithFlag(2, out var peripheralReset, name: "PERRST", 113 valueProviderCallback: _ => false) 114 .WithFlag(3, out var externalReset, name: "EXTRST", 115 valueProviderCallback: _ => false) 116 .WithReservedBits(4, 20) 117 .WithValueField(24, 8, out var controlKey, name: "KEY", 118 valueProviderCallback: _ => 0) 119 .WithWriteCallback((_, __) => 120 { 121 if(controlKey.Value != ResetPassword) 122 { 123 this.Log(LogLevel.Info, "Software tried to invoke software reset, but wrong key has been provided: {0:X} vs {1:X}", controlKey, ResetPassword); 124 return; 125 } 126 127 InvokeReset(ResetType.SoftwareReset, processorReset.Value, peripheralReset.Value, externalReset.Value); 128 }) 129 ; 130 131 Registers.Status.Define(this) 132 .WithFlag(0, FieldMode.Read, name: "URSTS", 133 valueProviderCallback: _ => 134 { 135 var previousValue = userResetStatus; 136 if(previousValue && userResetInterrupt) 137 { 138 IRQ.Unset(); 139 } 140 userResetStatus = false; 141 return previousValue; 142 }) 143 .WithReservedBits(1, 7) 144 .WithEnumField(8, 3, out lastResetReason, name: "RSTTYP") 145 .WithReservedBits(11, 5) 146 .WithTaggedFlag("NRSTL", 16) 147 .WithFlag(17, FieldMode.Read, name: "SRCMP", 148 valueProviderCallback: _ => false) 149 .WithReservedBits(18, 14) 150 ; 151 152 Registers.Mode.Define(this, 0x00000001) 153 .WithFlag(0, out var resetEnabled, FieldMode.Write, name: "URSTEN") 154 .WithReservedBits(1, 3) 155 .WithFlag(4, out var interruptEnabled, FieldMode.Write, name: "URSTIEN") 156 .WithReservedBits(5, 3) 157 .WithTag("ERSTL", 8, 4) 158 .WithReservedBits(12, 12) 159 .WithValueField(24, 8, out var modeKey, FieldMode.Write, name: "KEY") 160 .WithWriteCallback((_, __) => 161 { 162 if(modeKey.Value != ResetPassword) 163 { 164 this.Log(LogLevel.Info, "Software tried to modify configuration, but wrong key has been provided: {0:X} vs {1:X}", modeKey, ResetPassword); 165 return; 166 } 167 168 userResetEnabled = resetEnabled.Value; 169 userResetInterrupt = interruptEnabled.Value; 170 }) 171 ; 172 } 173 174 private IEnumRegisterField<ResetType> lastResetReason; 175 176 private bool previousPinState; 177 private bool userResetStatus; 178 private bool userResetEnabled; 179 private bool userResetInterrupt; 180 181 private const int ResetPassword = 0xA5; 182 183 public enum ResetType 184 { 185 GeneralReset, 186 BackupReset, 187 WatchdogReset, 188 SoftwareReset, 189 UserReset, 190 Reserved0, 191 Reserved1, 192 Reserved2, 193 } 194 195 public enum Registers 196 { 197 Control = 0x00, 198 Status = 0x04, 199 Mode = 0x08, 200 } 201 } 202 } 203