Add synthesis of for-loops
This required keeping for-loops as actual things through the netlist form so that the synthesizer can get at and understand the parts of the for-loop. This may improve vvp code generation in the future, but for now continue to present to the vvp code generation the block-while form.
This commit is contained in:
parent
ec0c66ff25
commit
be0c61051d
|
|
@ -1165,6 +1165,13 @@ void NetForever::dump(ostream&o, unsigned ind) const
|
|||
statement_->dump(o, ind+2);
|
||||
}
|
||||
|
||||
void NetForLoop::dump(ostream&fd, unsigned ind) const
|
||||
{
|
||||
fd << setw(ind) << "" << "FOR LOOP index=" << index_->name() << endl;
|
||||
statement_->dump(fd, ind+4);
|
||||
step_statement_->dump(fd, ind+4);
|
||||
}
|
||||
|
||||
void NetFree::dump(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "// free storage : " << scope_path(scope_) << endl;
|
||||
|
|
|
|||
37
elaborate.cc
37
elaborate.cc
|
|
@ -4549,15 +4549,12 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
|||
*/
|
||||
NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetExpr*etmp;
|
||||
NetExpr*initial_expr;
|
||||
assert(scope);
|
||||
|
||||
const PEIdent*id1 = dynamic_cast<const PEIdent*>(name1_);
|
||||
assert(id1);
|
||||
|
||||
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
||||
top->set_line(*this);
|
||||
|
||||
/* make the expression, and later the initial assignment to
|
||||
the condition variable. The statement in the for loop is
|
||||
very specifically an assignment. */
|
||||
|
|
@ -4569,34 +4566,23 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
return 0;
|
||||
}
|
||||
assert(sig);
|
||||
NetAssign_*lv = new NetAssign_(sig);
|
||||
|
||||
/* Make the r-value of the initial assignment, and size it
|
||||
properly. Then use it to build the assignment statement. */
|
||||
etmp = elaborate_rval_expr(des, scope, sig->net_type(),
|
||||
lv->expr_type(), lv->lwidth(),
|
||||
initial_expr = elaborate_rval_expr(des, scope, sig->net_type(),
|
||||
sig->data_type(), sig->vector_width(),
|
||||
expr1_);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: FOR initial assign: "
|
||||
<< sig->name() << " = " << *etmp << endl;
|
||||
<< sig->name() << " = " << *initial_expr << endl;
|
||||
}
|
||||
|
||||
NetAssign*init = new NetAssign(lv, etmp);
|
||||
init->set_line(*this);
|
||||
|
||||
top->append(init);
|
||||
|
||||
NetBlock*body = new NetBlock(NetBlock::SEQU, 0);
|
||||
body->set_line(*this);
|
||||
|
||||
/* Elaborate the statement that is contained in the for
|
||||
loop. If there is an error, this will return 0 and I should
|
||||
skip the append. No need to worry, the error has been
|
||||
reported so it's OK that the netlist is bogus. */
|
||||
NetProc*tmp = statement_->elaborate(des, scope);
|
||||
if (tmp)
|
||||
body->append(tmp);
|
||||
NetProc*sub = statement_->elaborate(des, scope);
|
||||
|
||||
|
||||
/* Now elaborate the for_step statement. I really should do
|
||||
|
|
@ -4604,20 +4590,19 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
really does step the variable. */
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Elaborate for_step statement "
|
||||
<< sig->name() << " = " << *etmp << endl;
|
||||
<< sig->name() << " = " << *initial_expr << endl;
|
||||
}
|
||||
|
||||
NetProc*step = step_->elaborate(des, scope);
|
||||
|
||||
body->append(step);
|
||||
|
||||
|
||||
/* Elaborate the condition expression. Try to evaluate it too,
|
||||
in case it is a constant. This is an interesting case
|
||||
worthy of a warning. */
|
||||
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
||||
if (ce == 0) {
|
||||
delete top;
|
||||
delete sub;
|
||||
delete step;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4629,10 +4614,10 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
/* All done, build up the loop. */
|
||||
|
||||
NetWhile*loop = new NetWhile(ce, body);
|
||||
NetForLoop*loop = new NetForLoop(sig, initial_expr, ce, sub, step);
|
||||
loop->set_line(*this);
|
||||
top->append(loop);
|
||||
return top;
|
||||
loop->wrap_up();
|
||||
return loop;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
5
emit.cc
5
emit.cc
|
|
@ -283,6 +283,11 @@ bool NetForever::emit_proc(struct target_t*tgt) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NetForLoop::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->proc_block(as_block_);
|
||||
}
|
||||
|
||||
bool NetFree::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_free(this);
|
||||
|
|
|
|||
|
|
@ -1271,6 +1271,22 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, NetExpr*root)
|
|||
*/
|
||||
NetNet* NetESignal::synthesize(Design*des, NetScope*scope, NetExpr*root)
|
||||
{
|
||||
// If this is a synthesis with a specific value for the
|
||||
// signal, then replace it (here) with a constant value.
|
||||
if (net_->scope()==scope && net_->name()==scope->genvar_tmp) {
|
||||
netvector_t*tmp_vec = new netvector_t(net_->data_type(),
|
||||
net_->vector_width()-1, 0);
|
||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::IMPLICIT, tmp_vec);
|
||||
verinum tmp_val ((uint64_t)scope->genvar_tmp_val, net_->vector_width());
|
||||
NetConst*tmp_const = new NetConst(scope, scope->local_symbol(), tmp_val);
|
||||
tmp_const->set_line(*this);
|
||||
des->add_node(tmp_const);
|
||||
|
||||
connect(tmp->pin(0), tmp_const->pin(0));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
if (word_ == 0)
|
||||
return net_;
|
||||
|
||||
|
|
|
|||
|
|
@ -628,6 +628,16 @@ bool NetForever::evaluate_function(const LineInfo&loc,
|
|||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, resort to the block form of the statement until we learn
|
||||
* to do this directly.
|
||||
*/
|
||||
bool NetForLoop::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&context_map) const
|
||||
{
|
||||
return as_block_->evaluate_function(loc, context_map);
|
||||
}
|
||||
|
||||
bool NetRepeat::evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&context_map) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -406,6 +406,25 @@ NexusSet* NetForce::nex_input(bool)
|
|||
return new NexusSet;
|
||||
}
|
||||
|
||||
NexusSet* NetForLoop::nex_input(bool rem_out)
|
||||
{
|
||||
NexusSet*result = init_expr_->nex_input(rem_out);
|
||||
|
||||
NexusSet*tmp = condition_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
tmp = statement_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
tmp = step_statement_->nex_input(rem_out);
|
||||
result->add(*tmp);
|
||||
delete tmp;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetForever::nex_input(bool rem_out)
|
||||
{
|
||||
NexusSet*result = statement_->nex_input(rem_out);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,11 @@ void NetEvWait::nex_output(NexusSet&out)
|
|||
statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetForLoop::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
}
|
||||
|
||||
void NetPDelay::nex_output(NexusSet&out)
|
||||
{
|
||||
if (statement_) statement_->nex_output(out);
|
||||
|
|
|
|||
37
net_proc.cc
37
net_proc.cc
|
|
@ -126,6 +126,43 @@ NetForever::~NetForever()
|
|||
delete statement_;
|
||||
}
|
||||
|
||||
NetForLoop::NetForLoop(NetNet*ind, NetExpr*iexpr, NetExpr*cond, NetProc*sub, NetProc*step)
|
||||
: index_(ind), init_expr_(iexpr), condition_(cond), statement_(sub), step_statement_(step)
|
||||
{
|
||||
}
|
||||
|
||||
void NetForLoop::wrap_up()
|
||||
{
|
||||
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
||||
top->set_line(*this);
|
||||
|
||||
NetAssign_*lv = new NetAssign_(index_);
|
||||
NetAssign*set_stmt = new NetAssign(lv, init_expr_);
|
||||
set_stmt->set_line(*init_expr_);
|
||||
top->append(set_stmt);
|
||||
|
||||
NetBlock*internal_block = new NetBlock(NetBlock::SEQU, 0);
|
||||
internal_block->set_line(*this);
|
||||
|
||||
internal_block->append(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()
|
||||
{
|
||||
delete init_expr_;
|
||||
delete condition_;
|
||||
delete statement_;
|
||||
delete step_statement_;
|
||||
}
|
||||
|
||||
NetPDelay::NetPDelay(uint64_t d, NetProc*st)
|
||||
: delay_(d), expr_(0), statement_(st)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2756,6 +2756,11 @@ DelayType NetForever::delay_type() const
|
|||
return statement_->delay_type();
|
||||
}
|
||||
|
||||
DelayType NetForLoop::delay_type() const
|
||||
{
|
||||
return get_loop_delay_type(condition_, statement_);
|
||||
}
|
||||
|
||||
DelayType NetPDelay::delay_type() const
|
||||
{
|
||||
if (expr_) {
|
||||
|
|
|
|||
40
netlist.h
40
netlist.h
|
|
@ -1172,6 +1172,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
std::map<perm_string,LocalVar> loop_index_tmp;
|
||||
|
||||
private:
|
||||
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
|
||||
void evaluate_parameter_real_(Design*des, param_ref_t cur);
|
||||
|
|
@ -3308,6 +3310,44 @@ class NetForever : public NetProc {
|
|||
NetProc*statement_;
|
||||
};
|
||||
|
||||
class NetForLoop : public NetProc {
|
||||
|
||||
public:
|
||||
explicit NetForLoop(NetNet*index, NetExpr*initial_expr, NetExpr*cond,
|
||||
NetProc*sub, NetProc*step);
|
||||
~NetForLoop();
|
||||
|
||||
void wrap_up();
|
||||
|
||||
void emit_recurse(struct target_t*) const;
|
||||
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
virtual void nex_output(NexusSet&);
|
||||
virtual bool emit_proc(struct target_t*) const;
|
||||
virtual void dump(ostream&, unsigned ind) const;
|
||||
virtual DelayType delay_type() const;
|
||||
virtual bool evaluate_function(const LineInfo&loc,
|
||||
map<perm_string,LocalVar>&ctx) const;
|
||||
|
||||
// synthesize as asynchronous logic, and return true.
|
||||
bool synth_async(Design*des, NetScope*scope,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
NetBus&accumulated_nex_out);
|
||||
|
||||
private:
|
||||
NetNet*index_;
|
||||
NetExpr*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 {
|
||||
|
||||
public:
|
||||
|
|
|
|||
101
synth2.cc
101
synth2.cc
|
|
@ -100,16 +100,22 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
|||
<< ", nex_out.pin_count()==" << nex_out.pin_count() << endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, nex_out.pin_count()==1);
|
||||
ivl_assert(*this, rsig->pin_count()==1);
|
||||
connect(nex_out.pin(0), rsig->pin(0));
|
||||
|
||||
#if 0
|
||||
// Here we note if the l-value is actually a bit/part
|
||||
// select. If so, generate a NetPartSelect to perform the select.
|
||||
if (lval_->lwidth() != lsig->vector_width()) {
|
||||
ivl_assert(*this, lval_->lwidth() < lsig->vector_width());
|
||||
|
||||
// XXXX If we ar within a NetForLoop or similar
|
||||
// processing, then there may be an index value. I
|
||||
// currently do not know how to handle that, but
|
||||
// probably I'm going to need the index_args passed in.
|
||||
long base_off = 0;
|
||||
if (! eval_as_long(base_off, lval_->get_base())) {
|
||||
|
||||
// Evaluate the index expression to a constant.
|
||||
const NetExpr*base_expr_raw = lval_->get_base();
|
||||
ivl_assert(*this, base_expr_raw);
|
||||
NetExpr*base_expr = base_expr_raw->evaluate_function(*this, scope->loop_index_tmp);
|
||||
if (! eval_as_long(base_off, base_expr)) {
|
||||
assert(0);
|
||||
}
|
||||
ivl_assert(*this, base_off >= 0);
|
||||
|
|
@ -129,7 +135,11 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
|||
connect(ps->pin(0), rsig->pin(0));
|
||||
rsig = tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
ivl_assert(*this, nex_out.pin_count()==1);
|
||||
ivl_assert(*this, rsig->pin_count()==1);
|
||||
connect(nex_out.pin(0), rsig->pin(0));
|
||||
|
||||
|
||||
/* This lval_ represents a reg that is a WIRE in the
|
||||
synthesized results. This function signals the destructor
|
||||
|
|
@ -533,6 +543,83 @@ bool NetEvWait::synth_async(Design*des, NetScope*scope,
|
|||
return flag;
|
||||
}
|
||||
|
||||
bool NetForLoop::synth_async(Design*des, NetScope*scope,
|
||||
NexusSet&nex_map, NetBus&nex_out,
|
||||
NetBus&accumulated_nex_out)
|
||||
{
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetForLoop::synth_async: "
|
||||
<< "Index variable is " << index_->name() << endl;
|
||||
cerr << get_fileline() << ": NetForLoop::synth_async: "
|
||||
<< "Initialization expression: " << *init_expr_ << endl;
|
||||
}
|
||||
|
||||
// Get the step assignment statement and break it into the
|
||||
// l-value (should be the index) and the r-value, which is the
|
||||
// step expressions.
|
||||
NetAssign*step_assign = dynamic_cast<NetAssign*> (step_statement_);
|
||||
ivl_assert(*this, step_assign);
|
||||
ivl_assert(*this, step_assign->assign_operator()==0);
|
||||
NetExpr*step_expr = step_assign->rval();
|
||||
|
||||
// Tell the scope that this index value is like a genvar.
|
||||
LocalVar index_var;
|
||||
index_var.nwords = 0;
|
||||
|
||||
map<perm_string,LocalVar> index_args;
|
||||
|
||||
// Calculate the initial value for the index.
|
||||
index_var.value = init_expr_->evaluate_function(*this, index_args);
|
||||
ivl_assert(*this, index_var.value);
|
||||
index_args[index_->name()] = index_var;
|
||||
|
||||
for (;;) {
|
||||
// Evaluate the condition expression. If it is false,
|
||||
// then we are going to break out of this synthesis loop.
|
||||
NetExpr*tmp = condition_->evaluate_function(*this, index_args);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
long cond_value;
|
||||
bool rc = eval_as_long(cond_value, tmp);
|
||||
ivl_assert(*this, rc);
|
||||
delete tmp;
|
||||
if (!cond_value) break;
|
||||
|
||||
scope->genvar_tmp = index_->name();
|
||||
rc = eval_as_long(scope->genvar_tmp_val, index_var.value);
|
||||
ivl_assert(*this, rc);
|
||||
|
||||
if (debug_synth2) {
|
||||
cerr << get_fileline() << ": NetForLoop::synth_async: "
|
||||
<< "Synthesis iteration with " << index_->name()
|
||||
<< "=" << *index_var.value << endl;
|
||||
}
|
||||
|
||||
// Synthesize the iterated expression. Stash the loop
|
||||
// index value so that the substatements can see this
|
||||
// value and use it during its own synthesis.
|
||||
ivl_assert(*this, scope->loop_index_tmp.empty());
|
||||
scope->loop_index_tmp = index_args;
|
||||
rc = statement_->synth_async(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||
scope->loop_index_tmp.clear();
|
||||
|
||||
// Evaluate the step_expr to generate the next index value.
|
||||
tmp = step_expr->evaluate_function(*this, index_args);
|
||||
ivl_assert(*this, tmp);
|
||||
delete index_var.value;
|
||||
index_var.value = tmp;
|
||||
index_args[index_->name()] = index_var;
|
||||
}
|
||||
|
||||
delete index_var.value;
|
||||
#if 0
|
||||
cerr << get_fileline() << ": sorry: Synthesis of for-loops not implemented." << endl;
|
||||
return as_block_->synth_async(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is called when the process is shown to be
|
||||
* asynchronous. Figure out the nexus set of outputs from this
|
||||
|
|
|
|||
Loading…
Reference in New Issue