Handle synthesis l-values that are part selects.

This commit is contained in:
Stephen Williams 2013-09-08 18:18:31 -07:00
parent 64b2345cf2
commit 7d6d93e4e2
8 changed files with 261 additions and 153 deletions

View File

@ -3850,7 +3850,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
return enet; return enet;
} }
if (nset->count() == 0) { if (nset->size() == 0) {
cerr << get_fileline() << ": warning: @* found no " cerr << get_fileline() << ": warning: @* found no "
"sensitivities so it will never trigger." "sensitivities so it will never trigger."
<< endl; << endl;
@ -3869,9 +3869,9 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(), NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(),
ev, NetEvProbe::ANYEDGE, ev, NetEvProbe::ANYEDGE,
nset->count()); nset->size());
for (unsigned idx = 0 ; idx < nset->count() ; idx += 1) for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
connect(nset[0][idx], pr->pin(idx)); connect(nset->at(idx).nex, pr->pin(idx));
delete nset; delete nset;
des->add_node(pr); des->add_node(pr);
@ -4134,7 +4134,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
return 0; return 0;
} }
if (wait_set->count() == 0) { if (wait_set->size() == 0) {
cerr << get_fileline() << ": internal error: Empty NexusSet" cerr << get_fileline() << ": internal error: Empty NexusSet"
<< " from wait expression." << endl; << " from wait expression." << endl;
des->errors += 1; des->errors += 1;
@ -4143,9 +4143,9 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
NetEvProbe*wait_pr = new NetEvProbe(scope, scope->local_symbol(), NetEvProbe*wait_pr = new NetEvProbe(scope, scope->local_symbol(),
wait_event, NetEvProbe::ANYEDGE, wait_event, NetEvProbe::ANYEDGE,
wait_set->count()); wait_set->size());
for (unsigned idx = 0; idx < wait_set->count() ; idx += 1) for (unsigned idx = 0; idx < wait_set->size() ; idx += 1)
connect(wait_set[0][idx], wait_pr->pin(idx)); connect(wait_set->at(idx).nex, wait_pr->pin(idx));
delete wait_set; delete wait_set;
des->add_node(wait_pr); des->add_node(wait_pr);

View File

@ -1310,16 +1310,16 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root)
NetEvWait*trigger = 0; NetEvWait*trigger = 0;
NexusSet*nset = root->nex_input(false); NexusSet*nset = root->nex_input(false);
if (nset && (nset->count() > 0)) { if (nset && (nset->size() > 0)) {
NetEvent*ev = new NetEvent(scope->local_symbol()); NetEvent*ev = new NetEvent(scope->local_symbol());
ev->set_line(*root); ev->set_line(*root);
NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(), NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(),
ev, NetEvProbe::ANYEDGE, ev, NetEvProbe::ANYEDGE,
nset->count()); nset->size());
pr->set_line(*root); pr->set_line(*root);
for (unsigned idx = 0 ; idx < nset->count() ; idx += 1) for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
connect(nset[0][idx], pr->pin(idx)); connect(nset->at(idx).nex, pr->pin(idx));
des->add_node(pr); des->add_node(pr);

View File

@ -225,9 +225,10 @@ NexusSet* NetEvent::nex_async_()
return 0; return 0;
} }
for (unsigned idx = 0 ; idx < cur->pin_count() ; idx += 1) for (unsigned idx = 0 ; idx < cur->pin_count() ; idx += 1) {
tmp->add(cur->pin(idx).nexus()); Nexus*nex = cur->pin(idx).nexus();
tmp->add(nex, 0, nex->vector_width());
}
} }
return tmp; return tmp;

View File

@ -523,108 +523,116 @@ const char* Nexus::name() const
NexusSet::NexusSet() NexusSet::NexusSet()
{ {
items_ = 0;
nitems_ = 0;
} }
NexusSet::~NexusSet() NexusSet::~NexusSet()
{ {
if (nitems_ > 0) {
assert(items_ != 0);
free(items_);
} else {
assert(items_ == 0);
}
} }
unsigned NexusSet::count() const size_t NexusSet::size() const
{ {
return nitems_; return items_.size();
} }
void NexusSet::add(Nexus*that) void NexusSet::add(Nexus*that, unsigned base, unsigned wid)
{ {
assert(that); assert(that);
if (nitems_ == 0) { elem_t cur (that, base, wid);
assert(items_ == 0);
items_ = (Nexus**)malloc(sizeof(Nexus*)); if (items_.size() == 0) {
items_[0] = that; items_.resize(1);
nitems_ = 1; items_[0] = cur;
return; return;
} }
unsigned ptr = bsearch_(that); unsigned ptr = bsearch_(cur);
if (ptr < nitems_) { if (ptr < items_.size()) {
assert(items_[ptr] == that);
return; return;
} }
assert(ptr == nitems_); assert(ptr == items_.size());
items_ = (Nexus**)realloc(items_, (nitems_+1) * sizeof(Nexus*)); items_.push_back(cur);
items_[ptr] = that;
nitems_ += 1;
} }
void NexusSet::add(const NexusSet&that) void NexusSet::add(const NexusSet&that)
{ {
for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1)
add(that.items_[idx]); add(that.items_[idx].nex, that.items_[idx].base, that.items_[idx].wid);
} }
void NexusSet::rem(Nexus*that) void NexusSet::rem_(const NexusSet::elem_t&that)
{ {
assert(that); if (items_.empty())
if (nitems_ == 0)
return; return;
unsigned ptr = bsearch_(that); unsigned ptr = bsearch_(that);
if (ptr >= nitems_) if (ptr >= items_.size())
return; return;
if (nitems_ == 1) { if (items_.size() == 1) {
free(items_); items_.clear();
items_ = 0;
nitems_ = 0;
return; return;
} }
for (unsigned idx = ptr ; idx < (nitems_-1) ; idx += 1) for (unsigned idx = ptr ; idx < (items_.size()-1) ; idx += 1)
items_[idx] = items_[idx+1]; items_[idx] = items_[idx+1];
items_ = (Nexus**)realloc(items_, (nitems_-1) * sizeof(Nexus*)); items_.pop_back();
nitems_ -= 1;
} }
void NexusSet::rem(const NexusSet&that) void NexusSet::rem(const NexusSet&that)
{ {
for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1)
rem(that.items_[idx]); rem_(that.items_[idx]);
} }
Nexus* NexusSet::operator[] (unsigned idx) const unsigned NexusSet::find_nexus(const NexusSet::elem_t&that) const
{ {
assert(idx < nitems_); return bsearch_(that);
}
const NexusSet::elem_t& NexusSet::at (unsigned idx) const
{
assert(idx < items_.size());
return items_[idx]; return items_[idx];
} }
unsigned NexusSet::bsearch_(Nexus*that) const size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const
{ {
for (unsigned idx = 0 ; idx < nitems_ ; idx += 1) { for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
if (items_[idx] == that) if (items_[idx]==that)
return idx; return idx;
} }
return nitems_; return items_.size();
}
bool NexusSet::elem_t::contains(const struct elem_t&that) const
{
if (nex != that.nex)
return false;
if (that.base < base)
return false;
if ((that.base+that.wid) > (base+wid))
return false;
return true;
}
bool NexusSet::contains_(const NexusSet::elem_t&that) const
{
for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
if (items_[idx].contains(that))
return true;
}
return false;
} }
bool NexusSet::contains(const NexusSet&that) const bool NexusSet::contains(const NexusSet&that) const
{ {
for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) { for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
unsigned where = bsearch_(that[idx]); if (! contains_(that.items_[idx]))
if (where == nitems_)
return false;
if (items_[where] != that[idx])
return false; return false;
} }
@ -633,11 +641,11 @@ bool NexusSet::contains(const NexusSet&that) const
bool NexusSet::intersect(const NexusSet&that) const bool NexusSet::intersect(const NexusSet&that) const
{ {
for (unsigned idx = 0 ; idx < that.nitems_ ; idx += 1) { for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
unsigned where = bsearch_(that[idx]); size_t where = bsearch_(that.items_[idx]);
if (where == nitems_) if (where == items_.size())
continue; continue;
if (items_[where] == that[idx])
return true; return true;
} }

View File

@ -184,7 +184,7 @@ NexusSet* NetESignal::nex_input(bool rem_out)
} }
} }
for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1) for (unsigned idx = 0 ; idx < net_->pin_count() ; idx += 1)
result->add(net_->pin(idx).nexus()); result->add(net_->pin(idx).nexus(), 0, net_->vector_width());
return result; return result;
} }

View File

@ -36,6 +36,42 @@ void NetProc::nex_output(NexusSet&)
<< endl; << endl;
} }
void NetAssign_::nex_output(NexusSet&out)
{
if (sig_ && !word_) {
Nexus*nex = sig_->pin(0).nexus();
unsigned use_base = 0;
unsigned use_wid = lwidth();
if (base_) {
long tmp = 0;
bool flag = eval_as_long(tmp, base_);
if (!flag) {
// Unable to evaluate the bit/part select of
// the l-value, so this is a mux. Pretty
// sure I don't know how to handle this yet
// in synthesis, so punt for now.
use_base = 0;
use_wid = nex->vector_width();
} else {
use_base = tmp;
}
}
out.add(nex, use_base, use_wid);
} else {
/* Quoting from netlist.h comments for class NetMemory:
* "This is not a node because memory objects can only be
* accessed by behavioral code."
*/
cerr << "?:?" << ": internal error: "
<< "NetAssignBase::nex_output on unsupported lval ";
dump_lval(cerr);
cerr << endl;
}
}
/* /*
* Assignments have as output all the bits of the concatenated signals * Assignments have as output all the bits of the concatenated signals
* of the l-value. * of the l-value.
@ -43,18 +79,7 @@ void NetProc::nex_output(NexusSet&)
void NetAssignBase::nex_output(NexusSet&out) void NetAssignBase::nex_output(NexusSet&out)
{ {
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) {
if (NetNet*lsig = cur->sig()) { cur->nex_output(out);
out.add(lsig->pin(0).nexus());
} else {
/* Quoting from netlist.h comments for class NetMemory:
* "This is not a node because memory objects can only be
* accessed by behavioral code."
*/
cerr << get_fileline() << ": internal error: "
<< "NetAssignBase::nex_output on unsupported lval ";
dump_lval(cerr);
cerr << endl;
}
} }
} }

View File

@ -405,33 +405,55 @@ inline void connect(Nexus*l, Link&r) { l->connect(r); }
class NexusSet { class NexusSet {
public:
struct elem_t {
inline elem_t(Nexus*n, unsigned b, unsigned w)
: nex(n), base(b), wid(w)
{ }
inline elem_t() : nex(0), base(0), wid(0) { }
inline bool operator == (const struct elem_t&that) const
{ return nex==that.nex && base==that.base && wid==that.wid; }
bool contains(const struct elem_t&that) const;
Nexus*nex;
unsigned base;
unsigned wid;
};
public: public:
~NexusSet(); ~NexusSet();
NexusSet(); NexusSet();
unsigned count() const; size_t size() const;
// Add the nexus to the set, if it is not already present. // Add the nexus/part to the set, if it is not already present.
void add(Nexus*that); void add(Nexus*that, unsigned base, unsigned wid);
void add(const NexusSet&that); void add(const NexusSet&that);
// Remove the nexus from the set, if it is present. // Remove the nexus from the set, if it is present.
void rem(Nexus*that);
void rem(const NexusSet&that); void rem(const NexusSet&that);
Nexus* operator[] (unsigned idx) const; unsigned find_nexus(const elem_t&that) const;
// Return true if this set contains every nexus in that set. const elem_t& at(unsigned idx) const;
inline const elem_t& operator[] (unsigned idx) const { return at(idx); }
// Return true if this set contains every nexus/part in that
// set. That means that every bit of that set is accounted for
// this set.
bool contains(const NexusSet&that) const; bool contains(const NexusSet&that) const;
// Return true if this set contains any nexus in that set. // Return true if this set contains any nexus in that set.
bool intersect(const NexusSet&that) const; bool intersect(const NexusSet&that) const;
private: private:
Nexus**items_; // NexSet items are canonical part selects of vectors.
unsigned nitems_; std::vector<struct elem_t> items_;
unsigned bsearch_(Nexus*that) const; size_t bsearch_(const struct elem_t&that) const;
void rem_(const struct elem_t&that);
bool contains_(const elem_t&htat) const;
private: // not implemented private: // not implemented
NexusSet(const NexusSet&); NexusSet(const NexusSet&);
@ -2392,7 +2414,7 @@ class NetProc : public virtual LineInfo {
// Synthesize as asynchronous logic, and return true. // Synthesize as asynchronous logic, and return true.
virtual bool synth_async(Design*des, NetScope*scope, virtual bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
// Synthesize as synchronous logic, and return true. That // Synthesize as synchronous logic, and return true. That
// means binding the outputs to the data port of a FF, and the // means binding the outputs to the data port of a FF, and the
@ -2408,7 +2430,7 @@ class NetProc : public virtual LineInfo {
// the flipflop being generated. // the flipflop being generated.
virtual bool synth_sync(Design*des, NetScope*scope, virtual bool synth_sync(Design*des, NetScope*scope,
NetNet*ff_clock, NetNet*ff_ce, NetNet*ff_clock, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
@ -2530,6 +2552,10 @@ class NetAssign_ {
// expression idx. // expression idx.
NexusSet* nex_input(bool rem_out = true); NexusSet* nex_input(bool rem_out = true);
// Figuring out nex_output to proces ultimately comes down to
// this method.
void nex_output(NexusSet&);
// This pointer is for keeping simple lists. // This pointer is for keeping simple lists.
NetAssign_* more; NetAssign_* more;
@ -2578,7 +2604,7 @@ class NetAssignBase : public NetProc {
unsigned lwidth() const; unsigned lwidth() const;
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
// This dumps all the lval structures. // This dumps all the lval structures.
void dump_lval(ostream&) const; void dump_lval(ostream&) const;
@ -2663,11 +2689,11 @@ class NetBlock : public NetProc {
// synthesize as asynchronous logic, and return true. // synthesize as asynchronous logic, and return true.
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
bool synth_sync(Design*des, NetScope*scope, bool synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
// This version of emit_recurse scans all the statements of // This version of emit_recurse scans all the statements of
@ -2720,7 +2746,7 @@ class NetCase : public NetProc {
virtual void nex_output(NexusSet&out); virtual void nex_output(NexusSet&out);
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;
@ -2795,11 +2821,11 @@ class NetCondit : public NetProc {
bool is_asynchronous(); bool is_asynchronous();
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
bool synth_sync(Design*des, NetScope*scope, bool synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
virtual bool emit_proc(struct target_t*) const; virtual bool emit_proc(struct target_t*) const;
@ -3042,11 +3068,11 @@ class NetEvWait : public NetProc {
virtual void nex_output(NexusSet&out); virtual void nex_output(NexusSet&out);
virtual bool synth_async(Design*des, NetScope*scope, virtual bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NexusSet&nex_map, NetBus&nex_out);
virtual bool synth_sync(Design*des, NetScope*scope, virtual bool synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
virtual void dump(ostream&, unsigned ind) const; virtual void dump(ostream&, unsigned ind) const;

150
synth2.cc
View File

@ -28,14 +28,14 @@
using namespace std; using namespace std;
bool NetProc::synth_async(Design*, NetScope*, const NetBus&, NetBus&) bool NetProc::synth_async(Design*, NetScope*, const NexusSet&, NetBus&)
{ {
return false; return false;
} }
bool NetProc::synth_sync(Design*des, NetScope*scope, bool NetProc::synth_sync(Design*des, NetScope*scope,
NetNet* /* ff_clk */, NetNet* /* ff_ce */, NetNet* /* ff_clk */, NetNet* /* ff_ce */,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events) const vector<NetEvProbe*>&events)
{ {
if (events.size() > 0) { if (events.size() > 0) {
@ -60,7 +60,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope,
* r-value. * r-value.
*/ */
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool NetAssignBase::synth_async(Design*des, NetScope*scope,
const NetBus& /*nex_map*/, NetBus&nex_out) const NexusSet&nex_map, NetBus&nex_out)
{ {
NetNet*rsig = rval_->synthesize(des, scope, rval_); NetNet*rsig = rval_->synthesize(des, scope, rval_);
assert(rsig); assert(rsig);
@ -77,14 +77,48 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
assert(lval_->more == 0); assert(lval_->more == 0);
if (debug_synth2) { if (debug_synth2) {
cerr << get_fileline() << ": debug: l-value signal is " cerr << get_fileline() << ": NetAssignBase::synth_async: "
<< lsig->vector_width() << " bits, r-value signal is " << "l-value signal is " << lsig->vector_width() << " bits, "
<< rsig->vector_width() << " bits." << endl; << "r-value signal is " << rsig->vector_width() << " bits." << endl;
cerr << get_fileline() << ": NetAssignBase::synth_async: "
<< "lval_->lwidth()=" << lval_->lwidth() << endl;
if (const NetExpr*base = lval_->get_base()) {
cerr << get_fileline() << ": NetAssignBase::synth_async: "
<< "base_=" << *base << endl;
}
cerr << get_fileline() << ": NetAssignBase::synth_async: "
<< "nex_map.size()==" << nex_map.size()
<< ", nex_out.pin_count()==" << nex_out.pin_count() << endl;
} }
/* For now, assume there is exactly one output. */ /* For now, assume there is exactly one output. */
assert(nex_out.pin_count() == 1); ivl_assert(*this, nex_out.pin_count() == 1);
#if 0
if (lval_->lwidth() != lsig->vector_width()) {
ivl_assert(*this, lval_->lwidth() < lsig->vector_width());
long base_off = 0;
if (! eval_as_long(base_off, lval_->get_base())) {
assert(0);
}
ivl_assert(*this, base_off >= 0);
ivl_variable_type_t tmp_data_type = rsig->data_type();
list<netrange_t>not_an_array;
netvector_t*tmp_type = new netvector_t(tmp_data_type, lsig->vector_width()-1,0);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, not_an_array, tmp_type);
tmp->local_flag(true);
NetPartSelect*ps = new NetPartSelect(tmp, base_off, lval_->lwidth(), NetPartSelect::PV);
ps->set_line(*this);
des->add_node(ps);
connect(ps->pin(0), rsig->pin(0));
rsig = tmp;
}
#endif
connect(nex_out.pin(0), rsig->pin(0)); connect(nex_out.pin(0), rsig->pin(0));
/* This lval_ represents a reg that is a WIRE in the /* This lval_ represents a reg that is a WIRE in the
@ -104,7 +138,7 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
* substatements. * substatements.
*/ */
bool NetBlock::synth_async(Design*des, NetScope*scope, bool NetBlock::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out) const NexusSet&nex_map, NetBus&nex_out)
{ {
if (last_ == 0) { if (last_ == 0) {
return true; return true;
@ -117,15 +151,12 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
/* Create a temporary map of the output only from this /* Create a temporary map of the output only from this
statement. */ statement. */
NexusSet tmp_set; NexusSet tmp_map;
cur->nex_output(tmp_set); cur->nex_output(tmp_map);
NetBus tmp_map (scope, tmp_set.count());
for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1)
connect(tmp_set[idx], tmp_map.pin(idx));
/* Create also a temporary NetBus to collect the /* Create also a temporary NetBus to collect the
output from the synthesis. */ output from the synthesis. */
NetBus tmp_out (scope, tmp_set.count()); NetBus tmp_out (scope, tmp_map.size());
bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out); bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out);
@ -139,8 +170,8 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
to the tmp_map.pin(idx) pin, and link that to the to the tmp_map.pin(idx) pin, and link that to the
tmp_out.pin(idx) output link. */ tmp_out.pin(idx) output link. */
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = nex_map.find_link(tmp_map.pin(idx)); unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
assert(ptr < nex_out.pin_count()); ivl_assert(*this, ptr < nex_out.pin_count());
connect(nex_out.pin(ptr), tmp_out.pin(idx)); connect(nex_out.pin(ptr), tmp_out.pin(idx));
} }
@ -150,7 +181,7 @@ 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 NexusSet&nex_map, NetBus&nex_out)
{ {
/* Synthesize the select expression. */ /* Synthesize the select expression. */
NetNet*esig = expr_->synthesize(des, scope, expr_); NetNet*esig = expr_->synthesize(des, scope, expr_);
@ -163,8 +194,8 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
mux_width += nex_out.pin(idx).nexus()->vector_width(); mux_width += nex_out.pin(idx).nexus()->vector_width();
unsigned map_width = 0; unsigned map_width = 0;
for (unsigned idx = 0 ; idx < nex_map.pin_count() ; idx += 1) for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1)
map_width += nex_map.pin(idx).nexus()->vector_width(); map_width += nex_map[idx].wid;
/* Calculate the mux width from the map, the mex_map values /* Calculate the mux width from the map, the mex_map values
are from the top level and are more reliable. */ are from the top level and are more reliable. */
@ -217,7 +248,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
connect(mux->pin_Sel(), esig->pin(0)); connect(mux->pin_Sel(), esig->pin(0));
/* For now, assume that the output is only 1 signal. */ /* For now, assume that the output is only 1 signal. */
assert(nex_out.pin_count() == 1); ivl_assert(*this, nex_out.pin_count() == 1);
connect(mux->pin_Result(), nex_out.pin(0)); connect(mux->pin_Result(), nex_out.pin(0));
/* Make sure the output is already connected to a net. */ /* Make sure the output is already connected to a net. */
@ -236,11 +267,12 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
NetNet*default_sig = 0; NetNet*default_sig = 0;
if (statement_default) { if (statement_default) {
NetBus tmp (scope, 1); NetBus tmp (scope, nex_map.size());
statement_default->synth_async(des, scope, tmp, tmp); statement_default->synth_async(des, scope, nex_map, tmp);
// Get the signal from the synthesized statement. This // Get the signal from the synthesized statement. This
// will be hooked to all the default cases. // will be hooked to all the default cases.
ivl_assert(*this, tmp.pin_count()==1);
default_sig = tmp.pin(0).nexus()->pick_any_net(); default_sig = tmp.pin(0).nexus()->pick_any_net();
ivl_assert(*this, default_sig); ivl_assert(*this, default_sig);
} }
@ -259,9 +291,10 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
continue; continue;
} }
NetBus tmp (scope, 1); NetBus tmp (scope, nex_map.size());
stmt->synth_async(des, scope, tmp, tmp); stmt->synth_async(des, scope, nex_map, tmp);
ivl_assert(*this, tmp.pin_count()==1);
connect(mux->pin_Data(idx), tmp.pin(0)); connect(mux->pin_Data(idx), tmp.pin(0));
ivl_assert(*this, mux->pin_Data(idx).nexus()->pick_any_net()); ivl_assert(*this, mux->pin_Data(idx).nexus()->pick_any_net());
} }
@ -270,7 +303,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
} }
bool NetCondit::synth_async(Design*des, NetScope*scope, bool NetCondit::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out) const NexusSet&nex_map, NetBus&nex_out)
{ {
if (if_ == 0) { if (if_ == 0) {
return false; return false;
@ -345,7 +378,7 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
} }
bool NetEvWait::synth_async(Design*des, NetScope*scope, bool NetEvWait::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out) const NexusSet&nex_map, NetBus&nex_out)
{ {
bool flag = statement_->synth_async(des, scope, nex_map, nex_out); bool flag = statement_->synth_async(des, scope, nex_map, nex_out);
return flag; return flag;
@ -365,16 +398,34 @@ bool NetProcTop::synth_async(Design*des)
statement_->nex_output(nex_set); statement_->nex_output(nex_set);
if (debug_synth2) { if (debug_synth2) {
cerr << get_fileline() << ": debug: Process has " cerr << get_fileline() << ": NetProcTop::synth_async: "
<< nex_set.count() << " outputs." << endl; << "Process has " << nex_set.size() << " outputs." << endl;
} }
NetBus nex_q (scope(), nex_set.count()); NetBus nex_q (scope(), nex_set.size());
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) { for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
connect(nex_set[idx], nex_q.pin(idx)); const NexusSet::elem_t&item = nex_set[idx];
if (item.base != 0 || item.wid!=item.nex->vector_width()) {
ivl_variable_type_t tmp_data_type = IVL_VT_LOGIC;
list<netrange_t>not_an_array;
netvector_t*tmp_type = new netvector_t(tmp_data_type, item.nex->vector_width()-1,0);
NetNet*tmp_sig = new NetNet(scope(), scope()->local_symbol(),
NetNet::WIRE, not_an_array, tmp_type);
tmp_sig->local_flag(true);
NetPartSelect*tmp = new NetPartSelect(tmp_sig, item.base,
item.wid, NetPartSelect::PV);
des->add_node(tmp);
tmp->set_line(*this);
connect(tmp->pin(0), nex_q.pin(idx));
connect(item.nex, tmp_sig->pin(0));
} else {
connect(item.nex, nex_q.pin(idx));
}
} }
bool flag = statement_->synth_async(des, scope(), nex_q, nex_q); bool flag = statement_->synth_async(des, scope(), nex_set, nex_q);
return flag; return flag;
} }
@ -394,7 +445,7 @@ bool NetProcTop::synth_async(Design*des)
*/ */
bool NetBlock::synth_sync(Design*des, NetScope*scope, bool NetBlock::synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events_in) const vector<NetEvProbe*>&events_in)
{ {
bool flag = true; bool flag = true;
@ -406,9 +457,6 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
/* Create a temporary nex_map for the substatement. */ /* Create a temporary nex_map for the substatement. */
NexusSet tmp_set; NexusSet tmp_set;
cur->nex_output(tmp_set); cur->nex_output(tmp_set);
NetBus tmp_map (scope, tmp_set.count());
for (unsigned idx = 0 ; idx < tmp_map.pin_count() ; idx += 1)
connect(tmp_set[idx], tmp_map.pin(idx));
/* NOTE: After this point, tmp_set should not be used as /* NOTE: After this point, tmp_set should not be used as
the various functions I call do a lot of connecting, the various functions I call do a lot of connecting,
@ -419,14 +467,14 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
output. The tmp1 and tmp2 map and out sets together output. The tmp1 and tmp2 map and out sets together
are used to collect the outputs from the substatement are used to collect the outputs from the substatement
for the inputs of the FF bank. */ for the inputs of the FF bank. */
NetBus tmp_out (scope, tmp_set.count()); NetBus tmp_out (scope, tmp_set.size());
/* Now go on with the synchronous synthesis for this /* Now go on with the synchronous synthesis for this
subset of the statement. The tmp_map is the output subset of the statement. The tmp_map is the output
nexa that we expect, and the tmp_out is where we want nexa that we expect, and the tmp_out is where we want
those outputs connected. */ those outputs connected. */
bool ok_flag = cur->synth_sync(des, scope, ff_clk, ff_ce, bool ok_flag = cur->synth_sync(des, scope, ff_clk, ff_ce,
tmp_map, tmp_out, events_in); tmp_set, tmp_out, events_in);
flag = flag && ok_flag; flag = flag && ok_flag;
if (ok_flag == false) if (ok_flag == false)
@ -438,7 +486,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
beyond the input set, for example when the l-value of beyond the input set, for example when the l-value of
an assignment is smaller than the r-value. */ an assignment is smaller than the r-value. */
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = nex_map.find_link(tmp_map.pin(idx)); unsigned ptr = nex_map.find_nexus(tmp_set[idx]);
assert(ptr < nex_out.pin_count()); assert(ptr < nex_out.pin_count());
connect(nex_out.pin(ptr), tmp_out.pin(idx)); connect(nex_out.pin(ptr), tmp_out.pin(idx));
} }
@ -456,7 +504,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
*/ */
bool NetCondit::synth_sync(Design*des, NetScope*scope, bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events_in) const vector<NetEvProbe*>&events_in)
{ {
/* First try to turn the condition expression into an /* First try to turn the condition expression into an
@ -470,7 +518,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
NetEvProbe*ev = events_in[idx]; NetEvProbe*ev = events_in[idx];
NexusSet pin_set; NexusSet pin_set;
pin_set.add(ev->pin(0).nexus()); pin_set.add(ev->pin(0).nexus(), 0, 0);
if (! expr_input->contains(pin_set)) if (! expr_input->contains(pin_set))
continue; continue;
@ -665,7 +713,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
bool NetEvWait::synth_sync(Design*des, NetScope*scope, bool NetEvWait::synth_sync(Design*des, NetScope*scope,
NetNet*ff_clk, NetNet*ff_ce, NetNet*ff_clk, NetNet*ff_ce,
const NetBus&nex_map, NetBus&nex_out, const NexusSet&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events_in) const vector<NetEvProbe*>&events_in)
{ {
if (events_in.size() > 0) { if (events_in.size() > 0) {
@ -697,7 +745,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope,
assert(tmp->pin_count() == 1); assert(tmp->pin_count() == 1);
NexusSet tmp_nex; NexusSet tmp_nex;
tmp_nex .add( tmp->pin(0).nexus() ); tmp_nex .add( tmp->pin(0).nexus(), 0, 0 );
if (! statement_input ->contains(tmp_nex)) { if (! statement_input ->contains(tmp_nex)) {
if (pclk != 0) { if (pclk != 0) {
@ -770,39 +818,39 @@ bool NetProcTop::synth_sync(Design*des)
NetNet::TRI, &netvector_t::scalar_logic); NetNet::TRI, &netvector_t::scalar_logic);
ce->local_flag(true); ce->local_flag(true);
NetBus nex_d (scope(), nex_set.count()); NetBus nex_d (scope(), nex_set.size());
NetBus nex_q (scope(), nex_set.count()); NetBus nex_q (scope(), nex_set.size());
/* The Q of the NetFF devices is connected to the output that /* The Q of the NetFF devices is connected to the output that
we are. The nex_q is a bundle of the outputs. We will also we are. The nex_q is a bundle of the outputs. We will also
pass the nex_q as a map to the statement's synth_sync pass the nex_q as a map to the statement's synth_sync
method to map it to the correct nex_d pin. */ method to map it to the correct nex_d pin. */
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) { for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
connect(nex_set[idx], nex_q.pin(idx)); connect(nex_set[idx].nex, nex_q.pin(idx));
} }
// Connect the input later. // Connect the input later.
/* Synthesize the input to the DFF. */ /* Synthesize the input to the DFF. */
bool flag = statement_->synth_sync(des, scope(), clock, ce, bool flag = statement_->synth_sync(des, scope(), clock, ce,
nex_q, nex_d, nex_set, nex_d,
vector<NetEvProbe*>()); vector<NetEvProbe*>());
if (! flag) { if (! flag) {
delete clock; delete clock;
return false; return false;
} }
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) { for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
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]->vector_width() << "-wide " << nex_set[idx].nex->vector_width() << "-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]->vector_width()); nex_set[idx].nex->vector_width());
des->add_node(ff2); des->add_node(ff2);
ff2->set_line(*this); ff2->set_line(*this);