summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Roelke <ar4jc@virginia.edu>2016-11-30 17:10:28 -0500
committerAlec Roelke <ar4jc@virginia.edu>2016-11-30 17:10:28 -0500
commit1229b3b62303e00693cfb052fca6e4f7879cf0af (patch)
tree39cf4ee7cbc80de16ca9c748f6852afdf3a9b3df
parent070da984936ea3f1bc0d3ae7d581b59b6733e4fe (diff)
downloadgem5-1229b3b62303e00693cfb052fca6e4f7879cf0af.tar.xz
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>
-rw-r--r--src/arch/riscv/faults.cc7
-rw-r--r--src/arch/riscv/faults.hh20
-rw-r--r--src/arch/riscv/isa/bitfields.isa10
-rw-r--r--src/arch/riscv/isa/decoder.isa829
-rw-r--r--src/arch/riscv/isa/formats/formats.isa1
-rw-r--r--src/arch/riscv/isa/formats/fp.isa136
-rw-r--r--src/arch/riscv/isa/includes.isa2
-rw-r--r--src/arch/riscv/isa/operands.isa11
-rw-r--r--src/arch/riscv/registers.hh2
-rw-r--r--src/arch/riscv/utility.hh40
10 files changed, 1057 insertions, 1 deletions
diff --git a/src/arch/riscv/faults.cc b/src/arch/riscv/faults.cc
index 2ed823a53..f5ba5c798 100644
--- a/src/arch/riscv/faults.cc
+++ b/src/arch/riscv/faults.cc
@@ -72,6 +72,13 @@ UnimplementedFault::invoke_se(ThreadContext *tc,
}
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
BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
{
schedRelBreak(0);
diff --git a/src/arch/riscv/faults.hh b/src/arch/riscv/faults.hh
index cd073235c..d0d7988c5 100644
--- a/src/arch/riscv/faults.hh
+++ b/src/arch/riscv/faults.hh
@@ -40,6 +40,12 @@
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 {
INST_ADDR_MISALIGNED = 0,
INST_ACCESS = 1,
@@ -124,6 +130,20 @@ class UnimplementedFault : public RiscvFault
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
{
public:
diff --git a/src/arch/riscv/isa/bitfields.isa b/src/arch/riscv/isa/bitfields.isa
index 9a2184453..0a0b99ba1 100644
--- a/src/arch/riscv/isa/bitfields.isa
+++ b/src/arch/riscv/isa/bitfields.isa
@@ -75,3 +75,13 @@ def bitfield UJIMMBITS19TO12 <19:12>;
// System
def bitfield FUNCT12 <31:20>;
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>;
diff --git a/src/arch/riscv/isa/decoder.isa b/src/arch/riscv/isa/decoder.isa
index e02d507de..1b28ae1de 100644
--- a/src/arch/riscv/isa/decoder.isa
+++ b/src/arch/riscv/isa/decoder.isa
@@ -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 {
format IOp {
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 {
format ROp {
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 {
format SBOp {
0x0: beq({{
diff --git a/src/arch/riscv/isa/formats/formats.isa b/src/arch/riscv/isa/formats/formats.isa
index b015f8baa..7e4dc6ef0 100644
--- a/src/arch/riscv/isa/formats/formats.isa
+++ b/src/arch/riscv/isa/formats/formats.isa
@@ -36,6 +36,7 @@
//Include the type formats
##include "type.isa"
##include "mem.isa"
+##include "fp.isa"
// Include the unknown
##include "unknown.isa"
diff --git a/src/arch/riscv/isa/formats/fp.isa b/src/arch/riscv/isa/formats/fp.isa
new file mode 100644
index 000000000..97a5a2a50
--- /dev/null
+++ b/src/arch/riscv/isa/formats/fp.isa
@@ -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)
+}};
diff --git a/src/arch/riscv/isa/includes.isa b/src/arch/riscv/isa/includes.isa
index 197133d25..c830f9085 100644
--- a/src/arch/riscv/isa/includes.isa
+++ b/src/arch/riscv/isa/includes.isa
@@ -68,12 +68,14 @@ using namespace RiscvISA;
}};
output exec {{
+#include <cfenv>
#include <cmath>
#include <string>
#include "arch/generic/memhelpers.hh"
#include "arch/riscv/faults.hh"
#include "arch/riscv/registers.hh"
+#include "arch/riscv/utility.hh"
#include "base/condcodes.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
diff --git a/src/arch/riscv/isa/operands.isa b/src/arch/riscv/isa/operands.isa
index d6bdda399..5e79717e7 100644
--- a/src/arch/riscv/isa/operands.isa
+++ b/src/arch/riscv/isa/operands.isa
@@ -39,6 +39,8 @@ def operand_types {{
'uw' : 'uint32_t',
'sd' : 'int64_t',
'ud' : 'uint64_t',
+ 'sf' : 'float',
+ 'df' : 'double'
}};
def operands {{
@@ -47,6 +49,15 @@ def operands {{
'Rs1': ('IntReg', 'ud', 'RS1', 'IsInteger', 2),
'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
'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 5),
diff --git a/src/arch/riscv/registers.hh b/src/arch/riscv/registers.hh
index 4d9a80601..cf23c18df 100644
--- a/src/arch/riscv/registers.hh
+++ b/src/arch/riscv/registers.hh
@@ -69,7 +69,7 @@ typedef uint64_t MiscReg;
const int NumIntArchRegs = 32;
const int NumIntRegs = NumIntArchRegs;
-const int NumFloatRegs = 0;
+const int NumFloatRegs = 32;
const int NumCCRegs = 0;
const int NumMiscRegs = 4096;
diff --git a/src/arch/riscv/utility.hh b/src/arch/riscv/utility.hh
index 56aa65f12..fc67fc806 100644
--- a/src/arch/riscv/utility.hh
+++ b/src/arch/riscv/utility.hh
@@ -56,6 +56,46 @@
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
buildRetPC(const PCState &curPC, const PCState &callPC)
{