Skip to content

Commit b4521fe

Browse files
authored
Merge pull request #24 from 2011eric/master
Detect NaN in FADD and FSUB
2 parents 89a86a9 + e176ed2 commit b4521fe

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

emulate.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,8 @@ static uint32_t *csr_get_ptr(struct riscv_t *rv, uint32_t csr)
617617
case CSR_MIP:
618618
return (uint32_t *) (&rv->csr_mip);
619619
#ifdef ENABLE_RV32F
620+
case CSR_FFLAGS:
621+
return (uint32_t *) (&rv->csr_fcsr);
620622
case CSR_FCSR:
621623
return (uint32_t *) (&rv->csr_fcsr);
622624
#endif
@@ -637,7 +639,11 @@ static uint32_t csr_csrrw(struct riscv_t *rv, uint32_t csr, uint32_t val)
637639
if (!c)
638640
return 0;
639641

640-
const uint32_t out = *c;
642+
uint32_t out = *c;
643+
#ifdef ENABLE_RV32F
644+
if (csr == CSR_FFLAGS)
645+
out &= FFLAG_MASK;
646+
#endif
641647
if (csr_is_writable(csr))
642648
*c = val;
643649

@@ -651,7 +657,11 @@ static uint32_t csr_csrrs(struct riscv_t *rv, uint32_t csr, uint32_t val)
651657
if (!c)
652658
return 0;
653659

654-
const uint32_t out = *c;
660+
uint32_t out = *c;
661+
#ifdef ENABLE_RV32F
662+
if (csr == CSR_FFLAGS)
663+
out &= FFLAG_MASK;
664+
#endif
655665
if (csr_is_writable(csr))
656666
*c |= val;
657667

@@ -665,7 +675,11 @@ static uint32_t csr_csrrc(struct riscv_t *rv, uint32_t csr, uint32_t val)
665675
if (!c)
666676
return 0;
667677

668-
const uint32_t out = *c;
678+
uint32_t out = *c;
679+
#ifdef ENABLE_RV32F
680+
if (csr == CSR_FFLAGS)
681+
out &= FFLAG_MASK;
682+
#endif
669683
if (csr_is_writable(csr))
670684
*c &= ~val;
671685
return out;
@@ -901,10 +915,25 @@ static bool op_fp(struct riscv_t *rv, uint32_t insn)
901915
/* dispatch based on func7 (low 2 bits are width) */
902916
switch (funct7) {
903917
case 0b0000000: /* FADD */
904-
rv->F[rd] = rv->F[rs1] + rv->F[rs2];
918+
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2]) ||
919+
isnan(rv->F[rs1] + rv->F[rs2])) {
920+
/* raise invalid operation */
921+
*((uint32_t *) &rv->F[rd]) = RV_NAN;
922+
rv->csr_fcsr |= FFLAG_INVALID_OP;
923+
} else {
924+
rv->F[rd] = rv->F[rs1] + rv->F[rs2];
925+
}
926+
if (isinff(rv->F[rd])) {
927+
rv->csr_fcsr |= FFLAG_OVERFLOW;
928+
rv->csr_fcsr |= FFLAG_INEXACT;
929+
}
905930
break;
906931
case 0b0000100: /* FSUB */
907-
rv->F[rd] = rv->F[rs1] - rv->F[rs2];
932+
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2])) {
933+
*((uint32_t *) &rv->F[rd]) = RV_NAN;
934+
} else {
935+
rv->F[rd] = rv->F[rs1] - rv->F[rs2];
936+
}
908937
break;
909938
case 0b0001000: /* FMUL */
910939
rv->F[rd] = rv->F[rs1] * rv->F[rs2];

riscv_private.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,19 @@ enum {
102102

103103
#ifdef ENABLE_RV32F
104104
enum {
105-
// ....xxxx....xxxx....xxxx....xxxx
106-
FMASK_SIGN = 0b10000000000000000000000000000000,
107-
FMASK_EXPN = 0b01111111100000000000000000000000,
108-
FMASK_FRAC = 0b00000000011111111111111111111111,
105+
// ....xxxx....xxxx....xxxx....xxxx
106+
FMASK_SIGN = 0b10000000000000000000000000000000,
107+
FMASK_EXPN = 0b01111111100000000000000000000000,
108+
FMASK_FRAC = 0b00000000011111111111111111111111,
109+
// ....xxxx....xxxx....xxxx....xxxx
110+
FFLAG_MASK = 0b00000000000000000000000000011111,
111+
FFLAG_INVALID_OP = 0b00000000000000000000000000010000,
112+
FFLAG_DIV_BY_ZERO = 0b00000000000000000000000000001000,
113+
FFLAG_OVERFLOW = 0b00000000000000000000000000000100,
114+
FFLAG_UNDERFLOW = 0b00000000000000000000000000000010,
115+
FFLAG_INEXACT = 0b00000000000000000000000000000001,
116+
// ....xxxx....xxxx....xxxx....xxxx
117+
RV_NAN = 0b01111111110000000000000000000000
109118
};
110119
#endif
111120
/* clang-format off */

0 commit comments

Comments
 (0)