Skip to content

Commit 4975222

Browse files
authored
Merge pull request #323 from visitorckw/fix-rounding-mode
Fix rounding mode selection
2 parents f842b5f + a00aeea commit 4975222

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
@@ -295,6 +295,20 @@ typedef struct rv_insn {
295295
#if RV32_HAS(EXT_C)
296296
uint8_t shamt;
297297
#endif
298+
299+
#if RV32_HAS(EXT_F)
300+
/* Floating-point operations use either a static rounding mode encoded in
301+
* the instruction, or a dynamic rounding mode held in frm. A value of 111
302+
* in the instruction’s rm field selects the dynamic rounding mode held in
303+
* frm. If frm is set to an invalid value (101–111), any subsequent attempt
304+
* to execute a floating-point operation with a dynamic rounding mode will
305+
* cause an illegal instruction trap. Some instructions that have the rm
306+
* field are nevertheless unaffected by the rounding mode; they should have
307+
* their rm field set to RNE (000).
308+
*/
309+
uint8_t rm;
310+
#endif
311+
298312
/* fuse operation */
299313
int32_t imm2;
300314
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)