From 4e81939eda43deba94ee1a028cf7a99eb04c40ae Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Feb 2014 14:16:22 -0800 Subject: [PATCH 1/4] Handle asynchronous if-without-else synthesis. --- elaborate.cc | 4 +- expr_synth.cc | 2 +- net_link.cc | 31 +++++++------ netlist.h | 63 +++++++++++++++++--------- synth2.cc | 122 +++++++++++++++++++++++++++++++++----------------- 5 files changed, 144 insertions(+), 78 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index a1567ea74..66f346853 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4029,7 +4029,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, ev, NetEvProbe::ANYEDGE, nset->size()); for (unsigned idx = 0 ; idx < nset->size() ; idx += 1) - connect(nset->at(idx).nex, pr->pin(idx)); + connect(nset->at(idx).lnk, pr->pin(idx)); delete nset; des->add_node(pr); @@ -4303,7 +4303,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope, wait_event, NetEvProbe::ANYEDGE, wait_set->size()); for (unsigned idx = 0; idx < wait_set->size() ; idx += 1) - connect(wait_set->at(idx).nex, wait_pr->pin(idx)); + connect(wait_set->at(idx).lnk, wait_pr->pin(idx)); delete wait_set; des->add_node(wait_pr); diff --git a/expr_synth.cc b/expr_synth.cc index 6b4085de4..89242ec9b 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -1319,7 +1319,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root) nset->size()); pr->set_line(*root); for (unsigned idx = 0 ; idx < nset->size() ; idx += 1) - connect(nset->at(idx).nex, pr->pin(idx)); + connect(nset->at(idx).lnk, pr->pin(idx)); des->add_node(pr); diff --git a/net_link.cc b/net_link.cc index 20e18809f..7552a9693 100644 --- a/net_link.cc +++ b/net_link.cc @@ -524,6 +524,8 @@ NexusSet::NexusSet() NexusSet::~NexusSet() { + for (size_t idx = 0 ; idx < items_.size() ; idx += 1) + delete items_[idx]; } size_t NexusSet::size() const @@ -534,7 +536,7 @@ size_t NexusSet::size() const void NexusSet::add(Nexus*that, unsigned base, unsigned wid) { assert(that); - elem_t cur (that, base, wid); + elem_t*cur = new elem_t(that, base, wid); if (items_.size() == 0) { items_.resize(1); @@ -542,8 +544,9 @@ void NexusSet::add(Nexus*that, unsigned base, unsigned wid) return; } - unsigned ptr = bsearch_(cur); + unsigned ptr = bsearch_(*cur); if (ptr < items_.size()) { + delete cur; return; } @@ -552,26 +555,28 @@ void NexusSet::add(Nexus*that, unsigned base, unsigned wid) items_.push_back(cur); } -void NexusSet::add(const NexusSet&that) +void NexusSet::add(NexusSet&that) { for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) - add(that.items_[idx].nex, that.items_[idx].base, that.items_[idx].wid); + add(that.items_[idx]->lnk.nexus(), that.items_[idx]->base, that.items_[idx]->wid); } -void NexusSet::rem_(const NexusSet::elem_t&that) +void NexusSet::rem_(const NexusSet::elem_t*that) { if (items_.empty()) return; - unsigned ptr = bsearch_(that); + unsigned ptr = bsearch_(*that); if (ptr >= items_.size()) return; if (items_.size() == 1) { + delete items_[0]; items_.clear(); return; } + delete items_[ptr]; for (unsigned idx = ptr ; idx < (items_.size()-1) ; idx += 1) items_[idx] = items_[idx+1]; @@ -589,16 +594,16 @@ unsigned NexusSet::find_nexus(const NexusSet::elem_t&that) const return bsearch_(that); } -const NexusSet::elem_t& NexusSet::at (unsigned idx) const +NexusSet::elem_t& NexusSet::at (unsigned idx) { assert(idx < items_.size()); - return items_[idx]; + return *items_[idx]; } size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const { for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) { - if (items_[idx]==that) + if (*items_[idx] == that) return idx; } @@ -607,7 +612,7 @@ size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const bool NexusSet::elem_t::contains(const struct elem_t&that) const { - if (nex != that.nex) + if (! lnk.is_linked(that.lnk)) return false; if (that.base < base) return false; @@ -620,7 +625,7 @@ bool NexusSet::elem_t::contains(const struct elem_t&that) const bool NexusSet::contains_(const NexusSet::elem_t&that) const { for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) { - if (items_[idx].contains(that)) + if (items_[idx]->contains(that)) return true; } return false; @@ -629,7 +634,7 @@ bool NexusSet::contains_(const NexusSet::elem_t&that) const bool NexusSet::contains(const NexusSet&that) const { for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) { - if (! contains_(that.items_[idx])) + if (! contains_(*that.items_[idx])) return false; } @@ -639,7 +644,7 @@ bool NexusSet::contains(const NexusSet&that) const bool NexusSet::intersect(const NexusSet&that) const { for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) { - size_t where = bsearch_(that.items_[idx]); + size_t where = bsearch_(*that.items_[idx]); if (where == items_.size()) continue; diff --git a/netlist.h b/netlist.h index 577036428..6cefc4c15 100644 --- a/netlist.h +++ b/netlist.h @@ -96,6 +96,7 @@ class Link { friend void connect(Link&, Link&); friend class NetPins; friend class Nexus; + friend class NexusSet; public: enum DIR { PASSIVE, INPUT, OUTPUT }; @@ -409,17 +410,25 @@ 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) { } + : base(b), wid(w) + { + lnk.set_dir(Link::PASSIVE); + n->connect(lnk); + } + inline elem_t() : base(0), wid(0) + { + } inline bool operator == (const struct elem_t&that) const - { return nex==that.nex && base==that.base && wid==that.wid; } + { return lnk.is_linked(that.lnk) && base==that.base && wid==that.wid; } bool contains(const struct elem_t&that) const; - Nexus*nex; + Link lnk; unsigned base; unsigned wid; + private: + elem_t(const elem_t&); + elem_t& operator= (elem_t&); }; public: @@ -430,15 +439,15 @@ class NexusSet { // Add the nexus/part to the set, if it is not already present. void add(Nexus*that, unsigned base, unsigned wid); - void add(const NexusSet&that); + void add(NexusSet&that); // Remove the nexus from the set, if it is present. void rem(const NexusSet&that); unsigned find_nexus(const elem_t&that) const; - const elem_t& at(unsigned idx) const; - inline const elem_t& operator[] (unsigned idx) const { return at(idx); } + elem_t& at(unsigned idx); + inline elem_t& operator[] (unsigned idx) { 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 @@ -450,11 +459,11 @@ class NexusSet { private: // NexSet items are canonical part selects of vectors. - std::vector items_; + std::vector items_; size_t bsearch_(const struct elem_t&that) const; - void rem_(const struct elem_t&that); - bool contains_(const elem_t&htat) const; + void rem_(const struct elem_t*that); + bool contains_(const elem_t&that) const; private: // not implemented NexusSet(const NexusSet&); @@ -2493,9 +2502,14 @@ class NetProc : public virtual LineInfo { // process. Most process types are not. virtual bool is_synchronous(); - // Synthesize as asynchronous logic, and return true. + // Synthesize as asynchronous logic, and return true. The + // nex_out is where this function attaches its output + // results. The accumulated_nex_out is used by sequential + // blocks to show outputs from the previous code. virtual bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, + NetBus&nex_out, + NetBus&accumulated_nex_out); // Synthesize as synchronous logic, and return true. That // means binding the outputs to the data port of a FF, and the @@ -2511,7 +2525,7 @@ class NetProc : public virtual LineInfo { // the flipflop being generated. virtual bool synth_sync(Design*des, NetScope*scope, NetNet*ff_clock, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const std::vector&events); virtual void dump(ostream&, unsigned ind) const; @@ -2695,7 +2709,8 @@ class NetAssignBase : public NetProc { unsigned lwidth() const; bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); // This dumps all the lval structures. void dump_lval(ostream&) const; @@ -2780,11 +2795,12 @@ class NetBlock : public NetProc { // synthesize as asynchronous logic, and return true. bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); bool synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const std::vector&events); // This version of emit_recurse scans all the statements of @@ -2837,7 +2853,8 @@ class NetCase : public NetProc { virtual void nex_output(NexusSet&out); bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; @@ -2912,11 +2929,12 @@ class NetCondit : public NetProc { bool is_asynchronous(); bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); bool synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const std::vector&events); virtual bool emit_proc(struct target_t*) const; @@ -3187,11 +3205,12 @@ class NetEvWait : public NetProc { virtual void nex_output(NexusSet&out); virtual bool synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out); + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out); virtual bool synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const std::vector&events); virtual void dump(ostream&, unsigned ind) const; diff --git a/synth2.cc b/synth2.cc index e456a0eb9..7b15d2ca6 100644 --- a/synth2.cc +++ b/synth2.cc @@ -28,14 +28,14 @@ using namespace std; -bool NetProc::synth_async(Design*, NetScope*, const NexusSet&, NetBus&) +bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&) { return false; } bool NetProc::synth_sync(Design*des, NetScope*scope, NetNet* /* ff_clk */, NetNet* /* ff_ce */, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const vector&events) { if (events.size() > 0) { @@ -45,7 +45,8 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, } /* Synthesize the input to the DFF. */ - return synth_async(des, scope, nex_map, nex_out); + NetBus accumulated_nex_out (scope, nex_out.pin_count()); + return synth_async(des, scope, nex_map, nex_out, accumulated_nex_out); } @@ -60,7 +61,8 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, * r-value. */ bool NetAssignBase::synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out) + NexusSet&nex_map, NetBus&nex_out, + NetBus&) { NetNet*rsig = rval_->synthesize(des, scope, rval_); assert(rsig); @@ -138,7 +140,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, * substatements. */ bool NetBlock::synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out) + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out) { if (last_ == 0) { return true; @@ -158,30 +161,48 @@ bool NetBlock::synth_async(Design*des, NetScope*scope, output from the synthesis. */ NetBus tmp_out (scope, tmp_map.size()); - bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out); + // Map (and move) the accumulated_nex_out for this block + // to the version that we can pass to the next + // statement. We will move the result back later. + NetBus accumulated_tmp_out (scope, tmp_map.size()); + + for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) { + unsigned ptr = tmp_map.find_nexus(nex_map[idx]); + if (ptr >= tmp_map.size()) + continue; + + connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx)); + accumulated_nex_out.pin(idx).unlink(); + } + + bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out); flag = flag && ok_flag; if (ok_flag == false) continue; - /* Now find the tmp_map pins in the nex_map global map, - and use that to direct the connection to the nex_out - output bus. Look for the nex_map pin that is linked - to the tmp_map.pin(idx) pin, and link that to the - tmp_out.pin(idx) output link. */ + // Now map the output from the substatement back to the + // accumulated_nex_out for this block. Look for the + // nex_map pin that is linked to the tmp_map.pin(idx) + // pin, and link that to the tmp_out.pin(idx) output link. for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { unsigned ptr = nex_map.find_nexus(tmp_map[idx]); - ivl_assert(*this, ptr < nex_out.pin_count()); - connect(nex_out.pin(ptr), tmp_out.pin(idx)); + ivl_assert(*this, ptr < accumulated_nex_out.pin_count()); + connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx)); } } while (cur != last_); + // The output from the block is now the accumulated outputs. + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) + connect(nex_out.pin(idx), accumulated_nex_out.pin(idx)); + return flag; } bool NetCase::synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out) + NexusSet&nex_map, NetBus&nex_out, + NetBus&) { /* Synthesize the select expression. */ NetNet*esig = expr_->synthesize(des, scope, expr_); @@ -248,7 +269,8 @@ bool NetCase::synth_async(Design*des, NetScope*scope, if (statement_default) { - statement_default->synth_async(des, scope, nex_map, default_bus); + NetBus tmp (scope, nex_out.pin_count()); + statement_default->synth_async(des, scope, nex_map, default_bus, tmp); // Get the signal from the synthesized statement. This // will be hooked to all the default cases. @@ -304,7 +326,8 @@ bool NetCase::synth_async(Design*des, NetScope*scope, } NetBus tmp (scope, nex_map.size()); - stmt->synth_async(des, scope, nex_map, tmp); + NetBus accumulated_tmp (scope, nex_map.size()); + stmt->synth_async(des, scope, nex_map, tmp, accumulated_tmp); ivl_assert(*this, tmp.pin_count() == mux.size()); for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) { @@ -329,20 +352,27 @@ bool NetCase::synth_async(Design*des, NetScope*scope, return true; } +/* + * A condit statement (if (cond) ... else ... ;) infers an A-B mux, + * with the cond expression acting as a select input. If the cond + * expression is true, the if_ clause is selected, and if false, the + * else_ clause is selected. + */ bool NetCondit::synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out) + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out) { if (if_ == 0) { return false; } if (else_ == 0) { - cerr << get_fileline() << ": error: Asynchronous if statement" - << " is missing the else clause." << endl; - return false; + cerr << get_fileline() << ": warning: Asynchronous if statement" + << " is missing the else clause, and I" << endl; + cerr << get_fileline() << ": : don't know how to check" + << " for latches yet." << endl; } - assert(if_ != 0); - assert(else_ != 0); + ivl_assert(*this, if_ != 0); // Synthesize the condition. This will act as a select signal // for a binary mux. @@ -351,15 +381,24 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, bool flag; NetBus asig(scope, nex_out.pin_count()); - flag = if_->synth_async(des, scope, nex_map, asig); + NetBus atmp(scope, nex_out.pin_count()); + flag = if_->synth_async(des, scope, nex_map, asig, atmp); if (!flag) { return false; } + NetBus btmp(scope, nex_out.pin_count()); NetBus bsig(scope, nex_out.pin_count()); - flag = else_->synth_async(des, scope, nex_map, bsig); - if (!flag) { - return false; + if (else_) { + flag = else_->synth_async(des, scope, nex_map, bsig, btmp); + if (!flag) { + return false; + } + } else { + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + connect(bsig.pin(idx), accumulated_nex_out.pin(idx)); + accumulated_nex_out.pin(idx).unlink(); + } } ivl_assert(*this, nex_out.pin_count()==asig.pin_count()); @@ -405,9 +444,10 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, } bool NetEvWait::synth_async(Design*des, NetScope*scope, - const NexusSet&nex_map, NetBus&nex_out) + NexusSet&nex_map, NetBus&nex_out, + NetBus&accumulated_nex_out) { - bool flag = statement_->synth_async(des, scope, nex_map, nex_out); + bool flag = statement_->synth_async(des, scope, nex_map, nex_out, accumulated_nex_out); return flag; } @@ -431,11 +471,11 @@ bool NetProcTop::synth_async(Design*des) NetBus nex_q (scope(), nex_set.size()); for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) { - const NexusSet::elem_t&item = nex_set[idx]; - if (item.base != 0 || item.wid!=item.nex->vector_width()) { + NexusSet::elem_t&item = nex_set[idx]; + if (item.base != 0 || item.wid!=item.lnk.nexus()->vector_width()) { ivl_variable_type_t tmp_data_type = IVL_VT_LOGIC; listnot_an_array; - netvector_t*tmp_type = new netvector_t(tmp_data_type, item.nex->vector_width()-1,0); + netvector_t*tmp_type = new netvector_t(tmp_data_type, item.lnk.nexus()->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); @@ -445,14 +485,15 @@ bool NetProcTop::synth_async(Design*des) des->add_node(tmp); tmp->set_line(*this); connect(tmp->pin(0), nex_q.pin(idx)); - connect(item.nex, tmp_sig->pin(0)); + connect(item.lnk, tmp_sig->pin(0)); } else { - connect(item.nex, nex_q.pin(idx)); + connect(item.lnk, nex_q.pin(idx)); } } - bool flag = statement_->synth_async(des, scope(), nex_set, nex_q); + NetBus tmp_q (scope(), nex_set.size()); + bool flag = statement_->synth_async(des, scope(), nex_set, nex_q, tmp_q); return flag; } @@ -472,7 +513,7 @@ bool NetProcTop::synth_async(Design*des) */ bool NetBlock::synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { bool flag = true; @@ -531,7 +572,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope, */ bool NetCondit::synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { /* First try to turn the condition expression into an @@ -689,7 +730,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, /* If this is an if/then/else, then it is likely a combinational if, and I should synthesize it that way. */ if (if_ && else_) { - bool flag = synth_async(des, scope, nex_map, nex_out); + NetBus tmp (scope, nex_out.pin_count()); + bool flag = synth_async(des, scope, nex_map, nex_out, tmp); return flag; } @@ -740,7 +782,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetNet*ff_clk, NetNet*ff_ce, - const NexusSet&nex_map, NetBus&nex_out, + NexusSet&nex_map, NetBus&nex_out, const vector&events_in) { if (events_in.size() > 0) { @@ -853,7 +895,7 @@ bool NetProcTop::synth_sync(Design*des) pass the nex_q as a map to the statement's synth_sync method to map it to the correct nex_d pin. */ for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) { - connect(nex_set[idx].nex, nex_q.pin(idx)); + connect(nex_set[idx].lnk, nex_q.pin(idx)); } // Connect the input later. @@ -869,7 +911,7 @@ bool NetProcTop::synth_sync(Design*des) for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) { - ivl_assert(*this, nex_set[idx].nex); + //ivl_assert(*this, nex_set[idx].nex); if (debug_synth2) { cerr << get_fileline() << ": debug: " << "Top level making a " From 6b6574dd8a741fdc6bd3962ba06d9caba341a23b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Feb 2014 14:44:15 -0800 Subject: [PATCH 2/4] sizer support for simple LPM MUX devices. --- tgt-sizer/scan_lpms.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tgt-sizer/scan_lpms.cc b/tgt-sizer/scan_lpms.cc index 4d23a8f40..6298d1275 100644 --- a/tgt-sizer/scan_lpms.cc +++ b/tgt-sizer/scan_lpms.cc @@ -46,6 +46,21 @@ static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&s stats.gate_count += 2*wid; } +/* + * Count mux devices as 2m gates. + */ +static void scan_lpms_mux(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats) +{ + // For now, don't generate statistics for wide mux devices. + if (ivl_lpm_size(lpm) > 2) { + stats.lpm_bytype[ivl_lpm_type(lpm)] += 1; + return; + } + + unsigned wid = ivl_lpm_width(lpm); + stats.gate_count += 2*wid; +} + void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats) { for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) { @@ -70,6 +85,10 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats) scan_lpms_ff(scope, lpm, stats); break; + case IVL_LPM_MUX: + scan_lpms_mux(scope, lpm, stats); + break; + default: stats.lpm_bytype[ivl_lpm_type(lpm)] += 1; break; From 463407572fbace59889568b816138631aa5d66e7 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Feb 2014 14:44:55 -0800 Subject: [PATCH 3/4] Sizer pay attention to ivl_synthesis_off attribute. --- tgt-sizer/sizer.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tgt-sizer/sizer.cc b/tgt-sizer/sizer.cc index 5eb17f343..2c985dd3a 100644 --- a/tgt-sizer/sizer.cc +++ b/tgt-sizer/sizer.cc @@ -116,6 +116,15 @@ int target_design(ivl_design_t des) */ static int process_scan_fun(ivl_process_t net, void* /*raw*/) { + for (unsigned idx = 0 ; idx < ivl_process_attr_cnt(net) ; idx += 1) { + ivl_attribute_t att = ivl_process_attr_val(net, idx); + + // If synthesis is explicitly turned off for this + // process, then we just ignore it. + if (strcmp(att->key, "ivl_synthesis_off") == 0) + return 0; + } + fprintf(stderr, "%s:%u: SIZER: Processes not synthesized for statistics.\n", ivl_process_file(net), ivl_process_lineno(net)); sizer_errors += 1; @@ -124,6 +133,7 @@ static int process_scan_fun(ivl_process_t net, void* /*raw*/) static void emit_sizer_scope(ivl_design_t des, ivl_scope_t scope, struct sizer_statistics&stats) { + fprintf(sizer_out, "**** module/scope: %s\n", ivl_scope_name(scope)); scan_logs(scope, stats); From f43080fbcb1182d56aec54ffd8452b3a53eb050f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Feb 2014 14:54:58 -0800 Subject: [PATCH 4/4] Detect proper support for missing else_ without latches (synthesis) --- synth2.cc | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/synth2.cc b/synth2.cc index 7b15d2ca6..b6dd772cf 100644 --- a/synth2.cc +++ b/synth2.cc @@ -366,10 +366,17 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, return false; } if (else_ == 0) { - cerr << get_fileline() << ": warning: Asynchronous if statement" - << " is missing the else clause, and I" << endl; - cerr << get_fileline() << ": : don't know how to check" - << " for latches yet." << endl; + bool latch_flag = false; + for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { + if (! accumulated_nex_out.pin(idx).is_linked()) + latch_flag = true; + } + if (latch_flag) { + cerr << get_fileline() << ": error: Asynchronous if statement" + << " cannot synthesize missing \"else\"" + << " without generating latches." << endl; + return false; + } } ivl_assert(*this, if_ != 0); @@ -389,16 +396,17 @@ bool NetCondit::synth_async(Design*des, NetScope*scope, NetBus btmp(scope, nex_out.pin_count()); NetBus bsig(scope, nex_out.pin_count()); - if (else_) { - flag = else_->synth_async(des, scope, nex_map, bsig, btmp); - if (!flag) { - return false; - } - } else { + + if (else_==0) { for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) { connect(bsig.pin(idx), accumulated_nex_out.pin(idx)); accumulated_nex_out.pin(idx).unlink(); } + } else { + flag = else_->synth_async(des, scope, nex_map, bsig, btmp); + if (!flag) { + return false; + } } ivl_assert(*this, nex_out.pin_count()==asig.pin_count());