diff --git a/Changes b/Changes index 698953a98..ff6999eb6 100644 --- a/Changes +++ b/Changes @@ -25,7 +25,7 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix modport function import not-found error. -**** Fix signed extension problem with -Wno-WIDTH, bug729. [Clifford Wolf] +**** Fix signed extension problems with -Wno-WIDTH, bug729. [Clifford Wolf] **** Fix power operator calculation, bug730. [Clifford Wolf] diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a112e1cf4..4f0413879 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -103,6 +103,7 @@ public: AstNodeDType* dtypep() const { return m_dtypep; } bool prelim() const { return m_stage&1; } bool final() const { return m_stage&2; } + bool isSelfDetermined() const { return m_dtypep == NULL; } // i.e. made with ANYSIZE char stageAscii() const { return "-PFB"[m_stage]; } }; ostream& operator<<(ostream& str, const WidthVP* vup) { @@ -123,6 +124,13 @@ private: bool m_doGenerate; // Do errors later inside generate statement int m_dtTables; // Number of created data type tables + // ENUMS + enum ExtendRule { + EXTEND_EXP, // Extend if expect sign and node signed, e.g. where node=x/y in "x + y" + EXTEND_ZERO, // Extend with zeros. e.g. node=x/y in "$signed(x) == $unsigned(y)" + EXTEND_LHS // Extend with sign if node signed. e.g. node=x/y in "$signed(x) == $signed(y)" + }; + // CLASSES #define ANYSIZE 0 @@ -295,8 +303,8 @@ private: nodep->expr2p()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); // Error report and change sizes for suboperands of this node. widthCheckReduce(nodep,"Conditional Test",nodep->condp()); - widthCheck(nodep,"Conditional True",nodep->expr1p(),subDTypep); - widthCheck(nodep,"Conditional False",nodep->expr2p(),subDTypep); + widthCheck(nodep,"Conditional True",nodep->expr1p(),subDTypep,EXTEND_EXP); + widthCheck(nodep,"Conditional False",nodep->expr2p(),subDTypep,EXTEND_EXP); } } virtual void visit(AstConcat* nodep, AstNUser* vup) { @@ -427,7 +435,7 @@ private: <<" bits from only "<fromp()->width()<<" bit number"); // Extend it. AstNodeDType* subDTypep = nodep->findLogicDType(width,width,nodep->fromp()->dtypep()->numeric()); - widthCheck(nodep,"errorless...",nodep->fromp(),subDTypep,true/*noerror*/); + widthCheck(nodep,"errorless...",nodep->fromp(),subDTypep,EXTEND_EXP,true/*noerror*/); } // Check bit indexes. // What is the MSB? We want the true MSB, not one starting at 0, @@ -482,7 +490,7 @@ private: if (!m_doGenerate) { AstNodeDType* subDTypep = nodep->findLogicDType(selwidth, selwidth, nodep->lsbp()->dtypep()->numeric()); - widthCheck(nodep,"Extract Range",nodep->lsbp(),subDTypep,true); + widthCheck(nodep,"Extract Range",nodep->lsbp(),subDTypep,EXTEND_EXP,true); } } } @@ -529,7 +537,7 @@ private: UINFO(1," Related dtype: "<dtypep()<bitp(),selDTypep,true); + widthCheck(nodep,"Extract Range",nodep->bitp(),selDTypep,EXTEND_EXP,true); } } @@ -629,7 +637,7 @@ private: nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p()); // rhs already finalized in shift_prelim nodep->dtypeChgSigned(nodep->lhsp()->isSigned()); - widthCheck(nodep,"LHS",nodep->lhsp(),nodep->dtypep()); + widthCheck(nodep,"LHS",nodep->lhsp(),nodep->dtypep(),EXTEND_EXP); AstNode* newp = NULL; // No change if (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()) { newp = new AstPowSS (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), @@ -811,7 +819,7 @@ private: // Note widthCheck might modify nodep->lhsp() AstNodeDType* subDTypep = nodep->findLogicDType(nodep->width(),nodep->width(), nodep->lhsp()->dtypep()->numeric()); - widthCheck(nodep,"Cast",nodep->lhsp(),subDTypep,true); + widthCheck(nodep,"Cast",nodep->lhsp(),subDTypep,EXTEND_EXP,true); } AstNode* newp = nodep->lhsp()->unlinkFrBack(); if (basicp->isDouble() && !newp->isDouble()) { @@ -852,7 +860,7 @@ private: AstNode* underp = nodep->lhsp()->unlinkFrBack(); nodep->replaceWith(underp); if (underp->width()!=width) { - fixWidthExtend(underp, newDtp); + fixWidthExtend(underp, newDtp, EXTEND_EXP); } pushDeletep(nodep); nodep=NULL; } @@ -942,10 +950,7 @@ private: //if (debug()) nodep->dumpTree(cout," final: "); if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep(),BOTH).p()); if (!nodep->valuep()->castInitArray()) { // No dtype at present, perhaps TODO - widthCheck(nodep,"Initial value",nodep->valuep(),nodep->dtypep()); - } - if (nodep->isDouble() && !nodep->valuep()->isDouble()) { - spliceCvtD(nodep->valuep()); + widthCheck(nodep,"Initial value",nodep->valuep(),nodep->dtypep(),EXTEND_EXP); } } UINFO(4,"varWidthed "<valuep()->iterateAndNext(*this,WidthVP(width,0,BOTH).p()); int mwidth = nodep->valuep()->widthMin(); // Value determines minwidth nodep->dtypeChgWidth(width, mwidth); - widthCheck(nodep,"Enum value",nodep->valuep(),nodep->dtypep()); + widthCheck(nodep,"Enum value",nodep->valuep(),nodep->dtypep(),EXTEND_EXP); } } virtual void visit(AstEnumItemRef* nodep, AstNUser* vup) { @@ -1076,9 +1081,9 @@ private: nodep->exprp()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p()); AstNodeDType* subDTypep = nodep->findLogicDType(width,mwidth,nodep->exprp()->dtypep()->numeric()); for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) { - widthCheck(nodep,"Inside Item",itemp,subDTypep); + widthCheck(nodep,"Inside Item",itemp,subDTypep,EXTEND_EXP); } - widthCheck(nodep,"Inside expression",nodep->exprp(),subDTypep); + widthCheck(nodep,"Inside expression",nodep->exprp(),subDTypep,EXTEND_EXP); nodep->dtypeSetLogicBool(); if (debug()>=9) nodep->dumpTree(cout,"-inside-in: "); // Now rip out the inside and replace with simple math @@ -1422,7 +1427,7 @@ private: if (nodep->lhssp()->nextp()) nodep->v3fatalSrc("PatMember value should be singular w/replicates removed"); nodep->lhssp()->dtypeFrom(nodep); nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p()); - widthCheck(nodep,"Value",nodep->lhssp(),vdtypep); + widthCheck(nodep,"Value",nodep->lhssp(),vdtypep,EXTEND_EXP); } int visitPatMemberRep(AstPatMember* nodep) { uint32_t times = 1; @@ -1479,10 +1484,10 @@ private: for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstNode* condp = itemp->condsp(); condp; condp=condp->nextp()) { condp->iterate(*this,WidthVP(subDTypep,FINAL).p()); - widthCheck(nodep,"Case Item",condp,subDTypep); + widthCheck(nodep,"Case Item",condp,subDTypep,EXTEND_EXP); } } - widthCheck(nodep,"Case expression",nodep->exprp(),subDTypep); + widthCheck(nodep,"Case expression",nodep->exprp(),subDTypep,EXTEND_EXP); } virtual void visit(AstNodeFor* nodep, AstNUser*) { // TOP LEVEL NODE @@ -1542,7 +1547,8 @@ private: // it using the normal width reduction checks. //UINFO(0,"aw "<rhsp()->width()<<" m"<rhsp()->widthMin()<dtypep(); - widthCheck(nodep,"Assign RHS",nodep->rhsp(),subDTypep); + // Note assignments do not look at the LHS's sign, extend based on right only + widthCheck(nodep,"Assign RHS",nodep->rhsp(),subDTypep,EXTEND_LHS); //if (debug()) nodep->dumpTree(cout," AssignOut: "); } } @@ -1892,7 +1898,7 @@ private: // (get an ASSIGN with EXTEND on the lhs instead of rhs) } if (portp->basicp() && !portp->basicp()->isOpaque()) { - widthCheck(nodep,"Function Argument",pinp,portp->dtypep()); + widthCheck(nodep,"Function Argument",pinp,portp->dtypep(),EXTEND_EXP); } } } @@ -1933,7 +1939,7 @@ private: checkCvtUS(nodep->lhsp()); nodep->dtypeSetDouble(); AstNodeDType* subDTypep = nodep->findLogicDType(64,64, nodep->lhsp()->dtypep()->numeric()); - widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,EXTEND_EXP); } } void visit_Or_Ls32(AstNodeUniop* nodep, AstNUser* vup) { @@ -1944,7 +1950,7 @@ private: checkCvtUS(nodep->lhsp()); nodep->dtypeSetDouble(); AstNodeDType* subDTypep = nodep->findLogicDType(32,32, nodep->lhsp()->dtypep()->numeric()); - widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,EXTEND_EXP); } } void visit_Os32_Lr(AstNodeUniop* nodep, AstNUser* vup) { @@ -2016,10 +2022,12 @@ private: // Widths: 1 bit out, lhs width == rhs width // Signed: if RHS&LHS signed, OPERATOR CHANGES to signed flavor // Real: allowed on RHS, if RHS|LHS is real, both become real, and OPERATOR CHANGES + // IEEE, 11.4.4: relational compares (<,>,<=,>=,==,===,!=,!==) use "zero padding" on unsigned if (vup->c()->prelim()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); } + bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned(); if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) { spliceCvtD(nodep->lhsp()); spliceCvtD(nodep->rhsp()); @@ -2027,7 +2035,6 @@ private: nodep = newp; // Process new node instead } } else { - bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned(); if (AstNodeBiop* newp=replaceWithUOrSVersion(nodep, signedFl)) { nodep=NULL; nodep = newp; // Process new node instead } @@ -2036,12 +2043,12 @@ private: int width = max(nodep->lhsp()->width(), nodep->rhsp()->width()); int ewidth = max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()); AstNodeDType* subDTypep = nodep->findLogicDType(width, ewidth, - AstNumeric::fromBool(nodep->signedFlavor())); + AstNumeric::fromBool(signedFl)); if (vup->c()->final()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); nodep->rhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); - widthCheck(nodep, "LHS", nodep->lhsp(), subDTypep); - widthCheck(nodep, "RHS", nodep->rhsp(), subDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,signedFl?EXTEND_LHS:EXTEND_ZERO); + widthCheck(nodep,"RHS",nodep->rhsp(),subDTypep,signedFl?EXTEND_LHS:EXTEND_ZERO); } } void visit_cmp_O1_LRrus(AstNodeBiop* nodep, AstNUser* vup, bool real_lhs) { @@ -2050,6 +2057,7 @@ private: // Widths: 1 bit out, lhs width == rhs width // Signed compare (not output) if both sides signed // Real if and only if real_lhs set + // IEEE, 11.4.4: relational compares (<,>,<=,>=,==,===,!=,!==) use "zero padding" on unsigned if (!nodep->rhsp()) nodep->v3fatalSrc("For binary ops only!"); if (vup->c()->prelim()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); @@ -2071,8 +2079,8 @@ private: if (vup->c()->final()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); nodep->rhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); - widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep); - widthCheck(nodep,"RHS",nodep->rhsp(),subDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,signedFl?EXTEND_LHS:EXTEND_ZERO); + widthCheck(nodep,"RHS",nodep->rhsp(),subDTypep,signedFl?EXTEND_LHS:EXTEND_ZERO); } } @@ -2105,25 +2113,28 @@ private: AstNodeDType* subDTypep = nodep->dtypep(); if (vup->c()->final()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); - widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,EXTEND_EXP); } } void visit_Ous_Lus_Wforce(AstNodeUniop* nodep, AstNUser* vup, AstNumeric rs_out) { // CALLER: Signed, Unsigned // Widths: lhs is self determined width - // Output though still may require extension + // See IEEE-2012 6.24.1 "returns packed array, of size $bits(expression), + // bit if expression is 2-state, otherwise type logic." if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!"); if (vup->c()->prelim()) { nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); checkCvtUS(nodep->lhsp()); } - int width = nodep->lhsp()->width(); - int ewidth = nodep->lhsp()->width(); // Not widthMin; force it. - nodep->dtypeSetLogicSized(width,ewidth,rs_out); + int width = nodep->lhsp()->width(); + nodep->dtypeSetLogicSized(width,width,rs_out); if (vup->c()->final()) { - // Final call, so make sure children check their sizes - nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p()); + // The child's width is self determined + AstNodeDType* subDTypep = nodep->dtypep(); + nodep->lhsp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p()); + // Now extend + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,EXTEND_EXP); } } @@ -2161,7 +2172,7 @@ private: nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p()); AstNodeDType* sublhsDTypep = nodep->findLogicDType(width, ewidth, nodep->lhsp()->dtypep()->numeric()); - widthCheck(nodep,"LHS",nodep->lhsp(),sublhsDTypep); + widthCheck(nodep,"LHS",nodep->lhsp(),sublhsDTypep,EXTEND_EXP); if (nodep->rhsp()->width()>32) { AstConst* shiftp = nodep->rhsp()->castConst(); if (shiftp && shiftp->num().mostSetBitP1() <= 32) { @@ -2214,8 +2225,8 @@ private: rhsOk = (mwidth >= (nodep->rhsp()->widthMin())); } // Error report and change sizes for suboperands of this node. - widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,lhsOk); - widthCheck(nodep,"RHS",nodep->rhsp(),subDTypep,rhsOk); + widthCheck(nodep,"LHS",nodep->lhsp(),subDTypep,EXTEND_EXP,lhsOk); + widthCheck(nodep,"RHS",nodep->rhsp(),subDTypep,EXTEND_EXP,rhsOk); } } @@ -2270,8 +2281,8 @@ private: rhsOk = (mwidth >= (nodep->rhsp()->widthMin())); } // Error report and change sizes for suboperands of this node. - widthCheck(nodep,"LHS",nodep->lhsp(),nodep->dtypep(),lhsOk); - widthCheck(nodep,"RHS",nodep->rhsp(),nodep->dtypep(),rhsOk); + widthCheck(nodep,"LHS",nodep->lhsp(),nodep->dtypep(),EXTEND_EXP,lhsOk); + widthCheck(nodep,"RHS",nodep->rhsp(),nodep->dtypep(),EXTEND_EXP,rhsOk); } //if (debug()>=9) nodep->dumpTree(cout,"-rusou-"); } @@ -2307,16 +2318,20 @@ private: return false; } - void fixWidthExtend (AstNode* nodep, AstNodeDType* expDTypep) { + void fixWidthExtend (AstNode* nodep, AstNodeDType* expDTypep, ExtendRule extendRule) { // Fix the width mismatch by extending or truncating bits // Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312; // A(CONSTwide)+B becomes A(CONSTwidened)+B // A(somewide)+B becomes A(TRUNC(somewide,width))+B // or A(EXTRACT(somewide,width,0))+B - UINFO(4," widthExtend_old: "<castConst(); int expWidth = expDTypep->width(); - if (constp && !expDTypep->isSigned()) { + if (constp && !nodep->isSigned()) { // Save later constant propagation work, just right-size it. V3Number num (nodep->fileline(), expWidth); num.opAssign(constp->num()); @@ -2336,13 +2351,26 @@ private: // Extend AstNRelinker linker; nodep->unlinkFrBack(&linker); - AstNode* newp = ((expDTypep->isSigned() && nodep->isSigned()) + bool doSigned; + switch (extendRule) { + case EXTEND_ZERO: doSigned = false; break; + case EXTEND_EXP: doSigned = nodep->isSigned() && expDTypep->isSigned(); break; + case EXTEND_LHS: doSigned = nodep->isSigned(); break; + default: nodep->v3fatalSrc("bad case"); + } + AstNode* newp = (doSigned ? (new AstExtendS(nodep->fileline(), nodep))->castNode() : (new AstExtend (nodep->fileline(), nodep))->castNode()); linker.relink(newp); nodep=newp; } - nodep->dtypeChgWidth(expWidth,expWidth); + if (expDTypep->isDouble() && !nodep->isDouble()) { + // For AstVar init() among others + // TODO do all to-real and to-integer conversions in this function rather than in callers + AstNode* newp = spliceCvtD(nodep); + nodep = newp; + } + nodep->dtypeFrom(expDTypep); UINFO(4," _new: "<findUInt32DType(); - widthCheck(nodep,"file_descriptor",underp,expDTypep,false); - } - void widthCheck (AstNode* nodep, const char* side, - AstNode* underp, int expWidth, int expWidthMin, - bool ignoreWarn=false) { - AstNodeDType* expDTypep = underp->findLogicDType(expWidth, expWidthMin, underp->dtypep()->numeric()); - widthCheck(nodep,side,underp,expDTypep,ignoreWarn); + widthCheck(nodep,"file_descriptor",underp,expDTypep,EXTEND_EXP,false); } void widthCheck (AstNode* nodep, const char* side, AstNode* underp, AstNodeDType* expDTypep, + ExtendRule extendRule, bool ignoreWarn=false) { //UINFO(9,"wchk "<width(); @@ -2444,7 +2467,7 @@ private: <<" bits."); } if (bad || underp->width()!=expWidth) { - fixWidthExtend(underp, expDTypep); underp=NULL;//Changed + fixWidthExtend(underp, expDTypep, extendRule); underp=NULL;//Changed } } @@ -2488,7 +2511,7 @@ private: } // We only fix input mismatches if (bad && inputPin) { - fixWidthExtend(underp, expDTypep); underp=NULL;//Changed + fixWidthExtend(underp, expDTypep, EXTEND_EXP); underp=NULL;//Changed } } @@ -2519,7 +2542,7 @@ private: linker.relink(newp); } } - void spliceCvtD(AstNode* nodep) { + AstNode* spliceCvtD(AstNode* nodep) { // For integer used in REAL context, convert to real // We don't warn here, "2.0 * 2" is common and reasonable if (nodep && !nodep->isDouble()) { @@ -2528,6 +2551,9 @@ private: nodep->unlinkFrBack(&linker); AstNode* newp = new AstIToRD(nodep->fileline(), nodep); linker.relink(newp); + return newp; + } else { + return nodep; } } void spliceCvtS(AstNode* nodep, bool ignoreWarn) { diff --git a/test_regress/t/t_math_signed2.v b/test_regress/t/t_math_signed2.v index fe692cadc..1250f9922 100644 --- a/test_regress/t/t_math_signed2.v +++ b/test_regress/t/t_math_signed2.v @@ -16,14 +16,6 @@ module t (/*AUTOARG*/ reg signed[7:0] delay_minmax[31:0]; integer k; - wire [1:0] bug729_a = ~0; - wire [2:0] bug729_b = ~0; - // verilator lint_off WIDTH - // the $signed becomes EXTEND(SIGNED(bug729_a)), not EXTENDS because the == is unsigned - wire [0:0] bug729_y = $signed(bug729_a) == bug729_b; - // verilator lint_on WIDTH - initial if (bug729_y) $stop; - initial begin in = 11'b10000001000; for(k=0;k<32;k=k+1) diff --git a/test_regress/t/t_math_signed3.pl b/test_regress/t/t_math_signed3.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_math_signed3.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_signed3.v b/test_regress/t/t_math_signed3.v new file mode 100644 index 000000000..ab5f54dc9 --- /dev/null +++ b/test_regress/t/t_math_signed3.v @@ -0,0 +1,89 @@ +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) + +module t (/*AUTOARG*/); + + // verilator lint_off WIDTH + wire [1:0] bug729_au = ~0; + wire signed [1:0] bug729_as = ~0; + wire [2:0] bug729_b = ~0; + // the $signed output is unsigned because the input is unsigned; the signedness does not change. + // See IEEE-2012 6.24.1 "The signedness shall pass through unchanged". + wire [0:0] bug729_yuu = $signed(2'b11) == 3'b111; //1'b0 + wire [0:0] bug729_ysu = $signed(2'sb11) == 3'b111; //1'b0 + wire [0:0] bug729_yus = $signed(2'b11) == 3'sb111; //1'b1 + wire [0:0] bug729_yss = $signed(2'sb11) == 3'sb111; //1'b1 + wire [0:0] bug729_zuu = 2'sb11 == 3'b111; //1'b0 + wire [0:0] bug729_zsu = 2'sb11 == 3'b111; //1'b0 + wire [0:0] bug729_zus = 2'sb11 == 3'sb111; //1'b1 + wire [0:0] bug729_zss = 2'sb11 == 3'sb111; //1'b1 + + wire [3:0] bug733_a = 4'b0010; + wire [3:0] bug733_yu = $signed(|bug733_a); // 4'b1111 note | is always unsigned + wire signed [3:0] bug733_ys = $signed(|bug733_a); // 4'b1111 + + wire [3:0] bug733_zu = $signed(2'b11); // 4'b1111 + wire signed [3:0] bug733_zs = $signed(2'sb11); // 4'b1111 + + // When RHS of assignment is fewer bits than lhs, RHS sign or zero extends based on RHS's sign + + wire [3:0] bug733_qu = 2'sb11; // 4'b1111 + wire signed [3:0] bug733_qs = 2'sb11; // 4'b1111 + reg signed [32:0] bug349_s; + reg signed [32:0] bug349_u; + + wire [3:0] subout_u; + sub sub (.a(2'sb11), .z(subout_u)); + initial `checkh(subout_u, 4'b1111); + + wire [5:0] cond_a = 1'b1 ? 3'sb111 : 5'sb11111; + initial `checkh(cond_a, 6'b111111); + wire [5:0] cond_b = 1'b0 ? 3'sb111 : 5'sb11111; + initial `checkh(cond_b, 6'b111111); + + initial begin + // verilator lint_on WIDTH + `checkh(bug729_yuu, 1'b0); + `checkh(bug729_ysu, 1'b0); + `checkh(bug729_yus, 1'b1); + `checkh(bug729_yss, 1'b1); + + `checkh(bug729_zuu, 1'b0); + `checkh(bug729_zsu, 1'b0); + `checkh(bug729_zus, 1'b1); + `checkh(bug729_zss, 1'b1); + + `checkh(bug733_yu, 4'b1111); + `checkh(bug733_ys, 4'b1111); + + `checkh(bug733_zu, 4'b1111); + `checkh(bug733_zs, 4'b1111); + + `checkh(bug733_qu, 4'b1111); + `checkh(bug733_qs, 4'b1111); + + // verilator lint_off WIDTH + bug349_s = 4'sb1111; + `checkh(bug349_s, 33'h1ffffffff); + bug349_u = 4'sb1111; + `checkh(bug349_u, 33'h1ffffffff); + + bug349_s = 4'sb1111 - 1'b1; + `checkh(bug349_s,33'he); + + bug349_s = 4'sb1111 - 5'b00001; + `checkh(bug349_s,33'he); + + case (2'sb11) + 4'b1111: ; + default: $stop; + endcase + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + +module sub (input [3:0] a, + output [3:0] z); + assign z = a; +endmodule