cpu_core.cpp (106738B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "cpu_core.h" 5 #include "bus.h" 6 #include "cpu_code_cache_private.h" 7 #include "cpu_core_private.h" 8 #include "cpu_disasm.h" 9 #include "cpu_pgxp.h" 10 #include "cpu_recompiler_thunks.h" 11 #include "gte.h" 12 #include "host.h" 13 #include "pcdrv.h" 14 #include "settings.h" 15 #include "system.h" 16 #include "timing_event.h" 17 18 #include "util/state_wrapper.h" 19 20 #include "common/align.h" 21 #include "common/fastjmp.h" 22 #include "common/file_system.h" 23 #include "common/log.h" 24 25 #include <cstdio> 26 27 Log_SetChannel(CPU::Core); 28 29 namespace CPU { 30 static bool ShouldUseInterpreter(); 31 static void UpdateLoadDelay(); 32 static void Branch(u32 target); 33 static void FlushLoadDelay(); 34 static void FlushPipeline(); 35 36 static u32 GetExceptionVector(bool debug_exception = false); 37 static void RaiseException(u32 CAUSE_bits, u32 EPC, u32 vector); 38 39 static u32 ReadReg(Reg rs); 40 static void WriteReg(Reg rd, u32 value); 41 static void WriteRegDelayed(Reg rd, u32 value); 42 43 static u32 ReadCop0Reg(Cop0Reg reg); 44 static void WriteCop0Reg(Cop0Reg reg, u32 value); 45 46 static void DispatchCop0Breakpoint(); 47 static bool IsCop0ExecutionBreakpointUnmasked(); 48 static void Cop0ExecutionBreakpointCheck(); 49 template<MemoryAccessType type> 50 static void Cop0DataBreakpointCheck(VirtualMemoryAddress address); 51 52 static BreakpointList& GetBreakpointList(BreakpointType type); 53 static bool CheckBreakpointList(BreakpointType type, VirtualMemoryAddress address); 54 static void ExecutionBreakpointCheck(); 55 template<MemoryAccessType type> 56 static void MemoryBreakpointCheck(VirtualMemoryAddress address); 57 58 #ifdef _DEBUG 59 static void TracePrintInstruction(); 60 #endif 61 62 static void DisassembleAndPrint(u32 addr, bool regs, const char* prefix); 63 static void PrintInstruction(u32 bits, u32 pc, bool regs, const char* prefix); 64 static void LogInstruction(u32 bits, u32 pc, bool regs); 65 66 static void HandleWriteSyscall(); 67 static void HandlePutcSyscall(); 68 static void HandlePutsSyscall(); 69 [[noreturn]] static void ExecuteInterpreter(); 70 71 template<PGXPMode pgxp_mode, bool debug> 72 static void ExecuteInstruction(); 73 74 template<PGXPMode pgxp_mode, bool debug> 75 [[noreturn]] static void ExecuteImpl(); 76 77 static bool FetchInstruction(); 78 static bool FetchInstructionForInterpreterFallback(); 79 template<bool add_ticks, bool icache_read = false, u32 word_count = 1, bool raise_exceptions> 80 static bool DoInstructionRead(PhysicalMemoryAddress address, void* data); 81 template<MemoryAccessType type, MemoryAccessSize size> 82 static bool DoSafeMemoryAccess(VirtualMemoryAddress address, u32& value); 83 template<MemoryAccessType type, MemoryAccessSize size> 84 static bool DoAlignmentCheck(VirtualMemoryAddress address); 85 static bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value); 86 static bool ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value); 87 static bool ReadMemoryWord(VirtualMemoryAddress addr, u32* value); 88 static bool WriteMemoryByte(VirtualMemoryAddress addr, u32 value); 89 static bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u32 value); 90 static bool WriteMemoryWord(VirtualMemoryAddress addr, u32 value); 91 92 alignas(HOST_CACHE_LINE_SIZE) State g_state; 93 bool TRACE_EXECUTION = false; 94 95 static fastjmp_buf s_jmp_buf; 96 97 static std::FILE* s_log_file = nullptr; 98 static bool s_log_file_opened = false; 99 static bool s_trace_to_log = false; 100 101 static constexpr u32 INVALID_BREAKPOINT_PC = UINT32_C(0xFFFFFFFF); 102 static std::array<std::vector<Breakpoint>, static_cast<u32>(BreakpointType::Count)> s_breakpoints; 103 static u32 s_breakpoint_counter = 1; 104 static u32 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; 105 static bool s_single_step = false; 106 static bool s_break_after_instruction = false; 107 } // namespace CPU 108 109 bool CPU::IsTraceEnabled() 110 { 111 return s_trace_to_log; 112 } 113 114 void CPU::StartTrace() 115 { 116 if (s_trace_to_log) 117 return; 118 119 s_trace_to_log = true; 120 if (UpdateDebugDispatcherFlag()) 121 System::InterruptExecution(); 122 } 123 124 void CPU::StopTrace() 125 { 126 if (!s_trace_to_log) 127 return; 128 129 if (s_log_file) 130 std::fclose(s_log_file); 131 132 s_log_file_opened = false; 133 s_trace_to_log = false; 134 if (UpdateDebugDispatcherFlag()) 135 System::InterruptExecution(); 136 } 137 138 void CPU::WriteToExecutionLog(const char* format, ...) 139 { 140 if (!s_log_file_opened) 141 { 142 s_log_file = FileSystem::OpenCFile("cpu_log.txt", "wb"); 143 s_log_file_opened = true; 144 } 145 146 if (s_log_file) 147 { 148 std::va_list ap; 149 va_start(ap, format); 150 std::vfprintf(s_log_file, format, ap); 151 va_end(ap); 152 153 #ifdef _DEBUG 154 std::fflush(s_log_file); 155 #endif 156 } 157 } 158 159 void CPU::Initialize() 160 { 161 // From nocash spec. 162 g_state.cop0_regs.PRID = UINT32_C(0x00000002); 163 164 g_state.using_debug_dispatcher = false; 165 g_state.using_interpreter = ShouldUseInterpreter(); 166 for (BreakpointList& bps : s_breakpoints) 167 bps.clear(); 168 s_breakpoint_counter = 1; 169 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; 170 s_single_step = false; 171 s_break_after_instruction = false; 172 173 UpdateMemoryPointers(); 174 UpdateDebugDispatcherFlag(); 175 176 GTE::Initialize(); 177 } 178 179 void CPU::Shutdown() 180 { 181 ClearBreakpoints(); 182 StopTrace(); 183 } 184 185 void CPU::Reset() 186 { 187 g_state.exception_raised = false; 188 g_state.bus_error = false; 189 190 g_state.regs = {}; 191 192 g_state.cop0_regs.BPC = 0; 193 g_state.cop0_regs.BDA = 0; 194 g_state.cop0_regs.TAR = 0; 195 g_state.cop0_regs.BadVaddr = 0; 196 g_state.cop0_regs.BDAM = 0; 197 g_state.cop0_regs.BPCM = 0; 198 g_state.cop0_regs.EPC = 0; 199 g_state.cop0_regs.sr.bits = 0; 200 g_state.cop0_regs.cause.bits = 0; 201 202 ClearICache(); 203 UpdateMemoryPointers(); 204 UpdateDebugDispatcherFlag(); 205 206 GTE::Reset(); 207 208 if (g_settings.gpu_pgxp_enable) 209 PGXP::Reset(); 210 211 // This consumes cycles, so do it first. 212 SetPC(RESET_VECTOR); 213 214 g_state.pending_ticks = 0; 215 g_state.downcount = 0; 216 } 217 218 bool CPU::DoState(StateWrapper& sw) 219 { 220 sw.Do(&g_state.pending_ticks); 221 sw.Do(&g_state.downcount); 222 sw.DoArray(g_state.regs.r, static_cast<u32>(Reg::count)); 223 sw.Do(&g_state.pc); 224 sw.Do(&g_state.npc); 225 sw.Do(&g_state.cop0_regs.BPC); 226 sw.Do(&g_state.cop0_regs.BDA); 227 sw.Do(&g_state.cop0_regs.TAR); 228 sw.Do(&g_state.cop0_regs.BadVaddr); 229 sw.Do(&g_state.cop0_regs.BDAM); 230 sw.Do(&g_state.cop0_regs.BPCM); 231 sw.Do(&g_state.cop0_regs.EPC); 232 sw.Do(&g_state.cop0_regs.PRID); 233 sw.Do(&g_state.cop0_regs.sr.bits); 234 sw.Do(&g_state.cop0_regs.cause.bits); 235 sw.Do(&g_state.cop0_regs.dcic.bits); 236 sw.Do(&g_state.next_instruction.bits); 237 sw.Do(&g_state.current_instruction.bits); 238 sw.Do(&g_state.current_instruction_pc); 239 sw.Do(&g_state.current_instruction_in_branch_delay_slot); 240 sw.Do(&g_state.current_instruction_was_branch_taken); 241 sw.Do(&g_state.next_instruction_is_branch_delay_slot); 242 sw.Do(&g_state.branch_was_taken); 243 sw.Do(&g_state.exception_raised); 244 sw.DoEx(&g_state.bus_error, 61, false); 245 if (sw.GetVersion() < 59) [[unlikely]] 246 { 247 bool interrupt_delay; 248 sw.Do(&interrupt_delay); 249 } 250 sw.Do(&g_state.load_delay_reg); 251 sw.Do(&g_state.load_delay_value); 252 sw.Do(&g_state.next_load_delay_reg); 253 sw.Do(&g_state.next_load_delay_value); 254 255 // Compatibility with old states. 256 if (sw.GetVersion() < 59) [[unlikely]] 257 { 258 g_state.load_delay_reg = 259 static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count))); 260 g_state.next_load_delay_reg = 261 static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count))); 262 } 263 264 sw.Do(&g_state.cache_control.bits); 265 sw.DoBytes(g_state.scratchpad.data(), g_state.scratchpad.size()); 266 267 if (!GTE::DoState(sw)) [[unlikely]] 268 return false; 269 270 if (sw.GetVersion() < 48) [[unlikely]] 271 { 272 DebugAssert(sw.IsReading()); 273 ClearICache(); 274 } 275 else 276 { 277 sw.Do(&g_state.icache_tags); 278 sw.Do(&g_state.icache_data); 279 } 280 281 bool using_interpreter = g_state.using_interpreter; 282 sw.DoEx(&using_interpreter, 67, g_state.using_interpreter); 283 284 if (sw.IsReading()) 285 { 286 // Since the recompilers do not use npc/next_instruction, and the icache emulation doesn't actually fill the data, 287 // only the tags, if we save state with the recompiler, then load state with the interpreter, we're most likely 288 // going to crash. Clear both in the case that we are switching. 289 if (using_interpreter != g_state.using_interpreter) 290 { 291 WARNING_LOG("Current execution mode does not match save state. Resetting icache state."); 292 ExecutionModeChanged(); 293 } 294 295 UpdateMemoryPointers(); 296 g_state.gte_completion_tick = 0; 297 } 298 299 return !sw.HasError(); 300 } 301 302 ALWAYS_INLINE_RELEASE bool CPU::ShouldUseInterpreter() 303 { 304 // Currently, any breakpoints require the interpreter. 305 return (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter || g_state.using_debug_dispatcher); 306 } 307 308 void CPU::SetPC(u32 new_pc) 309 { 310 DebugAssert(Common::IsAlignedPow2(new_pc, 4)); 311 g_state.npc = new_pc; 312 FlushPipeline(); 313 } 314 315 ALWAYS_INLINE_RELEASE void CPU::Branch(u32 target) 316 { 317 if (!Common::IsAlignedPow2(target, 4)) 318 { 319 // The BadVaddr and EPC must be set to the fetching address, not the instruction about to execute. 320 g_state.cop0_regs.BadVaddr = target; 321 RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::AdEL, false, false, 0), target); 322 return; 323 } 324 325 g_state.npc = target; 326 g_state.branch_was_taken = true; 327 } 328 329 ALWAYS_INLINE_RELEASE u32 CPU::GetExceptionVector(bool debug_exception /* = false*/) 330 { 331 const u32 base = g_state.cop0_regs.sr.BEV ? UINT32_C(0xbfc00100) : UINT32_C(0x80000000); 332 return base | (debug_exception ? UINT32_C(0x00000040) : UINT32_C(0x00000080)); 333 } 334 335 ALWAYS_INLINE_RELEASE void CPU::RaiseException(u32 CAUSE_bits, u32 EPC, u32 vector) 336 { 337 g_state.cop0_regs.EPC = EPC; 338 g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK) | 339 (CAUSE_bits & Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK); 340 341 #ifdef _DEBUG 342 if (g_state.cop0_regs.cause.Excode != Exception::INT && g_state.cop0_regs.cause.Excode != Exception::Syscall && 343 g_state.cop0_regs.cause.Excode != Exception::BP) 344 { 345 DEV_LOG("Exception {} at 0x{:08X} (epc=0x{:08X}, BD={}, CE={})", 346 static_cast<u8>(g_state.cop0_regs.cause.Excode.GetValue()), g_state.current_instruction_pc, 347 g_state.cop0_regs.EPC, g_state.cop0_regs.cause.BD ? "true" : "false", 348 g_state.cop0_regs.cause.CE.GetValue()); 349 DisassembleAndPrint(g_state.current_instruction_pc, 4u, 0u); 350 if (s_trace_to_log) 351 { 352 CPU::WriteToExecutionLog("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)\n", 353 static_cast<u8>(g_state.cop0_regs.cause.Excode.GetValue()), 354 g_state.current_instruction_pc, g_state.cop0_regs.EPC, 355 g_state.cop0_regs.cause.BD ? "true" : "false", g_state.cop0_regs.cause.CE.GetValue()); 356 } 357 } 358 #endif 359 360 if (g_state.cop0_regs.cause.BD) 361 { 362 // TAR is set to the address which was being fetched in this instruction, or the next instruction to execute if the 363 // exception hadn't occurred in the delay slot. 364 g_state.cop0_regs.EPC -= UINT32_C(4); 365 g_state.cop0_regs.TAR = g_state.pc; 366 } 367 368 // current -> previous, switch to kernel mode and disable interrupts 369 g_state.cop0_regs.sr.mode_bits <<= 2; 370 371 // flush the pipeline - we don't want to execute the previously fetched instruction 372 g_state.npc = vector; 373 g_state.exception_raised = true; 374 FlushPipeline(); 375 } 376 377 ALWAYS_INLINE_RELEASE void CPU::DispatchCop0Breakpoint() 378 { 379 // When a breakpoint address match occurs the PSX jumps to 80000040h (ie. unlike normal exceptions, not to 80000080h). 380 // The Excode value in the CAUSE register is set to 09h (same as BREAK opcode), and EPC contains the return address, 381 // as usually. One of the first things to be done in the exception handler is to disable breakpoints (eg. if the 382 // any-jump break is enabled, then it must be disabled BEFORE jumping from 80000040h to the actual exception handler). 383 RaiseException(Cop0Registers::CAUSE::MakeValueForException( 384 Exception::BP, g_state.current_instruction_in_branch_delay_slot, 385 g_state.current_instruction_was_branch_taken, g_state.current_instruction.cop.cop_n), 386 g_state.current_instruction_pc, GetExceptionVector(true)); 387 } 388 389 void CPU::RaiseException(u32 CAUSE_bits, u32 EPC) 390 { 391 RaiseException(CAUSE_bits, EPC, GetExceptionVector()); 392 } 393 394 void CPU::RaiseException(Exception excode) 395 { 396 RaiseException(Cop0Registers::CAUSE::MakeValueForException(excode, g_state.current_instruction_in_branch_delay_slot, 397 g_state.current_instruction_was_branch_taken, 398 g_state.current_instruction.cop.cop_n), 399 g_state.current_instruction_pc, GetExceptionVector()); 400 } 401 402 void CPU::RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits) 403 { 404 if (g_settings.pcdrv_enable) 405 { 406 // Load delays need to be flushed, because the break HLE might read a register which 407 // is currently being loaded, and on real hardware there isn't a hazard here. 408 FlushLoadDelay(); 409 410 if (PCDrv::HandleSyscall(instruction_bits, g_state.regs)) 411 { 412 // immediately return 413 g_state.npc = EPC + 4; 414 FlushPipeline(); 415 return; 416 } 417 } 418 419 // normal exception 420 RaiseException(CAUSE_bits, EPC, GetExceptionVector()); 421 } 422 423 void CPU::SetIRQRequest(bool state) 424 { 425 // Only uses bit 10. 426 constexpr u32 bit = (1u << 10); 427 const u32 old_cause = g_state.cop0_regs.cause.bits; 428 g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~bit) | (state ? bit : 0u); 429 if (old_cause ^ g_state.cop0_regs.cause.bits && state) 430 CheckForPendingInterrupt(); 431 } 432 433 ALWAYS_INLINE_RELEASE void CPU::UpdateLoadDelay() 434 { 435 // the old value is needed in case the delay slot instruction overwrites the same register 436 g_state.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value; 437 g_state.load_delay_reg = g_state.next_load_delay_reg; 438 g_state.load_delay_value = g_state.next_load_delay_value; 439 g_state.next_load_delay_reg = Reg::count; 440 } 441 442 ALWAYS_INLINE_RELEASE void CPU::FlushLoadDelay() 443 { 444 g_state.next_load_delay_reg = Reg::count; 445 g_state.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value; 446 g_state.load_delay_reg = Reg::count; 447 } 448 449 ALWAYS_INLINE_RELEASE void CPU::FlushPipeline() 450 { 451 // loads are flushed 452 FlushLoadDelay(); 453 454 // not in a branch delay slot 455 g_state.branch_was_taken = false; 456 g_state.next_instruction_is_branch_delay_slot = false; 457 g_state.current_instruction_pc = g_state.pc; 458 459 // prefetch the next instruction 460 FetchInstruction(); 461 462 // and set it as the next one to execute 463 g_state.current_instruction.bits = g_state.next_instruction.bits; 464 g_state.current_instruction_in_branch_delay_slot = false; 465 g_state.current_instruction_was_branch_taken = false; 466 } 467 468 ALWAYS_INLINE u32 CPU::ReadReg(Reg rs) 469 { 470 return g_state.regs.r[static_cast<u8>(rs)]; 471 } 472 473 ALWAYS_INLINE void CPU::WriteReg(Reg rd, u32 value) 474 { 475 g_state.regs.r[static_cast<u8>(rd)] = value; 476 g_state.load_delay_reg = (rd == g_state.load_delay_reg) ? Reg::count : g_state.load_delay_reg; 477 478 // prevent writes to $zero from going through - better than branching/cmov 479 g_state.regs.zero = 0; 480 } 481 482 ALWAYS_INLINE_RELEASE void CPU::WriteRegDelayed(Reg rd, u32 value) 483 { 484 DebugAssert(g_state.next_load_delay_reg == Reg::count); 485 if (rd == Reg::zero) 486 return; 487 488 // double load delays ignore the first value 489 if (g_state.load_delay_reg == rd) 490 g_state.load_delay_reg = Reg::count; 491 492 // save the old value, if something else overwrites this reg we want to preserve it 493 g_state.next_load_delay_reg = rd; 494 g_state.next_load_delay_value = value; 495 } 496 497 ALWAYS_INLINE_RELEASE u32 CPU::ReadCop0Reg(Cop0Reg reg) 498 { 499 switch (reg) 500 { 501 case Cop0Reg::BPC: 502 return g_state.cop0_regs.BPC; 503 504 case Cop0Reg::BPCM: 505 return g_state.cop0_regs.BPCM; 506 507 case Cop0Reg::BDA: 508 return g_state.cop0_regs.BDA; 509 510 case Cop0Reg::BDAM: 511 return g_state.cop0_regs.BDAM; 512 513 case Cop0Reg::DCIC: 514 return g_state.cop0_regs.dcic.bits; 515 516 case Cop0Reg::JUMPDEST: 517 return g_state.cop0_regs.TAR; 518 519 case Cop0Reg::BadVaddr: 520 return g_state.cop0_regs.BadVaddr; 521 522 case Cop0Reg::SR: 523 return g_state.cop0_regs.sr.bits; 524 525 case Cop0Reg::CAUSE: 526 return g_state.cop0_regs.cause.bits; 527 528 case Cop0Reg::EPC: 529 return g_state.cop0_regs.EPC; 530 531 case Cop0Reg::PRID: 532 return g_state.cop0_regs.PRID; 533 534 default: 535 return 0; 536 } 537 } 538 539 ALWAYS_INLINE_RELEASE void CPU::WriteCop0Reg(Cop0Reg reg, u32 value) 540 { 541 switch (reg) 542 { 543 case Cop0Reg::BPC: 544 { 545 g_state.cop0_regs.BPC = value; 546 DEV_LOG("COP0 BPC <- {:08X}", value); 547 } 548 break; 549 550 case Cop0Reg::BPCM: 551 { 552 g_state.cop0_regs.BPCM = value; 553 DEV_LOG("COP0 BPCM <- {:08X}", value); 554 if (UpdateDebugDispatcherFlag()) 555 ExitExecution(); 556 } 557 break; 558 559 case Cop0Reg::BDA: 560 { 561 g_state.cop0_regs.BDA = value; 562 DEV_LOG("COP0 BDA <- {:08X}", value); 563 } 564 break; 565 566 case Cop0Reg::BDAM: 567 { 568 g_state.cop0_regs.BDAM = value; 569 DEV_LOG("COP0 BDAM <- {:08X}", value); 570 } 571 break; 572 573 case Cop0Reg::JUMPDEST: 574 { 575 WARNING_LOG("Ignoring write to Cop0 JUMPDEST"); 576 } 577 break; 578 579 case Cop0Reg::DCIC: 580 { 581 g_state.cop0_regs.dcic.bits = 582 (g_state.cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) | (value & Cop0Registers::DCIC::WRITE_MASK); 583 DEV_LOG("COP0 DCIC <- {:08X} (now {:08X})", value, g_state.cop0_regs.dcic.bits); 584 if (UpdateDebugDispatcherFlag()) 585 ExitExecution(); 586 } 587 break; 588 589 case Cop0Reg::SR: 590 { 591 g_state.cop0_regs.sr.bits = 592 (g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK); 593 DEBUG_LOG("COP0 SR <- {:08X} (now {:08X})", value, g_state.cop0_regs.sr.bits); 594 UpdateMemoryPointers(); 595 CheckForPendingInterrupt(); 596 } 597 break; 598 599 case Cop0Reg::CAUSE: 600 { 601 g_state.cop0_regs.cause.bits = 602 (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK); 603 DEBUG_LOG("COP0 CAUSE <- {:08X} (now {:08X})", value, g_state.cop0_regs.cause.bits); 604 CheckForPendingInterrupt(); 605 } 606 break; 607 608 [[unlikely]] default : DEV_LOG("Unknown COP0 reg write {} ({:08X})", static_cast<u8>(reg), value); 609 break; 610 } 611 } 612 613 ALWAYS_INLINE_RELEASE bool CPU::IsCop0ExecutionBreakpointUnmasked() 614 { 615 static constexpr const u32 code_address_ranges[][2] = { 616 // KUSEG 617 {Bus::RAM_BASE, Bus::RAM_BASE | Bus::RAM_8MB_MASK}, 618 {Bus::BIOS_BASE, Bus::BIOS_BASE | Bus::BIOS_MASK}, 619 620 // KSEG0 621 {0x80000000u | Bus::RAM_BASE, 0x80000000u | Bus::RAM_BASE | Bus::RAM_8MB_MASK}, 622 {0x80000000u | Bus::BIOS_BASE, 0x80000000u | Bus::BIOS_BASE | Bus::BIOS_MASK}, 623 624 // KSEG1 625 {0xA0000000u | Bus::RAM_BASE, 0xA0000000u | Bus::RAM_BASE | Bus::RAM_8MB_MASK}, 626 {0xA0000000u | Bus::BIOS_BASE, 0xA0000000u | Bus::BIOS_BASE | Bus::BIOS_MASK}, 627 }; 628 629 const u32 bpc = g_state.cop0_regs.BPC; 630 const u32 bpcm = g_state.cop0_regs.BPCM; 631 const u32 masked_bpc = bpc & bpcm; 632 for (const auto [range_start, range_end] : code_address_ranges) 633 { 634 if (masked_bpc >= (range_start & bpcm) && masked_bpc <= (range_end & bpcm)) 635 return true; 636 } 637 638 return false; 639 } 640 641 ALWAYS_INLINE_RELEASE void CPU::Cop0ExecutionBreakpointCheck() 642 { 643 if (!g_state.cop0_regs.dcic.ExecutionBreakpointsEnabled()) 644 return; 645 646 const u32 pc = g_state.current_instruction_pc; 647 const u32 bpc = g_state.cop0_regs.BPC; 648 const u32 bpcm = g_state.cop0_regs.BPCM; 649 650 // Break condition is "((PC XOR BPC) AND BPCM)=0". 651 if (bpcm == 0 || ((pc ^ bpc) & bpcm) != 0u) 652 return; 653 654 DEV_LOG("Cop0 execution breakpoint at {:08X}", pc); 655 g_state.cop0_regs.dcic.status_any_break = true; 656 g_state.cop0_regs.dcic.status_bpc_code_break = true; 657 DispatchCop0Breakpoint(); 658 } 659 660 template<MemoryAccessType type> 661 ALWAYS_INLINE_RELEASE void CPU::Cop0DataBreakpointCheck(VirtualMemoryAddress address) 662 { 663 if constexpr (type == MemoryAccessType::Read) 664 { 665 if (!g_state.cop0_regs.dcic.DataReadBreakpointsEnabled()) 666 return; 667 } 668 else 669 { 670 if (!g_state.cop0_regs.dcic.DataWriteBreakpointsEnabled()) 671 return; 672 } 673 674 // Break condition is "((addr XOR BDA) AND BDAM)=0". 675 const u32 bda = g_state.cop0_regs.BDA; 676 const u32 bdam = g_state.cop0_regs.BDAM; 677 if (bdam == 0 || ((address ^ bda) & bdam) != 0u) 678 return; 679 680 DEV_LOG("Cop0 data breakpoint for {:08X} at {:08X}", address, g_state.current_instruction_pc); 681 682 g_state.cop0_regs.dcic.status_any_break = true; 683 g_state.cop0_regs.dcic.status_bda_data_break = true; 684 if constexpr (type == MemoryAccessType::Read) 685 g_state.cop0_regs.dcic.status_bda_data_read_break = true; 686 else 687 g_state.cop0_regs.dcic.status_bda_data_write_break = true; 688 689 DispatchCop0Breakpoint(); 690 } 691 692 #ifdef _DEBUG 693 694 void CPU::TracePrintInstruction() 695 { 696 const u32 pc = g_state.current_instruction_pc; 697 const u32 bits = g_state.current_instruction.bits; 698 699 TinyString instr; 700 TinyString comment; 701 DisassembleInstruction(&instr, pc, bits); 702 DisassembleInstructionComment(&comment, pc, bits); 703 if (!comment.empty()) 704 { 705 for (u32 i = instr.length(); i < 30; i++) 706 instr.append(' '); 707 instr.append("; "); 708 instr.append(comment); 709 } 710 711 std::printf("%08x: %08x %s\n", pc, bits, instr.c_str()); 712 } 713 714 #endif 715 716 void CPU::PrintInstruction(u32 bits, u32 pc, bool regs, const char* prefix) 717 { 718 TinyString instr; 719 DisassembleInstruction(&instr, pc, bits); 720 if (regs) 721 { 722 TinyString comment; 723 DisassembleInstructionComment(&comment, pc, bits); 724 if (!comment.empty()) 725 { 726 for (u32 i = instr.length(); i < 30; i++) 727 instr.append(' '); 728 instr.append("; "); 729 instr.append(comment); 730 } 731 } 732 733 DEV_LOG("{}{:08x}: {:08x} {}", prefix, pc, bits, instr); 734 } 735 736 void CPU::LogInstruction(u32 bits, u32 pc, bool regs) 737 { 738 TinyString instr; 739 DisassembleInstruction(&instr, pc, bits); 740 if (regs) 741 { 742 TinyString comment; 743 DisassembleInstructionComment(&comment, pc, bits); 744 if (!comment.empty()) 745 { 746 for (u32 i = instr.length(); i < 30; i++) 747 instr.append(' '); 748 instr.append("; "); 749 instr.append(comment); 750 } 751 } 752 753 WriteToExecutionLog("%08x: %08x %s\n", pc, bits, instr.c_str()); 754 } 755 756 void CPU::HandleWriteSyscall() 757 { 758 const auto& regs = g_state.regs; 759 if (regs.a0 != 1) // stdout 760 return; 761 762 u32 addr = regs.a1; 763 const u32 count = regs.a2; 764 for (u32 i = 0; i < count; i++) 765 { 766 u8 value; 767 if (!SafeReadMemoryByte(addr++, &value) || value == 0) 768 break; 769 770 Bus::AddTTYCharacter(static_cast<char>(value)); 771 } 772 } 773 774 void CPU::HandlePutcSyscall() 775 { 776 const auto& regs = g_state.regs; 777 if (regs.a0 != 0) 778 Bus::AddTTYCharacter(static_cast<char>(regs.a0)); 779 } 780 781 void CPU::HandlePutsSyscall() 782 { 783 const auto& regs = g_state.regs; 784 785 u32 addr = regs.a1; 786 for (u32 i = 0; i < 1024; i++) 787 { 788 u8 value; 789 if (!SafeReadMemoryByte(addr++, &value) || value == 0) 790 break; 791 792 Bus::AddTTYCharacter(static_cast<char>(value)); 793 } 794 } 795 796 void CPU::HandleA0Syscall() 797 { 798 const auto& regs = g_state.regs; 799 const u32 call = regs.t1; 800 if (call == 0x03) 801 HandleWriteSyscall(); 802 else if (call == 0x09 || call == 0x3c) 803 HandlePutcSyscall(); 804 else if (call == 0x3e) 805 HandlePutsSyscall(); 806 } 807 808 void CPU::HandleB0Syscall() 809 { 810 const auto& regs = g_state.regs; 811 const u32 call = regs.t1; 812 if (call == 0x35) 813 HandleWriteSyscall(); 814 else if (call == 0x3b || call == 0x3d) 815 HandlePutcSyscall(); 816 else if (call == 0x3f) 817 HandlePutsSyscall(); 818 } 819 820 const std::array<CPU::DebuggerRegisterListEntry, CPU::NUM_DEBUGGER_REGISTER_LIST_ENTRIES> 821 CPU::g_debugger_register_list = {{{"zero", &CPU::g_state.regs.zero}, 822 {"at", &CPU::g_state.regs.at}, 823 {"v0", &CPU::g_state.regs.v0}, 824 {"v1", &CPU::g_state.regs.v1}, 825 {"a0", &CPU::g_state.regs.a0}, 826 {"a1", &CPU::g_state.regs.a1}, 827 {"a2", &CPU::g_state.regs.a2}, 828 {"a3", &CPU::g_state.regs.a3}, 829 {"t0", &CPU::g_state.regs.t0}, 830 {"t1", &CPU::g_state.regs.t1}, 831 {"t2", &CPU::g_state.regs.t2}, 832 {"t3", &CPU::g_state.regs.t3}, 833 {"t4", &CPU::g_state.regs.t4}, 834 {"t5", &CPU::g_state.regs.t5}, 835 {"t6", &CPU::g_state.regs.t6}, 836 {"t7", &CPU::g_state.regs.t7}, 837 {"s0", &CPU::g_state.regs.s0}, 838 {"s1", &CPU::g_state.regs.s1}, 839 {"s2", &CPU::g_state.regs.s2}, 840 {"s3", &CPU::g_state.regs.s3}, 841 {"s4", &CPU::g_state.regs.s4}, 842 {"s5", &CPU::g_state.regs.s5}, 843 {"s6", &CPU::g_state.regs.s6}, 844 {"s7", &CPU::g_state.regs.s7}, 845 {"t8", &CPU::g_state.regs.t8}, 846 {"t9", &CPU::g_state.regs.t9}, 847 {"k0", &CPU::g_state.regs.k0}, 848 {"k1", &CPU::g_state.regs.k1}, 849 {"gp", &CPU::g_state.regs.gp}, 850 {"sp", &CPU::g_state.regs.sp}, 851 {"fp", &CPU::g_state.regs.fp}, 852 {"ra", &CPU::g_state.regs.ra}, 853 {"hi", &CPU::g_state.regs.hi}, 854 {"lo", &CPU::g_state.regs.lo}, 855 {"pc", &CPU::g_state.pc}, 856 857 {"COP0_SR", &CPU::g_state.cop0_regs.sr.bits}, 858 {"COP0_CAUSE", &CPU::g_state.cop0_regs.cause.bits}, 859 {"COP0_EPC", &CPU::g_state.cop0_regs.EPC}, 860 {"COP0_BadVAddr", &CPU::g_state.cop0_regs.BadVaddr}, 861 862 {"V0_XY", &CPU::g_state.gte_regs.r32[0]}, 863 {"V0_Z", &CPU::g_state.gte_regs.r32[1]}, 864 {"V1_XY", &CPU::g_state.gte_regs.r32[2]}, 865 {"V1_Z", &CPU::g_state.gte_regs.r32[3]}, 866 {"V2_XY", &CPU::g_state.gte_regs.r32[4]}, 867 {"V2_Z", &CPU::g_state.gte_regs.r32[5]}, 868 {"RGBC", &CPU::g_state.gte_regs.r32[6]}, 869 {"OTZ", &CPU::g_state.gte_regs.r32[7]}, 870 {"IR0", &CPU::g_state.gte_regs.r32[8]}, 871 {"IR1", &CPU::g_state.gte_regs.r32[9]}, 872 {"IR2", &CPU::g_state.gte_regs.r32[10]}, 873 {"IR3", &CPU::g_state.gte_regs.r32[11]}, 874 {"SXY0", &CPU::g_state.gte_regs.r32[12]}, 875 {"SXY1", &CPU::g_state.gte_regs.r32[13]}, 876 {"SXY2", &CPU::g_state.gte_regs.r32[14]}, 877 {"SXYP", &CPU::g_state.gte_regs.r32[15]}, 878 {"SZ0", &CPU::g_state.gte_regs.r32[16]}, 879 {"SZ1", &CPU::g_state.gte_regs.r32[17]}, 880 {"SZ2", &CPU::g_state.gte_regs.r32[18]}, 881 {"SZ3", &CPU::g_state.gte_regs.r32[19]}, 882 {"RGB0", &CPU::g_state.gte_regs.r32[20]}, 883 {"RGB1", &CPU::g_state.gte_regs.r32[21]}, 884 {"RGB2", &CPU::g_state.gte_regs.r32[22]}, 885 {"RES1", &CPU::g_state.gte_regs.r32[23]}, 886 {"MAC0", &CPU::g_state.gte_regs.r32[24]}, 887 {"MAC1", &CPU::g_state.gte_regs.r32[25]}, 888 {"MAC2", &CPU::g_state.gte_regs.r32[26]}, 889 {"MAC3", &CPU::g_state.gte_regs.r32[27]}, 890 {"IRGB", &CPU::g_state.gte_regs.r32[28]}, 891 {"ORGB", &CPU::g_state.gte_regs.r32[29]}, 892 {"LZCS", &CPU::g_state.gte_regs.r32[30]}, 893 {"LZCR", &CPU::g_state.gte_regs.r32[31]}, 894 {"RT_0", &CPU::g_state.gte_regs.r32[32]}, 895 {"RT_1", &CPU::g_state.gte_regs.r32[33]}, 896 {"RT_2", &CPU::g_state.gte_regs.r32[34]}, 897 {"RT_3", &CPU::g_state.gte_regs.r32[35]}, 898 {"RT_4", &CPU::g_state.gte_regs.r32[36]}, 899 {"TRX", &CPU::g_state.gte_regs.r32[37]}, 900 {"TRY", &CPU::g_state.gte_regs.r32[38]}, 901 {"TRZ", &CPU::g_state.gte_regs.r32[39]}, 902 {"LLM_0", &CPU::g_state.gte_regs.r32[40]}, 903 {"LLM_1", &CPU::g_state.gte_regs.r32[41]}, 904 {"LLM_2", &CPU::g_state.gte_regs.r32[42]}, 905 {"LLM_3", &CPU::g_state.gte_regs.r32[43]}, 906 {"LLM_4", &CPU::g_state.gte_regs.r32[44]}, 907 {"RBK", &CPU::g_state.gte_regs.r32[45]}, 908 {"GBK", &CPU::g_state.gte_regs.r32[46]}, 909 {"BBK", &CPU::g_state.gte_regs.r32[47]}, 910 {"LCM_0", &CPU::g_state.gte_regs.r32[48]}, 911 {"LCM_1", &CPU::g_state.gte_regs.r32[49]}, 912 {"LCM_2", &CPU::g_state.gte_regs.r32[50]}, 913 {"LCM_3", &CPU::g_state.gte_regs.r32[51]}, 914 {"LCM_4", &CPU::g_state.gte_regs.r32[52]}, 915 {"RFC", &CPU::g_state.gte_regs.r32[53]}, 916 {"GFC", &CPU::g_state.gte_regs.r32[54]}, 917 {"BFC", &CPU::g_state.gte_regs.r32[55]}, 918 {"OFX", &CPU::g_state.gte_regs.r32[56]}, 919 {"OFY", &CPU::g_state.gte_regs.r32[57]}, 920 {"H", &CPU::g_state.gte_regs.r32[58]}, 921 {"DQA", &CPU::g_state.gte_regs.r32[59]}, 922 {"DQB", &CPU::g_state.gte_regs.r32[60]}, 923 {"ZSF3", &CPU::g_state.gte_regs.r32[61]}, 924 {"ZSF4", &CPU::g_state.gte_regs.r32[62]}, 925 {"FLAG", &CPU::g_state.gte_regs.r32[63]}}}; 926 927 ALWAYS_INLINE static constexpr bool AddOverflow(u32 old_value, u32 add_value, u32 new_value) 928 { 929 return (((new_value ^ old_value) & (new_value ^ add_value)) & UINT32_C(0x80000000)) != 0; 930 } 931 932 ALWAYS_INLINE static constexpr bool SubOverflow(u32 old_value, u32 sub_value, u32 new_value) 933 { 934 return (((new_value ^ old_value) & (old_value ^ sub_value)) & UINT32_C(0x80000000)) != 0; 935 } 936 937 void CPU::DisassembleAndPrint(u32 addr, bool regs, const char* prefix) 938 { 939 u32 bits = 0; 940 SafeReadMemoryWord(addr, &bits); 941 PrintInstruction(bits, addr, regs, prefix); 942 } 943 944 void CPU::DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instructions_after /* = 0 */) 945 { 946 u32 disasm_addr = addr - (instructions_before * sizeof(u32)); 947 for (u32 i = 0; i < instructions_before; i++) 948 { 949 DisassembleAndPrint(disasm_addr, false, ""); 950 disasm_addr += sizeof(u32); 951 } 952 953 // <= to include the instruction itself 954 for (u32 i = 0; i <= instructions_after; i++) 955 { 956 DisassembleAndPrint(disasm_addr, (i == 0), (i == 0) ? "---->" : ""); 957 disasm_addr += sizeof(u32); 958 } 959 } 960 961 template<PGXPMode pgxp_mode, bool debug> 962 ALWAYS_INLINE_RELEASE void CPU::ExecuteInstruction() 963 { 964 restart_instruction: 965 const Instruction inst = g_state.current_instruction; 966 967 #if 0 968 if (g_state.current_instruction_pc == 0x80030000) 969 { 970 TRACE_EXECUTION = true; 971 __debugbreak(); 972 } 973 #endif 974 975 #ifdef _DEBUG 976 if (TRACE_EXECUTION) 977 TracePrintInstruction(); 978 #endif 979 980 // Skip nops. Makes PGXP-CPU quicker, but also the regular interpreter. 981 if (inst.bits == 0) 982 return; 983 984 switch (inst.op) 985 { 986 case InstructionOp::funct: 987 { 988 switch (inst.r.funct) 989 { 990 case InstructionFunct::sll: 991 { 992 const u32 rtVal = ReadReg(inst.r.rt); 993 const u32 rdVal = rtVal << inst.r.shamt; 994 WriteReg(inst.r.rd, rdVal); 995 996 if constexpr (pgxp_mode >= PGXPMode::CPU) 997 PGXP::CPU_SLL(inst, rtVal); 998 } 999 break; 1000 1001 case InstructionFunct::srl: 1002 { 1003 const u32 rtVal = ReadReg(inst.r.rt); 1004 const u32 rdVal = rtVal >> inst.r.shamt; 1005 WriteReg(inst.r.rd, rdVal); 1006 1007 if constexpr (pgxp_mode >= PGXPMode::CPU) 1008 PGXP::CPU_SRL(inst, rtVal); 1009 } 1010 break; 1011 1012 case InstructionFunct::sra: 1013 { 1014 const u32 rtVal = ReadReg(inst.r.rt); 1015 const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> inst.r.shamt); 1016 WriteReg(inst.r.rd, rdVal); 1017 1018 if constexpr (pgxp_mode >= PGXPMode::CPU) 1019 PGXP::CPU_SRA(inst, rtVal); 1020 } 1021 break; 1022 1023 case InstructionFunct::sllv: 1024 { 1025 const u32 rtVal = ReadReg(inst.r.rt); 1026 const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F); 1027 const u32 rdVal = rtVal << shamt; 1028 if constexpr (pgxp_mode >= PGXPMode::CPU) 1029 PGXP::CPU_SLLV(inst, rtVal, shamt); 1030 1031 WriteReg(inst.r.rd, rdVal); 1032 } 1033 break; 1034 1035 case InstructionFunct::srlv: 1036 { 1037 const u32 rtVal = ReadReg(inst.r.rt); 1038 const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F); 1039 const u32 rdVal = rtVal >> shamt; 1040 WriteReg(inst.r.rd, rdVal); 1041 1042 if constexpr (pgxp_mode >= PGXPMode::CPU) 1043 PGXP::CPU_SRLV(inst, rtVal, shamt); 1044 } 1045 break; 1046 1047 case InstructionFunct::srav: 1048 { 1049 const u32 rtVal = ReadReg(inst.r.rt); 1050 const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F); 1051 const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> shamt); 1052 WriteReg(inst.r.rd, rdVal); 1053 1054 if constexpr (pgxp_mode >= PGXPMode::CPU) 1055 PGXP::CPU_SRAV(inst, rtVal, shamt); 1056 } 1057 break; 1058 1059 case InstructionFunct::and_: 1060 { 1061 const u32 rsVal = ReadReg(inst.r.rs); 1062 const u32 rtVal = ReadReg(inst.r.rt); 1063 const u32 new_value = rsVal & rtVal; 1064 WriteReg(inst.r.rd, new_value); 1065 1066 if constexpr (pgxp_mode >= PGXPMode::CPU) 1067 PGXP::CPU_AND_(inst, rsVal, rtVal); 1068 } 1069 break; 1070 1071 case InstructionFunct::or_: 1072 { 1073 const u32 rsVal = ReadReg(inst.r.rs); 1074 const u32 rtVal = ReadReg(inst.r.rt); 1075 const u32 new_value = rsVal | rtVal; 1076 WriteReg(inst.r.rd, new_value); 1077 1078 if constexpr (pgxp_mode >= PGXPMode::CPU) 1079 PGXP::CPU_OR_(inst, rsVal, rtVal); 1080 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1081 PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt); 1082 } 1083 break; 1084 1085 case InstructionFunct::xor_: 1086 { 1087 const u32 rsVal = ReadReg(inst.r.rs); 1088 const u32 rtVal = ReadReg(inst.r.rt); 1089 const u32 new_value = rsVal ^ rtVal; 1090 WriteReg(inst.r.rd, new_value); 1091 1092 if constexpr (pgxp_mode >= PGXPMode::CPU) 1093 PGXP::CPU_XOR_(inst, rsVal, rtVal); 1094 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1095 PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt); 1096 } 1097 break; 1098 1099 case InstructionFunct::nor: 1100 { 1101 const u32 rsVal = ReadReg(inst.r.rs); 1102 const u32 rtVal = ReadReg(inst.r.rt); 1103 const u32 new_value = ~(rsVal | rtVal); 1104 WriteReg(inst.r.rd, new_value); 1105 1106 if constexpr (pgxp_mode >= PGXPMode::CPU) 1107 PGXP::CPU_NOR(inst, rsVal, rtVal); 1108 } 1109 break; 1110 1111 case InstructionFunct::add: 1112 { 1113 const u32 rsVal = ReadReg(inst.r.rs); 1114 const u32 rtVal = ReadReg(inst.r.rt); 1115 const u32 rdVal = rsVal + rtVal; 1116 if (AddOverflow(rsVal, rtVal, rdVal)) 1117 { 1118 RaiseException(Exception::Ov); 1119 return; 1120 } 1121 1122 WriteReg(inst.r.rd, rdVal); 1123 1124 if constexpr (pgxp_mode == PGXPMode::CPU) 1125 PGXP::CPU_ADD(inst, rsVal, rtVal); 1126 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1127 PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt); 1128 } 1129 break; 1130 1131 case InstructionFunct::addu: 1132 { 1133 const u32 rsVal = ReadReg(inst.r.rs); 1134 const u32 rtVal = ReadReg(inst.r.rt); 1135 const u32 rdVal = rsVal + rtVal; 1136 WriteReg(inst.r.rd, rdVal); 1137 1138 if constexpr (pgxp_mode >= PGXPMode::CPU) 1139 PGXP::CPU_ADD(inst, rsVal, rtVal); 1140 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1141 PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt); 1142 } 1143 break; 1144 1145 case InstructionFunct::sub: 1146 { 1147 const u32 rsVal = ReadReg(inst.r.rs); 1148 const u32 rtVal = ReadReg(inst.r.rt); 1149 const u32 rdVal = rsVal - rtVal; 1150 if (SubOverflow(rsVal, rtVal, rdVal)) 1151 { 1152 RaiseException(Exception::Ov); 1153 return; 1154 } 1155 1156 WriteReg(inst.r.rd, rdVal); 1157 1158 if constexpr (pgxp_mode >= PGXPMode::CPU) 1159 PGXP::CPU_SUB(inst, rsVal, rtVal); 1160 } 1161 break; 1162 1163 case InstructionFunct::subu: 1164 { 1165 const u32 rsVal = ReadReg(inst.r.rs); 1166 const u32 rtVal = ReadReg(inst.r.rt); 1167 const u32 rdVal = rsVal - rtVal; 1168 WriteReg(inst.r.rd, rdVal); 1169 1170 if constexpr (pgxp_mode >= PGXPMode::CPU) 1171 PGXP::CPU_SUB(inst, rsVal, rtVal); 1172 } 1173 break; 1174 1175 case InstructionFunct::slt: 1176 { 1177 const u32 rsVal = ReadReg(inst.r.rs); 1178 const u32 rtVal = ReadReg(inst.r.rt); 1179 const u32 result = BoolToUInt32(static_cast<s32>(rsVal) < static_cast<s32>(rtVal)); 1180 WriteReg(inst.r.rd, result); 1181 1182 if constexpr (pgxp_mode >= PGXPMode::CPU) 1183 PGXP::CPU_SLT(inst, rsVal, rtVal); 1184 } 1185 break; 1186 1187 case InstructionFunct::sltu: 1188 { 1189 const u32 rsVal = ReadReg(inst.r.rs); 1190 const u32 rtVal = ReadReg(inst.r.rt); 1191 const u32 result = BoolToUInt32(rsVal < rtVal); 1192 WriteReg(inst.r.rd, result); 1193 1194 if constexpr (pgxp_mode >= PGXPMode::CPU) 1195 PGXP::CPU_SLTU(inst, rsVal, rtVal); 1196 } 1197 break; 1198 1199 case InstructionFunct::mfhi: 1200 { 1201 const u32 value = g_state.regs.hi; 1202 WriteReg(inst.r.rd, value); 1203 1204 if constexpr (pgxp_mode >= PGXPMode::CPU) 1205 PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::hi), value); 1206 } 1207 break; 1208 1209 case InstructionFunct::mthi: 1210 { 1211 const u32 value = ReadReg(inst.r.rs); 1212 g_state.regs.hi = value; 1213 1214 if constexpr (pgxp_mode >= PGXPMode::CPU) 1215 PGXP::CPU_MOVE(static_cast<u32>(Reg::hi), static_cast<u32>(inst.r.rs.GetValue()), value); 1216 } 1217 break; 1218 1219 case InstructionFunct::mflo: 1220 { 1221 const u32 value = g_state.regs.lo; 1222 WriteReg(inst.r.rd, value); 1223 1224 if constexpr (pgxp_mode >= PGXPMode::CPU) 1225 PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::lo), value); 1226 } 1227 break; 1228 1229 case InstructionFunct::mtlo: 1230 { 1231 const u32 value = ReadReg(inst.r.rs); 1232 g_state.regs.lo = value; 1233 1234 if constexpr (pgxp_mode == PGXPMode::CPU) 1235 PGXP::CPU_MOVE(static_cast<u32>(Reg::lo), static_cast<u32>(inst.r.rs.GetValue()), value); 1236 } 1237 break; 1238 1239 case InstructionFunct::mult: 1240 { 1241 const u32 lhs = ReadReg(inst.r.rs); 1242 const u32 rhs = ReadReg(inst.r.rt); 1243 const u64 result = 1244 static_cast<u64>(static_cast<s64>(SignExtend64(lhs)) * static_cast<s64>(SignExtend64(rhs))); 1245 1246 g_state.regs.hi = Truncate32(result >> 32); 1247 g_state.regs.lo = Truncate32(result); 1248 1249 if constexpr (pgxp_mode >= PGXPMode::CPU) 1250 PGXP::CPU_MULT(inst, lhs, rhs); 1251 } 1252 break; 1253 1254 case InstructionFunct::multu: 1255 { 1256 const u32 lhs = ReadReg(inst.r.rs); 1257 const u32 rhs = ReadReg(inst.r.rt); 1258 const u64 result = ZeroExtend64(lhs) * ZeroExtend64(rhs); 1259 1260 g_state.regs.hi = Truncate32(result >> 32); 1261 g_state.regs.lo = Truncate32(result); 1262 1263 if constexpr (pgxp_mode >= PGXPMode::CPU) 1264 PGXP::CPU_MULTU(inst, lhs, rhs); 1265 } 1266 break; 1267 1268 case InstructionFunct::div: 1269 { 1270 const s32 num = static_cast<s32>(ReadReg(inst.r.rs)); 1271 const s32 denom = static_cast<s32>(ReadReg(inst.r.rt)); 1272 1273 if (denom == 0) 1274 { 1275 // divide by zero 1276 g_state.regs.lo = (num >= 0) ? UINT32_C(0xFFFFFFFF) : UINT32_C(1); 1277 g_state.regs.hi = static_cast<u32>(num); 1278 } 1279 else if (static_cast<u32>(num) == UINT32_C(0x80000000) && denom == -1) 1280 { 1281 // unrepresentable 1282 g_state.regs.lo = UINT32_C(0x80000000); 1283 g_state.regs.hi = 0; 1284 } 1285 else 1286 { 1287 g_state.regs.lo = static_cast<u32>(num / denom); 1288 g_state.regs.hi = static_cast<u32>(num % denom); 1289 } 1290 1291 if constexpr (pgxp_mode >= PGXPMode::CPU) 1292 PGXP::CPU_DIV(inst, num, denom); 1293 } 1294 break; 1295 1296 case InstructionFunct::divu: 1297 { 1298 const u32 num = ReadReg(inst.r.rs); 1299 const u32 denom = ReadReg(inst.r.rt); 1300 1301 if (denom == 0) 1302 { 1303 // divide by zero 1304 g_state.regs.lo = UINT32_C(0xFFFFFFFF); 1305 g_state.regs.hi = static_cast<u32>(num); 1306 } 1307 else 1308 { 1309 g_state.regs.lo = num / denom; 1310 g_state.regs.hi = num % denom; 1311 } 1312 1313 if constexpr (pgxp_mode >= PGXPMode::CPU) 1314 PGXP::CPU_DIVU(inst, num, denom); 1315 } 1316 break; 1317 1318 case InstructionFunct::jr: 1319 { 1320 g_state.next_instruction_is_branch_delay_slot = true; 1321 const u32 target = ReadReg(inst.r.rs); 1322 Branch(target); 1323 } 1324 break; 1325 1326 case InstructionFunct::jalr: 1327 { 1328 g_state.next_instruction_is_branch_delay_slot = true; 1329 const u32 target = ReadReg(inst.r.rs); 1330 WriteReg(inst.r.rd, g_state.npc); 1331 Branch(target); 1332 } 1333 break; 1334 1335 case InstructionFunct::syscall: 1336 { 1337 RaiseException(Exception::Syscall); 1338 } 1339 break; 1340 1341 case InstructionFunct::break_: 1342 { 1343 RaiseBreakException(Cop0Registers::CAUSE::MakeValueForException( 1344 Exception::BP, g_state.current_instruction_in_branch_delay_slot, 1345 g_state.current_instruction_was_branch_taken, g_state.current_instruction.cop.cop_n), 1346 g_state.current_instruction_pc, g_state.current_instruction.bits); 1347 } 1348 break; 1349 1350 default: 1351 { 1352 RaiseException(Exception::RI); 1353 break; 1354 } 1355 } 1356 } 1357 break; 1358 1359 case InstructionOp::lui: 1360 { 1361 const u32 value = inst.i.imm_zext32() << 16; 1362 WriteReg(inst.i.rt, value); 1363 1364 if constexpr (pgxp_mode >= PGXPMode::CPU) 1365 PGXP::CPU_LUI(inst); 1366 } 1367 break; 1368 1369 case InstructionOp::andi: 1370 { 1371 const u32 rsVal = ReadReg(inst.i.rs); 1372 const u32 new_value = rsVal & inst.i.imm_zext32(); 1373 WriteReg(inst.i.rt, new_value); 1374 1375 if constexpr (pgxp_mode >= PGXPMode::CPU) 1376 PGXP::CPU_ANDI(inst, rsVal); 1377 } 1378 break; 1379 1380 case InstructionOp::ori: 1381 { 1382 const u32 rsVal = ReadReg(inst.i.rs); 1383 const u32 imm = inst.i.imm_zext32(); 1384 const u32 rtVal = rsVal | imm; 1385 WriteReg(inst.i.rt, rtVal); 1386 1387 if constexpr (pgxp_mode >= PGXPMode::CPU) 1388 PGXP::CPU_ORI(inst, rsVal); 1389 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1390 PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm); 1391 } 1392 break; 1393 1394 case InstructionOp::xori: 1395 { 1396 const u32 rsVal = ReadReg(inst.i.rs); 1397 const u32 imm = inst.i.imm_zext32(); 1398 const u32 new_value = ReadReg(inst.i.rs) ^ imm; 1399 WriteReg(inst.i.rt, new_value); 1400 1401 if constexpr (pgxp_mode >= PGXPMode::CPU) 1402 PGXP::CPU_XORI(inst, rsVal); 1403 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1404 PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm); 1405 } 1406 break; 1407 1408 case InstructionOp::addi: 1409 { 1410 const u32 rsVal = ReadReg(inst.i.rs); 1411 const u32 imm = inst.i.imm_sext32(); 1412 const u32 rtVal = rsVal + imm; 1413 if (AddOverflow(rsVal, imm, rtVal)) 1414 { 1415 RaiseException(Exception::Ov); 1416 return; 1417 } 1418 1419 WriteReg(inst.i.rt, rtVal); 1420 1421 if constexpr (pgxp_mode >= PGXPMode::CPU) 1422 PGXP::CPU_ADDI(inst, rsVal); 1423 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1424 PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm); 1425 } 1426 break; 1427 1428 case InstructionOp::addiu: 1429 { 1430 const u32 rsVal = ReadReg(inst.i.rs); 1431 const u32 imm = inst.i.imm_sext32(); 1432 const u32 rtVal = rsVal + imm; 1433 WriteReg(inst.i.rt, rtVal); 1434 1435 if constexpr (pgxp_mode >= PGXPMode::CPU) 1436 PGXP::CPU_ADDI(inst, rsVal); 1437 else if constexpr (pgxp_mode >= PGXPMode::Memory) 1438 PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm); 1439 } 1440 break; 1441 1442 case InstructionOp::slti: 1443 { 1444 const u32 rsVal = ReadReg(inst.i.rs); 1445 const u32 result = BoolToUInt32(static_cast<s32>(rsVal) < static_cast<s32>(inst.i.imm_sext32())); 1446 WriteReg(inst.i.rt, result); 1447 1448 if constexpr (pgxp_mode >= PGXPMode::CPU) 1449 PGXP::CPU_SLTI(inst, rsVal); 1450 } 1451 break; 1452 1453 case InstructionOp::sltiu: 1454 { 1455 const u32 result = BoolToUInt32(ReadReg(inst.i.rs) < inst.i.imm_sext32()); 1456 WriteReg(inst.i.rt, result); 1457 1458 if constexpr (pgxp_mode >= PGXPMode::CPU) 1459 PGXP::CPU_SLTIU(inst, ReadReg(inst.i.rs)); 1460 } 1461 break; 1462 1463 case InstructionOp::lb: 1464 { 1465 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1466 if constexpr (debug) 1467 { 1468 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1469 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1470 } 1471 1472 u8 value; 1473 if (!ReadMemoryByte(addr, &value)) 1474 return; 1475 1476 const u32 sxvalue = SignExtend32(value); 1477 1478 WriteRegDelayed(inst.i.rt, sxvalue); 1479 1480 if constexpr (pgxp_mode >= PGXPMode::Memory) 1481 PGXP::CPU_LBx(inst, addr, sxvalue); 1482 } 1483 break; 1484 1485 case InstructionOp::lh: 1486 { 1487 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1488 if constexpr (debug) 1489 { 1490 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1491 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1492 } 1493 1494 u16 value; 1495 if (!ReadMemoryHalfWord(addr, &value)) 1496 return; 1497 1498 const u32 sxvalue = SignExtend32(value); 1499 WriteRegDelayed(inst.i.rt, sxvalue); 1500 1501 if constexpr (pgxp_mode >= PGXPMode::Memory) 1502 PGXP::CPU_LH(inst, addr, sxvalue); 1503 } 1504 break; 1505 1506 case InstructionOp::lw: 1507 { 1508 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1509 if constexpr (debug) 1510 { 1511 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1512 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1513 } 1514 1515 u32 value; 1516 if (!ReadMemoryWord(addr, &value)) 1517 return; 1518 1519 WriteRegDelayed(inst.i.rt, value); 1520 1521 if constexpr (pgxp_mode >= PGXPMode::Memory) 1522 PGXP::CPU_LW(inst, addr, value); 1523 } 1524 break; 1525 1526 case InstructionOp::lbu: 1527 { 1528 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1529 if constexpr (debug) 1530 { 1531 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1532 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1533 } 1534 1535 u8 value; 1536 if (!ReadMemoryByte(addr, &value)) 1537 return; 1538 1539 const u32 zxvalue = ZeroExtend32(value); 1540 WriteRegDelayed(inst.i.rt, zxvalue); 1541 1542 if constexpr (pgxp_mode >= PGXPMode::Memory) 1543 PGXP::CPU_LBx(inst, addr, zxvalue); 1544 } 1545 break; 1546 1547 case InstructionOp::lhu: 1548 { 1549 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1550 if constexpr (debug) 1551 { 1552 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1553 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1554 } 1555 1556 u16 value; 1557 if (!ReadMemoryHalfWord(addr, &value)) 1558 return; 1559 1560 const u32 zxvalue = ZeroExtend32(value); 1561 WriteRegDelayed(inst.i.rt, zxvalue); 1562 1563 if constexpr (pgxp_mode >= PGXPMode::Memory) 1564 PGXP::CPU_LHU(inst, addr, zxvalue); 1565 } 1566 break; 1567 1568 case InstructionOp::lwl: 1569 case InstructionOp::lwr: 1570 { 1571 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1572 const VirtualMemoryAddress aligned_addr = addr & ~UINT32_C(3); 1573 if constexpr (debug) 1574 { 1575 Cop0DataBreakpointCheck<MemoryAccessType::Read>(addr); 1576 MemoryBreakpointCheck<MemoryAccessType::Read>(addr); 1577 } 1578 1579 u32 aligned_value; 1580 if (!ReadMemoryWord(aligned_addr, &aligned_value)) 1581 return; 1582 1583 // Bypasses load delay. No need to check the old value since this is the delay slot or it's not relevant. 1584 const u32 existing_value = (inst.i.rt == g_state.load_delay_reg) ? g_state.load_delay_value : ReadReg(inst.i.rt); 1585 const u8 shift = (Truncate8(addr) & u8(3)) * u8(8); 1586 u32 new_value; 1587 if (inst.op == InstructionOp::lwl) 1588 { 1589 const u32 mask = UINT32_C(0x00FFFFFF) >> shift; 1590 new_value = (existing_value & mask) | (aligned_value << (24 - shift)); 1591 } 1592 else 1593 { 1594 const u32 mask = UINT32_C(0xFFFFFF00) << (24 - shift); 1595 new_value = (existing_value & mask) | (aligned_value >> shift); 1596 } 1597 1598 WriteRegDelayed(inst.i.rt, new_value); 1599 1600 if constexpr (pgxp_mode >= PGXPMode::Memory) 1601 PGXP::CPU_LW(inst, addr, new_value); 1602 } 1603 break; 1604 1605 case InstructionOp::sb: 1606 { 1607 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1608 if constexpr (debug) 1609 { 1610 Cop0DataBreakpointCheck<MemoryAccessType::Write>(addr); 1611 MemoryBreakpointCheck<MemoryAccessType::Write>(addr); 1612 } 1613 1614 const u32 value = ReadReg(inst.i.rt); 1615 WriteMemoryByte(addr, value); 1616 1617 if constexpr (pgxp_mode >= PGXPMode::Memory) 1618 PGXP::CPU_SB(inst, addr, value); 1619 } 1620 break; 1621 1622 case InstructionOp::sh: 1623 { 1624 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1625 if constexpr (debug) 1626 { 1627 Cop0DataBreakpointCheck<MemoryAccessType::Write>(addr); 1628 MemoryBreakpointCheck<MemoryAccessType::Write>(addr); 1629 } 1630 1631 const u32 value = ReadReg(inst.i.rt); 1632 WriteMemoryHalfWord(addr, value); 1633 1634 if constexpr (pgxp_mode >= PGXPMode::Memory) 1635 PGXP::CPU_SH(inst, addr, value); 1636 } 1637 break; 1638 1639 case InstructionOp::sw: 1640 { 1641 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1642 if constexpr (debug) 1643 { 1644 Cop0DataBreakpointCheck<MemoryAccessType::Write>(addr); 1645 MemoryBreakpointCheck<MemoryAccessType::Write>(addr); 1646 } 1647 1648 const u32 value = ReadReg(inst.i.rt); 1649 WriteMemoryWord(addr, value); 1650 1651 if constexpr (pgxp_mode >= PGXPMode::Memory) 1652 PGXP::CPU_SW(inst, addr, value); 1653 } 1654 break; 1655 1656 case InstructionOp::swl: 1657 case InstructionOp::swr: 1658 { 1659 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1660 const VirtualMemoryAddress aligned_addr = addr & ~UINT32_C(3); 1661 if constexpr (debug) 1662 { 1663 Cop0DataBreakpointCheck<MemoryAccessType::Write>(aligned_addr); 1664 MemoryBreakpointCheck<MemoryAccessType::Write>(aligned_addr); 1665 } 1666 1667 const u32 reg_value = ReadReg(inst.i.rt); 1668 const u8 shift = (Truncate8(addr) & u8(3)) * u8(8); 1669 u32 mem_value; 1670 if (!ReadMemoryWord(aligned_addr, &mem_value)) 1671 return; 1672 1673 u32 new_value; 1674 if (inst.op == InstructionOp::swl) 1675 { 1676 const u32 mem_mask = UINT32_C(0xFFFFFF00) << shift; 1677 new_value = (mem_value & mem_mask) | (reg_value >> (24 - shift)); 1678 } 1679 else 1680 { 1681 const u32 mem_mask = UINT32_C(0x00FFFFFF) >> (24 - shift); 1682 new_value = (mem_value & mem_mask) | (reg_value << shift); 1683 } 1684 1685 WriteMemoryWord(aligned_addr, new_value); 1686 1687 if constexpr (pgxp_mode >= PGXPMode::Memory) 1688 PGXP::CPU_SW(inst, aligned_addr, new_value); 1689 } 1690 break; 1691 1692 case InstructionOp::j: 1693 { 1694 g_state.next_instruction_is_branch_delay_slot = true; 1695 Branch((g_state.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2)); 1696 } 1697 break; 1698 1699 case InstructionOp::jal: 1700 { 1701 WriteReg(Reg::ra, g_state.npc); 1702 g_state.next_instruction_is_branch_delay_slot = true; 1703 Branch((g_state.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2)); 1704 } 1705 break; 1706 1707 case InstructionOp::beq: 1708 { 1709 // We're still flagged as a branch delay slot even if the branch isn't taken. 1710 g_state.next_instruction_is_branch_delay_slot = true; 1711 const bool branch = (ReadReg(inst.i.rs) == ReadReg(inst.i.rt)); 1712 if (branch) 1713 Branch(g_state.pc + (inst.i.imm_sext32() << 2)); 1714 } 1715 break; 1716 1717 case InstructionOp::bne: 1718 { 1719 g_state.next_instruction_is_branch_delay_slot = true; 1720 const bool branch = (ReadReg(inst.i.rs) != ReadReg(inst.i.rt)); 1721 if (branch) 1722 Branch(g_state.pc + (inst.i.imm_sext32() << 2)); 1723 } 1724 break; 1725 1726 case InstructionOp::bgtz: 1727 { 1728 g_state.next_instruction_is_branch_delay_slot = true; 1729 const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) > 0); 1730 if (branch) 1731 Branch(g_state.pc + (inst.i.imm_sext32() << 2)); 1732 } 1733 break; 1734 1735 case InstructionOp::blez: 1736 { 1737 g_state.next_instruction_is_branch_delay_slot = true; 1738 const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) <= 0); 1739 if (branch) 1740 Branch(g_state.pc + (inst.i.imm_sext32() << 2)); 1741 } 1742 break; 1743 1744 case InstructionOp::b: 1745 { 1746 g_state.next_instruction_is_branch_delay_slot = true; 1747 const u8 rt = static_cast<u8>(inst.i.rt.GetValue()); 1748 1749 // bgez is the inverse of bltz, so simply do ltz and xor the result 1750 const bool bgez = ConvertToBoolUnchecked(rt & u8(1)); 1751 const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) < 0) ^ bgez; 1752 1753 // register is still linked even if the branch isn't taken 1754 const bool link = (rt & u8(0x1E)) == u8(0x10); 1755 if (link) 1756 WriteReg(Reg::ra, g_state.npc); 1757 1758 if (branch) 1759 Branch(g_state.pc + (inst.i.imm_sext32() << 2)); 1760 } 1761 break; 1762 1763 case InstructionOp::cop0: 1764 { 1765 if (InUserMode() && !g_state.cop0_regs.sr.CU0) 1766 { 1767 WARNING_LOG("Coprocessor 0 not present in user mode"); 1768 RaiseException(Exception::CpU); 1769 return; 1770 } 1771 1772 if (inst.cop.IsCommonInstruction()) 1773 { 1774 switch (inst.cop.CommonOp()) 1775 { 1776 case CopCommonInstruction::mfcn: 1777 { 1778 const u32 value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())); 1779 WriteRegDelayed(inst.r.rt, value); 1780 1781 if constexpr (pgxp_mode == PGXPMode::CPU) 1782 PGXP::CPU_MFC0(inst, value); 1783 } 1784 break; 1785 1786 case CopCommonInstruction::mtcn: 1787 { 1788 const u32 rtVal = ReadReg(inst.r.rt); 1789 WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), rtVal); 1790 1791 if constexpr (pgxp_mode == PGXPMode::CPU) 1792 PGXP::CPU_MTC0(inst, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())), rtVal); 1793 } 1794 break; 1795 1796 default: 1797 [[unlikely]] ERROR_LOG("Unhandled instruction at {:08X}: {:08X}", g_state.current_instruction_pc, 1798 inst.bits); 1799 break; 1800 } 1801 } 1802 else 1803 { 1804 switch (inst.cop.Cop0Op()) 1805 { 1806 case Cop0Instruction::rfe: 1807 { 1808 // restore mode 1809 g_state.cop0_regs.sr.mode_bits = 1810 (g_state.cop0_regs.sr.mode_bits & UINT32_C(0b110000)) | (g_state.cop0_regs.sr.mode_bits >> 2); 1811 CheckForPendingInterrupt(); 1812 } 1813 break; 1814 1815 case Cop0Instruction::tlbr: 1816 case Cop0Instruction::tlbwi: 1817 case Cop0Instruction::tlbwr: 1818 case Cop0Instruction::tlbp: 1819 RaiseException(Exception::RI); 1820 break; 1821 1822 default: 1823 [[unlikely]] ERROR_LOG("Unhandled instruction at {:08X}: {:08X}", g_state.current_instruction_pc, 1824 inst.bits); 1825 break; 1826 } 1827 } 1828 } 1829 break; 1830 1831 case InstructionOp::cop2: 1832 { 1833 if (!g_state.cop0_regs.sr.CE2) 1834 { 1835 WARNING_LOG("Coprocessor 2 not enabled"); 1836 RaiseException(Exception::CpU); 1837 return; 1838 } 1839 1840 StallUntilGTEComplete(); 1841 1842 if (inst.cop.IsCommonInstruction()) 1843 { 1844 // TODO: Combine with cop0. 1845 switch (inst.cop.CommonOp()) 1846 { 1847 case CopCommonInstruction::cfcn: 1848 { 1849 const u32 value = GTE::ReadRegister(static_cast<u32>(inst.r.rd.GetValue()) + 32); 1850 WriteRegDelayed(inst.r.rt, value); 1851 1852 if constexpr (pgxp_mode >= PGXPMode::Memory) 1853 PGXP::CPU_MFC2(inst, value); 1854 } 1855 break; 1856 1857 case CopCommonInstruction::ctcn: 1858 { 1859 const u32 value = ReadReg(inst.r.rt); 1860 GTE::WriteRegister(static_cast<u32>(inst.r.rd.GetValue()) + 32, value); 1861 1862 if constexpr (pgxp_mode >= PGXPMode::Memory) 1863 PGXP::CPU_MTC2(inst, value); 1864 } 1865 break; 1866 1867 case CopCommonInstruction::mfcn: 1868 { 1869 const u32 value = GTE::ReadRegister(static_cast<u32>(inst.r.rd.GetValue())); 1870 WriteRegDelayed(inst.r.rt, value); 1871 1872 if constexpr (pgxp_mode >= PGXPMode::Memory) 1873 PGXP::CPU_MFC2(inst, value); 1874 } 1875 break; 1876 1877 case CopCommonInstruction::mtcn: 1878 { 1879 const u32 value = ReadReg(inst.r.rt); 1880 GTE::WriteRegister(static_cast<u32>(inst.r.rd.GetValue()), value); 1881 1882 if constexpr (pgxp_mode >= PGXPMode::Memory) 1883 PGXP::CPU_MTC2(inst, value); 1884 } 1885 break; 1886 1887 default: 1888 [[unlikely]] ERROR_LOG("Unhandled instruction at {:08X}: {:08X}", g_state.current_instruction_pc, 1889 inst.bits); 1890 break; 1891 } 1892 } 1893 else 1894 { 1895 GTE::ExecuteInstruction(inst.bits); 1896 } 1897 } 1898 break; 1899 1900 case InstructionOp::lwc2: 1901 { 1902 if (!g_state.cop0_regs.sr.CE2) 1903 { 1904 WARNING_LOG("Coprocessor 2 not enabled"); 1905 RaiseException(Exception::CpU); 1906 return; 1907 } 1908 1909 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1910 u32 value; 1911 if (!ReadMemoryWord(addr, &value)) 1912 return; 1913 1914 StallUntilGTEComplete(); 1915 GTE::WriteRegister(ZeroExtend32(static_cast<u8>(inst.i.rt.GetValue())), value); 1916 1917 if constexpr (pgxp_mode >= PGXPMode::Memory) 1918 PGXP::CPU_LWC2(inst, addr, value); 1919 } 1920 break; 1921 1922 case InstructionOp::swc2: 1923 { 1924 if (!g_state.cop0_regs.sr.CE2) 1925 { 1926 WARNING_LOG("Coprocessor 2 not enabled"); 1927 RaiseException(Exception::CpU); 1928 return; 1929 } 1930 1931 StallUntilGTEComplete(); 1932 1933 const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32(); 1934 const u32 value = GTE::ReadRegister(ZeroExtend32(static_cast<u8>(inst.i.rt.GetValue()))); 1935 WriteMemoryWord(addr, value); 1936 1937 if constexpr (pgxp_mode >= PGXPMode::Memory) 1938 PGXP::CPU_SWC2(inst, addr, value); 1939 } 1940 break; 1941 1942 // swc0/lwc0/cop1/cop3 are essentially no-ops 1943 case InstructionOp::cop1: 1944 case InstructionOp::cop3: 1945 case InstructionOp::lwc0: 1946 case InstructionOp::lwc1: 1947 case InstructionOp::lwc3: 1948 case InstructionOp::swc0: 1949 case InstructionOp::swc1: 1950 case InstructionOp::swc3: 1951 { 1952 } 1953 break; 1954 1955 // everything else is reserved/invalid 1956 default: 1957 { 1958 u32 ram_value; 1959 if (SafeReadInstruction(g_state.current_instruction_pc, &ram_value) && 1960 ram_value != g_state.current_instruction.bits) [[unlikely]] 1961 { 1962 ERROR_LOG("Stale icache at 0x{:08X} - ICache: {:08X} RAM: {:08X}", g_state.current_instruction_pc, 1963 g_state.current_instruction.bits, ram_value); 1964 g_state.current_instruction.bits = ram_value; 1965 goto restart_instruction; 1966 } 1967 1968 RaiseException(Exception::RI); 1969 } 1970 break; 1971 } 1972 } 1973 1974 void CPU::DispatchInterrupt() 1975 { 1976 // If the instruction we're about to execute is a GTE instruction, delay dispatching the interrupt until the next 1977 // instruction. For some reason, if we don't do this, we end up with incorrectly sorted polygons and flickering.. 1978 SafeReadInstruction(g_state.pc, &g_state.next_instruction.bits); 1979 if (g_state.next_instruction.op == InstructionOp::cop2 && !g_state.next_instruction.cop.IsCommonInstruction()) 1980 { 1981 StallUntilGTEComplete(); 1982 GTE::ExecuteInstruction(g_state.next_instruction.bits); 1983 } 1984 1985 // Interrupt raising occurs before the start of the instruction. 1986 RaiseException( 1987 Cop0Registers::CAUSE::MakeValueForException(Exception::INT, g_state.next_instruction_is_branch_delay_slot, 1988 g_state.branch_was_taken, g_state.next_instruction.cop.cop_n), 1989 g_state.pc); 1990 1991 // Fix up downcount, the pending IRQ set it to zero. 1992 TimingEvents::UpdateCPUDowncount(); 1993 } 1994 1995 bool CPU::UpdateDebugDispatcherFlag() 1996 { 1997 const bool has_any_breakpoints = HasAnyBreakpoints() || s_single_step; 1998 1999 const auto& dcic = g_state.cop0_regs.dcic; 2000 const bool has_cop0_breakpoints = dcic.super_master_enable_1 && dcic.super_master_enable_2 && 2001 dcic.execution_breakpoint_enable && IsCop0ExecutionBreakpointUnmasked(); 2002 2003 const bool use_debug_dispatcher = 2004 has_any_breakpoints || has_cop0_breakpoints || s_trace_to_log || 2005 (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter && g_settings.bios_tty_logging); 2006 if (use_debug_dispatcher == g_state.using_debug_dispatcher) 2007 return false; 2008 2009 DEV_LOG("{} debug dispatcher", use_debug_dispatcher ? "Now using" : "No longer using"); 2010 g_state.using_debug_dispatcher = use_debug_dispatcher; 2011 2012 // Switching to interpreter? 2013 if (g_state.using_interpreter != ShouldUseInterpreter()) 2014 ExecutionModeChanged(); 2015 2016 return true; 2017 } 2018 2019 [[noreturn]] void CPU::ExitExecution() 2020 { 2021 // can't exit while running events without messing things up 2022 DebugAssert(!TimingEvents::IsRunningEvents()); 2023 fastjmp_jmp(&s_jmp_buf, 1); 2024 } 2025 2026 bool CPU::HasAnyBreakpoints() 2027 { 2028 return (GetBreakpointList(BreakpointType::Execute).size() + GetBreakpointList(BreakpointType::Read).size() + 2029 GetBreakpointList(BreakpointType::Write).size()) > 0; 2030 } 2031 2032 ALWAYS_INLINE CPU::BreakpointList& CPU::GetBreakpointList(BreakpointType type) 2033 { 2034 return s_breakpoints[static_cast<size_t>(type)]; 2035 } 2036 2037 const char* CPU::GetBreakpointTypeName(BreakpointType type) 2038 { 2039 static constexpr std::array<const char*, static_cast<u32>(BreakpointType::Count)> names = {{ 2040 "Execute", 2041 "Read", 2042 "Write", 2043 }}; 2044 return names[static_cast<size_t>(type)]; 2045 } 2046 2047 bool CPU::HasBreakpointAtAddress(BreakpointType type, VirtualMemoryAddress address) 2048 { 2049 for (const Breakpoint& bp : GetBreakpointList(type)) 2050 { 2051 if (bp.address == address) 2052 return true; 2053 } 2054 2055 return false; 2056 } 2057 2058 CPU::BreakpointList CPU::CopyBreakpointList(bool include_auto_clear, bool include_callbacks) 2059 { 2060 BreakpointList bps; 2061 2062 size_t total = 0; 2063 for (const BreakpointList& bplist : s_breakpoints) 2064 total += bplist.size(); 2065 2066 bps.reserve(total); 2067 2068 for (const BreakpointList& bplist : s_breakpoints) 2069 { 2070 for (const Breakpoint& bp : bplist) 2071 { 2072 if (bp.callback && !include_callbacks) 2073 continue; 2074 if (bp.auto_clear && !include_auto_clear) 2075 continue; 2076 2077 bps.push_back(bp); 2078 } 2079 } 2080 2081 return bps; 2082 } 2083 2084 bool CPU::AddBreakpoint(BreakpointType type, VirtualMemoryAddress address, bool auto_clear, bool enabled) 2085 { 2086 if (HasBreakpointAtAddress(type, address)) 2087 return false; 2088 2089 INFO_LOG("Adding {} breakpoint at {:08X}, auto clear = {}", GetBreakpointTypeName(type), address, 2090 static_cast<unsigned>(auto_clear)); 2091 2092 Breakpoint bp{address, nullptr, auto_clear ? 0 : s_breakpoint_counter++, 0, type, auto_clear, enabled}; 2093 GetBreakpointList(type).push_back(std::move(bp)); 2094 if (UpdateDebugDispatcherFlag()) 2095 System::InterruptExecution(); 2096 2097 if (!auto_clear) 2098 Host::ReportDebuggerMessage(fmt::format("Added breakpoint at 0x{:08X}.", address)); 2099 2100 return true; 2101 } 2102 2103 bool CPU::AddBreakpointWithCallback(BreakpointType type, VirtualMemoryAddress address, BreakpointCallback callback) 2104 { 2105 if (HasBreakpointAtAddress(type, address)) 2106 return false; 2107 2108 INFO_LOG("Adding {} breakpoint with callback at {:08X}", GetBreakpointTypeName(type), address); 2109 2110 Breakpoint bp{address, callback, 0, 0, type, false, true}; 2111 GetBreakpointList(type).push_back(std::move(bp)); 2112 if (UpdateDebugDispatcherFlag()) 2113 System::InterruptExecution(); 2114 return true; 2115 } 2116 2117 bool CPU::RemoveBreakpoint(BreakpointType type, VirtualMemoryAddress address) 2118 { 2119 BreakpointList& bplist = GetBreakpointList(type); 2120 auto it = 2121 std::find_if(bplist.begin(), bplist.end(), [address](const Breakpoint& bp) { return bp.address == address; }); 2122 if (it == bplist.end()) 2123 return false; 2124 2125 Host::ReportDebuggerMessage(fmt::format("Removed {} breakpoint at 0x{:08X}.", GetBreakpointTypeName(type), address)); 2126 2127 bplist.erase(it); 2128 if (UpdateDebugDispatcherFlag()) 2129 System::InterruptExecution(); 2130 2131 if (address == s_last_breakpoint_check_pc) 2132 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; 2133 2134 return true; 2135 } 2136 2137 void CPU::ClearBreakpoints() 2138 { 2139 for (BreakpointList& bplist : s_breakpoints) 2140 bplist.clear(); 2141 s_breakpoint_counter = 0; 2142 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; 2143 if (UpdateDebugDispatcherFlag()) 2144 System::InterruptExecution(); 2145 } 2146 2147 bool CPU::AddStepOverBreakpoint() 2148 { 2149 u32 bp_pc = g_state.pc; 2150 2151 Instruction inst; 2152 if (!SafeReadInstruction(bp_pc, &inst.bits)) 2153 return false; 2154 2155 bp_pc += sizeof(Instruction); 2156 2157 if (!IsCallInstruction(inst)) 2158 { 2159 Host::ReportDebuggerMessage(fmt::format("0x{:08X} is not a call instruction.", g_state.pc)); 2160 return false; 2161 } 2162 2163 if (!SafeReadInstruction(bp_pc, &inst.bits)) 2164 return false; 2165 2166 if (IsBranchInstruction(inst)) 2167 { 2168 Host::ReportDebuggerMessage(fmt::format("Can't step over double branch at 0x{:08X}", g_state.pc)); 2169 return false; 2170 } 2171 2172 // skip the delay slot 2173 bp_pc += sizeof(Instruction); 2174 2175 Host::ReportDebuggerMessage(fmt::format("Stepping over to 0x{:08X}.", bp_pc)); 2176 2177 return AddBreakpoint(BreakpointType::Execute, bp_pc, true); 2178 } 2179 2180 bool CPU::AddStepOutBreakpoint(u32 max_instructions_to_search) 2181 { 2182 // find the branch-to-ra instruction. 2183 u32 ret_pc = g_state.pc; 2184 for (u32 i = 0; i < max_instructions_to_search; i++) 2185 { 2186 ret_pc += sizeof(Instruction); 2187 2188 Instruction inst; 2189 if (!SafeReadInstruction(ret_pc, &inst.bits)) 2190 { 2191 Host::ReportDebuggerMessage( 2192 fmt::format("Instruction read failed at {:08X} while searching for function end.", ret_pc)); 2193 return false; 2194 } 2195 2196 if (IsReturnInstruction(inst)) 2197 { 2198 Host::ReportDebuggerMessage(fmt::format("Stepping out to 0x{:08X}.", ret_pc)); 2199 return AddBreakpoint(BreakpointType::Execute, ret_pc, true); 2200 } 2201 } 2202 2203 Host::ReportDebuggerMessage(fmt::format("No return instruction found after {} instructions for step-out at {:08X}.", 2204 max_instructions_to_search, g_state.pc)); 2205 2206 return false; 2207 } 2208 2209 ALWAYS_INLINE_RELEASE bool CPU::CheckBreakpointList(BreakpointType type, VirtualMemoryAddress address) 2210 { 2211 BreakpointList& bplist = GetBreakpointList(type); 2212 size_t count = bplist.size(); 2213 if (count == 0) [[likely]] 2214 return false; 2215 2216 for (size_t i = 0; i < count;) 2217 { 2218 Breakpoint& bp = bplist[i]; 2219 if (!bp.enabled || bp.address != address) 2220 { 2221 i++; 2222 continue; 2223 } 2224 2225 bp.hit_count++; 2226 2227 const u32 pc = g_state.pc; 2228 2229 if (bp.callback) 2230 { 2231 // if callback returns false, the bp is no longer recorded 2232 if (!bp.callback(BreakpointType::Execute, pc, address)) 2233 { 2234 bplist.erase(bplist.begin() + i); 2235 count--; 2236 UpdateDebugDispatcherFlag(); 2237 } 2238 else 2239 { 2240 i++; 2241 } 2242 } 2243 else 2244 { 2245 System::PauseSystem(true); 2246 2247 if (bp.auto_clear) 2248 { 2249 Host::ReportDebuggerMessage(fmt::format("Stopped execution at 0x{:08X}.", pc)); 2250 bplist.erase(bplist.begin() + i); 2251 count--; 2252 UpdateDebugDispatcherFlag(); 2253 } 2254 else 2255 { 2256 Host::ReportDebuggerMessage( 2257 fmt::format("Hit {} breakpoint {} at 0x{:08X}.", GetBreakpointTypeName(type), bp.number, address)); 2258 i++; 2259 } 2260 2261 return true; 2262 } 2263 } 2264 2265 return false; 2266 } 2267 2268 ALWAYS_INLINE_RELEASE void CPU::ExecutionBreakpointCheck() 2269 { 2270 if (s_single_step) [[unlikely]] 2271 { 2272 // single step ignores breakpoints, since it stops anyway 2273 s_single_step = false; 2274 s_break_after_instruction = true; 2275 Host::ReportDebuggerMessage(fmt::format("Stepped to 0x{:08X}.", g_state.npc)); 2276 return; 2277 } 2278 2279 if (s_breakpoints[static_cast<u32>(BreakpointType::Execute)].empty()) [[likely]] 2280 return; 2281 2282 const u32 pc = g_state.pc; 2283 if (pc == s_last_breakpoint_check_pc) [[unlikely]] 2284 { 2285 // we don't want to trigger the same breakpoint which just paused us repeatedly. 2286 return; 2287 } 2288 2289 s_last_breakpoint_check_pc = pc; 2290 2291 if (CheckBreakpointList(BreakpointType::Execute, pc)) [[unlikely]] 2292 { 2293 s_single_step = false; 2294 ExitExecution(); 2295 } 2296 } 2297 2298 template<MemoryAccessType type> 2299 ALWAYS_INLINE_RELEASE void CPU::MemoryBreakpointCheck(VirtualMemoryAddress address) 2300 { 2301 const BreakpointType bptype = (type == MemoryAccessType::Read) ? BreakpointType::Read : BreakpointType::Write; 2302 if (CheckBreakpointList(bptype, address)) 2303 s_break_after_instruction = true; 2304 } 2305 2306 template<PGXPMode pgxp_mode, bool debug> 2307 [[noreturn]] void CPU::ExecuteImpl() 2308 { 2309 if (g_state.pending_ticks >= g_state.downcount) 2310 TimingEvents::RunEvents(); 2311 2312 for (;;) 2313 { 2314 do 2315 { 2316 if constexpr (debug) 2317 { 2318 Cop0ExecutionBreakpointCheck(); 2319 ExecutionBreakpointCheck(); 2320 } 2321 2322 g_state.pending_ticks++; 2323 2324 // now executing the instruction we previously fetched 2325 g_state.current_instruction.bits = g_state.next_instruction.bits; 2326 g_state.current_instruction_pc = g_state.pc; 2327 g_state.current_instruction_in_branch_delay_slot = g_state.next_instruction_is_branch_delay_slot; 2328 g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; 2329 g_state.next_instruction_is_branch_delay_slot = false; 2330 g_state.branch_was_taken = false; 2331 g_state.exception_raised = false; 2332 2333 // fetch the next instruction - even if this fails, it'll still refetch on the flush so we can continue 2334 if (!FetchInstruction()) 2335 continue; 2336 2337 // trace functionality 2338 if constexpr (debug) 2339 { 2340 if (s_trace_to_log) 2341 LogInstruction(g_state.current_instruction.bits, g_state.current_instruction_pc, true); 2342 2343 if (g_state.current_instruction_pc == 0xA0) [[unlikely]] 2344 HandleA0Syscall(); 2345 else if (g_state.current_instruction_pc == 0xB0) [[unlikely]] 2346 HandleB0Syscall(); 2347 } 2348 2349 #if 0 // GTE flag test debugging 2350 if (g_state.m_current_instruction_pc == 0x8002cdf4) 2351 { 2352 if (g_state.m_regs.v1 != g_state.m_regs.v0) 2353 printf("Got %08X Expected? %08X\n", g_state.m_regs.v1, g_state.m_regs.v0); 2354 } 2355 #endif 2356 2357 // execute the instruction we previously fetched 2358 ExecuteInstruction<pgxp_mode, debug>(); 2359 2360 // next load delay 2361 UpdateLoadDelay(); 2362 2363 if constexpr (debug) 2364 { 2365 if (s_break_after_instruction) 2366 { 2367 s_break_after_instruction = false; 2368 System::PauseSystem(true); 2369 UpdateDebugDispatcherFlag(); 2370 ExitExecution(); 2371 } 2372 } 2373 } while (g_state.pending_ticks < g_state.downcount); 2374 2375 TimingEvents::RunEvents(); 2376 } 2377 } 2378 2379 void CPU::ExecuteInterpreter() 2380 { 2381 if (g_state.using_debug_dispatcher) 2382 { 2383 if (g_settings.gpu_pgxp_enable) 2384 { 2385 if (g_settings.gpu_pgxp_cpu) 2386 ExecuteImpl<PGXPMode::CPU, true>(); 2387 else 2388 ExecuteImpl<PGXPMode::Memory, true>(); 2389 } 2390 else 2391 { 2392 ExecuteImpl<PGXPMode::Disabled, true>(); 2393 } 2394 } 2395 else 2396 { 2397 if (g_settings.gpu_pgxp_enable) 2398 { 2399 if (g_settings.gpu_pgxp_cpu) 2400 ExecuteImpl<PGXPMode::CPU, false>(); 2401 else 2402 ExecuteImpl<PGXPMode::Memory, false>(); 2403 } 2404 else 2405 { 2406 ExecuteImpl<PGXPMode::Disabled, false>(); 2407 } 2408 } 2409 } 2410 2411 void CPU::Execute() 2412 { 2413 if (fastjmp_set(&s_jmp_buf) != 0) 2414 return; 2415 2416 if (g_state.using_interpreter) 2417 ExecuteInterpreter(); 2418 else 2419 CodeCache::Execute(); 2420 } 2421 2422 void CPU::SetSingleStepFlag() 2423 { 2424 s_single_step = true; 2425 if (UpdateDebugDispatcherFlag()) 2426 System::InterruptExecution(); 2427 } 2428 2429 template<PGXPMode pgxp_mode> 2430 void CPU::CodeCache::InterpretCachedBlock(const Block* block) 2431 { 2432 // set up the state so we've already fetched the instruction 2433 DebugAssert(g_state.pc == block->pc); 2434 g_state.npc = block->pc + 4; 2435 2436 const Instruction* instruction = block->Instructions(); 2437 const Instruction* end_instruction = instruction + block->size; 2438 const CodeCache::InstructionInfo* info = block->InstructionsInfo(); 2439 2440 do 2441 { 2442 g_state.pending_ticks++; 2443 2444 // now executing the instruction we previously fetched 2445 g_state.current_instruction.bits = instruction->bits; 2446 g_state.current_instruction_pc = info->pc; 2447 g_state.current_instruction_in_branch_delay_slot = info->is_branch_delay_slot; // TODO: let int set it instead 2448 g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; 2449 g_state.branch_was_taken = false; 2450 g_state.exception_raised = false; 2451 2452 // update pc 2453 g_state.pc = g_state.npc; 2454 g_state.npc += 4; 2455 2456 // execute the instruction we previously fetched 2457 ExecuteInstruction<pgxp_mode, false>(); 2458 2459 // next load delay 2460 UpdateLoadDelay(); 2461 2462 if (g_state.exception_raised) 2463 break; 2464 2465 instruction++; 2466 info++; 2467 } while (instruction != end_instruction); 2468 2469 // cleanup so the interpreter can kick in if needed 2470 g_state.next_instruction_is_branch_delay_slot = false; 2471 } 2472 2473 template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::Disabled>(const Block* block); 2474 template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::Memory>(const Block* block); 2475 template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::CPU>(const Block* block); 2476 2477 template<PGXPMode pgxp_mode> 2478 void CPU::CodeCache::InterpretUncachedBlock() 2479 { 2480 g_state.npc = g_state.pc; 2481 if (!FetchInstructionForInterpreterFallback()) 2482 return; 2483 2484 // At this point, pc contains the last address executed (in the previous block). The instruction has not been fetched 2485 // yet. pc shouldn't be updated until the fetch occurs, that way the exception occurs in the delay slot. 2486 bool in_branch_delay_slot = false; 2487 for (;;) 2488 { 2489 g_state.pending_ticks++; 2490 2491 // now executing the instruction we previously fetched 2492 g_state.current_instruction.bits = g_state.next_instruction.bits; 2493 g_state.current_instruction_pc = g_state.pc; 2494 g_state.current_instruction_in_branch_delay_slot = g_state.next_instruction_is_branch_delay_slot; 2495 g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; 2496 g_state.next_instruction_is_branch_delay_slot = false; 2497 g_state.branch_was_taken = false; 2498 g_state.exception_raised = false; 2499 2500 // Fetch the next instruction, except if we're in a branch delay slot. The "fetch" is done in the next block. 2501 const bool branch = IsBranchInstruction(g_state.current_instruction); 2502 if (!g_state.current_instruction_in_branch_delay_slot || branch) 2503 { 2504 if (!FetchInstructionForInterpreterFallback()) 2505 break; 2506 } 2507 else 2508 { 2509 g_state.pc = g_state.npc; 2510 } 2511 2512 // execute the instruction we previously fetched 2513 ExecuteInstruction<pgxp_mode, false>(); 2514 2515 // next load delay 2516 UpdateLoadDelay(); 2517 2518 if (g_state.exception_raised || (!branch && in_branch_delay_slot) || 2519 IsExitBlockInstruction(g_state.current_instruction)) 2520 { 2521 break; 2522 } 2523 else if ((g_state.current_instruction.bits & 0xFFC0FFFFu) == 0x40806000u && HasPendingInterrupt()) 2524 { 2525 // mtc0 rt, sr - Jackie Chan Stuntmaster, MTV Sports games. 2526 // Pain in the ass games trigger a software interrupt by writing to SR.Im. 2527 break; 2528 } 2529 2530 in_branch_delay_slot = branch; 2531 } 2532 } 2533 2534 template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Disabled>(); 2535 template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Memory>(); 2536 template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::CPU>(); 2537 2538 bool CPU::Recompiler::Thunks::InterpretInstruction() 2539 { 2540 ExecuteInstruction<PGXPMode::Disabled, false>(); 2541 return g_state.exception_raised; 2542 } 2543 2544 bool CPU::Recompiler::Thunks::InterpretInstructionPGXP() 2545 { 2546 ExecuteInstruction<PGXPMode::Memory, false>(); 2547 return g_state.exception_raised; 2548 } 2549 2550 ALWAYS_INLINE_RELEASE Bus::MemoryReadHandler CPU::GetMemoryReadHandler(VirtualMemoryAddress address, 2551 MemoryAccessSize size) 2552 { 2553 Bus::MemoryReadHandler* base = 2554 Bus::OffsetHandlerArray<Bus::MemoryReadHandler>(g_state.memory_handlers, size, MemoryAccessType::Read); 2555 return base[address >> Bus::MEMORY_LUT_PAGE_SHIFT]; 2556 } 2557 2558 ALWAYS_INLINE_RELEASE Bus::MemoryWriteHandler CPU::GetMemoryWriteHandler(VirtualMemoryAddress address, 2559 MemoryAccessSize size) 2560 { 2561 Bus::MemoryWriteHandler* base = 2562 Bus::OffsetHandlerArray<Bus::MemoryWriteHandler>(g_state.memory_handlers, size, MemoryAccessType::Write); 2563 return base[address >> Bus::MEMORY_LUT_PAGE_SHIFT]; 2564 } 2565 2566 void CPU::UpdateMemoryPointers() 2567 { 2568 g_state.memory_handlers = Bus::GetMemoryHandlers(g_state.cop0_regs.sr.Isc, g_state.cop0_regs.sr.Swc); 2569 g_state.fastmem_base = Bus::GetFastmemBase(g_state.cop0_regs.sr.Isc); 2570 } 2571 2572 void CPU::ExecutionModeChanged() 2573 { 2574 const bool prev_interpreter = g_state.using_interpreter; 2575 2576 UpdateDebugDispatcherFlag(); 2577 2578 // Clear out bus errors in case only memory exceptions are toggled on. 2579 g_state.bus_error = false; 2580 2581 // Have to clear out the icache too, only the tags are valid in the recs. 2582 ClearICache(); 2583 2584 // Switching to interpreter? 2585 g_state.using_interpreter = ShouldUseInterpreter(); 2586 if (g_state.using_interpreter != prev_interpreter && !prev_interpreter) 2587 { 2588 // Before we return, set npc to pc so that we can switch from recs to int. 2589 // We'll also need to fetch the next instruction to execute. 2590 if (!SafeReadInstruction(g_state.pc, &g_state.next_instruction.bits)) [[unlikely]] 2591 { 2592 g_state.next_instruction.bits = 0; 2593 ERROR_LOG("Failed to read current instruction from 0x{:08X}", g_state.pc); 2594 } 2595 2596 g_state.npc = g_state.pc + sizeof(Instruction); 2597 } 2598 2599 // Wipe out code cache when switching back to recompiler. 2600 if (!g_state.using_interpreter && prev_interpreter) 2601 CPU::CodeCache::Reset(); 2602 2603 UpdateDebugDispatcherFlag(); 2604 System::InterruptExecution(); 2605 } 2606 2607 template<bool add_ticks, bool icache_read, u32 word_count, bool raise_exceptions> 2608 ALWAYS_INLINE_RELEASE bool CPU::DoInstructionRead(PhysicalMemoryAddress address, void* data) 2609 { 2610 using namespace Bus; 2611 2612 address &= PHYSICAL_MEMORY_ADDRESS_MASK; 2613 2614 if (address < RAM_MIRROR_END) 2615 { 2616 std::memcpy(data, &g_ram[address & g_ram_mask], sizeof(u32) * word_count); 2617 if constexpr (add_ticks) 2618 g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count; 2619 2620 return true; 2621 } 2622 else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE)) 2623 { 2624 std::memcpy(data, &g_bios[(address - BIOS_BASE) & BIOS_MASK], sizeof(u32) * word_count); 2625 if constexpr (add_ticks) 2626 g_state.pending_ticks += g_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] * word_count; 2627 2628 return true; 2629 } 2630 else 2631 { 2632 if (raise_exceptions) 2633 CPU::RaiseException(address, Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, false, false, 0)); 2634 2635 std::memset(data, 0, sizeof(u32) * word_count); 2636 return false; 2637 } 2638 } 2639 2640 TickCount CPU::GetInstructionReadTicks(VirtualMemoryAddress address) 2641 { 2642 using namespace Bus; 2643 2644 address &= PHYSICAL_MEMORY_ADDRESS_MASK; 2645 2646 if (address < RAM_MIRROR_END) 2647 { 2648 return RAM_READ_TICKS; 2649 } 2650 else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_MIRROR_SIZE)) 2651 { 2652 return g_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)]; 2653 } 2654 else 2655 { 2656 return 0; 2657 } 2658 } 2659 2660 TickCount CPU::GetICacheFillTicks(VirtualMemoryAddress address) 2661 { 2662 using namespace Bus; 2663 2664 address &= PHYSICAL_MEMORY_ADDRESS_MASK; 2665 2666 if (address < RAM_MIRROR_END) 2667 { 2668 return 1 * ((ICACHE_LINE_SIZE - (address & (ICACHE_LINE_SIZE - 1))) / sizeof(u32)); 2669 } 2670 else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_MIRROR_SIZE)) 2671 { 2672 return g_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] * 2673 ((ICACHE_LINE_SIZE - (address & (ICACHE_LINE_SIZE - 1))) / sizeof(u32)); 2674 } 2675 else 2676 { 2677 return 0; 2678 } 2679 } 2680 2681 void CPU::CheckAndUpdateICacheTags(u32 line_count) 2682 { 2683 VirtualMemoryAddress current_pc = g_state.pc & ICACHE_TAG_ADDRESS_MASK; 2684 2685 TickCount ticks = 0; 2686 TickCount cached_ticks_per_line = GetICacheFillTicks(current_pc); 2687 for (u32 i = 0; i < line_count; i++, current_pc += ICACHE_LINE_SIZE) 2688 { 2689 const u32 line = GetICacheLine(current_pc); 2690 if (g_state.icache_tags[line] != current_pc) 2691 { 2692 g_state.icache_tags[line] = current_pc; 2693 ticks += cached_ticks_per_line; 2694 } 2695 } 2696 2697 g_state.pending_ticks += ticks; 2698 } 2699 2700 u32 CPU::FillICache(VirtualMemoryAddress address) 2701 { 2702 const u32 line = GetICacheLine(address); 2703 u8* line_data = &g_state.icache_data[line * ICACHE_LINE_SIZE]; 2704 u32 line_tag; 2705 switch ((address >> 2) & 0x03u) 2706 { 2707 case 0: 2708 DoInstructionRead<true, true, 4, false>(address & ~(ICACHE_LINE_SIZE - 1u), line_data); 2709 line_tag = GetICacheTagForAddress(address); 2710 break; 2711 case 1: 2712 DoInstructionRead<true, true, 3, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x4), line_data + 0x4); 2713 line_tag = GetICacheTagForAddress(address) | 0x1; 2714 break; 2715 case 2: 2716 DoInstructionRead<true, true, 2, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x8), line_data + 0x8); 2717 line_tag = GetICacheTagForAddress(address) | 0x3; 2718 break; 2719 case 3: 2720 default: 2721 DoInstructionRead<true, true, 1, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0xC), line_data + 0xC); 2722 line_tag = GetICacheTagForAddress(address) | 0x7; 2723 break; 2724 } 2725 g_state.icache_tags[line] = line_tag; 2726 2727 const u32 offset = GetICacheLineOffset(address); 2728 u32 result; 2729 std::memcpy(&result, &line_data[offset], sizeof(result)); 2730 return result; 2731 } 2732 2733 void CPU::ClearICache() 2734 { 2735 std::memset(g_state.icache_data.data(), 0, ICACHE_SIZE); 2736 g_state.icache_tags.fill(ICACHE_INVALID_BITS); 2737 } 2738 2739 namespace CPU { 2740 ALWAYS_INLINE_RELEASE static u32 ReadICache(VirtualMemoryAddress address) 2741 { 2742 const u32 line = GetICacheLine(address); 2743 const u8* line_data = &g_state.icache_data[line * ICACHE_LINE_SIZE]; 2744 const u32 offset = GetICacheLineOffset(address); 2745 u32 result; 2746 std::memcpy(&result, &line_data[offset], sizeof(result)); 2747 return result; 2748 } 2749 } // namespace CPU 2750 2751 ALWAYS_INLINE_RELEASE bool CPU::FetchInstruction() 2752 { 2753 DebugAssert(Common::IsAlignedPow2(g_state.npc, 4)); 2754 2755 const PhysicalMemoryAddress address = g_state.npc; 2756 switch (address >> 29) 2757 { 2758 case 0x00: // KUSEG 0M-512M 2759 case 0x04: // KSEG0 - physical memory cached 2760 { 2761 #if 0 2762 DoInstructionRead<true, false, 1, false>(address, &g_state.next_instruction.bits); 2763 #else 2764 if (CompareICacheTag(address)) 2765 g_state.next_instruction.bits = ReadICache(address); 2766 else 2767 g_state.next_instruction.bits = FillICache(address); 2768 #endif 2769 } 2770 break; 2771 2772 case 0x05: // KSEG1 - physical memory uncached 2773 { 2774 if (!DoInstructionRead<true, false, 1, true>(address, &g_state.next_instruction.bits)) 2775 return false; 2776 } 2777 break; 2778 2779 case 0x01: // KUSEG 512M-1024M 2780 case 0x02: // KUSEG 1024M-1536M 2781 case 0x03: // KUSEG 1536M-2048M 2782 case 0x06: // KSEG2 2783 case 0x07: // KSEG2 2784 default: 2785 { 2786 CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, 2787 g_state.current_instruction_in_branch_delay_slot, 2788 g_state.current_instruction_was_branch_taken, 0), 2789 address); 2790 return false; 2791 } 2792 } 2793 2794 g_state.pc = g_state.npc; 2795 g_state.npc += sizeof(g_state.next_instruction.bits); 2796 return true; 2797 } 2798 2799 bool CPU::FetchInstructionForInterpreterFallback() 2800 { 2801 DebugAssert(Common::IsAlignedPow2(g_state.npc, 4)); 2802 2803 const PhysicalMemoryAddress address = g_state.npc; 2804 switch (address >> 29) 2805 { 2806 case 0x00: // KUSEG 0M-512M 2807 case 0x04: // KSEG0 - physical memory cached 2808 case 0x05: // KSEG1 - physical memory uncached 2809 { 2810 // We don't use the icache when doing interpreter fallbacks, because it's probably stale. 2811 if (!DoInstructionRead<false, false, 1, true>(address, &g_state.next_instruction.bits)) 2812 return false; 2813 } 2814 break; 2815 2816 case 0x01: // KUSEG 512M-1024M 2817 case 0x02: // KUSEG 1024M-1536M 2818 case 0x03: // KUSEG 1536M-2048M 2819 case 0x06: // KSEG2 2820 case 0x07: // KSEG2 2821 default: 2822 { 2823 CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, 2824 g_state.current_instruction_in_branch_delay_slot, 2825 g_state.current_instruction_was_branch_taken, 0), 2826 address); 2827 return false; 2828 } 2829 } 2830 2831 g_state.pc = g_state.npc; 2832 g_state.npc += sizeof(g_state.next_instruction.bits); 2833 return true; 2834 } 2835 2836 bool CPU::SafeReadInstruction(VirtualMemoryAddress addr, u32* value) 2837 { 2838 switch (addr >> 29) 2839 { 2840 case 0x00: // KUSEG 0M-512M 2841 case 0x04: // KSEG0 - physical memory cached 2842 case 0x05: // KSEG1 - physical memory uncached 2843 { 2844 // TODO: Check icache. 2845 return DoInstructionRead<false, false, 1, false>(addr, value); 2846 } 2847 2848 case 0x01: // KUSEG 512M-1024M 2849 case 0x02: // KUSEG 1024M-1536M 2850 case 0x03: // KUSEG 1536M-2048M 2851 case 0x06: // KSEG2 2852 case 0x07: // KSEG2 2853 default: 2854 { 2855 return false; 2856 } 2857 } 2858 } 2859 2860 template<MemoryAccessType type, MemoryAccessSize size> 2861 ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& value) 2862 { 2863 using namespace Bus; 2864 2865 switch (address >> 29) 2866 { 2867 case 0x00: // KUSEG 0M-512M 2868 case 0x04: // KSEG0 - physical memory cached 2869 { 2870 if ((address & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR) 2871 { 2872 const u32 offset = address & SCRATCHPAD_OFFSET_MASK; 2873 2874 if constexpr (type == MemoryAccessType::Read) 2875 { 2876 if constexpr (size == MemoryAccessSize::Byte) 2877 { 2878 value = CPU::g_state.scratchpad[offset]; 2879 } 2880 else if constexpr (size == MemoryAccessSize::HalfWord) 2881 { 2882 u16 temp; 2883 std::memcpy(&temp, &CPU::g_state.scratchpad[offset], sizeof(u16)); 2884 value = ZeroExtend32(temp); 2885 } 2886 else if constexpr (size == MemoryAccessSize::Word) 2887 { 2888 std::memcpy(&value, &CPU::g_state.scratchpad[offset], sizeof(u32)); 2889 } 2890 } 2891 else 2892 { 2893 if constexpr (size == MemoryAccessSize::Byte) 2894 { 2895 CPU::g_state.scratchpad[offset] = Truncate8(value); 2896 } 2897 else if constexpr (size == MemoryAccessSize::HalfWord) 2898 { 2899 std::memcpy(&CPU::g_state.scratchpad[offset], &value, sizeof(u16)); 2900 } 2901 else if constexpr (size == MemoryAccessSize::Word) 2902 { 2903 std::memcpy(&CPU::g_state.scratchpad[offset], &value, sizeof(u32)); 2904 } 2905 } 2906 2907 return true; 2908 } 2909 2910 address &= PHYSICAL_MEMORY_ADDRESS_MASK; 2911 } 2912 break; 2913 2914 case 0x01: // KUSEG 512M-1024M 2915 case 0x02: // KUSEG 1024M-1536M 2916 case 0x03: // KUSEG 1536M-2048M 2917 case 0x06: // KSEG2 2918 case 0x07: // KSEG2 2919 { 2920 // Above 512mb raises an exception. 2921 return false; 2922 } 2923 2924 case 0x05: // KSEG1 - physical memory uncached 2925 { 2926 address &= PHYSICAL_MEMORY_ADDRESS_MASK; 2927 } 2928 break; 2929 } 2930 2931 if (address < RAM_MIRROR_END) 2932 { 2933 const u32 offset = address & g_ram_mask; 2934 if constexpr (type == MemoryAccessType::Read) 2935 { 2936 if constexpr (size == MemoryAccessSize::Byte) 2937 { 2938 value = g_unprotected_ram[offset]; 2939 } 2940 else if constexpr (size == MemoryAccessSize::HalfWord) 2941 { 2942 u16 temp; 2943 std::memcpy(&temp, &g_unprotected_ram[offset], sizeof(temp)); 2944 value = ZeroExtend32(temp); 2945 } 2946 else if constexpr (size == MemoryAccessSize::Word) 2947 { 2948 std::memcpy(&value, &g_unprotected_ram[offset], sizeof(u32)); 2949 } 2950 } 2951 else 2952 { 2953 const u32 page_index = offset / HOST_PAGE_SIZE; 2954 2955 if constexpr (size == MemoryAccessSize::Byte) 2956 { 2957 if (g_unprotected_ram[offset] != Truncate8(value)) 2958 { 2959 g_unprotected_ram[offset] = Truncate8(value); 2960 if (g_ram_code_bits[page_index]) 2961 CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); 2962 } 2963 } 2964 else if constexpr (size == MemoryAccessSize::HalfWord) 2965 { 2966 const u16 new_value = Truncate16(value); 2967 u16 old_value; 2968 std::memcpy(&old_value, &g_unprotected_ram[offset], sizeof(old_value)); 2969 if (old_value != new_value) 2970 { 2971 std::memcpy(&g_unprotected_ram[offset], &new_value, sizeof(u16)); 2972 if (g_ram_code_bits[page_index]) 2973 CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); 2974 } 2975 } 2976 else if constexpr (size == MemoryAccessSize::Word) 2977 { 2978 u32 old_value; 2979 std::memcpy(&old_value, &g_unprotected_ram[offset], sizeof(u32)); 2980 if (old_value != value) 2981 { 2982 std::memcpy(&g_unprotected_ram[offset], &value, sizeof(u32)); 2983 if (g_ram_code_bits[page_index]) 2984 CPU::CodeCache::InvalidateBlocksWithPageIndex(page_index); 2985 } 2986 } 2987 } 2988 2989 return true; 2990 } 2991 if constexpr (type == MemoryAccessType::Read) 2992 { 2993 if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE)) 2994 { 2995 const u32 offset = (address & BIOS_MASK); 2996 if constexpr (size == MemoryAccessSize::Byte) 2997 { 2998 value = ZeroExtend32(g_bios[offset]); 2999 } 3000 else if constexpr (size == MemoryAccessSize::HalfWord) 3001 { 3002 u16 halfword; 3003 std::memcpy(&halfword, &g_bios[offset], sizeof(u16)); 3004 value = ZeroExtend32(halfword); 3005 } 3006 else 3007 { 3008 std::memcpy(&value, &g_bios[offset], sizeof(u32)); 3009 } 3010 3011 return true; 3012 } 3013 } 3014 return false; 3015 } 3016 3017 bool CPU::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value) 3018 { 3019 u32 temp = 0; 3020 if (!DoSafeMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp)) 3021 return false; 3022 3023 *value = Truncate8(temp); 3024 return true; 3025 } 3026 3027 bool CPU::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) 3028 { 3029 if ((addr & 1) == 0) 3030 { 3031 u32 temp = 0; 3032 if (!DoSafeMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp)) 3033 return false; 3034 3035 *value = Truncate16(temp); 3036 return true; 3037 } 3038 3039 u8 low, high; 3040 if (!SafeReadMemoryByte(addr, &low) || !SafeReadMemoryByte(addr + 1, &high)) 3041 return false; 3042 3043 *value = (ZeroExtend16(high) << 8) | ZeroExtend16(low); 3044 return true; 3045 } 3046 3047 bool CPU::SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value) 3048 { 3049 if ((addr & 3) == 0) 3050 return DoSafeMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value); 3051 3052 u16 low, high; 3053 if (!SafeReadMemoryHalfWord(addr, &low) || !SafeReadMemoryHalfWord(addr + 2, &high)) 3054 return false; 3055 3056 *value = (ZeroExtend32(high) << 16) | ZeroExtend32(low); 3057 return true; 3058 } 3059 3060 bool CPU::SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length /*= 1024*/) 3061 { 3062 value->clear(); 3063 3064 u8 ch; 3065 while (SafeReadMemoryByte(addr, &ch)) 3066 { 3067 if (ch == 0) 3068 return true; 3069 3070 value->push_back(ch); 3071 if (value->size() >= max_length) 3072 return true; 3073 3074 addr++; 3075 } 3076 3077 value->clear(); 3078 return false; 3079 } 3080 3081 bool CPU::SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value) 3082 { 3083 u32 temp = ZeroExtend32(value); 3084 return DoSafeMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp); 3085 } 3086 3087 bool CPU::SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) 3088 { 3089 if ((addr & 1) == 0) 3090 { 3091 u32 temp = ZeroExtend32(value); 3092 return DoSafeMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp); 3093 } 3094 3095 return SafeWriteMemoryByte(addr, Truncate8(value)) && SafeWriteMemoryByte(addr + 1, Truncate8(value >> 8)); 3096 } 3097 3098 bool CPU::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value) 3099 { 3100 if ((addr & 3) == 0) 3101 return DoSafeMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value); 3102 3103 return SafeWriteMemoryHalfWord(addr, Truncate16(value)) && SafeWriteMemoryHalfWord(addr + 2, Truncate16(value >> 16)); 3104 } 3105 3106 bool CPU::SafeReadMemoryBytes(VirtualMemoryAddress addr, void* data, u32 length) 3107 { 3108 using namespace Bus; 3109 3110 const u32 seg = (addr >> 29); 3111 if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & PHYSICAL_MEMORY_ADDRESS_MASK) >= RAM_MIRROR_END) || 3112 (((addr & g_ram_mask) + length) > g_ram_size)) 3113 { 3114 u8* ptr = static_cast<u8*>(data); 3115 u8* const ptr_end = ptr + length; 3116 while (ptr != ptr_end) 3117 { 3118 if (!SafeReadMemoryByte(addr++, ptr++)) 3119 return false; 3120 } 3121 3122 return true; 3123 } 3124 3125 // Fast path: all in RAM, no wraparound. 3126 std::memcpy(data, &g_ram[addr & g_ram_mask], length); 3127 return true; 3128 } 3129 3130 bool CPU::SafeWriteMemoryBytes(VirtualMemoryAddress addr, const void* data, u32 length) 3131 { 3132 using namespace Bus; 3133 3134 const u32 seg = (addr >> 29); 3135 if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & PHYSICAL_MEMORY_ADDRESS_MASK) >= RAM_MIRROR_END) || 3136 (((addr & g_ram_mask) + length) > g_ram_size)) 3137 { 3138 const u8* ptr = static_cast<const u8*>(data); 3139 const u8* const ptr_end = ptr + length; 3140 while (ptr != ptr_end) 3141 { 3142 if (!SafeWriteMemoryByte(addr++, *(ptr++))) 3143 return false; 3144 } 3145 3146 return true; 3147 } 3148 3149 // Fast path: all in RAM, no wraparound. 3150 std::memcpy(&g_ram[addr & g_ram_mask], data, length); 3151 return true; 3152 } 3153 3154 void* CPU::GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks) 3155 { 3156 using namespace Bus; 3157 3158 const u32 seg = (address >> 29); 3159 if (seg != 0 && seg != 4 && seg != 5) 3160 return nullptr; 3161 3162 const PhysicalMemoryAddress paddr = address & PHYSICAL_MEMORY_ADDRESS_MASK; 3163 if (paddr < RAM_MIRROR_END) 3164 { 3165 if (read_ticks) 3166 *read_ticks = RAM_READ_TICKS; 3167 3168 return &g_ram[paddr & g_ram_mask]; 3169 } 3170 3171 if ((paddr & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR) 3172 { 3173 if (read_ticks) 3174 *read_ticks = 0; 3175 3176 return &g_state.scratchpad[paddr & SCRATCHPAD_OFFSET_MASK]; 3177 } 3178 3179 if (paddr >= BIOS_BASE && paddr < (BIOS_BASE + BIOS_SIZE)) 3180 { 3181 if (read_ticks) 3182 *read_ticks = g_bios_access_time[static_cast<u32>(size)]; 3183 3184 return &g_bios[paddr & BIOS_MASK]; 3185 } 3186 3187 return nullptr; 3188 } 3189 3190 void* CPU::GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size) 3191 { 3192 using namespace Bus; 3193 3194 const u32 seg = (address >> 29); 3195 if (seg != 0 && seg != 4 && seg != 5) 3196 return nullptr; 3197 3198 const PhysicalMemoryAddress paddr = address & PHYSICAL_MEMORY_ADDRESS_MASK; 3199 3200 if (paddr < RAM_MIRROR_END) 3201 return &g_ram[paddr & g_ram_mask]; 3202 3203 if ((paddr & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR) 3204 return &g_state.scratchpad[paddr & SCRATCHPAD_OFFSET_MASK]; 3205 3206 return nullptr; 3207 } 3208 3209 template<MemoryAccessType type, MemoryAccessSize size> 3210 ALWAYS_INLINE_RELEASE bool CPU::DoAlignmentCheck(VirtualMemoryAddress address) 3211 { 3212 if constexpr (size == MemoryAccessSize::HalfWord) 3213 { 3214 if (Common::IsAlignedPow2(address, 2)) 3215 return true; 3216 } 3217 else if constexpr (size == MemoryAccessSize::Word) 3218 { 3219 if (Common::IsAlignedPow2(address, 4)) 3220 return true; 3221 } 3222 else 3223 { 3224 return true; 3225 } 3226 3227 g_state.cop0_regs.BadVaddr = address; 3228 RaiseException(type == MemoryAccessType::Read ? Exception::AdEL : Exception::AdES); 3229 return false; 3230 } 3231 3232 #if 0 3233 static void MemoryBreakpoint(MemoryAccessType type, MemoryAccessSize size, VirtualMemoryAddress addr, u32 value) 3234 { 3235 static constexpr const char* sizes[3] = { "byte", "halfword", "word" }; 3236 static constexpr const char* types[2] = { "read", "write" }; 3237 3238 const u32 cycle = TimingEvents::GetGlobalTickCounter() + CPU::g_state.pending_ticks; 3239 if (cycle == 3301006373) 3240 __debugbreak(); 3241 3242 #if 0 3243 static std::FILE* fp = nullptr; 3244 if (!fp) 3245 fp = std::fopen("D:\\memory.txt", "wb"); 3246 if (fp) 3247 { 3248 std::fprintf(fp, "%u %s %s %08X %08X\n", cycle, types[static_cast<u32>(type)], sizes[static_cast<u32>(size)], addr, value); 3249 std::fflush(fp); 3250 } 3251 #endif 3252 3253 #if 0 3254 if (type == MemoryAccessType::Read && addr == 0x1F000084) 3255 __debugbreak(); 3256 #endif 3257 #if 0 3258 if (type == MemoryAccessType::Write && addr == 0x000000B0 /*&& value == 0x3C080000*/) 3259 __debugbreak(); 3260 #endif 3261 3262 #if 0 // TODO: MEMBP 3263 if (type == MemoryAccessType::Write && address == 0x80113028) 3264 { 3265 if ((TimingEvents::GetGlobalTickCounter() + CPU::g_state.pending_ticks) == 5051485) 3266 __debugbreak(); 3267 3268 Log_WarningPrintf("VAL %08X @ %u", value, (TimingEvents::GetGlobalTickCounter() + CPU::g_state.pending_ticks)); 3269 } 3270 #endif 3271 } 3272 #define MEMORY_BREAKPOINT(type, size, addr, value) MemoryBreakpoint((type), (size), (addr), (value)) 3273 #else 3274 #define MEMORY_BREAKPOINT(type, size, addr, value) 3275 #endif 3276 3277 bool CPU::ReadMemoryByte(VirtualMemoryAddress addr, u8* value) 3278 { 3279 *value = Truncate8(GetMemoryReadHandler(addr, MemoryAccessSize::Byte)(addr)); 3280 if (g_state.bus_error) [[unlikely]] 3281 { 3282 g_state.bus_error = false; 3283 RaiseException(Exception::DBE); 3284 return false; 3285 } 3286 3287 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, addr, *value); 3288 return true; 3289 } 3290 3291 bool CPU::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) 3292 { 3293 if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr)) 3294 return false; 3295 3296 *value = Truncate16(GetMemoryReadHandler(addr, MemoryAccessSize::HalfWord)(addr)); 3297 if (g_state.bus_error) [[unlikely]] 3298 { 3299 g_state.bus_error = false; 3300 RaiseException(Exception::DBE); 3301 return false; 3302 } 3303 3304 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, addr, *value); 3305 return true; 3306 } 3307 3308 bool CPU::ReadMemoryWord(VirtualMemoryAddress addr, u32* value) 3309 { 3310 if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr)) 3311 return false; 3312 3313 *value = GetMemoryReadHandler(addr, MemoryAccessSize::Word)(addr); 3314 if (g_state.bus_error) [[unlikely]] 3315 { 3316 g_state.bus_error = false; 3317 RaiseException(Exception::DBE); 3318 return false; 3319 } 3320 3321 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, addr, *value); 3322 return true; 3323 } 3324 3325 bool CPU::WriteMemoryByte(VirtualMemoryAddress addr, u32 value) 3326 { 3327 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, addr, value); 3328 3329 GetMemoryWriteHandler(addr, MemoryAccessSize::Byte)(addr, value); 3330 if (g_state.bus_error) [[unlikely]] 3331 { 3332 g_state.bus_error = false; 3333 RaiseException(Exception::DBE); 3334 return false; 3335 } 3336 3337 return true; 3338 } 3339 3340 bool CPU::WriteMemoryHalfWord(VirtualMemoryAddress addr, u32 value) 3341 { 3342 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, addr, value); 3343 3344 if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr)) 3345 return false; 3346 3347 GetMemoryWriteHandler(addr, MemoryAccessSize::HalfWord)(addr, value); 3348 if (g_state.bus_error) [[unlikely]] 3349 { 3350 g_state.bus_error = false; 3351 RaiseException(Exception::DBE); 3352 return false; 3353 } 3354 3355 return true; 3356 } 3357 3358 bool CPU::WriteMemoryWord(VirtualMemoryAddress addr, u32 value) 3359 { 3360 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, addr, value); 3361 3362 if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr)) 3363 return false; 3364 3365 GetMemoryWriteHandler(addr, MemoryAccessSize::Word)(addr, value); 3366 if (g_state.bus_error) [[unlikely]] 3367 { 3368 g_state.bus_error = false; 3369 RaiseException(Exception::DBE); 3370 return false; 3371 } 3372 3373 return true; 3374 } 3375 3376 u64 CPU::Recompiler::Thunks::ReadMemoryByte(u32 address) 3377 { 3378 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address); 3379 if (g_state.bus_error) [[unlikely]] 3380 { 3381 g_state.bus_error = false; 3382 return static_cast<u64>(-static_cast<s64>(Exception::DBE)); 3383 } 3384 3385 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, address, value); 3386 return ZeroExtend64(value); 3387 } 3388 3389 u64 CPU::Recompiler::Thunks::ReadMemoryHalfWord(u32 address) 3390 { 3391 if (!Common::IsAlignedPow2(address, 2)) [[unlikely]] 3392 { 3393 g_state.cop0_regs.BadVaddr = address; 3394 return static_cast<u64>(-static_cast<s64>(Exception::AdEL)); 3395 } 3396 3397 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::HalfWord)(address); 3398 if (g_state.bus_error) [[unlikely]] 3399 { 3400 g_state.bus_error = false; 3401 return static_cast<u64>(-static_cast<s64>(Exception::DBE)); 3402 } 3403 3404 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, address, value); 3405 return ZeroExtend64(value); 3406 } 3407 3408 u64 CPU::Recompiler::Thunks::ReadMemoryWord(u32 address) 3409 { 3410 if (!Common::IsAlignedPow2(address, 4)) [[unlikely]] 3411 { 3412 g_state.cop0_regs.BadVaddr = address; 3413 return static_cast<u64>(-static_cast<s64>(Exception::AdEL)); 3414 } 3415 3416 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Word)(address); 3417 if (g_state.bus_error) [[unlikely]] 3418 { 3419 g_state.bus_error = false; 3420 return static_cast<u64>(-static_cast<s64>(Exception::DBE)); 3421 } 3422 3423 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, address, value); 3424 return ZeroExtend64(value); 3425 } 3426 3427 u32 CPU::Recompiler::Thunks::WriteMemoryByte(u32 address, u32 value) 3428 { 3429 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value); 3430 3431 GetMemoryWriteHandler(address, MemoryAccessSize::Byte)(address, value); 3432 if (g_state.bus_error) [[unlikely]] 3433 { 3434 g_state.bus_error = false; 3435 return static_cast<u32>(Exception::DBE); 3436 } 3437 3438 return 0; 3439 } 3440 3441 u32 CPU::Recompiler::Thunks::WriteMemoryHalfWord(u32 address, u32 value) 3442 { 3443 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value); 3444 3445 if (!Common::IsAlignedPow2(address, 2)) [[unlikely]] 3446 { 3447 g_state.cop0_regs.BadVaddr = address; 3448 return static_cast<u32>(Exception::AdES); 3449 } 3450 3451 GetMemoryWriteHandler(address, MemoryAccessSize::HalfWord)(address, value); 3452 if (g_state.bus_error) [[unlikely]] 3453 { 3454 g_state.bus_error = false; 3455 return static_cast<u32>(Exception::DBE); 3456 } 3457 3458 return 0; 3459 } 3460 3461 u32 CPU::Recompiler::Thunks::WriteMemoryWord(u32 address, u32 value) 3462 { 3463 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value); 3464 3465 if (!Common::IsAlignedPow2(address, 4)) [[unlikely]] 3466 { 3467 g_state.cop0_regs.BadVaddr = address; 3468 return static_cast<u32>(Exception::AdES); 3469 } 3470 3471 GetMemoryWriteHandler(address, MemoryAccessSize::Word)(address, value); 3472 if (g_state.bus_error) [[unlikely]] 3473 { 3474 g_state.bus_error = false; 3475 return static_cast<u32>(Exception::DBE); 3476 } 3477 3478 return 0; 3479 } 3480 3481 u32 CPU::Recompiler::Thunks::UncheckedReadMemoryByte(u32 address) 3482 { 3483 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Byte)(address); 3484 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Byte, address, value); 3485 return value; 3486 } 3487 3488 u32 CPU::Recompiler::Thunks::UncheckedReadMemoryHalfWord(u32 address) 3489 { 3490 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::HalfWord)(address); 3491 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::HalfWord, address, value); 3492 return value; 3493 } 3494 3495 u32 CPU::Recompiler::Thunks::UncheckedReadMemoryWord(u32 address) 3496 { 3497 const u32 value = GetMemoryReadHandler(address, MemoryAccessSize::Word)(address); 3498 MEMORY_BREAKPOINT(MemoryAccessType::Read, MemoryAccessSize::Word, address, value); 3499 return value; 3500 } 3501 3502 void CPU::Recompiler::Thunks::UncheckedWriteMemoryByte(u32 address, u32 value) 3503 { 3504 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Byte, address, value); 3505 GetMemoryWriteHandler(address, MemoryAccessSize::Byte)(address, value); 3506 } 3507 3508 void CPU::Recompiler::Thunks::UncheckedWriteMemoryHalfWord(u32 address, u32 value) 3509 { 3510 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::HalfWord, address, value); 3511 GetMemoryWriteHandler(address, MemoryAccessSize::HalfWord)(address, value); 3512 } 3513 3514 void CPU::Recompiler::Thunks::UncheckedWriteMemoryWord(u32 address, u32 value) 3515 { 3516 MEMORY_BREAKPOINT(MemoryAccessType::Write, MemoryAccessSize::Word, address, value); 3517 GetMemoryWriteHandler(address, MemoryAccessSize::Word)(address, value); 3518 } 3519 3520 #undef MEMORY_BREAKPOINT