From 9e61b9f696fecb66423404a6882e0397b9c60733 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 Jun 2015 13:43:14 -0400 Subject: [PATCH] Fix width propagation on sized casts, bug925. --- Changes | 2 ++ src/V3Width.cpp | 34 ++++++++++++++++++++++++++------- test_regress/t/t_cast.v | 22 +++++++++++++++++++++ test_regress/t/t_math_signed5.v | 4 ++++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/Changes b/Changes index dd5a60a93..aaef60614 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Fix width extension on mis-width ports, bug918. [Patrick Maupin] +**** Fix width propagation on sized casts, bug925. [Jonathon Donaldson] + **** Fix MSVC++ compiler error, bug927. [Hans Tichelaar] diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9872c1e90..1ee35ec80 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1009,8 +1009,10 @@ private: //if (debug()) newp->dumpTree(cout," CastOut: "); } virtual void visit(AstCastSize* nodep, AstNUser* vup) { + // IEEE: Signedness of result is same as self-determined signedness + // However, the result is same as BITSEL, so we do not sign extend the LHS if (!nodep->rhsp()->castConst()) nodep->v3fatalSrc("Unsupported: Non-const cast of size"); - //if (debug()) nodep->dumpTree(cout," CastPre: "); + //if (debug()) nodep->dumpTree(cout," CastSizePre: "); if (vup->c()->prelim()) { int width = nodep->rhsp()->castConst()->toSInt(); if (width < 1) { nodep->v3error("Size-changing cast to zero or negative size"); width=1; } @@ -1020,12 +1022,29 @@ private: nodep->v3error("Unsupported: Size-changing cast on non-basic data type"); underDtp = nodep->findLogicBoolDType()->castBasicDType(); } - AstNodeDType* newDtp = (underDtp->keyword().isFourstate() - ? nodep->findLogicDType(width, width, underDtp->numeric()) - : nodep->findBitDType(width, width, underDtp->numeric())); - nodep->dtypep(newDtp); - // We ignore warnings as that is sort of the point of a cast - iterateCheck(nodep,"Cast LHS",nodep->lhsp(),CONTEXT,FINAL,newDtp,EXTEND_EXP,false); + // A cast propagates its size to the lower expression and is included in the maximum + // width, so 23'(1'b1 + 1'b1) uses 23-bit math, but 1'(2'h2 * 2'h1) uses two-bit math. + // However the output width is exactly that requested. + // So two steps, first do the calculation's width (max of the two widths) + { + int calcWidth = max(width, underDtp->width()); + AstNodeDType* calcDtp = (underDtp->keyword().isFourstate() + ? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric()) + : nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric())); + nodep->dtypep(calcDtp); + // We ignore warnings as that is sort of the point of a cast + iterateCheck(nodep,"Cast expr",nodep->lhsp(),CONTEXT,FINAL,calcDtp,EXTEND_EXP,false); + } + if (debug()) nodep->dumpTree(cout," CastSizeClc: "); + // Next step, make the proper output width + { + AstNodeDType* outDtp = (underDtp->keyword().isFourstate() + ? nodep->findLogicDType(width, width, underDtp->numeric()) + : nodep->findBitDType(width, width, underDtp->numeric())); + nodep->dtypep(outDtp); + // We ignore warnings as that is sort of the point of a cast + widthCheckSized(nodep,"Cast expr",nodep->lhsp(),outDtp,EXTEND_EXP,false); + } } if (vup->c()->final()) { // CastSize not needed once sizes determined @@ -1033,6 +1052,7 @@ private: nodep->replaceWith(underp); pushDeletep(nodep); nodep=NULL; } + //if (debug()) nodep->dumpTree(cout," CastSizeOut: "); } virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); diff --git a/test_regress/t/t_cast.v b/test_regress/t/t_cast.v index 5f23ff48b..616ac394d 100644 --- a/test_regress/t/t_cast.v +++ b/test_regress/t/t_cast.v @@ -13,6 +13,23 @@ module t; logic [15:0] allones = 16'hffff; parameter FOUR = 4; + // bug925 + localparam [6:0] RESULT = 7'((6*9+92)%96); + + logic signed [14:0] samp0 = 15'h0000; + logic signed [14:0] samp1 = 15'h0000; + logic signed [14:0] samp2 = 15'h6000; + logic signed [11:0] coeff0 = 12'h009; + logic signed [11:0] coeff1 = 12'h280; + logic signed [11:0] coeff2 = 12'h4C5; + logic signed [26:0] mida = ((27'(coeff2 * samp2) >>> 11)); + // verilator lint_off WIDTH + logic signed [26:0] midb = 15'((27'(coeff2 * samp2) >>> 11)); + // verilator lint_on WIDTH + logic signed [14:0] outa = 15'((27'(coeff0 * samp0) >>> 11) + // 27' size casting in order for intermediate result to not be truncated to the width of LHS vector + (27'(coeff1 * samp1) >>> 11) + + (27'(coeff2 * samp2) >>> 11)); // 15' size casting to avoid synthesis/simulator warnings + initial begin if (4'shf > 4'sh0) $stop; if (signed'(4'hf) > 4'sh0) $stop; @@ -24,10 +41,15 @@ module t; if ((4+2)'(allones) !== 6'h3f) $stop; if ((4-2)'(allones) !== 2'h3) $stop; if ((FOUR+2)'(allones) !== 6'h3f) $stop; + if (50 !== RESULT) $stop; o = tocast_t'(4'b1); if (o != 4'b1) $stop; + if (15'h6cec != outa) $stop; + if (27'h7ffecec != mida) $stop; + if (27'h7ffecec != midb) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_math_signed5.v b/test_regress/t/t_math_signed5.v index f8d170080..d2d52c539 100644 --- a/test_regress/t/t_math_signed5.v +++ b/test_regress/t/t_math_signed5.v @@ -169,6 +169,10 @@ `checkh(w32_u, 32'h0000_0180); w32_u = 32'(signed'({4'b0011,5'b10000}) << 3); `checkh(w32_u, 32'h0000_0380); + w32_u = signed'(32'({4'b0001,5'b10000}) << 3); + `checkh(w32_u, 32'h0000_0180); + w32_u = signed'(32'({4'b0011,5'b10000}) << 3); + `checkh(w32_u, 32'h0000_0380); // verilator lint_on WIDTH w32_u = 32'(signed'({4'b0011,5'b10000})) << 3; // Check no width warning `checkh(w32_u, 32'h0000_0380);