riscv: [Patch 3/5] Added RISCV floating point extensions RV64FD
Third of five patches adding RISC-V to GEM5. This patch adds the RV64FD extensions, which include single- and double-precision floating point instructions. Patch 1 introduced RISC-V and implemented the base instruction set, RV64I and patch 2 implemented the integer multiply extension, RV64M. Patch 4 will implement the atomic memory instructions, RV64A, and patch 5 will add support for timing, minor, and detailed CPU models that is missing from the first four patches. [Fixed exception handling in floating-point instructions to conform better to IEEE-754 2008 standard and behavior of the Chisel-generated RISC-V simulator.] [Fixed style errors in decoder.isa.] [Fixed some fuzz caused by modifying a previous patch.] Signed-off by: Alec Roelke Signed-off by: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
parent
070da98493
commit
1229b3b623
10 changed files with 1057 additions and 1 deletions
|
@ -71,6 +71,13 @@ UnimplementedFault::invoke_se(ThreadContext *tc,
|
||||||
tc->pcState().pc());
|
tc->pcState().pc());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IllegalFrmFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
||||||
|
{
|
||||||
|
panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.",
|
||||||
|
frm, tc->pcState().pc());
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,12 @@
|
||||||
namespace RiscvISA
|
namespace RiscvISA
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const uint32_t FloatInexact = 1 << 0;
|
||||||
|
const uint32_t FloatUnderflow = 1 << 1;
|
||||||
|
const uint32_t FloatOverflow = 1 << 2;
|
||||||
|
const uint32_t FloatDivZero = 1 << 3;
|
||||||
|
const uint32_t FloatInvalid = 1 << 4;
|
||||||
|
|
||||||
enum ExceptionCode {
|
enum ExceptionCode {
|
||||||
INST_ADDR_MISALIGNED = 0,
|
INST_ADDR_MISALIGNED = 0,
|
||||||
INST_ACCESS = 1,
|
INST_ACCESS = 1,
|
||||||
|
@ -124,6 +130,20 @@ class UnimplementedFault : public RiscvFault
|
||||||
invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
|
invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IllegalFrmFault: public RiscvFault
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const uint8_t frm;
|
||||||
|
public:
|
||||||
|
IllegalFrmFault(uint8_t r)
|
||||||
|
: RiscvFault("Illegal floating-point rounding mode", INST_ILLEGAL,
|
||||||
|
SOFTWARE),
|
||||||
|
frm(r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
|
||||||
|
};
|
||||||
|
|
||||||
class BreakpointFault : public RiscvFault
|
class BreakpointFault : public RiscvFault
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -75,3 +75,13 @@ def bitfield UJIMMBITS19TO12 <19:12>;
|
||||||
// System
|
// System
|
||||||
def bitfield FUNCT12 <31:20>;
|
def bitfield FUNCT12 <31:20>;
|
||||||
def bitfield ZIMM <19:15>;
|
def bitfield ZIMM <19:15>;
|
||||||
|
|
||||||
|
// Floating point
|
||||||
|
def bitfield FD <11:7>;
|
||||||
|
def bitfield FS1 <19:15>;
|
||||||
|
def bitfield FS2 <24:20>;
|
||||||
|
def bitfield FS3 <31:27>;
|
||||||
|
|
||||||
|
def bitfield ROUND_MODE <14:12>;
|
||||||
|
def bitfield CONV_SGN <24:20>;
|
||||||
|
def bitfield FUNCT2 <26:25>;
|
||||||
|
|
|
@ -61,6 +61,17 @@ decode OPCODE default Unknown::unknown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0x07: decode FUNCT3 {
|
||||||
|
format Load {
|
||||||
|
0x2: flw({{
|
||||||
|
Fd_bits = (uint64_t)Mem_uw;
|
||||||
|
}});
|
||||||
|
0x3: fld({{
|
||||||
|
Fd_bits = Mem;
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
0x0f: decode FUNCT3 {
|
0x0f: decode FUNCT3 {
|
||||||
format IOp {
|
format IOp {
|
||||||
0x0: fence({{
|
0x0: fence({{
|
||||||
|
@ -144,6 +155,17 @@ decode OPCODE default Unknown::unknown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0x27: decode FUNCT3 {
|
||||||
|
format Store {
|
||||||
|
0x2: fsw({{
|
||||||
|
Mem_uw = (uint32_t)Fs2_bits;
|
||||||
|
}});
|
||||||
|
0x3: fsd({{
|
||||||
|
Mem_ud = Fs2_bits;
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
0x33: decode FUNCT3 {
|
0x33: decode FUNCT3 {
|
||||||
format ROp {
|
format ROp {
|
||||||
0x0: decode FUNCT7 {
|
0x0: decode FUNCT7 {
|
||||||
|
@ -347,6 +369,813 @@ decode OPCODE default Unknown::unknown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format FPR4Op {
|
||||||
|
0x43: decode FUNCT2 {
|
||||||
|
0x0: fmadd_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)
|
||||||
|
|| issignalingnan(fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else if (std::isinf(fs1) || std::isinf(fs2) ||
|
||||||
|
std::isinf(fs3)) {
|
||||||
|
if (std::signbit(fs1) == std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = std::numeric_limits<float>::infinity();
|
||||||
|
} else if (std::signbit(fs1) != std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = -std::numeric_limits<float>::infinity();
|
||||||
|
} else { // Fs3_sf is infinity
|
||||||
|
fd = fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fd = fs1*fs2 + fs3;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0x1: fmadd_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|
||||||
|
|| issignalingnan(Fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
|
||||||
|
std::isinf(Fs3)) {
|
||||||
|
if (std::signbit(Fs1) == std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = std::numeric_limits<double>::infinity();
|
||||||
|
} else if (std::signbit(Fs1) != std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = -std::numeric_limits<double>::infinity();
|
||||||
|
} else {
|
||||||
|
Fd = Fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fd = Fs1*Fs2 + Fs3;
|
||||||
|
}
|
||||||
|
}}, FloatMultOp);
|
||||||
|
}
|
||||||
|
0x47: decode FUNCT2 {
|
||||||
|
0x0: fmsub_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)
|
||||||
|
|| issignalingnan(fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else if (std::isinf(fs1) || std::isinf(fs2) ||
|
||||||
|
std::isinf(fs3)) {
|
||||||
|
if (std::signbit(fs1) == std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = std::numeric_limits<float>::infinity();
|
||||||
|
} else if (std::signbit(fs1) != std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = -std::numeric_limits<float>::infinity();
|
||||||
|
} else { // Fs3_sf is infinity
|
||||||
|
fd = -fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fd = fs1*fs2 - fs3;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0x1: fmsub_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|
||||||
|
|| issignalingnan(Fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
|
||||||
|
std::isinf(Fs3)) {
|
||||||
|
if (std::signbit(Fs1) == std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = std::numeric_limits<double>::infinity();
|
||||||
|
} else if (std::signbit(Fs1) != std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = -std::numeric_limits<double>::infinity();
|
||||||
|
} else {
|
||||||
|
Fd = -Fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fd = Fs1*Fs2 - Fs3;
|
||||||
|
}
|
||||||
|
}}, FloatMultOp);
|
||||||
|
}
|
||||||
|
0x4b: decode FUNCT2 {
|
||||||
|
0x0: fnmsub_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)
|
||||||
|
|| issignalingnan(fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else if (std::isinf(fs1) || std::isinf(fs2) ||
|
||||||
|
std::isinf(fs3)) {
|
||||||
|
if (std::signbit(fs1) == std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = -std::numeric_limits<float>::infinity();
|
||||||
|
} else if (std::signbit(fs1) != std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = std::numeric_limits<float>::infinity();
|
||||||
|
} else { // Fs3_sf is infinity
|
||||||
|
fd = fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fd = -(fs1*fs2 - fs3);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0x1: fnmsub_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|
||||||
|
|| issignalingnan(Fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else if (std::isinf(Fs1) || std::isinf(Fs2)
|
||||||
|
|| std::isinf(Fs3)) {
|
||||||
|
if (std::signbit(Fs1) == std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = -std::numeric_limits<double>::infinity();
|
||||||
|
} else if (std::signbit(Fs1) != std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = std::numeric_limits<double>::infinity();
|
||||||
|
} else {
|
||||||
|
Fd = Fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fd = -(Fs1*Fs2 - Fs3);
|
||||||
|
}
|
||||||
|
}}, FloatMultOp);
|
||||||
|
}
|
||||||
|
0x4f: decode FUNCT2 {
|
||||||
|
0x0: fnmadd_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)
|
||||||
|
|| issignalingnan(fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else if (std::isinf(fs1) || std::isinf(fs2) ||
|
||||||
|
std::isinf(fs3)) {
|
||||||
|
if (std::signbit(fs1) == std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = -std::numeric_limits<float>::infinity();
|
||||||
|
} else if (std::signbit(fs1) != std::signbit(fs2)
|
||||||
|
&& !std::isinf(fs3)) {
|
||||||
|
fd = std::numeric_limits<float>::infinity();
|
||||||
|
} else { // Fs3_sf is infinity
|
||||||
|
fd = -fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fd = -(fs1*fs2 + fs3);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0x1: fnmadd_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|
||||||
|
|| issignalingnan(Fs3)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
|
||||||
|
std::isinf(Fs3)) {
|
||||||
|
if (std::signbit(Fs1) == std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = -std::numeric_limits<double>::infinity();
|
||||||
|
} else if (std::signbit(Fs1) != std::signbit(Fs2)
|
||||||
|
&& !std::isinf(Fs3)) {
|
||||||
|
Fd = std::numeric_limits<double>::infinity();
|
||||||
|
} else {
|
||||||
|
Fd = -Fs3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Fd = -(Fs1*Fs2 + Fs3);
|
||||||
|
}
|
||||||
|
}}, FloatMultOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
0x53: decode FUNCT7 {
|
||||||
|
format FPROp {
|
||||||
|
0x0: fadd_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
fd = fs1 + fs2;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatAddOp);
|
||||||
|
0x1: fadd_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
Fd = Fs1 + Fs2;
|
||||||
|
}
|
||||||
|
}}, FloatAddOp);
|
||||||
|
0x4: fsub_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
fd = fs1 - fs2;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatAddOp);
|
||||||
|
0x5: fsub_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
Fd = Fs1 - Fs2;
|
||||||
|
}
|
||||||
|
}}, FloatAddOp);
|
||||||
|
0x8: fmul_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
fd = fs1*fs2;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0x9: fmul_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
Fd = Fs1*Fs2;
|
||||||
|
}
|
||||||
|
}}, FloatMultOp);
|
||||||
|
0xc: fdiv_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
fd = fs1/fs2;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatDivOp);
|
||||||
|
0xd: fdiv_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
} else {
|
||||||
|
Fd = Fs1/Fs2;
|
||||||
|
}
|
||||||
|
}}, FloatDivOp);
|
||||||
|
0x10: decode ROUND_MODE {
|
||||||
|
0x0: fsgnj_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(fs1)) {
|
||||||
|
fd = std::numeric_limits<float>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
fd = std::copysign(fs1, fs2);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}});
|
||||||
|
0x1: fsgnjn_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(fs1)) {
|
||||||
|
fd = std::numeric_limits<float>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
fd = std::copysign(fs1, -fs2);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}});
|
||||||
|
0x2: fsgnjx_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(fs1)) {
|
||||||
|
fd = std::numeric_limits<float>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
fd = fs1*(std::signbit(fs2) ? -1.0 : 1.0);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
0x11: decode ROUND_MODE {
|
||||||
|
0x0: fsgnj_d({{
|
||||||
|
if (issignalingnan(Fs1)) {
|
||||||
|
Fd = std::numeric_limits<double>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
Fd = std::copysign(Fs1, Fs2);
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
0x1: fsgnjn_d({{
|
||||||
|
if (issignalingnan(Fs1)) {
|
||||||
|
Fd = std::numeric_limits<double>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
Fd = std::copysign(Fs1, -Fs2);
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
0x2: fsgnjx_d({{
|
||||||
|
if (issignalingnan(Fs1)) {
|
||||||
|
Fd = std::numeric_limits<double>::signaling_NaN();
|
||||||
|
std::feclearexcept(FE_INVALID);
|
||||||
|
} else {
|
||||||
|
Fd = Fs1*(std::signbit(Fs2) ? -1.0 : 1.0);
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
0x14: decode ROUND_MODE {
|
||||||
|
0x0: fmin_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(fs2)) {
|
||||||
|
fd = fs1;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else if (issignalingnan(fs1)) {
|
||||||
|
fd = fs2;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
fd = std::fmin(fs1, fs2);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x1: fmax_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(fs2)) {
|
||||||
|
fd = fs1;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else if (issignalingnan(fs1)) {
|
||||||
|
fd = fs2;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
fd = std::fmax(fs1, fs2);
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
}
|
||||||
|
0x15: decode ROUND_MODE {
|
||||||
|
0x0: fmin_d({{
|
||||||
|
if (issignalingnan(Fs2)) {
|
||||||
|
Fd = Fs1;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else if (issignalingnan(Fs1)) {
|
||||||
|
Fd = Fs2;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Fd = std::fmin(Fs1, Fs2);
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x1: fmax_d({{
|
||||||
|
if (issignalingnan(Fs2)) {
|
||||||
|
Fd = Fs1;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else if (issignalingnan(Fs1)) {
|
||||||
|
Fd = Fs2;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Fd = std::fmax(Fs1, Fs2);
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
}
|
||||||
|
0x20: fcvt_s_d({{
|
||||||
|
assert(CONV_SGN == 1);
|
||||||
|
float fd;
|
||||||
|
if (issignalingnan(Fs1)) {
|
||||||
|
fd = std::numeric_limits<float>::quiet_NaN();
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
fd = (float)Fs1;
|
||||||
|
}
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x21: fcvt_d_s({{
|
||||||
|
assert(CONV_SGN == 0);
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
|
||||||
|
if (issignalingnan(fs1)) {
|
||||||
|
Fd = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Fd = (double)fs1;
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x2c: fsqrt_s({{
|
||||||
|
assert(RS2 == 0);
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fd;
|
||||||
|
|
||||||
|
if (issignalingnan(Fs1_sf)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
fd = std::sqrt(fs1);
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
|
||||||
|
}}, FloatSqrtOp);
|
||||||
|
0x2d: fsqrt_d({{
|
||||||
|
assert(RS2 == 0);
|
||||||
|
Fd = std::sqrt(Fs1);
|
||||||
|
}}, FloatSqrtOp);
|
||||||
|
0x50: decode ROUND_MODE {
|
||||||
|
0x0: fle_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
Rd = 0;
|
||||||
|
} else {
|
||||||
|
Rd = fs1 <= fs2 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x1: flt_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
|
||||||
|
if (std::isnan(fs1) || std::isnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
Rd = 0;
|
||||||
|
} else {
|
||||||
|
Rd = fs1 < fs2 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x2: feq_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
|
||||||
|
|
||||||
|
if (issignalingnan(fs1) || issignalingnan(fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Rd = fs1 == fs2 ? 1 : 0;
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
}
|
||||||
|
0x51: decode ROUND_MODE {
|
||||||
|
0x0: fle_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
Rd = 0;
|
||||||
|
} else {
|
||||||
|
Rd = Fs1 <= Fs2 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x1: flt_d({{
|
||||||
|
if (std::isnan(Fs1) || std::isnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
Rd = 0;
|
||||||
|
} else {
|
||||||
|
Rd = Fs1 < Fs2 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
0x2: feq_d({{
|
||||||
|
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
Rd = Fs1 == Fs2 ? 1 : 0;
|
||||||
|
}}, FloatCmpOp);
|
||||||
|
}
|
||||||
|
0x60: decode CONV_SGN {
|
||||||
|
0x0: fcvt_w_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
|
||||||
|
if (std::isnan(fs1)) {
|
||||||
|
Rd_sd = std::numeric_limits<int32_t>::max();
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd_sd = (int32_t)fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd_sd = std::numeric_limits<int32_t>::min();
|
||||||
|
} else {
|
||||||
|
Rd_sd = std::numeric_limits<int32_t>::max();
|
||||||
|
}
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fcvt_wu_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
|
||||||
|
if (fs1 < 0.0) {
|
||||||
|
Rd = 0;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd = (uint32_t)fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
Rd = std::numeric_limits<uint64_t>::max();
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x2: fcvt_l_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
|
||||||
|
if (std::isnan(fs1)) {
|
||||||
|
Rd_sd = std::numeric_limits<int64_t>::max();
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd_sd = (int64_t)fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd_sd = std::numeric_limits<int64_t>::min();
|
||||||
|
} else {
|
||||||
|
Rd_sd = std::numeric_limits<int64_t>::max();
|
||||||
|
}
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x3: fcvt_lu_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
|
||||||
|
if (fs1 < 0.0) {
|
||||||
|
Rd = 0;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd = (uint64_t)fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
Rd = std::numeric_limits<uint64_t>::max();
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
}
|
||||||
|
0x61: decode CONV_SGN {
|
||||||
|
0x0: fcvt_w_d({{
|
||||||
|
Rd_sd = (int32_t)Fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
if (Fs1 < 0.0) {
|
||||||
|
Rd_sd = std::numeric_limits<int32_t>::min();
|
||||||
|
} else {
|
||||||
|
Rd_sd = std::numeric_limits<int32_t>::max();
|
||||||
|
}
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fcvt_wu_d({{
|
||||||
|
if (Fs1 < 0.0) {
|
||||||
|
Rd = 0;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd = (uint32_t)Fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
Rd = std::numeric_limits<uint64_t>::max();
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x2: fcvt_l_d({{
|
||||||
|
Rd_sd = Fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
if (Fs1 < 0.0) {
|
||||||
|
Rd_sd = std::numeric_limits<int64_t>::min();
|
||||||
|
} else {
|
||||||
|
Rd_sd = std::numeric_limits<int64_t>::max();
|
||||||
|
}
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x3: fcvt_lu_d({{
|
||||||
|
if (Fs1 < 0.0) {
|
||||||
|
Rd = 0;
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
} else {
|
||||||
|
Rd = (uint64_t)Fs1;
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
Rd = std::numeric_limits<uint64_t>::max();
|
||||||
|
std::feclearexcept(FE_INEXACT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
}
|
||||||
|
0x68: decode CONV_SGN {
|
||||||
|
0x0: fcvt_s_w({{
|
||||||
|
float temp = (float)Rs1_sw;
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fcvt_s_wu({{
|
||||||
|
float temp = (float)Rs1_uw;
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x2: fcvt_s_l({{
|
||||||
|
float temp = (float)Rs1_sd;
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x3: fcvt_s_lu({{
|
||||||
|
float temp = (float)Rs1;
|
||||||
|
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
}
|
||||||
|
0x69: decode CONV_SGN {
|
||||||
|
0x0: fcvt_d_w({{
|
||||||
|
Fd = (double)Rs1_sw;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fcvt_d_wu({{
|
||||||
|
Fd = (double)Rs1_uw;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x2: fcvt_d_l({{
|
||||||
|
Fd = (double)Rs1_sd;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x3: fcvt_d_lu({{
|
||||||
|
Fd = (double)Rs1;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
}
|
||||||
|
0x70: decode ROUND_MODE {
|
||||||
|
0x0: fmv_x_s({{
|
||||||
|
Rd = (uint32_t)Fs1_bits;
|
||||||
|
if ((Rd&0x80000000) != 0) {
|
||||||
|
Rd |= (0xFFFFFFFFULL << 32);
|
||||||
|
}
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fclass_s({{
|
||||||
|
uint32_t temp;
|
||||||
|
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
|
||||||
|
switch (std::fpclassify(fs1)) {
|
||||||
|
case FP_INFINITE:
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd = 1 << 0;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_NAN:
|
||||||
|
if (issignalingnan(fs1)) {
|
||||||
|
Rd = 1 << 8;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 9;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_ZERO:
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd = 1 << 3;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_SUBNORMAL:
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd = 1 << 2;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_NORMAL:
|
||||||
|
if (std::signbit(fs1)) {
|
||||||
|
Rd = 1 << 1;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 6;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Unknown classification for operand.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
0x71: decode ROUND_MODE {
|
||||||
|
0x0: fmv_x_d({{
|
||||||
|
Rd = Fs1_bits;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x1: fclass_d({{
|
||||||
|
switch (std::fpclassify(Fs1)) {
|
||||||
|
case FP_INFINITE:
|
||||||
|
if (std::signbit(Fs1)) {
|
||||||
|
Rd = 1 << 0;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_NAN:
|
||||||
|
if (issignalingnan(Fs1)) {
|
||||||
|
Rd = 1 << 8;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 9;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_ZERO:
|
||||||
|
if (std::signbit(Fs1)) {
|
||||||
|
Rd = 1 << 3;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_SUBNORMAL:
|
||||||
|
if (std::signbit(Fs1)) {
|
||||||
|
Rd = 1 << 2;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FP_NORMAL:
|
||||||
|
if (std::signbit(Fs1)) {
|
||||||
|
Rd = 1 << 1;
|
||||||
|
} else {
|
||||||
|
Rd = 1 << 6;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Unknown classification for operand.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
0x78: fmv_s_x({{
|
||||||
|
Fd_bits = (uint64_t)Rs1_uw;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
0x79: fmv_d_x({{
|
||||||
|
Fd_bits = Rs1;
|
||||||
|
}}, FloatCvtOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
0x63: decode FUNCT3 {
|
0x63: decode FUNCT3 {
|
||||||
format SBOp {
|
format SBOp {
|
||||||
0x0: beq({{
|
0x0: beq({{
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
//Include the type formats
|
//Include the type formats
|
||||||
##include "type.isa"
|
##include "type.isa"
|
||||||
##include "mem.isa"
|
##include "mem.isa"
|
||||||
|
##include "fp.isa"
|
||||||
|
|
||||||
// Include the unknown
|
// Include the unknown
|
||||||
##include "unknown.isa"
|
##include "unknown.isa"
|
||||||
|
|
136
src/arch/riscv/isa/formats/fp.isa
Normal file
136
src/arch/riscv/isa/formats/fp.isa
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
// -*- mode:c++ -*-
|
||||||
|
|
||||||
|
// Copyright (c) 2015 Riscv Developers
|
||||||
|
// Copyright (c) 2016 The University of Virginia
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met: redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer;
|
||||||
|
// redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution;
|
||||||
|
// neither the name of the copyright holders nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
// Authors: Alec Roelke
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Floating point operation instructions
|
||||||
|
//
|
||||||
|
def template FloatExecute {{
|
||||||
|
Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc,
|
||||||
|
Trace::InstRecord *traceData) const
|
||||||
|
{
|
||||||
|
Fault fault = NoFault;
|
||||||
|
|
||||||
|
%(op_decl)s;
|
||||||
|
%(op_rd)s;
|
||||||
|
if (fault == NoFault) {
|
||||||
|
switch (ROUND_MODE) {
|
||||||
|
case 0x0:
|
||||||
|
std::fesetround(FE_TONEAREST);
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
std::fesetround(FE_TOWARDZERO);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
std::fesetround(FE_DOWNWARD);
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
std::fesetround(FE_UPWARD);
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
panic("Round to nearest, "
|
||||||
|
"ties to max magnitude not implemented.");
|
||||||
|
break;
|
||||||
|
case 0x7: {
|
||||||
|
uint8_t frm = xc->readMiscReg(MISCREG_FRM);
|
||||||
|
switch (frm) {
|
||||||
|
case 0x0:
|
||||||
|
std::fesetround(FE_TONEAREST);
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
std::fesetround(FE_TOWARDZERO);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
std::fesetround(FE_DOWNWARD);
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
std::fesetround(FE_UPWARD);
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
panic("Round to nearest,"
|
||||||
|
" ties to max magnitude not implemented.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fault = std::make_shared<IllegalFrmFault>(frm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fault = std::make_shared<IllegalFrmFault>(ROUND_MODE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fault == NoFault) {
|
||||||
|
MiscReg FFLAGS = xc->readMiscReg(MISCREG_FFLAGS);
|
||||||
|
std::feclearexcept(FE_ALL_EXCEPT);
|
||||||
|
%(code)s;
|
||||||
|
if (std::fetestexcept(FE_INEXACT)) {
|
||||||
|
FFLAGS |= FloatInexact;
|
||||||
|
}
|
||||||
|
if (std::fetestexcept(FE_UNDERFLOW)) {
|
||||||
|
FFLAGS |= FloatUnderflow;
|
||||||
|
}
|
||||||
|
if (std::fetestexcept(FE_OVERFLOW)) {
|
||||||
|
FFLAGS |= FloatOverflow;
|
||||||
|
}
|
||||||
|
if (std::fetestexcept(FE_DIVBYZERO)) {
|
||||||
|
FFLAGS |= FloatDivZero;
|
||||||
|
}
|
||||||
|
if (std::fetestexcept(FE_INVALID)) {
|
||||||
|
FFLAGS |= FloatInvalid;
|
||||||
|
}
|
||||||
|
xc->setMiscReg(MISCREG_FFLAGS, FFLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fault == NoFault) {
|
||||||
|
%(op_wb)s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fault;
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
def format FPROp(code, *opt_flags) {{
|
||||||
|
iop = InstObjParams(name, Name, 'ROp', code, opt_flags)
|
||||||
|
header_output = BasicDeclare.subst(iop)
|
||||||
|
decoder_output = BasicConstructor.subst(iop)
|
||||||
|
decode_block = BasicDecode.subst(iop)
|
||||||
|
exec_output = FloatExecute.subst(iop)
|
||||||
|
}};
|
||||||
|
|
||||||
|
def format FPR4Op(code, *opt_flags) {{
|
||||||
|
iop = InstObjParams(name, Name, 'ROp', code, opt_flags)
|
||||||
|
header_output = BasicDeclare.subst(iop)
|
||||||
|
decoder_output = BasicConstructor.subst(iop)
|
||||||
|
decode_block = BasicDecode.subst(iop)
|
||||||
|
exec_output = FloatExecute.subst(iop)
|
||||||
|
}};
|
|
@ -68,12 +68,14 @@ using namespace RiscvISA;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
output exec {{
|
output exec {{
|
||||||
|
#include <cfenv>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "arch/generic/memhelpers.hh"
|
#include "arch/generic/memhelpers.hh"
|
||||||
#include "arch/riscv/faults.hh"
|
#include "arch/riscv/faults.hh"
|
||||||
#include "arch/riscv/registers.hh"
|
#include "arch/riscv/registers.hh"
|
||||||
|
#include "arch/riscv/utility.hh"
|
||||||
#include "base/condcodes.hh"
|
#include "base/condcodes.hh"
|
||||||
#include "cpu/base.hh"
|
#include "cpu/base.hh"
|
||||||
#include "cpu/exetrace.hh"
|
#include "cpu/exetrace.hh"
|
||||||
|
|
|
@ -39,6 +39,8 @@ def operand_types {{
|
||||||
'uw' : 'uint32_t',
|
'uw' : 'uint32_t',
|
||||||
'sd' : 'int64_t',
|
'sd' : 'int64_t',
|
||||||
'ud' : 'uint64_t',
|
'ud' : 'uint64_t',
|
||||||
|
'sf' : 'float',
|
||||||
|
'df' : 'double'
|
||||||
}};
|
}};
|
||||||
|
|
||||||
def operands {{
|
def operands {{
|
||||||
|
@ -47,6 +49,15 @@ def operands {{
|
||||||
'Rs1': ('IntReg', 'ud', 'RS1', 'IsInteger', 2),
|
'Rs1': ('IntReg', 'ud', 'RS1', 'IsInteger', 2),
|
||||||
'Rs2': ('IntReg', 'ud', 'RS2', 'IsInteger', 3),
|
'Rs2': ('IntReg', 'ud', 'RS2', 'IsInteger', 3),
|
||||||
|
|
||||||
|
'Fd': ('FloatReg', 'df', 'FD', 'IsFloating', 1),
|
||||||
|
'Fd_bits': ('FloatReg', 'ud', 'FD', 'IsFloating', 1),
|
||||||
|
'Fs1': ('FloatReg', 'df', 'FS1', 'IsFloating', 2),
|
||||||
|
'Fs1_bits': ('FloatReg', 'ud', 'FS1', 'IsFloating', 2),
|
||||||
|
'Fs2': ('FloatReg', 'df', 'FS2', 'IsFloating', 3),
|
||||||
|
'Fs2_bits': ('FloatReg', 'ud', 'FS2', 'IsFloating', 3),
|
||||||
|
'Fs3': ('FloatReg', 'df', 'FS3', 'IsFloating', 4),
|
||||||
|
'Fs3_bits': ('FloatReg', 'ud', 'FS3', 'IsFloating', 4),
|
||||||
|
|
||||||
#Memory Operand
|
#Memory Operand
|
||||||
'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 5),
|
'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 5),
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ typedef uint64_t MiscReg;
|
||||||
|
|
||||||
const int NumIntArchRegs = 32;
|
const int NumIntArchRegs = 32;
|
||||||
const int NumIntRegs = NumIntArchRegs;
|
const int NumIntRegs = NumIntArchRegs;
|
||||||
const int NumFloatRegs = 0;
|
const int NumFloatRegs = 32;
|
||||||
const int NumCCRegs = 0;
|
const int NumCCRegs = 0;
|
||||||
const int NumMiscRegs = 4096;
|
const int NumMiscRegs = 4096;
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,46 @@
|
||||||
namespace RiscvISA
|
namespace RiscvISA
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename T> inline bool
|
||||||
|
isquietnan(T val)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool
|
||||||
|
isquietnan<float>(float val)
|
||||||
|
{
|
||||||
|
return std::isnan(val)
|
||||||
|
&& (reinterpret_cast<uint32_t&>(val)&0x00400000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool
|
||||||
|
isquietnan<double>(double val)
|
||||||
|
{
|
||||||
|
return std::isnan(val)
|
||||||
|
&& (reinterpret_cast<uint64_t&>(val)&0x0008000000000000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> inline bool
|
||||||
|
issignalingnan(T val)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool
|
||||||
|
issignalingnan<float>(float val)
|
||||||
|
{
|
||||||
|
return std::isnan(val)
|
||||||
|
&& (reinterpret_cast<uint32_t&>(val)&0x00200000);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline bool
|
||||||
|
issignalingnan<double>(double val)
|
||||||
|
{
|
||||||
|
return std::isnan(val)
|
||||||
|
&& (reinterpret_cast<uint64_t&>(val)&0x0004000000000000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
inline PCState
|
inline PCState
|
||||||
buildRetPC(const PCState &curPC, const PCState &callPC)
|
buildRetPC(const PCState &curPC, const PCState &callPC)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue