Skip to content

Commit

Permalink
Add compiler support for break and continue
Browse files Browse the repository at this point in the history
This includes support at the parser (pform) through enaboration
and the netlist format for the break and continue statements.

Elaboration actually already worked for for-loops, but since the code
generators need more information, this is a rewire of that support to
be explicit about for-loops. This means they are not rewritten as fancy
while loops. The code generators will have to handle that.

Given the elaboration of for-loops now work, write the vvp code generator
support needed to implement it.

Now that for-loops are presented as for-loops to the code generator, the
vlog95 code generator doesn't need to infer them anymore. Generate the code
more directly.

Also update the tests list so that the vlog95_reg tests all pass.
  • Loading branch information
steveicarus committed Jan 16, 2023
1 parent 45bd096 commit 6c9c876
Show file tree
Hide file tree
Showing 24 changed files with 672 additions and 213 deletions.
13 changes: 13 additions & 0 deletions Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
28 changes: 27 additions & 1 deletion design_dump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) << "";
Expand Down Expand Up @@ -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) << "";
Expand Down Expand Up @@ -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
Expand Down
32 changes: 29 additions & 3 deletions elaborate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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] == '$') {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
36 changes: 35 additions & 1 deletion emit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions ivl.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
29 changes: 26 additions & 3 deletions ivl_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
*
Expand Down
3 changes: 3 additions & 0 deletions ivtest/regress-vlog95.list
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,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.
Expand Down
51 changes: 48 additions & 3 deletions net_func_eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 6c9c876

Please sign in to comment.