duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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