247 lines
5.9 KiB
C++
247 lines
5.9 KiB
C++
#pragma once
|
|
#include <core/registers/Cop0.hpp>
|
|
#include <cstring>
|
|
|
|
namespace n64 {
|
|
struct Cop1;
|
|
|
|
union FCR31 {
|
|
FCR31() = default;
|
|
struct {
|
|
unsigned rounding_mode : 2;
|
|
struct {
|
|
unsigned inexact_operation : 1;
|
|
unsigned underflow : 1;
|
|
unsigned overflow : 1;
|
|
unsigned division_by_zero : 1;
|
|
unsigned invalid_operation : 1;
|
|
} flag;
|
|
struct {
|
|
unsigned inexact_operation : 1;
|
|
unsigned underflow : 1;
|
|
unsigned overflow : 1;
|
|
unsigned division_by_zero : 1;
|
|
unsigned invalid_operation : 1;
|
|
} enable;
|
|
struct {
|
|
unsigned inexact_operation : 1;
|
|
unsigned underflow : 1;
|
|
unsigned overflow : 1;
|
|
unsigned division_by_zero : 1;
|
|
unsigned invalid_operation : 1;
|
|
unsigned unimplemented_operation : 1;
|
|
} cause;
|
|
unsigned : 5;
|
|
unsigned compare : 1;
|
|
unsigned fs : 1;
|
|
unsigned : 7;
|
|
} __attribute__((__packed__));
|
|
|
|
[[nodiscard]] u32 read() const {
|
|
u32 ret = 0;
|
|
ret |= (u32(fs) << 24);
|
|
ret |= (u32(compare) << 23);
|
|
ret |= (u32(cause.unimplemented_operation) << 17);
|
|
ret |= (u32(cause.invalid_operation) << 16);
|
|
ret |= (u32(cause.division_by_zero) << 15);
|
|
ret |= (u32(cause.overflow) << 14);
|
|
ret |= (u32(cause.underflow) << 13);
|
|
ret |= (u32(cause.inexact_operation) << 12);
|
|
ret |= (u32(enable.invalid_operation) << 11);
|
|
ret |= (u32(enable.division_by_zero) << 10);
|
|
ret |= (u32(enable.overflow) << 9);
|
|
ret |= (u32(enable.underflow) << 8);
|
|
ret |= (u32(enable.inexact_operation) << 7);
|
|
ret |= (u32(flag.invalid_operation) << 6);
|
|
ret |= (u32(flag.division_by_zero) << 5);
|
|
ret |= (u32(flag.overflow) << 4);
|
|
ret |= (u32(flag.underflow) << 3);
|
|
ret |= (u32(flag.inexact_operation) << 2);
|
|
ret |= (u32(rounding_mode) & 3);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void write(u32 val) {
|
|
fs = val >> 24;
|
|
compare = val >> 23;
|
|
cause.unimplemented_operation = val >> 17;
|
|
cause.invalid_operation = val >> 16;
|
|
cause.division_by_zero = val >> 15;
|
|
cause.overflow = val >> 14;
|
|
cause.underflow = val >> 13;
|
|
cause.inexact_operation = val >> 12;
|
|
enable.invalid_operation = val >> 11;
|
|
enable.division_by_zero = val >> 10;
|
|
enable.overflow = val >> 9;
|
|
enable.underflow = val >> 8;
|
|
enable.inexact_operation = val >> 7;
|
|
flag.invalid_operation = val >> 6;
|
|
flag.division_by_zero = val >> 5;
|
|
flag.overflow = val >> 4;
|
|
flag.underflow = val >> 3;
|
|
flag.inexact_operation = val >> 2;
|
|
rounding_mode = val & 3;
|
|
}
|
|
};
|
|
|
|
union FloatingPointReg {
|
|
struct {
|
|
s32 int32;
|
|
s32 int32h;
|
|
};
|
|
struct {
|
|
u32 uint32;
|
|
u32 uint32h;
|
|
};
|
|
struct {
|
|
s64 int64;
|
|
};
|
|
struct {
|
|
u64 uint64;
|
|
};
|
|
struct {
|
|
float float32;
|
|
float float32h;
|
|
};
|
|
struct {
|
|
double float64;
|
|
};
|
|
};
|
|
|
|
struct Cop1 {
|
|
explicit Cop1();
|
|
u32 fcr0{};
|
|
FCR31 fcr31{};
|
|
FloatingPointReg fgr[32]{};
|
|
bool fgrIsConstant[32]{};
|
|
|
|
void Reset();
|
|
void decode(u32);
|
|
friend struct Interpreter;
|
|
friend struct JIT;
|
|
|
|
template <bool preserveCause = false>
|
|
bool CheckFPUUsable();
|
|
template <typename T>
|
|
bool CheckResult(T &);
|
|
template <typename T>
|
|
bool CheckArg(T);
|
|
template <typename T>
|
|
bool CheckArgs(T, T);
|
|
template <typename T>
|
|
bool isqnan(T);
|
|
|
|
template <typename T, bool quiet, bool cf>
|
|
bool XORDERED(T fs, T ft);
|
|
|
|
template <typename T>
|
|
bool CheckCVTArg(float f);
|
|
template <typename T>
|
|
bool CheckCVTArg(double f);
|
|
|
|
template <bool cvt = false>
|
|
bool TestExceptions();
|
|
void SetCauseUnimplemented();
|
|
bool SetCauseUnderflow();
|
|
bool SetCauseInexact();
|
|
bool SetCauseDivisionByZero();
|
|
bool SetCauseOverflow();
|
|
bool SetCauseInvalid();
|
|
|
|
private:
|
|
template <typename T>
|
|
auto FGR_T(const Cop0Status &, u32) -> T &;
|
|
template <typename T>
|
|
auto FGR_S(const Cop0Status &, u32) -> T &;
|
|
template <typename T>
|
|
auto FGR_D(const Cop0Status &, u32) -> T &;
|
|
void absd(u32 instr);
|
|
void abss(u32 instr);
|
|
void adds(u32 instr);
|
|
void addd(u32 instr);
|
|
void subs(u32 instr);
|
|
void subd(u32 instr);
|
|
void ceills(u32 instr);
|
|
void ceilws(u32 instr);
|
|
void ceilld(u32 instr);
|
|
void ceilwd(u32 instr);
|
|
void cfc1(u32 instr);
|
|
void ctc1(u32 instr);
|
|
void unimplemented();
|
|
void roundls(u32 instr);
|
|
void roundld(u32 instr);
|
|
void roundws(u32 instr);
|
|
void roundwd(u32 instr);
|
|
void floorls(u32 instr);
|
|
void floorld(u32 instr);
|
|
void floorws(u32 instr);
|
|
void floorwd(u32 instr);
|
|
void cvtls(u32 instr);
|
|
void cvtws(u32 instr);
|
|
void cvtds(u32 instr);
|
|
void cvtsw(u32 instr);
|
|
void cvtdw(u32 instr);
|
|
void cvtsd(u32 instr);
|
|
void cvtwd(u32 instr);
|
|
void cvtld(u32 instr);
|
|
void cvtdl(u32 instr);
|
|
void cvtsl(u32 instr);
|
|
template <typename T>
|
|
void cf(u32 instr);
|
|
template <typename T>
|
|
void cun(u32 instr);
|
|
template <typename T>
|
|
void ceq(u32 instr);
|
|
template <typename T>
|
|
void cueq(u32 instr);
|
|
template <typename T>
|
|
void colt(u32 instr);
|
|
template <typename T>
|
|
void cult(u32 instr);
|
|
template <typename T>
|
|
void cole(u32 instr);
|
|
template <typename T>
|
|
void cule(u32 instr);
|
|
template <typename T>
|
|
void csf(u32 instr);
|
|
template <typename T>
|
|
void cngle(u32 instr);
|
|
template <typename T>
|
|
void cseq(u32 instr);
|
|
template <typename T>
|
|
void cngl(u32 instr);
|
|
template <typename T>
|
|
void clt(u32 instr);
|
|
template <typename T>
|
|
void cnge(u32 instr);
|
|
template <typename T>
|
|
void cle(u32 instr);
|
|
template <typename T>
|
|
void cngt(u32 instr);
|
|
void divs(u32 instr);
|
|
void divd(u32 instr);
|
|
void muls(u32 instr);
|
|
void muld(u32 instr);
|
|
void movs(u32 instr);
|
|
void movd(u32 instr);
|
|
void negs(u32 instr);
|
|
void negd(u32 instr);
|
|
void sqrts(u32 instr);
|
|
void sqrtd(u32 instr);
|
|
void lwc1(u32);
|
|
void swc1(u32);
|
|
void ldc1(u32);
|
|
void sdc1(u32);
|
|
|
|
void mfc1(u32 instr);
|
|
void dmfc1(u32 instr);
|
|
void mtc1(u32 instr);
|
|
void dmtc1(u32 instr);
|
|
void truncws(u32 instr);
|
|
void truncwd(u32 instr);
|
|
void truncls(u32 instr);
|
|
void truncld(u32 instr);
|
|
};
|
|
} // namespace n64
|