From a767da4f3f8961003df400c01e4c5457f88b6ac8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 5 Mar 2013 22:13:22 -0500 Subject: [PATCH] Support '() sized casts, bug628. --- Changes | 2 ++ src/V3AstNodes.h | 14 ++++++++++++++ src/V3Width.cpp | 22 ++++++++++++++++++++++ src/verilog.y | 1 + test_regress/t/t_cast.v | 3 +++ 5 files changed, 42 insertions(+) diff --git a/Changes b/Changes index 05f0412fb..9243a4a23 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Support bind in $unit, bug602. [Ed Lander] +**** Support '() sized casts, bug628. [Ed Lander] + **** Fix DETECTARRAY on packed structures, bug610. [Jeremy Bennett] **** Fix LITENDIAN on unpacked structures, bug614. [Wai Sum Mong] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 1de37bf20..4ef64340a 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3184,6 +3184,20 @@ struct AstCast : public AstNode { AstNodeDType* childDTypep() const { return op2p()->castNodeDType(); } }; +struct AstCastSize : public AstNode { + // Cast to specific size; signed/twostate inherited from lower element per IEEE + AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) : AstNode(fl) { + setOp1p(lhsp); setOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(CastSize, CASTSIZE) + virtual string emitVerilog() { return "((%r)'(%l))"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() { V3ERROR_NA; return true;} virtual bool cleanLhs() {return true;} + virtual bool sizeMattersLhs() {return false;} + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } +}; + struct AstCCast : public AstNodeUniop { // Cast to C-based data type private: diff --git a/src/V3Width.cpp b/src/V3Width.cpp index c2a3a7f57..7dbb607ac 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -805,6 +805,28 @@ private: pushDeletep(nodep); nodep=NULL; //if (debug()) newp->dumpTree(cout," CastOut: "); } + virtual void visit(AstCastSize* nodep, AstNUser* vup) { + if (!nodep->rhsp()->castConst()) nodep->v3fatalSrc("Unsupported: Non-const cast of size"); + //if (debug()) nodep->dumpTree(cout," CastPre: "); + int width = nodep->rhsp()->castConst()->toSInt(); + if (width < 1) { nodep->v3error("Size-changing cast to zero or negative size"); width=1; } + nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + AstBasicDType* underDtp = nodep->lhsp()->dtypep()->castBasicDType(); + if (!underDtp) { + 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); + AstNode* underp = nodep->lhsp()->unlinkFrBack(); + nodep->replaceWith(underp); + if (underp->width()!=width) { + fixWidthExtend(underp, newDtp); + } + pushDeletep(nodep); nodep=NULL; + } virtual void visit(AstVar* nodep, AstNUser* vup) { //if (debug()) nodep->dumpTree(cout," InitPre: "); // Must have deterministic constant width diff --git a/src/verilog.y b/src/verilog.y index 6baf41349..de3745e24 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2825,6 +2825,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // Spec only allows primary with addition of a type reference // // We'll be more general, and later assert LHS was a type. //UNSUP ~l~expr yP_TICK '(' expr ')' { UNSUP } + | yaINTNUM yP_TICK '(' expr ')' { $$ = new AstCastSize($2,$4,new AstConst($1->fileline(),*$1)); } // // // IEEE: assignment_pattern_expression // // IEEE: streaming_concatenation diff --git a/test_regress/t/t_cast.v b/test_regress/t/t_cast.v index a8b63d562..cda5ed171 100644 --- a/test_regress/t/t_cast.v +++ b/test_regress/t/t_cast.v @@ -10,11 +10,14 @@ module t; mc_t o; + logic [15:0] allones = 16'hffff; + initial begin if (4'shf > 4'sh0) $stop; if (signed'(4'hf) > 4'sh0) $stop; if (4'hf < 4'h0) $stop; if (unsigned'(4'shf) < 4'h0) $stop; + if (4'(allones) !== 4'hf) $stop; o = tocast_t'(4'b1); if (o != 4'b1) $stop;