diff --git a/Statement.h b/Statement.h index 613f2d64bb..5e3d7b0c1c 100644 --- a/Statement.h +++ b/Statement.h @@ -211,6 +211,12 @@ class PBlock : public PScope, public Statement, public PNamedItem { std::vectorlist_; }; +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: diff --git a/design_dump.cc b/design_dump.cc index c89d3158cb..31f9915c3c 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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 << ""; + fd << ", init_expr="; + if (init_expr_) + fd << *init_expr_; + else + fd << ""; + fd << ", condition="; + if (condition_) + fd << *condition_; + else + fd << ""; 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 diff --git a/elaborate.cc b/elaborate.cc index 127ce71e39..95effd6ea3 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3055,6 +3055,21 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const return cur; } +NetProc* PBreak::elaborate(Design*des, NetScope*) const +{ + if (!gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "'break' jump statement requires SystemVerilog." << endl; + des->errors += 1; + return nullptr; + } + + + NetBreak*res = new NetBreak; + res->set_line(*this); + return res; +} + static int test_case_width(Design*des, NetScope*scope, PExpr*pe, PExpr::width_mode_t&mode) { @@ -3447,6 +3462,20 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const return res; } +NetProc* PContinue::elaborate(Design*des, NetScope*) const +{ + if (!gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "'continue' jump statement requires SystemVerilog." << endl; + des->errors += 1; + return nullptr; + } + + NetContinue*res = new NetContinue; + res->set_line(*this); + return res; +} + NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const { if (peek_tail_name(path_)[0] == '$') { @@ -5445,7 +5474,6 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const NetForLoop*stmt = new NetForLoop(idx_sig, init_expr, cond_expr, sub, step); stmt->set_line(*this); - stmt->wrap_up(); return stmt; } @@ -5520,7 +5548,6 @@ NetProc* PForeach::elaborate_static_array_(Design*des, NetScope*scope, stmt = new NetForLoop(idx_sig, low_expr, cond_expr, sub, step); stmt->set_line(*this); - stmt->wrap_up(); sub = stmt; } @@ -5646,7 +5673,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step); loop->set_line(*this); - loop->wrap_up(); return loop; } diff --git a/emit.cc b/emit.cc index 18f267df6b..39339c281a 100644 --- a/emit.cc +++ b/emit.cc @@ -243,6 +243,11 @@ bool NetBlock::emit_proc(struct target_t*tgt) const return tgt->proc_block(this); } +bool NetBreak::emit_proc(struct target_t*tgt) const +{ + return tgt->proc_break(this); +} + bool NetCase::emit_proc(struct target_t*tgt) const { tgt->proc_case(this); @@ -259,6 +264,11 @@ bool NetCondit::emit_proc(struct target_t*tgt) const return tgt->proc_condit(this); } +bool NetContinue::emit_proc(struct target_t*tgt) const +{ + return tgt->proc_continue(this); +} + bool NetContribution::emit_proc(struct target_t*tgt) const { return tgt->proc_contribution(this); @@ -298,7 +308,31 @@ bool NetForever::emit_proc(struct target_t*tgt) const bool NetForLoop::emit_proc(struct target_t*tgt) const { - return tgt->proc_block(as_block_); + return tgt->proc_forloop(this); +} + +bool NetForLoop::emit_recurse_init(struct target_t*tgt) const +{ + if (init_statement_) return init_statement_->emit_proc(tgt); + return true; +} + +bool NetForLoop::emit_recurse_stmt(struct target_t*tgt) const +{ + if (statement_) return statement_->emit_proc(tgt); + return true; +} + +bool NetForLoop::emit_recurse_step(struct target_t*tgt) const +{ + if (step_statement_) return step_statement_->emit_proc(tgt); + return true; +} + +bool NetForLoop::emit_recurse_condition(struct expr_scan_t*tgt) const +{ + if (condition_) condition_->expr_scan(tgt); + return true; } bool NetFree::emit_proc(struct target_t*tgt) const diff --git a/ivl.def b/ivl.def index a226a22a0c..630a10cc15 100644 --- a/ivl.def +++ b/ivl.def @@ -294,6 +294,7 @@ ivl_stmt_delay_val ivl_stmt_events ivl_stmt_file ivl_stmt_flow_control +ivl_stmt_init_stmt ivl_stmt_lexp ivl_stmt_lineno ivl_stmt_lval @@ -307,6 +308,7 @@ ivl_stmt_parm ivl_stmt_parm_count ivl_stmt_rval ivl_stmt_sfunc_as_task +ivl_stmt_step_stmt ivl_stmt_sub_stmt ivl_switch_a diff --git a/ivl_target.h b/ivl_target.h index 30405c9f16..7f551aa72f 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -409,18 +409,21 @@ typedef enum ivl_statement_type_e { IVL_ST_ASSIGN = 2, IVL_ST_ASSIGN_NB = 3, IVL_ST_BLOCK = 4, + IVL_ST_BREAK = 32, IVL_ST_CASE = 5, IVL_ST_CASER = 24, /* Case statement with real expressions. */ IVL_ST_CASEX = 6, IVL_ST_CASEZ = 7, IVL_ST_CASSIGN = 8, IVL_ST_CONDIT = 9, + IVL_ST_CONTINUE= 33, IVL_ST_CONTRIB = 27, IVL_ST_DEASSIGN = 10, IVL_ST_DELAY = 11, IVL_ST_DELAYX = 12, IVL_ST_DISABLE = 13, IVL_ST_DO_WHILE = 30, + IVL_ST_FORLOOP = 34, IVL_ST_FORCE = 14, IVL_ST_FOREVER = 15, IVL_ST_FORK = 16, @@ -2215,6 +2218,21 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * force l-values, and also non-constant bit or part selects. The * compiler will assure these constraints are met. * + * - IVL_ST_FORLOOP + * This contains the key portions of a for loop, broken into the init + * statement, the sub statement, and the step statement. There is also + * a condition expression that the code generator must check. It is up + * to the target code generator to put these to use. In general, the + * result needs to reflect this: + * + * ivl_stmt_init_stmt(net); + * while( 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 * diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 3f5db26eb2..4bc0de1312 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -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. diff --git a/net_func_eval.cc b/net_func_eval.cc index 278e172999..c7924273aa 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -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&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 (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, diff --git a/net_proc.cc b/net_proc.cc index f425560c5d..ad2644b404 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -201,42 +201,14 @@ NetForever::~NetForever() NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step) : index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step) { - as_block_ = NULL; -} - -void NetForLoop::wrap_up() -{ - NetBlock*top = new NetBlock(NetBlock::SEQU, 0); - - // Handle the case that we are missing the initialization - // statement. This can happen for example with statments like this: - // for ( ; ; ) ; - // 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() diff --git a/netlist.h b/netlist.h index cf180df72c..37fd61f48f 100644 --- a/netlist.h +++ b/netlist.h @@ -3062,6 +3062,12 @@ class NetBlock : public NetProc { NetProc*last_; }; +class NetBreak : public NetProc { + public: + virtual void dump(std::ostream&, unsigned ind) const; + virtual bool emit_proc(struct target_t*) const; +}; + /* * A CASE statement in the Verilog source leads, eventually, to one of * these. This is different from a simple conditional because of the @@ -3210,6 +3216,12 @@ class NetCondit : public NetProc { NetProc*else_; }; +class NetContinue : public NetProc { + public: + virtual void dump(std::ostream&, unsigned ind) const; + virtual bool emit_proc(struct target_t*) const; +}; + /* * This represents the analog contribution statement. The l-val is a * branch expression, and the r-value is an arbitrary expression that @@ -3628,8 +3640,6 @@ class NetForLoop : public NetProc { NetProc*sub, NetProc*step); ~NetForLoop(); - void wrap_up(); - void emit_recurse(struct target_t*) const; virtual NexusSet* nex_input(bool rem_out = true, bool always_sens = false, @@ -3642,6 +3652,11 @@ class NetForLoop : public NetProc { virtual bool evaluate_function(const LineInfo&loc, std::map&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 { diff --git a/parse.y b/parse.y index 081851b2f3..29d47aaa63 100644 --- a/parse.y +++ b/parse.y @@ -1622,8 +1622,14 @@ join_keyword /* IEEE1800-2005: A.6.3 */ jump_statement /* IEEE1800-2005: A.6.5 */ : K_break ';' - { yyerror(@1, "sorry: break statements not supported."); - $$ = 0; + { PBreak*tmp = new PBreak; + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_continue ';' + { PContinue*tmp = new PContinue; + FILE_NAME(tmp, @1); + $$ = tmp; } | K_return ';' { PReturn*tmp = new PReturn(0); diff --git a/pform_dump.cc b/pform_dump.cc index 5b72cbeb46..0d6c03c29a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -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 @@ -921,6 +921,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 +1032,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_ diff --git a/t-dll-api.cc b/t-dll-api.cc index aefc0c5e54..50cb6a2ebe 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2810,6 +2810,10 @@ extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net) case IVL_ST_WHILE: return net->u_.while_.cond_; + case IVL_ST_FORLOOP: + assert(net->u_.forloop_.condition); // XXXX + return net->u_.forloop_.condition; + default: assert(0); return 0; @@ -2863,6 +2867,18 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) return net->u_.delay_.value; } +extern "C" ivl_statement_t ivl_stmt_init_stmt(ivl_statement_t net) +{ + assert(net); + switch (net->type_) { + case IVL_ST_FORLOOP: + return net->u_.forloop_.init_stmt; + default: + assert(0); + return 0; + } +} + extern "C" unsigned ivl_stmt_needs_t0_trigger(ivl_statement_t net) { assert(net); @@ -3091,6 +3107,18 @@ extern "C" ivl_sfunc_as_task_t ivl_stmt_sfunc_as_task(ivl_statement_t net) return IVL_SFUNC_AS_TASK_ERROR; } +extern "C" ivl_statement_t ivl_stmt_step_stmt(ivl_statement_t net) +{ + assert(net); + switch (net->type_) { + case IVL_ST_FORLOOP: + return net->u_.forloop_.step; + default: + assert(0); + return 0; + } +} + extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) { assert(net); @@ -3101,6 +3129,8 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) return net->u_.delayx_.stmt_; case IVL_ST_FOREVER: return net->u_.forever_.stmt_; + case IVL_ST_FORLOOP: + return net->u_.forloop_.stmt; case IVL_ST_WAIT: return net->u_.wait_.stmt_; case IVL_ST_DO_WHILE: diff --git a/t-dll-proc.cc b/t-dll-proc.cc index ab4ee69d23..c8c3677237 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -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_); diff --git a/t-dll.h b/t-dll.h index c492d36e62..909ab5e940 100644 --- a/t-dll.h +++ b/t-dll.h @@ -113,9 +113,11 @@ struct dll_target : public target_t, public expr_scan_t { bool proc_assign(const NetAssign*); void proc_assign_nb(const NetAssignNB*); bool proc_block(const NetBlock*); + bool proc_break(const NetBreak*); void proc_case(const NetCase*); bool proc_cassign(const NetCAssign*); bool proc_condit(const NetCondit*); + bool proc_continue(const NetContinue*); bool proc_contribution(const NetContribution*); bool proc_deassign(const NetDeassign*); bool proc_delay(const NetPDelay*); @@ -123,6 +125,7 @@ struct dll_target : public target_t, public expr_scan_t { void proc_do_while(const NetDoWhile*); bool proc_force(const NetForce*); void proc_forever(const NetForever*); + bool proc_forloop(const NetForLoop*); void proc_free(const NetFree*); bool proc_release(const NetRelease*); void proc_repeat(const NetRepeat*); @@ -851,6 +854,13 @@ struct ivl_statement_s { ivl_statement_t stmt_; } forever_; + struct { /* IVL_ST_FORLOOP */ + ivl_statement_t init_stmt; + ivl_expr_t condition; + ivl_statement_t stmt; + ivl_statement_t step; + } forloop_; + struct { /* IVL_ST_FREE */ ivl_scope_t scope; } free_; diff --git a/target.cc b/target.cc index 8950e2d722..575766f347 100644 --- a/target.cc +++ b/target.cc @@ -325,6 +325,13 @@ bool target_t::proc_block(const NetBlock*) return false; } +bool target_t::proc_break(const NetBreak*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_break." << endl; + return false; +} + void target_t::proc_case(const NetCase*cur) { cerr << "target (" << typeid(*this).name() << "): " @@ -348,6 +355,13 @@ bool target_t::proc_condit(const NetCondit*condit) return false; } +bool target_t::proc_continue(const NetContinue*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_continue." << endl; + return false; +} + bool target_t::proc_contribution(const NetContribution*net) { cerr << "target (" << typeid(*this).name() << "): " @@ -399,6 +413,13 @@ void target_t::proc_forever(const NetForever*) "Unhandled proc_forever." << endl; } +bool target_t::proc_forloop(const NetForLoop*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_forloop." << endl; + return false; +} + void target_t::proc_free(const NetFree*) { cerr << "target (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index 66d5e0733a..6a5879a0ad 100644 --- a/target.h +++ b/target.h @@ -129,15 +129,18 @@ struct target_t { virtual bool proc_assign(const NetAssign*); virtual void proc_assign_nb(const NetAssignNB*); virtual bool proc_block(const NetBlock*); + virtual bool proc_break(const NetBreak*); virtual void proc_case(const NetCase*); virtual bool proc_cassign(const NetCAssign*); virtual bool proc_condit(const NetCondit*); + virtual bool proc_continue(const NetContinue*); virtual bool proc_contribution(const NetContribution*); virtual bool proc_deassign(const NetDeassign*); virtual bool proc_delay(const NetPDelay*); virtual bool proc_disable(const NetDisable*); virtual void proc_do_while(const NetDoWhile*); virtual bool proc_force(const NetForce*); + virtual bool proc_forloop(const NetForLoop*) =0; virtual void proc_forever(const NetForever*); virtual void proc_free(const NetFree*); virtual bool proc_release(const NetRelease*); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 63a5fc8df7..58de7bb7d6 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -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; diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 0821255b5f..078a0e77f3 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -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)); diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index f947333053..ca692f27fd 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -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(; ; ) into - * - * begin - * ; - * while () begin - * - * - * 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 = repeat() 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); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 7bfa5316ba..251b0dcc12 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -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 diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index aadec55128..6d96a10968 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -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 */ diff --git a/tgt-vvp/vvp_proc_loops.c b/tgt-vvp/vvp_proc_loops.c new file mode 100644 index 0000000000..165d239af9 --- /dev/null +++ b/tgt-vvp/vvp_proc_loops.c @@ -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 +# include +# include +# include +# include + +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: + * + * + * top_label: + * if ( is false) + * goto out_label; + * + * continue_label: + * + * 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; +} diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 11dd7a5969..1fe111332b 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -23,8 +23,6 @@ # include # include -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;