Handle synthesis of fully packed case statements.
This commit is contained in:
parent
5cf2ce6499
commit
dac11c2468
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CVS_IDENT
|
#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
|
#endif
|
||||||
|
|
||||||
# include "config.h"
|
# 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
|
void NetMux::dump_node(ostream&o, unsigned ind) const
|
||||||
{
|
{
|
||||||
o << setw(ind) << "" << "Multiplexer (NetMux): " << name()
|
o << setw(ind) << "" << "Multiplexer (NetMux): " << name()
|
||||||
|
<< " width=" << width_ << " swidth=" << swidth_ << " size=" << size_
|
||||||
<< " scope=" << scope()->name() << endl;
|
<< " scope=" << scope()->name() << endl;
|
||||||
dump_node_pins(o, ind+4);
|
dump_node_pins(o, ind+4);
|
||||||
dump_obj_attr(o, ind+4);
|
dump_obj_attr(o, ind+4);
|
||||||
|
|
@ -1165,6 +1166,9 @@ void Design::dump(ostream&o) const
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: design_dump.cc,v $
|
* $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
|
* Revision 1.162 2005/07/11 16:56:50 steve
|
||||||
* Remove NetVariable and ivl_variable_t structures.
|
* Remove NetVariable and ivl_variable_t structures.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
169
synth2.cc
169
synth2.cc
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CVS_IDENT
|
#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
|
#endif
|
||||||
|
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
|
|
@ -178,136 +178,86 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
|
||||||
bool NetCase::synth_async(Design*des, NetScope*scope,
|
bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
const NetBus&nex_map, NetBus&nex_out)
|
const NetBus&nex_map, NetBus&nex_out)
|
||||||
{
|
{
|
||||||
#if 0
|
/* Synthesize the select expression. */
|
||||||
unsigned cur;
|
|
||||||
|
|
||||||
NetNet*esig = expr_->synthesize(des);
|
NetNet*esig = expr_->synthesize(des);
|
||||||
|
|
||||||
/* Scan the select vector looking for constant bits. The
|
unsigned sel_width = esig->vector_width();
|
||||||
constant bits will be elided from the select input connect,
|
assert(sel_width > 0);
|
||||||
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) {
|
|
||||||
|
|
||||||
if (esig->pin(idx).nexus()->drivers_constant()) {
|
unsigned mux_width = 0;
|
||||||
verinum::V bit = esig->pin(idx).nexus()->driven_value();
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
|
||||||
if (bit == verinum::V1)
|
mux_width += nex_out.pin(idx).nexus()->vector_width();
|
||||||
sel_ref |= 1 << idx;
|
|
||||||
|
|
||||||
} else {
|
/* Collect all the statements into a map of index to
|
||||||
sel_pins += 1;
|
statement. The guard expression it evaluated to be the
|
||||||
sel_mask |= 1 << idx;
|
index of the mux value, and the statement is bound to that
|
||||||
}
|
index. */
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a map of guard values to mux select values. This
|
unsigned long max_guard_value = 0;
|
||||||
helps account for constant select bits that are being
|
map<unsigned long,NetProc*>statement_map;
|
||||||
elided. */
|
NetProc*statement_default = 0;
|
||||||
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));
|
|
||||||
|
|
||||||
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) {
|
for (unsigned item = 0 ; item < nitems_ ; item += 1) {
|
||||||
/* Skip the default case this pass. */
|
|
||||||
if (items_[item].guard == 0) {
|
if (items_[item].guard == 0) {
|
||||||
default_statement = items_[item].statement;
|
statement_default = items_[item].statement;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
|
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
|
||||||
assert(ge);
|
assert(ge);
|
||||||
verinum gval = ge->value();
|
verinum gval = ge->value();
|
||||||
unsigned sel_idx = guard2sel[gval.as_ulong()];
|
|
||||||
|
unsigned sel_idx = gval.as_ulong();
|
||||||
|
|
||||||
assert(items_[item].statement);
|
assert(items_[item].statement);
|
||||||
statement_map[sel_idx] = 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
|
unsigned mux_size = max_guard_value + 1;
|
||||||
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) {
|
|
||||||
|
|
||||||
/* Detect the case that this is a default input, and I
|
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
||||||
have a precalculated default_sig. */
|
mux_width, mux_size, sel_width);
|
||||||
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;
|
|
||||||
des->add_node(mux);
|
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;
|
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,
|
bool NetCondit::synth_async(Design*des, NetScope*scope,
|
||||||
|
|
@ -1050,6 +1000,9 @@ void synth2(Design*des)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Log: synth2.cc,v $
|
* $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
|
* Revision 1.44 2005/05/15 04:45:50 steve
|
||||||
* Debug text.
|
* Debug text.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CVS_IDENT
|
#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
|
#endif
|
||||||
|
|
||||||
# include "vvp_priv.h"
|
# include "vvp_priv.h"
|
||||||
|
|
@ -48,24 +48,73 @@ static void draw_lpm_mux_ab(ivl_lpm_t net)
|
||||||
fprintf(vvp_out, ", C4<>;\n");
|
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)
|
void draw_lpm_mux(ivl_lpm_t net)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ((ivl_lpm_size(net) == 2) && (ivl_lpm_selects(net) == 1)) {
|
if ((ivl_lpm_size(net) == 2) && (ivl_lpm_selects(net) == 1)) {
|
||||||
draw_lpm_mux_ab(net);
|
draw_lpm_mux_ab(net);
|
||||||
return;
|
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 $
|
* $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
|
* Revision 1.10 2005/06/17 03:46:52 steve
|
||||||
* Make functors know their own width.
|
* Make functors know their own width.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue