Support repeat and forever statements.

This commit is contained in:
Wilson Snyder 2009-02-25 22:06:59 -05:00
parent 8fe0c3dd84
commit d60d0a60c7
11 changed files with 129 additions and 12 deletions

View File

@ -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]

View File

@ -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) {

View File

@ -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() {}

View File

@ -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;

View File

@ -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 (");

View File

@ -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");
}
}

View File

@ -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: ");

View File

@ -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);}

View File

@ -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)

17
test_regress/t/t_repeat.pl Executable file
View File

@ -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;

33
test_regress/t/t_repeat.v Normal file
View File

@ -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