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 System.Collections.Generic; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Exceptions; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.CPU; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.Miscellaneous 16 { 17 // OpenTitan ResetManager as per https://docs.opentitan.org/hw/ip/rstmgr/doc/ (sha: f4e3845) 18 public class OpenTitan_ResetManager : BasicDoubleWordPeripheral, IGPIOReceiver, IKnownSize 19 { OpenTitan_ResetManager(IMachine machine, ulong resetPC)20 public OpenTitan_ResetManager(IMachine machine, ulong resetPC) : base(machine) 21 { 22 DefineRegisters(); 23 this.resetPC = resetPC; 24 skippedOnLifeCycleReset = new HashSet<IPeripheral>(); 25 skippedOnSystemReset = new HashSet<IPeripheral>(); 26 skippedOnLowPowerExitReset = new HashSet<IPeripheral>(); 27 modules = new IPeripheral[numberOfModules]; 28 29 // Outputs 30 LifeCycleState = new GPIO(); // Current state of rst_lc_n tree. 31 SystemState = new GPIO(); // Current state of rst_sys_n tree. 32 Resets = new GPIO(); // Resets used by the rest of the core domain. 33 34 // Alerts 35 FatalAlert = new GPIO(); // Triggered when a fatal structural fault is detected 36 FatalConsistencyAlert = new GPIO(); // Triggered when a reset consistency fault is detected 37 } 38 Reset()39 public override void Reset() 40 { 41 base.Reset(); 42 FatalAlert.Unset(); 43 FatalConsistencyAlert.Unset(); 44 } 45 MarkAsSkippedOnLifeCycleReset(IPeripheral peripheral)46 public void MarkAsSkippedOnLifeCycleReset(IPeripheral peripheral) 47 { 48 if(!skippedOnLifeCycleReset.Contains(peripheral)) 49 { 50 skippedOnLifeCycleReset.Add(peripheral); 51 } 52 } 53 MarkAsSkippedOnSystemReset(IPeripheral peripheral)54 public void MarkAsSkippedOnSystemReset(IPeripheral peripheral) 55 { 56 if(!skippedOnSystemReset.Contains(peripheral)) 57 { 58 skippedOnSystemReset.Add(peripheral); 59 } 60 } 61 MarkAsSkippedOnLowPowerExitReset(IPeripheral peripheral)62 public void MarkAsSkippedOnLowPowerExitReset(IPeripheral peripheral) 63 { 64 if(!skippedOnLowPowerExitReset.Contains(peripheral)) 65 { 66 skippedOnLowPowerExitReset.Add(peripheral); 67 } 68 } 69 LifeCycleReset()70 public void LifeCycleReset() 71 { 72 ExecuteResetWithSkipped(skippedOnLifeCycleReset); 73 } 74 PeripheralRequestedReset(HardwareResetReason resetReason, bool lowPower)75 public void PeripheralRequestedReset(HardwareResetReason resetReason, bool lowPower) 76 { 77 // Reset initiated by peripheral 78 ExecutePeripheralInitiatedResetWithSkipped(skippedOnSystemReset); 79 80 hardwareResetRequest.Value = resetReason; 81 lowPowerExitFlag.Value = lowPower; 82 powerOnResetFlag.Value = false; 83 softwareResetFlag.Value = false; 84 } 85 LowPowerExitReset()86 public void LowPowerExitReset() 87 { 88 ExecutePeripheralInitiatedResetWithSkipped(skippedOnLowPowerExitReset); 89 90 hardwareResetRequest.Value = 0; 91 lowPowerExitFlag.Value = true; 92 powerOnResetFlag.Value = false; 93 softwareResetFlag.Value = false; 94 } 95 RegisterModuleSpecificReset(IPeripheral peripheral, uint id)96 public void RegisterModuleSpecificReset(IPeripheral peripheral, uint id) 97 { 98 if(id >= modules.Length) 99 { 100 throw new RecoverableException($"Id has to be less than {modules.Length}."); 101 } 102 if(modules[id] != null) 103 { 104 throw new RecoverableException($"Module with id {id} already registered."); 105 } 106 modules[id] = peripheral; 107 } 108 OnGPIO(int number, bool value)109 public void OnGPIO(int number, bool value) 110 { 111 var signal = (GPIOInput)number; 112 var ignored = false; 113 switch(signal) 114 { 115 case GPIOInput.PowerOnReset: 116 if(value) 117 { 118 ExecuteResetWithSkipped(null); 119 } 120 break; 121 case GPIOInput.CPUReset: 122 case GPIOInput.NonDebugModeReset: 123 if(value) 124 { 125 SystemReset(); 126 } 127 break; 128 case GPIOInput.CPUDump: 129 ignored = true; 130 break; 131 case GPIOInput.LifeCycleReset: 132 if(value) 133 { 134 LifeCycleReset(); 135 } 136 break; 137 case GPIOInput.SystemReset: 138 if(value) 139 { 140 SystemReset(); 141 } 142 break; 143 case GPIOInput.ResetCause: 144 case GPIOInput.PeripheralReset: 145 ignored = true; 146 break; 147 default: 148 this.Log(LogLevel.Error, "Received GPIO signal on an unsupported port #{0}.", number); 149 break; 150 } 151 if(ignored) 152 { 153 this.Log(LogLevel.Warning, "{0} signal ignored. Function not supported.", signal); 154 } 155 } 156 157 public long Size => 0x1000; 158 159 public GPIO LifeCycleState { get; } 160 public GPIO SystemState { get; } 161 public GPIO Resets { get; } 162 163 public GPIO FatalAlert { get; } 164 public GPIO FatalConsistencyAlert { get; } 165 ExecuteResetWithSkipped(ICollection<IPeripheral> toSkip)166 private void ExecuteResetWithSkipped(ICollection<IPeripheral> toSkip) 167 { 168 // This method is intended to run only as a result of memory access from translated code. 169 if(!machine.TryRestartTranslationBlockOnCurrentCpu()) 170 { 171 this.Log(LogLevel.Error, "Software reset failed."); 172 return; 173 } 174 175 // If the translation block restart succeeded, we know GetCurrentCPU is safe 176 var cpu = machine.SystemBus.GetCurrentCPU(); 177 178 machine.RequestResetInSafeState(() => 179 { 180 cpu.PC = resetPC; 181 this.Log(LogLevel.Info, "Software reset complete."); 182 }, unresetable: toSkip); 183 } 184 ExecutePeripheralInitiatedResetWithSkipped(ICollection<IPeripheral> toSkip)185 private void ExecutePeripheralInitiatedResetWithSkipped(ICollection<IPeripheral> toSkip) 186 { 187 if(!machine.SystemBus.TryGetCurrentCPU(out var cpu)) 188 { 189 this.Log(LogLevel.Error, "Couldn't find the cpu to reset."); 190 return; 191 } 192 193 machine.RequestResetInSafeState(() => 194 { 195 cpu.PC = resetPC; 196 this.Log(LogLevel.Info, "Hardware reset complete."); 197 }, unresetable: toSkip); 198 } 199 SystemReset()200 private void SystemReset() 201 { 202 ExecuteResetWithSkipped(skippedOnSystemReset); 203 } 204 SoftwareRequestedReset()205 private void SoftwareRequestedReset() 206 { 207 LifeCycleReset(); 208 softwareResetFlag.Value = true; 209 } 210 SetResetHolds(uint value)211 private void SetResetHolds(uint value) 212 { 213 for(byte i = 0; i < softwareControllableResetsWriteEnableMask.Width; ++i) 214 { 215 if(!BitHelper.IsBitSet(value, i)) 216 { 217 continue; 218 } 219 if(BitHelper.IsBitSet(softwareControllableResetsWriteEnableMask.Value, i)) 220 { 221 modules[i].Reset(); 222 } 223 else 224 { 225 this.Log(LogLevel.Warning, "Trying to use disabled software controllable reset VAL_{0}.", i); 226 } 227 } 228 } 229 DefineRegisters()230 private void DefineRegisters() 231 { 232 Registers.AlertTest.Define(this, 0x0) 233 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 234 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalConsistencyAlert.Blink(); }, name: "fatal_cnsty_fault") 235 .WithReservedBits(2, 30); 236 Registers.ResetRequested.Define(this, 0x5) 237 .WithValueField(0, 4, out resetRequest, name: "VAL") 238 .WithReservedBits(4, 28) 239 .WithChangeCallback((_, __) => 240 { 241 if(resetRequest.Value == (uint)MultiBitBool4.True) 242 { 243 resetRequest.Value = 0; 244 SoftwareRequestedReset(); 245 } 246 }); 247 Registers.DeviceResetReason.Define(this, 0x1) 248 .WithFlag(0, out powerOnResetFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "POR") 249 .WithFlag(1, out lowPowerExitFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "LOW_POWER_EXIT") 250 .WithFlag(2, out softwareResetFlag, FieldMode.Read | FieldMode.WriteOneToClear, name: "SW_RESET") 251 .WithEnumField(3, 5, out hardwareResetRequest, FieldMode.Read | FieldMode.WriteOneToClear, name: "HW_REQ") 252 .WithReservedBits(8, 24); 253 Registers.AlertWriteEnable.Define(this, 0x1) 254 .WithTaggedFlag("EN", 0); 255 Registers.AlertInfoControls.Define(this, 0x0) 256 .WithTaggedFlag("EN", 0) 257 .WithReservedBits(1, 3) 258 .WithTag("INDEX", 4, 4) 259 .WithReservedBits(8, 24); 260 Registers.AlertInfoAttributes.Define(this, 0x0) 261 .WithTag("CNT_AVAIL", 0, 4) 262 .WithReservedBits(4, 24); 263 Registers.AlertDumpInfo.Define(this, 0x0) 264 .WithTag("VALUE", 0, 32); 265 Registers.CpuWriteEnable.Define(this, 0x0) 266 .WithTaggedFlag("EN", 0) 267 .WithReservedBits(1, 31); 268 Registers.CpuInfoControls.Define(this, 0x0) 269 .WithTaggedFlag("EN", 0) 270 .WithReservedBits(1, 3) 271 .WithTag("INDEX", 4, 4) 272 .WithReservedBits(8, 24); 273 Registers.CpuInfoAttributes.Define(this, 0x0) 274 .WithTag("CNT_AVAIL", 0, 4) 275 .WithReservedBits(4, 28); 276 Registers.CpuDumpInformation.Define(this, 0x0) 277 .WithTag("VALUE", 0, 32); 278 Registers.SoftwareControllableResetsWriteEnable.Define(this, 0xff) 279 .WithValueField(0, 8, out softwareControllableResetsWriteEnableMask, FieldMode.Read | FieldMode.WriteZeroToClear, name: "EN") 280 .WithReservedBits(8, 24); 281 Registers.SoftwareControllableResets.Define(this, 0xff) 282 .WithValueField(0, 8, writeCallback: (_, val) => { SetResetHolds((uint)val); }, name: "VAL") 283 .WithReservedBits(8, 24); 284 Registers.ErrorCode.Define(this) 285 .WithTaggedFlag("REG_INTG_ERR", 0) 286 .WithTaggedFlag("RESET_CONSISTENCY_ERR", 1) 287 .WithReservedBits(2, 30); 288 } 289 290 private IValueRegisterField resetRequest; 291 private IFlagRegisterField powerOnResetFlag; 292 private IFlagRegisterField lowPowerExitFlag; 293 private IFlagRegisterField softwareResetFlag; 294 private IEnumRegisterField<HardwareResetReason> hardwareResetRequest; 295 private IValueRegisterField softwareControllableResetsWriteEnableMask; 296 private readonly ulong resetPC; 297 private readonly HashSet<IPeripheral> skippedOnLifeCycleReset; 298 private readonly HashSet<IPeripheral> skippedOnSystemReset; 299 private readonly HashSet<IPeripheral> skippedOnLowPowerExitReset; 300 private readonly IPeripheral[] modules; 301 302 private const int numberOfModules = 8; 303 304 public enum GPIOInput 305 { 306 PowerOnReset, // Input from ast. This signal is the root reset of the design and is used to generate rst_por_n. 307 CPUReset, // CPU reset indication. This informs the reset manager that the processor has reset. 308 NonDebugModeReset, // Non-debug-module reset request from rv_dm. 309 CPUDump, // CPU crash dump state from rv_core_ibex. 310 LifeCycleReset, // Power manager request to assert the rst_lc_n tree. 311 SystemReset, // Power manager request to assert the rst_sys_n tree. 312 ResetCause, // Power manager indication for why it requested reset, the cause can be low power entry or peripheral issued request. 313 PeripheralReset, // Peripheral reset requests. 314 } 315 316 public enum HardwareResetReason 317 { 318 SystemResetControl = 0b00001, 319 Watchdog = 0b00010, 320 PowerUnstable = 0b00100, 321 Escalation = 0b01000, 322 NonDebugModule = 0b10000, 323 } 324 325 private enum Registers 326 { 327 AlertTest = 0x0, // Alert Test Register 328 ResetRequested = 0x4, // Software requested system reset. 329 DeviceResetReason = 0x8, // Device reset reason. 330 AlertWriteEnable = 0xc, // Alert write enable 331 AlertInfoControls = 0x10, // Alert info dump controls. 332 AlertInfoAttributes = 0x14, // Alert info dump attributes. 333 AlertDumpInfo = 0x18, // Alert dump information prior to last reset. Which value read is controlled by the ALERT_INFO_CTRL register. 334 CpuWriteEnable = 0x1c, // Cpu write enable 335 CpuInfoControls = 0x20, // Cpu info dump controls. 336 CpuInfoAttributes = 0x24, // Cpu info dump attributes. 337 CpuDumpInformation = 0x28, // Cpu dump information prior to last reset. Which value read is controlled by the CPU_INFO_CTRL register. 338 SoftwareControllableResetsWriteEnable = 0x2c, // Register write enable for software controllable resets. When a particular bit value is 0, the corresponding value in SW_RST_CTRL_N can no longer be changed. When a particular bit value is 1, the corresponding value in SW_RST_CTRL_N can be changed. 339 SoftwareControllableResets = 0x30, // Software controllable resets. When a particular bit value is 0, the corresponding module is held in reset. When a particular bit value is 1, the corresponding module is not held in reset. 340 ErrorCode = 0x34, // A bit vector of all the errors that have occurred in reset manager 341 } 342 } 343 } 344