diff --git a/design_dump.cc b/design_dump.cc index 2b628a8df..ad2b3fcbb 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: design_dump.cc,v 1.162 2005/07/11 16:56:50 steve Exp $" +#ident "$Id: design_dump.cc,v 1.163 2005/08/27 04:32:08 steve Exp $" #endif # include "config.h" @@ -256,6 +256,7 @@ void NetMult::dump_node(ostream&o, unsigned ind) const void NetMux::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "Multiplexer (NetMux): " << name() + << " width=" << width_ << " swidth=" << swidth_ << " size=" << size_ << " scope=" << scope()->name() << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); @@ -1165,6 +1166,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.163 2005/08/27 04:32:08 steve + * Handle synthesis of fully packed case statements. + * * Revision 1.162 2005/07/11 16:56:50 steve * Remove NetVariable and ivl_variable_t structures. * diff --git a/synth2.cc b/synth2.cc index 3ac2fb304..02eef5a52 100644 --- a/synth2.cc +++ b/synth2.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: synth2.cc,v 1.44 2005/05/15 04:45:50 steve Exp $" +#ident "$Id: synth2.cc,v 1.45 2005/08/27 04:32:08 steve Exp $" #endif # include "config.h" @@ -178,136 +178,86 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, bool NetCase::synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out) { -#if 0 - unsigned cur; - + /* Synthesize the select expression. */ NetNet*esig = expr_->synthesize(des); - /* Scan the select vector looking for constant bits. The - constant bits will be elided from the select input connect, - but we still need to keep track of them. */ - unsigned sel_pins = 0; - unsigned long sel_mask = 0; - unsigned long sel_ref = 0; - for (unsigned idx = 0 ; idx < esig->pin_count() ; idx += 1) { + unsigned sel_width = esig->vector_width(); + assert(sel_width > 0); - if (esig->pin(idx).nexus()->drivers_constant()) { - verinum::V bit = esig->pin(idx).nexus()->driven_value(); - if (bit == verinum::V1) - sel_ref |= 1 << idx; + unsigned mux_width = 0; + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) + mux_width += nex_out.pin(idx).nexus()->vector_width(); - } else { - sel_pins += 1; - sel_mask |= 1 << idx; - } - } + /* Collect all the statements into a map of index to + statement. The guard expression it evaluated to be the + index of the mux value, and the statement is bound to that + index. */ - /* Build a map of guard values to mux select values. This - helps account for constant select bits that are being - elided. */ - mapguard2sel; - cur = 0; - for (unsigned idx = 0 ; idx < (1U<vector_width()) ; idx += 1) { - if ((idx & ~sel_mask) == sel_ref) { - guard2sel[idx] = cur; - cur += 1; - } - } - assert(cur == (1U << sel_pins)); + unsigned long max_guard_value = 0; + mapstatement_map; + NetProc*statement_default = 0; - NetMux*mux = new NetMux(scope, scope->local_symbol(), - nex_out->pin_count(), - 1U << sel_pins, sel_pins); - - /* Connect the non-constant select bits to the select input of - the mux device. */ - cur = 0; - for (unsigned idx = 0 ; idx < esig->pin_count() ; idx += 1) { - /* skip bits that are known to be constant. */ - if ((sel_mask & (1U << idx)) == 0) - continue; - - connect(mux->pin_Sel(cur), esig->pin(idx)); - cur += 1; - } - assert(cur == sel_pins); - - /* Hook up the output of the mux to the mapped output pins. */ - for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) - connect(nex_out->pin(idx), mux->pin_Result(idx)); - - NetProc**statement_map = new NetProc*[1 << sel_pins]; - for (unsigned item = 0 ; item < (1U<(items_[item].guard); assert(ge); verinum gval = ge->value(); - unsigned sel_idx = guard2sel[gval.as_ulong()]; + + unsigned sel_idx = gval.as_ulong(); assert(items_[item].statement); statement_map[sel_idx] = items_[item].statement; + + if (sel_idx > max_guard_value) + max_guard_value = sel_idx; } - /* Now that statements match with mux inputs, synthesize the - sub-statements. If I get to an input that has no statement, - then use the default statement there. */ - NetNet*default_sig = 0; - for (unsigned item = 0 ; item < (1U<width() ; idx += 1) - connect(mux->pin_Data(idx, item), default_sig->pin(idx)); - continue; - } - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, nex_map->pin_count()); - sig->local_flag(true); - - if (statement_map[item] == 0) { - statement_map[item] = default_statement; - default_statement = 0; - default_sig = sig; - } - - if (statement_map[item] == 0) { - /* Missing case and no default; this could still be - * synthesizable with synchronous logic, but not here. */ - DEBUG_SYNTH2_EXIT("NetCase", false) - return false; - } - statement_map[item]->synth_async(des, scope, nex_map, sig); - - for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) - connect(mux->pin_Data(idx, item), sig->pin(idx)); - } - - delete[]statement_map; + NetMux*mux = new NetMux(scope, scope->local_symbol(), + mux_width, mux_size, sel_width); des->add_node(mux); - DEBUG_SYNTH2_EXIT("NetCase", true) + /* The select signal is already synthesized. Simply hook it up. */ + connect(mux->pin_Sel(), esig->pin(0)); + + /* For now, assume that the output is only 1 signal. */ + assert(nex_out.pin_count() == 1); + connect(mux->pin_Result(), nex_out.pin(0)); + + /* For now, only support logic types. */ + ivl_variable_type_t mux_data_type = IVL_VT_LOGIC; + + /* Forgot to support default statements? */ + assert(statement_default == 0); + + NetNet*isig; + for (unsigned idx = 0 ; idx < mux_size ; idx += 1) { + + NetProc*stmt = statement_map[idx]; + if (stmt == 0) { + cerr << get_line() << ": error: case " << idx + << " is not accounted for in asynchronous mux." << endl; + continue; + } + + isig = new NetNet(scope, scope->local_symbol(), + NetNet::TRI, mux_width); + isig->local_flag(true); + isig->data_type(mux_data_type); + + connect(mux->pin_Data(idx), isig->pin(0)); + + NetBus tmp (scope, 1); + connect(tmp.pin(0), isig->pin(0)); + stmt->synth_async(des, scope, tmp, tmp); + } + return true; -#else - cerr << get_line() << ": sorry: forgot how to implement " - << "NetCase::synth_async" << endl; - return false; -#endif } bool NetCondit::synth_async(Design*des, NetScope*scope, @@ -1050,6 +1000,9 @@ void synth2(Design*des) /* * $Log: synth2.cc,v $ + * Revision 1.45 2005/08/27 04:32:08 steve + * Handle synthesis of fully packed case statements. + * * Revision 1.44 2005/05/15 04:45:50 steve * Debug text. * diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 3d0ed7a2b..f04446064 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: draw_mux.c,v 1.10 2005/06/17 03:46:52 steve Exp $" +#ident "$Id: draw_mux.c,v 1.11 2005/08/27 04:32:08 steve Exp $" #endif # include "vvp_priv.h" @@ -48,24 +48,73 @@ static void draw_lpm_mux_ab(ivl_lpm_t net) fprintf(vvp_out, ", C4<>;\n"); } +static void draw_lpm_mux_nest(ivl_lpm_t net) +{ + int idx, level; + unsigned width = ivl_lpm_width(net); + unsigned swidth = ivl_lpm_selects(net); + char*select_input; + + assert(ivl_lpm_size(net) == (1 << swidth)); + + select_input = strdup(draw_net_input(ivl_lpm_select(net))); + + fprintf(vvp_out, "L_%p/0s .part %s, 0, 1; Bit 0 of the select\n", + net, select_input); + + for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 2) { + fprintf(vvp_out, "L_%p/0/%d .functor MUXZ %u", + net, idx/2, width); + fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx+0))); + fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx+1))); + fprintf(vvp_out, ", L_%p/0s, C4<>;\n", net); + } + + for (level = 1 ; level < swidth-1 ; level += 1) { + fprintf(vvp_out, "L_%p/%ds .part %s, %d, 1;\n", + net, level, select_input, level); + + for (idx = 0 ; idx < (ivl_lpm_size(net) >> level); idx += 2) { + fprintf(vvp_out, "L_%p/%d/%d .functor MUXZ %u", + net, width, level,idx); + fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+0); + fprintf(vvp_out, ", L_%p/%d/%d", net, level-1, idx/2+1); + fprintf(vvp_out, ", L_%p/%ds", net, level); + fprintf(vvp_out, ", C4<>;\n"); + } + + } + + + fprintf(vvp_out, "L_%p/%ds .part %s, %d, 1; Bit %d of the select\n", + net, swidth-1, select_input, swidth-1, swidth-1); + + + fprintf(vvp_out, "L_%p .functor MUXZ %u", net, width); + fprintf(vvp_out, ", L_%p/%d/0", net, swidth-2); + fprintf(vvp_out, ", L_%p/%d/1", net, swidth-2); + fprintf(vvp_out, ", L_%p/%ds", net, swidth-1); + fprintf(vvp_out, ", C4<>;\n"); + + free(select_input);} + void draw_lpm_mux(ivl_lpm_t net) { - if ((ivl_lpm_size(net) == 2) && (ivl_lpm_selects(net) == 1)) { draw_lpm_mux_ab(net); return; } -# if 0 - for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) - draw_lpm_mux_bitslice(net, idx); -# else - fprintf(stderr, "XXXX Forgot how to implement wide muxes.\n"); -#endif + /* Here we are at the worst case, we generate a tree of MUXZ + devices to handle the arbitrary size. */ + draw_lpm_mux_nest(net); } /* * $Log: draw_mux.c,v $ + * Revision 1.11 2005/08/27 04:32:08 steve + * Handle synthesis of fully packed case statements. + * * Revision 1.10 2005/06/17 03:46:52 steve * Make functors know their own width. *