Merge pull request #855 from steveicarus/steveicarus/loop-control-support

Add break and continue loop control statements support
This commit is contained in:
Stephen Williams 2023-01-15 22:21:55 -08:00 committed by GitHub
commit b74059eaa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 796 additions and 213 deletions

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

222
tgt-vvp/vvp_proc_loops.c Normal file
View File

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

View File

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