diff --git a/Changes b/Changes index d0ec0cc89..c15dee736 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Support loop unrolling on width mismatches, bug 333. [Joe Eiler] +**** Support simple cast operators, bug335. [Alex Solomatnikov] + **** Accelerate bit-selected inversions. **** Add error on circular parameter definitions, bug329. [Alex Solomatnikov] diff --git a/bin/verilator b/bin/verilator index aa00c8a62..fc265d26c 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2235,6 +2235,11 @@ Increment/decrement can only be used as standalone statements or in for loops. They cannot be used as side effect operators inside more complicate expressions ("a = b++;"). +=item cast operator + +Casting is supported only between simple scalar types, signed and unsigned, +not arrays nor structs. + =item chandle Treated as a "longint"; does not yet warn about operations that are diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e45510ee6..10909bfd0 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2622,8 +2622,23 @@ struct AstOneHot0 : public AstNodeUniop { virtual int instrCount() const { return widthInstrs()*3; } }; +struct AstCast : public AstNode { + // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc + AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtypep) : AstNode(fl) { + setOp1p(lhsp); setOp2p(dtypep); + if (dtypep) { widthSignedFrom(dtypep); } + } + ASTNODE_NODE_FUNCS(Cast, CAST) + 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(); } + AstNodeDType* dtypep() const { return op2p()->castNodeDType(); } +}; + struct AstCCast : public AstNodeUniop { - // Cast to appropriate data type + // Cast to C-based data type private: int m_size; public: diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 533a86ee8..51469ae40 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -163,6 +163,11 @@ private: nodep->itemp()->iterate(*this); nodep->signedFrom(nodep->itemp()); } + virtual void visit(AstCast* nodep, AstNUser*) { + nodep->lhsp()->iterate(*this); + nodep->dtypep()->iterate(*this); + nodep->signedFrom(nodep->dtypep()); + } virtual void visit(AstConst* nodep, AstNUser*) { // The node got setup with the signed state of the node. // However a later operation may have changed the node->signed w/o changing diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 443536a41..807f394a2 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -524,6 +524,25 @@ private: nodep->iterateChildren(*this, vup); nodep->widthFrom(nodep->dtypep()->skipRefp()); } + virtual void visit(AstCast* nodep, AstNUser* vup) { + nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + nodep->dtypep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + // When more general casts are supported, the cast elimination will be done later. + // For now, replace it ASAP, so widthing can propagate easily + // The cast may change signing, but we don't know the sign yet. Make it so. + // Note we don't sign lhsp() that would make the algorithm O(n^2) if lots of casting. + V3Width::widthParamsEdit(nodep->dtypep()); // MAY CHANGE dtypep() + AstBasicDType* basicp = nodep->dtypep()->basicp(); if (!basicp) nodep->v3fatalSrc("Unimplemented: Casting non-simple data type"); + nodep->widthSignedFrom(basicp); + widthCheck(nodep,"Cast",nodep->lhsp(),nodep->width(),nodep->width(),true); + AstNode* newp = nodep->lhsp()->unlinkFrBack(); + if (basicp->isSigned()) { + newp = new AstSigned(nodep->fileline(), newp); + } else { + newp = new AstUnsigned(nodep->fileline(), newp); + } + nodep->replaceWith(newp); + } 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 fb9a3be56..49a4c5658 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1078,6 +1078,31 @@ signing: // ==IEEE: signing //************************************************ // Data Types +casting_type: // IEEE: casting_type + simple_type { $$ = $1; } + // // IEEE: constant_primary + // // In expr:cast this is expanded to just "expr" + // + // // IEEE: signing + //See where casting_type used + //^^ ySIGNED { $$ = new AstSigned($1,$3); } + //^^ yUNSIGNED { $$ = new AstUnsigned($1,$3); } + //UNSUP ySTRING { $$ = $1; } + //UNSUP yCONST__ETC/*then `*/ { $$ = $1; } + ; + +simple_type: // ==IEEE: simple_type + // // IEEE: integer_type + integer_atom_type { $$ = $1; } + | integer_vector_type { $$ = $1; } + //UNSUP non_integer_type { $$ = $1; } + // // IEEE: ps_type_identifier + // // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE) + | ps_type { $$ = $1; } + // // { generate_block_identifer ... } '.' + // // Need to determine if generate_block_identifier can be lex-detected + ; + data_type: // ==IEEE: data_type // // This expansion also replicated elsewhere, IE data_type__AndID data_typeNoRef { $$ = $1; } @@ -2455,7 +2480,10 @@ expr: // IEEE: part of expression/constant_expression/primary | '_' '(' statePushVlg expr statePop ')' { $$ = $4; } // Arbitrary Verilog inside PSL // // // IEEE: cast/constant_cast - //UNSUP casting_type yP_TICK '(' expr ')' { UNSUP } + | casting_type yP_TICK '(' expr ')' { $$ = new AstCast($2,$4,$1); } + // // expanded from casting_type + | ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned($1,$4); } + | yUNSIGNED yP_TICK '(' expr ')' { $$ = new AstUnsigned($1,$4); } // // 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 } diff --git a/test_regress/t/t_cast.pl b/test_regress/t/t_cast.pl new file mode 100755 index 000000000..7058e622f --- /dev/null +++ b/test_regress/t/t_cast.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_cast.v b/test_regress/t/t_cast.v new file mode 100644 index 000000000..a8b63d562 --- /dev/null +++ b/test_regress/t/t_cast.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2011 by Wilson Snyder. + +module t; + + typedef logic [3:0] mc_t; + typedef mc_t tocast_t; + + mc_t o; + + 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; + + o = tocast_t'(4'b1); + if (o != 4'b1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule