diff --git a/vvp/arith.cc b/vvp/arith.cc index c7ee15e85..7b23e3bd6 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -453,35 +453,37 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, { dispatch_operand_(ptr, bit); - vvp_vector4_t res4; - if (signed_flag_) { - if (op_a_.has_xz() || op_b_.has_xz()) { - ptr.ptr()->send_vec4(x_val_, 0); - return; - } + vvp_vector2_t a2 (op_a_, true); + vvp_vector2_t b2 (op_b_, true); - double ad, bd, resd; - vector4_to_value(op_a_, ad, true); - vector4_to_value(op_b_, bd, true); - /* 2**-1 and -2**-1 are defined to be zero. */ - if ((bd == -1) && (fabs(ad) == 2.0)) resd = 0.0; - else resd = pow(ad, bd); - - res4 = vvp_vector4_t(wid_, resd); - } else { - vvp_vector2_t a2 (op_a_, true); - vvp_vector2_t b2 (op_b_, true); - - if (a2.is_NaN() || b2.is_NaN()) { - ptr.ptr()->send_vec4(x_val_, 0); - return; - } - - vvp_vector2_t result = pow(a2, b2); - res4 = vector2_to_vector4(result, wid_); + // If we have an X or Z in the arguments return X. + if (a2.is_NaN() || b2.is_NaN()) { + ptr.ptr()->send_vec4(x_val_, 0); + return; } - ptr.ptr()->send_vec4(res4, 0); + // Is the exponent negative? If so, table 5-6 in IEEE1364-2005 + // defines what value is returned. + if (signed_flag_ && b2.value(b2.size()-1)) { + int a_val; + double r_val = 0.0; + if (vector2_to_value(a2, a_val, true)) { + if (a_val == 0) { + ptr.ptr()->send_vec4(x_val_, 0); + return; + } + if (a_val == 1) { + r_val = 1.0; + } + if (a_val == -1) { + r_val = b2.value(0) ? -1.0 : 1.0; + } + } + ptr.ptr()->send_vec4(vvp_vector4_t(wid_, r_val), 0); + return; + } + + ptr.ptr()->send_vec4(vector2_to_vector4(pow(a2, b2), wid_), 0); } diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 73d9b41f5..5b5171b9b 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4540,24 +4540,50 @@ bool of_POP_STR(vthread_t thr, vvp_code_t cp) return true; } -bool of_POW(vthread_t thr, vvp_code_t cp) +static bool of_POW_base(vthread_t thr, vvp_code_t cp, bool signed_flag) { assert(cp->bit_idx[0] >= 4); unsigned idx = cp->bit_idx[0]; unsigned idy = cp->bit_idx[1]; unsigned wid = cp->number; - vvp_vector2_t xv2 = vvp_vector2_t(vthread_bits_to_vector(thr, idx, wid), true); - vvp_vector2_t yv2 = vvp_vector2_t(vthread_bits_to_vector(thr, idy, wid), true); + vvp_vector2_t a2 = vvp_vector2_t(vthread_bits_to_vector(thr, idx, wid), true); + vvp_vector2_t b2 = vvp_vector2_t(vthread_bits_to_vector(thr, idy, wid), true); - /* If we have an X or Z in the arguments return X. */ - if (xv2.is_NaN() || yv2.is_NaN()) { + // If we have an X or Z in the arguments return X. + if (a2.is_NaN() || b2.is_NaN()) { for (unsigned jdx = 0 ; jdx < wid ; jdx += 1) thr_put_bit(thr, cp->bit_idx[0]+jdx, BIT4_X); return true; } - vvp_vector2_t result = pow(xv2, yv2); + // Is the exponent negative? If so, table 5-6 in IEEE1364-2005 + // defines what value is returned. + if (signed_flag && b2.value(b2.size()-1)) { + int a_val; + vvp_bit4_t pad = BIT4_0, lsb = BIT4_0; + if (vector2_to_value(a2, a_val, true)) { + if (a_val == 0) { + pad = BIT4_X; lsb = BIT4_X; + } + if (a_val == 1) { + pad = BIT4_0; lsb = BIT4_1; + } + if (a_val == -1) { + if (b2.value(0)) { + pad = BIT4_1; lsb = BIT4_1; + } else { + pad = BIT4_0; lsb = BIT4_1; + } + } + } + thr_put_bit(thr, cp->bit_idx[0], lsb); + for (unsigned jdx = 1 ; jdx < wid ; jdx += 1) + thr_put_bit(thr, cp->bit_idx[0]+jdx, pad); + return true; + } + + vvp_vector2_t result = pow(a2, b2); /* Copy only what we need of the result. */ for (unsigned jdx = 0; jdx < wid; jdx += 1) @@ -4567,37 +4593,14 @@ bool of_POW(vthread_t thr, vvp_code_t cp) return true; } +bool of_POW(vthread_t thr, vvp_code_t cp) +{ + return of_POW_base(thr, cp, false); +} + bool of_POW_S(vthread_t thr, vvp_code_t cp) { - assert(cp->bit_idx[0] >= 4); - - unsigned idx = cp->bit_idx[0]; - unsigned idy = cp->bit_idx[1]; - unsigned wid = cp->number; - vvp_vector4_t xv = vthread_bits_to_vector(thr, idx, wid); - vvp_vector4_t yv = vthread_bits_to_vector(thr, idy, wid); - - /* If we have an X or Z in the arguments return X. */ - if (xv.has_xz() || yv.has_xz()) { - for (unsigned jdx = 0 ; jdx < wid ; jdx += 1) - thr_put_bit(thr, cp->bit_idx[0]+jdx, BIT4_X); - return true; - } - - /* Calculate the result using the double pow() function. */ - double xd, yd, resd; - vector4_to_value(xv, xd, true); - vector4_to_value(yv, yd, true); - /* 2**-1 and -2**-1 are defined to be zero. */ - if ((yd == -1.0) && (fabs(xd) == 2.0)) resd = 0.0; - else resd = pow(xd, yd); - vvp_vector4_t res = vvp_vector4_t(wid, resd); - - /* Copy the result. */ - for (unsigned jdx = 0; jdx < wid; jdx += 1) - thr_put_bit(thr, cp->bit_idx[0]+jdx, res.value(jdx)); - - return true; + return of_POW_base(thr, cp, true); } bool of_POW_WR(vthread_t thr, vvp_code_t)