Skip to content

Commit

Permalink
Fix rounding mode selection
Browse files Browse the repository at this point in the history
Some F extension instructions include an rm field, indicating the
rounding mode to be used. When an instruction has an rm field, the
rounding mode should be chosen based on the value of that field. If the
rm field is set to 0b111, it signifies dynamic selection of the
rounding mode based on the fcsr's frm field.

The current implementation always selected the rounding mode
dynamically based on fcsr's frm, regardless of the rm field in the
instruction. This patch corrects this error, ensuring that the rounding
mode is now chosen according to the rm field when present.
  • Loading branch information
visitorckw committed Jan 6, 2024
1 parent 664f90d commit a00aeea
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 27 deletions.
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;
#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;
}
}

0 comments on commit a00aeea

Please sign in to comment.