diff --git a/vvp/delay.cc b/vvp/delay.cc index ac751f860..66a22a4c6 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -135,6 +135,17 @@ vvp_fun_delay::vvp_fun_delay(vvp_net_t*n, vvp_bit4_t init, const vvp_delay_t&d) cur_real_ = 0.0; list_ = 0; initial_ = true; + // Calculate the values used when converting variable delays + // to simulation time units. + struct __vpiScope*scope = vpip_peek_current_scope(); + + int pow = scope->time_units - scope->time_precision; + round_ = 1; + for (int lp = 0; lp < pow; lp += 1) round_ *= 10; + + pow = scope->time_precision - vpip_get_time_precision(); + scale_ = 1; + for (int lp = 0; lp < pow; lp += 1) scale_ *= 10; } vvp_fun_delay::~vvp_fun_delay() @@ -176,8 +187,12 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit) if (port.port() > 0) { // Get the integer value of the bit vector, or 0 if // there are X or Z bits. - unsigned long val = 0; - vector4_to_value(bit, val); + vvp_time64_t bval = 0; + // The following does not work correctly for negative values. + // They should be sign extended to 64 bits (1364-2001 9.7.1). + vector4_to_value(bit, bval); + // Integer values do not need to be rounded so just scale them. + vvp_time64_t val = bval * round_ * scale_; switch (port.port()) { case 1: @@ -272,9 +287,17 @@ void vvp_fun_delay::recv_real(vvp_net_ptr_t port, double bit) if (port.port() > 0) { /* If the port is not 0, then this is a delay value that should be rounded and converted to an integer delay. */ - unsigned long long val = 0; - if (bit > 0) - val = (unsigned long long) (bit+0.5); + vvp_time64_t val = 0; + if (bit > -0.5) { + val = (vvp_time64_t) (bit * round_ +0.5) * scale_; + } else if (bit != bit) { + // For a NaN we use the default (0). + } else { + vvp_vector4_t vec4(8*sizeof(vvp_time64_t), bit); + vvp_time64_t bval = 0; + vector4_to_value(vec4, bval); + val = bval * round_ * scale_; + } switch (port.port()) { case 1: diff --git a/vvp/delay.h b/vvp/delay.h index 20fa617e9..d886f0c94 100644 --- a/vvp/delay.h +++ b/vvp/delay.h @@ -106,6 +106,7 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s { vvp_vector4_t cur_vec4_; vvp_vector8_t cur_vec8_; double cur_real_; + vvp_time64_t round_, scale_; // Needed to scale variable time values. struct event_ *list_; void enqueue_(struct event_*cur) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index fa869bf0a..af7402245 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1156,7 +1156,9 @@ bool vector4_to_value(const vvp_vector4_t&vec, long&val, long msk = 1; bool rc_flag = true; - for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + unsigned size = vec.size(); + if (size > 8*sizeof(val)) size = 8*sizeof(val); + for (unsigned idx = 0 ; idx < size ; idx += 1) { switch (vec.value(idx)) { case BIT4_0: break; @@ -1187,7 +1189,34 @@ bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val) unsigned long res = 0; unsigned long msk = 1; - for (unsigned idx = 0 ; idx < vec.size() ; idx += 1) { + unsigned size = vec.size(); + if (size > 8*sizeof(val)) size = 8*sizeof(val); + for (unsigned idx = 0 ; idx < size ; idx += 1) { + switch (vec.value(idx)) { + case BIT4_0: + break; + case BIT4_1: + res |= msk; + break; + default: + return false; + } + + msk <<= 1UL; + } + + val = res; + return true; +} + +bool vector4_to_value(const vvp_vector4_t&vec, vvp_time64_t&val) +{ + vvp_time64_t res = 0; + vvp_time64_t msk = 1; + + unsigned size = vec.size(); + if (size > 8*sizeof(val)) size = 8*sizeof(val); + for (unsigned idx = 0 ; idx < size ; idx += 1) { switch (vec.value(idx)) { case BIT4_0: break; diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index b9b3bfb6c..9313df469 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -394,6 +394,7 @@ template extern T coerce_to_width(const T&that, unsigned width); */ extern bool vector4_to_value(const vvp_vector4_t&a, long&val, bool is_signed, bool is_arithmetic =true); extern bool vector4_to_value(const vvp_vector4_t&a, unsigned long&val); +extern bool vector4_to_value(const vvp_vector4_t&a, vvp_time64_t&val); extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed); /*