diff --git a/src/sysc/datatypes/int/sc_bigint_inlines.h b/src/sysc/datatypes/int/sc_bigint_inlines.h index 97d35fd82..dd7d38686 100644 --- a/src/sysc/datatypes/int/sc_bigint_inlines.h +++ b/src/sysc/datatypes/int/sc_bigint_inlines.h @@ -487,34 +487,12 @@ sc_bigint::operator>>(int v) const if (v <= 0) { return sc_signed(*this); } - int nb = W - v; - // If we shift off the end return the sign bit. + // Preserve full width W in the result (IEEE 1666-2023 §7.2.8). - if ( 0 >= nb ) { - sc_signed result(1, false); - result.digit[0] = 0 > (int)digit[HOD] ? -1 : 0; - return result; - } - - // Return a value that is the width of the shifted value: - - sc_signed result(nb, false); - if ( W < 33 ) { - result.digit[0] = (int)digit[0] >> v; - } - else if ( W < 65 ) { - int64 tmp = digit[DIV_CEIL(W)-1]; - tmp = (tmp << 32) | digit[0]; - tmp = tmp >> v; - result.digit[0] = tmp; - if ( nb > 32 ) { - result.digit[1] = (tmp >>32); - } - } - else { - vector_extract(digit, result.digit, W-1, v); - } + sc_signed result(*this); + vector_shift_right(result.ndigits, result.digit, v, + (int)digit[HOD] < 0 ? DIGIT_MASK : 0); result.adjust_hod(); return result; } diff --git a/src/sysc/datatypes/int/sc_biguint_inlines.h b/src/sysc/datatypes/int/sc_biguint_inlines.h index 151e5a855..91d667d2a 100644 --- a/src/sysc/datatypes/int/sc_biguint_inlines.h +++ b/src/sysc/datatypes/int/sc_biguint_inlines.h @@ -463,37 +463,11 @@ sc_biguint::operator>>(int v) const if (v <= 0) { return sc_unsigned(*this); } - int nb = W - v; - // If we shift off the end return a single bit 0. + // Preserve full width W in the result (IEEE 1666-2023 §7.2.8). - if ( nb <= 0 ) { - sc_unsigned result(1, true); - return result; - } - - - // Return a value that is the width of the shifted value: - // - // Note: sc_biguint values have one extra bit on the top, so the comparison is down - // one bit, e.g., W < 32, not W < 33. - - sc_unsigned result(nb, false); - if ( W < 32 ) { - result.digit[0] = digit[0] >> v; - } - else if ( W < 64 ) { - uint64 tmp = digit[DIV_CEIL(W)-1]; - tmp = (tmp << 32) | digit[0]; - tmp = tmp >> v; - result.digit[0] = tmp; - if ( result.nbits > 32 ) { - result.digit[1] = (tmp >> 32); - } - } - else { - vector_extract(digit, result.digit, W-1, v); - } + sc_unsigned result(*this); + vector_shift_right(result.ndigits, result.digit, v, 0); result.adjust_hod(); return result; } diff --git a/src/sysc/datatypes/int/sc_signed.h b/src/sysc/datatypes/int/sc_signed.h index 091465203..612f1c933 100644 --- a/src/sysc/datatypes/int/sc_signed.h +++ b/src/sysc/datatypes/int/sc_signed.h @@ -1075,34 +1075,12 @@ class SC_API sc_signed : public sc_value_base if (v <= 0) { return sc_signed(*this); } - int nb = nbits - v; - // If we shift off the end return the sign bit. + // Preserve full width in the result (IEEE 1666-2023 §7.2.8). - if ( 0 >= nb ) { - sc_signed result(1, false); - result.digit[0] = 0 > (int)digit[ndigits-1] ? -1 : 0; - return result; - } - - // Return a value that is the width of the shifted value: - - sc_signed result(nb, false); - if ( nbits < 33 ) { - result.digit[0] = (int)digit[0] >> v; - } - else if ( nbits < 65 ) { - int64 tmp = digit[1]; - tmp = (tmp << 32) | digit[0]; - tmp = tmp >> v; - result.digit[0] = (sc_digit)tmp; - if ( nb > 32 ) { - result.digit[1] = (tmp >>32); - } - } - else { - vector_extract(digit, result.digit, nbits-1, v); - } + sc_signed result(*this); + vector_shift_right(result.ndigits, result.digit, v, + (int)digit[ndigits-1] < 0 ? DIGIT_MASK : 0); result.adjust_hod(); return result; } diff --git a/src/sysc/datatypes/int/sc_unsigned.h b/src/sysc/datatypes/int/sc_unsigned.h index 4a5ed2c49..d6e177240 100644 --- a/src/sysc/datatypes/int/sc_unsigned.h +++ b/src/sysc/datatypes/int/sc_unsigned.h @@ -1068,33 +1068,11 @@ class SC_API sc_unsigned : public sc_value_base if (v <= 0) { return sc_unsigned(*this); } - int nb = nbits - v; - // If we shift off the end return the sign bit. + // Preserve full width in the result (IEEE 1666-2023 §7.2.8). - if ( 0 >= nb ) { - sc_unsigned result(1, true); - return result; - } - - // Return a value that is the width of the shifted value: - - sc_unsigned result(nb, false); - if ( nbits < 33 ) { - result.digit[0] = (int)digit[0] >> v; - } - else if ( nbits < 65 ) { - int64 tmp = digit[1]; - tmp = (tmp << 32) | digit[0]; - tmp = tmp >> v; - result.digit[0] = (sc_digit)tmp; - if ( nb > 32 ) { - result.digit[1] = (tmp >>32); - } - } - else { - vector_extract(digit, result.digit, nbits-1, v); - } + sc_unsigned result(*this); + vector_shift_right(result.ndigits, result.digit, v, 0); result.adjust_hod(); return result; } diff --git a/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/golden/rshift_width.log b/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/golden/rshift_width.log new file mode 100644 index 000000000..a81dd04d1 --- /dev/null +++ b/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/golden/rshift_width.log @@ -0,0 +1,10 @@ +SystemC Simulation +sc_bigint<54>(-1048577) >> 32: value=-1 width=54 +sc_bigint<128>(-1) >> 64: value=-1 width=128 +sc_bigint<54>(pos) >> 48: value=0 width=54 +sc_bigint<54>(-1048577) >> 100: value=-1 width=54 +sc_signed(54)(-1048577) >> 32: value=-1 width=54 +sc_biguint<54>(0x3FFFFFFFFF) >> 32: value=63 width=54 +sc_biguint<54>(0x3FFFFFFFFF) >> 100: value=0 width=54 +sc_unsigned(54)(0x3FFFFFFFFF) >> 32: value=63 width=54 +PASSED diff --git a/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/rshift_width.cpp b/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/rshift_width.cpp new file mode 100644 index 000000000..8560abfdc --- /dev/null +++ b/tests/systemc/datatypes/int/big_datatypes/shifts/rshift_width/rshift_width.cpp @@ -0,0 +1,81 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +// Test that operator>> preserves the result width (IEEE 1666-2023 §7.2.8). + +#include "systemc.h" + +using std::cout; +using std::endl; + +int sc_main(int, char*[]) +{ + // --- sc_bigint (signed) --- + + sc_bigint<54> si54 = -1048577; + sc_signed r_si54 = si54 >> 32; + cout << "sc_bigint<54>(-1048577) >> 32: value=" << r_si54.to_int64() + << " width=" << r_si54.length() << endl; + + sc_bigint<128> si128 = -1; + sc_signed r_si128 = si128 >> 64; + cout << "sc_bigint<128>(-1) >> 64: value=" << r_si128.to_int64() + << " width=" << r_si128.length() << endl; + + sc_bigint<54> si54z = 0x3FFFFF00000LL; + sc_signed r_si54z = si54z >> 48; + cout << "sc_bigint<54>(pos) >> 48: value=" << r_si54z.to_int64() + << " width=" << r_si54z.length() << endl; + + // shift >= width + sc_signed r_si54_full = si54 >> 100; + cout << "sc_bigint<54>(-1048577) >> 100: value=" << r_si54_full.to_int64() + << " width=" << r_si54_full.length() << endl; + + // --- sc_signed --- + + sc_signed ss(54); + ss = -1048577; + sc_signed r_ss = ss >> 32; + cout << "sc_signed(54)(-1048577) >> 32: value=" << r_ss.to_int64() + << " width=" << r_ss.length() << endl; + + // --- sc_biguint (unsigned) --- + + sc_biguint<54> ui54 = 0x3FFFFFFFFFLL; + sc_unsigned r_ui54 = ui54 >> 32; + cout << "sc_biguint<54>(0x3FFFFFFFFF) >> 32: value=" << r_ui54.to_int64() + << " width=" << r_ui54.length() << endl; + + // shift >= width + sc_unsigned r_ui54_full = ui54 >> 100; + cout << "sc_biguint<54>(0x3FFFFFFFFF) >> 100: value=" << r_ui54_full.to_int64() + << " width=" << r_ui54_full.length() << endl; + + // --- sc_unsigned --- + + sc_unsigned su(54); + su = 0x3FFFFFFFFFLL; + sc_unsigned r_su = su >> 32; + cout << "sc_unsigned(54)(0x3FFFFFFFFF) >> 32: value=" << r_su.to_int64() + << " width=" << r_su.length() << endl; + + cout << "PASSED" << endl; + return 0; +}