fpu improvements
This commit is contained in:
Submodule external/parallel-rdp/parallel-rdp-standalone updated: 1203303ac1...63f8935dbb
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void JIT::add(u32 instr) {
|
void JIT::add(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
movsx(eax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // rs
|
movsx(eax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // rs
|
||||||
movsx(ecx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // rt
|
movsx(ecx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // rt
|
||||||
CodeGenerator::add(eax, ecx);
|
CodeGenerator::add(eax, ecx);
|
||||||
@@ -19,7 +19,7 @@ void JIT::addu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::addi(u32 instr) {
|
void JIT::addi(u32 instr) {
|
||||||
if(likely(RT(instr) != 0)) {
|
if (RT(instr) != 0) [[likely]] {
|
||||||
movsx(eax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]);
|
movsx(eax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]);
|
||||||
mov(ecx, s32(s16(instr)));
|
mov(ecx, s32(s16(instr)));
|
||||||
CodeGenerator::add(eax, ecx);
|
CodeGenerator::add(eax, ecx);
|
||||||
@@ -32,7 +32,7 @@ void JIT::addiu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dadd(u32 instr) {
|
void JIT::dadd(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr))); // rs
|
mov(rax, GPR(RS(instr))); // rs
|
||||||
mov(rcx, GPR(RT(instr))); // rt
|
mov(rcx, GPR(RT(instr))); // rt
|
||||||
CodeGenerator::add(rax, rcx);
|
CodeGenerator::add(rax, rcx);
|
||||||
@@ -45,7 +45,7 @@ void JIT::daddu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::daddi(u32 instr) {
|
void JIT::daddi(u32 instr) {
|
||||||
if(likely(RT(instr) != 0)) {
|
if (RT(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(rcx, s64(s16(instr)));
|
mov(rcx, s64(s16(instr)));
|
||||||
CodeGenerator::add(rax, rcx);
|
CodeGenerator::add(rax, rcx);
|
||||||
@@ -665,7 +665,7 @@ void JIT::ori(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::or_(u32 instr) {
|
void JIT::or_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(rcx, GPR(RT(instr)));
|
mov(rcx, GPR(RT(instr)));
|
||||||
CodeGenerator::or_(rax, rcx);
|
CodeGenerator::or_(rax, rcx);
|
||||||
@@ -674,7 +674,7 @@ void JIT::or_(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::nor(u32 instr) {
|
void JIT::nor(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(rcx, GPR(RT(instr)));
|
mov(rcx, GPR(RT(instr)));
|
||||||
CodeGenerator::or_(rax, rcx);
|
CodeGenerator::or_(rax, rcx);
|
||||||
@@ -702,7 +702,7 @@ void JIT::jalr(u32 instr) {
|
|||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(qword[rdi + offsetof(Registers, nextPC)], rax);
|
mov(qword[rdi + offsetof(Registers, nextPC)], rax);
|
||||||
|
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, qword[rdi + offsetof(Registers, pc)]);
|
mov(rax, qword[rdi + offsetof(Registers, pc)]);
|
||||||
CodeGenerator::add(rax, 4);
|
CodeGenerator::add(rax, 4);
|
||||||
mov(GPR(RD(instr)), rax);
|
mov(GPR(RD(instr)), rax);
|
||||||
@@ -724,7 +724,7 @@ void JIT::sltiu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::slt(u32 instr) {
|
void JIT::slt(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(rcx, GPR(RT(instr)));
|
mov(rcx, GPR(RT(instr)));
|
||||||
cmp(rax, rcx);
|
cmp(rax, rcx);
|
||||||
@@ -733,7 +733,7 @@ void JIT::slt(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::sltu(u32 instr) {
|
void JIT::sltu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RS(instr)));
|
mov(rax, GPR(RS(instr)));
|
||||||
mov(rcx, GPR(RT(instr)));
|
mov(rcx, GPR(RT(instr)));
|
||||||
cmp(rax, rcx);
|
cmp(rax, rcx);
|
||||||
@@ -750,7 +750,7 @@ void JIT::xori(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::xor_(u32 instr) {
|
void JIT::xor_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::xor_(rax, rcx);
|
CodeGenerator::xor_(rax, rcx);
|
||||||
@@ -767,7 +767,7 @@ void JIT::andi(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::and_(u32 instr) {
|
void JIT::and_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(rax, rcx);
|
CodeGenerator::and_(rax, rcx);
|
||||||
@@ -776,7 +776,7 @@ void JIT::and_(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::sll(u32 instr) {
|
void JIT::sll(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sal(rax, sa);
|
sal(rax, sa);
|
||||||
@@ -786,7 +786,7 @@ void JIT::sll(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::sllv(u32 instr) {
|
void JIT::sllv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 0x1F);
|
CodeGenerator::and_(cl, 0x1F);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -797,7 +797,7 @@ void JIT::sllv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsll32(u32 instr) {
|
void JIT::dsll32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sal(rax, sa);
|
sal(rax, sa);
|
||||||
@@ -806,7 +806,7 @@ void JIT::dsll32(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsll(u32 instr) {
|
void JIT::dsll(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sal(rax, sa);
|
sal(rax, sa);
|
||||||
@@ -815,7 +815,7 @@ void JIT::dsll(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsllv(u32 instr) {
|
void JIT::dsllv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 63);
|
CodeGenerator::and_(cl, 63);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -825,7 +825,7 @@ void JIT::dsllv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::srl(u32 instr) {
|
void JIT::srl(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
CodeGenerator::shr(rax, sa);
|
CodeGenerator::shr(rax, sa);
|
||||||
@@ -835,7 +835,7 @@ void JIT::srl(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::srlv(u32 instr) {
|
void JIT::srlv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 0x1F);
|
CodeGenerator::and_(cl, 0x1F);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -846,7 +846,7 @@ void JIT::srlv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsrl(u32 instr) {
|
void JIT::dsrl(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
CodeGenerator::shr(rax, sa);
|
CodeGenerator::shr(rax, sa);
|
||||||
@@ -855,7 +855,7 @@ void JIT::dsrl(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsrlv(u32 instr) {
|
void JIT::dsrlv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 63);
|
CodeGenerator::and_(cl, 63);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -865,7 +865,7 @@ void JIT::dsrlv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsrl32(u32 instr) {
|
void JIT::dsrl32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
CodeGenerator::shr(rax, sa);
|
CodeGenerator::shr(rax, sa);
|
||||||
@@ -874,7 +874,7 @@ void JIT::dsrl32(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::sra(u32 instr) {
|
void JIT::sra(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sar(rax, sa);
|
sar(rax, sa);
|
||||||
@@ -884,7 +884,7 @@ void JIT::sra(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::srav(u32 instr) {
|
void JIT::srav(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 0x1F);
|
CodeGenerator::and_(cl, 0x1F);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -895,7 +895,7 @@ void JIT::srav(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsra(u32 instr) {
|
void JIT::dsra(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sar(rax, sa);
|
sar(rax, sa);
|
||||||
@@ -904,7 +904,7 @@ void JIT::dsra(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsrav(u32 instr) {
|
void JIT::dsrav(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::and_(cl, 63);
|
CodeGenerator::and_(cl, 63);
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
@@ -914,7 +914,7 @@ void JIT::dsrav(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsra32(u32 instr) {
|
void JIT::dsra32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
u8 sa = ((instr >> 6) & 0x1f) + 32;
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
sar(rax, sa);
|
sar(rax, sa);
|
||||||
@@ -929,7 +929,7 @@ void JIT::jr(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::dsub(u32 instr) {
|
void JIT::dsub(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(rax, GPR(RT(instr)));
|
mov(rax, GPR(RT(instr)));
|
||||||
mov(rcx, GPR(RS(instr)));
|
mov(rcx, GPR(RS(instr)));
|
||||||
CodeGenerator::sub(rcx, rax);
|
CodeGenerator::sub(rcx, rax);
|
||||||
@@ -942,7 +942,7 @@ void JIT::dsubu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::sub(u32 instr) {
|
void JIT::sub(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
mov(eax, GPR(RT(instr)));
|
mov(eax, GPR(RT(instr)));
|
||||||
mov(ecx, GPR(RS(instr)));
|
mov(ecx, GPR(RS(instr)));
|
||||||
CodeGenerator::sub(ecx, eax);
|
CodeGenerator::sub(ecx, eax);
|
||||||
@@ -988,13 +988,13 @@ void JIT::mult(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::mflo(u32 instr) {
|
void JIT::mflo(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.lo;
|
regs.gpr[RD(instr)] = regs.lo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::mfhi(u32 instr) {
|
void JIT::mfhi(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.hi;
|
regs.gpr[RD(instr)] = regs.hi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ void Interpreter::add(u32 instr) {
|
|||||||
if(check_signed_overflow(rs, rt, result)) {
|
if(check_signed_overflow(rs, rt, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = s32(result);
|
regs.gpr[RD(instr)] = s32(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addu(u32 instr) {
|
void Interpreter::addu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s32 rs = (s32)regs.gpr[RS(instr)];
|
s32 rs = (s32)regs.gpr[RS(instr)];
|
||||||
s32 rt = (s32)regs.gpr[RT(instr)];
|
s32 rt = (s32)regs.gpr[RT(instr)];
|
||||||
s32 result = rs + rt;
|
s32 result = rs + rt;
|
||||||
@@ -34,15 +34,19 @@ void Interpreter::addi(u32 instr) {
|
|||||||
if(check_signed_overflow(rs, imm, result)) {
|
if(check_signed_overflow(rs, imm, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = s32(result);
|
regs.gpr[RT(instr)] = s32(result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addiu(u32 instr) {
|
void Interpreter::addiu(u32 instr) {
|
||||||
s32 rs = (s32)regs.gpr[RS(instr)];
|
s32 rs = (s32)regs.gpr[RS(instr)];
|
||||||
s16 imm = (s16)(instr);
|
s16 imm = (s16)(instr);
|
||||||
s32 result = rs + imm;
|
s32 result = rs + imm;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dadd(u32 instr) {
|
void Interpreter::dadd(u32 instr) {
|
||||||
@@ -52,14 +56,14 @@ void Interpreter::dadd(u32 instr) {
|
|||||||
if(check_signed_overflow(rs, rt, result)) {
|
if(check_signed_overflow(rs, rt, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::daddu(u32 instr) {
|
void Interpreter::daddu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 rs = regs.gpr[RS(instr)];
|
s64 rs = regs.gpr[RS(instr)];
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
regs.gpr[RD(instr)] = rs + rt;
|
regs.gpr[RD(instr)] = rs + rt;
|
||||||
@@ -73,14 +77,18 @@ void Interpreter::daddi(u32 instr) {
|
|||||||
if(check_signed_overflow(rs, imm, result)) {
|
if(check_signed_overflow(rs, imm, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::daddiu(u32 instr) {
|
void Interpreter::daddiu(u32 instr) {
|
||||||
s16 imm = (s16)(instr);
|
s16 imm = (s16)(instr);
|
||||||
s64 rs = regs.gpr[RS(instr)];
|
s64 rs = regs.gpr[RS(instr)];
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = rs + imm;
|
regs.gpr[RT(instr)] = rs + imm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::div(u32 instr) {
|
void Interpreter::div(u32 instr) {
|
||||||
@@ -200,7 +208,9 @@ void Interpreter::bllink(u32 instr, bool cond) {
|
|||||||
void Interpreter::lui(u32 instr) {
|
void Interpreter::lui(u32 instr) {
|
||||||
u64 val = s64((s16)instr);
|
u64 val = s64((s16)instr);
|
||||||
val <<= 16;
|
val <<= 16;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = val;
|
regs.gpr[RT(instr)] = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lb(u32 instr) {
|
void Interpreter::lb(u32 instr) {
|
||||||
@@ -210,13 +220,15 @@ void Interpreter::lb(u32 instr) {
|
|||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr);
|
if (RT(instr) != 0) [[likely]] {
|
||||||
|
regs.gpr[RT(instr)] = (s8) mem.Read8(regs, paddr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lh(u32 instr) {
|
void Interpreter::lh(u32 instr) {
|
||||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 0b1) > 0) {
|
if (check_address_error(0b1, address)) {
|
||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
return;
|
return;
|
||||||
@@ -227,7 +239,9 @@ void Interpreter::lh(u32 instr) {
|
|||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RT(instr)] = (s16)mem.Read16(regs, paddr);
|
if (RT(instr) != 0) [[likely]] {
|
||||||
|
regs.gpr[RT(instr)] = (s16) mem.Read16(regs, paddr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +259,9 @@ void Interpreter::lw(u32 instr) {
|
|||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical);
|
if(RT(instr) != 0) [[likely]] {
|
||||||
|
regs.gpr[RT(instr)] = (s32) mem.Read32(regs, physical);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,12 +273,14 @@ void Interpreter::ll(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
s32 result = mem.Read32(regs, physical);
|
s32 result = mem.Read32(regs, physical);
|
||||||
if ((address & 0b11) > 0) {
|
if (check_address_error(0b11, address)) {
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
|
}
|
||||||
|
|
||||||
regs.cop0.llbit = true;
|
regs.cop0.llbit = true;
|
||||||
regs.cop0.LLAddr = physical >> 4;
|
regs.cop0.LLAddr = physical >> 4;
|
||||||
@@ -280,8 +298,10 @@ void Interpreter::lwl(u32 instr) {
|
|||||||
u32 mask = 0xFFFFFFFF << shift;
|
u32 mask = 0xFFFFFFFF << shift;
|
||||||
u32 data = mem.Read32(regs, paddr & ~3);
|
u32 data = mem.Read32(regs, paddr & ~3);
|
||||||
s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data << shift));
|
s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data << shift));
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lwr(u32 instr) {
|
void Interpreter::lwr(u32 instr) {
|
||||||
@@ -295,8 +315,10 @@ void Interpreter::lwr(u32 instr) {
|
|||||||
u32 mask = 0xFFFFFFFF >> shift;
|
u32 mask = 0xFFFFFFFF >> shift;
|
||||||
u32 data = mem.Read32(regs, paddr & ~3);
|
u32 data = mem.Read32(regs, paddr & ~3);
|
||||||
s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data >> shift));
|
s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data >> shift));
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ld(u32 instr) {
|
void Interpreter::ld(u32 instr) {
|
||||||
@@ -313,8 +335,10 @@ void Interpreter::ld(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
s64 value = mem.Read64(regs, paddr);
|
s64 value = mem.Read64(regs, paddr);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = value;
|
regs.gpr[RT(instr)] = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lld(u32 instr) {
|
void Interpreter::lld(u32 instr) {
|
||||||
@@ -329,10 +353,12 @@ void Interpreter::lld(u32 instr) {
|
|||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
if ((address & 0b111) > 0) {
|
if (check_address_error(0b111, address)) {
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
} else {
|
} else {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = mem.Read64(regs, paddr);
|
regs.gpr[RT(instr)] = mem.Read64(regs, paddr);
|
||||||
|
}
|
||||||
regs.cop0.llbit = true;
|
regs.cop0.llbit = true;
|
||||||
regs.cop0.LLAddr = paddr >> 4;
|
regs.cop0.LLAddr = paddr >> 4;
|
||||||
}
|
}
|
||||||
@@ -350,8 +376,10 @@ void Interpreter::ldl(u32 instr) {
|
|||||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||||
u64 data = mem.Read64(regs, paddr & ~7);
|
u64 data = mem.Read64(regs, paddr & ~7);
|
||||||
s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data << shift));
|
s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data << shift));
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ldr(u32 instr) {
|
void Interpreter::ldr(u32 instr) {
|
||||||
@@ -365,8 +393,10 @@ void Interpreter::ldr(u32 instr) {
|
|||||||
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||||
u64 data = mem.Read64(regs, paddr & ~7);
|
u64 data = mem.Read64(regs, paddr & ~7);
|
||||||
s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data >> shift));
|
s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data >> shift));
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lbu(u32 instr) {
|
void Interpreter::lbu(u32 instr) {
|
||||||
@@ -377,13 +407,15 @@ void Interpreter::lbu(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
u8 value = mem.Read8(regs, paddr);
|
u8 value = mem.Read8(regs, paddr);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = value;
|
regs.gpr[RT(instr)] = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lhu(u32 instr) {
|
void Interpreter::lhu(u32 instr) {
|
||||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 0b1) > 0) {
|
if (check_address_error(0b1, address)) {
|
||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
return;
|
return;
|
||||||
@@ -394,13 +426,15 @@ void Interpreter::lhu(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
u16 value = mem.Read16(regs, paddr);
|
u16 value = mem.Read16(regs, paddr);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = value;
|
regs.gpr[RT(instr)] = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lwu(u32 instr) {
|
void Interpreter::lwu(u32 instr) {
|
||||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 0b11) > 0) {
|
if (check_address_error(0b11, address)) {
|
||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
return;
|
return;
|
||||||
@@ -412,8 +446,10 @@ void Interpreter::lwu(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
u32 value = mem.Read32(regs, paddr);
|
u32 value = mem.Read32(regs, paddr);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = value;
|
regs.gpr[RT(instr)] = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sb(u32 instr) {
|
void Interpreter::sb(u32 instr) {
|
||||||
@@ -430,7 +466,7 @@ void Interpreter::sb(u32 instr) {
|
|||||||
void Interpreter::sc(u32 instr) {
|
void Interpreter::sc(u32 instr) {
|
||||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
|
|
||||||
if ((address & 0b11) > 0) {
|
if (check_address_error(0b11, address)) {
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -443,11 +479,15 @@ void Interpreter::sc(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||||
} else {
|
} else {
|
||||||
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
|
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = 1;
|
regs.gpr[RT(instr)] = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = 0;
|
regs.gpr[RT(instr)] = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::scd(u32 instr) {
|
void Interpreter::scd(u32 instr) {
|
||||||
@@ -457,7 +497,7 @@ void Interpreter::scd(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 0b111) > 0) {
|
if (check_address_error(0b111, address)) {
|
||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||||
return;
|
return;
|
||||||
@@ -471,11 +511,15 @@ void Interpreter::scd(u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||||
} else {
|
} else {
|
||||||
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
|
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = 1;
|
regs.gpr[RT(instr)] = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = 0;
|
regs.gpr[RT(instr)] = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sh(u32 instr) {
|
void Interpreter::sh(u32 instr) {
|
||||||
@@ -588,17 +632,19 @@ void Interpreter::swr(u32 instr) {
|
|||||||
void Interpreter::ori(u32 instr) {
|
void Interpreter::ori(u32 instr) {
|
||||||
s64 imm = (u16)instr;
|
s64 imm = (u16)instr;
|
||||||
s64 result = imm | regs.gpr[RS(instr)];
|
s64 result = imm | regs.gpr[RS(instr)];
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::or_(u32 instr) {
|
void Interpreter::or_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] | regs.gpr[RT(instr)];
|
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] | regs.gpr[RT(instr)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::nor(u32 instr) {
|
void Interpreter::nor(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = ~(regs.gpr[RS(instr)] | regs.gpr[RT(instr)]);
|
regs.gpr[RD(instr)] = ~(regs.gpr[RS(instr)] | regs.gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -616,58 +662,71 @@ void Interpreter::jal(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::jalr(u32 instr) {
|
void Interpreter::jalr(u32 instr) {
|
||||||
branch(true, regs.gpr[RS(instr)]);
|
u64 addr = regs.gpr[RS(instr)];
|
||||||
if(likely(RD(instr) != 0)) {
|
if(check_address_error(0b11, addr)) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
|
} else {
|
||||||
|
branch(true, addr);
|
||||||
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.pc + 4;
|
regs.gpr[RD(instr)] = regs.pc + 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::slti(u32 instr) {
|
void Interpreter::slti(u32 instr) {
|
||||||
s16 imm = instr;
|
s16 imm = instr;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < imm;
|
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < imm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sltiu(u32 instr) {
|
void Interpreter::sltiu(u32 instr) {
|
||||||
s16 imm = instr;
|
s16 imm = instr;
|
||||||
regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < imm;
|
if (RT(instr) != 0) [[likely]] {
|
||||||
|
regs.gpr[RT(instr)] = (u64) regs.gpr[RS(instr)] < imm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::slt(u32 instr) {
|
void Interpreter::slt(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] < regs.gpr[RT(instr)];
|
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] < regs.gpr[RT(instr)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sltu(u32 instr) {
|
void Interpreter::sltu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = (u64) regs.gpr[RS(instr)] < (u64) regs.gpr[RT(instr)];
|
regs.gpr[RD(instr)] = (u64) regs.gpr[RS(instr)] < (u64) regs.gpr[RT(instr)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::xori(u32 instr) {
|
void Interpreter::xori(u32 instr) {
|
||||||
s64 imm = (u16)instr;
|
s64 imm = (u16)instr;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] ^ imm;
|
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] ^ imm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::xor_(u32 instr) {
|
void Interpreter::xor_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.gpr[RT(instr)] ^ regs.gpr[RS(instr)];
|
regs.gpr[RD(instr)] = regs.gpr[RT(instr)] ^ regs.gpr[RS(instr)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::andi(u32 instr) {
|
void Interpreter::andi(u32 instr) {
|
||||||
s64 imm = (u16)instr;
|
s64 imm = (u16)instr;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm;
|
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::and_(u32 instr) {
|
void Interpreter::and_(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)];
|
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sll(u32 instr) {
|
void Interpreter::sll(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s32 result = regs.gpr[RT(instr)] << sa;
|
s32 result = regs.gpr[RT(instr)] << sa;
|
||||||
regs.gpr[RD(instr)] = (s64) result;
|
regs.gpr[RD(instr)] = (s64) result;
|
||||||
@@ -675,7 +734,7 @@ void Interpreter::sll(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sllv(u32 instr) {
|
void Interpreter::sllv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = (regs.gpr[RS(instr)]) & 0x1F;
|
u8 sa = (regs.gpr[RS(instr)]) & 0x1F;
|
||||||
u32 rt = regs.gpr[RT(instr)];
|
u32 rt = regs.gpr[RT(instr)];
|
||||||
s32 result = rt << sa;
|
s32 result = rt << sa;
|
||||||
@@ -684,7 +743,7 @@ void Interpreter::sllv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsll32(u32 instr) {
|
void Interpreter::dsll32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s64 result = regs.gpr[RT(instr)] << (sa + 32);
|
s64 result = regs.gpr[RT(instr)] << (sa + 32);
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
@@ -692,7 +751,7 @@ void Interpreter::dsll32(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsll(u32 instr) {
|
void Interpreter::dsll(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s64 result = regs.gpr[RT(instr)] << sa;
|
s64 result = regs.gpr[RT(instr)] << sa;
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
@@ -700,7 +759,7 @@ void Interpreter::dsll(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsllv(u32 instr) {
|
void Interpreter::dsllv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 sa = regs.gpr[RS(instr)] & 63;
|
s64 sa = regs.gpr[RS(instr)] & 63;
|
||||||
s64 result = regs.gpr[RT(instr)] << sa;
|
s64 result = regs.gpr[RT(instr)] << sa;
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
@@ -708,7 +767,7 @@ void Interpreter::dsllv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srl(u32 instr) {
|
void Interpreter::srl(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u32 rt = regs.gpr[RT(instr)];
|
u32 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
u32 result = rt >> sa;
|
u32 result = rt >> sa;
|
||||||
@@ -717,7 +776,7 @@ void Interpreter::srl(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srlv(u32 instr) {
|
void Interpreter::srlv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 sa = (regs.gpr[RS(instr)] & 0x1F);
|
u8 sa = (regs.gpr[RS(instr)] & 0x1F);
|
||||||
u32 rt = regs.gpr[RT(instr)];
|
u32 rt = regs.gpr[RT(instr)];
|
||||||
s32 result = rt >> sa;
|
s32 result = rt >> sa;
|
||||||
@@ -726,7 +785,7 @@ void Interpreter::srlv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrl(u32 instr) {
|
void Interpreter::dsrl(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u64 rt = regs.gpr[RT(instr)];
|
u64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
u64 result = rt >> sa;
|
u64 result = rt >> sa;
|
||||||
@@ -735,7 +794,7 @@ void Interpreter::dsrl(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrlv(u32 instr) {
|
void Interpreter::dsrlv(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u8 amount = (regs.gpr[RS(instr)] & 63);
|
u8 amount = (regs.gpr[RS(instr)] & 63);
|
||||||
u64 rt = regs.gpr[RT(instr)];
|
u64 rt = regs.gpr[RT(instr)];
|
||||||
u64 result = rt >> amount;
|
u64 result = rt >> amount;
|
||||||
@@ -744,7 +803,7 @@ void Interpreter::dsrlv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrl32(u32 instr) {
|
void Interpreter::dsrl32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u64 rt = regs.gpr[RT(instr)];
|
u64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
u64 result = rt >> (sa + 32);
|
u64 result = rt >> (sa + 32);
|
||||||
@@ -753,7 +812,7 @@ void Interpreter::dsrl32(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sra(u32 instr) {
|
void Interpreter::sra(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s32 result = rt >> sa;
|
s32 result = rt >> sa;
|
||||||
@@ -762,9 +821,9 @@ void Interpreter::sra(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srav(u32 instr) {
|
void Interpreter::srav(u32 instr) {
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
if (RD(instr) != 0) [[likely]] {
|
||||||
if(likely(RD(instr) != 0)) {
|
|
||||||
s64 rs = regs.gpr[RS(instr)];
|
s64 rs = regs.gpr[RS(instr)];
|
||||||
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = rs & 0x1f;
|
u8 sa = rs & 0x1f;
|
||||||
s32 result = rt >> sa;
|
s32 result = rt >> sa;
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
@@ -772,7 +831,7 @@ void Interpreter::srav(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsra(u32 instr) {
|
void Interpreter::dsra(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s64 result = rt >> sa;
|
s64 result = rt >> sa;
|
||||||
@@ -781,7 +840,7 @@ void Interpreter::dsra(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrav(u32 instr) {
|
void Interpreter::dsrav(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
s64 rs = regs.gpr[RS(instr)];
|
s64 rs = regs.gpr[RS(instr)];
|
||||||
s64 sa = rs & 63;
|
s64 sa = rs & 63;
|
||||||
@@ -791,7 +850,7 @@ void Interpreter::dsrav(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsra32(u32 instr) {
|
void Interpreter::dsra32(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
u8 sa = ((instr >> 6) & 0x1f);
|
u8 sa = ((instr >> 6) & 0x1f);
|
||||||
s64 result = rt >> (sa + 32);
|
s64 result = rt >> (sa + 32);
|
||||||
@@ -801,7 +860,11 @@ void Interpreter::dsra32(u32 instr) {
|
|||||||
|
|
||||||
void Interpreter::jr(u32 instr) {
|
void Interpreter::jr(u32 instr) {
|
||||||
s64 address = regs.gpr[RS(instr)];
|
s64 address = regs.gpr[RS(instr)];
|
||||||
|
if(check_address_error(0b11, address)) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||||
|
} else {
|
||||||
branch(true, address);
|
branch(true, address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsub(u32 instr) {
|
void Interpreter::dsub(u32 instr) {
|
||||||
@@ -811,14 +874,14 @@ void Interpreter::dsub(u32 instr) {
|
|||||||
if(check_signed_underflow(rs, rt, result)) {
|
if(check_signed_underflow(rs, rt, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsubu(u32 instr) {
|
void Interpreter::dsubu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u64 rt = regs.gpr[RT(instr)];
|
u64 rt = regs.gpr[RT(instr)];
|
||||||
u64 rs = regs.gpr[RS(instr)];
|
u64 rs = regs.gpr[RS(instr)];
|
||||||
u64 result = rs - rt;
|
u64 result = rs - rt;
|
||||||
@@ -833,14 +896,14 @@ void Interpreter::sub(u32 instr) {
|
|||||||
if(check_signed_underflow(rs, rt, result)) {
|
if(check_signed_underflow(rs, rt, result)) {
|
||||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||||
} else {
|
} else {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::subu(u32 instr) {
|
void Interpreter::subu(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
u32 rt = regs.gpr[RT(instr)];
|
u32 rt = regs.gpr[RT(instr)];
|
||||||
u32 rs = regs.gpr[RS(instr)];
|
u32 rs = regs.gpr[RS(instr)];
|
||||||
u32 result = rs - rt;
|
u32 result = rs - rt;
|
||||||
@@ -881,13 +944,13 @@ void Interpreter::mult(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mflo(u32 instr) {
|
void Interpreter::mflo(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.lo;
|
regs.gpr[RD(instr)] = regs.lo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mfhi(u32 instr) {
|
void Interpreter::mfhi(u32 instr) {
|
||||||
if(likely(RD(instr) != 0)) {
|
if (RD(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RD(instr)] = regs.hi;
|
regs.gpr[RD(instr)] = regs.hi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -912,7 +975,9 @@ void Interpreter::mtc2(u32 instr) {
|
|||||||
|
|
||||||
void Interpreter::mfc2(u32 instr) {
|
void Interpreter::mfc2(u32 instr) {
|
||||||
s32 value = cop2Latch;
|
s32 value = cop2Latch;
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = value;
|
regs.gpr[RT(instr)] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dmtc2(u32 instr) {
|
void Interpreter::dmtc2(u32 instr) {
|
||||||
@@ -920,7 +985,9 @@ void Interpreter::dmtc2(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dmfc2(u32 instr) {
|
void Interpreter::dmfc2(u32 instr) {
|
||||||
|
if (RT(instr) != 0) [[likely]] {
|
||||||
regs.gpr[RT(instr)] = cop2Latch;
|
regs.gpr[RT(instr)] = cop2Latch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ctc2(u32) {
|
void Interpreter::ctc2(u32) {
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC)
|
|||||||
bool old_exl = regs.cop0.status.exl;
|
bool old_exl = regs.cop0.status.exl;
|
||||||
s64 pc = useOldPC ? regs.oldPC : regs.pc;
|
s64 pc = useOldPC ? regs.oldPC : regs.pc;
|
||||||
|
|
||||||
if(!regs.cop0.status.exl) {
|
if(!old_exl) {
|
||||||
if(regs.prevDelaySlot) {
|
if(regs.prevDelaySlot) {
|
||||||
regs.cop0.cause.branchDelay = true;
|
regs.cop0.cause.branchDelay = true;
|
||||||
pc -= 4;
|
pc -= 4;
|
||||||
|
|||||||
@@ -171,20 +171,20 @@ enum TLBError : u8 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class ExceptionCode : u8 {
|
enum class ExceptionCode : u8 {
|
||||||
Interrupt,
|
Interrupt = 0,
|
||||||
TLBModification,
|
TLBModification = 1,
|
||||||
TLBLoad,
|
TLBLoad = 2,
|
||||||
TLBStore,
|
TLBStore = 3,
|
||||||
AddressErrorLoad,
|
AddressErrorLoad = 4,
|
||||||
AddressErrorStore,
|
AddressErrorStore = 5,
|
||||||
InstructionBusError,
|
InstructionBusError = 6,
|
||||||
DataBusError,
|
DataBusError = 7,
|
||||||
Syscall,
|
Syscall = 8,
|
||||||
Breakpoint,
|
Breakpoint = 9,
|
||||||
ReservedInstruction,
|
ReservedInstruction = 10,
|
||||||
CoprocessorUnusable,
|
CoprocessorUnusable = 11,
|
||||||
Overflow,
|
Overflow = 12,
|
||||||
Trap,
|
Trap = 13,
|
||||||
FloatingPointError = 15,
|
FloatingPointError = 15,
|
||||||
Watch = 23
|
Watch = 23
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ Cop1::Cop1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::Reset() {
|
void Cop1::Reset() {
|
||||||
fcr0 = 0;
|
fcr0 = 0xa00;
|
||||||
fcr31.raw = 0x01000800;
|
fcr31.write(0x01000800);
|
||||||
memset(fgr, 0, 32 * sizeof(FGR));
|
memset(fgr, 0, 32 * sizeof(FGR));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,10 +32,6 @@ template void Cop1::decode<JIT>(JIT&, u32);
|
|||||||
|
|
||||||
void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
||||||
Registers ®s = cpu.regs;
|
Registers ®s = cpu.regs;
|
||||||
if(!regs.cop0.status.cu1) {
|
|
||||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 mask_sub = (instr >> 21) & 0x1F;
|
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
u8 mask_fun = instr & 0x3F;
|
u8 mask_fun = instr & 0x3F;
|
||||||
@@ -45,11 +41,11 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x00: mfc1(regs, instr); break;
|
case 0x00: mfc1(regs, instr); break;
|
||||||
case 0x01: dmfc1(regs, instr); break;
|
case 0x01: dmfc1(regs, instr); break;
|
||||||
case 0x02: cfc1(regs, instr); break;
|
case 0x02: cfc1(regs, instr); break;
|
||||||
case 0x03: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
|
case 0x03: unimplemented(regs); break;
|
||||||
case 0x04: mtc1(regs, instr); break;
|
case 0x04: mtc1(regs, instr); break;
|
||||||
case 0x05: dmtc1(regs, instr); break;
|
case 0x05: dmtc1(regs, instr); break;
|
||||||
case 0x06: ctc1(regs, instr); break;
|
case 0x06: ctc1(regs, instr); break;
|
||||||
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
|
case 0x07: unimplemented(regs); break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
switch(mask_branch) {
|
switch(mask_branch) {
|
||||||
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break;
|
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break;
|
||||||
@@ -77,9 +73,6 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x0D: truncws(regs, instr); break;
|
case 0x0D: truncws(regs, instr); break;
|
||||||
case 0x0E: ceilws(regs, instr); break;
|
case 0x0E: ceilws(regs, instr); break;
|
||||||
case 0x0F: floorws(regs, instr); break;
|
case 0x0F: floorws(regs, instr); break;
|
||||||
case 0x20:
|
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
|
||||||
break;
|
|
||||||
case 0x21: cvtds(regs, instr); break;
|
case 0x21: cvtds(regs, instr); break;
|
||||||
case 0x24: cvtws(regs, instr); break;
|
case 0x24: cvtws(regs, instr); break;
|
||||||
case 0x25: cvtls(regs, instr); break;
|
case 0x25: cvtls(regs, instr); break;
|
||||||
@@ -99,7 +92,7 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x3D: ccond<float>(regs, instr, NGE); break;
|
case 0x3D: ccond<float>(regs, instr, NGE); break;
|
||||||
case 0x3E: ccond<float>(regs, instr, LE); break;
|
case 0x3E: ccond<float>(regs, instr, LE); break;
|
||||||
case 0x3F: ccond<float>(regs, instr, NGT); break;
|
case 0x3F: ccond<float>(regs, instr, NGT); break;
|
||||||
default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
default: unimplemented(regs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x11: // d
|
case 0x11: // d
|
||||||
@@ -121,9 +114,6 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x0E: ceilwd(regs, instr); break;
|
case 0x0E: ceilwd(regs, instr); break;
|
||||||
case 0x0F: floorwd(regs, instr); break;
|
case 0x0F: floorwd(regs, instr); break;
|
||||||
case 0x20: cvtsd(regs, instr); break;
|
case 0x20: cvtsd(regs, instr); break;
|
||||||
case 0x21:
|
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
|
||||||
break;
|
|
||||||
case 0x24: cvtwd(regs, instr); break;
|
case 0x24: cvtwd(regs, instr); break;
|
||||||
case 0x25: cvtld(regs, instr); break;
|
case 0x25: cvtld(regs, instr); break;
|
||||||
case 0x30: ccond<double>(regs, instr, F); break;
|
case 0x30: ccond<double>(regs, instr, F); break;
|
||||||
@@ -142,35 +132,21 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x3D: ccond<double>(regs, instr, NGE); break;
|
case 0x3D: ccond<double>(regs, instr, NGE); break;
|
||||||
case 0x3E: ccond<double>(regs, instr, LE); break;
|
case 0x3E: ccond<double>(regs, instr, LE); break;
|
||||||
case 0x3F: ccond<double>(regs, instr, NGT); break;
|
case 0x3F: ccond<double>(regs, instr, NGT); break;
|
||||||
default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
default: unimplemented(regs);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x14: // w
|
case 0x14: // w
|
||||||
switch(mask_fun) {
|
switch(mask_fun) {
|
||||||
case 0x01: subw(regs, instr); break;
|
|
||||||
case 0x05: absw(regs, instr); break;
|
|
||||||
case 0x02: mulw(regs, instr); break;
|
|
||||||
case 0x06: movw(regs, instr); break;
|
|
||||||
case 0x20: cvtsw(regs, instr); break;
|
case 0x20: cvtsw(regs, instr); break;
|
||||||
case 0x21: cvtdw(regs, instr); break;
|
case 0x21: cvtdw(regs, instr); break;
|
||||||
case 0x24:
|
default: unimplemented(regs);
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
|
||||||
break;
|
|
||||||
default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x15: // l
|
case 0x15: // l
|
||||||
switch(mask_fun) {
|
switch(mask_fun) {
|
||||||
case 0x01: subl(regs, instr); break;
|
|
||||||
case 0x05: absl(regs, instr); break;
|
|
||||||
case 0x02: mull(regs, instr); break;
|
|
||||||
case 0x06: movl(regs, instr); break;
|
|
||||||
case 0x20: cvtsl(regs, instr); break;
|
case 0x20: cvtsl(regs, instr); break;
|
||||||
case 0x21: cvtdl(regs, instr); break;
|
case 0x21: cvtdl(regs, instr); break;
|
||||||
case 0x24: case 0x25:
|
default: unimplemented(regs);
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
|
||||||
break;
|
|
||||||
default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
|
default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
|
||||||
@@ -197,11 +173,11 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
|
|||||||
case 0x00: mfc1(regs, instr); break;
|
case 0x00: mfc1(regs, instr); break;
|
||||||
case 0x01: dmfc1(regs, instr); break;
|
case 0x01: dmfc1(regs, instr); break;
|
||||||
case 0x02: cfc1(regs, instr); break;
|
case 0x02: cfc1(regs, instr); break;
|
||||||
case 0x03: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
|
case 0x03: unimplemented(regs); break;
|
||||||
case 0x04: mtc1(regs, instr); break;
|
case 0x04: mtc1(regs, instr); break;
|
||||||
case 0x05: dmtc1(regs, instr); break;
|
case 0x05: dmtc1(regs, instr); break;
|
||||||
case 0x06: ctc1(regs, instr); break;
|
case 0x06: ctc1(regs, instr); break;
|
||||||
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
|
case 0x07: unimplemented(regs); break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
/*switch(mask_branch) {
|
/*switch(mask_branch) {
|
||||||
case 0: {
|
case 0: {
|
||||||
@@ -239,7 +215,7 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
|
|||||||
case 0x0E: ceilws(regs, instr); break;
|
case 0x0E: ceilws(regs, instr); break;
|
||||||
case 0x0F: floorws(regs, instr); break;
|
case 0x0F: floorws(regs, instr); break;
|
||||||
case 0x20:
|
case 0x20:
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
unimplemented(regs);
|
||||||
break;
|
break;
|
||||||
case 0x21: cvtds(regs, instr); break;
|
case 0x21: cvtds(regs, instr); break;
|
||||||
case 0x24: cvtws(regs, instr); break;
|
case 0x24: cvtws(regs, instr); break;
|
||||||
@@ -283,7 +259,7 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
|
|||||||
case 0x0F: floorwd(regs, instr); break;
|
case 0x0F: floorwd(regs, instr); break;
|
||||||
case 0x20: cvtsd(regs, instr); break;
|
case 0x20: cvtsd(regs, instr); break;
|
||||||
case 0x21:
|
case 0x21:
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
unimplemented(regs);
|
||||||
break;
|
break;
|
||||||
case 0x24: cvtwd(regs, instr); break;
|
case 0x24: cvtwd(regs, instr); break;
|
||||||
case 0x25: cvtld(regs, instr); break;
|
case 0x25: cvtld(regs, instr); break;
|
||||||
@@ -308,28 +284,20 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
|
|||||||
break;
|
break;
|
||||||
case 0x14: // w
|
case 0x14: // w
|
||||||
switch(mask_fun) {
|
switch(mask_fun) {
|
||||||
case 0x01: subw(regs, instr); break;
|
|
||||||
case 0x05: absw(regs, instr); break;
|
|
||||||
case 0x02: mulw(regs, instr); break;
|
|
||||||
case 0x06: movw(regs, instr); break;
|
|
||||||
case 0x20: cvtsw(regs, instr); break;
|
case 0x20: cvtsw(regs, instr); break;
|
||||||
case 0x21: cvtdw(regs, instr); break;
|
case 0x21: cvtdw(regs, instr); break;
|
||||||
case 0x24:
|
case 0x24:
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
unimplemented(regs);
|
||||||
break;
|
break;
|
||||||
default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x15: // l
|
case 0x15: // l
|
||||||
switch(mask_fun) {
|
switch(mask_fun) {
|
||||||
case 0x01: subl(regs, instr); break;
|
|
||||||
case 0x05: absl(regs, instr); break;
|
|
||||||
case 0x02: mull(regs, instr); break;
|
|
||||||
case 0x06: movl(regs, instr); break;
|
|
||||||
case 0x20: cvtsl(regs, instr); break;
|
case 0x20: cvtsl(regs, instr); break;
|
||||||
case 0x21: cvtdl(regs, instr); break;
|
case 0x21: cvtdl(regs, instr); break;
|
||||||
case 0x24: case 0x25:
|
case 0x24: case 0x25:
|
||||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
unimplemented(regs);
|
||||||
break;
|
break;
|
||||||
default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,18 @@ union FCR31 {
|
|||||||
unsigned:14;
|
unsigned:14;
|
||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
u32 raw;
|
u32 read() const {
|
||||||
|
return (fs << 24) | (compare << 23) | (cause << 12) | (enable << 7) | (flag << 2) | rounding_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(u32 val) {
|
||||||
|
fs = (val & 0x01000000) >> 24;
|
||||||
|
compare = (val & 0x00800000) >> 23;
|
||||||
|
cause = (val & 0x0003f000) >> 12;
|
||||||
|
enable = (val & 0x00000f80) >> 7;
|
||||||
|
flag = (val & 0x0000007c) >> 2;
|
||||||
|
rounding_mode = val & 3;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CompConds {
|
enum CompConds {
|
||||||
@@ -70,92 +81,133 @@ struct Cop1 {
|
|||||||
friend struct Interpreter;
|
friend struct Interpreter;
|
||||||
friend struct JIT;
|
friend struct JIT;
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
FORCE_INLINE void SetReg(Cop0& cop0, u8 index, T value) {
|
FORCE_INLINE T GetFGR_FR(Cop0& cop0, u8 r) {
|
||||||
if constexpr(sizeof(T) == 4) {
|
if constexpr (std::is_same_v<T, u32> || std::is_same_v<T, s32>) {
|
||||||
if (cop0.status.fr) {
|
if (cop0.status.fr) {
|
||||||
fgr[index].lo = value;
|
return fgr[r].lo;
|
||||||
} else {
|
} else {
|
||||||
if (index & 1) {
|
if (r & 1) {
|
||||||
fgr[index & ~1].hi = value;
|
return fgr[r & ~1].hi;
|
||||||
} else {
|
} else {
|
||||||
fgr[index].lo = value;
|
return fgr[r].lo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr(sizeof(T) == 8) {
|
} else if constexpr (std::is_same_v<T, u64> || std::is_same_v<T, s64>) {
|
||||||
if(!cop0.status.fr) {
|
if (!cop0.status.fr) {
|
||||||
index &= ~1;
|
// When this bit is not set, accessing odd registers is not allowed.
|
||||||
|
r &= ~1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fgr[index].raw = value;
|
return fgr[r].raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
FORCE_INLINE void SetFGR_FR(Cop0& cop0, u8 r, T value) {
|
||||||
|
if constexpr (std::is_same_v<T, u32> || std::is_same_v<T, s32>) {
|
||||||
|
if (cop0.status.fr) {
|
||||||
|
fgr[r].lo = value;
|
||||||
|
} else {
|
||||||
|
if (r & 1) {
|
||||||
|
fgr[r & ~1].hi = value;
|
||||||
|
} else {
|
||||||
|
fgr[r].lo = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if constexpr (std::is_same_v<T, u64> || std::is_same_v<T, s64>) {
|
||||||
|
if (!cop0.status.fr) {
|
||||||
|
// When this bit is not set, accessing odd registers is not allowed.
|
||||||
|
r &= ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fgr[r].raw = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
FORCE_INLINE void SetFGR(u8 r, T value) {
|
||||||
|
fgr[r].raw = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
FORCE_INLINE u64 GetFGR(u8 r) {
|
||||||
|
if constexpr (std::is_same_v<T, u32> || std::is_same_v<T, s32>) {
|
||||||
|
return fgr[r].lo;
|
||||||
|
} else if constexpr (std::is_same_v<T, u64> || std::is_same_v<T, s64>) {
|
||||||
|
return fgr[r].raw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE T GetReg(Cop0& cop0, u8 index) {
|
FORCE_INLINE T GetFGR_FS(Cop0& cop0, u8 fs) {
|
||||||
if constexpr(sizeof(T) == 4) {
|
if constexpr (std::is_same_v<T, u32> || std::is_same_v<T, s32>) {
|
||||||
if(cop0.status.fr) {
|
if (!cop0.status.fr) {
|
||||||
return fgr[index].lo;
|
fs &= ~1;
|
||||||
} else {
|
|
||||||
if (index & 1) {
|
|
||||||
return fgr[index & ~1].hi;
|
|
||||||
} else {
|
|
||||||
return fgr[index].lo;
|
|
||||||
}
|
}
|
||||||
|
return fgr[fs].lo;
|
||||||
|
} else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, double>) {
|
||||||
|
if (!cop0.status.fr) {
|
||||||
|
fs &= ~1;
|
||||||
}
|
}
|
||||||
} else if constexpr(sizeof(T) == 8) {
|
return GetFGR_Raw<T>(fs);
|
||||||
if(!cop0.status.fr) {
|
|
||||||
index &= ~1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fgr[index].raw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE void SetCop1Reg(Cop0& cop0, u8 index, T value) {
|
FORCE_INLINE T GetFGR_Raw(u8 r) {
|
||||||
if constexpr (sizeof(T) == 4) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
u32 raw;
|
static_assert(sizeof(float) == sizeof(u32), "float and u32 need to both be 32 bits for this to work.");
|
||||||
memcpy(&raw, &value, sizeof(T));
|
auto rawvalue = GetFGR<u32>(r);
|
||||||
SetReg<u32>(cop0, index, raw);
|
float floatvalue;
|
||||||
} else if constexpr (sizeof(T) == 8) {
|
memcpy(&floatvalue, &rawvalue, sizeof(float));
|
||||||
u64 raw;
|
return floatvalue;
|
||||||
memcpy(&raw, &value, sizeof(T));
|
} else if constexpr (std::is_same_v<T, double>) {
|
||||||
SetReg<u64>(cop0, index, raw);
|
static_assert(sizeof(double) == sizeof(u64), "double and u64 need to both be 64 bits for this to work.");
|
||||||
|
double doublevalue;
|
||||||
|
auto rawvalue = GetFGR<u64>(r);
|
||||||
|
memcpy(&doublevalue, &rawvalue, sizeof(double));
|
||||||
|
return doublevalue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE T GetCop1Reg(Cop0& cop0, u8 index) {
|
FORCE_INLINE void SetFGR_Raw(u8 r, T val) {
|
||||||
T value;
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
if constexpr (sizeof(T) == 4) {
|
static_assert(sizeof(float) == sizeof(u32), "float and u32 need to both be 32 bits for this to work.");
|
||||||
u32 raw = GetReg<u32>(cop0, index);
|
|
||||||
memcpy(&value, &raw, sizeof(T));
|
u32 rawvalue;
|
||||||
} else if constexpr (sizeof(T) == 8) {
|
memcpy(&rawvalue, &val, sizeof(float));
|
||||||
u64 raw = GetReg<u64>(cop0, index);
|
SetFGR<u32>(r, rawvalue);
|
||||||
memcpy(&value, &raw, sizeof(T));
|
} else if constexpr (std::is_same_v<T, double>) {
|
||||||
|
static_assert(sizeof(double) == sizeof(u64), "double and u64 need to both be 64 bits for this to work.");
|
||||||
|
|
||||||
|
u64 rawvalue;
|
||||||
|
memcpy(&rawvalue, &val, sizeof(double));
|
||||||
|
SetFGR<u64>(r, rawvalue);
|
||||||
}
|
}
|
||||||
return value;
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE T GetFGR_FT(u8 ft) {
|
||||||
|
return GetFGR_Raw<T>(ft);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void decodeInterp(Interpreter&, u32);
|
void decodeInterp(Interpreter&, u32);
|
||||||
void decodeJIT(JIT&, u32);
|
void decodeJIT(JIT&, u32);
|
||||||
void absd(Registers&, u32 instr);
|
void absd(Registers&, u32 instr);
|
||||||
void abss(Registers&, u32 instr);
|
void abss(Registers&, u32 instr);
|
||||||
void absw(Registers&, u32 instr);
|
|
||||||
void absl(Registers&, u32 instr);
|
|
||||||
void adds(Registers&, u32 instr);
|
void adds(Registers&, u32 instr);
|
||||||
void addd(Registers&, u32 instr);
|
void addd(Registers&, u32 instr);
|
||||||
void subs(Registers&, u32 instr);
|
void subs(Registers&, u32 instr);
|
||||||
void subd(Registers&, u32 instr);
|
void subd(Registers&, u32 instr);
|
||||||
void subw(Registers&, u32 instr);
|
|
||||||
void subl(Registers&, u32 instr);
|
|
||||||
void ceills(Registers&, u32 instr);
|
void ceills(Registers&, u32 instr);
|
||||||
void ceilws(Registers&, u32 instr);
|
void ceilws(Registers&, u32 instr);
|
||||||
void ceilld(Registers&, u32 instr);
|
void ceilld(Registers&, u32 instr);
|
||||||
void ceilwd(Registers&, u32 instr);
|
void ceilwd(Registers&, u32 instr);
|
||||||
void cfc1(Registers&, u32 instr) const;
|
void cfc1(Registers&, u32 instr) const;
|
||||||
void ctc1(Registers&, u32 instr);
|
void ctc1(Registers&, u32 instr);
|
||||||
|
void unimplemented(Registers&);
|
||||||
void roundls(Registers&, u32 instr);
|
void roundls(Registers&, u32 instr);
|
||||||
void roundld(Registers&, u32 instr);
|
void roundld(Registers&, u32 instr);
|
||||||
void roundws(Registers&, u32 instr);
|
void roundws(Registers&, u32 instr);
|
||||||
@@ -180,12 +232,8 @@ private:
|
|||||||
void divd(Registers&, u32 instr);
|
void divd(Registers&, u32 instr);
|
||||||
void muls(Registers&, u32 instr);
|
void muls(Registers&, u32 instr);
|
||||||
void muld(Registers&, u32 instr);
|
void muld(Registers&, u32 instr);
|
||||||
void mulw(Registers&, u32 instr);
|
|
||||||
void mull(Registers&, u32 instr);
|
|
||||||
void movs(Registers&, u32 instr);
|
void movs(Registers&, u32 instr);
|
||||||
void movd(Registers&, u32 instr);
|
void movd(Registers&, u32 instr);
|
||||||
void movw(Registers&, u32 instr);
|
|
||||||
void movl(Registers&, u32 instr);
|
|
||||||
void negs(Registers&, u32 instr);
|
void negs(Registers&, u32 instr);
|
||||||
void negd(Registers&, u32 instr);
|
void negd(Registers&, u32 instr);
|
||||||
void sqrts(Registers&, u32 instr);
|
void sqrts(Registers&, u32 instr);
|
||||||
|
|||||||
@@ -7,6 +7,21 @@
|
|||||||
#include <cfenv>
|
#include <cfenv>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
FORCE_INLINE bool FireFPUException(Registers& regs) {
|
||||||
|
FCR31& fcr31 = regs.cop1.fcr31;
|
||||||
|
if(fcr31.cause & ((1 << 5) | fcr31.enable)) {
|
||||||
|
FireException(regs, ExceptionCode::FloatingPointError, 0, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CheckFPUException() do { if(FireFPUException(regs)) { return; } } while(0)
|
||||||
|
#define CheckFPUUsable_PreserveCause() do { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } } while(0)
|
||||||
|
#define CheckFPUUsable() do { CheckFPUUsable_PreserveCause(); regs.cop1.fcr31.cause = 0; } while(0)
|
||||||
|
#define CheckRound(a, b) do { if ((a) != (b)) { fcr31.cause_inexact_operation = true; if(!fcr31.enable_inexact_operation) { fcr31.flag_inexact_operation = true; } } CheckFPUException(); } while(0);
|
||||||
|
|
||||||
FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) {
|
FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) {
|
||||||
int og = fegetround();
|
int og = fegetround();
|
||||||
switch(fcr31.rounding_mode) {
|
switch(fcr31.rounding_mode) {
|
||||||
@@ -19,85 +34,265 @@ FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) {
|
|||||||
return og;
|
return og;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CheckCVTArg(f) do { SetCauseByArgCVT(regs, f); CheckFPUException(); } while(0)
|
||||||
|
#define CheckArg(f) do { SetCauseByArg(regs, f); CheckFPUException(); } while(0)
|
||||||
|
#define PUSHROUNDING int orig_round = PushRoundingMode(regs.cop1.fcr31)
|
||||||
|
#define POPROUNDING fesetround(orig_round)
|
||||||
|
#define OP_CheckExcept(op) do { PUSHROUNDING; feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0)
|
||||||
|
#define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0)
|
||||||
|
|
||||||
|
#define OP(T, op) do { \
|
||||||
|
CheckFPUUsable(); \
|
||||||
|
auto fs = GetFGR_FS<T>(regs.cop0, FS(instr)); \
|
||||||
|
auto ft = GetFGR_FT<T>(FT(instr)); \
|
||||||
|
CheckArg(fs); \
|
||||||
|
CheckArg(ft); \
|
||||||
|
T result; \
|
||||||
|
OP_CheckExcept({result = (op);}); \
|
||||||
|
SetFGR_Raw<T>(FD(instr), result); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE void SetCauseByArgCVT(Registers& regs, T f) {
|
||||||
|
if constexpr(sizeof(T) == 4) {
|
||||||
|
switch (std::fpclassify(f)) {
|
||||||
|
case FP_NAN:
|
||||||
|
case FP_INFINITE:
|
||||||
|
case FP_SUBNORMAL:
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_NORMAL:
|
||||||
|
// Check overflow
|
||||||
|
if (f >= 2147483648.0 || f < -2147483648.0) {
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_ZERO:
|
||||||
|
break; // Fine
|
||||||
|
}
|
||||||
|
} else if constexpr(sizeof(T) == 8) {
|
||||||
|
switch (std::fpclassify(f)) {
|
||||||
|
case FP_NAN:
|
||||||
|
case FP_INFINITE:
|
||||||
|
case FP_SUBNORMAL:
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_NORMAL:
|
||||||
|
// Check overflow
|
||||||
|
if (f >= 9007199254740992.000000 || f <= -9007199254740992.000000) {
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FP_ZERO:
|
||||||
|
break; // Fine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) {
|
||||||
|
if (raised == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raised & FE_UNDERFLOW) {
|
||||||
|
if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) {
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
regs.cop1.fcr31.cause_underflow = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_underflow) {
|
||||||
|
regs.cop1.fcr31.flag_underflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raised & FE_INEXACT) {
|
||||||
|
regs.cop1.fcr31.cause_inexact_operation = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_inexact_operation) {
|
||||||
|
regs.cop1.fcr31.flag_inexact_operation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raised & FE_DIVBYZERO) {
|
||||||
|
regs.cop1.fcr31.cause_division_by_zero = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_division_by_zero) {
|
||||||
|
regs.cop1.fcr31.flag_division_by_zero = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raised & FE_OVERFLOW) {
|
||||||
|
regs.cop1.fcr31.cause_overflow = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_overflow) {
|
||||||
|
regs.cop1.fcr31.flag_overflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raised & FE_INVALID) {
|
||||||
|
regs.cop1.fcr31.cause_invalid_operation = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_invalid_operation) {
|
||||||
|
regs.cop1.fcr31.flag_invalid_operation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE void SetFPUCauseCVTRaised(Registers& regs, int raised) {
|
||||||
|
if(raised & FE_INVALID) {
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFPUCauseRaised(regs, raised);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE void SetCauseByArg(Registers& regs, T f) {
|
||||||
|
int c = std::fpclassify(f);
|
||||||
|
switch(c) {
|
||||||
|
case FP_NAN:
|
||||||
|
if(isqnan(f)) {
|
||||||
|
regs.cop1.fcr31.cause_invalid_operation = true;
|
||||||
|
if(!regs.cop1.fcr31.enable_invalid_operation) {
|
||||||
|
regs.cop1.fcr31.flag_invalid_operation = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_SUBNORMAL:
|
||||||
|
regs.cop1.fcr31.cause_unimplemented_operation = true;
|
||||||
|
break;
|
||||||
|
case FP_INFINITE:
|
||||||
|
case FP_ZERO:
|
||||||
|
case FP_NORMAL:
|
||||||
|
break; // No-op, these are fine.
|
||||||
|
default:
|
||||||
|
Util::panic("Unknown floating point classification: {}", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define PUSHROUNDINGMODE int og = PushRoundingMode(fcr31)
|
#define PUSHROUNDINGMODE int og = PushRoundingMode(fcr31)
|
||||||
#define POPROUNDINGMODE fesetround(og)
|
#define POPROUNDINGMODE fesetround(og)
|
||||||
|
|
||||||
|
#define any_unordered(fs, ft) (std::isnan(fs) || std::isnan(ft))
|
||||||
|
|
||||||
|
#define F_TO_U32(f) (*((u32*)(&(f))))
|
||||||
|
#define D_TO_U64(d) (*((u64*)(&(d))))
|
||||||
|
#define U64_TO_D(d) (*((double*)(&(d))))
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE bool isnan(T f) {
|
||||||
|
if constexpr(std::is_same<T, float>::value) {
|
||||||
|
u32 v = F_TO_U32(f);
|
||||||
|
return ((v & 0x7F800000) == 0x7F800000) && ((v & 0x7FFFFF) != 0);
|
||||||
|
} else if constexpr(std::is_same<T, double>::value) {
|
||||||
|
u64 v = D_TO_U64(f);
|
||||||
|
return ((v & 0x7FF0000000000000) == 0x7FF0000000000000) && ((v & 0xFFFFFFFFFFFFF) != 0);
|
||||||
|
} else {
|
||||||
|
Util::panic("Invalid float type in isnan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FORCE_INLINE bool isqnan(T f) {
|
||||||
|
if constexpr(std::is_same<T, float>::value) {
|
||||||
|
u32 v = F_TO_U32(f);
|
||||||
|
return (v & 0x7FC00000) == 0x7FC00000;
|
||||||
|
} else if constexpr(std::is_same<T, double>::value) {
|
||||||
|
u64 v = D_TO_U64(f);
|
||||||
|
return (v & 0x7FF8000000000000) == 0x7FF8000000000000;
|
||||||
|
} else {
|
||||||
|
Util::panic("Invalid float type in isqnan");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define checknanregs(fs, ft) do { \
|
#define checknanregs(fs, ft) do { \
|
||||||
if(std::isnan(fs) || std::isnan(ft)) { \
|
if(isnan(fs) || isnan(ft)) { \
|
||||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
|
||||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
if(!regs.cop1.fcr31.enable_invalid_operation) { \
|
||||||
return; \
|
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||||
|
} \
|
||||||
|
CheckFPUException(); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define checkqnanregs(fs, ft) do { \
|
||||||
|
if(isqnan(fs) || isqnan(ft)) { \
|
||||||
|
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||||
|
if(!regs.cop1.fcr31.enable_invalid_operation) { \
|
||||||
|
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||||
|
} \
|
||||||
|
CheckFPUException(); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
void Cop1::absd(Registers& regs, u32 instr) {
|
void Cop1::absd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, std::abs(fs));
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::abss(Registers& regs, u32 instr) {
|
void Cop1::abss(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, std::abs(fs));
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::absw(Registers& regs, u32 instr) {
|
|
||||||
s32 fs = GetReg<s32>(regs.cop0, FS(instr));
|
|
||||||
SetReg<u32>(regs.cop0, FD(instr), std::abs(fs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::absl(Registers& regs, u32 instr) {
|
|
||||||
s64 fs = GetReg<s64>(regs.cop0, FS(instr));
|
|
||||||
SetReg(regs.cop0, FD(instr), std::abs(fs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::adds(Registers& regs, u32 instr) {
|
void Cop1::adds(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, fs + ft);
|
||||||
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
|
||||||
checknanregs(fs, ft);
|
|
||||||
float result = fs + ft;
|
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::addd(Registers& regs, u32 instr) {
|
void Cop1::addd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, fs + ft);
|
||||||
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
|
||||||
checknanregs(fs, ft);
|
|
||||||
double result = fs + ft;
|
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceills(Registers& regs, u32 instr) {
|
void Cop1::ceills(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
s64 result = std::ceil(fs);
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::ceil(fs); });
|
||||||
|
CheckRound(result, fs);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilws(Registers& regs, u32 instr) {
|
void Cop1::ceilws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
s32 result = std::ceil(fs);
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::ceil(fs); });
|
||||||
|
CheckRound(result, fs);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilld(Registers& regs, u32 instr) {
|
void Cop1::ceilld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
s64 result = std::ceil(fs);
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::ceil(fs); });
|
||||||
|
CheckRound(result, fs);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilwd(Registers& regs, u32 instr) {
|
void Cop1::ceilwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
s32 result = std::ceil(fs);
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::ceil(fs); });
|
||||||
|
CheckRound(result, fs);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cfc1(Registers& regs, u32 instr) const {
|
void Cop1::cfc1(Registers& regs, u32 instr) const {
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
u8 fd = RD(instr);
|
u8 fd = RD(instr);
|
||||||
s32 val = 0;
|
s32 val = 0;
|
||||||
switch(fd) {
|
switch(fd) {
|
||||||
case 0: val = fcr0; break;
|
case 0: val = fcr0; break;
|
||||||
case 31:
|
case 31:
|
||||||
val = fcr31.raw;
|
val = fcr31.read();
|
||||||
break;
|
break;
|
||||||
default: Util::panic("Undefined CFC1 with rd != 0 or 31");
|
default: Util::panic("Undefined CFC1 with rd != 0 or 31");
|
||||||
}
|
}
|
||||||
@@ -105,349 +300,327 @@ void Cop1::cfc1(Registers& regs, u32 instr) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ctc1(Registers& regs, u32 instr) {
|
void Cop1::ctc1(Registers& regs, u32 instr) {
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
u8 fs = RD(instr);
|
u8 fs = RD(instr);
|
||||||
u32 val = regs.gpr[RT(instr)];
|
u32 val = regs.gpr[RT(instr)];
|
||||||
switch(fs) {
|
switch(fs) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case 31: {
|
case 31: {
|
||||||
val &= 0x183ffff;
|
fcr31.write(val);
|
||||||
fcr31.raw = val;
|
FireFPUException(regs);
|
||||||
} break;
|
} break;
|
||||||
default: Util::panic("Undefined CTC1 with rd != 0 or 31");
|
default: Util::panic("Undefined CTC1 with rd != 0 or 31");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtds(Registers& regs, u32 instr) {
|
void Cop1::cvtds(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<double>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<float>(
|
double result;
|
||||||
regs.cop0,
|
CVT_OP_CheckExcept({ result = double(fs); });
|
||||||
FS(instr)
|
SetFGR_Raw(FD(instr), result);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<float>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<double>(
|
float result;
|
||||||
regs.cop0,
|
CVT_OP_CheckExcept({ result = float(fs); });
|
||||||
FS(instr)
|
SetFGR_Raw(FD(instr), result);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtwd(Registers& regs, u32 instr) {
|
void Cop1::cvtwd(Registers& regs, u32 instr) {
|
||||||
SetReg<u32>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<double>(
|
s32 result;
|
||||||
regs.cop0,
|
CVT_OP_CheckExcept({ result = s32(fs); });
|
||||||
FS(instr)
|
SetFGR(FD(instr), result);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtws(Registers& regs, u32 instr) {
|
void Cop1::cvtws(Registers& regs, u32 instr) {
|
||||||
SetReg<u32>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<float>(
|
s32 result;
|
||||||
regs.cop0,
|
CVT_OP_CheckExcept({ result = s32(fs); });
|
||||||
FS(instr)
|
SetFGR(FD(instr), result);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtls(Registers& regs, u32 instr) {
|
void Cop1::cvtls(Registers& regs, u32 instr) {
|
||||||
SetReg<u64>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<float>(
|
s64 result;
|
||||||
regs.cop0,
|
CVT_OP_CheckExcept({ result = s64(fs); });
|
||||||
FS(instr)
|
SetFGR(FD(instr), result);
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<float>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FR<s64>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
if (fs >= (s64)0x0080000000000000 || fs < s64(0xff80'0000'0000'0000)) {
|
||||||
(s64)GetReg<u64>(
|
fcr31.cause_unimplemented_operation = true;
|
||||||
regs.cop0,
|
CheckFPUException();
|
||||||
FS(instr)
|
}
|
||||||
)
|
float result;
|
||||||
);
|
OP_CheckExcept({ result = float(fs); });
|
||||||
|
SetFGR_Raw(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<double>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<s32>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
double result;
|
||||||
(s32)GetReg<u32>(
|
OP_CheckExcept({ result = double(fs); });
|
||||||
regs.cop0,
|
SetFGR_Raw(FD(instr), result);
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<float>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<s32>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
float result;
|
||||||
(s32)GetReg<u32>(
|
OP_CheckExcept({ result = float(fs); });
|
||||||
regs.cop0,
|
SetFGR_Raw(FD(instr), result);
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<double>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FR<s64>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
if (fs >= (s64)0x0080000000000000 || fs < s64(0xff80'0000'0000'0000)) {
|
||||||
(s64)GetReg<u64>(
|
fcr31.cause_unimplemented_operation = true;
|
||||||
regs.cop0,
|
CheckFPUException();
|
||||||
FS(instr)
|
}
|
||||||
)
|
double result;
|
||||||
);
|
OP_CheckExcept({ result = double(fs); });
|
||||||
|
SetFGR_Raw(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtld(Registers& regs, u32 instr) {
|
void Cop1::cvtld(Registers& regs, u32 instr) {
|
||||||
SetReg<u64>(
|
CheckFPUUsable();
|
||||||
regs.cop0,
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
CheckCVTArg(fs);
|
||||||
GetCop1Reg<double>(
|
s64 result;
|
||||||
regs.cop0,
|
PUSHROUNDING;
|
||||||
FS(instr)
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
||||||
)
|
POPROUNDING;
|
||||||
);
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
|
inline bool CalculateCondition(T fs, T ft, CompConds cond) {
|
||||||
switch(cond) {
|
switch(cond) {
|
||||||
case F: return false;
|
case F: case SF: return false;
|
||||||
case UN: return std::isnan(fs) || std::isnan(ft);
|
case UN: case NGLE: return any_unordered(fs, ft);
|
||||||
case EQ: return fs == ft;
|
case EQ: case SEQ: return fs == ft;
|
||||||
case UEQ: return (std::isnan(fs) || std::isnan(ft)) || (fs == ft);
|
case UEQ: case NGL: return fs == ft || any_unordered(fs, ft);
|
||||||
case OLT: return (!std::isnan(fs) && !std::isnan(ft)) && (fs < ft);
|
case OLT: case LT: return fs < ft;
|
||||||
case ULT: return (std::isnan(fs) || std::isnan(ft)) || (fs < ft);
|
case ULT: case NGE: return fs < ft || any_unordered(fs, ft);
|
||||||
case OLE: return (!std::isnan(fs) && !std::isnan(ft)) && (fs <= ft);
|
case OLE: case LE: return fs <= ft;
|
||||||
case ULE: return (std::isnan(fs) || std::isnan(ft)) || (fs <= ft);
|
case ULE: case NGT: return fs <= ft || any_unordered(fs, ft);
|
||||||
default:
|
|
||||||
if(std::isnan(fs) || std::isnan(ft)) {
|
|
||||||
regs.cop1.fcr31.flag_invalid_operation = true;
|
|
||||||
regs.cop1.fcr31.cause_invalid_operation = true;
|
|
||||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return CalculateCondition(regs, fs, ft, static_cast<CompConds>(cond - 8));
|
template <typename T>
|
||||||
|
inline void CheckInvalidRegs(Registers& regs, T fs, T ft, CompConds cond) {
|
||||||
|
switch(cond) {
|
||||||
|
case F ... ULE: checkqnanregs(fs, ft); break;
|
||||||
|
case SF ... NGT: checknanregs(fs, ft); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Cop1::ccond(Registers& regs, u32 instr, CompConds cond) {
|
void Cop1::ccond(Registers& regs, u32 instr, CompConds cond) {
|
||||||
T fs = GetCop1Reg<T>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
T ft = GetCop1Reg<T>(regs.cop0, FT(instr));
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
||||||
|
T ft = GetFGR_FT<T>(FT(instr));
|
||||||
fcr31.compare = CalculateCondition(regs, fs, ft, cond);
|
CheckInvalidRegs(regs, fs, ft, cond);
|
||||||
|
fcr31.compare = CalculateCondition(fs, ft, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
template void Cop1::ccond<float>(Registers& regs, u32 instr, CompConds cond);
|
template void Cop1::ccond<float>(Registers& regs, u32 instr, CompConds cond);
|
||||||
template void Cop1::ccond<double>(Registers& regs, u32 instr, CompConds cond);
|
template void Cop1::ccond<double>(Registers& regs, u32 instr, CompConds cond);
|
||||||
|
|
||||||
void Cop1::divs(Registers ®s, u32 instr) {
|
void Cop1::divs(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, fs / ft);
|
||||||
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::divd(Registers ®s, u32 instr) {
|
void Cop1::divd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, fs / ft);
|
||||||
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::muls(Registers ®s, u32 instr) {
|
void Cop1::muls(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, fs * ft);
|
||||||
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::muld(Registers& regs, u32 instr) {
|
void Cop1::muld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, fs * ft);
|
||||||
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::mulw(Registers ®s, u32 instr) {
|
|
||||||
u32 fs = GetReg<u32>(regs.cop0, FS(instr));
|
|
||||||
u32 ft = GetReg<u32>(regs.cop0, FT(instr));
|
|
||||||
SetReg<u32>(regs.cop0, FD(instr), fs * ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::mull(Registers ®s, u32 instr) {
|
|
||||||
u64 fs = GetReg<u64>(regs.cop0, FS(instr));
|
|
||||||
u64 ft = GetReg<u64>(regs.cop0, FT(instr));
|
|
||||||
SetReg<u64>(regs.cop0, FD(instr), fs * ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::subs(Registers ®s, u32 instr) {
|
void Cop1::subs(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, fs - ft);
|
||||||
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::subd(Registers ®s, u32 instr) {
|
void Cop1::subd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, fs - ft);
|
||||||
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::subw(Registers ®s, u32 instr) {
|
|
||||||
u32 fs = GetReg<u32>(regs.cop0, FS(instr));
|
|
||||||
u32 ft = GetReg<u32>(regs.cop0, FT(instr));
|
|
||||||
SetReg<u32>(regs.cop0, FD(instr), fs - ft);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::subl(Registers ®s, u32 instr) {
|
|
||||||
u64 fs = GetReg<u64>(regs.cop0, FS(instr));
|
|
||||||
u64 ft = GetReg<u64>(regs.cop0, FT(instr));
|
|
||||||
SetReg<u64>(regs.cop0, FD(instr), fs - ft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::movs(Registers& regs, u32 instr) {
|
void Cop1::movs(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<float>(
|
CheckFPUUsable_PreserveCause();
|
||||||
regs.cop0,
|
auto val = GetFGR_FR<u64>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
SetFGR(FD(instr), val);
|
||||||
GetCop1Reg<float>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::movd(Registers& regs, u32 instr) {
|
void Cop1::movd(Registers& regs, u32 instr) {
|
||||||
SetCop1Reg<double>(
|
CheckFPUUsable_PreserveCause();
|
||||||
regs.cop0,
|
auto val = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
FD(instr),
|
SetFGR_Raw(FD(instr), val);
|
||||||
GetCop1Reg<double>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::movw(Registers& regs, u32 instr) {
|
|
||||||
SetReg<u32>(
|
|
||||||
regs.cop0,
|
|
||||||
FD(instr),
|
|
||||||
GetReg<u32>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::movl(Registers& regs, u32 instr) {
|
|
||||||
SetReg<u64>(
|
|
||||||
regs.cop0,
|
|
||||||
FD(instr),
|
|
||||||
GetReg<u64>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::negs(Registers ®s, u32 instr) {
|
void Cop1::negs(Registers ®s, u32 instr) {
|
||||||
SetCop1Reg<float>(
|
OP(float, -fs);
|
||||||
regs.cop0,
|
|
||||||
FD(instr),
|
|
||||||
-GetCop1Reg<float>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::negd(Registers ®s, u32 instr) {
|
void Cop1::negd(Registers ®s, u32 instr) {
|
||||||
SetCop1Reg<double>(
|
OP(double, -ft);
|
||||||
regs.cop0,
|
|
||||||
FD(instr),
|
|
||||||
-GetCop1Reg<double>(
|
|
||||||
regs.cop0,
|
|
||||||
FS(instr)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sqrts(Registers ®s, u32 instr) {
|
void Cop1::sqrts(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
OP(float, std::sqrt(fs));
|
||||||
SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sqrtd(Registers ®s, u32 instr) {
|
void Cop1::sqrtd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
OP(double, std::sqrt(fs));
|
||||||
SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundls(Registers& regs, u32 instr) {
|
void Cop1::roundls(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
PUSHROUNDINGMODE;
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
CheckCVTArg(fs);
|
||||||
POPROUNDINGMODE;
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundld(Registers& regs, u32 instr) {
|
void Cop1::roundld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
PUSHROUNDINGMODE;
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs));
|
CheckCVTArg(fs);
|
||||||
POPROUNDINGMODE;
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundws(Registers& regs, u32 instr) {
|
void Cop1::roundws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
PUSHROUNDINGMODE;
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
CheckCVTArg(fs);
|
||||||
POPROUNDINGMODE;
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundwd(Registers& regs, u32 instr) {
|
void Cop1::roundwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
PUSHROUNDINGMODE;
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
CheckCVTArg(fs);
|
||||||
POPROUNDINGMODE;
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorls(Registers& regs, u32 instr) {
|
void Cop1::floorls(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::floor(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorld(Registers& regs, u32 instr) {
|
void Cop1::floorld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::floor(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorws(Registers& regs, u32 instr) {
|
void Cop1::floorws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::floor(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorwd(Registers& regs, u32 instr) {
|
void Cop1::floorwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
CheckFPUUsable();
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::floor(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cop1::truncws(Registers& regs, u32 instr) {
|
||||||
|
CheckFPUUsable();
|
||||||
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::trunc(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cop1::truncwd(Registers& regs, u32 instr) {
|
||||||
|
CheckFPUUsable();
|
||||||
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s32 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::trunc(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cop1::truncls(Registers& regs, u32 instr) {
|
||||||
|
CheckFPUUsable();
|
||||||
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::trunc(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cop1::truncld(Registers& regs, u32 instr) {
|
||||||
|
CheckFPUUsable();
|
||||||
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
||||||
|
CheckCVTArg(fs);
|
||||||
|
s64 result;
|
||||||
|
CVT_OP_CheckExcept({ result = std::trunc(fs); });
|
||||||
|
CheckRound(fs, result);
|
||||||
|
SetFGR(FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void Cop1::lwc1(T &cpu, Mem &mem, u32 instr) {
|
void Cop1::lwc1(T &cpu, Mem &mem, u32 instr) {
|
||||||
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
||||||
|
Registers& regs = cpu.regs;
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
lwc1Interp(cpu.regs, mem, instr);
|
lwc1Interp(cpu.regs, mem, instr);
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
||||||
lwc1JIT(cpu, mem, instr);
|
lwc1JIT(cpu, mem, instr);
|
||||||
@@ -462,6 +635,8 @@ template void Cop1::lwc1<JIT>(JIT&, Mem&, u32);
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Cop1::swc1(T &cpu, Mem &mem, u32 instr) {
|
void Cop1::swc1(T &cpu, Mem &mem, u32 instr) {
|
||||||
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
||||||
|
Registers& regs = cpu.regs;
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
swc1Interp(cpu.regs, mem, instr);
|
swc1Interp(cpu.regs, mem, instr);
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
||||||
swc1JIT(cpu, mem, instr);
|
swc1JIT(cpu, mem, instr);
|
||||||
@@ -476,6 +651,8 @@ template void Cop1::swc1<JIT>(JIT&, Mem&, u32);
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Cop1::ldc1(T &cpu, Mem &mem, u32 instr) {
|
void Cop1::ldc1(T &cpu, Mem &mem, u32 instr) {
|
||||||
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
||||||
|
Registers& regs = cpu.regs;
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
ldc1Interp(cpu.regs, mem, instr);
|
ldc1Interp(cpu.regs, mem, instr);
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
||||||
ldc1JIT(cpu, mem, instr);
|
ldc1JIT(cpu, mem, instr);
|
||||||
@@ -490,6 +667,8 @@ template void Cop1::ldc1<JIT>(JIT&, Mem&, u32);
|
|||||||
template<class T>
|
template<class T>
|
||||||
void Cop1::sdc1(T &cpu, Mem &mem, u32 instr) {
|
void Cop1::sdc1(T &cpu, Mem &mem, u32 instr) {
|
||||||
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
if constexpr(std::is_same_v<decltype(cpu), Interpreter&>) {
|
||||||
|
Registers& regs = cpu.regs;
|
||||||
|
CheckFPUUsable_PreserveCause();
|
||||||
sdc1Interp(cpu.regs, mem, instr);
|
sdc1Interp(cpu.regs, mem, instr);
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
|
||||||
sdc1JIT(cpu, mem, instr);
|
sdc1JIT(cpu, mem, instr);
|
||||||
@@ -515,7 +694,7 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
u32 data = mem.Read32(regs, physical);
|
u32 data = mem.Read32(regs, physical);
|
||||||
SetReg<u32>(regs.cop0, FT(instr), data);
|
SetFGR_FR<u32>(regs.cop0, FT(instr), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,10 +711,16 @@ void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|||||||
HandleTLBException(regs, addr);
|
HandleTLBException(regs, addr);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||||
} else {
|
} else {
|
||||||
mem.Write32(regs, physical, GetReg<u32>(regs.cop0, FT(instr)));
|
mem.Write32(regs, physical, GetFGR_FR<u32>(regs.cop0, FT(instr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cop1::unimplemented(Registers& regs) {
|
||||||
|
CheckFPUUsable();
|
||||||
|
fcr31.cause_unimplemented_operation = true;
|
||||||
|
FireFPUException(regs);
|
||||||
|
}
|
||||||
|
|
||||||
void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
||||||
if(!regs.cop0.status.cu1) {
|
if(!regs.cop0.status.cu1) {
|
||||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||||
@@ -550,7 +735,7 @@ void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
} else {
|
} else {
|
||||||
u64 data = mem.Read64(regs, physical);
|
u64 data = mem.Read64(regs, physical);
|
||||||
SetReg<u64>(regs.cop0, FT(instr), data);
|
SetFGR_FR<u64>(regs.cop0, FT(instr), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,48 +752,28 @@ void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|||||||
HandleTLBException(regs, addr);
|
HandleTLBException(regs, addr);
|
||||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||||
} else {
|
} else {
|
||||||
mem.Write64(regs, physical, GetReg<u64>(regs.cop0, FT(instr)));
|
mem.Write64(regs, physical, GetFGR_FR<u64>(regs.cop0, FT(instr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::truncws(Registers& regs, u32 instr) {
|
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
|
||||||
s32 result = (s32)std::trunc(fs);
|
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::truncwd(Registers& regs, u32 instr) {
|
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
|
||||||
s32 result = (s32)std::trunc(fs);
|
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::truncls(Registers& regs, u32 instr) {
|
|
||||||
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
|
||||||
s64 result = (s64)std::trunc(fs);
|
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::truncld(Registers& regs, u32 instr) {
|
|
||||||
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
|
||||||
s64 result = (s64)std::trunc(fs);
|
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::mfc1(Registers& regs, u32 instr) {
|
void Cop1::mfc1(Registers& regs, u32 instr) {
|
||||||
regs.gpr[RT(instr)] = (s32)GetReg<u32>(regs.cop0, FS(instr));
|
CheckFPUUsable_PreserveCause();
|
||||||
|
regs.gpr[RT(instr)] = (s32)GetFGR_FR<u32>(regs.cop0, FS(instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::dmfc1(Registers& regs, u32 instr) {
|
void Cop1::dmfc1(Registers& regs, u32 instr) {
|
||||||
regs.gpr[RT(instr)] = (s64)GetReg<u64>(regs.cop0, FS(instr));
|
CheckFPUUsable_PreserveCause();
|
||||||
|
regs.gpr[RT(instr)] = (s64)GetFGR_FR<u64>(regs.cop0, FS(instr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::mtc1(Registers& regs, u32 instr) {
|
void Cop1::mtc1(Registers& regs, u32 instr) {
|
||||||
SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
CheckFPUUsable_PreserveCause();
|
||||||
|
SetFGR_FR<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::dmtc1(Registers& regs, u32 instr) {
|
void Cop1::dmtc1(Registers& regs, u32 instr) {
|
||||||
SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
CheckFPUUsable_PreserveCause();
|
||||||
|
SetFGR_FR<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) {
|
|||||||
#define ELEMENT_INDEX(i) (7 - (i))
|
#define ELEMENT_INDEX(i) (7 - (i))
|
||||||
#define BYTE_INDEX(i) (15 - (i))
|
#define BYTE_INDEX(i) (15 - (i))
|
||||||
|
|
||||||
#define unlikely(exp) __builtin_expect(exp, 0)
|
|
||||||
#define likely(exp) __builtin_expect(exp, 1)
|
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
||||||
#define ABI_WINDOWS
|
#define ABI_WINDOWS
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ Settings::Settings(n64::Core& core) {
|
|||||||
settings = json::parse(settingsFile);
|
settings = json::parse(settingsFile);
|
||||||
|
|
||||||
checkjsonentry(oldVolumeL, float, "audio", "volumeL", 0.5);
|
checkjsonentry(oldVolumeL, float, "audio", "volumeL", 0.5);
|
||||||
volumeL = oldVolumeL;
|
|
||||||
checkjsonentry(oldVolumeR, float, "audio", "volumeR", 0.5);
|
checkjsonentry(oldVolumeR, float, "audio", "volumeR", 0.5);
|
||||||
volumeR = oldVolumeR;
|
|
||||||
checkjsonentry(mute, bool, "audio", "mute", false);
|
checkjsonentry(mute, bool, "audio", "mute", false);
|
||||||
|
volumeL = mute ? 0 : oldVolumeL;
|
||||||
|
volumeR = mute ? 0 : oldVolumeR;
|
||||||
checkjsonentry(lockChannels, bool, "audio", "lockChannels", true);
|
checkjsonentry(lockChannels, bool, "audio", "lockChannels", true);
|
||||||
checkjsonentry(jit, bool, "cpu", "enableJIT", false);
|
checkjsonentry(jit, bool, "cpu", "enableJIT", false);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user