From 1229b3b62303e00693cfb052fca6e4f7879cf0af Mon Sep 17 00:00:00 2001 From: Alec Roelke Date: Wed, 30 Nov 2016 17:10:28 -0500 Subject: [PATCH] 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 --- src/arch/riscv/faults.cc | 7 + src/arch/riscv/faults.hh | 20 + src/arch/riscv/isa/bitfields.isa | 10 + src/arch/riscv/isa/decoder.isa | 829 +++++++++++++++++++++++++ src/arch/riscv/isa/formats/formats.isa | 1 + src/arch/riscv/isa/formats/fp.isa | 136 ++++ src/arch/riscv/isa/includes.isa | 2 + src/arch/riscv/isa/operands.isa | 11 + src/arch/riscv/registers.hh | 2 +- src/arch/riscv/utility.hh | 40 ++ 10 files changed, 1057 insertions(+), 1 deletion(-) create mode 100644 src/arch/riscv/isa/formats/fp.isa 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 @@ -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) { 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(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fs3 = reinterpret_cast(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::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::infinity(); + } else if (std::signbit(fs1) != std::signbit(fs2) + && !std::isinf(fs3)) { + fd = -std::numeric_limits::infinity(); + } else { // Fs3_sf is infinity + fd = fs3; + } + } else { + fd = fs1*fs2 + fs3; + } + Fd_bits = (uint64_t)reinterpret_cast(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::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::infinity(); + } else if (std::signbit(Fs1) != std::signbit(Fs2) + && !std::isinf(Fs3)) { + Fd = -std::numeric_limits::infinity(); + } else { + Fd = Fs3; + } + } else { + Fd = Fs1*Fs2 + Fs3; + } + }}, FloatMultOp); + } + 0x47: decode FUNCT2 { + 0x0: fmsub_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fs3 = reinterpret_cast(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::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::infinity(); + } else if (std::signbit(fs1) != std::signbit(fs2) + && !std::isinf(fs3)) { + fd = -std::numeric_limits::infinity(); + } else { // Fs3_sf is infinity + fd = -fs3; + } + } else { + fd = fs1*fs2 - fs3; + } + Fd_bits = (uint64_t)reinterpret_cast(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::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::infinity(); + } else if (std::signbit(Fs1) != std::signbit(Fs2) + && !std::isinf(Fs3)) { + Fd = -std::numeric_limits::infinity(); + } else { + Fd = -Fs3; + } + } else { + Fd = Fs1*Fs2 - Fs3; + } + }}, FloatMultOp); + } + 0x4b: decode FUNCT2 { + 0x0: fnmsub_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fs3 = reinterpret_cast(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::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::infinity(); + } else if (std::signbit(fs1) != std::signbit(fs2) + && !std::isinf(fs3)) { + fd = std::numeric_limits::infinity(); + } else { // Fs3_sf is infinity + fd = fs3; + } + } else { + fd = -(fs1*fs2 - fs3); + } + Fd_bits = (uint64_t)reinterpret_cast(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::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::infinity(); + } else if (std::signbit(Fs1) != std::signbit(Fs2) + && !std::isinf(Fs3)) { + Fd = std::numeric_limits::infinity(); + } else { + Fd = Fs3; + } + } else { + Fd = -(Fs1*Fs2 - Fs3); + } + }}, FloatMultOp); + } + 0x4f: decode FUNCT2 { + 0x0: fnmadd_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fs3 = reinterpret_cast(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::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::infinity(); + } else if (std::signbit(fs1) != std::signbit(fs2) + && !std::isinf(fs3)) { + fd = std::numeric_limits::infinity(); + } else { // Fs3_sf is infinity + fd = -fs3; + } + } else { + fd = -(fs1*fs2 + fs3); + } + Fd_bits = (uint64_t)reinterpret_cast(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::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::infinity(); + } else if (std::signbit(Fs1) != std::signbit(Fs2) + && !std::isinf(Fs3)) { + Fd = std::numeric_limits::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(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (std::isnan(fs1) || std::isnan(fs2)) { + if (issignalingnan(fs1) || issignalingnan(fs2)) { + FFLAGS |= FloatInvalid; + } + fd = std::numeric_limits::quiet_NaN(); + } else { + fd = fs1 + fs2; + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}, FloatAddOp); + 0x1: fadd_d({{ + if (std::isnan(Fs1) || std::isnan(Fs2)) { + if (issignalingnan(Fs1) || issignalingnan(Fs2)) { + FFLAGS |= FloatInvalid; + } + Fd = std::numeric_limits::quiet_NaN(); + } else { + Fd = Fs1 + Fs2; + } + }}, FloatAddOp); + 0x4: fsub_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (std::isnan(fs1) || std::isnan(fs2)) { + if (issignalingnan(fs1) || issignalingnan(fs2)) { + FFLAGS |= FloatInvalid; + } + fd = std::numeric_limits::quiet_NaN(); + } else { + fd = fs1 - fs2; + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}, FloatAddOp); + 0x5: fsub_d({{ + if (std::isnan(Fs1) || std::isnan(Fs2)) { + if (issignalingnan(Fs1) || issignalingnan(Fs2)) { + FFLAGS |= FloatInvalid; + } + Fd = std::numeric_limits::quiet_NaN(); + } else { + Fd = Fs1 - Fs2; + } + }}, FloatAddOp); + 0x8: fmul_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (std::isnan(fs1) || std::isnan(fs2)) { + if (issignalingnan(fs1) || issignalingnan(fs2)) { + FFLAGS |= FloatInvalid; + } + fd = std::numeric_limits::quiet_NaN(); + } else { + fd = fs1*fs2; + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}, FloatMultOp); + 0x9: fmul_d({{ + if (std::isnan(Fs1) || std::isnan(Fs2)) { + if (issignalingnan(Fs1) || issignalingnan(Fs2)) { + FFLAGS |= FloatInvalid; + } + Fd = std::numeric_limits::quiet_NaN(); + } else { + Fd = Fs1*Fs2; + } + }}, FloatMultOp); + 0xc: fdiv_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (std::isnan(fs1) || std::isnan(fs2)) { + if (issignalingnan(fs1) || issignalingnan(fs2)) { + FFLAGS |= FloatInvalid; + } + fd = std::numeric_limits::quiet_NaN(); + } else { + fd = fs1/fs2; + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}, FloatDivOp); + 0xd: fdiv_d({{ + if (std::isnan(Fs1) || std::isnan(Fs2)) { + if (issignalingnan(Fs1) || issignalingnan(Fs2)) { + FFLAGS |= FloatInvalid; + } + Fd = std::numeric_limits::quiet_NaN(); + } else { + Fd = Fs1/Fs2; + } + }}, FloatDivOp); + 0x10: decode ROUND_MODE { + 0x0: fsgnj_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (issignalingnan(fs1)) { + fd = std::numeric_limits::signaling_NaN(); + std::feclearexcept(FE_INVALID); + } else { + fd = std::copysign(fs1, fs2); + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}); + 0x1: fsgnjn_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (issignalingnan(fs1)) { + fd = std::numeric_limits::signaling_NaN(); + std::feclearexcept(FE_INVALID); + } else { + fd = std::copysign(fs1, -fs2); + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}); + 0x2: fsgnjx_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(temp = Fs2_bits); + float fd; + + if (issignalingnan(fs1)) { + fd = std::numeric_limits::signaling_NaN(); + std::feclearexcept(FE_INVALID); + } else { + fd = fs1*(std::signbit(fs2) ? -1.0 : 1.0); + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}); + } + 0x11: decode ROUND_MODE { + 0x0: fsgnj_d({{ + if (issignalingnan(Fs1)) { + Fd = std::numeric_limits::signaling_NaN(); + std::feclearexcept(FE_INVALID); + } else { + Fd = std::copysign(Fs1, Fs2); + } + }}); + 0x1: fsgnjn_d({{ + if (issignalingnan(Fs1)) { + Fd = std::numeric_limits::signaling_NaN(); + std::feclearexcept(FE_INVALID); + } else { + Fd = std::copysign(Fs1, -Fs2); + } + }}); + 0x2: fsgnjx_d({{ + if (issignalingnan(Fs1)) { + Fd = std::numeric_limits::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(temp = Fs1_bits); + float fs2 = reinterpret_cast(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(fd); + }}, FloatCmpOp); + 0x1: fmax_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fs2 = reinterpret_cast(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(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::quiet_NaN(); + FFLAGS |= FloatInvalid; + } else { + fd = (float)Fs1; + } + Fd_bits = (uint64_t)reinterpret_cast(fd); + }}, FloatCvtOp); + 0x21: fcvt_d_s({{ + assert(CONV_SGN == 0); + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + + if (issignalingnan(fs1)) { + Fd = std::numeric_limits::quiet_NaN(); + FFLAGS |= FloatInvalid; + } else { + Fd = (double)fs1; + } + }}, FloatCvtOp); + 0x2c: fsqrt_s({{ + assert(RS2 == 0); + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + float fd; + + if (issignalingnan(Fs1_sf)) { + FFLAGS |= FloatInvalid; + } + fd = std::sqrt(fs1); + Fd_bits = (uint64_t)reinterpret_cast(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(temp = Fs1_bits); + float fs2 = reinterpret_cast(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(temp = Fs1_bits); + float fs2 = reinterpret_cast(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(temp = Fs1_bits); + float fs2 = reinterpret_cast(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(temp = Fs1_bits); + + if (std::isnan(fs1)) { + Rd_sd = std::numeric_limits::max(); + FFLAGS |= FloatInvalid; + } else { + Rd_sd = (int32_t)fs1; + if (std::fetestexcept(FE_INVALID)) { + if (std::signbit(fs1)) { + Rd_sd = std::numeric_limits::min(); + } else { + Rd_sd = std::numeric_limits::max(); + } + std::feclearexcept(FE_INEXACT); + } + } + }}, FloatCvtOp); + 0x1: fcvt_wu_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(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::max(); + std::feclearexcept(FE_INEXACT); + } + } + }}, FloatCvtOp); + 0x2: fcvt_l_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(temp = Fs1_bits); + + if (std::isnan(fs1)) { + Rd_sd = std::numeric_limits::max(); + FFLAGS |= FloatInvalid; + } else { + Rd_sd = (int64_t)fs1; + if (std::fetestexcept(FE_INVALID)) { + if (std::signbit(fs1)) { + Rd_sd = std::numeric_limits::min(); + } else { + Rd_sd = std::numeric_limits::max(); + } + std::feclearexcept(FE_INEXACT); + } + } + }}, FloatCvtOp); + 0x3: fcvt_lu_s({{ + uint32_t temp; + float fs1 = reinterpret_cast(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::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::min(); + } else { + Rd_sd = std::numeric_limits::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::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::min(); + } else { + Rd_sd = std::numeric_limits::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::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(temp); + }}, FloatCvtOp); + 0x1: fcvt_s_wu({{ + float temp = (float)Rs1_uw; + Fd_bits = (uint64_t)reinterpret_cast(temp); + }}, FloatCvtOp); + 0x2: fcvt_s_l({{ + float temp = (float)Rs1_sd; + Fd_bits = (uint64_t)reinterpret_cast(temp); + }}, FloatCvtOp); + 0x3: fcvt_s_lu({{ + float temp = (float)Rs1; + Fd_bits = (uint64_t)reinterpret_cast(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(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(frm); + break; + } + break; + } + default: + fault = std::make_shared(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 #include #include #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 inline bool +isquietnan(T val) +{ + return false; +} + +template<> inline bool +isquietnan(float val) +{ + return std::isnan(val) + && (reinterpret_cast(val)&0x00400000); +} + +template<> inline bool +isquietnan(double val) +{ + return std::isnan(val) + && (reinterpret_cast(val)&0x0008000000000000ULL); +} + +template inline bool +issignalingnan(T val) +{ + return false; +} + +template<> inline bool +issignalingnan(float val) +{ + return std::isnan(val) + && (reinterpret_cast(val)&0x00200000); +} + +template<> inline bool +issignalingnan(double val) +{ + return std::isnan(val) + && (reinterpret_cast(val)&0x0004000000000000ULL); +} + inline PCState buildRetPC(const PCState &curPC, const PCState &callPC) {