#define invalid_pc(pc) ((pc) & 1)
/* Convenience wrappers to simplify softfloat code sequences */
-#define isBoxedF32(r) (((r) & 0xffffffff00000000) == 0xffffffff00000000)
-#define unboxF32(r) (isBoxedF32(r) ? (r) : defaultNaNF32UI)
-#define unboxF64(r) (r)
-struct freg_t { uint64_t v; };
+#define isBoxedF32(r) (isBoxedF64(r) && ((uint32_t)((r.v[0] >> 32) + 1) == 0))
+#define unboxF32(r) (isBoxedF32(r) ? (uint32_t)r.v[0] : defaultNaNF32UI)
+#define isBoxedF64(r) ((r.v[1] + 1) == 0)
+#define unboxF64(r) (isBoxedF64(r) ? r.v[0] : defaultNaNF64UI)
+typedef float128_t freg_t;
inline float32_t f32(uint32_t v) { return { v }; }
inline float64_t f64(uint64_t v) { return { v }; }
-inline float32_t f32(freg_t r) { return f32(unboxF32(r.v)); }
-inline float64_t f64(freg_t r) { return f64(unboxF64(r.v)); }
-inline freg_t freg(float32_t f) { return { ((decltype(freg_t::v))-1 << 32) | f.v }; }
-inline freg_t freg(float64_t f) { return { f.v }; }
-inline freg_t freg(freg_t f) { return f; }
-#define F64_SIGN ((decltype(freg_t::v))1 << 63)
-#define F32_SIGN ((decltype(freg_t::v))1 << 31)
+inline float32_t f32(freg_t r) { return f32(unboxF32(r)); }
+inline float64_t f64(freg_t r) { return f64(unboxF64(r)); }
+inline float128_t f128(freg_t r) { return r; }
+inline freg_t freg(float32_t f) { return { ((uint64_t)-1 << 32) | f.v, (uint64_t)-1 }; }
+inline freg_t freg(float64_t f) { return { f.v, (uint64_t)-1 }; }
+inline freg_t freg(float128_t f) { return f; }
+#define F32_SIGN ((uint32_t)1 << 31)
+#define F64_SIGN ((uint64_t)1 << 63)
#define fsgnj32(a, b, n, x) \
f32((f32(a).v & ~F32_SIGN) | ((((x) ? f32(a).v : (n) ? F32_SIGN : 0) ^ f32(b).v) & F32_SIGN))
#define fsgnj64(a, b, n, x) \
f64((f64(a).v & ~F64_SIGN) | ((((x) ? f64(a).v : (n) ? F64_SIGN : 0) ^ f64(b).v) & F64_SIGN))
+#define isNaNF128(x) isNaNF128UI(x.v[1], x.v[0])
+inline float128_t defaultNaNF128()
+{
+ float128_t nan;
+ nan.v[1] = defaultNaNF128UI64;
+ nan.v[0] = defaultNaNF128UI0;
+ return nan;
+}
+inline freg_t fsgnj128(freg_t a, freg_t b, bool n, bool x)
+{
+ a.v[1] = (a.v[1] & ~F64_SIGN) | (((x ? a.v[1] : n ? F64_SIGN : 0) ^ b.v[1]) & F64_SIGN);
+ return a;
+}
+inline freg_t f128_negate(freg_t a)
+{
+ a.v[1] ^= F64_SIGN;
+ return a;
+}
+
#define validate_csr(which, write) ({ \
if (!STATE.serialized) return PC_SERIALIZE_BEFORE; \
STATE.serialized = false; \
require_extension('C');
require_extension('D');
require_fp;
-MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_FRS2S.v);
+MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_FRS2S.v[0]);
require_extension('C');
require_extension('D');
require_fp;
-MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_FRS2.v);
+MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_FRS2.v[0]);
if (xlen == 32) {
require_extension('F');
require_fp;
- MMU.store_uint32(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S.v);
+ MMU.store_uint32(RVC_RS1S + insn.rvc_lw_imm(), RVC_FRS2S.v[0]);
} else { // c.sd
MMU.store_uint64(RVC_RS1S + insn.rvc_ld_imm(), RVC_RS2S);
}
if (xlen == 32) {
require_extension('F');
require_fp;
- MMU.store_uint32(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2.v);
+ MMU.store_uint32(RVC_SP + insn.rvc_swsp_imm(), RVC_FRS2.v[0]);
} else { // c.sdsp
MMU.store_uint64(RVC_SP + insn.rvc_sdsp_imm(), RVC_RS2);
}
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_add(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_RD(f128_classify(f128(FRS1)));
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_to_f64(f128(FRS1)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_rv64;
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_RD(f128_to_i64(f128(FRS1), RM, true));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_rv64;
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_RD(f128_to_ui64(f128(FRS1), RM, true));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f64_to_f128(f64(FRS1)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_rv64;
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(i64_to_f128(RS1));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_rv64;
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(ui64_to_f128(RS1));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f32_to_f128(f32(FRS1)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(i32_to_f128((int32_t)RS1));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(ui32_to_f128((uint32_t)RS1));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_to_f32(f128(FRS1)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_RD(sext32(f128_to_i32(f128(FRS1), RM, true)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_RD(sext32(f128_to_ui32(f128(FRS1), RM, true)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_div(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_RD(f128_eq(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_RD(f128_le(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_FRD(MMU.load_float128(RS1 + insn.i_imm()));
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_RD(f128_lt(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_mulAdd(f128(FRS1), f128(FRS2), f128(FRS3)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+bool greater = f128_lt_quiet(f128(FRS2), f128(FRS1)) ||
+ (f128_eq(f128(FRS2), f128(FRS1)) && (f128(FRS2).v[1] & F64_SIGN));
+WRITE_FRD(greater || isNaNF128(f128(FRS2)) ? FRS1 : FRS2);
+if (isNaNF128(f128(FRS1)) && isNaNF128(f128(FRS2)))
+ WRITE_FRD(f128(defaultNaNF128()));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+bool less = f128_lt_quiet(f128(FRS1), f128(FRS2)) ||
+ (f128_eq(f128(FRS1), f128(FRS2)) && (f128(FRS1).v[1] & F64_SIGN));
+WRITE_FRD(less || isNaNF128(f128(FRS2)) ? FRS1 : FRS2);
+if (isNaNF128(f128(FRS1)) && isNaNF128(f128(FRS2)))
+ WRITE_FRD(f128(defaultNaNF128()));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_mulAdd(f128(FRS1), f128(FRS2), f128_negate(f128(FRS3))));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_mul(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
require_extension('D');
require_rv64;
require_fp;
-WRITE_RD(FRS1.v);
+WRITE_RD(FRS1.v[0]);
require_extension('F');
require_fp;
-WRITE_RD(sext32(FRS1.v));
+WRITE_RD(sext32(FRS1.v[0]));
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_mulAdd(f128_negate(f128(FRS1)), f128(FRS2), f128_negate(f128(FRS3))));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_mulAdd(f128_negate(f128(FRS1)), f128(FRS2), f128(FRS3)));
+set_fp_exceptions;
require_extension('D');
require_fp;
-MMU.store_uint64(RS1 + insn.s_imm(), FRS2.v);
+MMU.store_uint64(RS1 + insn.s_imm(), FRS2.v[0]);
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_FRD(fsgnj128(FRS1, FRS2, false, false));
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_FRD(fsgnj128(FRS1, FRS2, true, false));
--- /dev/null
+require_extension('Q');
+require_fp;
+WRITE_FRD(fsgnj128(FRS1, FRS2, false, true));
--- /dev/null
+require_extension('Q');
+require_fp;
+MMU.store_float128(RS1 + insn.s_imm(), FRS2);
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_sqrt(f128(FRS1)));
+set_fp_exceptions;
--- /dev/null
+require_extension('Q');
+require_fp;
+softfloat_roundingMode = RM;
+WRITE_FRD(f128_sub(f128(FRS1), f128(FRS2)));
+set_fp_exceptions;
require_extension('F');
require_fp;
-MMU.store_uint32(RS1 + insn.s_imm(), FRS2.v);
+MMU.store_uint32(RS1 + insn.s_imm(), FRS2.v[0]);
void sim_t::interactive_freg(const std::string& cmd, const std::vector<std::string>& args)
{
- fprintf(stderr, "0x%016" PRIx64 "\n", get_freg(args).v);
+ freg_t r = get_freg(args);
+ fprintf(stderr, "0x%016" PRIx64 "%016" PRIx64 "\n", r.v[1], r.v[0]);
}
void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args)
{
fpr f;
f.r = get_freg(args);
- fprintf(stderr, "%g\n",f.s);
+ fprintf(stderr, "%g\n", isBoxedF32(f.r) ? (double)f.s : NAN);
}
void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args)
{
fpr f;
f.r = get_freg(args);
- fprintf(stderr, "%g\n",f.d);
+ fprintf(stderr, "%g\n", isBoxedF64(f.r) ? f.d : NAN);
}
reg_t sim_t::get_mem(const std::vector<std::string>& args)
} \
}
+ void store_float128(reg_t addr, float128_t val)
+ {
+#ifndef RISCV_ENABLE_MISALIGNED
+ if (unlikely(addr & (sizeof(float128_t)-1)))
+ throw trap_store_address_misaligned(addr);
+#endif
+ store_uint64(addr, val.v[0]);
+ store_uint64(addr + 8, val.v[1]);
+ }
+
+ float128_t load_float128(reg_t addr)
+ {
+#ifndef RISCV_ENABLE_MISALIGNED
+ if (unlikely(addr & (sizeof(float128_t)-1)))
+ throw trap_load_address_misaligned(addr);
+#endif
+ return (float128_t){load_uint64(addr), load_uint64(addr + 8)};
+ }
+
// store value to memory at aligned address
store_func(uint8)
store_func(uint16)
lowercase += std::tolower(*r);
const char* p = lowercase.c_str();
- const char* all_subsets = "imafdc";
+ const char* all_subsets = "imafdqc";
max_xlen = 64;
isa = reg_t(2) << 62;
p += 2;
if (!*p) {
- p = all_subsets;
+ p = "imafdc";
} else if (*p == 'g') { // treat "G" as "IMAFD"
tmp = std::string("imafd") + (p+1);
p = &tmp[0];
if (supports_extension('D') && !supports_extension('F'))
bad_isa_string(str);
+ if (supports_extension('Q') && !supports_extension('D'))
+ bad_isa_string(str);
+
+ if (supports_extension('Q') && max_xlen < 64)
+ bad_isa_string(str);
+
// advertise support for supervisor and user modes
isa |= 1L << ('s' - 'a');
isa |= 1L << ('u' - 'a');
ebreak \
ecall \
fadd_d \
+ fadd_q \
fadd_s \
fclass_d \
+ fclass_q \
fclass_s \
fcvt_d_l \
fcvt_d_lu \
+ fcvt_d_q \
fcvt_d_s \
fcvt_d_w \
fcvt_d_wu \
fcvt_l_d \
+ fcvt_l_q \
fcvt_l_s \
fcvt_lu_d \
+ fcvt_lu_q \
fcvt_lu_s \
+ fcvt_q_d \
+ fcvt_q_l \
+ fcvt_q_lu \
+ fcvt_q_s \
+ fcvt_q_w \
+ fcvt_q_wu \
fcvt_s_d \
fcvt_s_l \
fcvt_s_lu \
+ fcvt_s_q \
fcvt_s_w \
fcvt_s_wu \
fcvt_w_d \
+ fcvt_w_q \
fcvt_w_s \
fcvt_wu_d \
+ fcvt_wu_q \
fcvt_wu_s \
fdiv_d \
+ fdiv_q \
fdiv_s \
fence \
fence_i \
feq_d \
+ feq_q \
feq_s \
fld \
fle_d \
+ fle_q \
fle_s \
+ flq \
flt_d \
+ flt_q \
flt_s \
flw \
fmadd_d \
+ fmadd_q \
fmadd_s \
fmax_d \
+ fmax_q \
fmax_s \
fmin_d \
+ fmin_q \
fmin_s \
fmsub_d \
+ fmsub_q \
fmsub_s \
fmul_d \
+ fmul_q \
fmul_s \
fmv_d_x \
fmv_w_x \
fmv_x_d \
fmv_x_w \
fnmadd_d \
+ fnmadd_q \
fnmadd_s \
fnmsub_d \
+ fnmsub_q \
fnmsub_s \
fsd \
fsgnj_d \
+ fsgnj_q \
fsgnjn_d \
+ fsgnjn_q \
fsgnjn_s \
fsgnj_s \
fsgnjx_d \
+ fsgnjx_q \
fsgnjx_s \
+ fsq \
fsqrt_d \
+ fsqrt_q \
fsqrt_s \
fsub_d \
+ fsub_q \
fsub_s \
fsw \
jal \