From abe1099335365b5a1e85744e798dccf869d7fa58 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 8 May 2023 08:09:12 -0700 Subject: [PATCH] Fix formatting real to binary and hex strings on ARM Directly casting a negative double to a unsigned integer type is undefined behavior and has different results on x86 and ARM based platforms. On x86 the behavior is similar to casting a signed int to an unsigned integer, i.e. the sign bit will end up in the MSB. But on ARM the result will be 0. To get consistent behavior, first cast to signed integer and then cast the signed integer value to an unsigned integer value. Signed-off-by: Lars-Peter Clausen --- vvp/vpi_callback.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 80a640186..3427f32f6 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -858,6 +858,14 @@ static double vlg_round(double rval) } } +static uint64_t vlg_round_to_u64(double rval) +{ + // Directly casting a negative double to an unsigned integer types is + // undefined behavior and behaves differently on different architectures. + // Cast to signed integer first to get the behavior we want. + return static_cast(static_cast(vlg_round(rval))); +} + static void real_signal_value(struct t_vpi_value*vp, double rval) { static const size_t RBUF_SIZE = 64 + 1; @@ -890,12 +898,12 @@ static void real_signal_value(struct t_vpi_value*vp, double rval) break; case vpiHexStrVal: - snprintf(rbuf, RBUF_SIZE, "%" PRIx64, (uint64_t)vlg_round(rval)); + snprintf(rbuf, RBUF_SIZE, "%" PRIx64, vlg_round_to_u64(rval)); vp->value.str = rbuf; break; case vpiBinStrVal: { - uint64_t val = (uint64_t)vlg_round(rval); + uint64_t val = vlg_round_to_u64(rval); unsigned len = 0; while (val > 0) { @@ -903,7 +911,7 @@ static void real_signal_value(struct t_vpi_value*vp, double rval) val /= 2; } - val = (uint64_t)vlg_round(rval); + val = vlg_round_to_u64(rval); for (unsigned idx = 0 ; idx < len ; idx += 1) { rbuf[len-idx-1] = (val & 1)? '1' : '0'; val /= 2;