More FPU exceptions
This commit is contained in:
@@ -119,6 +119,9 @@
|
|||||||
"6d25b36f":{
|
"6d25b36f":{
|
||||||
"name": "All-Star Baseball 99 (USA)"
|
"name": "All-Star Baseball 99 (USA)"
|
||||||
},
|
},
|
||||||
|
"46239627": {
|
||||||
|
"name": "Animal Forest (Japan)"
|
||||||
|
},
|
||||||
"600bc49e":{
|
"600bc49e":{
|
||||||
"name": "Armorines - Project S.W.A.R.M. (Europe)"
|
"name": "Armorines - Project S.W.A.R.M. (Europe)"
|
||||||
},
|
},
|
||||||
@@ -741,7 +744,7 @@
|
|||||||
"name": "F-Zero X (USA)"
|
"name": "F-Zero X (USA)"
|
||||||
},
|
},
|
||||||
"68fe1cec":{
|
"68fe1cec":{
|
||||||
"name": "F-Zero X (USA) (Beta) (The Legend of Zelda Ocarina of Time Overdump)"
|
"name": "F-Zero X (USA) (Beta) (The Legend of Zelda - Ocarina of Time Overdump)"
|
||||||
},
|
},
|
||||||
"ed750623":{
|
"ed750623":{
|
||||||
"name": "F1 Pole Position 64 (Europe) (En,Fr,De)"
|
"name": "F1 Pole Position 64 (Europe) (En,Fr,De)"
|
||||||
@@ -1266,67 +1269,67 @@
|
|||||||
"name": "Last Legion UX (Japan)"
|
"name": "Last Legion UX (Japan)"
|
||||||
},
|
},
|
||||||
"9ead1608":{
|
"9ead1608":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (Europe) (En,Fr,De,Es)"
|
"name": "The Legend of Zelda - Majora's Mask (Europe) (En,Fr,De,Es)"
|
||||||
},
|
},
|
||||||
"e2e6823d":{
|
"e2e6823d":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1)"
|
"name": "The Legend of Zelda - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1)"
|
||||||
},
|
},
|
||||||
"b428d8a7":{
|
"b428d8a7":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (USA)"
|
"name": "The Legend of Zelda - Majora's Mask (USA)"
|
||||||
},
|
},
|
||||||
"dcc110a0":{
|
"dcc110a0":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (USA) (Demo) (Kiosk)"
|
"name": "The Legend of Zelda - Majora's Mask (USA) (Demo) (Kiosk)"
|
||||||
},
|
},
|
||||||
"04ea55ea":{
|
"04ea55ea":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1) (Debug)"
|
"name": "The Legend of Zelda - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1) (Debug)"
|
||||||
},
|
},
|
||||||
"b008458f":{
|
"b008458f":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (USA) (GameCube)"
|
"name": "The Legend of Zelda - Majora's Mask (USA) (GameCube)"
|
||||||
},
|
},
|
||||||
"12836e19":{
|
"12836e19":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (Europe) (GameCube)"
|
"name": "The Legend of Zelda - Majora's Mask (Europe) (GameCube)"
|
||||||
},
|
},
|
||||||
"a83abf72":{
|
"a83abf72":{
|
||||||
"name": "Legend of Zelda, The - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1) (Wii Virtual Console)"
|
"name": "The Legend of Zelda - Majora's Mask (Europe) (En,Fr,De,Es) (Rev 1) (Wii Virtual Console)"
|
||||||
},
|
},
|
||||||
"946fd0f7":{
|
"946fd0f7":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (Europe) (En,Fr,De)"
|
"name": "The Legend of Zelda - Ocarina of Time (Europe) (En,Fr,De)"
|
||||||
},
|
},
|
||||||
"a108f6e3":{
|
"a108f6e3":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (Europe) (En,Fr,De) (Rev 1)"
|
"name": "The Legend of Zelda - Ocarina of Time (Europe) (En,Fr,De) (Rev 1)"
|
||||||
},
|
},
|
||||||
"cd16c529":{
|
"cd16c529":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (USA)"
|
"name": "The Legend of Zelda - Ocarina of Time (USA)"
|
||||||
},
|
},
|
||||||
"3fd2151e":{
|
"3fd2151e":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (USA) (Rev 1)"
|
"name": "The Legend of Zelda - Ocarina of Time (USA) (Rev 1)"
|
||||||
},
|
},
|
||||||
"32120c23":{
|
"32120c23":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (USA) (Rev 2)"
|
"name": "The Legend of Zelda - Ocarina of Time (USA) (Rev 2)"
|
||||||
},
|
},
|
||||||
"346de3ae":{
|
"346de3ae":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (USA) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time (USA) (GameCube)"
|
||||||
},
|
},
|
||||||
"3fbd519f":{
|
"3fbd519f":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (Europe) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time (Europe) (GameCube)"
|
||||||
},
|
},
|
||||||
"5d1b2996":{
|
"5d1b2996":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (Europe) (Debug) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time (Europe) (Debug) (GameCube)"
|
||||||
},
|
},
|
||||||
"c188acda":{
|
"c188acda":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (Europe) (Beta) (2003-02-13) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time (Europe) (Beta) (2003-02-13) (GameCube)"
|
||||||
},
|
},
|
||||||
"6c348aa8":{
|
"6c348aa8":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time (USA) (Beta)"
|
"name": "The Legend of Zelda - Ocarina of Time (USA) (Beta)"
|
||||||
},
|
},
|
||||||
"a1d34e08":{
|
"a1d34e08":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time - Master Quest (Europe) (Debug) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time - Master Quest (Europe) (Debug) (GameCube)"
|
||||||
},
|
},
|
||||||
"c744c4db":{
|
"c744c4db":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time - Master Quest (USA) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time - Master Quest (USA) (GameCube)"
|
||||||
},
|
},
|
||||||
"832d6449":{
|
"832d6449":{
|
||||||
"name": "Legend of Zelda, The - Ocarina of Time - Master Quest (Europe) (GameCube)"
|
"name": "The Legend of Zelda - Ocarina of Time - Master Quest (Europe) (GameCube)"
|
||||||
},
|
},
|
||||||
"c7d9b21c":{
|
"c7d9b21c":{
|
||||||
"name": "LEGO Racers (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)"
|
"name": "LEGO Racers (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)"
|
||||||
|
|||||||
@@ -27,63 +27,6 @@ inline void CheckCompareInterrupt(MI& mi, Registers& regs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Is64BitAddressing(Cop0& cp0, u64 addr) {
|
|
||||||
u8 region = (addr >> 62) & 3;
|
|
||||||
switch(region) {
|
|
||||||
case 0b00: return cp0.status.ux;
|
|
||||||
case 0b01: return cp0.status.sx;
|
|
||||||
case 0b11: return cp0.status.kx;
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
|
|
||||||
bool old_exl = regs.cop0.status.exl;
|
|
||||||
|
|
||||||
if(!regs.cop0.status.exl) {
|
|
||||||
if(regs.prevDelaySlot) {
|
|
||||||
regs.cop0.cause.branchDelay = true;
|
|
||||||
pc -= 4;
|
|
||||||
} else {
|
|
||||||
regs.cop0.cause.branchDelay = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs.cop0.status.exl = true;
|
|
||||||
regs.cop0.EPC = pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
regs.cop0.cause.copError = cop;
|
|
||||||
regs.cop0.cause.exceptionCode = code;
|
|
||||||
|
|
||||||
s64 exceptionVector = 0;
|
|
||||||
|
|
||||||
if(regs.cop0.status.bev) {
|
|
||||||
util::panic("BEV bit set!\n");
|
|
||||||
} else {
|
|
||||||
switch(code) {
|
|
||||||
case Interrupt: case TLBModification:
|
|
||||||
case AddressErrorLoad: case AddressErrorStore:
|
|
||||||
case InstructionBusError: case DataBusError:
|
|
||||||
case Syscall: case Breakpoint:
|
|
||||||
case ReservedInstruction: case CoprocessorUnusable:
|
|
||||||
case Overflow: case Trap:
|
|
||||||
case FloatingPointError: case Watch:
|
|
||||||
regs.SetPC(s64(s32(0x80000180)));
|
|
||||||
break;
|
|
||||||
case TLBLoad: case TLBStore:
|
|
||||||
if(old_exl || regs.cop0.tlbError == INVALID) {
|
|
||||||
regs.SetPC(s64(s32(0x80000180)));
|
|
||||||
} else if(Is64BitAddressing(regs.cop0, regs.cop0.badVaddr)) {
|
|
||||||
regs.SetPC(s64(s32(0x80000080)));
|
|
||||||
} else {
|
|
||||||
regs.SetPC(s64(s32(0x80000000)));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default: util::panic("Unhandled exception! {}\n", code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void HandleInterrupt(Registers& regs) {
|
inline void HandleInterrupt(Registers& regs) {
|
||||||
if(ShouldServiceInterrupt(regs)) {
|
if(ShouldServiceInterrupt(regs)) {
|
||||||
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc);
|
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc);
|
||||||
|
|||||||
@@ -117,25 +117,4 @@ private:
|
|||||||
void xor_(u32);
|
void xor_(u32);
|
||||||
void xori(u32);
|
void xori(u32);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ExceptionCode : u8 {
|
|
||||||
Interrupt,
|
|
||||||
TLBModification,
|
|
||||||
TLBLoad,
|
|
||||||
TLBStore,
|
|
||||||
AddressErrorLoad,
|
|
||||||
AddressErrorStore,
|
|
||||||
InstructionBusError,
|
|
||||||
DataBusError,
|
|
||||||
Syscall,
|
|
||||||
Breakpoint,
|
|
||||||
ReservedInstruction,
|
|
||||||
CoprocessorUnusable,
|
|
||||||
Overflow,
|
|
||||||
Trap,
|
|
||||||
FloatingPointError = 15,
|
|
||||||
Watch = 23
|
|
||||||
};
|
|
||||||
|
|
||||||
void FireException(Registers& regs_, ExceptionCode code, int cop, s64 pc);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ bool MapVAddr(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr)
|
|||||||
|
|
||||||
switch(vaddr >> 29) {
|
switch(vaddr >> 29) {
|
||||||
case 0 ... 3: case 7:
|
case 0 ... 3: case 7:
|
||||||
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr);
|
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||||
case 4 ... 5: return true;
|
case 4 ... 5: return true;
|
||||||
case 6: util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})\n", vaddr);
|
case 6: util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})\n", vaddr);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ auto RSP::Read(u32 addr) -> u32{
|
|||||||
case 0x04040008:
|
case 0x04040008:
|
||||||
case 0x0404000C: return spDMALen.raw;
|
case 0x0404000C: return spDMALen.raw;
|
||||||
case 0x04040010: return spStatus.raw;
|
case 0x04040010: return spStatus.raw;
|
||||||
|
case 0x04040014: return spStatus.dmaFull;
|
||||||
case 0x04040018: return 0;
|
case 0x04040018: return 0;
|
||||||
case 0x0404001C: return AcquireSemaphore();
|
case 0x0404001C: return AcquireSemaphore();
|
||||||
case 0x04080000:
|
case 0x04080000: return pc & 0xFFC;
|
||||||
return pc & 0xFFC;
|
|
||||||
default: util::panic("Unimplemented SP register read {:08X}\n", addr);
|
default: util::panic("Unimplemented SP register read {:08X}\n", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,8 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) {
|
|||||||
pc = value & 0xFFC;
|
pc = value & 0xFFC;
|
||||||
nextPC = value & 0xFFC;
|
nextPC = value & 0xFFC;
|
||||||
} break;
|
} break;
|
||||||
default: util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value);
|
default:
|
||||||
|
util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,12 @@
|
|||||||
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
|
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
|
||||||
void Cpu::add(u32 instr) {
|
void Cpu::add(u32 instr) {
|
||||||
u32 rs = (s32)regs.gpr[RS(instr)];
|
u32 rs = (s32)regs.gpr[RS(instr)];
|
||||||
u32 rt = (s32)regs.gpr[RT(instr)];
|
u32 rt = (s32)regs.gpr[RT(instr)];
|
||||||
u32 result = rs + rt;
|
u32 result = rs + rt;
|
||||||
if(check_signed_overflow(rs, rt, result)) {
|
if(check_signed_overflow(rs, rt, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = s32(result);
|
regs.gpr[RD(instr)] = s32(result);
|
||||||
}
|
}
|
||||||
@@ -27,13 +26,13 @@ void Cpu::addu(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::addi(u32 instr) {
|
void Cpu::addi(u32 instr) {
|
||||||
u32 rs = (s32)regs.gpr[RS(instr)];
|
u32 rs = regs.gpr[RS(instr)];
|
||||||
u32 imm = s32(s16(instr));
|
u32 imm = s32(s16(instr));
|
||||||
u32 result = rs + imm;
|
u32 result = rs + imm;
|
||||||
if(check_signed_overflow(rs, imm, result)) {
|
if(check_signed_overflow(rs, imm, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = s32(result);
|
regs.gpr[RT(instr)] = s32(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +48,7 @@ void Cpu::dadd(u32 instr) {
|
|||||||
u64 rt = regs.gpr[RT(instr)];
|
u64 rt = regs.gpr[RT(instr)];
|
||||||
u64 result = rt + rs;
|
u64 result = rt + rs;
|
||||||
if(check_signed_overflow(rs, rt, result)) {
|
if(check_signed_overflow(rs, rt, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
@@ -66,9 +65,9 @@ void Cpu::daddi(u32 instr) {
|
|||||||
u64 rs = regs.gpr[RS(instr)];
|
u64 rs = regs.gpr[RS(instr)];
|
||||||
u64 result = imm + rs;
|
u64 result = imm + rs;
|
||||||
if(check_signed_overflow(rs, imm, result)) {
|
if(check_signed_overflow(rs, imm, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +657,7 @@ void Cpu::dsub(u32 instr) {
|
|||||||
s64 rs = regs.gpr[RS(instr)];
|
s64 rs = regs.gpr[RS(instr)];
|
||||||
s64 result = rs - rt;
|
s64 result = rs - rt;
|
||||||
if(check_signed_underflow(rs, rt, result)) {
|
if(check_signed_underflow(rs, rt, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
@@ -676,7 +675,7 @@ void Cpu::sub(u32 instr) {
|
|||||||
s32 rs = regs.gpr[RS(instr)];
|
s32 rs = regs.gpr[RS(instr)];
|
||||||
s32 result = rs - rt;
|
s32 result = rs - rt;
|
||||||
if(check_signed_underflow(rs, rt, result)) {
|
if(check_signed_underflow(rs, rt, result)) {
|
||||||
FireException(regs, Overflow, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.gpr[RD(instr)] = result;
|
regs.gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,6 +232,63 @@ bool ProbeTLB(Registers& regs, TLBAccessType access_type, s64 vaddr, u32& paddr,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Is64BitAddressing(Cop0& cp0, u64 addr) {
|
||||||
|
u8 region = (addr >> 62) & 3;
|
||||||
|
switch(region) {
|
||||||
|
case 0b00: return cp0.status.ux;
|
||||||
|
case 0b01: return cp0.status.sx;
|
||||||
|
case 0b11: return cp0.status.kx;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
|
||||||
|
bool old_exl = regs.cop0.status.exl;
|
||||||
|
|
||||||
|
if(!regs.cop0.status.exl) {
|
||||||
|
if(regs.prevDelaySlot) {
|
||||||
|
regs.cop0.cause.branchDelay = true;
|
||||||
|
pc -= 4;
|
||||||
|
} else {
|
||||||
|
regs.cop0.cause.branchDelay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.cop0.status.exl = true;
|
||||||
|
regs.cop0.EPC = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs.cop0.cause.copError = cop;
|
||||||
|
regs.cop0.cause.exceptionCode = static_cast<u8>(code);
|
||||||
|
|
||||||
|
s64 exceptionVector = 0;
|
||||||
|
|
||||||
|
if(regs.cop0.status.bev) {
|
||||||
|
util::panic("BEV bit set!\n");
|
||||||
|
} else {
|
||||||
|
switch(code) {
|
||||||
|
case ExceptionCode::Interrupt: case ExceptionCode::TLBModification:
|
||||||
|
case ExceptionCode::AddressErrorLoad: case ExceptionCode::AddressErrorStore:
|
||||||
|
case ExceptionCode::InstructionBusError: case ExceptionCode::DataBusError:
|
||||||
|
case ExceptionCode::Syscall: case ExceptionCode::Breakpoint:
|
||||||
|
case ExceptionCode::ReservedInstruction: case ExceptionCode::CoprocessorUnusable:
|
||||||
|
case ExceptionCode::Overflow: case ExceptionCode::Trap:
|
||||||
|
case ExceptionCode::FloatingPointError: case ExceptionCode::Watch:
|
||||||
|
regs.SetPC(s64(s32(0x80000180)));
|
||||||
|
break;
|
||||||
|
case ExceptionCode::TLBLoad: case ExceptionCode::TLBStore:
|
||||||
|
if(old_exl || regs.cop0.tlbError == INVALID) {
|
||||||
|
regs.SetPC(s64(s32(0x80000180)));
|
||||||
|
} else if(Is64BitAddressing(regs.cop0, regs.cop0.badVaddr)) {
|
||||||
|
regs.SetPC(s64(s32(0x80000080)));
|
||||||
|
} else {
|
||||||
|
regs.SetPC(s64(s32(0x80000000)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: util::panic("Unhandled exception! {}\n", static_cast<u8>(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HandleTLBException(Registers& regs, u64 vaddr) {
|
void HandleTLBException(Registers& regs, u64 vaddr) {
|
||||||
u64 vpn2 = (vaddr >> 13) & 0x7FFFF;
|
u64 vpn2 = (vaddr >> 13) & 0x7FFFF;
|
||||||
u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF;
|
u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF;
|
||||||
|
|||||||
@@ -157,6 +157,27 @@ enum TLBError : u8 {
|
|||||||
DISALLOWED_ADDRESS
|
DISALLOWED_ADDRESS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ExceptionCode : u8 {
|
||||||
|
Interrupt,
|
||||||
|
TLBModification,
|
||||||
|
TLBLoad,
|
||||||
|
TLBStore,
|
||||||
|
AddressErrorLoad,
|
||||||
|
AddressErrorStore,
|
||||||
|
InstructionBusError,
|
||||||
|
DataBusError,
|
||||||
|
Syscall,
|
||||||
|
Breakpoint,
|
||||||
|
ReservedInstruction,
|
||||||
|
CoprocessorUnusable,
|
||||||
|
Overflow,
|
||||||
|
Trap,
|
||||||
|
FloatingPointError = 15,
|
||||||
|
Watch = 23
|
||||||
|
};
|
||||||
|
|
||||||
|
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc);
|
||||||
|
|
||||||
union Cop0Context {
|
union Cop0Context {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
struct {
|
struct {
|
||||||
@@ -244,7 +265,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Registers;
|
struct Registers;
|
||||||
enum ExceptionCode : u8;
|
enum class ExceptionCode : u8;
|
||||||
|
|
||||||
TLBEntry* TLBTryMatch(Registers& regs, s64 vaddr, int* match);
|
TLBEntry* TLBTryMatch(Registers& regs, s64 vaddr, int* match);
|
||||||
bool ProbeTLB(Registers& regs, TLBAccessType access_type, s64 vaddr, u32& paddr, int* match);
|
bool ProbeTLB(Registers& regs, TLBAccessType access_type, s64 vaddr, u32& paddr, int* match);
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ void Cop1::decode(Cpu& 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::FloatingPointError, 0, regs.oldPC); 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::FloatingPointError, 0, regs.oldPC); 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;
|
||||||
@@ -62,22 +64,22 @@ void Cop1::decode(Cpu& cpu, u32 instr) {
|
|||||||
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;
|
||||||
case 0x30: cconds(regs, instr, F); break;
|
case 0x30: ccond<float>(regs, instr, F); break;
|
||||||
case 0x31: cconds(regs, instr, UN); break;
|
case 0x31: ccond<float>(regs, instr, UN); break;
|
||||||
case 0x32: cconds(regs, instr, EQ); break;
|
case 0x32: ccond<float>(regs, instr, EQ); break;
|
||||||
case 0x33: cconds(regs, instr, UEQ); break;
|
case 0x33: ccond<float>(regs, instr, UEQ); break;
|
||||||
case 0x34: cconds(regs, instr, OLT); break;
|
case 0x34: ccond<float>(regs, instr, OLT); break;
|
||||||
case 0x35: cconds(regs, instr, ULT); break;
|
case 0x35: ccond<float>(regs, instr, ULT); break;
|
||||||
case 0x36: cconds(regs, instr, OLE); break;
|
case 0x36: ccond<float>(regs, instr, OLE); break;
|
||||||
case 0x37: cconds(regs, instr, ULE); break;
|
case 0x37: ccond<float>(regs, instr, ULE); break;
|
||||||
case 0x38: cconds(regs, instr, SF); break;
|
case 0x38: ccond<float>(regs, instr, SF); break;
|
||||||
case 0x39: cconds(regs, instr, NGLE); break;
|
case 0x39: ccond<float>(regs, instr, NGLE); break;
|
||||||
case 0x3A: cconds(regs, instr, SEQ); break;
|
case 0x3A: ccond<float>(regs, instr, SEQ); break;
|
||||||
case 0x3B: cconds(regs, instr, NGL); break;
|
case 0x3B: ccond<float>(regs, instr, NGL); break;
|
||||||
case 0x3C: cconds(regs, instr, LT); break;
|
case 0x3C: ccond<float>(regs, instr, LT); break;
|
||||||
case 0x3D: cconds(regs, instr, NGE); break;
|
case 0x3D: ccond<float>(regs, instr, NGE); break;
|
||||||
case 0x3E: cconds(regs, instr, LE); break;
|
case 0x3E: ccond<float>(regs, instr, LE); break;
|
||||||
case 0x3F: cconds(regs, instr, NGT); break;
|
case 0x3F: ccond<float>(regs, instr, NGT); break;
|
||||||
default: util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
|
default: util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -102,22 +104,22 @@ void Cop1::decode(Cpu& cpu, u32 instr) {
|
|||||||
case 0x20: cvtsd(regs, instr); break;
|
case 0x20: cvtsd(regs, instr); 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: ccondd(regs, instr, F); break;
|
case 0x30: ccond<double>(regs, instr, F); break;
|
||||||
case 0x31: ccondd(regs, instr, UN); break;
|
case 0x31: ccond<double>(regs, instr, UN); break;
|
||||||
case 0x32: ccondd(regs, instr, EQ); break;
|
case 0x32: ccond<double>(regs, instr, EQ); break;
|
||||||
case 0x33: ccondd(regs, instr, UEQ); break;
|
case 0x33: ccond<double>(regs, instr, UEQ); break;
|
||||||
case 0x34: ccondd(regs, instr, OLT); break;
|
case 0x34: ccond<double>(regs, instr, OLT); break;
|
||||||
case 0x35: ccondd(regs, instr, ULT); break;
|
case 0x35: ccond<double>(regs, instr, ULT); break;
|
||||||
case 0x36: ccondd(regs, instr, OLE); break;
|
case 0x36: ccond<double>(regs, instr, OLE); break;
|
||||||
case 0x37: ccondd(regs, instr, ULE); break;
|
case 0x37: ccond<double>(regs, instr, ULE); break;
|
||||||
case 0x38: ccondd(regs, instr, SF); break;
|
case 0x38: ccond<double>(regs, instr, SF); break;
|
||||||
case 0x39: ccondd(regs, instr, NGLE); break;
|
case 0x39: ccond<double>(regs, instr, NGLE); break;
|
||||||
case 0x3A: ccondd(regs, instr, SEQ); break;
|
case 0x3A: ccond<double>(regs, instr, SEQ); break;
|
||||||
case 0x3B: ccondd(regs, instr, NGL); break;
|
case 0x3B: ccond<double>(regs, instr, NGL); break;
|
||||||
case 0x3C: ccondd(regs, instr, LT); break;
|
case 0x3C: ccond<double>(regs, instr, LT); break;
|
||||||
case 0x3D: ccondd(regs, instr, NGE); break;
|
case 0x3D: ccond<double>(regs, instr, NGE); break;
|
||||||
case 0x3E: ccondd(regs, instr, LE); break;
|
case 0x3E: ccond<double>(regs, instr, LE); break;
|
||||||
case 0x3F: ccondd(regs, instr, NGT); break;
|
case 0x3F: ccond<double>(regs, instr, NGT); break;
|
||||||
default: util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
|
default: util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016lX})", mask_fun >> 3, mask_fun & 7, instr, regs.oldPC);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ union FCR31 {
|
|||||||
u32 raw;
|
u32 raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CompConds {
|
||||||
|
F, UN, EQ, UEQ,
|
||||||
|
OLT, ULT, OLE, ULE,
|
||||||
|
SF, NGLE, SEQ, NGL,
|
||||||
|
LT, NGE, LE, NGT
|
||||||
|
};
|
||||||
|
|
||||||
union FGR {
|
union FGR {
|
||||||
struct {
|
struct {
|
||||||
s32 lo:32;
|
s32 lo:32;
|
||||||
@@ -100,43 +107,32 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetCop1RegDouble(Cop0& cop0, u8 index, double value) {
|
template <typename T>
|
||||||
u64 raw;
|
inline void SetCop1Reg(Cop0& cop0, u8 index, T value) {
|
||||||
memcpy(&raw, &value, sizeof(double));
|
if constexpr (sizeof(T) == 4) {
|
||||||
SetReg<u64>(cop0, index, raw);
|
u32 raw;
|
||||||
|
memcpy(&raw, &value, sizeof(T));
|
||||||
|
SetReg<u32>(cop0, index, raw);
|
||||||
|
} else if constexpr (sizeof(T) == 8) {
|
||||||
|
u64 raw;
|
||||||
|
memcpy(&raw, &value, sizeof(T));
|
||||||
|
SetReg<u64>(cop0, index, raw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double GetCop1RegDouble(Cop0& cop0, u8 index) {
|
template <typename T>
|
||||||
double doublevalue;
|
inline T GetCop1Reg(Cop0& cop0, u8 index) {
|
||||||
u64 raw = GetReg<u64>(cop0, index);
|
T value;
|
||||||
memcpy(&doublevalue, &raw, sizeof(double));
|
if constexpr (sizeof(T) == 4) {
|
||||||
return doublevalue;
|
u32 raw = GetReg<u32>(cop0, index);
|
||||||
|
memcpy(&value, &raw, sizeof(T));
|
||||||
|
} else if constexpr (sizeof(T) == 8) {
|
||||||
|
u64 raw = GetReg<u64>(cop0, index);
|
||||||
|
memcpy(&value, &raw, sizeof(T));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void SetCop1RegFloat(Cop0& cop0, u8 index, float value) {
|
|
||||||
u32 raw;
|
|
||||||
memcpy(&raw, &value, sizeof(float));
|
|
||||||
SetReg<u32>(cop0, index, raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline float GetCop1RegFloat(Cop0& cop0, u8 index) {
|
|
||||||
u32 raw = GetReg<u32>(cop0, index);
|
|
||||||
float floatvalue;
|
|
||||||
memcpy(&floatvalue, &raw, sizeof(float));
|
|
||||||
return floatvalue;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum CompConds {
|
|
||||||
T, UN, EQ, UEQ,
|
|
||||||
OLT, ULT, OLE, ULE,
|
|
||||||
SF, NGLE, SEQ, NGL,
|
|
||||||
LT, NGE, LE, NGT,
|
|
||||||
F, OR, NEQ, OLG,
|
|
||||||
UGE, OGE, UGT, OGT,
|
|
||||||
ST, GLE, SNE, GL,
|
|
||||||
NLT, GE, NLE, GT
|
|
||||||
};
|
|
||||||
|
|
||||||
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 absw(Registers&, u32 instr);
|
||||||
@@ -151,7 +147,7 @@ private:
|
|||||||
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);
|
void cfc1(Registers&, u32 instr) const;
|
||||||
void ctc1(Registers&, u32 instr);
|
void ctc1(Registers&, u32 instr);
|
||||||
void roundls(Registers&, u32 instr);
|
void roundls(Registers&, u32 instr);
|
||||||
void roundld(Registers&, u32 instr);
|
void roundld(Registers&, u32 instr);
|
||||||
@@ -171,8 +167,8 @@ private:
|
|||||||
void cvtld(Registers&, u32 instr);
|
void cvtld(Registers&, u32 instr);
|
||||||
void cvtdl(Registers&, u32 instr);
|
void cvtdl(Registers&, u32 instr);
|
||||||
void cvtsl(Registers&, u32 instr);
|
void cvtsl(Registers&, u32 instr);
|
||||||
void ccondd(Registers&, u32 instr, CompConds);
|
template <typename T>
|
||||||
void cconds(Registers&, u32 instr, CompConds);
|
void ccond(Registers&, u32 instr, CompConds);
|
||||||
void divs(Registers&, u32 instr);
|
void divs(Registers&, u32 instr);
|
||||||
void divd(Registers&, u32 instr);
|
void divd(Registers&, u32 instr);
|
||||||
void muls(Registers&, u32 instr);
|
void muls(Registers&, u32 instr);
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void Cop1::absd(Registers& regs, u32 instr) {
|
void Cop1::absd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), fabs(fs));
|
SetCop1Reg<double>(regs.cop0, FD(instr), fabs(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::abss(Registers& regs, u32 instr) {
|
void Cop1::abss(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), fabsf(fs));
|
SetCop1Reg<float>(regs.cop0, FD(instr), fabsf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::absw(Registers& regs, u32 instr) {
|
void Cop1::absw(Registers& regs, u32 instr) {
|
||||||
@@ -26,44 +26,44 @@ void Cop1::absl(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::adds(Registers& regs, u32 instr) {
|
void Cop1::adds(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
float ft = GetCop1RegFloat(regs.cop0, FT(instr));
|
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||||
float result = fs + ft;
|
float result = fs + ft;
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), result);
|
SetCop1Reg<float>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::addd(Registers& regs, u32 instr) {
|
void Cop1::addd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
double ft = GetCop1RegDouble(regs.cop0, FT(instr));
|
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||||
double result = fs + ft;
|
double result = fs + ft;
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), result);
|
SetCop1Reg<double>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceills(Registers& regs, u32 instr) {
|
void Cop1::ceills(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
s64 result = ceilf(fs);
|
s64 result = ceilf(fs);
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
SetReg<u64>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilws(Registers& regs, u32 instr) {
|
void Cop1::ceilws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
s32 result = ceilf(fs);
|
s32 result = ceilf(fs);
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
SetReg<u32>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilld(Registers& regs, u32 instr) {
|
void Cop1::ceilld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
s64 result = ceil(fs);
|
s64 result = ceil(fs);
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
SetReg<u64>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ceilwd(Registers& regs, u32 instr) {
|
void Cop1::ceilwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
s32 result = ceil(fs);
|
s32 result = ceil(fs);
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
SetReg<u32>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cfc1(Registers& regs, u32 instr) {
|
void Cop1::cfc1(Registers& regs, u32 instr) const {
|
||||||
u8 fd = FD(instr);
|
u8 fd = FD(instr);
|
||||||
s32 val = 0;
|
s32 val = 0;
|
||||||
switch(fd) {
|
switch(fd) {
|
||||||
@@ -78,7 +78,7 @@ void Cop1::ctc1(Registers& regs, u32 instr) {
|
|||||||
u8 fs = FS(instr);
|
u8 fs = FS(instr);
|
||||||
u32 val = regs.gpr[RT(instr)];
|
u32 val = regs.gpr[RT(instr)];
|
||||||
switch(fs) {
|
switch(fs) {
|
||||||
case 0: util::panic("CTC1 attempt to write to FCR0 which is read only!\n");
|
case 0: break;
|
||||||
case 31: {
|
case 31: {
|
||||||
val &= 0x183ffff;
|
val &= 0x183ffff;
|
||||||
fcr31.raw = val;
|
fcr31.raw = val;
|
||||||
@@ -88,10 +88,10 @@ void Cop1::ctc1(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtds(Registers& regs, u32 instr) {
|
void Cop1::cvtds(Registers& regs, u32 instr) {
|
||||||
SetCop1RegDouble(
|
SetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegFloat(
|
GetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -99,10 +99,10 @@ void Cop1::cvtds(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
||||||
SetCop1RegFloat(
|
SetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegDouble(
|
GetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -113,7 +113,7 @@ void Cop1::cvtwd(Registers& regs, u32 instr) {
|
|||||||
SetReg<u32>(
|
SetReg<u32>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegDouble(
|
GetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -124,7 +124,7 @@ void Cop1::cvtws(Registers& regs, u32 instr) {
|
|||||||
SetReg<u32>(
|
SetReg<u32>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegFloat(
|
GetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -135,7 +135,7 @@ void Cop1::cvtls(Registers& regs, u32 instr) {
|
|||||||
SetReg<u64>(
|
SetReg<u64>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegFloat(
|
GetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -143,7 +143,7 @@ void Cop1::cvtls(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
||||||
SetCop1RegFloat(
|
SetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
(s64)GetReg<u64>(
|
(s64)GetReg<u64>(
|
||||||
@@ -154,7 +154,7 @@ void Cop1::cvtsl(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
||||||
SetCop1RegDouble(
|
SetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
(s32)GetReg<u32>(
|
(s32)GetReg<u32>(
|
||||||
@@ -165,7 +165,7 @@ void Cop1::cvtdw(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
||||||
SetCop1RegFloat(
|
SetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
(s32)GetReg<u32>(
|
(s32)GetReg<u32>(
|
||||||
@@ -176,7 +176,7 @@ void Cop1::cvtsw(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
||||||
SetCop1RegDouble(
|
SetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
(s64)GetReg<u64>(
|
(s64)GetReg<u64>(
|
||||||
@@ -188,77 +188,62 @@ void Cop1::cvtdl(Registers& regs, u32 instr) {
|
|||||||
|
|
||||||
void Cop1::cvtld(Registers& regs, u32 instr) {
|
void Cop1::cvtld(Registers& regs, u32 instr) {
|
||||||
SetReg<u64>(
|
SetReg<u64>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegDouble(
|
GetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ccondd(Registers& regs, u32 instr, CompConds cond) {
|
template <typename T>
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
inline bool CalculateCondition(T fs, T ft, u8 cond) {
|
||||||
double ft = GetCop1RegDouble(regs.cop0, FT(instr));
|
switch(cond) {
|
||||||
|
case F: return false;
|
||||||
bool less, equal, unordered;
|
case UN: return std::isnan(fs) || std::isnan(ft);
|
||||||
if(std::isnan(fs) || std::isnan(ft)) {
|
case EQ: return fs == ft;
|
||||||
less = false;
|
case UEQ: return (std::isnan(fs) || std::isnan(ft)) || (fs == ft);
|
||||||
equal = false;
|
case OLT: return (!std::isnan(fs) && !std::isnan(ft)) && (fs < ft);
|
||||||
unordered = true;
|
case ULT: return (std::isnan(fs) || std::isnan(ft)) || (fs < ft);
|
||||||
} else {
|
case OLE: return (!std::isnan(fs) && !std::isnan(ft)) && (fs <= ft);
|
||||||
less = fs < ft;
|
default: return CalculateCondition(fs, ft, cond - 8);
|
||||||
equal = fs == ft;
|
|
||||||
unordered = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool condition = ((cond >> 2) && less) || ((cond >> 1) && equal) || ((cond & 1) && unordered);
|
|
||||||
|
|
||||||
fcr31.compare = condition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::cconds(Registers& regs, u32 instr, CompConds cond) {
|
template <typename T>
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
void Cop1::ccond(Registers& regs, u32 instr, CompConds cond) {
|
||||||
float ft = GetCop1RegFloat(regs.cop0, FT(instr));
|
T fs = GetCop1Reg<T>(regs.cop0, FS(instr));
|
||||||
|
T ft = GetCop1Reg<T>(regs.cop0, FT(instr));
|
||||||
|
|
||||||
bool less, equal, unordered;
|
fcr31.compare = CalculateCondition(fs, ft, cond);
|
||||||
if(std::isnan(fs) || std::isnan(ft)) {
|
|
||||||
less = false;
|
|
||||||
equal = false;
|
|
||||||
unordered = true;
|
|
||||||
} else {
|
|
||||||
less = fs < ft;
|
|
||||||
equal = fs == ft;
|
|
||||||
unordered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool condition = ((cond >> 2) && less) || ((cond >> 1) && equal) || ((cond & 1) && unordered);
|
|
||||||
|
|
||||||
fcr31.compare = condition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template void Cop1::ccond<float>(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 = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
float ft = GetCop1RegFloat(regs.cop0, FT(instr));
|
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), fs / ft);
|
SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::divd(Registers ®s, u32 instr) {
|
void Cop1::divd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
double ft = GetCop1RegDouble(regs.cop0, FT(instr));
|
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), fs / ft);
|
SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::muls(Registers ®s, u32 instr) {
|
void Cop1::muls(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
float ft = GetCop1RegFloat(regs.cop0, FT(instr));
|
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), fs * ft);
|
SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::muld(Registers& regs, u32 instr) {
|
void Cop1::muld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
double ft = GetCop1RegDouble(regs.cop0, FT(instr));
|
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), fs * ft);
|
SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::mulw(Registers ®s, u32 instr) {
|
void Cop1::mulw(Registers ®s, u32 instr) {
|
||||||
@@ -274,15 +259,15 @@ void Cop1::mull(Registers ®s, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::subs(Registers ®s, u32 instr) {
|
void Cop1::subs(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
float ft = GetCop1RegFloat(regs.cop0, FT(instr));
|
float ft = GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), fs - ft);
|
SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::subd(Registers ®s, u32 instr) {
|
void Cop1::subd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
double ft = GetCop1RegDouble(regs.cop0, FT(instr));
|
double ft = GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), fs - ft);
|
SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::subw(Registers ®s, u32 instr) {
|
void Cop1::subw(Registers ®s, u32 instr) {
|
||||||
@@ -298,10 +283,10 @@ void Cop1::subl(Registers ®s, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::movs(Registers& regs, u32 instr) {
|
void Cop1::movs(Registers& regs, u32 instr) {
|
||||||
SetCop1RegFloat(
|
SetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegFloat(
|
GetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -309,10 +294,10 @@ void Cop1::movs(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::movd(Registers& regs, u32 instr) {
|
void Cop1::movd(Registers& regs, u32 instr) {
|
||||||
SetCop1RegDouble(
|
SetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
GetCop1RegDouble(
|
GetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -342,10 +327,10 @@ void Cop1::movl(Registers& regs, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::negs(Registers ®s, u32 instr) {
|
void Cop1::negs(Registers ®s, u32 instr) {
|
||||||
SetCop1RegFloat(
|
SetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
-GetCop1RegFloat(
|
-GetCop1Reg<float>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -353,10 +338,10 @@ void Cop1::negs(Registers ®s, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::negd(Registers ®s, u32 instr) {
|
void Cop1::negd(Registers ®s, u32 instr) {
|
||||||
SetCop1RegDouble(
|
SetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FD(instr),
|
FD(instr),
|
||||||
-GetCop1RegDouble(
|
-GetCop1Reg<double>(
|
||||||
regs.cop0,
|
regs.cop0,
|
||||||
FS(instr)
|
FS(instr)
|
||||||
)
|
)
|
||||||
@@ -364,101 +349,161 @@ void Cop1::negd(Registers ®s, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sqrts(Registers ®s, u32 instr) {
|
void Cop1::sqrts(Registers ®s, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetCop1RegFloat(regs.cop0, FD(instr), sqrtf(fs));
|
SetCop1Reg<float>(regs.cop0, FD(instr), sqrtf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sqrtd(Registers ®s, u32 instr) {
|
void Cop1::sqrtd(Registers ®s, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetCop1RegDouble(regs.cop0, FD(instr), sqrt(fs));
|
SetCop1Reg<double>(regs.cop0, FD(instr), sqrt(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundls(Registers& regs, u32 instr) {
|
void Cop1::roundls(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s32)roundf(fs));
|
SetReg<u64>(regs.cop0, FD(instr), (s32)roundf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundld(Registers& regs, u32 instr) {
|
void Cop1::roundld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)round(fs));
|
SetReg<u64>(regs.cop0, FD(instr), (s64)round(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundws(Registers& regs, u32 instr) {
|
void Cop1::roundws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s32)roundf(fs));
|
SetReg<u32>(regs.cop0, FD(instr), (s32)roundf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::roundwd(Registers& regs, u32 instr) {
|
void Cop1::roundwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s64)round(fs));
|
SetReg<u32>(regs.cop0, FD(instr), (s64)round(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorls(Registers& regs, u32 instr) {
|
void Cop1::floorls(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)floorf(fs));
|
SetReg<u64>(regs.cop0, FD(instr), (s64)floorf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorld(Registers& regs, u32 instr) {
|
void Cop1::floorld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u64>(regs.cop0, FD(instr), (s64)floor(fs));
|
SetReg<u64>(regs.cop0, FD(instr), (s64)floor(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorws(Registers& regs, u32 instr) {
|
void Cop1::floorws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s64)floorf(fs));
|
SetReg<u32>(regs.cop0, FD(instr), (s64)floorf(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::floorwd(Registers& regs, u32 instr) {
|
void Cop1::floorwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
SetReg<u32>(regs.cop0, FD(instr), (s64)floor(fs));
|
SetReg<u32>(regs.cop0, FD(instr), (s64)floor(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
|
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
|
||||||
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
if(!regs.cop0.status.cu1) {
|
||||||
u32 data = mem.Read32(regs, addr, regs.oldPC);
|
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||||
SetReg<u32>(regs.cop0, FT(instr), data);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||||
|
if(addr & 3) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 physical;
|
||||||
|
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||||
|
HandleTLBException(regs, addr);
|
||||||
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||||
|
} else {
|
||||||
|
u32 data = mem.Read32<false>(regs, physical, regs.oldPC);
|
||||||
|
SetReg<u32>(regs.cop0, FT(instr), data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
|
void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
|
||||||
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
if(!regs.cop0.status.cu1) {
|
||||||
mem.Write32(regs, addr, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
|
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||||
|
if(addr & 3) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 physical;
|
||||||
|
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||||
|
HandleTLBException(regs, addr);
|
||||||
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||||
|
} else {
|
||||||
|
mem.Write32<false>(regs, physical, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) {
|
void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) {
|
||||||
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
if(!regs.cop0.status.cu1) {
|
||||||
u64 data = mem.Read64(regs, addr, regs.oldPC);
|
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||||
SetReg<u64>(regs.cop0, FT(instr), data);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||||
|
if(addr & 7) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 physical;
|
||||||
|
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||||
|
HandleTLBException(regs, addr);
|
||||||
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||||
|
} else {
|
||||||
|
u64 data = mem.Read64<false>(regs, physical, regs.oldPC);
|
||||||
|
SetReg<u64>(regs.cop0, FT(instr), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) {
|
||||||
|
if(!regs.cop0.status.cu1) {
|
||||||
|
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||||
|
if(addr & 7) {
|
||||||
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 physical;
|
||||||
|
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||||
|
HandleTLBException(regs, addr);
|
||||||
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||||
|
} else {
|
||||||
|
mem.Write64<false>(regs, physical, GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::truncws(Registers& regs, u32 instr) {
|
void Cop1::truncws(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
s32 result = (s32)truncf(fs);
|
s32 result = (s32)truncf(fs);
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
SetReg<u32>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::truncwd(Registers& regs, u32 instr) {
|
void Cop1::truncwd(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
s32 result = (s32)trunc(fs);
|
s32 result = (s32)trunc(fs);
|
||||||
SetReg<u32>(regs.cop0, FD(instr), result);
|
SetReg<u32>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::truncls(Registers& regs, u32 instr) {
|
void Cop1::truncls(Registers& regs, u32 instr) {
|
||||||
float fs = GetCop1RegFloat(regs.cop0, FS(instr));
|
float fs = GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||||
s64 result = (s64)truncf(fs);
|
s64 result = (s64)truncf(fs);
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
SetReg<u64>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::truncld(Registers& regs, u32 instr) {
|
void Cop1::truncld(Registers& regs, u32 instr) {
|
||||||
double fs = GetCop1RegDouble(regs.cop0, FS(instr));
|
double fs = GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||||
s64 result = (s64)trunc(fs);
|
s64 result = (s64)trunc(fs);
|
||||||
SetReg<u64>(regs.cop0, FD(instr), result);
|
SetReg<u64>(regs.cop0, FD(instr), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) {
|
|
||||||
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
|
||||||
mem.Write64(regs, addr, GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
regs.gpr[RT(instr)] = (s32)GetReg<u32>(regs.cop0, FS(instr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,18 +226,24 @@ void RSP::sqv(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RSP::sllv(u32 instr) {
|
void RSP::sllv(u32 instr) {
|
||||||
u8 sa = gpr[RS(instr)] & 0x1F;
|
u8 sa = (gpr[RS(instr)]) & 0x1F;
|
||||||
gpr[RD(instr)] = (u32)gpr[RT(instr)] << sa;
|
u32 rt = gpr[RT(instr)];
|
||||||
|
u32 result = rt << sa;
|
||||||
|
gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::srlv(u32 instr) {
|
void RSP::srlv(u32 instr) {
|
||||||
u8 sa = gpr[RS(instr)] & 0x1F;
|
u8 sa = (gpr[RS(instr)]) & 0x1F;
|
||||||
gpr[RD(instr)] = (u32)gpr[RT(instr)] >> sa;
|
u32 rt = gpr[RT(instr)];
|
||||||
|
u32 result = rt >> sa;
|
||||||
|
gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::srav(u32 instr) {
|
void RSP::srav(u32 instr) {
|
||||||
u8 sa = gpr[RS(instr)] & 0x1F;
|
u8 sa = (gpr[RS(instr)]) & 0x1F;
|
||||||
gpr[RD(instr)] = gpr[RT(instr)] >> sa;
|
s32 rt = gpr[RT(instr)];
|
||||||
|
s32 result = rt >> sa;
|
||||||
|
gpr[RD(instr)] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::sll(u32 instr) {
|
void RSP::sll(u32 instr) {
|
||||||
|
|||||||
Reference in New Issue
Block a user