diff --git a/vvp/arith.cc b/vvp/arith.cc index c67846d9f..995809201 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -885,13 +885,14 @@ void vvp_shiftl::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_vector4_t out (op_a_.size()); + bool overflow_flag; unsigned long shift; - if (! vector4_to_value(op_b_, shift)) { + if (! vector4_to_value(op_b_, overflow_flag, shift)) { ptr.ptr()->send_vec4(x_val_, 0); return; } - if (shift > out.size()) + if (overflow_flag || shift > out.size()) shift = out.size(); for (unsigned idx = 0 ; idx < shift ; idx += 1) @@ -919,13 +920,14 @@ void vvp_shiftr::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, vvp_vector4_t out (op_a_.size()); + bool overflow_flag; unsigned long shift; - if (! vector4_to_value(op_b_, shift)) { + if (! vector4_to_value(op_b_, overflow_flag, shift)) { ptr.ptr()->send_vec4(x_val_, 0); return; } - if (shift > out.size()) + if (overflow_flag || shift > out.size()) shift = out.size(); for (unsigned idx = shift ; idx < out.size() ; idx += 1) diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 9bd3a066f..570fc68a9 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -587,12 +587,13 @@ or z, then the index register gets the value 0. The %ix/vec4/s instruction is the same, except that it assumes the source vector is sign extended to fit the index register. -The instruction also writes into bit 4 a 1 if any of the bits of the +The instruction also writes into flag 4 a 1 if any of the bits of the input vector are x or z. This is a flag that the 0 value written into the index register is really the result of calculating from unknown -bits. +bits. It writes an X into flag 4 if the vec4 value overflows the index +register. - 4: unknown value + 4: unknown value or overflow 5: (reserved) 6: (reserved) @@ -600,8 +601,8 @@ bits. * %ix/getv/s , These instructions are like the %ix/vec4 instructions, except that they -read directly from a functor label instead of from thread bits. They -set bit 4 just like %ix/get. +read directly from a functor label instead of from thread bits. They set +flag 4 just like %ix/get (overflow is not currently checked by ix/getv/s). * %ix/load , , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 77804137c..f2e3961fc 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3017,8 +3017,9 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp) vvp_vector4_t vec; sig->vec4_value(vec); + bool overflow_flag; uint64_t val; - bool known_flag = vector4_to_value(vec, val); + bool known_flag = vector4_to_value(vec, overflow_flag, val); if (known_flag) thr->words[index].w_uint = val; @@ -3026,7 +3027,7 @@ bool of_IX_GETV(vthread_t thr, vvp_code_t cp) thr->words[index].w_uint = 0; /* Set bit 4 as a flag if the input is unknown. */ - thr->flags[4] = known_flag ? BIT4_0 : BIT4_1; + thr->flags[4] = known_flag ? (overflow_flag ? BIT4_X : BIT4_0) : BIT4_1; return true; } @@ -3082,12 +3083,19 @@ static uint64_t vec4_to_index(vthread_t thr, bool signed_flag) thr->flags[4] = BIT4_0; assert(sizeof(bits[0]) <= sizeof(v)); - //assert(val_size <= 8*sizeof(v)); v = 0; for (unsigned idx = 0 ; idx < val_size ; idx += 8*sizeof(bits[0])) { uint64_t tmp = bits[idx/8/sizeof(bits[0])]; - v |= tmp << idx; + if (idx < 8*sizeof(v)) { + v |= tmp << idx; + } else { + bool overflow = signed_flag && (v >> 63) ? ~tmp != 0 : tmp != 0; + if (overflow) { + thr->flags[4] = BIT4_X; + break; + } + } } // Set the high bits that are not necessarily filled in by the @@ -4936,7 +4944,7 @@ bool of_SHIFTL(vthread_t thr, vvp_code_t cp) // The result is 'bx if the shift amount is undefined val = vvp_vector4_t(wid, BIT4_X); - } else if (shift >= wid) { + } else if (thr->flags[4] == BIT4_X || shift >= wid) { // Shift is so big that all value is shifted out. Write // a constant 0 result. val = vvp_vector4_t(wid, BIT4_0); @@ -4968,7 +4976,7 @@ bool of_SHIFTR(vthread_t thr, vvp_code_t cp) if (thr->flags[4] == BIT4_1) { val = vvp_vector4_t(wid, BIT4_X); - } else if (shift > wid) { + } else if (thr->flags[4] == BIT4_X || shift > wid) { val = vvp_vector4_t(wid, BIT4_0); } else if (shift > 0) { @@ -4998,7 +5006,7 @@ bool of_SHIFTR_S(vthread_t thr, vvp_code_t cp) if (thr->flags[4] == BIT4_1) { val = vvp_vector4_t(wid, BIT4_X); - } else if (shift > wid) { + } else if (thr->flags[4] == BIT4_X || shift > wid) { val = vvp_vector4_t(wid, sign_bit); } else if (shift > 0) { diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 544dfa624..a3f4abc86 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -2042,20 +2042,21 @@ template bool vector4_to_value(const vvp_vector4_t&vec, uint32_t&val, template bool vector4_to_value(const vvp_vector4_t&vec, uint64_t&val, bool is_signed, bool is_arithmetic); -template bool vector4_to_value(const vvp_vector4_t&vec, T&val) +template bool vector4_to_value(const vvp_vector4_t&vec, + bool&overflow_flag, T&val) { T res = 0; T msk = 1; + overflow_flag = false; unsigned size = vec.size(); for (unsigned idx = 0 ; idx < size ; idx += 1) { switch (vec.value(idx)) { case BIT4_0: break; case BIT4_1: - // On overflow, return the maximum value of type T if (msk == 0) - res = ~msk; + overflow_flag = true; else res |= msk; break; @@ -2070,9 +2071,11 @@ template bool vector4_to_value(const vvp_vector4_t&vec, T&val) return true; } -template bool vector4_to_value(const vvp_vector4_t&vec, unsigned long&val); +template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag, + unsigned long&val); #ifndef UL_AND_TIME64_SAME -template bool vector4_to_value(const vvp_vector4_t&vec, vvp_time64_t&val); +template bool vector4_to_value(const vvp_vector4_t&vec, bool&overflow_flag, + vvp_time64_t&val); #endif bool vector4_to_value(const vvp_vector4_t&vec, double&val, bool signed_flag) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 625ef7393..60caac64b 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -558,7 +558,14 @@ template extern bool vector4_to_value(const vvp_vector4_t&a, T&val, bool is_signed, bool is_arithmetic =true); -template extern bool vector4_to_value(const vvp_vector4_t&a, T&val); +template extern bool vector4_to_value(const vvp_vector4_t&a, + bool&overflow_flag, T&val); + +template inline bool vector4_to_value(const vvp_vector4_t&a, T&val) +{ + bool overflow_flag; + return vector4_to_value(a, overflow_flag, val); +} extern bool vector4_to_value(const vvp_vector4_t&a, double&val, bool is_signed);