cpu_core.h (7458B)
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 #pragma once 5 6 #include "cpu_types.h" 7 #include "gte_types.h" 8 #include "types.h" 9 10 #include "common/bitfield.h" 11 12 #include <array> 13 #include <optional> 14 #include <string> 15 #include <vector> 16 17 class StateWrapper; 18 19 namespace CPU { 20 21 enum : VirtualMemoryAddress 22 { 23 RESET_VECTOR = UINT32_C(0xBFC00000) 24 }; 25 enum : PhysicalMemoryAddress 26 { 27 SCRATCHPAD_ADDR = UINT32_C(0x1F800000), 28 SCRATCHPAD_ADDR_MASK = UINT32_C(0x7FFFFC00), 29 SCRATCHPAD_OFFSET_MASK = UINT32_C(0x000003FF), 30 SCRATCHPAD_SIZE = UINT32_C(0x00000400), 31 ICACHE_SIZE = UINT32_C(0x00001000), 32 ICACHE_SLOTS = ICACHE_SIZE / sizeof(u32), 33 ICACHE_LINE_SIZE = 16, 34 ICACHE_LINES = ICACHE_SIZE / ICACHE_LINE_SIZE, 35 ICACHE_SLOTS_PER_LINE = ICACHE_SLOTS / ICACHE_LINES, 36 ICACHE_TAG_ADDRESS_MASK = 0xFFFFFFF0u, 37 ICACHE_INVALID_BITS = 0x0Fu, 38 }; 39 40 union CacheControl 41 { 42 u32 bits; 43 44 BitField<u32, bool, 0, 1> lock_mode; 45 BitField<u32, bool, 1, 1> invalidate_mode; 46 BitField<u32, bool, 2, 1> tag_test_mode; 47 BitField<u32, bool, 3, 1> dcache_scratchpad; 48 BitField<u32, bool, 7, 1> dcache_enable; 49 BitField<u32, u8, 8, 2> icache_fill_size; // actually dcache? icache always fills to 16 bytes 50 BitField<u32, bool, 11, 1> icache_enable; 51 }; 52 53 struct PGXPValue 54 { 55 float x; 56 float y; 57 float z; 58 u32 value; 59 u32 flags; 60 61 ALWAYS_INLINE void Validate(u32 psxval) { flags = (value == psxval) ? flags : 0; } 62 63 ALWAYS_INLINE float GetValidX(u32 psxval) const 64 { 65 return (flags & 1) ? x : static_cast<float>(static_cast<s16>(psxval)); 66 } 67 ALWAYS_INLINE float GetValidY(u32 psxval) const 68 { 69 return (flags & 2) ? y : static_cast<float>(static_cast<s16>(psxval >> 16)); 70 } 71 }; 72 73 struct State 74 { 75 // ticks the CPU has executed 76 u32 downcount = 0; 77 u32 pending_ticks = 0; 78 u32 gte_completion_tick = 0; 79 80 Registers regs = {}; 81 Cop0Registers cop0_regs = {}; 82 83 u32 pc; // at execution time: the address of the next instruction to execute (already fetched) 84 u32 npc; // at execution time: the address of the next instruction to fetch 85 86 // address of the instruction currently being executed 87 Instruction current_instruction = {}; 88 u32 current_instruction_pc = 0; 89 bool current_instruction_in_branch_delay_slot = false; 90 bool current_instruction_was_branch_taken = false; 91 bool next_instruction_is_branch_delay_slot = false; 92 bool branch_was_taken = false; 93 bool exception_raised = false; 94 bool bus_error = false; 95 96 // load delays 97 Reg load_delay_reg = Reg::count; 98 Reg next_load_delay_reg = Reg::count; 99 u32 load_delay_value = 0; 100 u32 next_load_delay_value = 0; 101 102 Instruction next_instruction = {}; 103 CacheControl cache_control{0}; 104 105 // GTE registers are stored here so we can access them on ARM with a single instruction 106 GTE::Regs gte_regs = {}; 107 108 // 2 bytes of padding here on x64 109 bool using_interpreter = false; 110 bool using_debug_dispatcher = false; 111 112 void* fastmem_base = nullptr; 113 void** memory_handlers = nullptr; 114 115 PGXPValue pgxp_gpr[static_cast<u8>(Reg::count)] = {}; 116 PGXPValue pgxp_cop0[32] = {}; 117 PGXPValue pgxp_gte[64] = {}; 118 119 std::array<u32, ICACHE_LINES> icache_tags = {}; 120 std::array<u8, ICACHE_SIZE> icache_data = {}; 121 122 std::array<u8, SCRATCHPAD_SIZE> scratchpad = {}; 123 124 static constexpr u32 GPRRegisterOffset(u32 index) { return OFFSETOF(State, regs.r) + (sizeof(u32) * index); } 125 static constexpr u32 GTERegisterOffset(u32 index) { return OFFSETOF(State, gte_regs.r32) + (sizeof(u32) * index); } 126 }; 127 128 ALIGN_TO_CACHE_LINE extern State g_state; 129 130 void Initialize(); 131 void Shutdown(); 132 void Reset(); 133 bool DoState(StateWrapper& sw); 134 void ClearICache(); 135 bool UpdateDebugDispatcherFlag(); 136 void UpdateMemoryPointers(); 137 void ExecutionModeChanged(); 138 139 /// Executes interpreter loop. 140 void Execute(); 141 142 // Forces an early exit from the CPU dispatcher. 143 [[noreturn]] void ExitExecution(); 144 145 ALWAYS_INLINE static Registers& GetRegs() 146 { 147 return g_state.regs; 148 } 149 150 ALWAYS_INLINE static u32 GetPendingTicks() 151 { 152 return g_state.pending_ticks; 153 } 154 ALWAYS_INLINE static void ResetPendingTicks() 155 { 156 g_state.gte_completion_tick = 157 (g_state.pending_ticks < g_state.gte_completion_tick) ? (g_state.gte_completion_tick - g_state.pending_ticks) : 0; 158 g_state.pending_ticks = 0; 159 } 160 ALWAYS_INLINE static void AddPendingTicks(TickCount ticks) 161 { 162 g_state.pending_ticks += static_cast<u32>(ticks); 163 } 164 165 // state helpers 166 ALWAYS_INLINE static bool InUserMode() 167 { 168 return g_state.cop0_regs.sr.KUc; 169 } 170 ALWAYS_INLINE static bool InKernelMode() 171 { 172 return !g_state.cop0_regs.sr.KUc; 173 } 174 175 // Memory reads variants which do not raise exceptions. 176 // These methods do not support writing to MMIO addresses with side effects, and are 177 // thus safe to call from the UI thread in debuggers, for example. 178 bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value); 179 bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value); 180 bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value); 181 bool SafeReadMemoryCString(VirtualMemoryAddress addr, std::string* value, u32 max_length = 1024); 182 bool SafeReadMemoryBytes(VirtualMemoryAddress addr, void* data, u32 length); 183 bool SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value); 184 bool SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value); 185 bool SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value); 186 bool SafeWriteMemoryBytes(VirtualMemoryAddress addr, const void* data, u32 length); 187 188 // External IRQs 189 void SetIRQRequest(bool state); 190 191 void DisassembleAndPrint(u32 addr); 192 void DisassembleAndLog(u32 addr); 193 void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_after); 194 195 // Write to CPU execution log file. 196 void WriteToExecutionLog(const char* format, ...) printflike(1, 2); 197 198 // Trace Routines 199 bool IsTraceEnabled(); 200 void StartTrace(); 201 void StopTrace(); 202 203 // Breakpoint types - execute => breakpoint, read/write => watchpoints 204 enum class BreakpointType : u8 205 { 206 Execute, 207 Read, 208 Write, 209 Count 210 }; 211 212 // Breakpoint callback - if the callback returns false, the breakpoint will be removed. 213 using BreakpointCallback = bool (*)(BreakpointType type, VirtualMemoryAddress pc, VirtualMemoryAddress memaddr); 214 215 struct Breakpoint 216 { 217 VirtualMemoryAddress address; 218 BreakpointCallback callback; 219 u32 number; 220 u32 hit_count; 221 BreakpointType type; 222 bool auto_clear; 223 bool enabled; 224 }; 225 226 using BreakpointList = std::vector<Breakpoint>; 227 228 // Breakpoints 229 const char* GetBreakpointTypeName(BreakpointType type); 230 bool HasAnyBreakpoints(); 231 bool HasBreakpointAtAddress(BreakpointType type, VirtualMemoryAddress address); 232 BreakpointList CopyBreakpointList(bool include_auto_clear = false, bool include_callbacks = false); 233 bool AddBreakpoint(BreakpointType type, VirtualMemoryAddress address, bool auto_clear = false, bool enabled = true); 234 bool AddBreakpointWithCallback(BreakpointType type, VirtualMemoryAddress address, BreakpointCallback callback); 235 bool RemoveBreakpoint(BreakpointType type, VirtualMemoryAddress address); 236 void ClearBreakpoints(); 237 bool AddStepOverBreakpoint(); 238 bool AddStepOutBreakpoint(u32 max_instructions_to_search = 1000); 239 void SetSingleStepFlag(); 240 241 extern bool TRACE_EXECUTION; 242 243 // Debug register introspection 244 struct DebuggerRegisterListEntry 245 { 246 const char* name; 247 u32* value_ptr; 248 }; 249 250 static constexpr u32 NUM_DEBUGGER_REGISTER_LIST_ENTRIES = 103; 251 extern const std::array<DebuggerRegisterListEntry, NUM_DEBUGGER_REGISTER_LIST_ENTRIES> g_debugger_register_list; 252 253 } // namespace CPU