From d3049d9c89eb55c9b88ca250c47e4fa4eb1a933a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 15 May 2014 21:49:43 -0400 Subject: [PATCH] Fix huge shifts to zero with -Wno-WIDTH, bug766. --- Changes | 2 +- src/V3Number.cpp | 16 ++++++++++++---- src/V3Number.h | 9 ++++++++- test_regress/t/t_math_signed5.v | 7 +++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Changes b/Changes index c65dd7ae9..de6a843b5 100644 --- a/Changes +++ b/Changes @@ -9,7 +9,7 @@ indicates the contributor was also the author of the fix; Thanks! *** Support SV 2012 package import before port list. -**** Fix huge shifts to zero with -Wno-WIDTH, bug765. [Clifford Wolf] +**** Fix huge shifts to zero with -Wno-WIDTH, bug765, bug766. [Clifford Wolf] **** Fix gate primitives with arrays and non-arrayed pins. diff --git a/src/V3Number.cpp b/src/V3Number.cpp index c8ca9717d..857181875 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1125,8 +1125,10 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) { if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); - for (int bit=0; bitwidth(); bit++) { - setBit(bit,lhs.bitIs(bit + rhsval)); + if (rhsval < (uint32_t)lhs.width()) { + for (int bit=0; bitwidth(); bit++) { + setBit(bit,lhs.bitIs(bit + rhsval)); + } } return *this; } @@ -1138,8 +1140,14 @@ V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) { if (rhs.isFourState()) return setAllBitsX(); setZero(); uint32_t rhsval = rhs.toUInt(); - for (int bit=0; bitwidth(); bit++) { - setBit(bit,lhs.bitIsExtend(bit + rhsval)); + if (rhsval < (uint32_t)lhs.width()) { + for (int bit=0; bitwidth(); bit++) { + setBit(bit,lhs.bitIsExtend(bit + rhsval)); + } + } else { + for (int bit=0; bitwidth(); bit++) { + setBit(bit,lhs.bitIsExtend(lhs.width()-1)); + } } return *this; } diff --git a/src/V3Number.h b/src/V3Number.h index 2caba3e20..c0940cf23 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -60,13 +60,14 @@ public: } private: char bitIs (int bit) const { - if (bit>=m_width) { + if (bit>=m_width || bit<0) { // We never sign extend return '0'; } return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); } char bitIsExtend (int bit) const { + if (bit<0) return '0'; if (bit>=m_width) { bit = m_width-1; // We do sign extend @@ -76,22 +77,28 @@ private: return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); } bool bitIs0 (int bit) const { + if (bit<0) return false; if (bit>=m_width) return !bitIsXZ(m_width-1); return ( (m_value[bit/32] & (1UL<<(bit&31)))==0 && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } bool bitIs1 (int bit) const { + if (bit<0) return false; if (bit>=m_width) return false; return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } bool bitIs1Extend (int bit) const { + if (bit<0) return false; if (bit>=m_width) return bitIs1Extend(m_width-1); return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); } bool bitIsX (int bit) const { + if (bit<0) return false; if (bit>=m_width) return bitIsZ(m_width-1); return ( (m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); } bool bitIsXZ(int bit) const { + if (bit<0) return false; if (bit>=m_width) return bitIsXZ(m_width-1); return ( (m_valueX[bit/32] & (1UL<<(bit&31))) && 1); } bool bitIsZ (int bit) const { + if (bit<0) return false; if (bit>=m_width) return bitIsZ(m_width-1); return ( (~m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); } uint32_t bitsValue(int lsb, int nbits) const { diff --git a/test_regress/t/t_math_signed5.v b/test_regress/t/t_math_signed5.v index ec90fd8ac..a93c74307 100644 --- a/test_regress/t/t_math_signed5.v +++ b/test_regress/t/t_math_signed5.v @@ -15,6 +15,8 @@ reg [2:0] w3_u; reg [3:0] w4_u; reg [4:0] w5_u; + reg [15:0] w16a_u; + reg [15:0] w16_u; real r; reg signed [4:0] bug754_a; @@ -116,6 +118,11 @@ w4_u = (w3_u >> 2'b11) >> 1; `checkh(w4_u, 4'b0000); + // bug766 + w16a_u = 16'h1234; + w16_u = (w16a_u >> 16) >>> 32'h7ffffff1; + `checkh(w16_u, 16'h0000); + if (fail) $stop; $write("*-* All Finished *-*\n"); $finish;