riscv: [Patch 3/5] Added RISCV floating point extensions RV64FD
authorAlec Roelke <ar4jc@virginia.edu>
Wed, 30 Nov 2016 22:10:28 +0000 (17:10 -0500)
committerAlec Roelke <ar4jc@virginia.edu>
Wed, 30 Nov 2016 22:10:28 +0000 (17:10 -0500)
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>

src/arch/riscv/faults.cc
src/arch/riscv/faults.hh
src/arch/riscv/isa/bitfields.isa
src/arch/riscv/isa/decoder.isa
src/arch/riscv/isa/formats/formats.isa
src/arch/riscv/isa/formats/fp.isa [new file with mode: 0644]
src/arch/riscv/isa/includes.isa
src/arch/riscv/isa/operands.isa
src/arch/riscv/registers.hh
src/arch/riscv/utility.hh

index 2ed823a5306ff35fc56211ce5b2f85a18226c5c3..f5ba5c7983b494f439e09d4320f8e8f8eea93f5a 100644 (file)
@@ -71,6 +71,13 @@ UnimplementedFault::invoke_se(ThreadContext *tc,
         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
 BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
 {
index cd073235cd40ac0a127df03843591df1414e3a09..d0d7988c591498a54829722dce7be3412a874927 100644 (file)
 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:
index 9a2184453d4475ac696621767226b7e42ea8135f..0a0b99ba1160b6c95eb257b78d3d0c8e241e8a62 100644 (file)
@@ -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>;
index e02d507ded87d41106e5be3f36da2fdf8d8253f5..1b28ae1de0c29e7400ee23bdf5c5c3a13c73e16d 100644 (file)
@@ -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({{
index b015f8baa6c54dd11d665a6f38504038317a2e2e..7e4dc6ef013eb4e61ff12eab508d76cb0aab8e48 100644 (file)
@@ -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 (file)
index 0000000..97a5a2a
--- /dev/null
@@ -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)
+}};
index 197133d25c267cb34a62548c3ae361b1f9c31589..c830f90858e24e3ca43a9cd9fe71755b4e73136a 100644 (file)
@@ -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"
index d6bdda3992da5525ca76e43df9681f8ac329601a..5e79717e796f520ec8868e1a80c7d84cd19f6c0a 100644 (file)
@@ -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),
 
index 4d9a80601265fe934952ce4c22d9301ba56c106b..cf23c18dfe659c5adfd7d24d53da8eaa9379722b 100644 (file)
@@ -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;
 
index 56aa65f1266ee2febfcb58327f98d36f26973c1f..fc67fc80604267c929acf95308f0e98922b952df 100644 (file)
 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)
 {