Handle special case of if inside of block.

If statements within blocks can confuse the synthesizer when there
are outputs that are assigned ahead of the if statement. This patch
handles that case.
This commit is contained in:
Stephen Williams 2014-04-16 21:06:01 -07:00
parent c32610d135
commit 17be8e8c7c
2 changed files with 93 additions and 41 deletions

View File

@ -2542,6 +2542,11 @@ class NetProc : public virtual LineInfo {
// Recursively checks to see if there is delay in this element.
virtual DelayType delay_type() const;
protected:
bool synth_async_block_substatement_(Design*des, NetScope*scope,
NexusSet&nex_map,
NetBus&accumulated_nex_out,
NetProc*substmt);
private:
friend class NetBlock;
NetProc*next_;

129
synth2.cc
View File

@ -93,8 +93,10 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
<< ", nex_out.pin_count()==" << nex_out.pin_count() << endl;
}
/* For now, assume there is exactly one output. */
ivl_assert(*this, nex_out.pin_count() == 1);
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
if (lval_->lwidth() != lsig->vector_width()) {
ivl_assert(*this, lval_->lwidth() < lsig->vector_width());
@ -121,7 +123,6 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
rsig = tmp;
}
#endif
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
@ -133,6 +134,57 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
return true;
}
bool NetProc::synth_async_block_substatement_(Design*des, NetScope*scope,
NexusSet&nex_map,
NetBus&accumulated_nex_out,
NetProc*substmt)
{
// Create a temporary map of the output only from this statement.
NexusSet tmp_map;
substmt->nex_output(tmp_map);
if (debug_synth2) {
cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: "
<< "tmp_map.size()==" << tmp_map.size()
<< " for statement at " << substmt->get_fileline()
<< endl;
}
/* Create also a temporary NetBus to collect the
output from the synthesis. */
NetBus tmp_out (scope, tmp_map.size());
// Map (and move) the accumulated_nex_out for this block
// to the version that we can pass to the next
// statement. We will move the result back later.
NetBus accumulated_tmp_out (scope, tmp_map.size());
for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) {
unsigned ptr = tmp_map.find_nexus(nex_map[idx]);
if (ptr >= tmp_map.size())
continue;
connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx));
accumulated_nex_out.pin(idx).unlink();
}
bool ok_flag = substmt->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out);
if (ok_flag == false)
return false;
// Now map the output from the substatement back to the
// accumulated_nex_out for this block. Look for the
// nex_map pin that is linked to the tmp_map.pin(idx)
// pin, and link that to the tmp_out.pin(idx) output link.
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
ivl_assert(*this, ptr < accumulated_nex_out.pin_count());
connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx));
}
return true;
}
/*
* Sequential blocks are translated to asynchronous logic by
* translating each statement of the block, in order, into gates. The
@ -152,45 +204,13 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
do {
cur = cur->next_;
/* Create a temporary map of the output only from this
statement. */
NexusSet tmp_map;
cur->nex_output(tmp_map);
/* Create also a temporary NetBus to collect the
output from the synthesis. */
NetBus tmp_out (scope, tmp_map.size());
// Map (and move) the accumulated_nex_out for this block
// to the version that we can pass to the next
// statement. We will move the result back later.
NetBus accumulated_tmp_out (scope, tmp_map.size());
for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) {
unsigned ptr = tmp_map.find_nexus(nex_map[idx]);
if (ptr >= tmp_map.size())
continue;
connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx));
accumulated_nex_out.pin(idx).unlink();
}
bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out);
bool ok_flag = synth_async_block_substatement_(des, scope, nex_map,
accumulated_nex_out,
cur);
flag = flag && ok_flag;
if (ok_flag == false)
continue;
// Now map the output from the substatement back to the
// accumulated_nex_out for this block. Look for the
// nex_map pin that is linked to the tmp_map.pin(idx)
// pin, and link that to the tmp_out.pin(idx) output link.
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
ivl_assert(*this, ptr < accumulated_nex_out.pin_count());
connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx));
}
} while (cur != last_);
// The output from the block is now the accumulated outputs.
@ -386,6 +406,12 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
NetNet*ssig = expr_->synthesize(des, scope, expr_);
assert(ssig);
if (debug_synth2) {
cerr << get_fileline() << ": NetCondit::synth_async: "
<< "Synthesize if clause at " << if_->get_fileline()
<< endl;
}
bool flag;
NetBus asig(scope, nex_out.pin_count());
NetBus atmp(scope, nex_out.pin_count());
@ -402,16 +428,29 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
connect(bsig.pin(idx), accumulated_nex_out.pin(idx));
accumulated_nex_out.pin(idx).unlink();
}
} else {
flag = else_->synth_async(des, scope, nex_map, bsig, btmp);
if (debug_synth2) {
cerr << get_fileline() << ": NetCondit::synth_async: "
<< "Synthesize else clause at " << else_->get_fileline()
<< endl;
}
flag = synth_async_block_substatement_(des, scope, nex_map, accumulated_nex_out, else_);
if (!flag) {
return false;
}
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
connect(bsig.pin(idx), accumulated_nex_out.pin(idx));
accumulated_nex_out.pin(idx).unlink();
}
}
ivl_assert(*this, nex_out.pin_count()==asig.pin_count());
ivl_assert(*this, nex_out.pin_count()==bsig.pin_count());
bool rc_flag = true;
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
ivl_assert(*this, asig.pin(idx).nexus()->pick_any_net());
ivl_assert(*this, bsig.pin(idx).nexus()->pick_any_net());
@ -422,7 +461,15 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
}
unsigned mux_width = asig.pin(idx).nexus()->vector_width();
ivl_assert(*this, mux_width != 0);
ivl_assert(*this, mux_width==bsig.pin(idx).nexus()->vector_width());
if (mux_width != bsig.pin(idx).nexus()->vector_width()) {
cerr << get_fileline() << ": internal error: "
<< "NetCondit::synth_async: "
<< "Mux input sizes do not match."
<< "A size=" << mux_width
<< ", B size=" << bsig.pin(idx).nexus()->vector_width()
<< endl;
rc_flag = false;
}
NetMux*mux = new NetMux(scope, scope->local_symbol(),
mux_width, 2, 1);
@ -448,7 +495,7 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
des->add_node(mux);
}
return true;
return rc_flag;
}
bool NetEvWait::synth_async(Design*des, NetScope*scope,