2022-12-04 11:03:45 +00:00
|
|
|
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
|
|
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
|
|
|
|
2020-08-08 05:15:56 +00:00
|
|
|
#pragma once
|
2020-10-16 13:30:56 +00:00
|
|
|
#include "bus.h"
|
2020-10-29 13:04:36 +00:00
|
|
|
#include "cpu_core.h"
|
2020-08-08 05:15:56 +00:00
|
|
|
|
|
|
|
namespace CPU {
|
|
|
|
|
|
|
|
// exceptions
|
|
|
|
void RaiseException(Exception excode);
|
|
|
|
void RaiseException(u32 CAUSE_bits, u32 EPC);
|
2023-04-29 10:45:39 +00:00
|
|
|
void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits);
|
2020-08-08 05:15:56 +00:00
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static bool HasPendingInterrupt()
|
2020-08-08 06:44:12 +00:00
|
|
|
{
|
2020-10-16 15:28:08 +00:00
|
|
|
return g_state.cop0_regs.sr.IEc &&
|
2020-10-29 13:04:36 +00:00
|
|
|
(((g_state.cop0_regs.cause.bits & g_state.cop0_regs.sr.bits) & (UINT32_C(0xFF) << 8)) != 0);
|
2020-08-08 06:44:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static void CheckForPendingInterrupt()
|
2020-08-08 06:44:12 +00:00
|
|
|
{
|
2020-10-16 15:28:08 +00:00
|
|
|
if (HasPendingInterrupt())
|
|
|
|
g_state.downcount = 0;
|
2020-08-08 06:44:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 15:28:08 +00:00
|
|
|
void DispatchInterrupt();
|
2024-01-01 05:25:39 +00:00
|
|
|
bool UpdateDebugDispatcherFlag();
|
2020-10-16 15:28:08 +00:00
|
|
|
|
2020-08-29 12:07:33 +00:00
|
|
|
// icache stuff
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static bool IsCachedAddress(VirtualMemoryAddress address)
|
2020-08-29 12:07:33 +00:00
|
|
|
{
|
|
|
|
// KUSEG, KSEG0
|
|
|
|
return (address >> 29) <= 4;
|
|
|
|
}
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static u32 GetICacheLine(VirtualMemoryAddress address)
|
2020-08-29 12:07:33 +00:00
|
|
|
{
|
|
|
|
return ((address >> 4) & 0xFFu);
|
|
|
|
}
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static u32 GetICacheLineOffset(VirtualMemoryAddress address)
|
2020-08-29 12:07:33 +00:00
|
|
|
{
|
|
|
|
return (address & (ICACHE_LINE_SIZE - 1));
|
|
|
|
}
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static u32 GetICacheTagForAddress(VirtualMemoryAddress address)
|
2020-08-29 12:07:33 +00:00
|
|
|
{
|
|
|
|
return (address & ICACHE_TAG_ADDRESS_MASK);
|
|
|
|
}
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static u32 GetICacheFillTagForAddress(VirtualMemoryAddress address)
|
2020-10-29 13:04:36 +00:00
|
|
|
{
|
|
|
|
static const u32 invalid_bits[4] = {0, 1, 3, 7};
|
|
|
|
return GetICacheTagForAddress(address) | invalid_bits[(address >> 2) & 0x03u];
|
|
|
|
}
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static u32 GetICacheTagMaskForAddress(VirtualMemoryAddress address)
|
2020-10-29 13:04:36 +00:00
|
|
|
{
|
|
|
|
static const u32 mask[4] = {ICACHE_TAG_ADDRESS_MASK | 1, ICACHE_TAG_ADDRESS_MASK | 2, ICACHE_TAG_ADDRESS_MASK | 4,
|
|
|
|
ICACHE_TAG_ADDRESS_MASK | 8};
|
|
|
|
return mask[(address >> 2) & 0x03u];
|
|
|
|
}
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static bool CompareICacheTag(VirtualMemoryAddress address)
|
2020-08-29 12:07:33 +00:00
|
|
|
{
|
|
|
|
const u32 line = GetICacheLine(address);
|
2020-10-29 13:04:36 +00:00
|
|
|
return ((g_state.icache_tags[line] & GetICacheTagMaskForAddress(address)) == GetICacheTagForAddress(address));
|
2020-08-29 12:07:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TickCount GetInstructionReadTicks(VirtualMemoryAddress address);
|
|
|
|
TickCount GetICacheFillTicks(VirtualMemoryAddress address);
|
|
|
|
u32 FillICache(VirtualMemoryAddress address);
|
|
|
|
void CheckAndUpdateICacheTags(u32 line_count, TickCount uncached_ticks);
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static Segment GetSegmentForAddress(VirtualMemoryAddress address)
|
2020-12-16 15:11:50 +00:00
|
|
|
{
|
|
|
|
switch ((address >> 29))
|
|
|
|
{
|
|
|
|
case 0x00: // KUSEG 0M-512M
|
|
|
|
case 0x01: // KUSEG 512M-1024M
|
|
|
|
case 0x02: // KUSEG 1024M-1536M
|
|
|
|
case 0x03: // KUSEG 1536M-2048M
|
|
|
|
return Segment::KUSEG;
|
|
|
|
|
|
|
|
case 0x04: // KSEG0 - physical memory cached
|
|
|
|
return Segment::KSEG0;
|
|
|
|
|
|
|
|
case 0x05: // KSEG1 - physical memory uncached
|
|
|
|
return Segment::KSEG1;
|
|
|
|
|
|
|
|
case 0x06: // KSEG2
|
|
|
|
case 0x07: // KSEG2
|
|
|
|
default:
|
|
|
|
return Segment::KSEG2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static constexpr PhysicalMemoryAddress VirtualAddressToPhysical(VirtualMemoryAddress address)
|
2020-12-16 15:11:50 +00:00
|
|
|
{
|
|
|
|
return (address & PHYSICAL_MEMORY_ADDRESS_MASK);
|
|
|
|
}
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddress address, Segment segment)
|
2020-12-16 15:11:50 +00:00
|
|
|
{
|
|
|
|
static constexpr std::array<VirtualMemoryAddress, 4> bases = {{0x00000000, 0x80000000, 0xA0000000, 0xE0000000}};
|
|
|
|
return bases[static_cast<u32>(segment)] | address;
|
|
|
|
}
|
|
|
|
|
2023-10-01 06:30:28 +00:00
|
|
|
Bus::MemoryReadHandler GetMemoryReadHandler(VirtualMemoryAddress address, MemoryAccessSize size);
|
|
|
|
Bus::MemoryWriteHandler GetMemoryWriteHandler(VirtualMemoryAddress address, MemoryAccessSize size);
|
|
|
|
|
|
|
|
// memory access functions which return false if an exception was thrown.
|
2020-08-29 12:07:33 +00:00
|
|
|
bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value);
|
2020-10-16 13:30:56 +00:00
|
|
|
void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks);
|
|
|
|
void* GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size);
|
2020-08-08 05:15:56 +00:00
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static void AddGTETicks(TickCount ticks)
|
2021-07-15 11:57:52 +00:00
|
|
|
{
|
|
|
|
g_state.gte_completion_tick = g_state.pending_ticks + ticks + 1;
|
|
|
|
}
|
|
|
|
|
2023-08-15 13:12:21 +00:00
|
|
|
ALWAYS_INLINE static void StallUntilGTEComplete()
|
2021-07-15 11:57:52 +00:00
|
|
|
{
|
|
|
|
g_state.pending_ticks =
|
|
|
|
(g_state.gte_completion_tick > g_state.pending_ticks) ? g_state.gte_completion_tick : g_state.pending_ticks;
|
|
|
|
}
|
|
|
|
|
2023-08-29 11:18:04 +00:00
|
|
|
// kernel call interception
|
|
|
|
void HandleA0Syscall();
|
|
|
|
void HandleB0Syscall();
|
|
|
|
|
2020-08-08 05:15:56 +00:00
|
|
|
} // namespace CPU
|