diff --git a/Changes b/Changes index de6a843b5..cc6966a12 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, bug766. [Clifford Wolf] +**** Fix huge shifts to zero with -Wno-WIDTH, bug765, bug766, bug768. [Clifford Wolf] **** Fix gate primitives with arrays and non-arrayed pins. diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 28226a72a..ae8c04b35 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3194,9 +3194,11 @@ struct AstExtendS : public AstNodeUniop { // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() AstExtendS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {} AstExtendS(FileLine* fl, AstNode* lhsp, int width) : AstNodeUniop(fl, lhsp) { + // Important that widthMin be correct, as opExtend requires it after V3Expand dtypeSetLogicSized(width,width,AstNumeric::UNSIGNED); } ASTNODE_NODE_FUNCS(ExtendS, EXTENDS) - virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opExtendS(lhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs) { + out.opExtendS(lhs, lhsp()->widthMin()); } virtual string emitVerilog() { return "%l"; } virtual string emitC() { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; } virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} @@ -3876,10 +3878,12 @@ struct AstShiftRS : public AstNodeBiop { // Output data type's width determines which bit is used for sign extension AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0) : AstNodeBiop(fl, lhsp, rhsp) { + // Important that widthMin be correct, as opExtend requires it after V3Expand if (setwidth) { dtypeSetLogicSized(setwidth,setwidth,AstNumeric::SIGNED); } } ASTNODE_NODE_FUNCS(ShiftRS, SHIFTRS) - virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opShiftRS(lhs,rhs); } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + out.opShiftRS(lhs,rhs,lhsp()->widthMin()); } virtual string emitVerilog() { return "%k(%l %f>>> %r)"; } virtual string emitC() { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 857181875..99321c589 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1133,7 +1133,7 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) { return *this; } -V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) { +V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits) { // L(lhs) bit return // The spec says a unsigned >>> still acts as a normal >>. // We presume it is signed; as that's V3Width's job to convert to opShiftR @@ -1142,11 +1142,11 @@ V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) { uint32_t rhsval = rhs.toUInt(); if (rhsval < (uint32_t)lhs.width()) { for (int bit=0; bitwidth(); bit++) { - setBit(bit,lhs.bitIsExtend(bit + rhsval)); + setBit(bit,lhs.bitIsExtend(bit + rhsval, lbits)); } } else { for (int bit=0; bitwidth(); bit++) { - setBit(bit,lhs.bitIsExtend(lhs.width()-1)); + setBit(bit,lhs.bitIs(lbits-1)); } } return *this; @@ -1481,11 +1481,11 @@ V3Number& V3Number::opAssign (const V3Number& lhs) { return *this; } -V3Number& V3Number::opExtendS (const V3Number& lhs) { +V3Number& V3Number::opExtendS (const V3Number& lhs, uint32_t lbits) { // Note may be a width change during the sign extension setZero(); for(int bit=0; bitwidth(); bit++) { - setBit(bit,lhs.bitIsExtend(bit)); + setBit(bit,lhs.bitIsExtend(bit, lbits)); } return *this; } diff --git a/src/V3Number.h b/src/V3Number.h index c0940cf23..1ef58c6f5 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -66,10 +66,12 @@ private: } 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 { + char bitIsExtend (int bit, int lbits) const { + // lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less if (bit<0) return '0'; - if (bit>=m_width) { - bit = m_width-1; + UASSERT(lbits<=m_width, "Extend of wrong size"); + if (bit>=lbits) { + bit = lbits ? lbits-1 : 0; // We do sign extend return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0) | ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); @@ -205,7 +207,7 @@ public: V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1 // V3Number& opAssign (const V3Number& lhs); - V3Number& opExtendS (const V3Number& lhs); // Sign extension + V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension V3Number& opRedOr (const V3Number& lhs); V3Number& opRedAnd (const V3Number& lhs); V3Number& opRedXor (const V3Number& lhs); @@ -257,7 +259,7 @@ public: V3Number& opRotR (const V3Number& lhs, const V3Number& rhs); V3Number& opRotL (const V3Number& lhs, const V3Number& rhs); V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs); - V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs); // Arithmetic w/carry + V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs); // Comparisons V3Number& opEq (const V3Number& lhs, const V3Number& rhs); diff --git a/test_regress/t/t_math_signed5.v b/test_regress/t/t_math_signed5.v index a93c74307..0222e048e 100644 --- a/test_regress/t/t_math_signed5.v +++ b/test_regress/t/t_math_signed5.v @@ -123,6 +123,16 @@ w16_u = (w16a_u >> 16) >>> 32'h7ffffff1; `checkh(w16_u, 16'h0000); + // bug768 + w4_s = 4'sd4; + w4_u = $signed(5'd1 > w4_s-w4_s); + `checkh(w4_u, 4'b1111); +`ifdef VERILATOR + w4_s = $c4("4"); // Eval at runtime +`endif + w4_u = $signed(5'd1 > w4_s-w4_s); + `checkh(w4_u, 4'b1111); + if (fail) $stop; $write("*-* All Finished *-*\n"); $finish;