Support repeat and forever statements.
This commit is contained in:
parent
8fe0c3dd84
commit
d60d0a60c7
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* Verilator 3.70**
|
||||
|
||||
** Support repeat and forever statements. [Jeremy Bennett]
|
||||
|
||||
*** Add --debugi-<srcfile> option, for internal debugging. [Dennis Muhlestein]
|
||||
|
||||
**** Fix compile issues with GCC 4.3, bug47. [Lane Brooks]
|
||||
|
|
|
|||
|
|
@ -1408,6 +1408,21 @@ struct AstFor : public AstNodeFor {
|
|||
ASTNODE_NODE_FUNCS(For, FOR)
|
||||
};
|
||||
|
||||
struct AstRepeat : public AstNodeStmt {
|
||||
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
|
||||
: AstNodeStmt(fileline) {
|
||||
setOp2p(countp); addNOp3p(bodysp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Repeat, REPEAT)
|
||||
AstNode* countp() const { return op2p()->castNode(); } // op2= condition to continue
|
||||
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountBranch(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
struct AstWhile : public AstNodeStmt {
|
||||
AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp)
|
||||
: AstNodeStmt(fileline) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ private:
|
|||
AstModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_beginScope; // Name of begin blocks above us
|
||||
int m_repeatNum; // Repeat counter
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
|
|
@ -58,6 +59,7 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
|
|
@ -136,6 +138,38 @@ private:
|
|||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
new AstRange(nodep->fileline(), countp->width()-1, 0));
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
countp);
|
||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* condp;
|
||||
if (countp->isSigned()) {
|
||||
condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
} else {
|
||||
condp = new AstGt (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
}
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(decp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
|
|
@ -161,6 +195,7 @@ public:
|
|||
BeginVisitor(AstNetlist* nodep) {
|
||||
m_modp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_repeatNum = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BeginVisitor() {}
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ private:
|
|||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Unroll\n");
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin\n");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
bool oldloop = m_inLoop;
|
||||
|
|
|
|||
|
|
@ -239,6 +239,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
nodep->bodysp()->iterateAndNext(*this);
|
||||
puts("}\n");
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||
puts("repeat (");
|
||||
nodep->countp()->iterateAndNext(*this);
|
||||
puts(") {\n");
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
puts("}\n");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
nodep->precondsp()->iterateAndNext(*this);
|
||||
puts("while (");
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ private:
|
|||
if (m_generate) { // Ignore for's when expanding genfor's
|
||||
nodep->iterateChildren(*this);
|
||||
} else {
|
||||
nodep->v3error("V3Task should have removed standard FORs");
|
||||
nodep->v3error("V3Begin should have removed standard FORs");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -479,9 +479,9 @@ private:
|
|||
nodep->sensesp()->iterateAndNext(*this);
|
||||
if (nodep->disablep()) {
|
||||
nodep->disablep()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
widthCheckReduce(nodep,"Disable",nodep->disablep(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"Disable",nodep->disablep(),1,1); // it's like an if() condition.
|
||||
}
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like an if() condition.
|
||||
nodep->width(1,1);
|
||||
}
|
||||
|
||||
|
|
@ -536,14 +536,18 @@ private:
|
|||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
if (!nodep->castGenFor()) nodep->bodysp()->iterateAndNext(*this);
|
||||
nodep->incsp()->iterateAndNext(*this);
|
||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||
nodep->countp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
// TOP LEVEL NODE
|
||||
nodep->precondsp()->iterateAndNext(*this);
|
||||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
// TOP LEVEL NODE
|
||||
|
|
@ -553,7 +557,7 @@ private:
|
|||
nodep->elsesp()->iterateAndNext(*this);
|
||||
}
|
||||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
widthCheckReduce(nodep,"If",nodep->condp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"If",nodep->condp(),1,1); // it's like an if() condition.
|
||||
//if (debug()) nodep->dumpTree(cout," IfPos: ");
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
|
|
@ -654,19 +658,19 @@ private:
|
|||
// TOP LEVEL NODE
|
||||
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
nodep->stmtsp()->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
||||
// TOP LEVEL NODE
|
||||
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||
// TOP LEVEL NODE
|
||||
nodep->propp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
nodep->passsp()->iterateAndNext(*this);
|
||||
nodep->failsp()->iterateAndNext(*this);
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like a if() condition.
|
||||
widthCheckReduce(nodep,"Property",nodep->propp(),1,1); // it's like an if() condition.
|
||||
}
|
||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||
//if (debug()) nodep->dumpTree(cout,"- PinPre: ");
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"endspecify" {yylval.fileline = CRELINE(); return yENDSPECIFY;}
|
||||
"endtask" {yylval.fileline = CRELINE(); return yENDTASK;}
|
||||
"for" {yylval.fileline = CRELINE(); return yFOR;}
|
||||
"forever" {yylval.fileline = CRELINE(); return yFOREVER;}
|
||||
"function" {yylval.fileline = CRELINE(); return yFUNCTION;}
|
||||
"if" {yylval.fileline = CRELINE(); return yIF;}
|
||||
"initial" {yylval.fileline = CRELINE(); return yINITIAL;}
|
||||
|
|
@ -220,6 +221,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"pulldown" {yylval.fileline = CRELINE(); return yPULLDOWN;}
|
||||
"pullup" {yylval.fileline = CRELINE(); return yPULLUP;}
|
||||
"reg" {yylval.fileline = CRELINE(); return yREG;}
|
||||
"repeat" {yylval.fileline = CRELINE(); return yREPEAT;}
|
||||
"scalared" {yylval.fileline = CRELINE(); return ySCALARED;}
|
||||
"specify" {yylval.fileline = CRELINE(); return ySPECIFY;}
|
||||
"specparam" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
|
||||
|
|
@ -252,7 +254,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"endtable" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"event" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"force" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"forever" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"fork" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"highz0" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"highz1" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
|
|
@ -268,7 +269,6 @@ escid \\[^ \t\f\r\n]+
|
|||
"real" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"realtime" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"release" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"repeat" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"rnmos" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"rpmos" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
"rtran" {yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext);}
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ class AstSenTree;
|
|||
%token<fileline> yENDTASK "endtask"
|
||||
%token<fileline> yFINAL "final"
|
||||
%token<fileline> yFOR "for"
|
||||
%token<fileline> yFOREVER "forever"
|
||||
%token<fileline> yFUNCTION "function"
|
||||
%token<fileline> yGENERATE "generate"
|
||||
%token<fileline> yGENVAR "genvar"
|
||||
|
|
@ -244,6 +245,7 @@ class AstSenTree;
|
|||
%token<fileline> yPULLDOWN "pulldown"
|
||||
%token<fileline> yPULLUP "pullup"
|
||||
%token<fileline> yREG "reg"
|
||||
%token<fileline> yREPEAT "repeat"
|
||||
%token<fileline> ySCALARED "scalared"
|
||||
%token<fileline> ySIGNED "signed"
|
||||
%token<fileline> ySPECIFY "specify"
|
||||
|
|
@ -1062,6 +1064,8 @@ stmt<nodep>:
|
|||
| yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||
//
|
||||
// // IEEE: loop_statement (INCOMPLETE)
|
||||
| yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,V3Number($1,1,1)),$2); }
|
||||
| yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);}
|
||||
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
||||
| yFOR '(' varRefBase '=' expr ';' expr ';' varRefBase '=' expr ')' stmtBlock
|
||||
{ $$ = new AstFor($1, new AstAssign($4,$3,$5)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#!/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
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2009 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
reg signed [2:0] negcnt;
|
||||
integer times;
|
||||
integer repeats;
|
||||
initial begin
|
||||
times = 0;
|
||||
repeat (1) begin
|
||||
repeat (0) $stop;
|
||||
repeat (-1) $stop;
|
||||
negcnt = 'sb111;
|
||||
repeat (negcnt) $stop;
|
||||
repeat (5) begin
|
||||
repeat (2) begin
|
||||
times = times + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
if (times != 10) $stop;
|
||||
//
|
||||
repeats = 0;
|
||||
forever begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue