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 8 #ifndef Cpu_h 9 #define Cpu_h 10 11 #include "../renode.h" 12 #include "../renode_bus.h" 13 #include "cpu-interface.h" 14 15 class CpuAgent : public RenodeAgent 16 { 17 public: 18 using RenodeAgent::RenodeAgent; 19 addCPU(DebuggableCPU * cpu)20 void addCPU(DebuggableCPU *cpu) 21 { 22 this->cpu = cpu; 23 } 24 tick(bool countEnable,uint64_t steps)25 void tick(bool countEnable, uint64_t steps) override 26 { 27 for (size_t i = 0; i < steps; i++) 28 { 29 for (auto &bus : initatorInterfaces) 30 { 31 bus->readHandler(); 32 bus->writeHandler(); 33 } 34 cpu->clkHigh(); 35 cpu->evaluateModel(); 36 cpu->clkLow(); 37 cpu->evaluateModel(); 38 39 for (auto &bus : initatorInterfaces) 40 bus->clearSignals(); 41 } 42 if (countEnable) 43 tickCounter += steps; 44 } 45 handleRequest(Protocol * message)46 void handleRequest(Protocol *message) override 47 { 48 switch (message->actionId) 49 { 50 case interrupt: 51 cpu->onGPIO(message->addr, message->value); 52 break; 53 54 case registerGet: 55 communicationChannel->sendSender(Protocol(registerGet, message->addr, getRegister(message->addr))); 56 break; 57 58 case registerSet: 59 setRegister(message->addr, message->value); 60 communicationChannel->sendSender(Protocol(registerSet, 0, 0)); 61 break; 62 63 case singleStepMode: 64 if (message->value) 65 { 66 if (!inSingleStepMode) 67 enterSingleStepMode(); 68 } 69 else 70 { 71 if (inSingleStepMode) 72 exitSingleStepMode(); 73 } 74 communicationChannel->sendSender(Protocol(singleStepMode, 0, 0)); 75 break; 76 77 case tickClock: 78 { 79 int64_t ticks = 0; 80 if (!inSingleStepMode) 81 { 82 ticks = message->value - tickCounter; 83 if (ticks < 0) 84 tickCounter -= message->value; 85 else 86 { 87 tick(false, ticks); 88 tickCounter = 0; 89 } 90 91 bool halted = cpu->isHalted(); 92 if (wasHalted != halted) 93 { 94 communicationChannel->sendSender(Protocol(isHalted, 0, halted)); 95 wasHalted = halted; 96 } 97 } 98 ticks = ticks > 0 ? ticks : 0; 99 communicationChannel->sendSender(Protocol(tickClock, 0, ticks)); 100 } 101 break; 102 103 case step: 104 { 105 int64_t ticks = 0; 106 if (inSingleStepMode) 107 { 108 ticks = message->value - tickCounter; 109 if (ticks < 0) 110 tickCounter -= message->value; 111 else 112 { 113 for (int64_t i = 0; i < ticks; i++) 114 { 115 waitForNonDebugProgramInstruction(); 116 waitForFirstDebugProgramInstruction(); 117 } 118 tickCounter = 0; 119 } 120 121 ticks = ticks > 0 ? ticks : 0; 122 communicationChannel->sendSender(Protocol(step, 0, ticks)); 123 } 124 } 125 break; 126 127 default: 128 RenodeAgent::handleRequest(message); 129 break; 130 } 131 } 132 reset()133 void reset() override 134 { 135 cpu->reset(); 136 } 137 getRegister(uint64_t id)138 uint64_t getRegister(uint64_t id) 139 { 140 log(LOG_LEVEL_DEBUG, "Start getRegister"); 141 debugProgram = cpu->getRegisterGetProgram(id); 142 143 cpu->debugRequest(true); 144 waitForFirstDebugProgramInstruction(); 145 if (!inSingleStepMode) 146 cpu->debugRequest(false); 147 runDebugProgram(true); 148 149 log(LOG_LEVEL_DEBUG, "End getRegister"); 150 return debugProgramReturnValue; 151 } 152 setRegister(uint64_t id,uint64_t value)153 void setRegister(uint64_t id, uint64_t value) 154 { 155 log(LOG_LEVEL_DEBUG, "Start setRegister"); 156 debugProgram = cpu->getRegisterSetProgram(id, value); 157 158 cpu->debugRequest(true); 159 waitForFirstDebugProgramInstruction(); 160 if (!inSingleStepMode) 161 cpu->debugRequest(false); 162 runDebugProgram(false); 163 164 log(LOG_LEVEL_DEBUG, "End setRegister"); 165 } 166 enterSingleStepMode()167 void enterSingleStepMode() 168 { 169 log(LOG_LEVEL_DEBUG, "Start enterSingleStepMode"); 170 debugProgram = cpu->getEnterSingleStepModeProgram(); 171 172 cpu->debugRequest(true); 173 waitForFirstDebugProgramInstruction(); 174 cpu->debugRequest(false); 175 runDebugProgram(false); 176 177 log(LOG_LEVEL_DEBUG, "End enterSingleStepMode"); 178 inSingleStepMode = true; 179 debugProgram = cpu->getSingleStepModeProgram(); 180 } 181 exitSingleStepMode()182 void exitSingleStepMode() 183 { 184 log(LOG_LEVEL_DEBUG, "Start exitSingleStepMode"); 185 inSingleStepMode = false; 186 debugProgram = cpu->getExitSingleStepModeProgram(); 187 188 cpu->debugRequest(true); 189 waitForFirstDebugProgramInstruction(); 190 cpu->debugRequest(false); 191 runDebugProgram(false); 192 193 log(LOG_LEVEL_DEBUG, "End exitSingleStepMode"); 194 waitForNonDebugProgramInstruction(); 195 debugProgram = {}; 196 } 197 pushByteToAgent(uint64_t addr,uint8_t value)198 void pushByteToAgent(uint64_t addr, uint8_t value) override 199 { 200 if (!inDebugMode) 201 RenodeAgent::pushByteToAgent(addr, value); 202 else 203 debugProgramReturn(addr, value); 204 } 205 pushWordToAgent(uint64_t addr,uint16_t value)206 void pushWordToAgent(uint64_t addr, uint16_t value) override 207 { 208 if (!inDebugMode) 209 RenodeAgent::pushWordToAgent(addr, value); 210 else 211 debugProgramReturn(addr, value); 212 } 213 pushDoubleWordToAgent(uint64_t addr,uint32_t value)214 void pushDoubleWordToAgent(uint64_t addr, uint32_t value) override 215 { 216 if (!inDebugMode) 217 RenodeAgent::pushDoubleWordToAgent(addr, value); 218 else 219 debugProgramReturn(addr, value); 220 } 221 222 requestDoubleWordFromAgent(uint64_t addr)223 uint64_t requestDoubleWordFromAgent(uint64_t addr) override 224 { 225 if (!inDebugMode) 226 { 227 debugProgramOrPrefetch = debugProgramOrPrefetch && (lastRequestAddress + 4 == addr); 228 lastRequestAddress = addr; 229 230 if (inSingleStepMode && inDebugProgramRange(addr)) 231 { 232 debugProgramOrPrefetch = true; 233 return debugProgram.memory[(addr - debugProgram.address) / 4]; 234 } 235 else 236 { 237 if (debugProgramOrPrefetch) 238 return debugProgram.memory.back(); // CPU is prefetching debug program 239 else 240 return RenodeAgent::requestDoubleWordFromAgent(addr); 241 } 242 } 243 else 244 { 245 debugProgramOrPrefetch = true; 246 lastRequestAddress = addr; 247 248 if (inDebugProgramRange(addr)) 249 { 250 debugProgramReadCount++; 251 uint64_t idx = (addr - debugProgram.address) / 4; 252 if (idx + 1 == debugProgram.memory.size()) 253 debugProgramReadLastInstruction = true; 254 return debugProgram.memory[idx]; 255 } 256 else 257 return debugProgram.memory.back(); // CPU is probably prefetching, last program instruction should be debug return instruction 258 } 259 } 260 261 private: waitForFirstDebugProgramInstruction()262 void waitForFirstDebugProgramInstruction() 263 { 264 bool adressSpecified = false; 265 266 while (true) 267 { 268 for (auto &bus : initatorInterfaces) 269 { 270 log(LOG_LEVEL_DEBUG, "Waiting for first debug program instruction access"); 271 if (bus->hasSpecifiedAdress() && bus->getSpecifiedAdress() == debugProgram.address) 272 { 273 log(LOG_LEVEL_DEBUG, "Finished waiting"); 274 adressSpecified = true; 275 break; 276 } 277 } 278 if (adressSpecified) 279 break; 280 tick(false, 1); 281 tickCounter++; 282 } 283 } 284 waitForNonDebugProgramInstruction()285 void waitForNonDebugProgramInstruction() 286 { 287 bool adressSpecified = false; 288 289 while (true) 290 { 291 for (auto &bus : initatorInterfaces) 292 { 293 log(LOG_LEVEL_DEBUG, "Waiting for non debug program instruction access"); 294 if (bus->hasSpecifiedAdress() && !inDebugProgramRange(bus->getSpecifiedAdress()) && !debugProgramOrPrefetch) 295 { 296 log(LOG_LEVEL_DEBUG, "Finished waiting"); 297 adressSpecified = true; 298 break; 299 } 300 } 301 if (adressSpecified) 302 break; 303 tick(false, 1); 304 tickCounter++; 305 } 306 } 307 runDebugProgram(bool withReturnSuccess)308 void runDebugProgram(bool withReturnSuccess) 309 { 310 if (inSingleStepMode) // Re-enter debug mode after running program 311 cpu->debugRequest(true); 312 313 inDebugMode = true; 314 315 debugProgramReadCount = 0; 316 debugProgramReturnSuccess = false; 317 debugProgramReadLastInstruction = false; 318 319 while (debugProgramReadCount < debugProgram.readCount || (!debugProgramReturnSuccess && withReturnSuccess) || !debugProgramReadLastInstruction) 320 { 321 log(LOG_LEVEL_DEBUG, "runDebugProgram tick start"); 322 tick(false, 1); 323 log(LOG_LEVEL_DEBUG, "runDebugProgram tick end"); 324 } 325 326 inDebugMode = false; 327 328 if (inSingleStepMode) 329 { 330 waitForFirstDebugProgramInstruction(); 331 cpu->debugRequest(false); 332 debugProgram = cpu->getSingleStepModeProgram(); 333 } 334 } 335 debugProgramReturn(uint64_t addr,uint64_t value)336 void debugProgramReturn(uint64_t addr, uint64_t value) 337 { 338 if (addr != 0) 339 throw "debug program writes to non 0 address"; 340 if (debugProgramReturnSuccess) 341 throw "debug program have already written return value"; 342 343 debugProgramReturnValue = value; 344 debugProgramReturnSuccess = true; 345 } 346 inDebugProgramRange(uint64_t addr)347 bool inDebugProgramRange(uint64_t addr) 348 { 349 return addr >= debugProgram.address && addr < debugProgram.address + debugProgram.memory.size() * 4; 350 } 351 352 DebuggableCPU *cpu = nullptr; 353 DebuggableCPU::DebugProgram debugProgram; 354 uint64_t debugProgramReadCount = 0; 355 uint64_t debugProgramReturnValue; 356 int64_t tickCounter = 0; 357 uint64_t lastRequestAddress = 0; 358 bool debugProgramReturnSuccess = false; 359 bool debugProgramReadLastInstruction = false; 360 bool wasHalted = false; 361 362 bool inDebugMode = false; 363 bool inSingleStepMode = false; 364 365 bool debugProgramOrPrefetch = false; 366 }; 367 368 #endif 369