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_;
|
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 {
|
class PCallTask : public Statement {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -345,6 +351,13 @@ class PCondit : public Statement {
|
||||||
PCondit& operator= (const PCondit&);
|
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 {
|
class PDeassign : public Statement {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1180,6 +1180,11 @@ void NetBlock::dump(ostream&o, unsigned ind) const
|
||||||
o << setw(ind) << "" << "end" << endl;
|
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
|
void NetCase::dump(ostream&o, unsigned ind) const
|
||||||
{
|
{
|
||||||
o << setw(ind) << "";
|
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
|
void NetContribution::dump(ostream&o, unsigned ind) const
|
||||||
{
|
{
|
||||||
o << setw(ind) << "";
|
o << setw(ind) << "";
|
||||||
|
|
@ -1386,10 +1396,26 @@ void NetForLoop::dump(ostream&fd, unsigned ind) const
|
||||||
fd << index_->name();
|
fd << index_->name();
|
||||||
else
|
else
|
||||||
fd << "<nil>";
|
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 << 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);
|
statement_->dump(fd, ind+4);
|
||||||
|
fd << setw(ind+4) << "" << "Step Statement {" << endl;
|
||||||
if (step_statement_)
|
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
|
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;
|
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,
|
static int test_case_width(Design*des, NetScope*scope, PExpr*pe,
|
||||||
PExpr::width_mode_t&mode)
|
PExpr::width_mode_t&mode)
|
||||||
{
|
{
|
||||||
|
|
@ -3447,6 +3462,20 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
||||||
return res;
|
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
|
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
|
||||||
{
|
{
|
||||||
if (peek_tail_name(path_)[0] == '$') {
|
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);
|
NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step);
|
||||||
stmt->set_line(*this);
|
stmt->set_line(*this);
|
||||||
stmt->wrap_up();
|
|
||||||
|
|
||||||
return stmt;
|
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 = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step);
|
||||||
stmt->set_line(*this);
|
stmt->set_line(*this);
|
||||||
stmt->wrap_up();
|
|
||||||
|
|
||||||
sub = stmt;
|
sub = stmt;
|
||||||
}
|
}
|
||||||
|
|
@ -5646,7 +5673,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step);
|
NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step);
|
||||||
loop->set_line(*this);
|
loop->set_line(*this);
|
||||||
loop->wrap_up();
|
|
||||||
return loop;
|
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);
|
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
|
bool NetCase::emit_proc(struct target_t*tgt) const
|
||||||
{
|
{
|
||||||
tgt->proc_case(this);
|
tgt->proc_case(this);
|
||||||
|
|
@ -259,6 +264,11 @@ bool NetCondit::emit_proc(struct target_t*tgt) const
|
||||||
return tgt->proc_condit(this);
|
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
|
bool NetContribution::emit_proc(struct target_t*tgt) const
|
||||||
{
|
{
|
||||||
return tgt->proc_contribution(this);
|
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
|
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
|
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_events
|
||||||
ivl_stmt_file
|
ivl_stmt_file
|
||||||
ivl_stmt_flow_control
|
ivl_stmt_flow_control
|
||||||
|
ivl_stmt_init_stmt
|
||||||
ivl_stmt_lexp
|
ivl_stmt_lexp
|
||||||
ivl_stmt_lineno
|
ivl_stmt_lineno
|
||||||
ivl_stmt_lval
|
ivl_stmt_lval
|
||||||
|
|
@ -307,6 +308,7 @@ ivl_stmt_parm
|
||||||
ivl_stmt_parm_count
|
ivl_stmt_parm_count
|
||||||
ivl_stmt_rval
|
ivl_stmt_rval
|
||||||
ivl_stmt_sfunc_as_task
|
ivl_stmt_sfunc_as_task
|
||||||
|
ivl_stmt_step_stmt
|
||||||
ivl_stmt_sub_stmt
|
ivl_stmt_sub_stmt
|
||||||
|
|
||||||
ivl_switch_a
|
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 = 2,
|
||||||
IVL_ST_ASSIGN_NB = 3,
|
IVL_ST_ASSIGN_NB = 3,
|
||||||
IVL_ST_BLOCK = 4,
|
IVL_ST_BLOCK = 4,
|
||||||
|
IVL_ST_BREAK = 32,
|
||||||
IVL_ST_CASE = 5,
|
IVL_ST_CASE = 5,
|
||||||
IVL_ST_CASER = 24, /* Case statement with real expressions. */
|
IVL_ST_CASER = 24, /* Case statement with real expressions. */
|
||||||
IVL_ST_CASEX = 6,
|
IVL_ST_CASEX = 6,
|
||||||
IVL_ST_CASEZ = 7,
|
IVL_ST_CASEZ = 7,
|
||||||
IVL_ST_CASSIGN = 8,
|
IVL_ST_CASSIGN = 8,
|
||||||
IVL_ST_CONDIT = 9,
|
IVL_ST_CONDIT = 9,
|
||||||
|
IVL_ST_CONTINUE= 33,
|
||||||
IVL_ST_CONTRIB = 27,
|
IVL_ST_CONTRIB = 27,
|
||||||
IVL_ST_DEASSIGN = 10,
|
IVL_ST_DEASSIGN = 10,
|
||||||
IVL_ST_DELAY = 11,
|
IVL_ST_DELAY = 11,
|
||||||
IVL_ST_DELAYX = 12,
|
IVL_ST_DELAYX = 12,
|
||||||
IVL_ST_DISABLE = 13,
|
IVL_ST_DISABLE = 13,
|
||||||
IVL_ST_DO_WHILE = 30,
|
IVL_ST_DO_WHILE = 30,
|
||||||
|
IVL_ST_FORLOOP = 34,
|
||||||
IVL_ST_FORCE = 14,
|
IVL_ST_FORCE = 14,
|
||||||
IVL_ST_FOREVER = 15,
|
IVL_ST_FOREVER = 15,
|
||||||
IVL_ST_FORK = 16,
|
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
|
* force l-values, and also non-constant bit or part selects. The
|
||||||
* compiler will assure these constraints are met.
|
* 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
|
* - IVL_ST_TRIGGER
|
||||||
* This represents the "-> name" statement that sends a trigger to a
|
* This represents the "-> name" statement that sends a trigger to a
|
||||||
* named event. The ivl_stmt_nevent function should always return 1,
|
* 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);
|
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 */
|
/* 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);
|
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);
|
extern ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net);
|
||||||
/* IVL_ST_CONDIT */
|
/* IVL_ST_CONDIT */
|
||||||
extern ivl_statement_t ivl_stmt_cond_false(ivl_statement_t net);
|
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);
|
extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
|
||||||
/* IVL_ST_STASK */
|
/* IVL_ST_STASK */
|
||||||
extern ivl_sfunc_as_task_t ivl_stmt_sfunc_as_task(ivl_statement_t net);
|
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_DELAY, IVL_ST_DELAYX, IVL_ST_FOREVER, IVL_ST_FORLOOP,
|
||||||
IVL_ST_WAIT, IVL_ST_WHILE */
|
IVL_ST_REPEAT, IVL_ST_WAIT, IVL_ST_WHILE */
|
||||||
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
|
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
|
/* 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_gh167b normal,-g2009 ivltests
|
||||||
br_gh177a normal,-g2009 ivltests
|
br_gh177a normal,-g2009 ivltests
|
||||||
br_gh177b 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_gh194 normal,-g2009 ivltests
|
||||||
br_gh219 normal,-g2009 ivltests
|
br_gh219 normal,-g2009 ivltests
|
||||||
br_gh220 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_cast10 EF,-g2009,-pallowsigned=1 ivltests
|
||||||
implicit_cast11 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.
|
# These tests have unresolved failures that still need to be looked at.
|
||||||
# The following two have problem getting the correct net/expression
|
# The following two have problem getting the correct net/expression
|
||||||
# information from the nexus. pr1723367 is the real torture test.
|
# 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
|
* Process the for-loop to generate a value, as if this were in a function.
|
||||||
* to do this directly.
|
|
||||||
*/
|
*/
|
||||||
bool NetForLoop::evaluate_function(const LineInfo&loc,
|
bool NetForLoop::evaluate_function(const LineInfo&loc,
|
||||||
map<perm_string,LocalVar>&context_map) const
|
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,
|
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)
|
NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step)
|
||||||
: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step)
|
: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step)
|
||||||
{
|
{
|
||||||
as_block_ = NULL;
|
if (index_ && init_expr_) {
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
NetAssign_*lv = new NetAssign_(index_);
|
NetAssign_*lv = new NetAssign_(index_);
|
||||||
NetAssign*set_stmt = new NetAssign(lv, init_expr_);
|
NetAssign*use_init_statement = new NetAssign(lv, init_expr_);
|
||||||
set_stmt->set_line(*init_expr_);
|
use_init_statement->set_line(*init_expr_);
|
||||||
top->append(set_stmt);
|
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()
|
NetForLoop::~NetForLoop()
|
||||||
|
|
|
||||||
26
netlist.h
26
netlist.h
|
|
@ -3062,6 +3062,12 @@ class NetBlock : public NetProc {
|
||||||
NetProc*last_;
|
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
|
* A CASE statement in the Verilog source leads, eventually, to one of
|
||||||
* these. This is different from a simple conditional because of the
|
* these. This is different from a simple conditional because of the
|
||||||
|
|
@ -3210,6 +3216,12 @@ class NetCondit : public NetProc {
|
||||||
NetProc*else_;
|
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
|
* This represents the analog contribution statement. The l-val is a
|
||||||
* branch expression, and the r-value is an arbitrary expression that
|
* branch expression, and the r-value is an arbitrary expression that
|
||||||
|
|
@ -3628,8 +3640,6 @@ class NetForLoop : public NetProc {
|
||||||
NetProc*sub, NetProc*step);
|
NetProc*sub, NetProc*step);
|
||||||
~NetForLoop();
|
~NetForLoop();
|
||||||
|
|
||||||
void wrap_up();
|
|
||||||
|
|
||||||
void emit_recurse(struct target_t*) const;
|
void emit_recurse(struct target_t*) const;
|
||||||
|
|
||||||
virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false,
|
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,
|
virtual bool evaluate_function(const LineInfo&loc,
|
||||||
std::map<perm_string,LocalVar>&ctx) const;
|
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.
|
// synthesize as asynchronous logic, and return true.
|
||||||
bool synth_async(Design*des, NetScope*scope,
|
bool synth_async(Design*des, NetScope*scope,
|
||||||
NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
|
@ -3650,15 +3665,10 @@ class NetForLoop : public NetProc {
|
||||||
private:
|
private:
|
||||||
NetNet*index_;
|
NetNet*index_;
|
||||||
NetExpr*init_expr_;
|
NetExpr*init_expr_;
|
||||||
|
NetProc*init_statement_; // Generated form index_ and init_expr_.
|
||||||
NetExpr*condition_;
|
NetExpr*condition_;
|
||||||
NetProc*statement_;
|
NetProc*statement_;
|
||||||
NetProc*step_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 {
|
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 */
|
jump_statement /* IEEE1800-2005: A.6.5 */
|
||||||
: K_break ';'
|
: K_break ';'
|
||||||
{ yyerror(@1, "sorry: break statements not supported.");
|
{ PBreak*tmp = new PBreak;
|
||||||
$$ = 0;
|
FILE_NAME(tmp, @1);
|
||||||
|
$$ = tmp;
|
||||||
|
}
|
||||||
|
| K_continue ';'
|
||||||
|
{ PContinue*tmp = new PContinue;
|
||||||
|
FILE_NAME(tmp, @1);
|
||||||
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| K_return ';'
|
| K_return ';'
|
||||||
{ PReturn*tmp = new PReturn(0);
|
{ 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
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* 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':
|
case 'E':
|
||||||
out << "===";
|
out << "===";
|
||||||
break;
|
break;
|
||||||
|
case 'G':
|
||||||
|
out << ">=";
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
out << "<<";
|
out << "<<";
|
||||||
break;
|
break;
|
||||||
|
|
@ -921,6 +924,11 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
||||||
out << setw(ind) << "" << "end" << endl;
|
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
|
void PCallTask::dump(ostream&out, unsigned ind) const
|
||||||
{
|
{
|
||||||
out << setw(ind) << "" << path_;
|
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
|
void PCAssign::dump(ostream&out, unsigned ind) const
|
||||||
{
|
{
|
||||||
out << setw(ind) << "" << "assign " << *lval_ << " = " << *expr_
|
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:
|
case IVL_ST_WHILE:
|
||||||
return net->u_.while_.cond_;
|
return net->u_.while_.cond_;
|
||||||
|
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
|
assert(net->u_.forloop_.condition); // XXXX
|
||||||
|
return net->u_.forloop_.condition;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -2863,6 +2867,18 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net)
|
||||||
return net->u_.delay_.value;
|
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)
|
extern "C" unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net)
|
||||||
{
|
{
|
||||||
assert(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;
|
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)
|
extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
||||||
{
|
{
|
||||||
assert(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_;
|
return net->u_.delayx_.stmt_;
|
||||||
case IVL_ST_FOREVER:
|
case IVL_ST_FOREVER:
|
||||||
return net->u_.forever_.stmt_;
|
return net->u_.forever_.stmt_;
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
|
return net->u_.forloop_.stmt;
|
||||||
case IVL_ST_WAIT:
|
case IVL_ST_WAIT:
|
||||||
return net->u_.wait_.stmt_;
|
return net->u_.wait_.stmt_;
|
||||||
case IVL_ST_DO_WHILE:
|
case IVL_ST_DO_WHILE:
|
||||||
|
|
|
||||||
|
|
@ -462,8 +462,17 @@ bool dll_target::proc_block(const NetBlock*net)
|
||||||
return flag;
|
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
|
* expressions. This builds arrays of the right size and builds the
|
||||||
* ivl_expr_t and ivl_statement_s arrays for the substatements.
|
* 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;
|
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)
|
bool dll_target::proc_deassign(const NetDeassign*net)
|
||||||
{
|
{
|
||||||
assert(stmt_cur_);
|
assert(stmt_cur_);
|
||||||
|
|
@ -715,6 +733,58 @@ void dll_target::proc_forever(const NetForever*net)
|
||||||
stmt_cur_ = save_cur_;
|
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)
|
void dll_target::proc_free(const NetFree*net)
|
||||||
{
|
{
|
||||||
assert(stmt_cur_);
|
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*);
|
bool proc_assign(const NetAssign*);
|
||||||
void proc_assign_nb(const NetAssignNB*);
|
void proc_assign_nb(const NetAssignNB*);
|
||||||
bool proc_block(const NetBlock*);
|
bool proc_block(const NetBlock*);
|
||||||
|
bool proc_break(const NetBreak*);
|
||||||
void proc_case(const NetCase*);
|
void proc_case(const NetCase*);
|
||||||
bool proc_cassign(const NetCAssign*);
|
bool proc_cassign(const NetCAssign*);
|
||||||
bool proc_condit(const NetCondit*);
|
bool proc_condit(const NetCondit*);
|
||||||
|
bool proc_continue(const NetContinue*);
|
||||||
bool proc_contribution(const NetContribution*);
|
bool proc_contribution(const NetContribution*);
|
||||||
bool proc_deassign(const NetDeassign*);
|
bool proc_deassign(const NetDeassign*);
|
||||||
bool proc_delay(const NetPDelay*);
|
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*);
|
void proc_do_while(const NetDoWhile*);
|
||||||
bool proc_force(const NetForce*);
|
bool proc_force(const NetForce*);
|
||||||
void proc_forever(const NetForever*);
|
void proc_forever(const NetForever*);
|
||||||
|
bool proc_forloop(const NetForLoop*);
|
||||||
void proc_free(const NetFree*);
|
void proc_free(const NetFree*);
|
||||||
bool proc_release(const NetRelease*);
|
bool proc_release(const NetRelease*);
|
||||||
void proc_repeat(const NetRepeat*);
|
void proc_repeat(const NetRepeat*);
|
||||||
|
|
@ -851,6 +854,13 @@ struct ivl_statement_s {
|
||||||
ivl_statement_t stmt_;
|
ivl_statement_t stmt_;
|
||||||
} forever_;
|
} 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 */
|
struct { /* IVL_ST_FREE */
|
||||||
ivl_scope_t scope;
|
ivl_scope_t scope;
|
||||||
} free_;
|
} free_;
|
||||||
|
|
|
||||||
21
target.cc
21
target.cc
|
|
@ -325,6 +325,13 @@ bool target_t::proc_block(const NetBlock*)
|
||||||
return false;
|
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)
|
void target_t::proc_case(const NetCase*cur)
|
||||||
{
|
{
|
||||||
cerr << "target (" << typeid(*this).name() << "): "
|
cerr << "target (" << typeid(*this).name() << "): "
|
||||||
|
|
@ -348,6 +355,13 @@ bool target_t::proc_condit(const NetCondit*condit)
|
||||||
return false;
|
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)
|
bool target_t::proc_contribution(const NetContribution*net)
|
||||||
{
|
{
|
||||||
cerr << "target (" << typeid(*this).name() << "): "
|
cerr << "target (" << typeid(*this).name() << "): "
|
||||||
|
|
@ -399,6 +413,13 @@ void target_t::proc_forever(const NetForever*)
|
||||||
"Unhandled proc_forever." << endl;
|
"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*)
|
void target_t::proc_free(const NetFree*)
|
||||||
{
|
{
|
||||||
cerr << "target (" << typeid(*this).name() << "): "
|
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 bool proc_assign(const NetAssign*);
|
||||||
virtual void proc_assign_nb(const NetAssignNB*);
|
virtual void proc_assign_nb(const NetAssignNB*);
|
||||||
virtual bool proc_block(const NetBlock*);
|
virtual bool proc_block(const NetBlock*);
|
||||||
|
virtual bool proc_break(const NetBreak*);
|
||||||
virtual void proc_case(const NetCase*);
|
virtual void proc_case(const NetCase*);
|
||||||
virtual bool proc_cassign(const NetCAssign*);
|
virtual bool proc_cassign(const NetCAssign*);
|
||||||
virtual bool proc_condit(const NetCondit*);
|
virtual bool proc_condit(const NetCondit*);
|
||||||
|
virtual bool proc_continue(const NetContinue*);
|
||||||
virtual bool proc_contribution(const NetContribution*);
|
virtual bool proc_contribution(const NetContribution*);
|
||||||
virtual bool proc_deassign(const NetDeassign*);
|
virtual bool proc_deassign(const NetDeassign*);
|
||||||
virtual bool proc_delay(const NetPDelay*);
|
virtual bool proc_delay(const NetPDelay*);
|
||||||
virtual bool proc_disable(const NetDisable*);
|
virtual bool proc_disable(const NetDisable*);
|
||||||
virtual void proc_do_while(const NetDoWhile*);
|
virtual void proc_do_while(const NetDoWhile*);
|
||||||
virtual bool proc_force(const NetForce*);
|
virtual bool proc_force(const NetForce*);
|
||||||
|
virtual bool proc_forloop(const NetForLoop*) =0;
|
||||||
virtual void proc_forever(const NetForever*);
|
virtual void proc_forever(const NetForever*);
|
||||||
virtual void proc_free(const NetFree*);
|
virtual void proc_free(const NetFree*);
|
||||||
virtual bool proc_release(const NetRelease*);
|
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);
|
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)
|
static void show_stmt_release(ivl_statement_t net, unsigned ind)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
|
@ -404,6 +413,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IVL_ST_BREAK: {
|
||||||
|
fprintf(out, "%*sbreak;\n", ind, "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IVL_ST_CASEX:
|
case IVL_ST_CASEX:
|
||||||
case IVL_ST_CASEZ:
|
case IVL_ST_CASEZ:
|
||||||
case IVL_ST_CASER:
|
case IVL_ST_CASER:
|
||||||
|
|
@ -471,6 +485,11 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case IVL_ST_CONTINUE: {
|
||||||
|
fprintf(out, "%*scontinue;\n", ind, "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case IVL_ST_CONTRIB:
|
case IVL_ST_CONTRIB:
|
||||||
fprintf(out, "%*sCONTRIBUTION ( <+ )\n", ind, "");
|
fprintf(out, "%*sCONTRIBUTION ( <+ )\n", ind, "");
|
||||||
|
|
@ -544,6 +563,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
|
show_stmt_forloop(net, ind);
|
||||||
|
break;
|
||||||
|
|
||||||
case IVL_ST_FREE:
|
case IVL_ST_FREE:
|
||||||
fprintf(out, "%*sfree automatic storage ...\n", ind, "");
|
fprintf(out, "%*sfree automatic storage ...\n", ind, "");
|
||||||
break;
|
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_NOOP:
|
||||||
case IVL_ST_ALLOC:
|
case IVL_ST_ALLOC:
|
||||||
case IVL_ST_ASSIGN:
|
case IVL_ST_ASSIGN:
|
||||||
|
case IVL_ST_BREAK:
|
||||||
case IVL_ST_CASSIGN:
|
case IVL_ST_CASSIGN:
|
||||||
|
case IVL_ST_CONTINUE:
|
||||||
case IVL_ST_DEASSIGN:
|
case IVL_ST_DEASSIGN:
|
||||||
case IVL_ST_FORCE:
|
case IVL_ST_FORCE:
|
||||||
case IVL_ST_FREE:
|
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. */
|
/* These have a single sub-statement so look for a disable there. */
|
||||||
case IVL_ST_DO_WHILE:
|
case IVL_ST_DO_WHILE:
|
||||||
case IVL_ST_FOREVER:
|
case IVL_ST_FOREVER:
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
case IVL_ST_REPEAT:
|
case IVL_ST_REPEAT:
|
||||||
case IVL_ST_WHILE:
|
case IVL_ST_WHILE:
|
||||||
rtn = has_func_disable(scope, ivl_stmt_sub_stmt(stmt));
|
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);
|
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
|
* Icarus translated <var> = repeat(<count>) <event> <value> into
|
||||||
* begin
|
* begin
|
||||||
|
|
@ -1375,6 +1310,27 @@ static void emit_stmt_fork_named(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
ivl_scope_basename(my_scope));
|
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)
|
static void emit_stmt_release(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
{
|
{
|
||||||
fprintf(vlog_out, "%*crelease ", get_indent(), ' ');
|
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);
|
emit_stmt_block_named(scope, stmt);
|
||||||
} else {
|
} else {
|
||||||
if (is_delayed_or_event_assign(scope, stmt)) break;
|
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_repeat_event_assign(scope, stmt)) break;
|
||||||
if (is_wait(scope, stmt)) break;
|
if (is_wait(scope, stmt)) break;
|
||||||
if (is_utask_call_with_args(scope, stmt)) break;
|
if (is_utask_call_with_args(scope, stmt)) break;
|
||||||
emit_stmt_block(scope, stmt);
|
emit_stmt_block(scope, stmt);
|
||||||
}
|
}
|
||||||
break;
|
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_CASE:
|
||||||
case IVL_ST_CASER:
|
case IVL_ST_CASER:
|
||||||
case IVL_ST_CASEX:
|
case IVL_ST_CASEX:
|
||||||
|
|
@ -1557,6 +1519,13 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
case IVL_ST_CONDIT:
|
case IVL_ST_CONDIT:
|
||||||
emit_stmt_condit(scope, stmt);
|
emit_stmt_condit(scope, stmt);
|
||||||
break;
|
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:
|
case IVL_ST_DEASSIGN:
|
||||||
emit_stmt_deassign(scope, stmt);
|
emit_stmt_deassign(scope, stmt);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1578,6 +1547,9 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
case IVL_ST_FOREVER:
|
case IVL_ST_FOREVER:
|
||||||
emit_stmt_forever(scope, stmt);
|
emit_stmt_forever(scope, stmt);
|
||||||
break;
|
break;
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
|
emit_stmt_forloop(scope, stmt);
|
||||||
|
break;
|
||||||
case IVL_ST_FORK:
|
case IVL_ST_FORK:
|
||||||
if (ivl_stmt_block_scope(stmt)) {
|
if (ivl_stmt_block_scope(stmt)) {
|
||||||
emit_stmt_fork_named(scope, stmt);
|
emit_stmt_fork_named(scope, stmt);
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:32 steve Exp $"
|
|
||||||
#
|
|
||||||
#
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
suffix = @install_suffix@
|
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_expr.o eval_object.o eval_real.o eval_string.o \
|
||||||
eval_vec4.o \
|
eval_vec4.o \
|
||||||
modpath.o stmt_assign.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
|
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);
|
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 */
|
#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 <stdlib.h>
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
|
|
||||||
static int show_statement(ivl_statement_t net, ivl_scope_t sscope);
|
|
||||||
|
|
||||||
unsigned local_count = 0;
|
unsigned local_count = 0;
|
||||||
unsigned thread_count = 0;
|
unsigned thread_count = 0;
|
||||||
|
|
||||||
|
|
@ -1414,21 +1412,6 @@ static int show_stmt_force(ivl_statement_t net)
|
||||||
return 0;
|
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)
|
static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
|
@ -1606,40 +1589,6 @@ static int show_stmt_release(ivl_statement_t net)
|
||||||
return 0;
|
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
|
* The trigger statement is straight forward. All we have to do is
|
||||||
* write a single bit of fake data to the event object.
|
* 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);
|
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)
|
static int show_delete_method(ivl_statement_t net)
|
||||||
{
|
{
|
||||||
show_stmt_file_line(net, "Delete object");
|
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
|
* switches on the statement type and draws code based on the type and
|
||||||
* further specifics.
|
* 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);
|
const ivl_statement_type_t code = ivl_statement_type(net);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
@ -2347,6 +2262,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IVL_ST_BREAK:
|
||||||
|
rc += show_stmt_break(net, sscope);
|
||||||
|
break;
|
||||||
|
|
||||||
case IVL_ST_CASE:
|
case IVL_ST_CASE:
|
||||||
case IVL_ST_CASEX:
|
case IVL_ST_CASEX:
|
||||||
case IVL_ST_CASEZ:
|
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);
|
rc += show_stmt_condit(net, sscope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IVL_ST_CONTINUE:
|
||||||
|
rc += show_stmt_continue(net, sscope);
|
||||||
|
break;
|
||||||
|
|
||||||
case IVL_ST_DEASSIGN:
|
case IVL_ST_DEASSIGN:
|
||||||
rc += show_stmt_deassign(net);
|
rc += show_stmt_deassign(net);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2399,6 +2322,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
rc += show_stmt_fork(net, sscope);
|
rc += show_stmt_fork(net, sscope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IVL_ST_FORLOOP:
|
||||||
|
rc += show_stmt_forloop(net, sscope);
|
||||||
|
break;
|
||||||
|
|
||||||
case IVL_ST_FREE:
|
case IVL_ST_FREE:
|
||||||
rc += show_stmt_free(net);
|
rc += show_stmt_free(net);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue