diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 7a3d0bd38..91e7b3e1a 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -96,6 +96,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 vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) { __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(ref); @@ -141,17 +149,17 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) break; case vpiOctStrVal: - snprintf(rbuf, RBUF_USE_SIZE, "%" PRIo64, (uint64_t)vlg_round(val)); + snprintf(rbuf, RBUF_USE_SIZE, "%" PRIo64, vlg_round_to_u64(val)); vp->value.str = rbuf; break; case vpiHexStrVal: - snprintf(rbuf, RBUF_USE_SIZE, "%" PRIx64, (uint64_t)vlg_round(val)); + snprintf(rbuf, RBUF_USE_SIZE, "%" PRIx64, vlg_round_to_u64(val)); vp->value.str = rbuf; break; case vpiBinStrVal: { - uint64_t vali = (uint64_t)vlg_round(val); + uint64_t vali = vlg_round_to_u64(val); unsigned len = 0; while (vali > 0) { @@ -159,7 +167,7 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) vali /= 2; } - vali = (uint64_t)vlg_round(val); + vali = vlg_round_to_u64(val); for (unsigned idx = 0 ; idx < len ; idx += 1) { rbuf[len-idx-1] = (vali & 1)? '1' : '0'; vali /= 2; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index deee63fd0..505e5f11c 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2374,17 +2374,30 @@ bool of_CVT_SR(vthread_t thr, vvp_code_t cp) return true; } +static double vlg_round(double rval) +{ + if (rval >= 0.0) { + return floor(rval + 0.5); + } else { + return ceil(rval - 0.5); + } +} + +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))); +} + /* * %cvt/ur */ bool of_CVT_UR(vthread_t thr, vvp_code_t cp) { double r = thr->pop_real(); - if (r >= 0.0) - thr->words[cp->bit_idx[0]].w_uint = (uint64_t)floor(r+0.5); - else - thr->words[cp->bit_idx[0]].w_uint = (uint64_t)ceil(r-0.5); - + thr->words[cp->bit_idx[0]].w_uint = vlg_round_to_u64(r); return true; }