Skip to content

Commit a00aeea

Browse files
committed
Fix rounding mode selection
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.
1 parent 664f90d commit a00aeea

File tree

4 files changed

+115
-27
lines changed

4 files changed

+115
-27
lines changed

src/decode.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ static inline void decode_r4type(rv_insn_t *ir, const uint32_t insn)
381381
ir->rs1 = decode_rs1(insn);
382382
ir->rs2 = decode_rs2(insn);
383383
ir->rs3 = decode_r4type_rs3(insn);
384+
ir->rm = decode_funct3(insn);
384385
}
385386
#endif
386387

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

10461047
/* decode R-type */
1047-
uint8_t funct3 = decode_funct3(insn);
1048+
ir->rm = decode_funct3(insn);
10481049
decode_rtype(ir, insn);
10491050

10501051
/* dispatch from funct7 field */
@@ -1066,7 +1067,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
10661067
break;
10671068
case 0b0010000:
10681069
/* dispatch from rm region */
1069-
switch (funct3) {
1070+
switch (ir->rm) {
10701071
case 0b000: /* FSGNJ.S */
10711072
ir->opcode = rv_insn_fsgnjs;
10721073
break;
@@ -1093,7 +1094,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
10931094
break;
10941095
case 0b0010100:
10951096
/* dispatch from rm region */
1096-
switch (funct3) {
1097+
switch (ir->rm) {
10971098
case 0b000: /* FMIN.S */
10981099
ir->opcode = rv_insn_fmins;
10991100
break;
@@ -1106,7 +1107,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
11061107
break;
11071108
case 0b1110000:
11081109
/* dispatch from rm region */
1109-
switch (funct3) {
1110+
switch (ir->rm) {
11101111
case 0b000: /* FMV.X.W */
11111112
ir->opcode = rv_insn_fmvxw;
11121113
break;
@@ -1119,7 +1120,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
11191120
break;
11201121
case 0b1010000:
11211122
/* dispatch from rm region */
1122-
switch (funct3) {
1123+
switch (ir->rm) {
11231124
case 0b010: /* FEQ.S */
11241125
ir->opcode = rv_insn_feqs;
11251126
break;

src/decode.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,20 @@ typedef struct rv_insn {
288288
#if RV32_HAS(EXT_C)
289289
uint8_t shamt;
290290
#endif
291+
292+
#if RV32_HAS(EXT_F)
293+
/* Floating-point operations use either a static rounding mode encoded in
294+
* the instruction, or a dynamic rounding mode held in frm. A value of 111
295+
* in the instruction’s rm field selects the dynamic rounding mode held in
296+
* frm. If frm is set to an invalid value (101–111), any subsequent attempt
297+
* to execute a floating-point operation with a dynamic rounding mode will
298+
* cause an illegal instruction trap. Some instructions that have the rm
299+
* field are nevertheless unaffected by the rounding mode; they should have
300+
* their rm field set to RNE (000).
301+
*/
302+
uint8_t rm;
303+
#endif
304+
291305
/* fuse operation */
292306
int32_t imm2;
293307
opcode_fuse_t *fuse;

src/rv32_template.c

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,10 @@ RVOP(
14131413
RVOP(
14141414
fmadds,
14151415
{
1416-
set_rounding_mode(rv);
1416+
if (likely(ir->rm == 0b111))
1417+
set_dynamic_rounding_mode(rv);
1418+
else
1419+
set_static_rounding_mode(ir->rm);
14171420
rv->F[ir->rd] =
14181421
f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], rv->F[ir->rs3]);
14191422
set_fflag(rv);
@@ -1426,7 +1429,10 @@ RVOP(
14261429
RVOP(
14271430
fmsubs,
14281431
{
1429-
set_rounding_mode(rv);
1432+
if (likely(ir->rm == 0b111))
1433+
set_dynamic_rounding_mode(rv);
1434+
else
1435+
set_static_rounding_mode(ir->rm);
14301436
riscv_float_t tmp = rv->F[ir->rs3];
14311437
tmp.v ^= FMASK_SIGN;
14321438
rv->F[ir->rd] = f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], tmp);
@@ -1440,7 +1446,10 @@ RVOP(
14401446
RVOP(
14411447
fnmsubs,
14421448
{
1443-
set_rounding_mode(rv);
1449+
if (likely(ir->rm == 0b111))
1450+
set_dynamic_rounding_mode(rv);
1451+
else
1452+
set_static_rounding_mode(ir->rm);
14441453
riscv_float_t tmp = rv->F[ir->rs1];
14451454
tmp.v ^= FMASK_SIGN;
14461455
rv->F[ir->rd] = f32_mulAdd(tmp, rv->F[ir->rs2], rv->F[ir->rs3]);
@@ -1454,7 +1463,10 @@ RVOP(
14541463
RVOP(
14551464
fnmadds,
14561465
{
1457-
set_rounding_mode(rv);
1466+
if (likely(ir->rm == 0b111))
1467+
set_dynamic_rounding_mode(rv);
1468+
else
1469+
set_static_rounding_mode(ir->rm);
14581470
riscv_float_t tmp1 = rv->F[ir->rs1];
14591471
riscv_float_t tmp2 = rv->F[ir->rs3];
14601472
tmp1.v ^= FMASK_SIGN;
@@ -1470,7 +1482,10 @@ RVOP(
14701482
RVOP(
14711483
fadds,
14721484
{
1473-
set_rounding_mode(rv);
1485+
if (likely(ir->rm == 0b111))
1486+
set_dynamic_rounding_mode(rv);
1487+
else
1488+
set_static_rounding_mode(ir->rm);
14741489
rv->F[ir->rd] = f32_add(rv->F[ir->rs1], rv->F[ir->rs2]);
14751490
set_fflag(rv);
14761491
},
@@ -1482,7 +1497,10 @@ RVOP(
14821497
RVOP(
14831498
fsubs,
14841499
{
1485-
set_rounding_mode(rv);
1500+
if (likely(ir->rm == 0b111))
1501+
set_dynamic_rounding_mode(rv);
1502+
else
1503+
set_static_rounding_mode(ir->rm);
14861504
rv->F[ir->rd] = f32_sub(rv->F[ir->rs1], rv->F[ir->rs2]);
14871505
set_fflag(rv);
14881506
},
@@ -1494,7 +1512,10 @@ RVOP(
14941512
RVOP(
14951513
fmuls,
14961514
{
1497-
set_rounding_mode(rv);
1515+
if (likely(ir->rm == 0b111))
1516+
set_dynamic_rounding_mode(rv);
1517+
else
1518+
set_static_rounding_mode(ir->rm);
14981519
rv->F[ir->rd] = f32_mul(rv->F[ir->rs1], rv->F[ir->rs2]);
14991520
set_fflag(rv);
15001521
},
@@ -1506,7 +1527,10 @@ RVOP(
15061527
RVOP(
15071528
fdivs,
15081529
{
1509-
set_rounding_mode(rv);
1530+
if (likely(ir->rm == 0b111))
1531+
set_dynamic_rounding_mode(rv);
1532+
else
1533+
set_static_rounding_mode(ir->rm);
15101534
rv->F[ir->rd] = f32_div(rv->F[ir->rs1], rv->F[ir->rs2]);
15111535
set_fflag(rv);
15121536
},
@@ -1518,7 +1542,10 @@ RVOP(
15181542
RVOP(
15191543
fsqrts,
15201544
{
1521-
set_rounding_mode(rv);
1545+
if (likely(ir->rm == 0b111))
1546+
set_dynamic_rounding_mode(rv);
1547+
else
1548+
set_static_rounding_mode(ir->rm);
15221549
rv->F[ir->rd] = f32_sqrt(rv->F[ir->rs1]);
15231550
set_fflag(rv);
15241551
},
@@ -1611,7 +1638,10 @@ RVOP(
16111638
RVOP(
16121639
fcvtws,
16131640
{
1614-
set_rounding_mode(rv);
1641+
if (likely(ir->rm == 0b111))
1642+
set_dynamic_rounding_mode(rv);
1643+
else
1644+
set_static_rounding_mode(ir->rm);
16151645
uint32_t ret = f32_to_i32(rv->F[ir->rs1], softfloat_roundingMode, true);
16161646
if (ir->rd)
16171647
rv->X[ir->rd] = ret;
@@ -1625,7 +1655,10 @@ RVOP(
16251655
RVOP(
16261656
fcvtwus,
16271657
{
1628-
set_rounding_mode(rv);
1658+
if (likely(ir->rm == 0b111))
1659+
set_dynamic_rounding_mode(rv);
1660+
else
1661+
set_static_rounding_mode(ir->rm);
16291662
uint32_t ret =
16301663
f32_to_ui32(rv->F[ir->rs1], softfloat_roundingMode, true);
16311664
if (ir->rd)
@@ -1653,7 +1686,7 @@ RVOP(
16531686
RVOP(
16541687
feqs,
16551688
{
1656-
set_rounding_mode(rv);
1689+
set_dynamic_rounding_mode(rv);
16571690
uint32_t ret = f32_eq(rv->F[ir->rs1], rv->F[ir->rs2]);
16581691
if (ir->rd)
16591692
rv->X[ir->rd] = ret;
@@ -1670,7 +1703,7 @@ RVOP(
16701703
RVOP(
16711704
flts,
16721705
{
1673-
set_rounding_mode(rv);
1706+
set_dynamic_rounding_mode(rv);
16741707
uint32_t ret = f32_lt(rv->F[ir->rs1], rv->F[ir->rs2]);
16751708
if (ir->rd)
16761709
rv->X[ir->rd] = ret;
@@ -1683,7 +1716,7 @@ RVOP(
16831716
RVOP(
16841717
fles,
16851718
{
1686-
set_rounding_mode(rv);
1719+
set_dynamic_rounding_mode(rv);
16871720
uint32_t ret = f32_le(rv->F[ir->rs1], rv->F[ir->rs2]);
16881721
if (ir->rd)
16891722
rv->X[ir->rd] = ret;
@@ -1708,7 +1741,10 @@ RVOP(
17081741
RVOP(
17091742
fcvtsw,
17101743
{
1711-
set_rounding_mode(rv);
1744+
if (likely(ir->rm == 0b111))
1745+
set_dynamic_rounding_mode(rv);
1746+
else
1747+
set_static_rounding_mode(ir->rm);
17121748
rv->F[ir->rd] = i32_to_f32(rv->X[ir->rs1]);
17131749
set_fflag(rv);
17141750
},
@@ -1720,7 +1756,10 @@ RVOP(
17201756
RVOP(
17211757
fcvtswu,
17221758
{
1723-
set_rounding_mode(rv);
1759+
if (likely(ir->rm == 0b111))
1760+
set_dynamic_rounding_mode(rv);
1761+
else
1762+
set_static_rounding_mode(ir->rm);
17241763
rv->F[ir->rd] = ui32_to_f32(rv->X[ir->rs1]);
17251764
set_fflag(rv);
17261765
},

src/softfloat.h

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,51 @@ static inline void set_fflag(riscv_t *rv)
101101
softfloat_exceptionFlags = 0;
102102
}
103103

104-
static inline void set_rounding_mode(riscv_t *rv)
104+
static inline void set_dynamic_rounding_mode(riscv_t *rv)
105105
{
106106
uint32_t frm = (rv->csr_fcsr >> 5) & (~(1 << 3));
107-
if (frm == 0b000)
107+
switch (frm) {
108+
case 0b000:
108109
softfloat_roundingMode = softfloat_round_near_even;
109-
if (frm == 0b001)
110+
break;
111+
case 0b001:
110112
softfloat_roundingMode = softfloat_round_minMag;
111-
if (frm == 0b010)
113+
break;
114+
case 0b010:
112115
softfloat_roundingMode = softfloat_round_min;
113-
if (frm == 0b011)
116+
break;
117+
case 0b011:
114118
softfloat_roundingMode = softfloat_round_max;
115-
if (frm == 0b100)
119+
break;
120+
case 0b100:
116121
softfloat_roundingMode = softfloat_round_near_maxMag;
122+
break;
123+
default:
124+
__UNREACHABLE;
125+
break;
126+
}
127+
}
128+
129+
static inline void set_static_rounding_mode(uint8_t rm)
130+
{
131+
switch (rm) {
132+
case 0b000:
133+
softfloat_roundingMode = softfloat_round_near_even;
134+
break;
135+
case 0b001:
136+
softfloat_roundingMode = softfloat_round_minMag;
137+
break;
138+
case 0b010:
139+
softfloat_roundingMode = softfloat_round_min;
140+
break;
141+
case 0b011:
142+
softfloat_roundingMode = softfloat_round_max;
143+
break;
144+
case 0b100:
145+
softfloat_roundingMode = softfloat_round_near_maxMag;
146+
break;
147+
default:
148+
__UNREACHABLE;
149+
break;
150+
}
117151
}

0 commit comments

Comments
 (0)