diff --git a/Changes b/Changes index 391b7a1c9..b0a425680 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 3.887 devel +** Support foreach, bug1078. [Xuan Guo] + *** Add --no-decoration to remove output comments, msg2015. [Frederic Requin] *** If VM_PARALLEL_BUILDS=1, use OPT_FAST and OPT_SLOW. [Frederic Requin] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index cce454f27..341b023e2 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2677,6 +2677,23 @@ public: ASTNODE_NODE_FUNCS(GenFor, GENFOR) }; +class AstForeach : public AstNodeStmt { +public: + AstForeach(FileLine* fileline, AstNode* arrayp, AstNode* varsp, + AstNode* bodysp) + : AstNodeStmt(fileline) { + setOp1p(arrayp); addNOp2p(varsp); addNOp4p(bodysp); + } + ASTNODE_NODE_FUNCS(Foreach, FOREACH) + AstNode* arrayp() const { return op1p()->castNode(); } // op1= array + AstNode* varsp() const { return op2p()->castNode(); } // op2= variable index list + AstNode* bodysp() const { return op4p()->castNode(); } // op4= body of loop + virtual bool isGateOptimizable() const { return false; } + virtual int instrCount() const { return instrCountBranch(); } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(AstNode* samep) const { return true; } +}; + class AstRepeat : public AstNodeStmt { public: AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index a022f7a84..6c34e5656 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -322,6 +322,51 @@ private: nodep->unlinkFrBack()->deleteTree(); } + virtual void visit(AstForeach* nodep, AstNUser*) { + // FOREACH(array,loopvars,body) + // -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body)) + //nodep->dumpTree(cout, "-foreach-old:"); + AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext(); + AstNode* arrayp = nodep->arrayp(); + int dimension = 1; + // Must do innermost (last) variable first + AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext(); + AstNode* lastVarsp = firstVarsp; + while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); dimension++; } + for (AstNode* varsp = lastVarsp; varsp; varsp=varsp->backp()) { + UINFO(0,"foreachVar "<fileline(); + AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP, + varsp->name(), nodep->findSigned32DType()); + AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT, + new AstVarRef(fl, arrayp->name(), false), + new AstConst(fl, dimension)); + AstNode* rightp = new AstAttrOf(fl, AstAttrType::DIM_RIGHT, + new AstVarRef(fl, arrayp->name(), false), + new AstConst(fl, dimension)); + AstNode* stmtsp = varp; + stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp)); + AstNode* comparep = + new AstCond(fl, new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true)), + // left increments up to right + new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)), + // left decrements down to right + new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); + AstNode* incp = + new AstAssign(fl, new AstVarRef(fl, varp->name(), true), + new AstAdd(fl, new AstVarRef(fl, varp->name(), false), + new AstNegate(fl, new AstAttrOf(fl, AstAttrType::DIM_INCREMENT, + new AstVarRef(fl, arrayp->name(), false), + new AstConst(fl, dimension))))); + stmtsp->addNext(new AstWhile(fl, comparep, newp, incp)); + newp = new AstBegin(nodep->fileline(),"",stmtsp); + dimension--; + } + //newp->dumpTree(cout, "-foreach-new:"); + firstVarsp->deleteTree(); VL_DANGLING(firstVarsp); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } + virtual void visit(AstNodeModule* nodep, AstNUser*) { // Module: Create sim table for entire module and iterate cleanFileline(nodep); diff --git a/src/verilog.l b/src/verilog.l index 0386245df..86ae5f93a 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -261,6 +261,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "endtable" { yyerrorf("Syntax error: ENDTABLE outside of TABLE"); } "endtask" { FL; return yENDTASK; } "for" { FL; return yFOR; } + "foreach" { FL; return yFOREACH; } "forever" { FL; return yFOREVER; } "function" { FL; return yFUNCTION; } "if" { FL; return yIF; } @@ -486,7 +487,6 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "extern" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "first_match" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "foreach" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "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); } diff --git a/src/verilog.y b/src/verilog.y index 88742b0a9..0dd68d6bf 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -344,6 +344,7 @@ class AstSenTree; %token yEXPORT "export" %token yFINAL "final" %token yFOR "for" +%token yFOREACH "foreach" %token yFOREVER "forever" %token yFUNCTION "function" %token yGENERATE "generate" @@ -2327,7 +2328,7 @@ statement_item: // IEEE: statement_item { $$ = new AstBegin($1,"",$3); $3->addNext(new AstWhile($1, $4,$8,$6)); } | yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));} // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 - //UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP } + | yFOREACH '(' idClassForeach '[' loop_variables ']' ')' stmtBlock { $$ = new AstForeach($1,$3,$5,$8); } // // // IEEE: jump_statement | yRETURN ';' { $$ = new AstReturn($1); } @@ -2559,6 +2560,11 @@ for_step: // IEEE: for_step genvar_iteration { $$ = $1; } ; +loop_variables: // IEEE: loop_variables + varRefBase { $$ = $1; } + | loop_variables ',' varRefBase { $$ = $1;$1->addNext($3); } + ; + //************************************************ // Functions/tasks @@ -3546,6 +3552,17 @@ idArrayed: // IEEE: id + select | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); } ; +idClassForeach: + idForeach { $$ = $1; } + | package_scopeIdFollows idForeach { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } + ; + +idForeach: + varRefBase { $$ = $1; } + | idForeach '.' varRefBase { $$ = new AstDot($2,$1,$3); } + ; + + // VarRef without any dots or vectorizaion varRefBase: id { $$ = new AstVarRef($1,*$1,false);} diff --git a/test_regress/t/t_foreach.pl b/test_regress/t/t_foreach.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_foreach.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_foreach.v b/test_regress/t/t_foreach.v new file mode 100644 index 000000000..97fe8021e --- /dev/null +++ b/test_regress/t/t_foreach.v @@ -0,0 +1,76 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2016 by Wilson Snyder. + +`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); + +module t (/*AUTOARG*/); + + // verilator lint_off LITENDIAN + // verilator lint_off WIDTH + + reg [63:0] sum; + reg [2:1] [4:3] array [5:6] [7:8]; + reg [1:2] [3:4] larray [6:5] [8:7]; + + function [63:0] crc (input [63:0] sum, input [31:0] a, input [31:0] b, input [31:0] c, input [31:0] d); + crc = {sum[62:0],sum[63]} ^ {4'b0,a[7:0], 4'h0,b[7:0], 4'h0,c[7:0], 4'h0,d[7:0]}; + endfunction + + initial begin + sum = 0; + foreach (array[a]) begin + sum = crc(sum, a, 0, 0, 0); + end + `checkh(sum, 64'h000000c000000000); + + sum = 0; + foreach (array[a,b]) begin + sum = crc(sum, a, b, 0, 0); + end + `checkh(sum, 64'h000003601e000000); + + sum = 0; + foreach (array[a,b,c]) begin + sum = crc(sum, a, b, c, 0); + end + `checkh(sum, 64'h00003123fc101000); + + sum = 0; + foreach (array[a,b,c,d]) begin + sum = crc(sum, a, b, c, d); + end + `checkh(sum, 64'h0030128ab2a8e557); + + // + + sum = 0; + foreach (larray[a]) begin + sum = crc(sum, a, 0, 0, 0); + end + `checkh(sum, 64'h0000009000000000); + + sum = 0; + foreach (larray[a,b]) begin + sum = crc(sum, a, b, 0, 0); + sum = sum + {4'b0,a[7:0], 4'h0,b[7:0]}; + end + `checkh(sum, 64'h000002704b057073); + + sum = 0; + foreach (larray[a,b,c]) begin + sum = crc(sum, a, b, c, 0); + end + `checkh(sum, 64'h00002136f9000000); + + sum = 0; + foreach (larray[a,b,c,d]) begin + sum = crc(sum, a, b, c, d); + end + `checkh(sum, 64'h0020179aa7aa0aaa); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule