Handle synthesis of fully packed case statements.

This commit is contained in:
steve 2005-08-27 04:32:08 +00:00
parent 5cf2ce6499
commit dac11c2468
3 changed files with 123 additions and 117 deletions

View File

@ -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.
*

169
synth2.cc
View File

@ -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. */
map<unsigned long,unsigned long>guard2sel;
cur = 0;
for (unsigned idx = 0 ; idx < (1U<<esig->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;
map<unsigned long,NetProc*>statement_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<<sel_pins) ; item += 1)
statement_map[item] = 0;
/* Assign the input statements to MUX inputs. This involves
calculating the guard value, passing that through the
guard2sel map, then saving the statement in the
statement_map. If I find a default case, then save that for
use later. */
NetProc*default_statement = 0;
for (unsigned item = 0 ; item < nitems_ ; item += 1) {
/* Skip the default case this pass. */
if (items_[item].guard == 0) {
default_statement = items_[item].statement;
statement_default = items_[item].statement;
continue;
}
NetEConst*ge = dynamic_cast<NetEConst*>(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<<sel_pins) ; item += 1) {
unsigned mux_size = max_guard_value + 1;
/* Detect the case that this is a default input, and I
have a precalculated default_sig. */
if ((statement_map[item] == 0) && (default_sig != 0)) {
for (unsigned idx = 0 ; idx < mux->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.
*

View File

@ -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.
*