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 System.Linq; 9 using System.Threading; 10 using System.Collections.Generic; 11 using System.Collections.Concurrent; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Exceptions; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Peripherals.Bus; 16 using Antmicro.Renode.Peripherals.CPU; 17 using Antmicro.Renode.Peripherals.Timers; 18 using Antmicro.Renode.Plugins.CoSimulationPlugin.Connection; 19 using Antmicro.Renode.Plugins.CoSimulationPlugin.Connection.Protocols; 20 using Antmicro.Renode.Peripherals.CPU.Disassembler; 21 using Antmicro.Renode.Peripherals.CPU.Registers; 22 using Antmicro.Renode.Utilities; 23 using Antmicro.Renode.Time; 24 using ELFSharp.ELF; 25 using ELFSharp.UImage; 26 using Range = Antmicro.Renode.Core.Range; 27 using Machine = Antmicro.Renode.Core.Machine; 28 29 namespace Antmicro.Renode.Peripherals.CoSimulated 30 { 31 public abstract class CoSimulatedCPU : BaseCPU, IGPIOReceiver, ICoSimulationConnectible, ITimeSink, IDisposable 32 { CoSimulatedCPU(string cpuType, Machine machine, Endianess endianness, CpuBitness bitness = CpuBitness.Bits32, string simulationFilePathLinux = null, string simulationFilePathWindows = null, string simulationFilePathMacOS = null, string simulationContextLinux = null, string simulationContextWindows = null, string simulationContextMacOS = null, string address = null)33 public CoSimulatedCPU(string cpuType, Machine machine, Endianess endianness, CpuBitness bitness = CpuBitness.Bits32, 34 string simulationFilePathLinux = null, string simulationFilePathWindows = null, string simulationFilePathMacOS = null, 35 string simulationContextLinux = null, string simulationContextWindows = null, string simulationContextMacOS = null, string address = null) 36 : base(0, cpuType, machine, endianness, bitness) 37 { 38 // Multiple CoSimulatedCPUs per CoSimulationConnection are currently not supported. 39 RenodeToCosimIndex = 0; 40 CosimToRenodeIndex = 0; 41 42 cosimConnection = new CoSimulationConnection(machine, "cpu_cosim_cosimConnection", 0, 43 simulationFilePathLinux, simulationFilePathWindows, simulationFilePathMacOS, 44 simulationContextLinux, simulationContextWindows, simulationContextMacOS, 45 0, 0, address); 46 cosimConnection.AttachTo(this); 47 48 InitializeRegisters(); 49 } 50 Reset()51 public override void Reset() 52 { 53 base.Reset(); 54 55 gotRegisterValue = false; 56 setRegisterValue = false; 57 gotSingleStepMode = false; 58 ticksProcessed = false; 59 gotStep = false; 60 61 registerValue = 0; 62 instructionsExecutedThisRound = 0; 63 totalExecutedInstructions = 0; 64 65 lock(cosimConnectionLock) 66 { 67 cosimConnection.Reset(); 68 } 69 } 70 Dispose()71 public override void Dispose() 72 { 73 base.Dispose(); 74 lock(cosimConnectionLock) 75 { 76 cosimConnection.Dispose(); 77 } 78 } 79 OnGPIO(int number, bool value)80 public void OnGPIO(int number, bool value) 81 { 82 if(!cosimConnection.IsConnected) 83 { 84 this.NoisyLog("OnGPIO for IRQ {number}, value {value} will have no effect, because co-simulation is not connected."); 85 return; 86 } 87 this.NoisyLog("IRQ {0}, value {1}", number, value); 88 lock(cosimConnectionLock) 89 { 90 cosimConnection.Send(this, ActionType.Interrupt, (ulong)number, (ulong)(value ? 1 : 0)); 91 } 92 } 93 SetRegisterValue32(int register, uint value)94 public virtual void SetRegisterValue32(int register, uint value) 95 { 96 lock(cosimConnectionLock) 97 { 98 setRegisterValue = false; 99 cosimConnection.Send(this, ActionType.RegisterSet, (ulong)register, (ulong) value); 100 while(!setRegisterValue) // This kind of while loops are for socket communication 101 { 102 cosimConnection.HandleMessage(); 103 } 104 } 105 } 106 GetRegisterValue32(int register)107 public virtual uint GetRegisterValue32(int register) 108 { 109 lock(cosimConnectionLock) 110 { 111 gotRegisterValue = false; 112 cosimConnection.Send(this, ActionType.RegisterGet, (ulong)register, 0); 113 while(!gotRegisterValue) 114 { 115 cosimConnection.HandleMessage(); 116 } 117 return (uint)registerValue; 118 } 119 } 120 ExecuteInstructions(ulong numberOfInstructionsToExecute, out ulong numberOfExecutedInstructions)121 public override ExecutionResult ExecuteInstructions(ulong numberOfInstructionsToExecute, out ulong numberOfExecutedInstructions) 122 { 123 instructionsExecutedThisRound = 0UL; 124 125 try 126 { 127 lock(cosimConnectionLock) 128 { 129 if (IsSingleStepMode) 130 { 131 while(instructionsExecutedThisRound < 1) 132 { 133 gotStep = false; 134 cosimConnection.Send(this, ActionType.Step, 0, 1); 135 while(!gotStep) 136 { 137 cosimConnection.HandleMessage(); 138 } 139 } 140 } 141 else 142 { 143 ticksProcessed = false; 144 cosimConnection.Send(this, ActionType.TickClock, 0, numberOfInstructionsToExecute); 145 while(!ticksProcessed) 146 { 147 cosimConnection.HandleMessage(); 148 } 149 } 150 } 151 } 152 catch(Exception) 153 { 154 this.NoisyLog("CPU exception detected, halting."); 155 InvokeHalted(new HaltArguments(HaltReason.Abort, this)); 156 return ExecutionResult.Aborted; 157 } 158 finally 159 { 160 numberOfExecutedInstructions = instructionsExecutedThisRound; 161 totalExecutedInstructions += instructionsExecutedThisRound; 162 } 163 164 return ExecutionResult.Ok; 165 } 166 OnConnectionAttached(CoSimulationConnection connection)167 public virtual void OnConnectionAttached(CoSimulationConnection connection) 168 { 169 cosimConnection.OnReceive += HandleReceived; 170 } 171 OnConnectionDetached(CoSimulationConnection connection)172 public virtual void OnConnectionDetached(CoSimulationConnection connection) 173 { 174 cosimConnection.OnReceive -= HandleReceived; 175 } 176 177 public override ExecutionMode ExecutionMode 178 { 179 get => executionMode; 180 set 181 { 182 lock(singleStepSynchronizer.Guard) 183 { 184 if(executionMode == value) 185 { 186 return; 187 } 188 189 executionMode = value; 190 191 gotSingleStepMode = false; 192 lock(cosimConnectionLock) 193 { 194 switch(executionMode) 195 { 196 case ExecutionMode.Continuous: 197 cosimConnection.Send(this, ActionType.SingleStepMode, 0, 0); 198 break; 199 case ExecutionMode.SingleStep: 200 cosimConnection.Send(this, ActionType.SingleStepMode, 0, 1); 201 break; 202 } 203 204 while(!gotSingleStepMode) 205 { 206 cosimConnection.HandleMessage(); 207 } 208 } 209 210 singleStepSynchronizer.Enabled = IsSingleStepMode; 211 UpdateHaltedState(); 212 } 213 } 214 } 215 216 public override ulong ExecutedInstructions => totalExecutedInstructions; 217 InitializeRegisters()218 protected abstract void InitializeRegisters(); 219 HandleReceived(ProtocolMessage message)220 protected bool HandleReceived(ProtocolMessage message) 221 { 222 switch(message.ActionId) 223 { 224 case ActionType.TickClock: 225 ticksProcessed = true; 226 instructionsExecutedThisRound = message.Data; 227 return true; 228 case ActionType.IsHalted: 229 isHaltedRequested = message.Data > 0 ? true : false; 230 this.NoisyLog("isHaltedRequested: {0}", isHaltedRequested); 231 return true; 232 case ActionType.RegisterGet: 233 registerValue = message.Data; 234 gotRegisterValue = true; 235 return true; 236 case ActionType.RegisterSet: 237 setRegisterValue = true; 238 return true; 239 case ActionType.SingleStepMode: 240 gotSingleStepMode = true; 241 return true; 242 case ActionType.Step: 243 gotStep = true; 244 instructionsExecutedThisRound = message.Data; 245 return true; 246 default: 247 break; 248 } 249 250 return false; 251 } 252 253 public string SimulationFilePathLinux 254 { 255 get => SimulationFilePath; 256 set 257 { 258 #if PLATFORM_LINUX 259 SimulationFilePath = value; 260 #endif 261 } 262 } 263 264 public string SimulationFilePathWindows 265 { 266 get => SimulationFilePath; 267 set 268 { 269 #if PLATFORM_WINDOWS 270 SimulationFilePath = value; 271 #endif 272 } 273 } 274 275 public string SimulationFilePathMacOS 276 { 277 get => SimulationFilePath; 278 set 279 { 280 #if PLATFORM_OSX 281 SimulationFilePath = value; 282 #endif 283 } 284 } 285 286 public string SimulationFilePath 287 { 288 get => cosimConnection.SimulationFilePath; 289 set 290 { 291 if(!String.IsNullOrWhiteSpace(value)) 292 { 293 cosimConnection.SimulationFilePath = value; 294 } 295 } 296 } 297 298 public int RenodeToCosimIndex { get; } 299 public int CosimToRenodeIndex { get; } 300 301 protected readonly object cosimConnectionLock = new object(); 302 303 private readonly CoSimulationConnection cosimConnection; 304 305 private ulong registerValue; 306 307 private bool gotRegisterValue; 308 private bool setRegisterValue; 309 private bool gotSingleStepMode; 310 private bool gotStep; 311 private ulong instructionsExecutedThisRound; 312 private ulong totalExecutedInstructions; 313 private bool ticksProcessed; 314 } 315 } 316