riscv: [Patch 3/5] Added RISCV floating point extensions RV64FD

Third of five patches adding RISC-V to GEM5. This patch adds the RV64FD
extensions, which include single- and double-precision floating point
instructions.

Patch 1 introduced RISC-V and implemented the base instruction set, RV64I
and patch 2 implemented the integer multiply extension, RV64M.

Patch 4 will implement the atomic memory instructions, RV64A, and patch
5 will add support for timing, minor, and detailed CPU models that is
missing from the first four patches.

[Fixed exception handling in floating-point instructions to conform better
to IEEE-754 2008 standard and behavior of the Chisel-generated RISC-V
simulator.]
[Fixed style errors in decoder.isa.]
[Fixed some fuzz caused by modifying a previous patch.]
Signed-off by: Alec Roelke

Signed-off by: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
Alec Roelke 2016-11-30 17:10:28 -05:00
parent 070da98493
commit 1229b3b623
10 changed files with 1057 additions and 1 deletions

View file

@ -71,6 +71,13 @@ UnimplementedFault::invoke_se(ThreadContext *tc,
tc->pcState().pc()); tc->pcState().pc());
} }
void
IllegalFrmFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
{
panic("Illegal floating-point rounding mode 0x%x at pc 0x%016llx.",
frm, tc->pcState().pc());
}
void void
BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst) BreakpointFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
{ {

View file

@ -40,6 +40,12 @@
namespace RiscvISA namespace RiscvISA
{ {
const uint32_t FloatInexact = 1 << 0;
const uint32_t FloatUnderflow = 1 << 1;
const uint32_t FloatOverflow = 1 << 2;
const uint32_t FloatDivZero = 1 << 3;
const uint32_t FloatInvalid = 1 << 4;
enum ExceptionCode { enum ExceptionCode {
INST_ADDR_MISALIGNED = 0, INST_ADDR_MISALIGNED = 0,
INST_ACCESS = 1, INST_ACCESS = 1,
@ -124,6 +130,20 @@ class UnimplementedFault : public RiscvFault
invoke_se(ThreadContext *tc, const StaticInstPtr &inst); invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
}; };
class IllegalFrmFault: public RiscvFault
{
private:
const uint8_t frm;
public:
IllegalFrmFault(uint8_t r)
: RiscvFault("Illegal floating-point rounding mode", INST_ILLEGAL,
SOFTWARE),
frm(r)
{}
void invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
};
class BreakpointFault : public RiscvFault class BreakpointFault : public RiscvFault
{ {
public: public:

View file

@ -75,3 +75,13 @@ def bitfield UJIMMBITS19TO12 <19:12>;
// System // System
def bitfield FUNCT12 <31:20>; def bitfield FUNCT12 <31:20>;
def bitfield ZIMM <19:15>; def bitfield ZIMM <19:15>;
// Floating point
def bitfield FD <11:7>;
def bitfield FS1 <19:15>;
def bitfield FS2 <24:20>;
def bitfield FS3 <31:27>;
def bitfield ROUND_MODE <14:12>;
def bitfield CONV_SGN <24:20>;
def bitfield FUNCT2 <26:25>;

View 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 { 0x0f: decode FUNCT3 {
format IOp { format IOp {
0x0: fence({{ 0x0: fence({{
@ -144,6 +155,17 @@ decode OPCODE default Unknown::unknown() {
} }
} }
0x27: decode FUNCT3 {
format Store {
0x2: fsw({{
Mem_uw = (uint32_t)Fs2_bits;
}});
0x3: fsd({{
Mem_ud = Fs2_bits;
}});
}
}
0x33: decode FUNCT3 { 0x33: decode FUNCT3 {
format ROp { format ROp {
0x0: decode FUNCT7 { 0x0: decode FUNCT7 {
@ -347,6 +369,813 @@ decode OPCODE default Unknown::unknown() {
} }
} }
format FPR4Op {
0x43: decode FUNCT2 {
0x0: fmadd_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
if (issignalingnan(fs1) || issignalingnan(fs2)
|| issignalingnan(fs3)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else if (std::isinf(fs1) || std::isinf(fs2) ||
std::isinf(fs3)) {
if (std::signbit(fs1) == std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = std::numeric_limits<float>::infinity();
} else if (std::signbit(fs1) != std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = -std::numeric_limits<float>::infinity();
} else { // Fs3_sf is infinity
fd = fs3;
}
} else {
fd = fs1*fs2 + fs3;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatMultOp);
0x1: fmadd_d({{
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|| issignalingnan(Fs3)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
std::isinf(Fs3)) {
if (std::signbit(Fs1) == std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = std::numeric_limits<double>::infinity();
} else if (std::signbit(Fs1) != std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = -std::numeric_limits<double>::infinity();
} else {
Fd = Fs3;
}
} else {
Fd = Fs1*Fs2 + Fs3;
}
}}, FloatMultOp);
}
0x47: decode FUNCT2 {
0x0: fmsub_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
if (issignalingnan(fs1) || issignalingnan(fs2)
|| issignalingnan(fs3)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else if (std::isinf(fs1) || std::isinf(fs2) ||
std::isinf(fs3)) {
if (std::signbit(fs1) == std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = std::numeric_limits<float>::infinity();
} else if (std::signbit(fs1) != std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = -std::numeric_limits<float>::infinity();
} else { // Fs3_sf is infinity
fd = -fs3;
}
} else {
fd = fs1*fs2 - fs3;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatMultOp);
0x1: fmsub_d({{
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|| issignalingnan(Fs3)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
std::isinf(Fs3)) {
if (std::signbit(Fs1) == std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = std::numeric_limits<double>::infinity();
} else if (std::signbit(Fs1) != std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = -std::numeric_limits<double>::infinity();
} else {
Fd = -Fs3;
}
} else {
Fd = Fs1*Fs2 - Fs3;
}
}}, FloatMultOp);
}
0x4b: decode FUNCT2 {
0x0: fnmsub_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
if (issignalingnan(fs1) || issignalingnan(fs2)
|| issignalingnan(fs3)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else if (std::isinf(fs1) || std::isinf(fs2) ||
std::isinf(fs3)) {
if (std::signbit(fs1) == std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = -std::numeric_limits<float>::infinity();
} else if (std::signbit(fs1) != std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = std::numeric_limits<float>::infinity();
} else { // Fs3_sf is infinity
fd = fs3;
}
} else {
fd = -(fs1*fs2 - fs3);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatMultOp);
0x1: fnmsub_d({{
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|| issignalingnan(Fs3)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else if (std::isinf(Fs1) || std::isinf(Fs2)
|| std::isinf(Fs3)) {
if (std::signbit(Fs1) == std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = -std::numeric_limits<double>::infinity();
} else if (std::signbit(Fs1) != std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = std::numeric_limits<double>::infinity();
} else {
Fd = Fs3;
}
} else {
Fd = -(Fs1*Fs2 - Fs3);
}
}}, FloatMultOp);
}
0x4f: decode FUNCT2 {
0x0: fnmadd_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fs3 = reinterpret_cast<float&>(temp = Fs3_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2) || std::isnan(fs3)) {
if (issignalingnan(fs1) || issignalingnan(fs2)
|| issignalingnan(fs3)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else if (std::isinf(fs1) || std::isinf(fs2) ||
std::isinf(fs3)) {
if (std::signbit(fs1) == std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = -std::numeric_limits<float>::infinity();
} else if (std::signbit(fs1) != std::signbit(fs2)
&& !std::isinf(fs3)) {
fd = std::numeric_limits<float>::infinity();
} else { // Fs3_sf is infinity
fd = -fs3;
}
} else {
fd = -(fs1*fs2 + fs3);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatMultOp);
0x1: fnmadd_d({{
if (std::isnan(Fs1) || std::isnan(Fs2) || std::isnan(Fs3)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)
|| issignalingnan(Fs3)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else if (std::isinf(Fs1) || std::isinf(Fs2) ||
std::isinf(Fs3)) {
if (std::signbit(Fs1) == std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = -std::numeric_limits<double>::infinity();
} else if (std::signbit(Fs1) != std::signbit(Fs2)
&& !std::isinf(Fs3)) {
Fd = std::numeric_limits<double>::infinity();
} else {
Fd = -Fs3;
}
} else {
Fd = -(Fs1*Fs2 + Fs3);
}
}}, FloatMultOp);
}
}
0x53: decode FUNCT7 {
format FPROp {
0x0: fadd_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2)) {
if (issignalingnan(fs1) || issignalingnan(fs2)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else {
fd = fs1 + fs2;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatAddOp);
0x1: fadd_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else {
Fd = Fs1 + Fs2;
}
}}, FloatAddOp);
0x4: fsub_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2)) {
if (issignalingnan(fs1) || issignalingnan(fs2)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else {
fd = fs1 - fs2;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatAddOp);
0x5: fsub_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else {
Fd = Fs1 - Fs2;
}
}}, FloatAddOp);
0x8: fmul_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2)) {
if (issignalingnan(fs1) || issignalingnan(fs2)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else {
fd = fs1*fs2;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatMultOp);
0x9: fmul_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else {
Fd = Fs1*Fs2;
}
}}, FloatMultOp);
0xc: fdiv_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (std::isnan(fs1) || std::isnan(fs2)) {
if (issignalingnan(fs1) || issignalingnan(fs2)) {
FFLAGS |= FloatInvalid;
}
fd = std::numeric_limits<float>::quiet_NaN();
} else {
fd = fs1/fs2;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatDivOp);
0xd: fdiv_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
FFLAGS |= FloatInvalid;
}
Fd = std::numeric_limits<double>::quiet_NaN();
} else {
Fd = Fs1/Fs2;
}
}}, FloatDivOp);
0x10: decode ROUND_MODE {
0x0: fsgnj_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (issignalingnan(fs1)) {
fd = std::numeric_limits<float>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
fd = std::copysign(fs1, fs2);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}});
0x1: fsgnjn_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (issignalingnan(fs1)) {
fd = std::numeric_limits<float>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
fd = std::copysign(fs1, -fs2);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}});
0x2: fsgnjx_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (issignalingnan(fs1)) {
fd = std::numeric_limits<float>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
fd = fs1*(std::signbit(fs2) ? -1.0 : 1.0);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}});
}
0x11: decode ROUND_MODE {
0x0: fsgnj_d({{
if (issignalingnan(Fs1)) {
Fd = std::numeric_limits<double>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
Fd = std::copysign(Fs1, Fs2);
}
}});
0x1: fsgnjn_d({{
if (issignalingnan(Fs1)) {
Fd = std::numeric_limits<double>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
Fd = std::copysign(Fs1, -Fs2);
}
}});
0x2: fsgnjx_d({{
if (issignalingnan(Fs1)) {
Fd = std::numeric_limits<double>::signaling_NaN();
std::feclearexcept(FE_INVALID);
} else {
Fd = Fs1*(std::signbit(Fs2) ? -1.0 : 1.0);
}
}});
}
0x14: decode ROUND_MODE {
0x0: fmin_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (issignalingnan(fs2)) {
fd = fs1;
FFLAGS |= FloatInvalid;
} else if (issignalingnan(fs1)) {
fd = fs2;
FFLAGS |= FloatInvalid;
} else {
fd = std::fmin(fs1, fs2);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatCmpOp);
0x1: fmax_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
float fd;
if (issignalingnan(fs2)) {
fd = fs1;
FFLAGS |= FloatInvalid;
} else if (issignalingnan(fs1)) {
fd = fs2;
FFLAGS |= FloatInvalid;
} else {
fd = std::fmax(fs1, fs2);
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatCmpOp);
}
0x15: decode ROUND_MODE {
0x0: fmin_d({{
if (issignalingnan(Fs2)) {
Fd = Fs1;
FFLAGS |= FloatInvalid;
} else if (issignalingnan(Fs1)) {
Fd = Fs2;
FFLAGS |= FloatInvalid;
} else {
Fd = std::fmin(Fs1, Fs2);
}
}}, FloatCmpOp);
0x1: fmax_d({{
if (issignalingnan(Fs2)) {
Fd = Fs1;
FFLAGS |= FloatInvalid;
} else if (issignalingnan(Fs1)) {
Fd = Fs2;
FFLAGS |= FloatInvalid;
} else {
Fd = std::fmax(Fs1, Fs2);
}
}}, FloatCmpOp);
}
0x20: fcvt_s_d({{
assert(CONV_SGN == 1);
float fd;
if (issignalingnan(Fs1)) {
fd = std::numeric_limits<float>::quiet_NaN();
FFLAGS |= FloatInvalid;
} else {
fd = (float)Fs1;
}
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatCvtOp);
0x21: fcvt_d_s({{
assert(CONV_SGN == 0);
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
if (issignalingnan(fs1)) {
Fd = std::numeric_limits<double>::quiet_NaN();
FFLAGS |= FloatInvalid;
} else {
Fd = (double)fs1;
}
}}, FloatCvtOp);
0x2c: fsqrt_s({{
assert(RS2 == 0);
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fd;
if (issignalingnan(Fs1_sf)) {
FFLAGS |= FloatInvalid;
}
fd = std::sqrt(fs1);
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(fd);
}}, FloatSqrtOp);
0x2d: fsqrt_d({{
assert(RS2 == 0);
Fd = std::sqrt(Fs1);
}}, FloatSqrtOp);
0x50: decode ROUND_MODE {
0x0: fle_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
if (std::isnan(fs1) || std::isnan(fs2)) {
FFLAGS |= FloatInvalid;
Rd = 0;
} else {
Rd = fs1 <= fs2 ? 1 : 0;
}
}}, FloatCmpOp);
0x1: flt_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
if (std::isnan(fs1) || std::isnan(fs2)) {
FFLAGS |= FloatInvalid;
Rd = 0;
} else {
Rd = fs1 < fs2 ? 1 : 0;
}
}}, FloatCmpOp);
0x2: feq_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
float fs2 = reinterpret_cast<float&>(temp = Fs2_bits);
if (issignalingnan(fs1) || issignalingnan(fs2)) {
FFLAGS |= FloatInvalid;
}
Rd = fs1 == fs2 ? 1 : 0;
}}, FloatCmpOp);
}
0x51: decode ROUND_MODE {
0x0: fle_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
FFLAGS |= FloatInvalid;
Rd = 0;
} else {
Rd = Fs1 <= Fs2 ? 1 : 0;
}
}}, FloatCmpOp);
0x1: flt_d({{
if (std::isnan(Fs1) || std::isnan(Fs2)) {
FFLAGS |= FloatInvalid;
Rd = 0;
} else {
Rd = Fs1 < Fs2 ? 1 : 0;
}
}}, FloatCmpOp);
0x2: feq_d({{
if (issignalingnan(Fs1) || issignalingnan(Fs2)) {
FFLAGS |= FloatInvalid;
}
Rd = Fs1 == Fs2 ? 1 : 0;
}}, FloatCmpOp);
}
0x60: decode CONV_SGN {
0x0: fcvt_w_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
if (std::isnan(fs1)) {
Rd_sd = std::numeric_limits<int32_t>::max();
FFLAGS |= FloatInvalid;
} else {
Rd_sd = (int32_t)fs1;
if (std::fetestexcept(FE_INVALID)) {
if (std::signbit(fs1)) {
Rd_sd = std::numeric_limits<int32_t>::min();
} else {
Rd_sd = std::numeric_limits<int32_t>::max();
}
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
0x1: fcvt_wu_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
if (fs1 < 0.0) {
Rd = 0;
FFLAGS |= FloatInvalid;
} else {
Rd = (uint32_t)fs1;
if (std::fetestexcept(FE_INVALID)) {
Rd = std::numeric_limits<uint64_t>::max();
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
0x2: fcvt_l_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
if (std::isnan(fs1)) {
Rd_sd = std::numeric_limits<int64_t>::max();
FFLAGS |= FloatInvalid;
} else {
Rd_sd = (int64_t)fs1;
if (std::fetestexcept(FE_INVALID)) {
if (std::signbit(fs1)) {
Rd_sd = std::numeric_limits<int64_t>::min();
} else {
Rd_sd = std::numeric_limits<int64_t>::max();
}
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
0x3: fcvt_lu_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
if (fs1 < 0.0) {
Rd = 0;
FFLAGS |= FloatInvalid;
} else {
Rd = (uint64_t)fs1;
if (std::fetestexcept(FE_INVALID)) {
Rd = std::numeric_limits<uint64_t>::max();
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
}
0x61: decode CONV_SGN {
0x0: fcvt_w_d({{
Rd_sd = (int32_t)Fs1;
if (std::fetestexcept(FE_INVALID)) {
if (Fs1 < 0.0) {
Rd_sd = std::numeric_limits<int32_t>::min();
} else {
Rd_sd = std::numeric_limits<int32_t>::max();
}
std::feclearexcept(FE_INEXACT);
}
}}, FloatCvtOp);
0x1: fcvt_wu_d({{
if (Fs1 < 0.0) {
Rd = 0;
FFLAGS |= FloatInvalid;
} else {
Rd = (uint32_t)Fs1;
if (std::fetestexcept(FE_INVALID)) {
Rd = std::numeric_limits<uint64_t>::max();
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
0x2: fcvt_l_d({{
Rd_sd = Fs1;
if (std::fetestexcept(FE_INVALID)) {
if (Fs1 < 0.0) {
Rd_sd = std::numeric_limits<int64_t>::min();
} else {
Rd_sd = std::numeric_limits<int64_t>::max();
}
std::feclearexcept(FE_INEXACT);
}
}}, FloatCvtOp);
0x3: fcvt_lu_d({{
if (Fs1 < 0.0) {
Rd = 0;
FFLAGS |= FloatInvalid;
} else {
Rd = (uint64_t)Fs1;
if (std::fetestexcept(FE_INVALID)) {
Rd = std::numeric_limits<uint64_t>::max();
std::feclearexcept(FE_INEXACT);
}
}
}}, FloatCvtOp);
}
0x68: decode CONV_SGN {
0x0: fcvt_s_w({{
float temp = (float)Rs1_sw;
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
}}, FloatCvtOp);
0x1: fcvt_s_wu({{
float temp = (float)Rs1_uw;
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
}}, FloatCvtOp);
0x2: fcvt_s_l({{
float temp = (float)Rs1_sd;
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
}}, FloatCvtOp);
0x3: fcvt_s_lu({{
float temp = (float)Rs1;
Fd_bits = (uint64_t)reinterpret_cast<uint32_t&>(temp);
}}, FloatCvtOp);
}
0x69: decode CONV_SGN {
0x0: fcvt_d_w({{
Fd = (double)Rs1_sw;
}}, FloatCvtOp);
0x1: fcvt_d_wu({{
Fd = (double)Rs1_uw;
}}, FloatCvtOp);
0x2: fcvt_d_l({{
Fd = (double)Rs1_sd;
}}, FloatCvtOp);
0x3: fcvt_d_lu({{
Fd = (double)Rs1;
}}, FloatCvtOp);
}
0x70: decode ROUND_MODE {
0x0: fmv_x_s({{
Rd = (uint32_t)Fs1_bits;
if ((Rd&0x80000000) != 0) {
Rd |= (0xFFFFFFFFULL << 32);
}
}}, FloatCvtOp);
0x1: fclass_s({{
uint32_t temp;
float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
switch (std::fpclassify(fs1)) {
case FP_INFINITE:
if (std::signbit(fs1)) {
Rd = 1 << 0;
} else {
Rd = 1 << 7;
}
break;
case FP_NAN:
if (issignalingnan(fs1)) {
Rd = 1 << 8;
} else {
Rd = 1 << 9;
}
break;
case FP_ZERO:
if (std::signbit(fs1)) {
Rd = 1 << 3;
} else {
Rd = 1 << 4;
}
break;
case FP_SUBNORMAL:
if (std::signbit(fs1)) {
Rd = 1 << 2;
} else {
Rd = 1 << 5;
}
break;
case FP_NORMAL:
if (std::signbit(fs1)) {
Rd = 1 << 1;
} else {
Rd = 1 << 6;
}
break;
default:
panic("Unknown classification for operand.");
break;
}
}});
}
0x71: decode ROUND_MODE {
0x0: fmv_x_d({{
Rd = Fs1_bits;
}}, FloatCvtOp);
0x1: fclass_d({{
switch (std::fpclassify(Fs1)) {
case FP_INFINITE:
if (std::signbit(Fs1)) {
Rd = 1 << 0;
} else {
Rd = 1 << 7;
}
break;
case FP_NAN:
if (issignalingnan(Fs1)) {
Rd = 1 << 8;
} else {
Rd = 1 << 9;
}
break;
case FP_ZERO:
if (std::signbit(Fs1)) {
Rd = 1 << 3;
} else {
Rd = 1 << 4;
}
break;
case FP_SUBNORMAL:
if (std::signbit(Fs1)) {
Rd = 1 << 2;
} else {
Rd = 1 << 5;
}
break;
case FP_NORMAL:
if (std::signbit(Fs1)) {
Rd = 1 << 1;
} else {
Rd = 1 << 6;
}
break;
default:
panic("Unknown classification for operand.");
break;
}
}});
}
0x78: fmv_s_x({{
Fd_bits = (uint64_t)Rs1_uw;
}}, FloatCvtOp);
0x79: fmv_d_x({{
Fd_bits = Rs1;
}}, FloatCvtOp);
}
}
0x63: decode FUNCT3 { 0x63: decode FUNCT3 {
format SBOp { format SBOp {
0x0: beq({{ 0x0: beq({{

View file

@ -36,6 +36,7 @@
//Include the type formats //Include the type formats
##include "type.isa" ##include "type.isa"
##include "mem.isa" ##include "mem.isa"
##include "fp.isa"
// Include the unknown // Include the unknown
##include "unknown.isa" ##include "unknown.isa"

View file

@ -0,0 +1,136 @@
// -*- mode:c++ -*-
// Copyright (c) 2015 Riscv Developers
// Copyright (c) 2016 The University of Virginia
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Alec Roelke
////////////////////////////////////////////////////////////////////
//
// Floating point operation instructions
//
def template FloatExecute {{
Fault %(class_name)s::execute(CPU_EXEC_CONTEXT *xc,
Trace::InstRecord *traceData) const
{
Fault fault = NoFault;
%(op_decl)s;
%(op_rd)s;
if (fault == NoFault) {
switch (ROUND_MODE) {
case 0x0:
std::fesetround(FE_TONEAREST);
break;
case 0x1:
std::fesetround(FE_TOWARDZERO);
break;
case 0x2:
std::fesetround(FE_DOWNWARD);
break;
case 0x3:
std::fesetround(FE_UPWARD);
break;
case 0x4:
panic("Round to nearest, "
"ties to max magnitude not implemented.");
break;
case 0x7: {
uint8_t frm = xc->readMiscReg(MISCREG_FRM);
switch (frm) {
case 0x0:
std::fesetround(FE_TONEAREST);
break;
case 0x1:
std::fesetround(FE_TOWARDZERO);
break;
case 0x2:
std::fesetround(FE_DOWNWARD);
break;
case 0x3:
std::fesetround(FE_UPWARD);
break;
case 0x4:
panic("Round to nearest,"
" ties to max magnitude not implemented.");
break;
default:
fault = std::make_shared<IllegalFrmFault>(frm);
break;
}
break;
}
default:
fault = std::make_shared<IllegalFrmFault>(ROUND_MODE);
break;
}
if (fault == NoFault) {
MiscReg FFLAGS = xc->readMiscReg(MISCREG_FFLAGS);
std::feclearexcept(FE_ALL_EXCEPT);
%(code)s;
if (std::fetestexcept(FE_INEXACT)) {
FFLAGS |= FloatInexact;
}
if (std::fetestexcept(FE_UNDERFLOW)) {
FFLAGS |= FloatUnderflow;
}
if (std::fetestexcept(FE_OVERFLOW)) {
FFLAGS |= FloatOverflow;
}
if (std::fetestexcept(FE_DIVBYZERO)) {
FFLAGS |= FloatDivZero;
}
if (std::fetestexcept(FE_INVALID)) {
FFLAGS |= FloatInvalid;
}
xc->setMiscReg(MISCREG_FFLAGS, FFLAGS);
}
if (fault == NoFault) {
%(op_wb)s;
}
}
return fault;
}
}};
def format FPROp(code, *opt_flags) {{
iop = InstObjParams(name, Name, 'ROp', code, opt_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = FloatExecute.subst(iop)
}};
def format FPR4Op(code, *opt_flags) {{
iop = InstObjParams(name, Name, 'ROp', code, opt_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = FloatExecute.subst(iop)
}};

View file

@ -68,12 +68,14 @@ using namespace RiscvISA;
}}; }};
output exec {{ output exec {{
#include <cfenv>
#include <cmath> #include <cmath>
#include <string> #include <string>
#include "arch/generic/memhelpers.hh" #include "arch/generic/memhelpers.hh"
#include "arch/riscv/faults.hh" #include "arch/riscv/faults.hh"
#include "arch/riscv/registers.hh" #include "arch/riscv/registers.hh"
#include "arch/riscv/utility.hh"
#include "base/condcodes.hh" #include "base/condcodes.hh"
#include "cpu/base.hh" #include "cpu/base.hh"
#include "cpu/exetrace.hh" #include "cpu/exetrace.hh"

View file

@ -39,6 +39,8 @@ def operand_types {{
'uw' : 'uint32_t', 'uw' : 'uint32_t',
'sd' : 'int64_t', 'sd' : 'int64_t',
'ud' : 'uint64_t', 'ud' : 'uint64_t',
'sf' : 'float',
'df' : 'double'
}}; }};
def operands {{ def operands {{
@ -47,6 +49,15 @@ def operands {{
'Rs1': ('IntReg', 'ud', 'RS1', 'IsInteger', 2), 'Rs1': ('IntReg', 'ud', 'RS1', 'IsInteger', 2),
'Rs2': ('IntReg', 'ud', 'RS2', 'IsInteger', 3), 'Rs2': ('IntReg', 'ud', 'RS2', 'IsInteger', 3),
'Fd': ('FloatReg', 'df', 'FD', 'IsFloating', 1),
'Fd_bits': ('FloatReg', 'ud', 'FD', 'IsFloating', 1),
'Fs1': ('FloatReg', 'df', 'FS1', 'IsFloating', 2),
'Fs1_bits': ('FloatReg', 'ud', 'FS1', 'IsFloating', 2),
'Fs2': ('FloatReg', 'df', 'FS2', 'IsFloating', 3),
'Fs2_bits': ('FloatReg', 'ud', 'FS2', 'IsFloating', 3),
'Fs3': ('FloatReg', 'df', 'FS3', 'IsFloating', 4),
'Fs3_bits': ('FloatReg', 'ud', 'FS3', 'IsFloating', 4),
#Memory Operand #Memory Operand
'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 5), 'Mem': ('Mem', 'ud', None, ('IsMemRef', 'IsLoad', 'IsStore'), 5),

View file

@ -69,7 +69,7 @@ typedef uint64_t MiscReg;
const int NumIntArchRegs = 32; const int NumIntArchRegs = 32;
const int NumIntRegs = NumIntArchRegs; const int NumIntRegs = NumIntArchRegs;
const int NumFloatRegs = 0; const int NumFloatRegs = 32;
const int NumCCRegs = 0; const int NumCCRegs = 0;
const int NumMiscRegs = 4096; const int NumMiscRegs = 4096;

View file

@ -56,6 +56,46 @@
namespace RiscvISA namespace RiscvISA
{ {
template<typename T> inline bool
isquietnan(T val)
{
return false;
}
template<> inline bool
isquietnan<float>(float val)
{
return std::isnan(val)
&& (reinterpret_cast<uint32_t&>(val)&0x00400000);
}
template<> inline bool
isquietnan<double>(double val)
{
return std::isnan(val)
&& (reinterpret_cast<uint64_t&>(val)&0x0008000000000000ULL);
}
template<typename T> inline bool
issignalingnan(T val)
{
return false;
}
template<> inline bool
issignalingnan<float>(float val)
{
return std::isnan(val)
&& (reinterpret_cast<uint32_t&>(val)&0x00200000);
}
template<> inline bool
issignalingnan<double>(double val)
{
return std::isnan(val)
&& (reinterpret_cast<uint64_t&>(val)&0x0004000000000000ULL);
}
inline PCState inline PCState
buildRetPC(const PCState &curPC, const PCState &callPC) buildRetPC(const PCState &curPC, const PCState &callPC)
{ {