cpu_core_private.h (4153B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 #include "bus.h" 6 #include "cpu_core.h" 7 8 namespace CPU { 9 10 void SetPC(u32 new_pc); 11 12 // exceptions 13 void RaiseException(Exception excode); 14 void RaiseException(u32 CAUSE_bits, u32 EPC); 15 void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits); 16 17 ALWAYS_INLINE static bool HasPendingInterrupt() 18 { 19 return g_state.cop0_regs.sr.IEc && 20 (((g_state.cop0_regs.cause.bits & g_state.cop0_regs.sr.bits) & (UINT32_C(0xFF) << 8)) != 0); 21 } 22 23 ALWAYS_INLINE static void CheckForPendingInterrupt() 24 { 25 if (HasPendingInterrupt()) 26 g_state.downcount = 0; 27 } 28 29 void DispatchInterrupt(); 30 31 // icache stuff 32 ALWAYS_INLINE static bool IsCachedAddress(VirtualMemoryAddress address) 33 { 34 // KUSEG, KSEG0 35 return (address >> 29) <= 4; 36 } 37 ALWAYS_INLINE static u32 GetICacheLine(VirtualMemoryAddress address) 38 { 39 return ((address >> 4) & 0xFFu); 40 } 41 ALWAYS_INLINE static u32 GetICacheLineOffset(VirtualMemoryAddress address) 42 { 43 return (address & (ICACHE_LINE_SIZE - 1)); 44 } 45 ALWAYS_INLINE static u32 GetICacheTagForAddress(VirtualMemoryAddress address) 46 { 47 return (address & ICACHE_TAG_ADDRESS_MASK); 48 } 49 ALWAYS_INLINE static u32 GetICacheFillTagForAddress(VirtualMemoryAddress address) 50 { 51 static const u32 invalid_bits[4] = {0, 1, 3, 7}; 52 return GetICacheTagForAddress(address) | invalid_bits[(address >> 2) & 0x03u]; 53 } 54 ALWAYS_INLINE static u32 GetICacheTagMaskForAddress(VirtualMemoryAddress address) 55 { 56 static const u32 mask[4] = {ICACHE_TAG_ADDRESS_MASK | 1, ICACHE_TAG_ADDRESS_MASK | 2, ICACHE_TAG_ADDRESS_MASK | 4, 57 ICACHE_TAG_ADDRESS_MASK | 8}; 58 return mask[(address >> 2) & 0x03u]; 59 } 60 61 ALWAYS_INLINE static bool CompareICacheTag(VirtualMemoryAddress address) 62 { 63 const u32 line = GetICacheLine(address); 64 return ((g_state.icache_tags[line] & GetICacheTagMaskForAddress(address)) == GetICacheTagForAddress(address)); 65 } 66 67 TickCount GetInstructionReadTicks(VirtualMemoryAddress address); 68 TickCount GetICacheFillTicks(VirtualMemoryAddress address); 69 u32 FillICache(VirtualMemoryAddress address); 70 void CheckAndUpdateICacheTags(u32 line_count); 71 72 ALWAYS_INLINE static Segment GetSegmentForAddress(VirtualMemoryAddress address) 73 { 74 switch ((address >> 29)) 75 { 76 case 0x00: // KUSEG 0M-512M 77 case 0x01: // KUSEG 512M-1024M 78 case 0x02: // KUSEG 1024M-1536M 79 case 0x03: // KUSEG 1536M-2048M 80 return Segment::KUSEG; 81 82 case 0x04: // KSEG0 - physical memory cached 83 return Segment::KSEG0; 84 85 case 0x05: // KSEG1 - physical memory uncached 86 return Segment::KSEG1; 87 88 case 0x06: // KSEG2 89 case 0x07: // KSEG2 90 default: 91 return Segment::KSEG2; 92 } 93 } 94 95 ALWAYS_INLINE static constexpr PhysicalMemoryAddress VirtualAddressToPhysical(VirtualMemoryAddress address) 96 { 97 return (address & PHYSICAL_MEMORY_ADDRESS_MASK); 98 } 99 100 ALWAYS_INLINE static VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddress address, Segment segment) 101 { 102 static constexpr std::array<VirtualMemoryAddress, 4> bases = {{0x00000000, 0x80000000, 0xA0000000, 0xE0000000}}; 103 return bases[static_cast<u32>(segment)] | address; 104 } 105 106 Bus::MemoryReadHandler GetMemoryReadHandler(VirtualMemoryAddress address, MemoryAccessSize size); 107 Bus::MemoryWriteHandler GetMemoryWriteHandler(VirtualMemoryAddress address, MemoryAccessSize size); 108 109 // memory access functions which return false if an exception was thrown. 110 bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value); 111 void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks); 112 void* GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size); 113 114 ALWAYS_INLINE static void AddGTETicks(TickCount ticks) 115 { 116 g_state.gte_completion_tick = g_state.pending_ticks + ticks + 1; 117 } 118 119 ALWAYS_INLINE static void StallUntilGTEComplete() 120 { 121 g_state.pending_ticks = 122 (g_state.gte_completion_tick > g_state.pending_ticks) ? g_state.gte_completion_tick : g_state.pending_ticks; 123 } 124 125 // kernel call interception 126 void HandleA0Syscall(); 127 void HandleB0Syscall(); 128 129 } // namespace CPU