Cache instructions implemented but broken lmao. Commented out for now
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
#include <Core.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void InstructionCache::FillLine(u64 vaddr, u32 paddr) {
|
||||
int index = GetICacheLineIndex(vaddr);
|
||||
auto &line = lines[index];
|
||||
line.valid = true;
|
||||
line.ptag = paddr & ~0x00000fff;
|
||||
auto &mmio = Core::GetMem().mmio;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
line.data[i] = mmio.rdp.ReadRDRAM<u32>(line.ptag | index);
|
||||
}
|
||||
}
|
||||
|
||||
void InstructionCache::StoreTag(u64 vaddr, u32 ptag, Cop0 &cop0) {
|
||||
auto &line = lines[GetICacheLineIndex(vaddr)];
|
||||
|
||||
line.valid = (cop0.tagLo.pstate >> 1) & 1;
|
||||
line.ptag = ptag;
|
||||
}
|
||||
|
||||
void DataCache::StoreTag(u64 vaddr, u32 ptag, Cop0 &cop0) {
|
||||
auto &line = lines[GetDCacheLineIndex(vaddr)];
|
||||
|
||||
line.valid = (cop0.tagLo.pstate >> 1) & 1;
|
||||
line.dirty = (cop0.tagLo.pstate >> 0) & 1;
|
||||
line.ptag = ptag;
|
||||
}
|
||||
|
||||
void InstructionCache::LoadTag(u64 vaddr) {
|
||||
auto &cop0 = Core::GetRegs().cop0;
|
||||
auto &line = lines[GetICacheLineIndex(vaddr)];
|
||||
cop0.tagLo.pstate = line.valid << 1;
|
||||
cop0.tagLo.ptaglo = line.ptag;
|
||||
}
|
||||
|
||||
void DataCache::LoadTag(u64 vaddr) {
|
||||
auto &cop0 = Core::GetRegs().cop0;
|
||||
auto &line = lines[GetDCacheLineIndex(vaddr)];
|
||||
cop0.tagLo.pstate = (line.valid << 1) | line.dirty;
|
||||
cop0.tagLo.ptaglo = line.ptag;
|
||||
}
|
||||
|
||||
template <>
|
||||
void DataCache::WriteBack<false>(u64 vaddr, u32 paddr) {
|
||||
auto &mmio = Core::GetMem().mmio;
|
||||
|
||||
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
|
||||
if (!line.valid)
|
||||
return;
|
||||
|
||||
u32 origPhysAddr = (line.ptag << 12) | (paddr & 0xfff);
|
||||
u32 lineStart = GetDCacheLineStart(origPhysAddr);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
mmio.rdp.WriteRDRAM(lineStart + i, line.data[i]);
|
||||
}
|
||||
|
||||
line.dirty = false;
|
||||
}
|
||||
|
||||
template <>
|
||||
void DataCache::WriteBack<true>(u64 vaddr, u32 paddr) {
|
||||
WriteBack<false>(vaddr, paddr);
|
||||
lines[GetDCacheLineIndex(vaddr)].valid = false;
|
||||
}
|
||||
|
||||
template <>
|
||||
void DataCache::WriteBack<false>(u64 vaddr, u32 paddr, u32 ptag) {
|
||||
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
|
||||
if (line.ptag == ptag)
|
||||
WriteBack(vaddr, paddr);
|
||||
}
|
||||
|
||||
template <>
|
||||
void DataCache::WriteBack<true>(u64 vaddr, u32 paddr, u32 ptag) {
|
||||
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
|
||||
if (line.ptag == ptag)
|
||||
WriteBack<true>(vaddr, paddr);
|
||||
}
|
||||
|
||||
void InstructionCache::WriteBack(u64 vaddr, u32 paddr, u32 ptag) {
|
||||
auto &mmio = Core::GetMem().mmio;
|
||||
ICacheLine &line = lines[GetICacheLineIndex(vaddr)];
|
||||
|
||||
if (line.ptag == ptag && line.valid) {
|
||||
u32 origPhysAddr = (line.ptag << 12) | (paddr & 0xfff);
|
||||
u32 lineStart = GetICacheLineStart(origPhysAddr);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
mmio.rdp.WriteRDRAM(lineStart + i, line.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace n64
|
||||
+44
-10
@@ -1,27 +1,61 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace n64 {
|
||||
struct alignas(32) InstructionCache {
|
||||
struct alignas(32) ICacheLine {
|
||||
bool valid;
|
||||
u32 data[8];
|
||||
u32 ptag;
|
||||
|
||||
private:
|
||||
friend struct Interpreter;
|
||||
int GetLineIndex(u64 vaddr) { return (vaddr >> 5) & 0x1FF; }
|
||||
u32 GetLineStart(u64 paddr) { return paddr & ~0x1F; }
|
||||
};
|
||||
|
||||
struct alignas(32) DataCache {
|
||||
struct alignas(32) DCacheLine {
|
||||
bool valid, dirty;
|
||||
u8 data[16];
|
||||
u32 ptag;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct Cop0;
|
||||
|
||||
inline const u32 GetPhysicalAddressPTag(const u32 paddr) { return paddr >> 12; }
|
||||
inline const int GetICacheLineIndex(u64 vaddr) { return (vaddr >> 5) & 0x1FF; }
|
||||
inline const u32 GetICacheLineStart(u64 paddr) { return paddr & ~0x1F; }
|
||||
inline const int GetDCacheLineIndex(u64 vaddr) { return (vaddr >> 4) & 0x1FF; }
|
||||
inline const u32 GetDCacheLineStart(u64 paddr) { return paddr & ~0xF; }
|
||||
|
||||
struct InstructionCache {
|
||||
std::array<ICacheLine, 512> lines;
|
||||
|
||||
void FillLine(u64, u32);
|
||||
void InvalidateIndex(u64 vaddr) { lines[GetICacheLineIndex(vaddr)].valid = false; }
|
||||
void StoreTag(u64, u32, Cop0 &);
|
||||
void LoadTag(u64 vaddr);
|
||||
|
||||
void WriteBack(u64 vaddr, u32 paddr, u32 ptag);
|
||||
void InvalidateIndex(u64 vaddr, u32 ptag) {
|
||||
int lineIndex = GetICacheLineIndex(vaddr);
|
||||
if (lines[lineIndex].valid && lines[lineIndex].ptag == ptag)
|
||||
lines[lineIndex].valid = false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct Interpreter;
|
||||
int GetLineIndex(u64 vaddr) { return (vaddr >> 4) & 0x1FF; }
|
||||
u32 GetLineStart(u64 paddr) { return paddr & ~0xF; }
|
||||
};
|
||||
|
||||
struct DataCache {
|
||||
std::array<DCacheLine, 512> lines;
|
||||
|
||||
void StoreTag(u64, u32, Cop0 &);
|
||||
void LoadTag(u64 vaddr);
|
||||
template <bool invalidate = false>
|
||||
void WriteBack(u64 vaddr, u32 paddr);
|
||||
template <bool invalidate = false>
|
||||
void WriteBack(u64 vaddr, u32 paddr, u32 ptag);
|
||||
void InvalidateIndex(u64 vaddr) { lines[GetDCacheLineIndex(vaddr)].valid = false; }
|
||||
void InvalidateIndex(u64 vaddr, u32 ptag) {
|
||||
int lineIndex = GetDCacheLineIndex(vaddr);
|
||||
if (lines[lineIndex].valid && lines[lineIndex].ptag == ptag)
|
||||
lines[lineIndex].valid = false;
|
||||
}
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -29,7 +29,7 @@ u32 Interpreter::Step() {
|
||||
|
||||
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ u32 Interpreter::Step() {
|
||||
const u32 instruction = mem.Read<u32>(paddr);
|
||||
|
||||
if (ShouldServiceInterrupt()) {
|
||||
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Interrupt, 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ struct Interpreter final {
|
||||
u64 cop2Latch{};
|
||||
friend struct Cop1;
|
||||
|
||||
void cache_type_data(u8);
|
||||
void cache_type_instruction(u8);
|
||||
void cache_type_data(u8, u64, u32, u32);
|
||||
void cache_type_instruction(u8, u64, u32, u32);
|
||||
#define check_address_error(mask, vaddr) \
|
||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
||||
|
||||
@@ -43,7 +43,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
||||
|
||||
if (check_address_error(0b11, vaddr)) [[unlikely]] {
|
||||
/*regs.cop0.HandleTLBException(blockPC);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, blockPC);
|
||||
return 1;*/
|
||||
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
|
||||
blockPC, {},
|
||||
|
||||
@@ -26,7 +26,7 @@ void Cop0::dmfc0(const Instruction instr) const {
|
||||
void Cop0::eret() {
|
||||
Registers ®s = Core::GetRegs();
|
||||
if (!regs.cop0.kernelMode) {
|
||||
FireException(ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
|
||||
FireException(Cop0::ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
if (status.erl) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace n64 {
|
||||
template <>
|
||||
auto Cop1::FGR_T<s32>(const Cop0Status &status, const u32 index) -> s32 & {
|
||||
auto Cop1::FGR_T<s32>(const Cop0::Status &status, const u32 index) -> s32 & {
|
||||
if (status.fr) {
|
||||
return fgr[index].int32;
|
||||
}
|
||||
@@ -18,17 +18,17 @@ auto Cop1::FGR_T<s32>(const Cop0Status &status, const u32 index) -> s32 & {
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_T<u32>(const Cop0Status &status, const u32 index) -> u32 & {
|
||||
auto Cop1::FGR_T<u32>(const Cop0::Status &status, const u32 index) -> u32 & {
|
||||
return reinterpret_cast<u32 &>(FGR_T<s32>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_T<float>(const Cop0Status &, const u32 index) -> float & {
|
||||
auto Cop1::FGR_T<float>(const Cop0::Status &, const u32 index) -> float & {
|
||||
return fgr[index].float32;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_T<s64>(const Cop0Status &status, const u32 index) -> s64 & {
|
||||
auto Cop1::FGR_T<s64>(const Cop0::Status &status, const u32 index) -> s64 & {
|
||||
if (status.fr) {
|
||||
return fgr[index].int64;
|
||||
}
|
||||
@@ -37,17 +37,17 @@ auto Cop1::FGR_T<s64>(const Cop0Status &status, const u32 index) -> s64 & {
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_T<u64>(const Cop0Status &status, const u32 index) -> u64 & {
|
||||
auto Cop1::FGR_T<u64>(const Cop0::Status &status, const u32 index) -> u64 & {
|
||||
return reinterpret_cast<u64 &>(FGR_T<s64>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_T<double>(const Cop0Status &, const u32 index) -> double & {
|
||||
auto Cop1::FGR_T<double>(const Cop0::Status &, const u32 index) -> double & {
|
||||
return fgr[index].float64;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<s32>(const Cop0Status &status, const u32 index) -> s32 & {
|
||||
auto Cop1::FGR_S<s32>(const Cop0::Status &status, const u32 index) -> s32 & {
|
||||
if (status.fr) {
|
||||
return fgr[index].int32;
|
||||
}
|
||||
@@ -56,12 +56,12 @@ auto Cop1::FGR_S<s32>(const Cop0Status &status, const u32 index) -> s32 & {
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<u32>(const Cop0Status &status, const u32 index) -> u32 & {
|
||||
auto Cop1::FGR_S<u32>(const Cop0::Status &status, const u32 index) -> u32 & {
|
||||
return reinterpret_cast<u32 &>(FGR_S<s32>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<float>(const Cop0Status &status, const u32 index) -> float & {
|
||||
auto Cop1::FGR_S<float>(const Cop0::Status &status, const u32 index) -> float & {
|
||||
if (status.fr) {
|
||||
return fgr[index].float32;
|
||||
}
|
||||
@@ -70,17 +70,17 @@ auto Cop1::FGR_S<float>(const Cop0Status &status, const u32 index) -> float & {
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<s64>(const Cop0Status &status, const u32 index) -> s64 & {
|
||||
auto Cop1::FGR_S<s64>(const Cop0::Status &status, const u32 index) -> s64 & {
|
||||
return FGR_T<s64>(status, index);
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<u64>(const Cop0Status &status, const u32 index) -> u64 & {
|
||||
auto Cop1::FGR_S<u64>(const Cop0::Status &status, const u32 index) -> u64 & {
|
||||
return reinterpret_cast<u64 &>(FGR_S<s64>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_S<double>(const Cop0Status &status, const u32 index) -> double & {
|
||||
auto Cop1::FGR_S<double>(const Cop0::Status &status, const u32 index) -> double & {
|
||||
if (status.fr) {
|
||||
return fgr[index].float64;
|
||||
}
|
||||
@@ -89,34 +89,34 @@ auto Cop1::FGR_S<double>(const Cop0Status &status, const u32 index) -> double &
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<s32>(const Cop0Status &, const u32 index) -> s32 & {
|
||||
auto Cop1::FGR_D<s32>(const Cop0::Status &, const u32 index) -> s32 & {
|
||||
fgr[index].int32h = 0;
|
||||
return fgr[index].int32;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<u32>(const Cop0Status &status, const u32 index) -> u32 & {
|
||||
auto Cop1::FGR_D<u32>(const Cop0::Status &status, const u32 index) -> u32 & {
|
||||
return reinterpret_cast<u32 &>(FGR_D<s32>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<float>(const Cop0Status &, const u32 index) -> float & {
|
||||
auto Cop1::FGR_D<float>(const Cop0::Status &, const u32 index) -> float & {
|
||||
fgr[index].float32h = 0;
|
||||
return fgr[index].float32;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<s64>(const Cop0Status &, const u32 index) -> s64 & {
|
||||
auto Cop1::FGR_D<s64>(const Cop0::Status &, const u32 index) -> s64 & {
|
||||
return fgr[index].int64;
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<u64>(const Cop0Status &status, const u32 index) -> u64 & {
|
||||
auto Cop1::FGR_D<u64>(const Cop0::Status &status, const u32 index) -> u64 & {
|
||||
return reinterpret_cast<u64 &>(FGR_D<s64>(status, index));
|
||||
}
|
||||
|
||||
template <>
|
||||
auto Cop1::FGR_D<double>(const Cop0Status &status, const u32 index) -> double & {
|
||||
auto Cop1::FGR_D<double>(const Cop0::Status &status, const u32 index) -> double & {
|
||||
return FGR_T<double>(status, index);
|
||||
}
|
||||
|
||||
@@ -138,13 +138,13 @@ bool Cop1::CheckCVTArg<s32>(const float f) {
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f >= 0x1p+31f || f < -0x1p+31f) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -159,13 +159,13 @@ bool Cop1::CheckCVTArg<s32>(const double f) {
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((f >= 0x1p+31 || f < -0x1p+31)) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -180,13 +180,13 @@ bool Cop1::CheckCVTArg<s64>(const float f) {
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((f >= 0x1p+53f || f <= -0x1p+53f)) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,13 +201,13 @@ bool Cop1::CheckCVTArg<s64>(const double f) {
|
||||
case FP_INFINITE:
|
||||
case FP_NAN:
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((f >= 0x1p+53 || f <= -0x1p+53)) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -220,11 +220,11 @@ bool Cop1::CheckArg(const T f) {
|
||||
switch (std::fpclassify(f)) {
|
||||
case FP_SUBNORMAL:
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
case FP_NAN:
|
||||
if (isqnan(f) ? SetCauseInvalid() : (SetCauseUnimplemented(), true)) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -238,19 +238,19 @@ bool Cop1::CheckArgs(const T f1, const T f2) {
|
||||
auto class1 = std::fpclassify(f1), class2 = std::fpclassify(f2);
|
||||
if ((class1 == FP_NAN && !isqnan(f1)) || (class2 == FP_NAN && !isqnan(f2))) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (class1 == FP_SUBNORMAL || class2 == FP_SUBNORMAL) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((class1 == FP_NAN && isqnan(f1)) || (class2 == FP_NAN && isqnan(f2))) {
|
||||
if (SetCauseInvalid()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@ template<>
|
||||
bool Cop1::CheckFPUUsable<true>() {
|
||||
Registers ®s = Core::GetRegs();
|
||||
if (!regs.cop0.status.cu1) {
|
||||
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -271,7 +271,8 @@ bool Cop1::CheckFPUUsable<true>() {
|
||||
|
||||
template <>
|
||||
bool Cop1::CheckFPUUsable<false>() {
|
||||
if (!CheckFPUUsable<true>()) return false;
|
||||
if (!CheckFPUUsable<true>())
|
||||
return false;
|
||||
fcr31.cause = {};
|
||||
return true;
|
||||
}
|
||||
@@ -298,7 +299,7 @@ bool Cop1::CheckResult<float>(float &f) {
|
||||
case FP_SUBNORMAL:
|
||||
if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
SetCauseUnderflow();
|
||||
@@ -321,7 +322,7 @@ bool Cop1::CheckResult<double>(double &f) {
|
||||
case FP_SUBNORMAL:
|
||||
if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
SetCauseUnderflow();
|
||||
@@ -348,7 +349,7 @@ bool Cop1::TestExceptions() {
|
||||
if constexpr (cvt) {
|
||||
if (exc & FE_INVALID) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -356,7 +357,7 @@ bool Cop1::TestExceptions() {
|
||||
if (exc & FE_UNDERFLOW) {
|
||||
if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -374,7 +375,7 @@ bool Cop1::TestExceptions() {
|
||||
if (exc & FE_INVALID)
|
||||
raise |= SetCauseInvalid();
|
||||
if (raise)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return raise;
|
||||
}
|
||||
|
||||
@@ -589,17 +590,17 @@ void Cop1::ctc1(const Instruction instr) {
|
||||
}
|
||||
}
|
||||
if (fcr31.cause.inexact_operation && fcr31.enable.inexact_operation)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
if (fcr31.cause.underflow && fcr31.enable.underflow)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
if (fcr31.cause.overflow && fcr31.enable.overflow)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
if (fcr31.cause.division_by_zero && fcr31.enable.division_by_zero)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
if (fcr31.cause.invalid_operation && fcr31.enable.invalid_operation)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
if (fcr31.cause.unimplemented_operation)
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -639,7 +640,8 @@ void Cop1::cvtsw(const Instruction instr) {
|
||||
return;
|
||||
const auto fs = FGR_S<s32>(regs.cop0.status, instr.fs());
|
||||
CHECK_FPE(float, fd, fs)
|
||||
if (!CheckResult(fd)) return;
|
||||
if (!CheckResult(fd))
|
||||
return;
|
||||
FGR_D<float>(regs.cop0.status, instr.fd()) = fd;
|
||||
}
|
||||
|
||||
@@ -650,7 +652,7 @@ void Cop1::cvtsl(const Instruction instr) {
|
||||
const auto fs = FGR_S<s64>(regs.cop0.status, instr.fs());
|
||||
if (fs >= 0x0080000000000000 || fs < static_cast<s64>(0xff80000000000000)) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
CHECK_FPE(float, fd, fs)
|
||||
@@ -712,7 +714,7 @@ void Cop1::cvtdl(const Instruction instr) {
|
||||
|
||||
if (fs >= 0x0080000000000000 || fs < static_cast<s64>(0xff80000000000000)) {
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
CHECK_FPE(double, fd, fs)
|
||||
@@ -737,11 +739,11 @@ bool Cop1::XORDERED(const T fs, const T ft) {
|
||||
Registers ®s = Core::GetRegs();
|
||||
if (std::isnan(fs) || std::isnan(ft)) {
|
||||
if (std::isnan(fs) && (!quiet || isqnan(fs)) && SetCauseInvalid()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
if (std::isnan(ft) && (!quiet || isqnan(ft)) && SetCauseInvalid()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return false;
|
||||
}
|
||||
fcr31.compare = cf;
|
||||
@@ -1130,7 +1132,7 @@ void Cop1::roundls(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONST(s64, fd, ircolib::roundNearest(fs))
|
||||
if (fd != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s64>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1145,7 +1147,7 @@ void Cop1::roundld(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONST(s64, fd, ircolib::roundNearest(fs))
|
||||
if (fd != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s64>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1160,7 +1162,7 @@ void Cop1::roundws(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONV_CONST(s32, fd, ircolib::roundNearest(fs))
|
||||
if (fd != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s32>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1175,7 +1177,7 @@ void Cop1::roundwd(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONV_CONST(s32, fd, ircolib::roundNearest(fs))
|
||||
if (fd != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s32>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1234,7 +1236,7 @@ void Cop1::truncws(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONV_CONST(s32, fd, ircolib::roundTrunc(fs))
|
||||
if (static_cast<float>(fd) != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s32>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1249,7 +1251,7 @@ void Cop1::truncwd(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONV_CONST(s32, fd, ircolib::roundTrunc(fs))
|
||||
if (static_cast<double>(fd) != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s32>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1264,7 +1266,7 @@ void Cop1::truncls(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONST(s64, fd, ircolib::roundTrunc(fs))
|
||||
if (static_cast<float>(fd) != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s64>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1279,7 +1281,7 @@ void Cop1::truncld(const Instruction instr) {
|
||||
return;
|
||||
CHECK_FPE_CONST(s64, fd, ircolib::roundTrunc(fs))
|
||||
if (static_cast<double>(fd) != fs && SetCauseInexact()) {
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
FGR_D<s64>(regs.cop0.status, instr.fd()) = fd;
|
||||
@@ -1344,7 +1346,7 @@ void Cop1::unimplemented() {
|
||||
if (!CheckFPUUsable())
|
||||
return;
|
||||
SetCauseUnimplemented();
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
}
|
||||
|
||||
void Cop1::mfc1(const Instruction instr) {
|
||||
|
||||
@@ -33,10 +33,10 @@ void Interpreter::special(const Instruction instr) {
|
||||
jalr(instr);
|
||||
break;
|
||||
case Instruction::SYSCALL:
|
||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::BREAK:
|
||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::SYNC:
|
||||
break; // SYNC
|
||||
@@ -222,7 +222,7 @@ void Interpreter::regimm(const Instruction instr) {
|
||||
|
||||
void Interpreter::cop2Decode(const Instruction instr) {
|
||||
if (!regs.cop0.status.cu2) {
|
||||
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
switch (instr.rs()) {
|
||||
@@ -245,7 +245,7 @@ void Interpreter::cop2Decode(const Instruction instr) {
|
||||
ctc2(instr);
|
||||
break;
|
||||
default:
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 2, regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ void Interpreter::Exec(const Instruction instr) {
|
||||
ldr(instr);
|
||||
break;
|
||||
case 0x1F:
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::LB:
|
||||
lb(instr);
|
||||
@@ -409,10 +409,7 @@ void Interpreter::Exec(const Instruction instr) {
|
||||
swr(instr);
|
||||
break;
|
||||
case Instruction::CACHE:
|
||||
{
|
||||
panic("CACHE 0b{:05b}, 0x{:04X}({}/r{} = 0x{:08X})", instr.op(), instr.offset(),
|
||||
Registers::regNames[instr.base()], instr.base(), regs.Read<u64>(instr.base()));
|
||||
}
|
||||
// cache(instr);
|
||||
break;
|
||||
case Instruction::LL:
|
||||
ll(instr);
|
||||
|
||||
@@ -8,7 +8,7 @@ void Interpreter::add(const Instruction instr) {
|
||||
const u32 rs = regs.Read<s32>(instr.rs());
|
||||
const u32 rt = regs.Read<s32>(instr.rt());
|
||||
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rd(), static_cast<s32>(result));
|
||||
}
|
||||
@@ -25,7 +25,7 @@ void Interpreter::addi(const Instruction instr) {
|
||||
const u32 rs = regs.Read<s64>(instr.rs());
|
||||
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
|
||||
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rt(), static_cast<s32>(result));
|
||||
}
|
||||
@@ -42,7 +42,7 @@ void Interpreter::dadd(const Instruction instr) {
|
||||
const u64 rs = regs.Read<s64>(instr.rs());
|
||||
const u64 rt = regs.Read<s64>(instr.rt());
|
||||
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rd(), result);
|
||||
}
|
||||
@@ -58,7 +58,7 @@ void Interpreter::daddi(const Instruction instr) {
|
||||
const u64 imm = s64(s16(instr));
|
||||
const u64 rs = regs.Read<s64>(instr.rs());
|
||||
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rt(), result);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ void Interpreter::lh(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ void Interpreter::lw(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ void Interpreter::ll(const Instruction instr) {
|
||||
} else {
|
||||
const s32 result = mem.Read<u32>(physical);
|
||||
if (check_address_error(0b11, address)) {
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ void Interpreter::ld(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ void Interpreter::ld(const Instruction instr) {
|
||||
|
||||
void Interpreter::lld(const Instruction instr) {
|
||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ void Interpreter::lld(const Instruction instr) {
|
||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
if (check_address_error(0b111, address)) {
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rt(), mem.Read<u64>(paddr));
|
||||
regs.cop0.llbit = true;
|
||||
@@ -369,7 +369,7 @@ void Interpreter::lhu(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
u32 paddr;
|
||||
@@ -386,7 +386,7 @@ void Interpreter::lwu(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b11, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ void Interpreter::sc(const Instruction instr) {
|
||||
if (check_address_error(0b11, address)) {
|
||||
regs.Write(instr.rt(), 0);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ void Interpreter::sc(const Instruction instr) {
|
||||
|
||||
void Interpreter::scd(const Instruction instr) {
|
||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ void Interpreter::scd(const Instruction instr) {
|
||||
if (check_address_error(0b111, address)) {
|
||||
regs.Write(instr.rt(), 0);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -487,7 +487,7 @@ void Interpreter::sw(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -504,7 +504,7 @@ void Interpreter::sd(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ void Interpreter::dsub(const Instruction instr) {
|
||||
const s64 rt = regs.Read<s64>(instr.rt());
|
||||
const s64 rs = regs.Read<s64>(instr.rs());
|
||||
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rd(), result);
|
||||
}
|
||||
@@ -775,7 +775,7 @@ void Interpreter::sub(const Instruction instr) {
|
||||
const s32 rs = regs.Read<s64>(instr.rs());
|
||||
const s32 result = rs - rt;
|
||||
if (check_signed_underflow(rs, rt, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rd(), result);
|
||||
}
|
||||
@@ -831,7 +831,7 @@ void Interpreter::mthi(const Instruction instr) { regs.hi = regs.Read<s64>(instr
|
||||
void Interpreter::trap(const bool cond) const {
|
||||
Cop0 &cop0 = Core::GetRegs().cop0;
|
||||
if (cond) {
|
||||
cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
|
||||
cop0.FireException(Cop0::ExceptionCode::Trap, 0, regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -852,21 +852,84 @@ void Interpreter::cfc2(const Instruction) {}
|
||||
|
||||
void Interpreter::cache(const Instruction instr) {
|
||||
u8 type = instr.op() & 3;
|
||||
u8 op = (instr.op() >> 2) & 7;
|
||||
const u8 op = (instr.op() >> 2) & 7;
|
||||
u64 vaddr = regs.Read<u64>(instr.rs()) + (s16)instr.offset();
|
||||
u32 paddr;
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, vaddr, paddr)) {
|
||||
regs.cop0.HandleTLBException(vaddr);
|
||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 ptag = GetPhysicalAddressPTag(paddr);
|
||||
|
||||
if (type > 1)
|
||||
panic("Unknown cache type {}", type);
|
||||
|
||||
if (type == 0)
|
||||
return cache_type_instruction(op);
|
||||
return cache_type_instruction(op, vaddr, paddr, ptag);
|
||||
|
||||
if (type == 1)
|
||||
return cache_type_data(op);
|
||||
return cache_type_data(op, vaddr, paddr, ptag);
|
||||
}
|
||||
|
||||
void Interpreter::cache_type_instruction(const u8 op) {
|
||||
void Interpreter::cache_type_instruction(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) {
|
||||
switch (op) {
|
||||
case 0:
|
||||
icache.
|
||||
icache.InvalidateIndex(vaddr);
|
||||
break;
|
||||
case 1:
|
||||
icache.LoadTag(vaddr);
|
||||
break;
|
||||
case 2:
|
||||
icache.StoreTag(vaddr, regs.cop0.tagLo.ptaglo, regs.cop0);
|
||||
break;
|
||||
case 4:
|
||||
icache.InvalidateIndex(vaddr, ptag);
|
||||
break;
|
||||
case 5:
|
||||
icache.FillLine(vaddr, paddr);
|
||||
break;
|
||||
case 6:
|
||||
icache.WriteBack(vaddr, paddr, ptag);
|
||||
break;
|
||||
default:
|
||||
panic("Unimplemented icache op 0b{:03b}", op);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::cache_type_data(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) {
|
||||
switch (op) {
|
||||
case 0:
|
||||
dcache.WriteBack<true>(vaddr, paddr);
|
||||
break;
|
||||
case 1:
|
||||
dcache.LoadTag(vaddr);
|
||||
break;
|
||||
case 2:
|
||||
dcache.StoreTag(vaddr, regs.cop0.tagLo.ptaglo, regs.cop0);
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
auto &line = dcache.lines[GetDCacheLineIndex(vaddr)];
|
||||
if ((line.ptag != ptag || !line.valid) && line.dirty)
|
||||
dcache.WriteBack(vaddr, paddr);
|
||||
|
||||
line.ptag = ptag;
|
||||
line.valid = true;
|
||||
line.dirty = true;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
dcache.InvalidateIndex(vaddr, ptag);
|
||||
break;
|
||||
case 5:
|
||||
dcache.WriteBack<true>(vaddr, paddr, ptag);
|
||||
break;
|
||||
case 6:
|
||||
dcache.WriteBack(vaddr, paddr, ptag);
|
||||
break;
|
||||
default:
|
||||
panic("Unimplemented dcache op 0b{:03b}", op);
|
||||
}
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
@@ -32,10 +32,10 @@ void JIT::special(const Instruction instr) {
|
||||
jalr(instr);
|
||||
break;
|
||||
case Instruction::SYSCALL:
|
||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::BREAK:
|
||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::SYNC:
|
||||
break; // SYNC
|
||||
@@ -311,8 +311,7 @@ void JIT::Emit(const Instruction instr) {
|
||||
emitMemberFunctionCall(&Cop0::eret, ®s.cop0);
|
||||
break;
|
||||
default:
|
||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
|
||||
regs.oldPC);
|
||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr), regs.oldPC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -378,7 +377,7 @@ void JIT::Emit(const Instruction instr) {
|
||||
ldr(instr);
|
||||
break;
|
||||
case 0x1F:
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
break;
|
||||
case Instruction::LB:
|
||||
lb(instr);
|
||||
@@ -459,7 +458,8 @@ void JIT::Emit(const Instruction instr) {
|
||||
break;
|
||||
default:
|
||||
DumpBlockCacheToDisk();
|
||||
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr), static_cast<u64>(regs.oldPC));
|
||||
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr),
|
||||
static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
@@ -18,7 +18,7 @@ void JIT::add(const Instruction instr) {
|
||||
const u32 rt = regs.Read<s32>(instr.rt());
|
||||
const u32 result = rs + rt;
|
||||
if (check_signed_overflow(rs, rt, result)) {
|
||||
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled Overflow exception in ADD!");
|
||||
}
|
||||
|
||||
@@ -205,13 +205,9 @@ void JIT::BranchTaken(const Xbyak::Reg64 &offs) {
|
||||
SetPC64(code.SCR2);
|
||||
}
|
||||
|
||||
void JIT::BranchAbsTaken(const s64 addr) {
|
||||
SetPC64(addr);
|
||||
}
|
||||
void JIT::BranchAbsTaken(const s64 addr) { SetPC64(addr); }
|
||||
|
||||
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) {
|
||||
SetPC64(addr);
|
||||
}
|
||||
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) { SetPC64(addr); }
|
||||
|
||||
void JIT::branch_constant(const bool cond, const s64 offset) {
|
||||
if (cond) {
|
||||
@@ -239,7 +235,8 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
|
||||
}
|
||||
}
|
||||
|
||||
#define branch(offs, cond) do { \
|
||||
#define branch(offs, cond) \
|
||||
do { \
|
||||
Xbyak::Label taken, not_taken; \
|
||||
code.j##cond(taken); \
|
||||
code.jmp(not_taken); \
|
||||
@@ -247,9 +244,11 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
|
||||
BranchTaken(offs); \
|
||||
code.mov(code.byte[code.rbp + BRANCH_TAKEN_OFFSET], 1); \
|
||||
code.L(not_taken); \
|
||||
} while(0)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define branch_abs(addr, cond) do { \
|
||||
#define branch_abs(addr, cond) \
|
||||
do { \
|
||||
Xbyak::Label taken, not_taken; \
|
||||
code.j##cond(taken); \
|
||||
code.jmp(not_taken); \
|
||||
@@ -257,9 +256,11 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
|
||||
BranchAbsTaken(addr); \
|
||||
code.mov(code.byte[code.rbp + BRANCH_TAKEN_OFFSET], 1); \
|
||||
code.L(not_taken); \
|
||||
} while(0)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define branch_likely(offs, cond) do { \
|
||||
#define branch_likely(offs, cond) \
|
||||
do { \
|
||||
Xbyak::Label taken, not_taken, end; \
|
||||
code.j##cond(taken); \
|
||||
code.jmp(not_taken); \
|
||||
@@ -270,7 +271,8 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
|
||||
code.L(not_taken); \
|
||||
SetPC64(blockNextPC); \
|
||||
code.L(end); \
|
||||
} while(0)
|
||||
} \
|
||||
while (0)
|
||||
|
||||
void JIT::bltz(const Instruction instr) {
|
||||
const s16 imm = instr;
|
||||
@@ -558,7 +560,7 @@ void JIT::dadd(const Instruction instr) {
|
||||
auto rt = regs.Read<u64>(instr.rt());
|
||||
u64 result = rt + rs;
|
||||
if (check_signed_overflow(rs, rt, result)) {
|
||||
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled Overflow exception in DADD!");
|
||||
}
|
||||
regs.Write(instr.rd(), result);
|
||||
@@ -598,7 +600,7 @@ void JIT::daddi(const Instruction instr) {
|
||||
auto rs = regs.Read<u64>(instr.rs());
|
||||
u64 result = imm + rs;
|
||||
if (check_signed_overflow(rs, imm, result)) {
|
||||
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled Overflow exception in DADDI!");
|
||||
}
|
||||
regs.Write(instr.rt(), result);
|
||||
@@ -842,7 +844,7 @@ void JIT::dsub(const Instruction instr) {
|
||||
auto rs = regs.Read<s64>(instr.rs());
|
||||
s64 result = rs - rt;
|
||||
if (check_signed_underflow(rs, rt, result)) {
|
||||
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled Overflow exception in DSUB!");
|
||||
} else {
|
||||
regs.Write(instr.rd(), result);
|
||||
@@ -930,7 +932,7 @@ void JIT::ld(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
// regs.cop0.HandleTLBException(address);
|
||||
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// return;
|
||||
panic("[JIT]: Unhandled ADEL exception in LD!");
|
||||
}
|
||||
@@ -1014,7 +1016,7 @@ void JIT::lh(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
// regs.cop0.HandleTLBException(address);
|
||||
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// return;
|
||||
panic("[JIT]: Unhandled ADEL exception in LH!");
|
||||
return;
|
||||
@@ -1043,7 +1045,7 @@ void JIT::lhu(const Instruction instr) {
|
||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1080,7 +1082,7 @@ void JIT::lw(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
// regs.cop0.HandleTLBException(address);
|
||||
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
// return;
|
||||
panic("[JIT]: Unhandled ADEL exception in LW!");
|
||||
return;
|
||||
@@ -1283,7 +1285,7 @@ void JIT::sub(const Instruction instr) {
|
||||
s32 rs = regs.Read<s64>(instr.rs());
|
||||
s32 result = rs - rt;
|
||||
if (check_signed_underflow(rs, rt, result)) {
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
regs.Write(instr.rd(), result);
|
||||
}
|
||||
@@ -1344,7 +1346,7 @@ void JIT::sw(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
// regs.cop0.HandleTLBException(address);
|
||||
// regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled ADES exception in SW!");
|
||||
return;
|
||||
}
|
||||
@@ -1367,7 +1369,7 @@ void JIT::sw(const Instruction instr) {
|
||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
// regs.cop0.HandleTLBException(address);
|
||||
// regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
panic("[JIT]: Unhandled ADES exception in SW!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ void Cop0::Reset() {
|
||||
LLAddr = {}, WatchLo = {}, WatchHi = {};
|
||||
xcontext = {};
|
||||
r21 = {}, r22 = {}, r23 = {}, r24 = {}, r25 = {};
|
||||
ParityError = {}, CacheError = {}, TagLo = {}, TagHi = {};
|
||||
ParityError = {}, CacheError = {}, tagLo = {}, TagHi = {};
|
||||
ErrorEPC = {};
|
||||
r31 = {};
|
||||
memset(tlb, 0, sizeof(TLBEntry) * 32);
|
||||
@@ -89,7 +89,7 @@ u32 Cop0::GetReg32(const u8 addr) {
|
||||
case COP0_REG_CACHE_ERR:
|
||||
return CacheError;
|
||||
case COP0_REG_TAGLO:
|
||||
return TagLo;
|
||||
return tagLo.raw;
|
||||
case COP0_REG_TAGHI:
|
||||
return TagHi;
|
||||
case COP0_REG_ERROREPC:
|
||||
@@ -186,7 +186,7 @@ void Cop0::SetReg32(const u8 addr, const u32 value) {
|
||||
break;
|
||||
case COP0_REG_CAUSE:
|
||||
{
|
||||
Cop0Cause tmp{};
|
||||
Cause tmp{};
|
||||
tmp.raw = value;
|
||||
cause.ip0 = tmp.ip0;
|
||||
cause.ip1 = tmp.ip1;
|
||||
@@ -219,7 +219,7 @@ void Cop0::SetReg32(const u8 addr, const u32 value) {
|
||||
case COP0_REG_CACHE_ERR:
|
||||
break;
|
||||
case COP0_REG_TAGLO:
|
||||
TagLo = value;
|
||||
tagLo.raw = value;
|
||||
break;
|
||||
case COP0_REG_TAGHI:
|
||||
TagHi = value;
|
||||
@@ -263,7 +263,7 @@ void Cop0::SetReg64(const u8 addr, const u64 value) {
|
||||
break;
|
||||
case COP0_REG_CAUSE:
|
||||
{
|
||||
Cop0Cause tmp{};
|
||||
Cause tmp{};
|
||||
tmp.raw = value;
|
||||
cause.ip0 = tmp.ip0;
|
||||
cause.ip1 = tmp.ip1;
|
||||
@@ -292,7 +292,7 @@ static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) {
|
||||
return vpn & ~mask;
|
||||
}
|
||||
|
||||
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
|
||||
Cop0::TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
TLBEntry *entry = &tlb[i];
|
||||
if (!entry->initialized)
|
||||
@@ -314,7 +314,7 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) {
|
||||
Cop0::TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) {
|
||||
for (auto &t : tlb) {
|
||||
TLBEntry *entry = &t;
|
||||
if (!entry->initialized)
|
||||
@@ -366,8 +366,10 @@ void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) {
|
||||
u16 vectorOffset = 0x0180;
|
||||
if (tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) {
|
||||
if (!status.exl) {
|
||||
if(is64BitAddressing) vectorOffset = 0x0080;
|
||||
else vectorOffset = 0x0000;
|
||||
if (is64BitAddressing)
|
||||
vectorOffset = 0x0080;
|
||||
else
|
||||
vectorOffset = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +404,7 @@ void Cop0::HandleTLBException(const u64 vaddr) {
|
||||
entryHi.r = vaddr >> 62 & 3;
|
||||
}
|
||||
|
||||
ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
|
||||
Cop0::ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
|
||||
switch (error) {
|
||||
case NONE:
|
||||
panic("Getting TLB exception with error NONE");
|
||||
@@ -422,20 +424,37 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
|
||||
void Cop0::decode(const Instruction instr) {
|
||||
Registers ®s = Core::GetRegs();
|
||||
switch (instr.cop_rs()) {
|
||||
case 0x00: mfc0(instr); break;
|
||||
case 0x01: dmfc0(instr); break;
|
||||
case 0x04: mtc0(instr); break;
|
||||
case 0x05: dmtc0(instr); break;
|
||||
case 0x00:
|
||||
mfc0(instr);
|
||||
break;
|
||||
case 0x01:
|
||||
dmfc0(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
mtc0(instr);
|
||||
break;
|
||||
case 0x05:
|
||||
dmtc0(instr);
|
||||
break;
|
||||
case 0x10 ... 0x1F:
|
||||
switch (instr.cop_funct()) {
|
||||
case 0x01: tlbr(); break;
|
||||
case 0x02: tlbw(index.i); break;
|
||||
case 0x06: tlbw(GetRandom()); break;
|
||||
case 0x08: tlbp(); break;
|
||||
case 0x18: eret(); break;
|
||||
case 0x01:
|
||||
tlbr();
|
||||
break;
|
||||
case 0x02:
|
||||
tlbw(index.i);
|
||||
break;
|
||||
case 0x06:
|
||||
tlbw(GetRandom());
|
||||
break;
|
||||
case 0x08:
|
||||
tlbp();
|
||||
break;
|
||||
case 0x18:
|
||||
eret();
|
||||
break;
|
||||
default:
|
||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
|
||||
regs.oldPC);
|
||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr), regs.oldPC);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -537,14 +556,18 @@ bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr)
|
||||
panic("Supervisor mode memory access");
|
||||
|
||||
if (is64BitAddressing) [[unlikely]] {
|
||||
if (kernelMode) [[likely]] return MapVirtualAddress<u64, false>(accessType, vaddr, paddr);
|
||||
if (userMode) return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
|
||||
if (kernelMode) [[likely]]
|
||||
return MapVirtualAddress<u64, false>(accessType, vaddr, paddr);
|
||||
if (userMode)
|
||||
return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
|
||||
|
||||
panic("Unknown mode! This should never happen!");
|
||||
}
|
||||
|
||||
if (kernelMode) [[likely]] return MapVirtualAddress<u32, false>(accessType, vaddr, paddr);
|
||||
if (userMode) return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
|
||||
if (kernelMode) [[likely]]
|
||||
return MapVirtualAddress<u32, false>(accessType, vaddr, paddr);
|
||||
if (userMode)
|
||||
return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
|
||||
|
||||
panic("Unknown mode! This should never happen!");
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace n64 {
|
||||
#define ENTRY_HI_MASK 0xC00000FFFFFFE0FF
|
||||
#define PAGEMASK_MASK 0x1FFE000
|
||||
|
||||
union Cop0Cause {
|
||||
struct Cop0 {
|
||||
union Cause {
|
||||
u32 raw;
|
||||
struct {
|
||||
unsigned : 8;
|
||||
@@ -64,7 +65,7 @@ union Cop0Cause {
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
union Cop0Status {
|
||||
union Status {
|
||||
struct {
|
||||
unsigned ie : 1;
|
||||
unsigned exl : 1;
|
||||
@@ -170,7 +171,7 @@ enum class ExceptionCode : u8 {
|
||||
Watch = 23
|
||||
};
|
||||
|
||||
union Cop0Context {
|
||||
union Context {
|
||||
u64 raw;
|
||||
struct {
|
||||
u64 : 4;
|
||||
@@ -179,7 +180,7 @@ union Cop0Context {
|
||||
};
|
||||
};
|
||||
|
||||
union Cop0XContext {
|
||||
union XContext {
|
||||
u64 raw;
|
||||
struct {
|
||||
u64 : 4;
|
||||
@@ -189,7 +190,16 @@ union Cop0XContext {
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
struct Cop0 {
|
||||
union TagLo {
|
||||
u32 raw;
|
||||
struct {
|
||||
u64 : 4;
|
||||
u64 ptaglo : 20;
|
||||
u64 pstate : 2;
|
||||
u64 : 6;
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
|
||||
Cop0();
|
||||
|
||||
bool kernelMode{true};
|
||||
@@ -199,19 +209,20 @@ struct Cop0 {
|
||||
bool llbit{};
|
||||
TLBError tlbError = NONE;
|
||||
|
||||
TagLo tagLo;
|
||||
PageMask pageMask{};
|
||||
EntryHi entryHi{};
|
||||
EntryLo entryLo0{}, entryLo1{};
|
||||
Index index{};
|
||||
Cop0Context context{};
|
||||
Context context{};
|
||||
u32 wired{}, r7{};
|
||||
u32 compare{};
|
||||
Cop0Status status{};
|
||||
Cop0Cause cause{};
|
||||
Status status{};
|
||||
Cause cause{};
|
||||
u32 PRId{}, Config{}, LLAddr{}, WatchLo{}, WatchHi{};
|
||||
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagLo{}, TagHi{};
|
||||
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagHi{};
|
||||
u32 r31{};
|
||||
Cop0XContext xcontext{};
|
||||
XContext xcontext{};
|
||||
u64 badVaddr{}, count{};
|
||||
s64 EPC{};
|
||||
s64 ErrorEPC{};
|
||||
|
||||
@@ -152,11 +152,11 @@ struct Cop1 {
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
auto FGR_T(const Cop0Status &, u32) -> T &;
|
||||
auto FGR_T(const Cop0::Status &, u32) -> T &;
|
||||
template <typename T>
|
||||
auto FGR_S(const Cop0Status &, u32) -> T &;
|
||||
auto FGR_S(const Cop0::Status &, u32) -> T &;
|
||||
template <typename T>
|
||||
auto FGR_D(const Cop0Status &, u32) -> T &;
|
||||
auto FGR_D(const Cop0::Status &, u32) -> T &;
|
||||
void absd(const Instruction instr);
|
||||
void abss(const Instruction instr);
|
||||
void adds(const Instruction instr);
|
||||
|
||||
Reference in New Issue
Block a user