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