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
|
#pragma once
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct alignas(32) InstructionCache {
|
struct alignas(32) ICacheLine {
|
||||||
bool valid;
|
bool valid;
|
||||||
u32 data[8];
|
u32 data[8];
|
||||||
u32 ptag;
|
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;
|
bool valid, dirty;
|
||||||
u8 data[16];
|
u8 data[16];
|
||||||
u32 ptag;
|
u32 ptag;
|
||||||
int index;
|
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:
|
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
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Interpreter::Interpreter(Mem& mem, Registers& regs) : regs(regs), mem(mem) {}
|
Interpreter::Interpreter(Mem &mem, Registers ®s) : regs(regs), mem(mem) {}
|
||||||
|
|
||||||
bool Interpreter::ShouldServiceInterrupt() const {
|
bool Interpreter::ShouldServiceInterrupt() const {
|
||||||
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||||
const bool interrupts_enabled = regs.cop0.status.ie == 1;
|
const bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||||
const bool currently_handling_exception = regs.cop0.status.exl == 1;
|
const bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||||
const bool currently_handling_error = regs.cop0.status.erl == 1;
|
const bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||||
|
|
||||||
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::CheckCompareInterrupt() const {
|
void Interpreter::CheckCompareInterrupt() const {
|
||||||
regs.cop0.count++;
|
regs.cop0.count++;
|
||||||
regs.cop0.count &= 0x1FFFFFFFF;
|
regs.cop0.count &= 0x1FFFFFFFF;
|
||||||
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
||||||
regs.cop0.cause.ip7 = 1;
|
regs.cop0.cause.ip7 = 1;
|
||||||
mem.mmio.mi.UpdateInterrupt();
|
mem.mmio.mi.UpdateInterrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Interpreter::Step() {
|
u32 Interpreter::Step() {
|
||||||
CheckCompareInterrupt();
|
CheckCompareInterrupt();
|
||||||
|
|
||||||
regs.prevDelaySlot = regs.delaySlot;
|
regs.prevDelaySlot = regs.delaySlot;
|
||||||
regs.delaySlot = false;
|
regs.delaySlot = false;
|
||||||
|
|
||||||
|
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
|
||||||
|
regs.cop0.HandleTLBException(regs.pc);
|
||||||
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 paddr = 0;
|
||||||
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
||||||
|
regs.cop0.HandleTLBException(regs.pc);
|
||||||
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 instruction = mem.Read<u32>(paddr);
|
||||||
|
|
||||||
|
if (ShouldServiceInterrupt()) {
|
||||||
|
regs.cop0.FireException(Cop0::ExceptionCode::Interrupt, 0, regs.pc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.oldPC = regs.pc;
|
||||||
|
regs.pc = regs.nextPC;
|
||||||
|
regs.nextPC += 4;
|
||||||
|
|
||||||
|
Exec(instruction);
|
||||||
|
|
||||||
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
|
|
||||||
regs.cop0.HandleTLBException(regs.pc);
|
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
u32 paddr = 0;
|
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
|
||||||
regs.cop0.HandleTLBException(regs.pc);
|
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 instruction = mem.Read<u32>(paddr);
|
|
||||||
|
|
||||||
if (ShouldServiceInterrupt()) {
|
|
||||||
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs.oldPC = regs.pc;
|
|
||||||
regs.pc = regs.nextPC;
|
|
||||||
regs.nextPC += 4;
|
|
||||||
|
|
||||||
Exec(instruction);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ struct Interpreter final {
|
|||||||
u64 cop2Latch{};
|
u64 cop2Latch{};
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
|
|
||||||
void cache_type_data(u8);
|
void cache_type_data(u8, u64, u32, u32);
|
||||||
void cache_type_instruction(u8);
|
void cache_type_instruction(u8, u64, u32, u32);
|
||||||
#define check_address_error(mask, vaddr) \
|
#define check_address_error(mask, vaddr) \
|
||||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||||
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
|||||||
|
|
||||||
if (check_address_error(0b11, vaddr)) [[unlikely]] {
|
if (check_address_error(0b11, vaddr)) [[unlikely]] {
|
||||||
/*regs.cop0.HandleTLBException(blockPC);
|
/*regs.cop0.HandleTLBException(blockPC);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, blockPC);
|
||||||
return 1;*/
|
return 1;*/
|
||||||
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
|
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
|
||||||
blockPC, {},
|
blockPC, {},
|
||||||
|
|||||||
@@ -4,90 +4,90 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void Cop0::mtc0(const Instruction instr) {
|
void Cop0::mtc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers ®s = Core::GetRegs();
|
||||||
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
|
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::dmtc0(const Instruction instr) {
|
void Cop0::dmtc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers ®s = Core::GetRegs();
|
||||||
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
|
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::mfc0(const Instruction instr) {
|
void Cop0::mfc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers ®s = Core::GetRegs();
|
||||||
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
|
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::dmfc0(const Instruction instr) const {
|
void Cop0::dmfc0(const Instruction instr) const {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers ®s = Core::GetRegs();
|
||||||
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
|
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::eret() {
|
void Cop0::eret() {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers ®s = Core::GetRegs();
|
||||||
if (!regs.cop0.kernelMode) {
|
if (!regs.cop0.kernelMode) {
|
||||||
FireException(ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
|
FireException(Cop0::ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (status.erl) {
|
if (status.erl) {
|
||||||
regs.SetPC64(ErrorEPC);
|
regs.SetPC64(ErrorEPC);
|
||||||
status.erl = false;
|
status.erl = false;
|
||||||
} else {
|
} else {
|
||||||
regs.SetPC64(EPC);
|
regs.SetPC64(EPC);
|
||||||
status.exl = false;
|
status.exl = false;
|
||||||
}
|
}
|
||||||
regs.cop0.Update();
|
regs.cop0.Update();
|
||||||
llbit = false;
|
llbit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cop0::tlbr() {
|
void Cop0::tlbr() {
|
||||||
if (index.i >= 32) {
|
if (index.i >= 32) {
|
||||||
panic("TLBR with TLB index {}", index.i);
|
panic("TLBR with TLB index {}", index.i);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TLBEntry entry = tlb[index.i];
|
const TLBEntry entry = tlb[index.i];
|
||||||
|
|
||||||
entryHi.raw = entry.entryHi.raw;
|
entryHi.raw = entry.entryHi.raw;
|
||||||
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
||||||
entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
|
entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
|
||||||
|
|
||||||
entryLo0.g = entry.global;
|
entryLo0.g = entry.global;
|
||||||
entryLo1.g = entry.global;
|
entryLo1.g = entry.global;
|
||||||
pageMask.raw = entry.pageMask.raw;
|
pageMask.raw = entry.pageMask.raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::tlbw(const int index_) {
|
void Cop0::tlbw(const int index_) {
|
||||||
PageMask page_mask{};
|
PageMask page_mask{};
|
||||||
page_mask = pageMask;
|
page_mask = pageMask;
|
||||||
const u32 top = page_mask.mask & 0xAAA;
|
const u32 top = page_mask.mask & 0xAAA;
|
||||||
page_mask.mask = top | (top >> 1);
|
page_mask.mask = top | (top >> 1);
|
||||||
|
|
||||||
if (index_ >= 32) {
|
if (index_ >= 32) {
|
||||||
panic("TLBWI with TLB index {}", index_);
|
panic("TLBWI with TLB index {}", index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
tlb[index_].entryHi.raw = entryHi.raw;
|
tlb[index_].entryHi.raw = entryHi.raw;
|
||||||
tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
|
tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
|
||||||
|
|
||||||
tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
|
tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
|
||||||
tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
|
tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
|
||||||
tlb[index_].pageMask.raw = page_mask.raw;
|
tlb[index_].pageMask.raw = page_mask.raw;
|
||||||
|
|
||||||
tlb[index_].global = entryLo0.g && entryLo1.g;
|
tlb[index_].global = entryLo0.g && entryLo1.g;
|
||||||
tlb[index_].initialized = true;
|
tlb[index_].initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::tlbp() {
|
void Cop0::tlbp() {
|
||||||
int match = -1;
|
int match = -1;
|
||||||
const TLBEntry *entry = TLBTryMatch(entryHi.raw, match);
|
const TLBEntry *entry = TLBTryMatch(entryHi.raw, match);
|
||||||
if (match >= 0) {
|
if (match >= 0) {
|
||||||
index.raw = match;
|
index.raw = match;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
index.raw = 0;
|
index.raw = 0;
|
||||||
index.p = 1;
|
index.p = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -33,10 +33,10 @@ void Interpreter::special(const Instruction instr) {
|
|||||||
jalr(instr);
|
jalr(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::SYSCALL:
|
case Instruction::SYSCALL:
|
||||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case Instruction::BREAK:
|
case Instruction::BREAK:
|
||||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case Instruction::SYNC:
|
case Instruction::SYNC:
|
||||||
break; // SYNC
|
break; // SYNC
|
||||||
@@ -222,7 +222,7 @@ void Interpreter::regimm(const Instruction instr) {
|
|||||||
|
|
||||||
void Interpreter::cop2Decode(const Instruction instr) {
|
void Interpreter::cop2Decode(const Instruction instr) {
|
||||||
if (!regs.cop0.status.cu2) {
|
if (!regs.cop0.status.cu2) {
|
||||||
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (instr.rs()) {
|
switch (instr.rs()) {
|
||||||
@@ -245,7 +245,7 @@ void Interpreter::cop2Decode(const Instruction instr) {
|
|||||||
ctc2(instr);
|
ctc2(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
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);
|
ldr(instr);
|
||||||
break;
|
break;
|
||||||
case 0x1F:
|
case 0x1F:
|
||||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case Instruction::LB:
|
case Instruction::LB:
|
||||||
lb(instr);
|
lb(instr);
|
||||||
@@ -409,10 +409,7 @@ void Interpreter::Exec(const Instruction instr) {
|
|||||||
swr(instr);
|
swr(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::CACHE:
|
case Instruction::CACHE:
|
||||||
{
|
// cache(instr);
|
||||||
panic("CACHE 0b{:05b}, 0x{:04X}({}/r{} = 0x{:08X})", instr.op(), instr.offset(),
|
|
||||||
Registers::regNames[instr.base()], instr.base(), regs.Read<u64>(instr.base()));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Instruction::LL:
|
case Instruction::LL:
|
||||||
ll(instr);
|
ll(instr);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ void Interpreter::add(const Instruction instr) {
|
|||||||
const u32 rs = regs.Read<s32>(instr.rs());
|
const u32 rs = regs.Read<s32>(instr.rs());
|
||||||
const u32 rt = regs.Read<s32>(instr.rt());
|
const u32 rt = regs.Read<s32>(instr.rt());
|
||||||
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rd(), static_cast<s32>(result));
|
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 rs = regs.Read<s64>(instr.rs());
|
||||||
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
|
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
|
||||||
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rt(), static_cast<s32>(result));
|
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 rs = regs.Read<s64>(instr.rs());
|
||||||
const u64 rt = regs.Read<s64>(instr.rt());
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rd(), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ void Interpreter::daddi(const Instruction instr) {
|
|||||||
const u64 imm = s64(s16(instr));
|
const u64 imm = s64(s16(instr));
|
||||||
const u64 rs = regs.Read<s64>(instr.rs());
|
const u64 rs = regs.Read<s64>(instr.rs());
|
||||||
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rt(), result);
|
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;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b1, address)) {
|
if (check_address_error(0b1, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ void Interpreter::lw(const Instruction instr) {
|
|||||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ void Interpreter::ll(const Instruction instr) {
|
|||||||
} else {
|
} else {
|
||||||
const s32 result = mem.Read<u32>(physical);
|
const s32 result = mem.Read<u32>(physical);
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ void Interpreter::ld(const Instruction instr) {
|
|||||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ void Interpreter::ld(const Instruction instr) {
|
|||||||
|
|
||||||
void Interpreter::lld(const Instruction instr) {
|
void Interpreter::lld(const Instruction instr) {
|
||||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ void Interpreter::lld(const Instruction instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(instr.rt(), mem.Read<u64>(paddr));
|
regs.Write(instr.rt(), mem.Read<u64>(paddr));
|
||||||
regs.cop0.llbit = true;
|
regs.cop0.llbit = true;
|
||||||
@@ -369,7 +369,7 @@ void Interpreter::lhu(const Instruction instr) {
|
|||||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b1, address)) {
|
if (check_address_error(0b1, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
@@ -386,7 +386,7 @@ void Interpreter::lwu(const Instruction instr) {
|
|||||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ void Interpreter::sc(const Instruction instr) {
|
|||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.Write(instr.rt(), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +440,7 @@ void Interpreter::sc(const Instruction instr) {
|
|||||||
|
|
||||||
void Interpreter::scd(const Instruction instr) {
|
void Interpreter::scd(const Instruction instr) {
|
||||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,7 +452,7 @@ void Interpreter::scd(const Instruction instr) {
|
|||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.Write(instr.rt(), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,7 +487,7 @@ void Interpreter::sw(const Instruction instr) {
|
|||||||
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ void Interpreter::sd(const Instruction instr) {
|
|||||||
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,7 +757,7 @@ void Interpreter::dsub(const Instruction instr) {
|
|||||||
const s64 rt = regs.Read<s64>(instr.rt());
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const s64 rs = regs.Read<s64>(instr.rs());
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rd(), result);
|
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 rs = regs.Read<s64>(instr.rs());
|
||||||
const s32 result = rs - rt;
|
const s32 result = rs - rt;
|
||||||
if (check_signed_underflow(rs, rt, result)) {
|
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 {
|
} else {
|
||||||
regs.Write(instr.rd(), result);
|
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 {
|
void Interpreter::trap(const bool cond) const {
|
||||||
Cop0 &cop0 = Core::GetRegs().cop0;
|
Cop0 &cop0 = Core::GetRegs().cop0;
|
||||||
if (cond) {
|
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) {
|
void Interpreter::cache(const Instruction instr) {
|
||||||
u8 type = instr.op() & 3;
|
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)
|
if (type > 1)
|
||||||
panic("Unknown cache type {}", type);
|
panic("Unknown cache type {}", type);
|
||||||
|
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
return cache_type_instruction(op);
|
return cache_type_instruction(op, vaddr, paddr, ptag);
|
||||||
|
|
||||||
if (type == 1)
|
return cache_type_data(op, vaddr, paddr, ptag);
|
||||||
return cache_type_data(op);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
switch (op) {
|
||||||
case 0:
|
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
|
} // namespace n64
|
||||||
|
|||||||
+442
-442
@@ -3,463 +3,463 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void JIT::special(const Instruction instr) {
|
void JIT::special(const Instruction instr) {
|
||||||
// 00rr_rccc
|
// 00rr_rccc
|
||||||
switch (instr.special()) {
|
switch (instr.special()) {
|
||||||
case Instruction::SLL:
|
case Instruction::SLL:
|
||||||
if (instr != 0) {
|
if (instr != 0) {
|
||||||
sll(instr);
|
sll(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Instruction::SRL:
|
||||||
|
srl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SRA:
|
||||||
|
sra(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SLLV:
|
||||||
|
sllv(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SRLV:
|
||||||
|
srlv(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SRAV:
|
||||||
|
srav(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::JR:
|
||||||
|
jr(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::JALR:
|
||||||
|
jalr(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SYSCALL:
|
||||||
|
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
|
||||||
|
break;
|
||||||
|
case Instruction::BREAK:
|
||||||
|
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||||
|
break;
|
||||||
|
case Instruction::SYNC:
|
||||||
|
break; // SYNC
|
||||||
|
case Instruction::MFHI:
|
||||||
|
mfhi(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::MTHI:
|
||||||
|
mthi(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::MFLO:
|
||||||
|
mflo(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::MTLO:
|
||||||
|
mtlo(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSLLV:
|
||||||
|
dsllv(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRLV:
|
||||||
|
dsrlv(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRAV:
|
||||||
|
dsrav(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::MULT:
|
||||||
|
mult(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::MULTU:
|
||||||
|
multu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DIV:
|
||||||
|
div(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DIVU:
|
||||||
|
divu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DMULT:
|
||||||
|
dmult(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DMULTU:
|
||||||
|
dmultu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DDIV:
|
||||||
|
ddiv(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DDIVU:
|
||||||
|
ddivu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::ADD:
|
||||||
|
add(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::ADDU:
|
||||||
|
addu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SUB:
|
||||||
|
sub(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SUBU:
|
||||||
|
subu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::AND:
|
||||||
|
and_(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::OR:
|
||||||
|
or_(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::XOR:
|
||||||
|
xor_(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::NOR:
|
||||||
|
nor(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SLT:
|
||||||
|
slt(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SLTU:
|
||||||
|
sltu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DADD:
|
||||||
|
dadd(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DADDU:
|
||||||
|
daddu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSUB:
|
||||||
|
dsub(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSUBU:
|
||||||
|
dsubu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::TGE:
|
||||||
|
trap(regs.Read<s64>(instr.rs()) >= regs.Read<s64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::TGEU:
|
||||||
|
trap(regs.Read<u64>(instr.rs()) >= regs.Read<u64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::TLT:
|
||||||
|
trap(regs.Read<s64>(instr.rs()) < regs.Read<s64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::TLTU:
|
||||||
|
trap(regs.Read<u64>(instr.rs()) < regs.Read<u64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::TEQ:
|
||||||
|
trap(regs.Read<s64>(instr.rs()) == regs.Read<s64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::TNE:
|
||||||
|
trap(regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()));
|
||||||
|
break;
|
||||||
|
case Instruction::DSLL:
|
||||||
|
dsll(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRL:
|
||||||
|
dsrl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRA:
|
||||||
|
dsra(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSLL32:
|
||||||
|
dsll32(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRL32:
|
||||||
|
dsrl32(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DSRA32:
|
||||||
|
dsra32(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Unimplemented special {} ({:08X}) (pc: {:016X})", instr.special(), u32(instr),
|
||||||
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case Instruction::SRL:
|
|
||||||
srl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SRA:
|
|
||||||
sra(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SLLV:
|
|
||||||
sllv(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SRLV:
|
|
||||||
srlv(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SRAV:
|
|
||||||
srav(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::JR:
|
|
||||||
jr(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::JALR:
|
|
||||||
jalr(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SYSCALL:
|
|
||||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
|
||||||
break;
|
|
||||||
case Instruction::BREAK:
|
|
||||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
|
||||||
break;
|
|
||||||
case Instruction::SYNC:
|
|
||||||
break; // SYNC
|
|
||||||
case Instruction::MFHI:
|
|
||||||
mfhi(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::MTHI:
|
|
||||||
mthi(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::MFLO:
|
|
||||||
mflo(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::MTLO:
|
|
||||||
mtlo(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSLLV:
|
|
||||||
dsllv(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRLV:
|
|
||||||
dsrlv(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRAV:
|
|
||||||
dsrav(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::MULT:
|
|
||||||
mult(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::MULTU:
|
|
||||||
multu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DIV:
|
|
||||||
div(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DIVU:
|
|
||||||
divu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DMULT:
|
|
||||||
dmult(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DMULTU:
|
|
||||||
dmultu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DDIV:
|
|
||||||
ddiv(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DDIVU:
|
|
||||||
ddivu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ADD:
|
|
||||||
add(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ADDU:
|
|
||||||
addu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SUB:
|
|
||||||
sub(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SUBU:
|
|
||||||
subu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::AND:
|
|
||||||
and_(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::OR:
|
|
||||||
or_(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::XOR:
|
|
||||||
xor_(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::NOR:
|
|
||||||
nor(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SLT:
|
|
||||||
slt(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SLTU:
|
|
||||||
sltu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DADD:
|
|
||||||
dadd(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DADDU:
|
|
||||||
daddu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSUB:
|
|
||||||
dsub(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSUBU:
|
|
||||||
dsubu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::TGE:
|
|
||||||
trap(regs.Read<s64>(instr.rs()) >= regs.Read<s64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::TGEU:
|
|
||||||
trap(regs.Read<u64>(instr.rs()) >= regs.Read<u64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::TLT:
|
|
||||||
trap(regs.Read<s64>(instr.rs()) < regs.Read<s64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::TLTU:
|
|
||||||
trap(regs.Read<u64>(instr.rs()) < regs.Read<u64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::TEQ:
|
|
||||||
trap(regs.Read<s64>(instr.rs()) == regs.Read<s64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::TNE:
|
|
||||||
trap(regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()));
|
|
||||||
break;
|
|
||||||
case Instruction::DSLL:
|
|
||||||
dsll(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRL:
|
|
||||||
dsrl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRA:
|
|
||||||
dsra(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSLL32:
|
|
||||||
dsll32(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRL32:
|
|
||||||
dsrl32(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DSRA32:
|
|
||||||
dsra32(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unimplemented special {} ({:08X}) (pc: {:016X})", instr.special(), u32(instr),
|
|
||||||
static_cast<u64>(regs.oldPC));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::regimm(const Instruction instr) {
|
void JIT::regimm(const Instruction instr) {
|
||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
switch (instr.regimm()) {
|
switch (instr.regimm()) {
|
||||||
case Instruction::BLTZ:
|
case Instruction::BLTZ:
|
||||||
bltz(instr);
|
bltz(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BGEZ:
|
case Instruction::BGEZ:
|
||||||
bgez(instr);
|
bgez(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BLTZL:
|
case Instruction::BLTZL:
|
||||||
bltzl(instr);
|
bltzl(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BGEZL:
|
case Instruction::BGEZL:
|
||||||
bgezl(instr);
|
bgezl(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::TGEI:
|
case Instruction::TGEI:
|
||||||
trap(regs.Read<s64>(instr.rs()) >= static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(instr.rs()) >= static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case Instruction::TGEIU:
|
case Instruction::TGEIU:
|
||||||
trap(regs.Read<u64>(instr.rs()) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
trap(regs.Read<u64>(instr.rs()) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||||
break;
|
break;
|
||||||
case Instruction::TLTI:
|
case Instruction::TLTI:
|
||||||
trap(regs.Read<s64>(instr.rs()) < static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(instr.rs()) < static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case Instruction::TLTIU:
|
case Instruction::TLTIU:
|
||||||
trap(regs.Read<u64>(instr.rs()) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
trap(regs.Read<u64>(instr.rs()) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||||
break;
|
break;
|
||||||
case Instruction::TEQI:
|
case Instruction::TEQI:
|
||||||
trap(regs.Read<s64>(instr.rs()) == static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(instr.rs()) == static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case Instruction::TNEI:
|
case Instruction::TNEI:
|
||||||
trap(regs.Read<s64>(instr.rs()) != static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(instr.rs()) != static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case Instruction::BLTZAL:
|
case Instruction::BLTZAL:
|
||||||
bltzal(instr);
|
bltzal(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BGEZAL:
|
case Instruction::BGEZAL:
|
||||||
bgezal(instr);
|
bgezal(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BLTZALL:
|
case Instruction::BLTZALL:
|
||||||
bltzall(instr);
|
bltzall(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::BGEZALL:
|
case Instruction::BGEZALL:
|
||||||
bgezall(instr);
|
bgezall(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented regimm {} ({:08X}) (pc: {:016X})", instr.regimm(), u32(instr),
|
panic("Unimplemented regimm {} ({:08X}) (pc: {:016X})", instr.regimm(), u32(instr),
|
||||||
static_cast<u64>(regs.oldPC));
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::Emit(const Instruction instr) {
|
void JIT::Emit(const Instruction instr) {
|
||||||
switch (instr.opcode()) {
|
switch (instr.opcode()) {
|
||||||
case Instruction::SPECIAL:
|
case Instruction::SPECIAL:
|
||||||
special(instr);
|
special(instr);
|
||||||
break;
|
|
||||||
case Instruction::REGIMM:
|
|
||||||
regimm(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::J:
|
|
||||||
j(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::JAL:
|
|
||||||
jal(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BEQ:
|
|
||||||
beq(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BNE:
|
|
||||||
bne(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BLEZ:
|
|
||||||
blez(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BGTZ:
|
|
||||||
bgtz(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ADDI:
|
|
||||||
addi(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ADDIU:
|
|
||||||
addiu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SLTI:
|
|
||||||
slti(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SLTIU:
|
|
||||||
sltiu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ANDI:
|
|
||||||
andi(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::ORI:
|
|
||||||
ori(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::XORI:
|
|
||||||
xori(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LUI:
|
|
||||||
lui(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::COP0:
|
|
||||||
switch (instr.cop_rs()) {
|
|
||||||
case 0x00:
|
|
||||||
code.mov(code.ARG2, instr);
|
|
||||||
emitMemberFunctionCall(&Cop0::mfc0, ®s.cop0);
|
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case Instruction::REGIMM:
|
||||||
code.mov(code.ARG2, instr);
|
regimm(instr);
|
||||||
emitMemberFunctionCall(&Cop0::dmfc0, ®s.cop0);
|
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case Instruction::J:
|
||||||
code.mov(code.ARG2, instr);
|
j(instr);
|
||||||
emitMemberFunctionCall(&Cop0::mtc0, ®s.cop0);
|
|
||||||
break;
|
break;
|
||||||
case 0x05:
|
case Instruction::JAL:
|
||||||
code.mov(code.ARG2, instr);
|
jal(instr);
|
||||||
emitMemberFunctionCall(&Cop0::dmtc0, ®s.cop0);
|
|
||||||
break;
|
break;
|
||||||
case 0x10 ... 0x1F:
|
case Instruction::BEQ:
|
||||||
switch (instr.cop_funct()) {
|
beq(instr);
|
||||||
case 0x01:
|
|
||||||
emitMemberFunctionCall(&Cop0::tlbr, ®s.cop0);
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
code.mov(code.ARG2, COP0_REG_INDEX);
|
|
||||||
emitMemberFunctionCall(&Cop0::GetReg32, ®s.cop0);
|
|
||||||
code.mov(code.ARG2, code.rax);
|
|
||||||
code.and_(code.ARG2, 0x3F);
|
|
||||||
emitMemberFunctionCall(&Cop0::tlbw, ®s.cop0);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
emitMemberFunctionCall(&Cop0::GetRandom, ®s.cop0);
|
|
||||||
code.mov(code.ARG2, code.rax);
|
|
||||||
emitMemberFunctionCall(&Cop0::tlbw, ®s.cop0);
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
emitMemberFunctionCall(&Cop0::tlbp, ®s.cop0);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
emitMemberFunctionCall(&Cop0::eret, ®s.cop0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
|
|
||||||
regs.oldPC);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
case Instruction::BNE:
|
||||||
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
bne(instr);
|
||||||
}
|
break;
|
||||||
break;
|
case Instruction::BLEZ:
|
||||||
case Instruction::COP1:
|
blez(instr);
|
||||||
{
|
break;
|
||||||
if (instr.cop_rs() == 0x08) {
|
case Instruction::BGTZ:
|
||||||
switch (instr.cop_rt()) {
|
bgtz(instr);
|
||||||
case 0:
|
break;
|
||||||
// if (!regs.cop1.CheckFPUUsable())
|
case Instruction::ADDI:
|
||||||
// return;
|
addi(instr);
|
||||||
bfc0(instr);
|
break;
|
||||||
break;
|
case Instruction::ADDIU:
|
||||||
case 1:
|
addiu(instr);
|
||||||
// if (!regs.cop1.CheckFPUUsable())
|
break;
|
||||||
// return;
|
case Instruction::SLTI:
|
||||||
bfc1(instr);
|
slti(instr);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case Instruction::SLTIU:
|
||||||
// if (!regs.cop1.CheckFPUUsable())
|
sltiu(instr);
|
||||||
// return;
|
break;
|
||||||
blfc0(instr);
|
case Instruction::ANDI:
|
||||||
break;
|
andi(instr);
|
||||||
case 3:
|
break;
|
||||||
// if (!regs.cop1.CheckFPUUsable())
|
case Instruction::ORI:
|
||||||
// return;
|
ori(instr);
|
||||||
blfc1(instr);
|
break;
|
||||||
break;
|
case Instruction::XORI:
|
||||||
|
xori(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LUI:
|
||||||
|
lui(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::COP0:
|
||||||
|
switch (instr.cop_rs()) {
|
||||||
|
case 0x00:
|
||||||
|
code.mov(code.ARG2, instr);
|
||||||
|
emitMemberFunctionCall(&Cop0::mfc0, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
code.mov(code.ARG2, instr);
|
||||||
|
emitMemberFunctionCall(&Cop0::dmfc0, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
code.mov(code.ARG2, instr);
|
||||||
|
emitMemberFunctionCall(&Cop0::mtc0, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
code.mov(code.ARG2, instr);
|
||||||
|
emitMemberFunctionCall(&Cop0::dmtc0, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x10 ... 0x1F:
|
||||||
|
switch (instr.cop_funct()) {
|
||||||
|
case 0x01:
|
||||||
|
emitMemberFunctionCall(&Cop0::tlbr, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
code.mov(code.ARG2, COP0_REG_INDEX);
|
||||||
|
emitMemberFunctionCall(&Cop0::GetReg32, ®s.cop0);
|
||||||
|
code.mov(code.ARG2, code.rax);
|
||||||
|
code.and_(code.ARG2, 0x3F);
|
||||||
|
emitMemberFunctionCall(&Cop0::tlbw, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
emitMemberFunctionCall(&Cop0::GetRandom, ®s.cop0);
|
||||||
|
code.mov(code.ARG2, code.rax);
|
||||||
|
emitMemberFunctionCall(&Cop0::tlbw, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
emitMemberFunctionCall(&Cop0::tlbp, ®s.cop0);
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
emitMemberFunctionCall(&Cop0::eret, ®s.cop0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr), regs.oldPC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case Instruction::COP1:
|
||||||
regs.cop1.decode(instr);
|
{
|
||||||
|
if (instr.cop_rs() == 0x08) {
|
||||||
|
switch (instr.cop_rt()) {
|
||||||
|
case 0:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
bfc0(instr);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
bfc1(instr);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
blfc0(instr);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
blfc1(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
regs.cop1.decode(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Instruction::COP2:
|
||||||
|
break;
|
||||||
|
case Instruction::BEQL:
|
||||||
|
beql(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::BNEL:
|
||||||
|
bnel(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::BLEZL:
|
||||||
|
blezl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::BGTZL:
|
||||||
|
bgtzl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DADDI:
|
||||||
|
daddi(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::DADDIU:
|
||||||
|
daddiu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LDL:
|
||||||
|
ldl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LDR:
|
||||||
|
ldr(instr);
|
||||||
|
break;
|
||||||
|
case 0x1F:
|
||||||
|
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||||
|
break;
|
||||||
|
case Instruction::LB:
|
||||||
|
lb(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LH:
|
||||||
|
lh(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LWL:
|
||||||
|
lwl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LW:
|
||||||
|
lw(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LBU:
|
||||||
|
lbu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LHU:
|
||||||
|
lhu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LWR:
|
||||||
|
lwr(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LWU:
|
||||||
|
lwu(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SB:
|
||||||
|
sb(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SH:
|
||||||
|
sh(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SWL:
|
||||||
|
swl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SW:
|
||||||
|
sw(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SDL:
|
||||||
|
sdl(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SDR:
|
||||||
|
sdr(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SWR:
|
||||||
|
swr(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::CACHE:
|
||||||
|
break; // CACHE
|
||||||
|
case Instruction::LL:
|
||||||
|
ll(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LWC1:
|
||||||
|
lwc1(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LLD:
|
||||||
|
lld(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LDC1:
|
||||||
|
ldc1(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::LD:
|
||||||
|
ld(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SC:
|
||||||
|
sc(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SWC1:
|
||||||
|
swc1(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SCD:
|
||||||
|
scd(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SDC1:
|
||||||
|
sdc1(instr);
|
||||||
|
break;
|
||||||
|
case Instruction::SD:
|
||||||
|
sd(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DumpBlockCacheToDisk();
|
||||||
|
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr),
|
||||||
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case Instruction::COP2:
|
|
||||||
break;
|
|
||||||
case Instruction::BEQL:
|
|
||||||
beql(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BNEL:
|
|
||||||
bnel(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BLEZL:
|
|
||||||
blezl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::BGTZL:
|
|
||||||
bgtzl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DADDI:
|
|
||||||
daddi(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::DADDIU:
|
|
||||||
daddiu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LDL:
|
|
||||||
ldl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LDR:
|
|
||||||
ldr(instr);
|
|
||||||
break;
|
|
||||||
case 0x1F:
|
|
||||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
|
||||||
break;
|
|
||||||
case Instruction::LB:
|
|
||||||
lb(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LH:
|
|
||||||
lh(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LWL:
|
|
||||||
lwl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LW:
|
|
||||||
lw(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LBU:
|
|
||||||
lbu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LHU:
|
|
||||||
lhu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LWR:
|
|
||||||
lwr(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LWU:
|
|
||||||
lwu(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SB:
|
|
||||||
sb(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SH:
|
|
||||||
sh(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SWL:
|
|
||||||
swl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SW:
|
|
||||||
sw(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SDL:
|
|
||||||
sdl(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SDR:
|
|
||||||
sdr(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SWR:
|
|
||||||
swr(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::CACHE:
|
|
||||||
break; // CACHE
|
|
||||||
case Instruction::LL:
|
|
||||||
ll(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LWC1:
|
|
||||||
lwc1(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LLD:
|
|
||||||
lld(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LDC1:
|
|
||||||
ldc1(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::LD:
|
|
||||||
ld(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SC:
|
|
||||||
sc(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SWC1:
|
|
||||||
swc1(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SCD:
|
|
||||||
scd(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SDC1:
|
|
||||||
sdc1(instr);
|
|
||||||
break;
|
|
||||||
case Instruction::SD:
|
|
||||||
sd(instr);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DumpBlockCacheToDisk();
|
|
||||||
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr), static_cast<u64>(regs.oldPC));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+1058
-1056
File diff suppressed because it is too large
Load Diff
+477
-454
File diff suppressed because it is too large
Load Diff
+237
-226
@@ -38,248 +38,259 @@ namespace n64 {
|
|||||||
#define ENTRY_HI_MASK 0xC00000FFFFFFE0FF
|
#define ENTRY_HI_MASK 0xC00000FFFFFFE0FF
|
||||||
#define PAGEMASK_MASK 0x1FFE000
|
#define PAGEMASK_MASK 0x1FFE000
|
||||||
|
|
||||||
union Cop0Cause {
|
|
||||||
u32 raw;
|
|
||||||
struct {
|
|
||||||
unsigned : 8;
|
|
||||||
unsigned interruptPending : 8;
|
|
||||||
unsigned : 16;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
struct {
|
|
||||||
unsigned : 2;
|
|
||||||
unsigned exceptionCode : 5;
|
|
||||||
unsigned : 1;
|
|
||||||
unsigned ip0 : 1;
|
|
||||||
unsigned ip1 : 1;
|
|
||||||
unsigned ip2 : 1;
|
|
||||||
unsigned ip3 : 1;
|
|
||||||
unsigned ip4 : 1;
|
|
||||||
unsigned ip5 : 1;
|
|
||||||
unsigned ip6 : 1;
|
|
||||||
unsigned ip7 : 1;
|
|
||||||
unsigned : 12;
|
|
||||||
unsigned copError : 2;
|
|
||||||
unsigned : 1;
|
|
||||||
unsigned branchDelay : 1;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
};
|
|
||||||
|
|
||||||
union Cop0Status {
|
|
||||||
struct {
|
|
||||||
unsigned ie : 1;
|
|
||||||
unsigned exl : 1;
|
|
||||||
unsigned erl : 1;
|
|
||||||
unsigned ksu : 2;
|
|
||||||
unsigned ux : 1;
|
|
||||||
unsigned sx : 1;
|
|
||||||
unsigned kx : 1;
|
|
||||||
unsigned im : 8;
|
|
||||||
unsigned ds : 9;
|
|
||||||
unsigned re : 1;
|
|
||||||
unsigned fr : 1;
|
|
||||||
unsigned rp : 1;
|
|
||||||
unsigned cu0 : 1;
|
|
||||||
unsigned cu1 : 1;
|
|
||||||
unsigned cu2 : 1;
|
|
||||||
unsigned cu3 : 1;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
struct {
|
|
||||||
unsigned : 16;
|
|
||||||
unsigned de : 1;
|
|
||||||
unsigned ce : 1;
|
|
||||||
unsigned ch : 1;
|
|
||||||
unsigned : 1;
|
|
||||||
unsigned sr : 1;
|
|
||||||
unsigned ts : 1;
|
|
||||||
unsigned bev : 1;
|
|
||||||
unsigned : 1;
|
|
||||||
unsigned its : 1;
|
|
||||||
unsigned : 7;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
u32 raw;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
union EntryLo {
|
|
||||||
u32 raw;
|
|
||||||
struct {
|
|
||||||
unsigned g : 1;
|
|
||||||
unsigned v : 1;
|
|
||||||
unsigned d : 1;
|
|
||||||
unsigned c : 3;
|
|
||||||
unsigned pfn : 20;
|
|
||||||
unsigned : 6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
union EntryHi {
|
|
||||||
u64 raw;
|
|
||||||
struct {
|
|
||||||
u64 asid : 8;
|
|
||||||
u64 : 5;
|
|
||||||
u64 vpn2 : 27;
|
|
||||||
u64 fill : 22;
|
|
||||||
u64 r : 2;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
};
|
|
||||||
|
|
||||||
union PageMask {
|
|
||||||
u32 raw;
|
|
||||||
struct {
|
|
||||||
unsigned : 13;
|
|
||||||
unsigned mask : 12;
|
|
||||||
unsigned : 7;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
union Index {
|
|
||||||
u32 raw;
|
|
||||||
struct {
|
|
||||||
unsigned i : 6;
|
|
||||||
unsigned : 25;
|
|
||||||
unsigned p : 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TLBEntry {
|
|
||||||
bool initialized;
|
|
||||||
EntryLo entryLo0, entryLo1;
|
|
||||||
EntryHi entryHi;
|
|
||||||
PageMask pageMask;
|
|
||||||
|
|
||||||
bool global;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS };
|
|
||||||
|
|
||||||
enum class ExceptionCode : u8 {
|
|
||||||
Interrupt = 0,
|
|
||||||
TLBModification = 1,
|
|
||||||
TLBLoad = 2,
|
|
||||||
TLBStore = 3,
|
|
||||||
AddressErrorLoad = 4,
|
|
||||||
AddressErrorStore = 5,
|
|
||||||
InstructionBusError = 6,
|
|
||||||
DataBusError = 7,
|
|
||||||
Syscall = 8,
|
|
||||||
Breakpoint = 9,
|
|
||||||
ReservedInstruction = 10,
|
|
||||||
CoprocessorUnusable = 11,
|
|
||||||
Overflow = 12,
|
|
||||||
Trap = 13,
|
|
||||||
FloatingPointError = 15,
|
|
||||||
Watch = 23
|
|
||||||
};
|
|
||||||
|
|
||||||
union Cop0Context {
|
|
||||||
u64 raw;
|
|
||||||
struct {
|
|
||||||
u64 : 4;
|
|
||||||
u64 badvpn2 : 19;
|
|
||||||
u64 ptebase : 41;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
union Cop0XContext {
|
|
||||||
u64 raw;
|
|
||||||
struct {
|
|
||||||
u64 : 4;
|
|
||||||
u64 badvpn2 : 27;
|
|
||||||
u64 r : 2;
|
|
||||||
u64 ptebase : 31;
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Cop0 {
|
struct Cop0 {
|
||||||
Cop0();
|
union Cause {
|
||||||
|
u32 raw;
|
||||||
|
struct {
|
||||||
|
unsigned : 8;
|
||||||
|
unsigned interruptPending : 8;
|
||||||
|
unsigned : 16;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
struct {
|
||||||
|
unsigned : 2;
|
||||||
|
unsigned exceptionCode : 5;
|
||||||
|
unsigned : 1;
|
||||||
|
unsigned ip0 : 1;
|
||||||
|
unsigned ip1 : 1;
|
||||||
|
unsigned ip2 : 1;
|
||||||
|
unsigned ip3 : 1;
|
||||||
|
unsigned ip4 : 1;
|
||||||
|
unsigned ip5 : 1;
|
||||||
|
unsigned ip6 : 1;
|
||||||
|
unsigned ip7 : 1;
|
||||||
|
unsigned : 12;
|
||||||
|
unsigned copError : 2;
|
||||||
|
unsigned : 1;
|
||||||
|
unsigned branchDelay : 1;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
};
|
||||||
|
|
||||||
bool kernelMode{true};
|
union Status {
|
||||||
bool supervisorMode{false};
|
struct {
|
||||||
bool userMode{false};
|
unsigned ie : 1;
|
||||||
bool is64BitAddressing{false};
|
unsigned exl : 1;
|
||||||
bool llbit{};
|
unsigned erl : 1;
|
||||||
TLBError tlbError = NONE;
|
unsigned ksu : 2;
|
||||||
|
unsigned ux : 1;
|
||||||
|
unsigned sx : 1;
|
||||||
|
unsigned kx : 1;
|
||||||
|
unsigned im : 8;
|
||||||
|
unsigned ds : 9;
|
||||||
|
unsigned re : 1;
|
||||||
|
unsigned fr : 1;
|
||||||
|
unsigned rp : 1;
|
||||||
|
unsigned cu0 : 1;
|
||||||
|
unsigned cu1 : 1;
|
||||||
|
unsigned cu2 : 1;
|
||||||
|
unsigned cu3 : 1;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
struct {
|
||||||
|
unsigned : 16;
|
||||||
|
unsigned de : 1;
|
||||||
|
unsigned ce : 1;
|
||||||
|
unsigned ch : 1;
|
||||||
|
unsigned : 1;
|
||||||
|
unsigned sr : 1;
|
||||||
|
unsigned ts : 1;
|
||||||
|
unsigned bev : 1;
|
||||||
|
unsigned : 1;
|
||||||
|
unsigned its : 1;
|
||||||
|
unsigned : 7;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
u32 raw;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
PageMask pageMask{};
|
union EntryLo {
|
||||||
EntryHi entryHi{};
|
u32 raw;
|
||||||
EntryLo entryLo0{}, entryLo1{};
|
struct {
|
||||||
Index index{};
|
unsigned g : 1;
|
||||||
Cop0Context context{};
|
unsigned v : 1;
|
||||||
u32 wired{}, r7{};
|
unsigned d : 1;
|
||||||
u32 compare{};
|
unsigned c : 3;
|
||||||
Cop0Status status{};
|
unsigned pfn : 20;
|
||||||
Cop0Cause cause{};
|
unsigned : 6;
|
||||||
u32 PRId{}, Config{}, LLAddr{}, WatchLo{}, WatchHi{};
|
};
|
||||||
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagLo{}, TagHi{};
|
};
|
||||||
u32 r31{};
|
|
||||||
Cop0XContext xcontext{};
|
|
||||||
u64 badVaddr{}, count{};
|
|
||||||
s64 EPC{};
|
|
||||||
s64 ErrorEPC{};
|
|
||||||
s64 openbus{};
|
|
||||||
TLBEntry tlb[32]{};
|
|
||||||
|
|
||||||
enum TLBAccessType { LOAD, STORE };
|
|
||||||
|
|
||||||
u32 GetReg32(u8);
|
union EntryHi {
|
||||||
[[nodiscard]] u64 GetReg64(u8) const;
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 asid : 8;
|
||||||
|
u64 : 5;
|
||||||
|
u64 vpn2 : 27;
|
||||||
|
u64 fill : 22;
|
||||||
|
u64 r : 2;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
};
|
||||||
|
|
||||||
void SetReg32(u8, u32);
|
union PageMask {
|
||||||
void SetReg64(u8, u64);
|
u32 raw;
|
||||||
|
struct {
|
||||||
|
unsigned : 13;
|
||||||
|
unsigned mask : 12;
|
||||||
|
unsigned : 7;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
void Reset();
|
union Index {
|
||||||
|
u32 raw;
|
||||||
|
struct {
|
||||||
|
unsigned i : 6;
|
||||||
|
unsigned : 25;
|
||||||
|
unsigned p : 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
struct TLBEntry {
|
||||||
void FireException(ExceptionCode code, int cop, s64 pc);
|
bool initialized;
|
||||||
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
EntryLo entryLo0, entryLo1;
|
||||||
|
EntryHi entryHi;
|
||||||
|
PageMask pageMask;
|
||||||
|
|
||||||
TLBEntry *TLBTryMatch(u64 vaddr, int &index);
|
bool global;
|
||||||
TLBEntry *TLBTryMatch(u64 vaddr);
|
};
|
||||||
void HandleTLBException(u64 vaddr);
|
|
||||||
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);
|
|
||||||
void decode(const Instruction);
|
|
||||||
|
|
||||||
[[nodiscard]] FORCE_INLINE u32 GetRandom() const {
|
enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS };
|
||||||
u32 val = rand();
|
|
||||||
const auto wired_ = GetWired();
|
enum class ExceptionCode : u8 {
|
||||||
u32 lower, upper;
|
Interrupt = 0,
|
||||||
if (wired_ > 31) {
|
TLBModification = 1,
|
||||||
lower = 0;
|
TLBLoad = 2,
|
||||||
upper = 64;
|
TLBStore = 3,
|
||||||
} else {
|
AddressErrorLoad = 4,
|
||||||
lower = wired_;
|
AddressErrorStore = 5,
|
||||||
upper = 32 - wired_;
|
InstructionBusError = 6,
|
||||||
|
DataBusError = 7,
|
||||||
|
Syscall = 8,
|
||||||
|
Breakpoint = 9,
|
||||||
|
ReservedInstruction = 10,
|
||||||
|
CoprocessorUnusable = 11,
|
||||||
|
Overflow = 12,
|
||||||
|
Trap = 13,
|
||||||
|
FloatingPointError = 15,
|
||||||
|
Watch = 23
|
||||||
|
};
|
||||||
|
|
||||||
|
union Context {
|
||||||
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 : 4;
|
||||||
|
u64 badvpn2 : 19;
|
||||||
|
u64 ptebase : 41;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union XContext {
|
||||||
|
u64 raw;
|
||||||
|
struct {
|
||||||
|
u64 : 4;
|
||||||
|
u64 badvpn2 : 27;
|
||||||
|
u64 r : 2;
|
||||||
|
u64 ptebase : 31;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
};
|
||||||
|
|
||||||
|
union TagLo {
|
||||||
|
u32 raw;
|
||||||
|
struct {
|
||||||
|
u64 : 4;
|
||||||
|
u64 ptaglo : 20;
|
||||||
|
u64 pstate : 2;
|
||||||
|
u64 : 6;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
};
|
||||||
|
|
||||||
|
Cop0();
|
||||||
|
|
||||||
|
bool kernelMode{true};
|
||||||
|
bool supervisorMode{false};
|
||||||
|
bool userMode{false};
|
||||||
|
bool is64BitAddressing{false};
|
||||||
|
bool llbit{};
|
||||||
|
TLBError tlbError = NONE;
|
||||||
|
|
||||||
|
TagLo tagLo;
|
||||||
|
PageMask pageMask{};
|
||||||
|
EntryHi entryHi{};
|
||||||
|
EntryLo entryLo0{}, entryLo1{};
|
||||||
|
Index index{};
|
||||||
|
Context context{};
|
||||||
|
u32 wired{}, r7{};
|
||||||
|
u32 compare{};
|
||||||
|
Status status{};
|
||||||
|
Cause cause{};
|
||||||
|
u32 PRId{}, Config{}, LLAddr{}, WatchLo{}, WatchHi{};
|
||||||
|
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagHi{};
|
||||||
|
u32 r31{};
|
||||||
|
XContext xcontext{};
|
||||||
|
u64 badVaddr{}, count{};
|
||||||
|
s64 EPC{};
|
||||||
|
s64 ErrorEPC{};
|
||||||
|
s64 openbus{};
|
||||||
|
TLBEntry tlb[32]{};
|
||||||
|
|
||||||
|
enum TLBAccessType { LOAD, STORE };
|
||||||
|
|
||||||
|
u32 GetReg32(u8);
|
||||||
|
[[nodiscard]] u64 GetReg64(u8) const;
|
||||||
|
|
||||||
|
void SetReg32(u8, u32);
|
||||||
|
void SetReg64(u8, u64);
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||||
|
void FireException(ExceptionCode code, int cop, s64 pc);
|
||||||
|
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||||
|
|
||||||
|
TLBEntry *TLBTryMatch(u64 vaddr, int &index);
|
||||||
|
TLBEntry *TLBTryMatch(u64 vaddr);
|
||||||
|
void HandleTLBException(u64 vaddr);
|
||||||
|
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);
|
||||||
|
void decode(const Instruction);
|
||||||
|
|
||||||
|
[[nodiscard]] FORCE_INLINE u32 GetRandom() const {
|
||||||
|
u32 val = rand();
|
||||||
|
const auto wired_ = GetWired();
|
||||||
|
u32 lower, upper;
|
||||||
|
if (wired_ > 31) {
|
||||||
|
lower = 0;
|
||||||
|
upper = 64;
|
||||||
|
} else {
|
||||||
|
lower = wired_;
|
||||||
|
upper = 32 - wired_;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (val % upper) + lower;
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
val = (val % upper) + lower;
|
FORCE_INLINE void Update() {
|
||||||
return val;
|
const bool exception = status.exl || status.erl;
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE void Update() {
|
kernelMode = exception || status.ksu == 0;
|
||||||
const bool exception = status.exl || status.erl;
|
supervisorMode = !exception && status.ksu == 1;
|
||||||
|
userMode = !exception && status.ksu == 2;
|
||||||
|
is64BitAddressing = (kernelMode && status.kx) || (supervisorMode && status.sx) || (userMode && status.ux);
|
||||||
|
}
|
||||||
|
|
||||||
kernelMode = exception || status.ksu == 0;
|
private:
|
||||||
supervisorMode = !exception && status.ksu == 1;
|
friend struct JIT;
|
||||||
userMode = !exception && status.ksu == 2;
|
|
||||||
is64BitAddressing = (kernelMode && status.kx) || (supervisorMode && status.sx) || (userMode && status.ux);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
||||||
friend struct JIT;
|
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
||||||
|
|
||||||
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
void mtc0(const Instruction);
|
||||||
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
void dmtc0(const Instruction);
|
||||||
|
void mfc0(const Instruction);
|
||||||
|
void dmfc0(const Instruction) const;
|
||||||
|
void eret();
|
||||||
|
|
||||||
void mtc0(const Instruction);
|
void tlbr();
|
||||||
void dmtc0(const Instruction);
|
void tlbw(int);
|
||||||
void mfc0(const Instruction);
|
void tlbp();
|
||||||
void dmfc0(const Instruction) const;
|
|
||||||
void eret();
|
|
||||||
|
|
||||||
void tlbr();
|
template <typename T, bool User>
|
||||||
void tlbw(int);
|
bool MapVirtualAddress(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||||
void tlbp();
|
|
||||||
|
|
||||||
template <typename T, bool User>
|
|
||||||
bool MapVirtualAddress(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+219
-219
@@ -7,241 +7,241 @@ namespace n64 {
|
|||||||
struct Cop1;
|
struct Cop1;
|
||||||
|
|
||||||
union FCR31 {
|
union FCR31 {
|
||||||
FCR31() = default;
|
FCR31() = default;
|
||||||
struct {
|
|
||||||
unsigned rounding_mode : 2;
|
|
||||||
struct {
|
struct {
|
||||||
unsigned inexact_operation : 1;
|
unsigned rounding_mode : 2;
|
||||||
unsigned underflow : 1;
|
struct {
|
||||||
unsigned overflow : 1;
|
unsigned inexact_operation : 1;
|
||||||
unsigned division_by_zero : 1;
|
unsigned underflow : 1;
|
||||||
unsigned invalid_operation : 1;
|
unsigned overflow : 1;
|
||||||
} flag;
|
unsigned division_by_zero : 1;
|
||||||
struct {
|
unsigned invalid_operation : 1;
|
||||||
unsigned inexact_operation : 1;
|
} flag;
|
||||||
unsigned underflow : 1;
|
struct {
|
||||||
unsigned overflow : 1;
|
unsigned inexact_operation : 1;
|
||||||
unsigned division_by_zero : 1;
|
unsigned underflow : 1;
|
||||||
unsigned invalid_operation : 1;
|
unsigned overflow : 1;
|
||||||
} enable;
|
unsigned division_by_zero : 1;
|
||||||
struct {
|
unsigned invalid_operation : 1;
|
||||||
unsigned inexact_operation : 1;
|
} enable;
|
||||||
unsigned underflow : 1;
|
struct {
|
||||||
unsigned overflow : 1;
|
unsigned inexact_operation : 1;
|
||||||
unsigned division_by_zero : 1;
|
unsigned underflow : 1;
|
||||||
unsigned invalid_operation : 1;
|
unsigned overflow : 1;
|
||||||
unsigned unimplemented_operation : 1;
|
unsigned division_by_zero : 1;
|
||||||
} cause;
|
unsigned invalid_operation : 1;
|
||||||
unsigned : 5;
|
unsigned unimplemented_operation : 1;
|
||||||
unsigned compare : 1;
|
} cause;
|
||||||
unsigned fs : 1;
|
unsigned : 5;
|
||||||
unsigned : 7;
|
unsigned compare : 1;
|
||||||
} __attribute__((__packed__));
|
unsigned fs : 1;
|
||||||
|
unsigned : 7;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
[[nodiscard]] u32 read() const {
|
[[nodiscard]] u32 read() const {
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
ret |= (u32(fs) << 24);
|
ret |= (u32(fs) << 24);
|
||||||
ret |= (u32(compare) << 23);
|
ret |= (u32(compare) << 23);
|
||||||
ret |= (u32(cause.unimplemented_operation) << 17);
|
ret |= (u32(cause.unimplemented_operation) << 17);
|
||||||
ret |= (u32(cause.invalid_operation) << 16);
|
ret |= (u32(cause.invalid_operation) << 16);
|
||||||
ret |= (u32(cause.division_by_zero) << 15);
|
ret |= (u32(cause.division_by_zero) << 15);
|
||||||
ret |= (u32(cause.overflow) << 14);
|
ret |= (u32(cause.overflow) << 14);
|
||||||
ret |= (u32(cause.underflow) << 13);
|
ret |= (u32(cause.underflow) << 13);
|
||||||
ret |= (u32(cause.inexact_operation) << 12);
|
ret |= (u32(cause.inexact_operation) << 12);
|
||||||
ret |= (u32(enable.invalid_operation) << 11);
|
ret |= (u32(enable.invalid_operation) << 11);
|
||||||
ret |= (u32(enable.division_by_zero) << 10);
|
ret |= (u32(enable.division_by_zero) << 10);
|
||||||
ret |= (u32(enable.overflow) << 9);
|
ret |= (u32(enable.overflow) << 9);
|
||||||
ret |= (u32(enable.underflow) << 8);
|
ret |= (u32(enable.underflow) << 8);
|
||||||
ret |= (u32(enable.inexact_operation) << 7);
|
ret |= (u32(enable.inexact_operation) << 7);
|
||||||
ret |= (u32(flag.invalid_operation) << 6);
|
ret |= (u32(flag.invalid_operation) << 6);
|
||||||
ret |= (u32(flag.division_by_zero) << 5);
|
ret |= (u32(flag.division_by_zero) << 5);
|
||||||
ret |= (u32(flag.overflow) << 4);
|
ret |= (u32(flag.overflow) << 4);
|
||||||
ret |= (u32(flag.underflow) << 3);
|
ret |= (u32(flag.underflow) << 3);
|
||||||
ret |= (u32(flag.inexact_operation) << 2);
|
ret |= (u32(flag.inexact_operation) << 2);
|
||||||
ret |= (u32(rounding_mode) & 3);
|
ret |= (u32(rounding_mode) & 3);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(u32 val) {
|
void write(u32 val) {
|
||||||
fs = val >> 24;
|
fs = val >> 24;
|
||||||
compare = val >> 23;
|
compare = val >> 23;
|
||||||
cause.unimplemented_operation = val >> 17;
|
cause.unimplemented_operation = val >> 17;
|
||||||
cause.invalid_operation = val >> 16;
|
cause.invalid_operation = val >> 16;
|
||||||
cause.division_by_zero = val >> 15;
|
cause.division_by_zero = val >> 15;
|
||||||
cause.overflow = val >> 14;
|
cause.overflow = val >> 14;
|
||||||
cause.underflow = val >> 13;
|
cause.underflow = val >> 13;
|
||||||
cause.inexact_operation = val >> 12;
|
cause.inexact_operation = val >> 12;
|
||||||
enable.invalid_operation = val >> 11;
|
enable.invalid_operation = val >> 11;
|
||||||
enable.division_by_zero = val >> 10;
|
enable.division_by_zero = val >> 10;
|
||||||
enable.overflow = val >> 9;
|
enable.overflow = val >> 9;
|
||||||
enable.underflow = val >> 8;
|
enable.underflow = val >> 8;
|
||||||
enable.inexact_operation = val >> 7;
|
enable.inexact_operation = val >> 7;
|
||||||
flag.invalid_operation = val >> 6;
|
flag.invalid_operation = val >> 6;
|
||||||
flag.division_by_zero = val >> 5;
|
flag.division_by_zero = val >> 5;
|
||||||
flag.overflow = val >> 4;
|
flag.overflow = val >> 4;
|
||||||
flag.underflow = val >> 3;
|
flag.underflow = val >> 3;
|
||||||
flag.inexact_operation = val >> 2;
|
flag.inexact_operation = val >> 2;
|
||||||
rounding_mode = val & 3;
|
rounding_mode = val & 3;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
union FloatingPointReg {
|
union FloatingPointReg {
|
||||||
struct {
|
struct {
|
||||||
s32 int32;
|
s32 int32;
|
||||||
s32 int32h;
|
s32 int32h;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
u32 uint32;
|
u32 uint32;
|
||||||
u32 uint32h;
|
u32 uint32h;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
s64 int64;
|
s64 int64;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
u64 uint64;
|
u64 uint64;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
float float32;
|
float float32;
|
||||||
float float32h;
|
float float32h;
|
||||||
};
|
};
|
||||||
struct {
|
struct {
|
||||||
double float64;
|
double float64;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Cop1 {
|
struct Cop1 {
|
||||||
explicit Cop1();
|
explicit Cop1();
|
||||||
bool fgrIsConstant[32]{};
|
bool fgrIsConstant[32]{};
|
||||||
u32 fcr0{};
|
u32 fcr0{};
|
||||||
FCR31 fcr31{};
|
FCR31 fcr31{};
|
||||||
FloatingPointReg fgr[32]{};
|
FloatingPointReg fgr[32]{};
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void decode(const Instruction);
|
void decode(const Instruction);
|
||||||
friend struct Interpreter;
|
friend struct Interpreter;
|
||||||
friend struct JIT;
|
friend struct JIT;
|
||||||
|
|
||||||
template <bool preserveCause = false>
|
template <bool preserveCause = false>
|
||||||
bool CheckFPUUsable();
|
bool CheckFPUUsable();
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckResult(T &);
|
bool CheckResult(T &);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckArg(T);
|
bool CheckArg(T);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckArgs(T, T);
|
bool CheckArgs(T, T);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool isqnan(T);
|
bool isqnan(T);
|
||||||
|
|
||||||
template <typename T, bool quiet, bool cf>
|
template <typename T, bool quiet, bool cf>
|
||||||
bool XORDERED(T fs, T ft);
|
bool XORDERED(T fs, T ft);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckCVTArg(float f);
|
bool CheckCVTArg(float f);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckCVTArg(double f);
|
bool CheckCVTArg(double f);
|
||||||
|
|
||||||
template <bool cvt = false>
|
template <bool cvt = false>
|
||||||
bool TestExceptions();
|
bool TestExceptions();
|
||||||
void SetCauseUnimplemented();
|
void SetCauseUnimplemented();
|
||||||
bool SetCauseUnderflow();
|
bool SetCauseUnderflow();
|
||||||
bool SetCauseInexact();
|
bool SetCauseInexact();
|
||||||
bool SetCauseDivisionByZero();
|
bool SetCauseDivisionByZero();
|
||||||
bool SetCauseOverflow();
|
bool SetCauseOverflow();
|
||||||
bool SetCauseInvalid();
|
bool SetCauseInvalid();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto FGR_T(const Cop0Status &, u32) -> T &;
|
auto FGR_T(const Cop0::Status &, u32) -> T &;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto FGR_S(const Cop0Status &, u32) -> T &;
|
auto FGR_S(const Cop0::Status &, u32) -> T &;
|
||||||
template <typename 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 absd(const Instruction instr);
|
||||||
void abss(const Instruction instr);
|
void abss(const Instruction instr);
|
||||||
void adds(const Instruction instr);
|
void adds(const Instruction instr);
|
||||||
void addd(const Instruction instr);
|
void addd(const Instruction instr);
|
||||||
void subs(const Instruction instr);
|
void subs(const Instruction instr);
|
||||||
void subd(const Instruction instr);
|
void subd(const Instruction instr);
|
||||||
void ceills(const Instruction instr);
|
void ceills(const Instruction instr);
|
||||||
void ceilws(const Instruction instr);
|
void ceilws(const Instruction instr);
|
||||||
void ceilld(const Instruction instr);
|
void ceilld(const Instruction instr);
|
||||||
void ceilwd(const Instruction instr);
|
void ceilwd(const Instruction instr);
|
||||||
void cfc1(const Instruction instr);
|
void cfc1(const Instruction instr);
|
||||||
void ctc1(const Instruction instr);
|
void ctc1(const Instruction instr);
|
||||||
void unimplemented();
|
void unimplemented();
|
||||||
void roundls(const Instruction instr);
|
void roundls(const Instruction instr);
|
||||||
void roundld(const Instruction instr);
|
void roundld(const Instruction instr);
|
||||||
void roundws(const Instruction instr);
|
void roundws(const Instruction instr);
|
||||||
void roundwd(const Instruction instr);
|
void roundwd(const Instruction instr);
|
||||||
void floorls(const Instruction instr);
|
void floorls(const Instruction instr);
|
||||||
void floorld(const Instruction instr);
|
void floorld(const Instruction instr);
|
||||||
void floorws(const Instruction instr);
|
void floorws(const Instruction instr);
|
||||||
void floorwd(const Instruction instr);
|
void floorwd(const Instruction instr);
|
||||||
void cvtls(const Instruction instr);
|
void cvtls(const Instruction instr);
|
||||||
void cvtws(const Instruction instr);
|
void cvtws(const Instruction instr);
|
||||||
void cvtds(const Instruction instr);
|
void cvtds(const Instruction instr);
|
||||||
void cvtsw(const Instruction instr);
|
void cvtsw(const Instruction instr);
|
||||||
void cvtdw(const Instruction instr);
|
void cvtdw(const Instruction instr);
|
||||||
void cvtsd(const Instruction instr);
|
void cvtsd(const Instruction instr);
|
||||||
void cvtwd(const Instruction instr);
|
void cvtwd(const Instruction instr);
|
||||||
void cvtld(const Instruction instr);
|
void cvtld(const Instruction instr);
|
||||||
void cvtdl(const Instruction instr);
|
void cvtdl(const Instruction instr);
|
||||||
void cvtsl(const Instruction instr);
|
void cvtsl(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cf(const Instruction instr);
|
void cf(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cun(const Instruction instr);
|
void cun(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ceq(const Instruction instr);
|
void ceq(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cueq(const Instruction instr);
|
void cueq(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void colt(const Instruction instr);
|
void colt(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cult(const Instruction instr);
|
void cult(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cole(const Instruction instr);
|
void cole(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cule(const Instruction instr);
|
void cule(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void csf(const Instruction instr);
|
void csf(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cngle(const Instruction instr);
|
void cngle(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cseq(const Instruction instr);
|
void cseq(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cngl(const Instruction instr);
|
void cngl(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void clt(const Instruction instr);
|
void clt(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cnge(const Instruction instr);
|
void cnge(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cle(const Instruction instr);
|
void cle(const Instruction instr);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void cngt(const Instruction instr);
|
void cngt(const Instruction instr);
|
||||||
void divs(const Instruction instr);
|
void divs(const Instruction instr);
|
||||||
void divd(const Instruction instr);
|
void divd(const Instruction instr);
|
||||||
void muls(const Instruction instr);
|
void muls(const Instruction instr);
|
||||||
void muld(const Instruction instr);
|
void muld(const Instruction instr);
|
||||||
void movs(const Instruction instr);
|
void movs(const Instruction instr);
|
||||||
void movd(const Instruction instr);
|
void movd(const Instruction instr);
|
||||||
void negs(const Instruction instr);
|
void negs(const Instruction instr);
|
||||||
void negd(const Instruction instr);
|
void negd(const Instruction instr);
|
||||||
void sqrts(const Instruction instr);
|
void sqrts(const Instruction instr);
|
||||||
void sqrtd(const Instruction instr);
|
void sqrtd(const Instruction instr);
|
||||||
void lwc1(const Instruction instr);
|
void lwc1(const Instruction instr);
|
||||||
void swc1(const Instruction instr);
|
void swc1(const Instruction instr);
|
||||||
void ldc1(const Instruction instr);
|
void ldc1(const Instruction instr);
|
||||||
void sdc1(const Instruction instr);
|
void sdc1(const Instruction instr);
|
||||||
|
|
||||||
void mfc1(const Instruction instr);
|
void mfc1(const Instruction instr);
|
||||||
void dmfc1(const Instruction instr);
|
void dmfc1(const Instruction instr);
|
||||||
void mtc1(const Instruction instr);
|
void mtc1(const Instruction instr);
|
||||||
void dmtc1(const Instruction instr);
|
void dmtc1(const Instruction instr);
|
||||||
void truncws(const Instruction instr);
|
void truncws(const Instruction instr);
|
||||||
void truncwd(const Instruction instr);
|
void truncwd(const Instruction instr);
|
||||||
void truncls(const Instruction instr);
|
void truncls(const Instruction instr);
|
||||||
void truncld(const Instruction instr);
|
void truncld(const Instruction instr);
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
Reference in New Issue
Block a user