Merge pull request #855 from steveicarus/steveicarus/loop-control-support
Add break and continue loop control statements support
This commit is contained in:
commit
b74059eaa9
13
Statement.h
13
Statement.h
|
|
@ -211,6 +211,12 @@ class PBlock : public PScope, public Statement, public PNamedItem {
|
|||
std::vector<Statement*>list_;
|
||||
};
|
||||
|
||||
class PBreak : public Statement {
|
||||
public:
|
||||
void dump(std::ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
class PCallTask : public Statement {
|
||||
|
||||
public:
|
||||
|
|
@ -345,6 +351,13 @@ class PCondit : public Statement {
|
|||
PCondit& operator= (const PCondit&);
|
||||
};
|
||||
|
||||
class PContinue : public Statement {
|
||||
|
||||
public:
|
||||
virtual void dump(std::ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
};
|
||||
|
||||
class PDeassign : public Statement {
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -1180,6 +1180,11 @@ void NetBlock::dump(ostream&o, unsigned ind) const
|
|||
o << setw(ind) << "" << "end" << endl;
|
||||
}
|
||||
|
||||
void NetBreak::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "break;" << endl;
|
||||
}
|
||||
|
||||
void NetCase::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
|
@ -1248,6 +1253,11 @@ void NetCondit::dump(ostream&o, unsigned ind) const
|
|||
}
|
||||
}
|
||||
|
||||
void NetContinue::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "continue;" << endl;
|
||||
}
|
||||
|
||||
void NetContribution::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "";
|
||||
|
|
@ -1386,10 +1396,26 @@ void NetForLoop::dump(ostream&fd, unsigned ind) const
|
|||
fd << index_->name();
|
||||
else
|
||||
fd << "<nil>";
|
||||
fd << ", init_expr=";
|
||||
if (init_expr_)
|
||||
fd << *init_expr_;
|
||||
else
|
||||
fd << "<nil>";
|
||||
fd << ", condition=";
|
||||
if (condition_)
|
||||
fd << *condition_;
|
||||
else
|
||||
fd << "<nil>";
|
||||
fd << endl;
|
||||
fd << setw(ind+4) << "" << "Init Statement {" << endl;
|
||||
if (init_statement_)
|
||||
init_statement_->dump(fd, ind+8);
|
||||
fd << setw(ind+4) << "" << "}" << endl;
|
||||
statement_->dump(fd, ind+4);
|
||||
fd << setw(ind+4) << "" << "Step Statement {" << endl;
|
||||
if (step_statement_)
|
||||
step_statement_->dump(fd, ind+4);
|
||||
step_statement_->dump(fd, ind+8);
|
||||
fd << setw(ind+4) << "" << "}" << endl;
|
||||
}
|
||||
|
||||
void NetFree::dump(ostream&o, unsigned ind) const
|
||||
|
|
|
|||
32
elaborate.cc
32
elaborate.cc
|
|
@ -3055,6 +3055,21 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
|||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PBreak::elaborate(Design*des, NetScope*) const
|
||||
{
|
||||
if (!gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "'break' jump statement requires SystemVerilog." << endl;
|
||||
des->errors += 1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
NetBreak*res = new NetBreak;
|
||||
res->set_line(*this);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int test_case_width(Design*des, NetScope*scope, PExpr*pe,
|
||||
PExpr::width_mode_t&mode)
|
||||
{
|
||||
|
|
@ -3447,6 +3462,20 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
|||
return res;
|
||||
}
|
||||
|
||||
NetProc* PContinue::elaborate(Design*des, NetScope*) const
|
||||
{
|
||||
if (!gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "'continue' jump statement requires SystemVerilog." << endl;
|
||||
des->errors += 1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NetContinue*res = new NetContinue;
|
||||
res->set_line(*this);
|
||||
return res;
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (peek_tail_name(path_)[0] == '$') {
|
||||
|
|
@ -5445,7 +5474,6 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step);
|
||||
stmt->set_line(*this);
|
||||
stmt->wrap_up();
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
|
@ -5520,7 +5548,6 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope,
|
|||
|
||||
stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step);
|
||||
stmt->set_line(*this);
|
||||
stmt->wrap_up();
|
||||
|
||||
sub = stmt;
|
||||
}
|
||||
|
|
@ -5646,7 +5673,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step);
|
||||
loop->set_line(*this);
|
||||
loop->wrap_up();
|
||||
return loop;
|
||||
}
|
||||
|
||||
|
|
|
|||
36
emit.cc
36
emit.cc
|
|
@ -243,6 +243,11 @@ bool NetBlock::emit_proc(struct target_t*tgt) const
|
|||
return tgt->proc_block(this);
|
||||
}
|
||||
|
||||
bool NetBreak::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_break(this);
|
||||
}
|
||||
|
||||
bool NetCase::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_case(this);
|
||||
|
|
@ -259,6 +264,11 @@ bool NetCondit::emit_proc(struct target_t*tgt) const
|
|||
return tgt->proc_condit(this);
|
||||
}
|
||||
|
||||
bool NetContinue::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_continue(this);
|
||||
}
|
||||
|
||||
bool NetContribution::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_contribution(this);
|
||||
|
|
@ -298,7 +308,31 @@ bool NetForever::emit_proc(struct target_t*tgt) const
|
|||
|
||||
bool NetForLoop::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_block(as_block_);
|
||||
return tgt->proc_forloop(this);
|
||||
}
|
||||
|
||||
bool NetForLoop::emit_recurse_init(struct target_t*tgt) const
|
||||
{
|
||||
if (init_statement_) return init_statement_->emit_proc(tgt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetForLoop::emit_recurse_stmt(struct target_t*tgt) const
|
||||
{
|
||||
if (statement_) return statement_->emit_proc(tgt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetForLoop::emit_recurse_step(struct target_t*tgt) const
|
||||
{
|
||||
if (step_statement_) return step_statement_->emit_proc(tgt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetForLoop::emit_recurse_condition(struct expr_scan_t*tgt) const
|
||||
{
|
||||
if (condition_) condition_->expr_scan(tgt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetFree::emit_proc(struct target_t*tgt) const
|
||||
|
|
|
|||
2
ivl.def
2
ivl.def
|
|
@ -294,6 +294,7 @@ ivl_stmt_delay_val
|
|||
ivl_stmt_events
|
||||
ivl_stmt_file
|
||||
ivl_stmt_flow_control
|
||||
ivl_stmt_init_stmt
|
||||
ivl_stmt_lexp
|
||||
ivl_stmt_lineno
|
||||
ivl_stmt_lval
|
||||
|
|
@ -307,6 +308,7 @@ ivl_stmt_parm
|
|||
ivl_stmt_parm_count
|
||||
ivl_stmt_rval
|
||||
ivl_stmt_sfunc_as_task
|
||||
ivl_stmt_step_stmt
|
||||
ivl_stmt_sub_stmt
|
||||
|
||||
ivl_switch_a
|
||||
|
|
|
|||
29
ivl_target.h
29
ivl_target.h
|
|
@ -409,18 +409,21 @@ typedef enum ivl_statement_type_e {
|
|||
IVL_ST_ASSIGN = 2,
|
||||
IVL_ST_ASSIGN_NB = 3,
|
||||
IVL_ST_BLOCK = 4,
|
||||
IVL_ST_BREAK = 32,
|
||||
IVL_ST_CASE = 5,
|
||||
IVL_ST_CASER = 24, /* Case statement with real expressions. */
|
||||
IVL_ST_CASEX = 6,
|
||||
IVL_ST_CASEZ = 7,
|
||||
IVL_ST_CASSIGN = 8,
|
||||
IVL_ST_CONDIT = 9,
|
||||
IVL_ST_CONTINUE= 33,
|
||||
IVL_ST_CONTRIB = 27,
|
||||
IVL_ST_DEASSIGN = 10,
|
||||
IVL_ST_DELAY = 11,
|
||||
IVL_ST_DELAYX = 12,
|
||||
IVL_ST_DISABLE = 13,
|
||||
IVL_ST_DO_WHILE = 30,
|
||||
IVL_ST_FORLOOP = 34,
|
||||
IVL_ST_FORCE = 14,
|
||||
IVL_ST_FOREVER = 15,
|
||||
IVL_ST_FORK = 16,
|
||||
|
|
@ -2215,6 +2218,21 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net);
|
|||
* force l-values, and also non-constant bit or part selects. The
|
||||
* compiler will assure these constraints are met.
|
||||
*
|
||||
* - IVL_ST_FORLOOP
|
||||
* This contains the key portions of a for loop, broken into the init
|
||||
* statement, the sub statement, and the step statement. There is also
|
||||
* a condition expression that the code generator must check. It is up
|
||||
* to the target code generator to put these to use. In general, the
|
||||
* result needs to reflect this:
|
||||
*
|
||||
* ivl_stmt_init_stmt(net);
|
||||
* while( <ivl_stmt_cond_expr> is true ) {
|
||||
* ivl_stmt_sub_stmt(net);
|
||||
* continue_label:
|
||||
* ivl_stmt_step_stmt(net);
|
||||
* }
|
||||
* out_label:
|
||||
*
|
||||
* - IVL_ST_TRIGGER
|
||||
* This represents the "-> name" statement that sends a trigger to a
|
||||
* named event. The ivl_stmt_nevent function should always return 1,
|
||||
|
|
@ -2250,7 +2268,7 @@ extern ivl_expr_t ivl_stmt_case_expr(ivl_statement_t net, unsigned i);
|
|||
extern ivl_case_quality_t ivl_stmt_case_quality(ivl_statement_t net);
|
||||
/* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */
|
||||
extern ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned i);
|
||||
/* IVL_ST_CONDIT IVL_ST_CASE IVL_ST_REPEAT IVL_ST_WHILE */
|
||||
/* IVL_ST_CONDIT IVL_ST_FORLOOP IVL_ST_CASE IVL_ST_REPEAT IVL_ST_WHILE */
|
||||
extern ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net);
|
||||
/* IVL_ST_CONDIT */
|
||||
extern ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net);
|
||||
|
|
@ -2289,9 +2307,14 @@ extern unsigned ivl_stmt_parm_count(ivl_statement_t net);
|
|||
extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
|
||||
/* IVL_ST_STASK */
|
||||
extern ivl_sfunc_as_task_t ivl_stmt_sfunc_as_task(ivl_statement_t net);
|
||||
/* IVL_ST_DELAY, IVL_ST_DELAYX, IVL_ST_FOREVER, IVL_ST_REPEAT
|
||||
IVL_ST_WAIT, IVL_ST_WHILE */
|
||||
/* IVL_ST_DELAY, IVL_ST_DELAYX, IVL_ST_FOREVER, IVL_ST_FORLOOP,
|
||||
IVL_ST_REPEAT, IVL_ST_WAIT, IVL_ST_WHILE */
|
||||
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
|
||||
/* IVL_ST_FORLOOP */
|
||||
extern ivl_statement_t ivl_stmt_init_stmt(ivl_statement_t net);
|
||||
/* IVL_ST_FORLOOP */
|
||||
extern ivl_statement_t ivl_stmt_step_stmt(ivl_statement_t net);
|
||||
|
||||
|
||||
/* SWITCHES
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// github Issue#191
|
||||
//
|
||||
module main;
|
||||
integer idx;
|
||||
initial begin
|
||||
for(idx=0; idx < 5; idx=idx+1 ) begin
|
||||
if (idx >= 2)
|
||||
break;
|
||||
end
|
||||
if (idx != 2) begin
|
||||
$display("FAILED -- break from for loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
forever begin
|
||||
idx += 1;
|
||||
if (idx >= 2)
|
||||
break;
|
||||
end
|
||||
if (idx != 2) begin
|
||||
$display("FAILED -- break from forever loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
while (idx < 5) begin
|
||||
if (idx >= 2)
|
||||
break;
|
||||
idx += 1;
|
||||
end
|
||||
if (idx != 2) begin
|
||||
$display("FAILED -- break from while loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
repeat (5) begin
|
||||
if (idx >= 2)
|
||||
break;
|
||||
idx += 1;
|
||||
end
|
||||
if (idx != 2) begin
|
||||
$display("FAILED -- break from repeat(5) loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// github Issue#191
|
||||
//
|
||||
module main;
|
||||
integer idx;
|
||||
initial begin
|
||||
|
||||
for(idx=0; idx < 5; idx=idx+1 ) begin
|
||||
if (idx < 2)
|
||||
continue;
|
||||
if (idx < 2) begin
|
||||
$display("FAILED -- continue in for-loop");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
if (idx != 5) begin
|
||||
$display("FAILED -- break from for loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
forever begin
|
||||
idx += 1;
|
||||
if (idx < 2)
|
||||
continue;
|
||||
if (idx < 2) begin
|
||||
$display("FAILED -- continue in forever-loop");
|
||||
$finish;
|
||||
end
|
||||
// Need a 'break', since that (and 'return') is the only
|
||||
// way to escape a 'forever' loop.
|
||||
break;
|
||||
end
|
||||
if (idx != 2) begin
|
||||
$display("FAILED -- break from forever loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
while (idx < 5) begin
|
||||
idx += 1;
|
||||
if (idx < 2)
|
||||
continue;
|
||||
if (idx < 2) begin
|
||||
$display("FAILED -- continue in while loop");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
if (idx != 5) begin
|
||||
$display("FAILED -- break from while loop");
|
||||
$finish;
|
||||
end
|
||||
|
||||
idx = 0;
|
||||
repeat (5) begin
|
||||
idx += 1;
|
||||
if (idx < 2)
|
||||
continue;
|
||||
idx += 1;
|
||||
end
|
||||
if (idx != 9) begin
|
||||
$display("FAILED -- continue from repeat(5) loop (idx=%0d)", idx);
|
||||
$finish;
|
||||
end
|
||||
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -173,6 +173,8 @@ br_gh167a normal,-g2009 ivltests
|
|||
br_gh167b normal,-g2009 ivltests
|
||||
br_gh177a normal,-g2009 ivltests
|
||||
br_gh177b normal,-g2009 ivltests
|
||||
br_gh191_break normal,-g2009 ivltests
|
||||
br_gh191_continue normal,-g2009 ivltests
|
||||
br_gh194 normal,-g2009 ivltests
|
||||
br_gh219 normal,-g2009 ivltests
|
||||
br_gh220 normal,-g2009 ivltests
|
||||
|
|
|
|||
|
|
@ -576,6 +576,9 @@ implicit_cast8 EF,-g2009,-pallowsigned=1 ivltests
|
|||
implicit_cast10 EF,-g2009,-pallowsigned=1 ivltests
|
||||
implicit_cast11 EF,-g2009,-pallowsigned=1 ivltests
|
||||
|
||||
# break and continue statements not implemented by translator.
|
||||
br_gh191_break NI ivltests
|
||||
br_gh191_continue NI ivltests
|
||||
# These tests have unresolved failures that still need to be looked at.
|
||||
# The following two have problem getting the correct net/expression
|
||||
# information from the nexus. pr1723367 is the real torture test.
|
||||
|
|
|
|||
|
|
@ -776,13 +776,58 @@ bool NetForever::evaluate_function(const LineInfo&loc,
|
|||
}
|
||||
|
||||
/*
|
||||
* For now, resort to the block form of the statement until we learn
|
||||
* to do this directly.
|
||||
* Process the for-loop to generate a value, as if this were in a function.
|
||||
*/
|
||||
bool NetForLoop::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&context_map) const
|
||||
{
|
||||
return as_block_->evaluate_function(loc, context_map);
|
||||
bool flag = true;
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": NetForLoop::evaluate_function: "
|
||||
<< "Evaluate the for look as a function." << endl;
|
||||
}
|
||||
|
||||
if (init_statement_) {
|
||||
bool tmp_flag = init_statement_->evaluate_function(loc, context_map);
|
||||
flag &= tmp_flag;
|
||||
}
|
||||
|
||||
while (flag && !disable) {
|
||||
// Evaluate the condition expression to try and get the
|
||||
// condition for the loop.
|
||||
NetExpr*cond = condition_->evaluate_function(loc, context_map);
|
||||
if (cond == nullptr) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
|
||||
ivl_assert(loc, cond_const);
|
||||
|
||||
long val = cond_const->value().as_long();
|
||||
delete cond;
|
||||
|
||||
// If the condition is false, then break;
|
||||
if (val == 0)
|
||||
break;
|
||||
|
||||
bool tmp_flag = statement_->evaluate_function(loc, context_map);
|
||||
flag &= tmp_flag;
|
||||
|
||||
if (disable)
|
||||
break;
|
||||
|
||||
tmp_flag = step_statement_->evaluate_function(loc, context_map);
|
||||
flag &= tmp_flag;
|
||||
}
|
||||
|
||||
if (debug_eval_tree) {
|
||||
cerr << get_fileline() << ": NetForLoop::evaluate_function: "
|
||||
<< "Done for-loop, flag=" << (flag?"true":"false") << endl;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool NetRepeat::evaluate_function(const LineInfo&loc,
|
||||
|
|
|
|||
40
net_proc.cc
40
net_proc.cc
|
|
@ -201,42 +201,14 @@ NetForever::~NetForever()
|
|||
NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step)
|
||||
: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step)
|
||||
{
|
||||
as_block_ = NULL;
|
||||
}
|
||||
|
||||
void NetForLoop::wrap_up()
|
||||
{
|
||||
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
||||
|
||||
// Handle the case that we are missing the initialization
|
||||
// statement. This can happen for example with statments like this:
|
||||
// for ( ; <condition> ; <step> ) <statement> ;
|
||||
// If the index_ and init_expr_ are present, then generate the
|
||||
// inital assignment and push it into the sequential block.
|
||||
if (index_ || init_expr_) {
|
||||
top->set_line(*this);
|
||||
if (index_ && init_expr_) {
|
||||
NetAssign_*lv = new NetAssign_(index_);
|
||||
NetAssign*set_stmt = new NetAssign(lv, init_expr_);
|
||||
set_stmt->set_line(*init_expr_);
|
||||
top->append(set_stmt);
|
||||
NetAssign*use_init_statement = new NetAssign(lv, init_expr_);
|
||||
use_init_statement->set_line(*init_expr_);
|
||||
init_statement_ = use_init_statement;
|
||||
} else {
|
||||
init_statement_ = nullptr;
|
||||
}
|
||||
|
||||
NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0);
|
||||
internal_block->set_line(*this);
|
||||
|
||||
if (statement_) internal_block->append(statement_);
|
||||
|
||||
// The step statement is optional. If missing, it is assumed that
|
||||
// the programmer has added it to the regular statement. Hopefully.
|
||||
if (step_statement_)
|
||||
internal_block->append(step_statement_);
|
||||
|
||||
NetWhile*wloop = new NetWhile(condition_, internal_block);
|
||||
wloop->set_line(*this);
|
||||
|
||||
top->append(wloop);
|
||||
|
||||
as_block_ = top;
|
||||
}
|
||||
|
||||
NetForLoop::~NetForLoop()
|
||||
|
|
|
|||
26
netlist.h
26
netlist.h
|
|
@ -3062,6 +3062,12 @@ class NetBlock : public NetProc {
|
|||
NetProc*last_;
|
||||
};
|
||||
|
||||
class NetBreak : public NetProc {
|
||||
public:
|
||||
virtual void dump(std::ostream&, unsigned ind) const;
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* A CASE statement in the Verilog source leads, eventually, to one of
|
||||
* these. This is different from a simple conditional because of the
|
||||
|
|
@ -3210,6 +3216,12 @@ class NetCondit : public NetProc {
|
|||
NetProc*else_;
|
||||
};
|
||||
|
||||
class NetContinue : public NetProc {
|
||||
public:
|
||||
virtual void dump(std::ostream&, unsigned ind) const;
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* This represents the analog contribution statement. The l-val is a
|
||||
* branch expression, and the r-value is an arbitrary expression that
|
||||
|
|
@ -3628,8 +3640,6 @@ class NetForLoop : public NetProc {
|
|||
NetProc*sub, NetProc*step);
|
||||
~NetForLoop();
|
||||
|
||||
void wrap_up();
|
||||
|
||||
void emit_recurse(struct target_t*) const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false,
|
||||
|
|
@ -3642,6 +3652,11 @@ class NetForLoop : public NetProc {
|
|||
virtual bool evaluate_function(const LineInfo&loc,
|
||||
std::map<perm_string,LocalVar>&ctx) const;
|
||||
|
||||
bool emit_recurse_init(struct target_t*) const;
|
||||
bool emit_recurse_stmt(struct target_t*) const;
|
||||
bool emit_recurse_step(struct target_t*) const;
|
||||
bool emit_recurse_condition(struct expr_scan_t*) const;
|
||||
|
||||
// synthesize as asynchronous logic, and return true.
|
||||
bool synth_async(Design*des, NetScope*scope,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
|
|
@ -3650,15 +3665,10 @@ class NetForLoop : public NetProc {
|
|||
private:
|
||||
NetNet*index_;
|
||||
NetExpr*init_expr_;
|
||||
NetProc*init_statement_; // Generated form index_ and init_expr_.
|
||||
NetExpr*condition_;
|
||||
NetProc*statement_;
|
||||
NetProc*step_statement_;
|
||||
|
||||
// The code generator needs to see this rewritten as a while
|
||||
// loop with synthetic statements. This is a hack that I
|
||||
// should probably take out later as the ivl_target learns
|
||||
// about for loops.
|
||||
NetBlock*as_block_;
|
||||
};
|
||||
|
||||
class NetFree : public NetProc {
|
||||
|
|
|
|||
10
parse.y
10
parse.y
|
|
@ -1622,8 +1622,14 @@ join_keyword /* IEEE1800-2005: A.6.3 */
|
|||
|
||||
jump_statement /* IEEE1800-2005: A.6.5 */
|
||||
: K_break ';'
|
||||
{ yyerror(@1, "sorry: break statements not supported.");
|
||||
$$ = 0;
|
||||
{ PBreak*tmp = new PBreak;
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_continue ';'
|
||||
{ PContinue*tmp = new PContinue;
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_return ';'
|
||||
{ PReturn*tmp = new PReturn(0);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2021 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2023 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -569,6 +569,9 @@ void PEBinary::dump(ostream&out) const
|
|||
case 'E':
|
||||
out << "===";
|
||||
break;
|
||||
case 'G':
|
||||
out << ">=";
|
||||
break;
|
||||
case 'l':
|
||||
out << "<<";
|
||||
break;
|
||||
|
|
@ -921,6 +924,11 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
|||
out << setw(ind) << "" << "end" << endl;
|
||||
}
|
||||
|
||||
void PBreak::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "break;" << endl;
|
||||
}
|
||||
|
||||
void PCallTask::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << path_;
|
||||
|
|
@ -1027,6 +1035,11 @@ void PCondit::dump(ostream&out, unsigned ind) const
|
|||
}
|
||||
}
|
||||
|
||||
void PContinue::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "continue;" << endl;
|
||||
}
|
||||
|
||||
void PCAssign::dump(ostream&out, unsigned ind) const
|
||||
{
|
||||
out << setw(ind) << "" << "assign " << *lval_ << " = " << *expr_
|
||||
|
|
|
|||
30
t-dll-api.cc
30
t-dll-api.cc
|
|
@ -2810,6 +2810,10 @@ extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net)
|
|||
case IVL_ST_WHILE:
|
||||
return net->u_.while_.cond_;
|
||||
|
||||
case IVL_ST_FORLOOP:
|
||||
assert(net->u_.forloop_.condition); // XXXX
|
||||
return net->u_.forloop_.condition;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
|
|
@ -2863,6 +2867,18 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net)
|
|||
return net->u_.delay_.value;
|
||||
}
|
||||
|
||||
extern "C" ivl_statement_t ivl_stmt_init_stmt(ivl_statement_t net)
|
||||
{
|
||||
assert(net);
|
||||
switch (net->type_) {
|
||||
case IVL_ST_FORLOOP:
|
||||
return net->u_.forloop_.init_stmt;
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -3091,6 +3107,18 @@ extern "C" ivl_sfunc_as_task_t ivl_stmt_sfunc_as_task(ivl_statement_t net)
|
|||
return IVL_SFUNC_AS_TASK_ERROR;
|
||||
}
|
||||
|
||||
extern "C" ivl_statement_t ivl_stmt_step_stmt(ivl_statement_t net)
|
||||
{
|
||||
assert(net);
|
||||
switch (net->type_) {
|
||||
case IVL_ST_FORLOOP:
|
||||
return net->u_.forloop_.step;
|
||||
default:
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -3101,6 +3129,8 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
|||
return net->u_.delayx_.stmt_;
|
||||
case IVL_ST_FOREVER:
|
||||
return net->u_.forever_.stmt_;
|
||||
case IVL_ST_FORLOOP:
|
||||
return net->u_.forloop_.stmt;
|
||||
case IVL_ST_WAIT:
|
||||
return net->u_.wait_.stmt_;
|
||||
case IVL_ST_DO_WHILE:
|
||||
|
|
|
|||
|
|
@ -462,8 +462,17 @@ bool dll_target::proc_block(const NetBlock*net)
|
|||
return flag;
|
||||
}
|
||||
|
||||
bool dll_target::proc_break(const NetBreak*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
FILE_NAME(stmt_cur_, net);
|
||||
stmt_cur_->type_ = IVL_ST_BREAK;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* A case statement is in turn an array of statements with gate
|
||||
* A. case statement is in turn an array of statements with gate
|
||||
* expressions. This builds arrays of the right size and builds the
|
||||
* ivl_expr_t and ivl_statement_s arrays for the substatements.
|
||||
*/
|
||||
|
|
@ -579,6 +588,15 @@ bool dll_target::proc_condit(const NetCondit*net)
|
|||
return rc_flag;
|
||||
}
|
||||
|
||||
bool dll_target::proc_continue(const NetContinue*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
FILE_NAME(stmt_cur_, net);
|
||||
stmt_cur_->type_ = IVL_ST_CONTINUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::proc_deassign(const NetDeassign*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
|
|
@ -715,6 +733,58 @@ void dll_target::proc_forever(const NetForever*net)
|
|||
stmt_cur_ = save_cur_;
|
||||
}
|
||||
|
||||
bool dll_target::proc_forloop(const NetForLoop*net)
|
||||
{
|
||||
ivl_statement_t tmp;
|
||||
bool rc, res=true;
|
||||
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
FILE_NAME(stmt_cur_, net);
|
||||
stmt_cur_->type_ = IVL_ST_FORLOOP;
|
||||
|
||||
ivl_statement_t save_cur_ = stmt_cur_;
|
||||
|
||||
// Note that the init statement is optional. If it is not present,
|
||||
// then the emit_recurse_init will not generate a statement.
|
||||
tmp = (struct ivl_statement_s*)calloc(1, sizeof(struct ivl_statement_s));
|
||||
stmt_cur_ = tmp;
|
||||
rc = net->emit_recurse_init(this);
|
||||
if (stmt_cur_->type_ != IVL_ST_NONE)
|
||||
save_cur_->u_.forloop_.init_stmt = stmt_cur_;
|
||||
else {
|
||||
free(tmp);
|
||||
save_cur_->u_.forloop_.init_stmt = nullptr;
|
||||
}
|
||||
res = res && rc;
|
||||
|
||||
tmp = (struct ivl_statement_s*)calloc(1, sizeof(struct ivl_statement_s));
|
||||
stmt_cur_ = tmp;
|
||||
rc = net->emit_recurse_stmt(this);
|
||||
save_cur_->u_.forloop_.stmt = stmt_cur_;
|
||||
res = res && rc;
|
||||
|
||||
tmp = (struct ivl_statement_s*)calloc(1, sizeof(struct ivl_statement_s));
|
||||
stmt_cur_ = tmp;
|
||||
rc = net->emit_recurse_step(this);
|
||||
if (stmt_cur_->type_ != IVL_ST_NONE)
|
||||
save_cur_->u_.forloop_.step = stmt_cur_;
|
||||
else {
|
||||
free(tmp);
|
||||
save_cur_->u_.forloop_.step = nullptr;
|
||||
}
|
||||
res = res && rc;
|
||||
|
||||
assert(expr_ == nullptr);
|
||||
rc = net->emit_recurse_condition(this);
|
||||
save_cur_->u_.forloop_.condition = expr_;
|
||||
expr_ = nullptr;
|
||||
res = res && rc;
|
||||
|
||||
stmt_cur_ = save_cur_;
|
||||
return res;
|
||||
}
|
||||
|
||||
void dll_target::proc_free(const NetFree*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
|
|
|
|||
10
t-dll.h
10
t-dll.h
|
|
@ -113,9 +113,11 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
bool proc_assign(const NetAssign*);
|
||||
void proc_assign_nb(const NetAssignNB*);
|
||||
bool proc_block(const NetBlock*);
|
||||
bool proc_break(const NetBreak*);
|
||||
void proc_case(const NetCase*);
|
||||
bool proc_cassign(const NetCAssign*);
|
||||
bool proc_condit(const NetCondit*);
|
||||
bool proc_continue(const NetContinue*);
|
||||
bool proc_contribution(const NetContribution*);
|
||||
bool proc_deassign(const NetDeassign*);
|
||||
bool proc_delay(const NetPDelay*);
|
||||
|
|
@ -123,6 +125,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
void proc_do_while(const NetDoWhile*);
|
||||
bool proc_force(const NetForce*);
|
||||
void proc_forever(const NetForever*);
|
||||
bool proc_forloop(const NetForLoop*);
|
||||
void proc_free(const NetFree*);
|
||||
bool proc_release(const NetRelease*);
|
||||
void proc_repeat(const NetRepeat*);
|
||||
|
|
@ -851,6 +854,13 @@ struct ivl_statement_s {
|
|||
ivl_statement_t stmt_;
|
||||
} forever_;
|
||||
|
||||
struct { /* IVL_ST_FORLOOP */
|
||||
ivl_statement_t init_stmt;
|
||||
ivl_expr_t condition;
|
||||
ivl_statement_t stmt;
|
||||
ivl_statement_t step;
|
||||
} forloop_;
|
||||
|
||||
struct { /* IVL_ST_FREE */
|
||||
ivl_scope_t scope;
|
||||
} free_;
|
||||
|
|
|
|||
21
target.cc
21
target.cc
|
|
@ -325,6 +325,13 @@ bool target_t::proc_block(const NetBlock*)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool target_t::proc_break(const NetBreak*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_break." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_case(const NetCase*cur)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
|
@ -348,6 +355,13 @@ bool target_t::proc_condit(const NetCondit*condit)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool target_t::proc_continue(const NetContinue*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_continue." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::proc_contribution(const NetContribution*net)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
|
@ -399,6 +413,13 @@ void target_t::proc_forever(const NetForever*)
|
|||
"Unhandled proc_forever." << endl;
|
||||
}
|
||||
|
||||
bool target_t::proc_forloop(const NetForLoop*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled proc_forloop." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_free(const NetFree*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
|
|
|||
3
target.h
3
target.h
|
|
@ -129,15 +129,18 @@ struct target_t {
|
|||
virtual bool proc_assign(const NetAssign*);
|
||||
virtual void proc_assign_nb(const NetAssignNB*);
|
||||
virtual bool proc_block(const NetBlock*);
|
||||
virtual bool proc_break(const NetBreak*);
|
||||
virtual void proc_case(const NetCase*);
|
||||
virtual bool proc_cassign(const NetCAssign*);
|
||||
virtual bool proc_condit(const NetCondit*);
|
||||
virtual bool proc_continue(const NetContinue*);
|
||||
virtual bool proc_contribution(const NetContribution*);
|
||||
virtual bool proc_deassign(const NetDeassign*);
|
||||
virtual bool proc_delay(const NetPDelay*);
|
||||
virtual bool proc_disable(const NetDisable*);
|
||||
virtual void proc_do_while(const NetDoWhile*);
|
||||
virtual bool proc_force(const NetForce*);
|
||||
virtual bool proc_forloop(const NetForLoop*) =0;
|
||||
virtual void proc_forever(const NetForever*);
|
||||
virtual void proc_free(const NetFree*);
|
||||
virtual bool proc_release(const NetRelease*);
|
||||
|
|
|
|||
|
|
@ -229,6 +229,15 @@ static void show_stmt_force(ivl_statement_t net, unsigned ind)
|
|||
show_expression(ivl_stmt_rval(net), ind+4);
|
||||
}
|
||||
|
||||
static void show_stmt_forloop(ivl_statement_t net, unsigned ind)
|
||||
{
|
||||
fprintf(out, "%*sFOR-LOOP\n", ind, "");
|
||||
show_expression(ivl_stmt_cond_expr(net), ind+4);
|
||||
show_statement(ivl_stmt_init_stmt(net), ind+2);
|
||||
show_statement(ivl_stmt_sub_stmt(net), ind+2);
|
||||
show_statement(ivl_stmt_step_stmt(net), ind+2);
|
||||
}
|
||||
|
||||
static void show_stmt_release(ivl_statement_t net, unsigned ind)
|
||||
{
|
||||
unsigned idx;
|
||||
|
|
@ -404,6 +413,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
|||
break;
|
||||
}
|
||||
|
||||
case IVL_ST_BREAK: {
|
||||
fprintf(out, "%*sbreak;\n", ind, "");
|
||||
break;
|
||||
}
|
||||
|
||||
case IVL_ST_CASEX:
|
||||
case IVL_ST_CASEZ:
|
||||
case IVL_ST_CASER:
|
||||
|
|
@ -471,6 +485,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
|||
|
||||
break;
|
||||
}
|
||||
case IVL_ST_CONTINUE: {
|
||||
fprintf(out, "%*scontinue;\n", ind, "");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case IVL_ST_CONTRIB:
|
||||
fprintf(out, "%*sCONTRIBUTION ( <+ )\n", ind, "");
|
||||
|
|
@ -544,6 +563,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
|||
break;
|
||||
}
|
||||
|
||||
case IVL_ST_FORLOOP:
|
||||
show_stmt_forloop(net, ind);
|
||||
break;
|
||||
|
||||
case IVL_ST_FREE:
|
||||
fprintf(out, "%*sfree automatic storage ...\n", ind, "");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -905,7 +905,9 @@ static unsigned has_func_disable(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
case IVL_ST_NOOP:
|
||||
case IVL_ST_ALLOC:
|
||||
case IVL_ST_ASSIGN:
|
||||
case IVL_ST_BREAK:
|
||||
case IVL_ST_CASSIGN:
|
||||
case IVL_ST_CONTINUE:
|
||||
case IVL_ST_DEASSIGN:
|
||||
case IVL_ST_FORCE:
|
||||
case IVL_ST_FREE:
|
||||
|
|
@ -944,6 +946,7 @@ static unsigned has_func_disable(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
/* These have a single sub-statement so look for a disable there. */
|
||||
case IVL_ST_DO_WHILE:
|
||||
case IVL_ST_FOREVER:
|
||||
case IVL_ST_FORLOOP:
|
||||
case IVL_ST_REPEAT:
|
||||
case IVL_ST_WHILE:
|
||||
rtn = has_func_disable(scope, ivl_stmt_sub_stmt(stmt));
|
||||
|
|
|
|||
|
|
@ -470,71 +470,6 @@ static void emit_assign_and_opt_opcode(ivl_scope_t scope, ivl_statement_t stmt,
|
|||
emit_expr(scope, ivl_stmt_rval(stmt), wid, 1, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated for(<assign>; <cond>; <incr_assign>) <body> into
|
||||
*
|
||||
* begin
|
||||
* <assign>;
|
||||
* while (<cond>) begin
|
||||
* <body>
|
||||
* <incr_assign>
|
||||
* end
|
||||
* end
|
||||
* This routine looks for this pattern and turns it back into the
|
||||
* appropriate for loop.
|
||||
*/
|
||||
static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t assign, while_lp, while_blk, body, incr_assign;
|
||||
|
||||
/* We must have two block elements. */
|
||||
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
||||
/* The first must be an assign. */
|
||||
assign = ivl_stmt_block_stmt(stmt, 0);
|
||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* The second must be a while. */
|
||||
while_lp = ivl_stmt_block_stmt(stmt, 1);
|
||||
if (ivl_statement_type(while_lp) != IVL_ST_WHILE) return 0;
|
||||
/* The while statement must be a block. */
|
||||
while_blk = ivl_stmt_sub_stmt(while_lp);
|
||||
if (ivl_statement_type(while_blk) != IVL_ST_BLOCK) return 0;
|
||||
/* It must not be a named block. */
|
||||
if (ivl_stmt_block_scope(while_blk)) return 0;
|
||||
/* It must have two elements. */
|
||||
if (ivl_stmt_block_count(while_blk) != 2) return 0;
|
||||
/* The first block element (the body) can be anything. */
|
||||
body = ivl_stmt_block_stmt(while_blk, 0);
|
||||
/* The second block element must be the increment assign. */
|
||||
incr_assign = ivl_stmt_block_stmt(while_blk, 1);
|
||||
if (ivl_statement_type(incr_assign) != IVL_ST_ASSIGN) return 0;
|
||||
/* And finally the for statements must have the same line number
|
||||
* as the block. */
|
||||
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_lp)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_blk)) ||
|
||||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(incr_assign))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The pattern matched so generate the appropriate code. */
|
||||
fprintf(vlog_out, "%*cfor(", get_indent(), ' ');
|
||||
/* Emit the initialization statement (no opcode is allowed). */
|
||||
emit_assign_and_opt_opcode(scope, assign, 0);
|
||||
fprintf(vlog_out, "; ");
|
||||
/* Emit the condition. */
|
||||
emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0, 0, 0, 0);
|
||||
fprintf(vlog_out, "; ");
|
||||
/* Emit the increment statement (an opcode is allowed). */
|
||||
emit_assign_and_opt_opcode(scope, incr_assign, 1);
|
||||
fprintf(vlog_out, ")");
|
||||
emit_stmt_file_line(stmt);
|
||||
/* Now emit the body. */
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, body);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Icarus translated <var> = repeat(<count>) <event> <value> into
|
||||
* begin
|
||||
|
|
@ -1375,6 +1310,27 @@ static void emit_stmt_fork_named(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
ivl_scope_basename(my_scope));
|
||||
}
|
||||
|
||||
static void emit_stmt_forloop(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
ivl_statement_t use_init = ivl_stmt_init_stmt(stmt);
|
||||
ivl_statement_t use_step = ivl_stmt_step_stmt(stmt);
|
||||
ivl_statement_t use_stmt = ivl_stmt_sub_stmt(stmt);
|
||||
|
||||
fprintf(vlog_out, "%*cfor (", get_indent(), ' ');
|
||||
/* Assume that the init statement is an assignment. */
|
||||
if (use_init)
|
||||
emit_assign_and_opt_opcode(scope, use_init, 0);
|
||||
fprintf(vlog_out, "; ");
|
||||
emit_expr(scope, ivl_stmt_cond_expr(stmt), 0, 0, 0, 0);
|
||||
fprintf(vlog_out, "; ");
|
||||
/* Assume that the step statement is an assignment. */
|
||||
if (use_step)
|
||||
emit_assign_and_opt_opcode(scope, use_step, 1);
|
||||
fprintf(vlog_out, ")");
|
||||
single_indent = 1;
|
||||
emit_stmt(scope, use_stmt);
|
||||
}
|
||||
|
||||
static void emit_stmt_release(ivl_scope_t scope, ivl_statement_t stmt)
|
||||
{
|
||||
fprintf(vlog_out, "%*crelease ", get_indent(), ' ');
|
||||
|
|
@ -1538,13 +1494,19 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
emit_stmt_block_named(scope, stmt);
|
||||
} else {
|
||||
if (is_delayed_or_event_assign(scope, stmt)) break;
|
||||
if (is_for_loop(scope, stmt)) break;
|
||||
if (is_repeat_event_assign(scope, stmt)) break;
|
||||
if (is_wait(scope, stmt)) break;
|
||||
if (is_utask_call_with_args(scope, stmt)) break;
|
||||
emit_stmt_block(scope, stmt);
|
||||
}
|
||||
break;
|
||||
case IVL_ST_BREAK:
|
||||
fprintf(stderr, "%s:%u: vlog95 sorry: 'break' is not "
|
||||
"currently translated.\n",
|
||||
ivl_stmt_file(stmt),
|
||||
ivl_stmt_lineno(stmt));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
case IVL_ST_CASE:
|
||||
case IVL_ST_CASER:
|
||||
case IVL_ST_CASEX:
|
||||
|
|
@ -1557,6 +1519,13 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
case IVL_ST_CONDIT:
|
||||
emit_stmt_condit(scope, stmt);
|
||||
break;
|
||||
case IVL_ST_CONTINUE:
|
||||
fprintf(stderr, "%s:%u: vlog95 sorry: 'continue' is not "
|
||||
"currently translated.\n",
|
||||
ivl_stmt_file(stmt),
|
||||
ivl_stmt_lineno(stmt));
|
||||
vlog_errors += 1;
|
||||
break;
|
||||
case IVL_ST_DEASSIGN:
|
||||
emit_stmt_deassign(scope, stmt);
|
||||
break;
|
||||
|
|
@ -1578,6 +1547,9 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
|||
case IVL_ST_FOREVER:
|
||||
emit_stmt_forever(scope, stmt);
|
||||
break;
|
||||
case IVL_ST_FORLOOP:
|
||||
emit_stmt_forloop(scope, stmt);
|
||||
break;
|
||||
case IVL_ST_FORK:
|
||||
if (ivl_stmt_block_scope(stmt)) {
|
||||
emit_stmt_fork_named(scope, stmt);
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@
|
|||
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
suffix = @install_suffix@
|
||||
|
|
@ -53,7 +50,7 @@ O = vvp.o draw_class.o draw_delay.o draw_enum.o draw_mux.o draw_net_input.o \
|
|||
eval_expr.o eval_object.o eval_real.o eval_string.o \
|
||||
eval_vec4.o \
|
||||
modpath.o stmt_assign.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
vvp_process.o vvp_proc_loops.o vvp_scope.o
|
||||
|
||||
all: dep vvp.tgt vvp.conf vvp-s.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -274,5 +274,16 @@ extern unsigned thread_count;
|
|||
|
||||
extern void darray_new(ivl_type_t element_type, unsigned size_reg);
|
||||
|
||||
/*
|
||||
* These are various statement code generators.
|
||||
*/
|
||||
extern int show_statement(ivl_statement_t net, ivl_scope_t sscope);
|
||||
|
||||
extern int show_stmt_break(ivl_statement_t net, ivl_scope_t sscope);
|
||||
extern int show_stmt_continue(ivl_statement_t net, ivl_scope_t sscope);
|
||||
extern int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope);
|
||||
extern int show_stmt_forloop(ivl_statement_t net, ivl_scope_t sscope);
|
||||
extern int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope);
|
||||
extern int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope);
|
||||
|
||||
#endif /* IVL_vvp_priv_H */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2023 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <limits.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdbool.h>
|
||||
|
||||
const unsigned LABEL_NONE = UINT_MAX;
|
||||
static unsigned break_label = LABEL_NONE;
|
||||
static unsigned continue_label = LABEL_NONE;
|
||||
|
||||
#define PUSH_JUMPS(bl, cl) do { \
|
||||
save_break_label = break_label; \
|
||||
save_continue_label = continue_label; \
|
||||
break_label = bl; \
|
||||
continue_label = cl; \
|
||||
} while (0)
|
||||
|
||||
#define POP_JUMPS do { \
|
||||
break_label = save_break_label; \
|
||||
continue_label = save_continue_label; \
|
||||
} while (0)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
int show_stmt_break(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
if (break_label == LABEL_NONE) {
|
||||
fprintf(stderr, "vvp.tgt: error: 'break' not in a loop?!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u; break\n", thread_count, break_label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int show_stmt_continue(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
if (continue_label == LABEL_NONE) {
|
||||
fprintf(stderr, "vvp.tgt: error: 'continue' not in a loop?!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u; continue\n", thread_count, continue_label);
|
||||
return 0;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
unsigned lab_top = local_count++;
|
||||
unsigned lab_out = local_count++;
|
||||
|
||||
show_stmt_file_line(net, "Forever statement.");
|
||||
|
||||
unsigned save_break_label, save_continue_label;
|
||||
PUSH_JUMPS(lab_out, lab_top);
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
|
||||
rc += show_statement(stmt, sscope);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||
POP_JUMPS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The for-loop should be emitted like this:
|
||||
*
|
||||
* <ivl_stmt_init_stmt>
|
||||
* top_label:
|
||||
* if (<ivl_stmt_cond_expr> is false)
|
||||
* goto out_label;
|
||||
* <ivl_stmt_sub_stmt>
|
||||
* continue_label:
|
||||
* <ivl_stmt_step_stmt>
|
||||
* goto top_label
|
||||
* out_label:
|
||||
*
|
||||
* This is very similar to how the while loop is generated. The obvious
|
||||
* difference is that there is an init statement and a step statement
|
||||
* that fits into the flow.
|
||||
*/
|
||||
int show_stmt_forloop(ivl_statement_t net, ivl_scope_t scope)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned top_label = local_count++;
|
||||
unsigned out_label = local_count++;
|
||||
unsigned cont_label= local_count++;
|
||||
unsigned save_break_label, save_continue_label;
|
||||
PUSH_JUMPS(out_label, cont_label);
|
||||
|
||||
show_stmt_file_line(net, "For-loop statement.");
|
||||
|
||||
/* Draw the init statement before the entry point to the loop. */
|
||||
if (ivl_stmt_init_stmt(net))
|
||||
rc += show_statement(ivl_stmt_init_stmt(net), scope);
|
||||
|
||||
/* Top of the loop, draw the condition test. */
|
||||
fprintf(vvp_out, "T_%u.%u ; Top of for-loop \n", thread_count, top_label);
|
||||
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
|
||||
thread_count, out_label, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
||||
/* Draw the body of the loop. */
|
||||
rc += show_statement(ivl_stmt_sub_stmt(net), scope);
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ; for-loop step statement\n",
|
||||
thread_count, cont_label);
|
||||
if (ivl_stmt_step_stmt(net))
|
||||
rc += show_statement(ivl_stmt_step_stmt(net), scope);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label);
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ; for-loop exit label\n",
|
||||
thread_count, out_label);
|
||||
|
||||
POP_JUMPS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned lab_top = local_count++, lab_out = local_count++;
|
||||
ivl_expr_t expr = ivl_stmt_cond_expr(net);
|
||||
const char *sign = ivl_expr_signed(expr) ? "s" : "u";
|
||||
|
||||
unsigned save_break_label, save_continue_label;
|
||||
PUSH_JUMPS(lab_out, lab_top);
|
||||
|
||||
show_stmt_file_line(net, "Repeat statement.");
|
||||
|
||||
/* Calculate the repeat count onto the top of the vec4 stack. */
|
||||
draw_eval_vec4(expr);
|
||||
|
||||
/* Test that 0 < expr, escape if expr <= 0. If the expr is
|
||||
unsigned, then we only need to try to escape if expr==0 as
|
||||
it will never be <0. */
|
||||
fprintf(vvp_out, "T_%u.%u %%dup/vec4;\n", thread_count, lab_top);
|
||||
fprintf(vvp_out, " %%pushi/vec4 0, 0, %u;\n", ivl_expr_width(expr));
|
||||
fprintf(vvp_out, " %%cmp/%s;\n", sign);
|
||||
if (ivl_expr_signed(expr))
|
||||
fprintf(vvp_out, " %%jmp/1xz T_%u.%u, 5;\n", thread_count, lab_out);
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, lab_out);
|
||||
/* This adds -1 (all ones in 2's complement) to the count. */
|
||||
fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(expr));
|
||||
fprintf(vvp_out, " %%sub;\n");
|
||||
|
||||
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||
|
||||
POP_JUMPS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
unsigned top_label = local_count++;
|
||||
unsigned out_label = local_count++;
|
||||
|
||||
unsigned save_break_label, save_continue_label;
|
||||
PUSH_JUMPS(out_label, top_label);
|
||||
|
||||
show_stmt_file_line(net, "While statement.");
|
||||
|
||||
/* Start the loop. The top of the loop starts a basic block
|
||||
because it can be entered from above or from the bottom of
|
||||
the loop. */
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
||||
|
||||
|
||||
/* Draw the evaluation of the condition expression, and test
|
||||
the result. If the expression evaluates to false, then
|
||||
branch to the out label. */
|
||||
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
|
||||
thread_count, out_label, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
||||
/* Draw the body of the loop. */
|
||||
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||
|
||||
/* This is the bottom of the loop. branch to the top where the
|
||||
test is repeated, and also draw the out label. */
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, out_label);
|
||||
|
||||
POP_JUMPS;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -23,8 +23,6 @@
|
|||
# include <stdlib.h>
|
||||
# include <stdbool.h>
|
||||
|
||||
static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
|
||||
|
||||
unsigned local_count = 0;
|
||||
unsigned thread_count = 0;
|
||||
|
||||
|
|
@ -1414,21 +1412,6 @@ static int show_stmt_force(ivl_statement_t net)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
|
||||
unsigned lab_top = local_count++;
|
||||
|
||||
show_stmt_file_line(net, "Forever statement.");
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
|
||||
rc += show_statement(stmt, sscope);
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
unsigned idx;
|
||||
|
|
@ -1606,40 +1589,6 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned lab_top = local_count++, lab_out = local_count++;
|
||||
ivl_expr_t expr = ivl_stmt_cond_expr(net);
|
||||
const char *sign = ivl_expr_signed(expr) ? "s" : "u";
|
||||
|
||||
show_stmt_file_line(net, "Repeat statement.");
|
||||
|
||||
/* Calculate the repeat count onto the top of the vec4 stack. */
|
||||
draw_eval_vec4(expr);
|
||||
|
||||
/* Test that 0 < expr, escape if expr <= 0. If the expr is
|
||||
unsigned, then we only need to try to escape if expr==0 as
|
||||
it will never be <0. */
|
||||
fprintf(vvp_out, "T_%u.%u %%dup/vec4;\n", thread_count, lab_top);
|
||||
fprintf(vvp_out, " %%pushi/vec4 0, 0, %u;\n", ivl_expr_width(expr));
|
||||
fprintf(vvp_out, " %%cmp/%s;\n", sign);
|
||||
if (ivl_expr_signed(expr))
|
||||
fprintf(vvp_out, " %%jmp/1xz T_%u.%u, 5;\n", thread_count, lab_out);
|
||||
fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n", thread_count, lab_out);
|
||||
/* This adds -1 (all ones in 2's complement) to the count. */
|
||||
fprintf(vvp_out, " %%pushi/vec4 1, 0, %u;\n", ivl_expr_width(expr));
|
||||
fprintf(vvp_out, " %%sub;\n");
|
||||
|
||||
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The trigger statement is straight forward. All we have to do is
|
||||
* write a single bit of fake data to the event object.
|
||||
|
|
@ -1749,40 +1698,6 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
|||
return show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||
}
|
||||
|
||||
static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
unsigned top_label = local_count++;
|
||||
unsigned out_label = local_count++;
|
||||
|
||||
show_stmt_file_line(net, "While statement.");
|
||||
|
||||
/* Start the loop. The top of the loop starts a basic block
|
||||
because it can be entered from above or from the bottom of
|
||||
the loop. */
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
||||
|
||||
|
||||
/* Draw the evaluation of the condition expression, and test
|
||||
the result. If the expression evaluates to false, then
|
||||
branch to the out label. */
|
||||
int use_flag = draw_eval_condition(ivl_stmt_cond_expr(net));
|
||||
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, %d;\n",
|
||||
thread_count, out_label, use_flag);
|
||||
clr_flag(use_flag);
|
||||
|
||||
/* Draw the body of the loop. */
|
||||
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||
|
||||
/* This is the bottom of the loop. branch to the top where the
|
||||
test is repeated, and also draw the out label. */
|
||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label);
|
||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, out_label);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int show_delete_method(ivl_statement_t net)
|
||||
{
|
||||
show_stmt_file_line(net, "Delete object");
|
||||
|
|
@ -2307,7 +2222,7 @@ static unsigned is_utask_call_with_args(ivl_scope_t scope,
|
|||
* switches on the statement type and draws code based on the type and
|
||||
* further specifics.
|
||||
*/
|
||||
static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
||||
int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
||||
{
|
||||
const ivl_statement_type_t code = ivl_statement_type(net);
|
||||
int rc = 0;
|
||||
|
|
@ -2347,6 +2262,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
}
|
||||
break;
|
||||
|
||||
case IVL_ST_BREAK:
|
||||
rc += show_stmt_break(net, sscope);
|
||||
break;
|
||||
|
||||
case IVL_ST_CASE:
|
||||
case IVL_ST_CASEX:
|
||||
case IVL_ST_CASEZ:
|
||||
|
|
@ -2365,6 +2284,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
rc += show_stmt_condit(net, sscope);
|
||||
break;
|
||||
|
||||
case IVL_ST_CONTINUE:
|
||||
rc += show_stmt_continue(net, sscope);
|
||||
break;
|
||||
|
||||
case IVL_ST_DEASSIGN:
|
||||
rc += show_stmt_deassign(net);
|
||||
break;
|
||||
|
|
@ -2399,6 +2322,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
|||
rc += show_stmt_fork(net, sscope);
|
||||
break;
|
||||
|
||||
case IVL_ST_FORLOOP:
|
||||
rc += show_stmt_forloop(net, sscope);
|
||||
break;
|
||||
|
||||
case IVL_ST_FREE:
|
||||
rc += show_stmt_free(net);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in New Issue