diff --git a/Changes b/Changes index 8b3ad40a3..e5ecd160f 100644 --- a/Changes +++ b/Changes @@ -18,6 +18,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support $left, $right and related functions, bug448. [Iztok Jeras] +*** Support inside expressions. + *** Define SYSTEMVERILOG, SV_COV_START and other IEEE mandated predefines. **** Fix pin width mismatch error, bug595. [Alex Solomatnikov] diff --git a/bin/verilator b/bin/verilator index 388c1fb86..4fbd75742 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2558,6 +2558,11 @@ the disable statement itself is inside. This was commonly used to provide loop break and continue functionality before SystemVerilog added the break and continue keywords. +=item inside + +Inside expressions may not include unpacked array traversal or $ as an +upper bound. Case inside and case matches are also unsupported. + =item priority if, unique if Priority and unique if's are treated as normal ifs and not asserted to be diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 6341e68db..6511f1268 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2552,6 +2552,33 @@ struct AstFinal : public AstNode { AstNode* bodysp() const { return op1p()->castNode(); } // op1 = Expressions to evaluate }; +struct AstInside : public AstNodeMath { + AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) + : AstNodeMath(fl) { + addOp1p(exprp); addOp2p(itemsp); + dtypeSetLogicBool(); + } + ASTNODE_NODE_FUNCS(Inside, INSIDE) + AstNode* exprp() const { return op1p()->castNode(); } // op1 = LHS expression to compare with + AstNode* itemsp() const { return op2p()->castNode(); } // op2 = RHS, possibly a list of expr or AstInsideRange + virtual string emitVerilog() { return "%l inside { %r }"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() { return false; } // NA +}; + +struct AstInsideRange : public AstNodeMath { + AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : AstNodeMath(fl) { + addOp1p(lhsp); addOp2p(rhsp); + } + ASTNODE_NODE_FUNCS(InsideRange, INSIDERANGE) + AstNode* lhsp() const { return op1p()->castNode(); } // op1 = LHS + AstNode* rhsp() const { return op2p()->castNode(); } // op2 = RHS + virtual string emitVerilog() { return "[%l:%r]"; } + virtual string emitC() { V3ERROR_NA; return ""; } + virtual bool cleanOut() { return false; } // NA +}; + struct AstInitArray : public AstNode { // Set a var to a large list of values // The values must be in sorted order, and not exceed the size of the var's array. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d3e8fa49d..4ab4dc76c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -996,6 +996,58 @@ private: // Should be correct by construction, so we'll just loop through all types nodep->iterateChildren(*this, vup); } + virtual void visit(AstInside* nodep, AstNUser* vup) { + nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p()); + for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) { + nextip = itemp->nextp(); // Prelim may cause the node to get replaced + itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); itemp=NULL; + } + // Take width as maximum across all items + int width = nodep->exprp()->width(); + int mwidth = nodep->exprp()->widthMin(); + for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) { + width = max(width,itemp->width()); + mwidth = max(mwidth,itemp->widthMin()); + } + // Apply width + nodep->exprp()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p()); + for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) { + widthCheck(nodep,"Inside Item",itemp,width,mwidth); + } + widthCheck(nodep,"Inside expression",nodep->exprp(),width,mwidth); + nodep->dtypeSetLogicBool(); + if (debug()>=9) nodep->dumpTree(cout,"-inside-in: "); + // Now rip out the inside and replace with simple math + AstNode* newp = NULL; + for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) { + nextip = itemp->nextp(); // Will be unlinking + AstNode* inewp; + if (AstInsideRange* irangep = itemp->castInsideRange()) { + inewp = new AstAnd(itemp->fileline(), + new AstGte(itemp->fileline(), + nodep->exprp()->cloneTree(true), + irangep->lhsp()->unlinkFrBack()), + new AstLte(itemp->fileline(), + nodep->exprp()->cloneTree(true), + irangep->rhsp()->unlinkFrBack())); + } else { + inewp = new AstEqWild(itemp->fileline(), + nodep->exprp()->cloneTree(true), + itemp->unlinkFrBack()); + } + if (newp) newp = new AstOr(nodep->fileline(), newp, inewp); + else newp = inewp; + } + if (!newp) newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + if (debug()>=9) newp->dumpTree(cout,"-inside-out: "); + nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL; + } + virtual void visit(AstInsideRange* nodep, AstNUser* vup) { + // Just do each side; AstInside will rip these nodes out later + nodep->lhsp()->iterateAndNext(*this,vup); + nodep->rhsp()->iterateAndNext(*this,vup); + nodep->dtypeFrom(nodep->lhsp()); + } virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed diff --git a/src/verilog.l b/src/verilog.l index 1564e87d9..1a6e206a3 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -424,6 +424,7 @@ word [a-zA-Z0-9_]+ "final" { FL; return yFINAL; } "iff" { FL; return yIFF; } "import" { FL; return yIMPORT; } + "inside" { FL; return yINSIDE; } "int" { FL; return yINT; } "logic" { FL; return yLOGIC; } "longint" { FL; return yLONGINT; } @@ -469,7 +470,6 @@ word [a-zA-Z0-9_]+ "forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "inside" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } diff --git a/src/verilog.y b/src/verilog.y index 4ed264996..70136148e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -332,6 +332,7 @@ class AstSenTree; %token yINITIAL "initial" %token yINOUT "inout" %token yINPUT "input" +%token yINSIDE "inside" %token yINT "int" %token yINTEGER "integer" %token yLOCALPARAM "localparam" @@ -557,7 +558,7 @@ class AstSenTree; // PSL op precedence %right yP_MINUSGT yP_LOGIFF %right yP_ORMINUSGT yP_OREQGT -%left prPSLCLK +%left prPSLCLK // Verilog op precedence %right '?' ':' @@ -567,7 +568,7 @@ class AstSenTree; %left '^' yP_XNOR %left '&' yP_NAND %left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL -%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE +%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE %left yP_SLEFT yP_SRIGHT yP_SSRIGHT %left '+' '-' %left '*' '/' '%' @@ -2245,6 +2246,20 @@ case_itemList: // IEEE: { case_item + ... } | case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); } ; +open_range_list: // ==IEEE: open_range_list + open_value_range + open_value_range { $$ = $1; } + | open_range_list ',' open_value_range { $$ = $1;$1->addNext($3); } + ; + +open_value_range: // ==IEEE: open_value_range + value_range { $$ = $1; } + ; + +value_range: // ==IEEE: value_range + expr { $$ = $1; } + | '[' expr ':' expr ']' { $$ = new AstInsideRange($3,$2,$4); } + ; + caseCondList: // IEEE: part of case_item expr { $$ = $1; } | caseCondList ',' expr { $$ = $1;$1->addNext($3); } @@ -2757,7 +2772,7 @@ expr: // IEEE: part of expression/constant_expression/primary | ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); } // // // IEEE: inside_expression - //UNSUP ~l~expr yINSIDE '{' open_range_list '}' { UNSUP } + | ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); } // // // IEEE: tagged_union_expression //UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP } diff --git a/test_regress/t/t_inside.pl b/test_regress/t/t_inside.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_inside.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_inside.v b/test_regress/t/t_inside.v new file mode 100644 index 000000000..de6baba67 --- /dev/null +++ b/test_regress/t/t_inside.v @@ -0,0 +1,69 @@ +// DESCRIPTION::Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2013 by Wilson Snyder. + +module t; + +`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); + + typedef enum logic [1:0] + { ZERO = 2'd0, + ONE = 2'd1, + TWO = 2'd2, + THREE = 2'd3, + XXX = 2'dx + } num_t; + + function automatic logic is_odd; + input en; + input num_t number; + case (en) + 1'b1: begin + unique if (number inside {ONE, THREE}) + is_odd = 1'b1; + else if (number inside {ZERO, TWO}) + is_odd = 1'b0; + else + is_odd = 1'bx; + end + 1'b0: is_odd = 1'bx; + default: is_odd = 1'bx; + endcase + endfunction + + initial begin + `checkh ((4'd4 inside {4'd1,4'd5}), 1'b0); + `checkh ((4'd4 inside {4'd1,4'd4}), 1'b1); + // + `checkh ((4'b1011 inside {4'b1001}), 1'b0); + `checkh ((4'b1011 inside {4'b1xx1}), 1'b1); // Uses ==? + `checkh ((4'b1001 inside {4'b1xx1}), 1'b1); // Uses ==? + `checkh ((4'b1001 inside {4'b1??1}), 1'b1); +`ifndef VERILATOR + `checkh ((4'b1z11 inside {4'b11?1, 4'b1011}),1'bx); +`endif + // Range + `checkh ((4'd4 inside {[4'd5:4'd3], [4'd10:4'd8]}), 1'b0); // If left of colon < never matches + `checkh ((4'd3 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1); + `checkh ((4'd4 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1); + `checkh ((4'd5 inside {[4'd1:4'd2], [4'd3:4'd5]}), 1'b1); + // + // Unsupported $ bound + // + // Unsupported if unpacked array, elements tranversed + //int unpackedarray [$] = '{8,9}; + //( expr inside {2, 3, unpackedarray}) // { 2,3,8,9} + // + `checkh (is_odd(1'b1, ZERO), 1'd0); + `checkh (is_odd(1'b1, ONE), 1'd1); + `checkh (is_odd(1'b1, TWO), 1'd0); + `checkh (is_odd(1'b1, THREE),1'd1); +`ifndef VERILATOR + `checkh (is_odd(1'b1, XXX), 1'dx); +`endif + // + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule