Fix width propagation on sized casts, bug925.

This commit is contained in:
Wilson Snyder 2015-06-06 13:43:14 -04:00
parent 491539ff32
commit 9e61b9f696
4 changed files with 55 additions and 7 deletions

View File

@ -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]

View File

@ -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: ");

View File

@ -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

View File

@ -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);