More robust case statement synthesis
Handle the cases that the case statement carries complet sub- statements. This is just a generalization of what is already there.
This commit is contained in:
parent
9f2b7d6553
commit
be1130ddbf
114
synth2.cc
114
synth2.cc
|
|
@ -189,18 +189,18 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
unsigned sel_width = esig->vector_width();
|
unsigned sel_width = esig->vector_width();
|
||||||
assert(sel_width > 0);
|
assert(sel_width > 0);
|
||||||
|
|
||||||
unsigned mux_width = 0;
|
ivl_assert(*this, nex_map.size() == nex_out.pin_count());
|
||||||
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
|
|
||||||
mux_width += nex_out.pin(idx).nexus()->vector_width();
|
|
||||||
|
|
||||||
unsigned map_width = 0;
|
vector<unsigned> mux_width (nex_out.pin_count());
|
||||||
for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1)
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
|
||||||
map_width += nex_map[idx].wid;
|
mux_width[idx] = nex_map[idx].wid;
|
||||||
|
if (debug_synth2) {
|
||||||
|
cerr << get_fileline() << ": NetCase::synth_async: "
|
||||||
|
<< "idx=" << idx
|
||||||
|
<< ", mux_width[idx]=" << mux_width[idx] << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate the mux width from the map, the mex_map values
|
|
||||||
are from the top level and are more reliable. */
|
|
||||||
if (map_width > mux_width)
|
|
||||||
mux_width = map_width;
|
|
||||||
|
|
||||||
/* Collect all the statements into a map of index to
|
/* Collect all the statements into a map of index to
|
||||||
statement. The guard expression it evaluated to be the
|
statement. The guard expression it evaluated to be the
|
||||||
|
|
@ -230,6 +230,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
max_guard_value = sel_idx;
|
max_guard_value = sel_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The mux_size is the number of inputs that are selected.
|
||||||
unsigned mux_size = max_guard_value + 1;
|
unsigned mux_size = max_guard_value + 1;
|
||||||
|
|
||||||
// If the sel_width can select more than just the explicit
|
// If the sel_width can select more than just the explicit
|
||||||
|
|
@ -240,48 +241,59 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
/* If there is a default clause, synthesize is once and we'll
|
||||||
mux_width, mux_size, sel_width);
|
link it in wherever it is needed. */
|
||||||
des->add_node(mux);
|
NetBus default_bus (scope, nex_map.size());
|
||||||
|
vector<NetNet*>default_sig (nex_map.size());
|
||||||
|
|
||||||
/* The select signal is already synthesized. Simply hook it up. */
|
if (statement_default) {
|
||||||
connect(mux->pin_Sel(), esig->pin(0));
|
|
||||||
|
|
||||||
/* For now, assume that the output is only 1 signal. */
|
statement_default->synth_async(des, scope, nex_map, default_bus);
|
||||||
ivl_assert(*this, nex_out.pin_count() == 1);
|
|
||||||
connect(mux->pin_Result(), nex_out.pin(0));
|
|
||||||
|
|
||||||
/* Make sure the output is already connected to a net. */
|
// Get the signal from the synthesized statement. This
|
||||||
if (mux->pin_Result().nexus()->pick_any_net() == 0) {
|
// will be hooked to all the default cases.
|
||||||
|
ivl_assert(*this, default_bus.pin_count()==1);
|
||||||
|
default_sig[0] = default_bus.pin(0).nexus()->pick_any_net();
|
||||||
|
ivl_assert(*this, default_sig[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<NetMux*> mux (mux_width.size());
|
||||||
|
for (size_t mdx = 0 ; mdx < mux_width.size() ; mdx += 1) {
|
||||||
|
mux[mdx] = new NetMux(scope, scope->local_symbol(),
|
||||||
|
mux_width[mdx], mux_size, sel_width);
|
||||||
|
des->add_node(mux[mdx]);
|
||||||
|
|
||||||
|
// The select signal is already synthesized, and is
|
||||||
|
// common for every mux of this case statement. Simply
|
||||||
|
// hook it up.
|
||||||
|
connect(mux[mdx]->pin_Sel(), esig->pin(0));
|
||||||
|
|
||||||
|
// The outputs are in the nex_out, and connected to the
|
||||||
|
// mux Result pins.
|
||||||
|
connect(mux[mdx]->pin_Result(), nex_out.pin(mdx));
|
||||||
|
|
||||||
|
// Make sure the output is now connected to a net. If
|
||||||
|
// not, then create a fake one to carry the net-ness of
|
||||||
|
// the pin.
|
||||||
|
if (mux[mdx]->pin_Result().nexus()->pick_any_net() == 0) {
|
||||||
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
|
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
|
||||||
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width-1, 0);
|
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0);
|
||||||
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
||||||
NetNet::TRI, tmp_vec);
|
NetNet::TRI, tmp_vec);
|
||||||
tmp->local_flag(true);
|
tmp->local_flag(true);
|
||||||
ivl_assert(*this, tmp->vector_width() != 0);
|
ivl_assert(*this, tmp->vector_width() != 0);
|
||||||
connect(mux->pin_Result(), tmp->pin(0));
|
connect(mux[mdx]->pin_Result(), tmp->pin(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there is a default clause, synthesize is once and we'll
|
|
||||||
link it in wherever it is needed. */
|
|
||||||
NetNet*default_sig = 0;
|
|
||||||
if (statement_default) {
|
|
||||||
|
|
||||||
NetBus tmp (scope, nex_map.size());
|
|
||||||
statement_default->synth_async(des, scope, nex_map, tmp);
|
|
||||||
|
|
||||||
// Get the signal from the synthesized statement. This
|
|
||||||
// will be hooked to all the default cases.
|
|
||||||
ivl_assert(*this, tmp.pin_count()==1);
|
|
||||||
default_sig = tmp.pin(0).nexus()->pick_any_net();
|
|
||||||
ivl_assert(*this, default_sig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
|
for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
|
||||||
|
|
||||||
NetProc*stmt = statement_map[idx];
|
NetProc*stmt = statement_map[idx];
|
||||||
if (stmt==0 && default_sig!=0) {
|
if (stmt==0 && statement_default) {
|
||||||
connect(mux->pin_Data(idx), default_sig->pin(0));
|
ivl_assert(*this, default_sig.size() == mux.size());
|
||||||
|
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1)
|
||||||
|
connect(mux[mdx]->pin_Data(idx), default_sig[mdx]->pin(0));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stmt == 0) {
|
if (stmt == 0) {
|
||||||
|
|
@ -294,9 +306,24 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
NetBus tmp (scope, nex_map.size());
|
NetBus tmp (scope, nex_map.size());
|
||||||
stmt->synth_async(des, scope, nex_map, tmp);
|
stmt->synth_async(des, scope, nex_map, tmp);
|
||||||
|
|
||||||
ivl_assert(*this, tmp.pin_count()==1);
|
ivl_assert(*this, tmp.pin_count() == mux.size());
|
||||||
connect(mux->pin_Data(idx), tmp.pin(0));
|
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) {
|
||||||
ivl_assert(*this, mux->pin_Data(idx).nexus()->pick_any_net());
|
connect(mux[mdx]->pin_Data(idx), tmp.pin(mdx));
|
||||||
|
|
||||||
|
if (mux[mdx]->pin_Data(idx).nexus()->pick_any_net()==0) {
|
||||||
|
cerr << get_fileline() << ": warning: case " << idx
|
||||||
|
<< " has no input for mux " << mdx << "." << endl;
|
||||||
|
|
||||||
|
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
|
||||||
|
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0);
|
||||||
|
NetNet*tmpn = new NetNet(scope, scope->local_symbol(),
|
||||||
|
NetNet::TRI, tmp_vec);
|
||||||
|
tmpn->local_flag(true);
|
||||||
|
ivl_assert(*this, tmpn->vector_width() != 0);
|
||||||
|
connect(mux[mdx]->pin_Data(idx), tmpn->pin(0));
|
||||||
|
}
|
||||||
|
ivl_assert(*this, mux[mdx]->pin_Data(idx).nexus()->pick_any_net());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -842,15 +869,16 @@ bool NetProcTop::synth_sync(Design*des)
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||||
|
|
||||||
|
ivl_assert(*this, nex_set[idx].nex);
|
||||||
if (debug_synth2) {
|
if (debug_synth2) {
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
<< "Top level making a "
|
<< "Top level making a "
|
||||||
<< nex_set[idx].nex->vector_width() << "-wide "
|
<< nex_set[idx].wid << "-wide "
|
||||||
<< "NetFF device." << endl;
|
<< "NetFF device." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
||||||
nex_set[idx].nex->vector_width());
|
nex_set[idx].wid);
|
||||||
des->add_node(ff2);
|
des->add_node(ff2);
|
||||||
ff2->set_line(*this);
|
ff2->set_line(*this);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue