Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix rounding mode selection #323

Merged
merged 1 commit into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ static inline void decode_r4type(rv_insn_t *ir, const uint32_t insn)
ir->rs1 = decode_rs1(insn);
ir->rs2 = decode_rs2(insn);
ir->rs3 = decode_r4type_rs3(insn);
ir->rm = decode_funct3(insn);
}
#endif

Expand Down Expand Up @@ -1044,7 +1045,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
*/

/* decode R-type */
uint8_t funct3 = decode_funct3(insn);
ir->rm = decode_funct3(insn);
decode_rtype(ir, insn);

/* dispatch from funct7 field */
Expand All @@ -1066,7 +1067,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b0010000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FSGNJ.S */
ir->opcode = rv_insn_fsgnjs;
break;
Expand All @@ -1093,7 +1094,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b0010100:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FMIN.S */
ir->opcode = rv_insn_fmins;
break;
Expand All @@ -1106,7 +1107,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b1110000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FMV.X.W */
ir->opcode = rv_insn_fmvxw;
break;
Expand All @@ -1119,7 +1120,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b1010000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b010: /* FEQ.S */
ir->opcode = rv_insn_feqs;
break;
Expand Down
14 changes: 14 additions & 0 deletions src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,20 @@ typedef struct rv_insn {
#if RV32_HAS(EXT_C)
uint8_t shamt;
#endif

#if RV32_HAS(EXT_F)
/* Floating-point operations use either a static rounding mode encoded in
* the instruction, or a dynamic rounding mode held in frm. A value of 111
* in the instruction’s rm field selects the dynamic rounding mode held in
* frm. If frm is set to an invalid value (101–111), any subsequent attempt
* to execute a floating-point operation with a dynamic rounding mode will
* cause an illegal instruction trap. Some instructions that have the rm
* field are nevertheless unaffected by the rounding mode; they should have
* their rm field set to RNE (000).
*/
uint8_t rm;
jserv marked this conversation as resolved.
Show resolved Hide resolved
#endif

/* fuse operation */
int32_t imm2;
opcode_fuse_t *fuse;
Expand Down
71 changes: 55 additions & 16 deletions src/rv32_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,10 @@ RVOP(
RVOP(
fmadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] =
f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], rv->F[ir->rs3]);
set_fflag(rv);
Expand All @@ -1426,7 +1429,10 @@ RVOP(
RVOP(
fmsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp = rv->F[ir->rs3];
tmp.v ^= FMASK_SIGN;
rv->F[ir->rd] = f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], tmp);
Expand All @@ -1440,7 +1446,10 @@ RVOP(
RVOP(
fnmsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp = rv->F[ir->rs1];
tmp.v ^= FMASK_SIGN;
rv->F[ir->rd] = f32_mulAdd(tmp, rv->F[ir->rs2], rv->F[ir->rs3]);
Expand All @@ -1454,7 +1463,10 @@ RVOP(
RVOP(
fnmadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp1 = rv->F[ir->rs1];
riscv_float_t tmp2 = rv->F[ir->rs3];
tmp1.v ^= FMASK_SIGN;
Expand All @@ -1470,7 +1482,10 @@ RVOP(
RVOP(
fadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_add(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1482,7 +1497,10 @@ RVOP(
RVOP(
fsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_sub(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1494,7 +1512,10 @@ RVOP(
RVOP(
fmuls,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_mul(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1506,7 +1527,10 @@ RVOP(
RVOP(
fdivs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_div(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1518,7 +1542,10 @@ RVOP(
RVOP(
fsqrts,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_sqrt(rv->F[ir->rs1]);
set_fflag(rv);
},
Expand Down Expand Up @@ -1611,7 +1638,10 @@ RVOP(
RVOP(
fcvtws,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
uint32_t ret = f32_to_i32(rv->F[ir->rs1], softfloat_roundingMode, true);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1625,7 +1655,10 @@ RVOP(
RVOP(
fcvtwus,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
uint32_t ret =
f32_to_ui32(rv->F[ir->rs1], softfloat_roundingMode, true);
if (ir->rd)
Expand Down Expand Up @@ -1653,7 +1686,7 @@ RVOP(
RVOP(
feqs,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_eq(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1670,7 +1703,7 @@ RVOP(
RVOP(
flts,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_lt(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1683,7 +1716,7 @@ RVOP(
RVOP(
fles,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_le(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1708,7 +1741,10 @@ RVOP(
RVOP(
fcvtsw,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = i32_to_f32(rv->X[ir->rs1]);
set_fflag(rv);
},
Expand All @@ -1720,7 +1756,10 @@ RVOP(
RVOP(
fcvtswu,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = ui32_to_f32(rv->X[ir->rs1]);
set_fflag(rv);
},
Expand Down
46 changes: 40 additions & 6 deletions src/softfloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,51 @@ static inline void set_fflag(riscv_t *rv)
softfloat_exceptionFlags = 0;
}

static inline void set_rounding_mode(riscv_t *rv)
static inline void set_dynamic_rounding_mode(riscv_t *rv)
{
uint32_t frm = (rv->csr_fcsr >> 5) & (~(1 << 3));
if (frm == 0b000)
switch (frm) {
case 0b000:
softfloat_roundingMode = softfloat_round_near_even;
if (frm == 0b001)
break;
case 0b001:
softfloat_roundingMode = softfloat_round_minMag;
if (frm == 0b010)
break;
case 0b010:
softfloat_roundingMode = softfloat_round_min;
if (frm == 0b011)
break;
case 0b011:
softfloat_roundingMode = softfloat_round_max;
if (frm == 0b100)
break;
case 0b100:
softfloat_roundingMode = softfloat_round_near_maxMag;
break;
default:
__UNREACHABLE;
break;
}
}

static inline void set_static_rounding_mode(uint8_t rm)
{
switch (rm) {
case 0b000:
softfloat_roundingMode = softfloat_round_near_even;
break;
case 0b001:
softfloat_roundingMode = softfloat_round_minMag;
break;
case 0b010:
softfloat_roundingMode = softfloat_round_min;
break;
case 0b011:
softfloat_roundingMode = softfloat_round_max;
break;
case 0b100:
softfloat_roundingMode = softfloat_round_near_maxMag;
break;
default:
__UNREACHABLE;
break;
}
}