From 17be8e8c7c962c3af6f98c9b30f390a12e74ac1a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 16 Apr 2014 21:06:01 -0700 Subject: [PATCH] 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. --- netlist.h | 5 +++ synth2.cc | 129 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 93 insertions(+), 41 deletions(-) diff --git a/netlist.h b/netlist.h index 4f49bf9b2..3242e26c0 100644 --- a/netlist.h +++ b/netlist.h @@ -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_; diff --git a/synth2.cc b/synth2.cc index b6dd772cf..208ecf168 100644 --- a/synth2.cc +++ b/synth2.cc @@ -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,