Sanity check to prevent bad code getting through synth2 blending

When conditional ports are blending (by allowing NetPartSelects be
connected together to the outputs) make sure there isn't an accidental
overlap of drivers that invalidates the process.
This commit is contained in:
Stephen Williams 2014-06-02 15:42:02 -07:00
parent 579b59b8eb
commit ded1bd4949
3 changed files with 64 additions and 0 deletions

View File

@ -232,3 +232,58 @@ verinum Nexus::driven_vector() const
return val; return val;
} }
/*
* Calculate a vector that represent all the bits of the vector, with
* each driven bit set to true, otherwise false.
*/
vector<bool> Nexus::driven_mask(void) const
{
vector<bool> mask (vector_width());
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
Link::DIR link_dir = cur->get_dir();
if (link_dir==Link::PASSIVE)
continue;
if (link_dir==Link::INPUT)
continue;
const NetPins*obj = cur->get_obj();
// If the link is to a variable (REG or INTEGER) then
// the variable is driving all the bits. We have our
// complete answer, mark all the bits as driven and
// finish. Otherwise, we are not going to get new
// information from this node, move on.
if (const NetNet*sig = dynamic_cast<const NetNet*> (obj)) {
NetNet::Type sig_type = sig->type();
if (sig_type==NetNet::INTEGER || sig_type==NetNet::REG) {
for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true;
return mask;
}
continue;
}
const NetPartSelect*obj_ps = dynamic_cast<const NetPartSelect*>(obj);
if (obj_ps && obj_ps->dir()==NetPartSelect::VP)
continue;
if (obj_ps && cur->get_pin()!=1)
continue;
if (obj_ps) {
for (unsigned idx = 0 ; idx < obj_ps->width() ; idx += 1) {
size_t bit = idx + obj_ps->base();
ivl_assert(*obj, bit < mask.size());
mask[bit] = true;
}
continue;
}
for (size_t idx = 0 ; idx < mask.size() ; idx += 1)
mask[idx] = true;
return mask;
}
return mask;
}

View File

@ -386,6 +386,11 @@ class Nexus {
verinum::V driven_value() const; verinum::V driven_value() const;
verinum driven_vector() const; verinum driven_vector() const;
/* Return a mask of the bits of this vector that are
driven. This is usually all false or all true, but in
special cases it may be a blend. */
std::vector<bool> driven_mask(void)const;
/* The code generator sets an ivl_nexus_t to attach code /* The code generator sets an ivl_nexus_t to attach code
generation details to the nexus. */ generation details to the nexus. */
ivl_nexus_t t_cookie() const { return t_cookie_; } ivl_nexus_t t_cookie() const { return t_cookie_; }

View File

@ -621,6 +621,10 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
<< "MISSING TEST FOR CORRECTNESS OF THE BLEND!" << "MISSING TEST FOR CORRECTNESS OF THE BLEND!"
<< endl; << endl;
} }
vector<bool>mask = statement_input.pin(idx).nexus()->driven_mask();
for (size_t bit = mux_off ; bit < mux_off+mux_width ; bit += 1) {
ivl_assert(*this, mask[bit]==false);
}
connect(nex_out.pin(idx), statement_input.pin(idx)); connect(nex_out.pin(idx), statement_input.pin(idx));
} }