From 679ef3a38018319c59aa2d7c4a4692eb0e1e9151 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 20 Dec 2012 11:02:29 -0800 Subject: [PATCH] Collapse concatenation of constants into concatenated constant. --- cprop.cc | 48 +++++++++++++++++++++++++++++++++++++++++++++--- design_dump.cc | 4 +--- functor.cc | 9 +++++++++ functor.h | 3 +++ link_const.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ netlist.cc | 25 +++---------------------- netlist.h | 11 ++++++----- verinum.cc | 7 +++++++ verinum.h | 1 + 9 files changed, 119 insertions(+), 33 deletions(-) diff --git a/cprop.cc b/cprop.cc index c98041874..a37e66982 100644 --- a/cprop.cc +++ b/cprop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2010,2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -43,12 +43,14 @@ struct cprop_functor : public functor_t { virtual void signal(Design*des, NetNet*obj); virtual void lpm_add_sub(Design*des, NetAddSub*obj); virtual void lpm_compare(Design*des, NetCompare*obj); - virtual void lpm_compare_eq_(Design*des, NetCompare*obj); + virtual void lpm_concat(Design*des, NetConcat*obj); virtual void lpm_ff(Design*des, NetFF*obj); virtual void lpm_logic(Design*des, NetLogic*obj); virtual void lpm_mux(Design*des, NetMux*obj); virtual void lpm_part_select(Design*des, NetPartSelect*obj); -}; + + void lpm_compare_eq_(Design*des, NetCompare*obj); + }; void cprop_functor::signal(Design*, NetNet*) { @@ -76,6 +78,45 @@ void cprop_functor::lpm_compare_eq_(Design*, NetCompare*) { } +void cprop_functor::lpm_concat(Design*des, NetConcat*obj) +{ + verinum result (verinum::Vz, obj->width()); + unsigned off = 0; + + for (unsigned idx = 1 ; idx < obj->pin_count() ; idx += 1) { + Nexus*nex = obj->pin(idx).nexus(); + // If there are non-constant drivers, then give up. + if (! nex->drivers_constant()) + return; + + verinum tmp = nex->driven_vector(); + result.set(off, tmp); + off += tmp.len(); + } + + if (debug_optimizer) + cerr << obj->get_fileline() << ": cprop_functor::lpm_concat: " + << "Replace NetConcat with " << result << "." << endl; + + + NetScope*scope = obj->scope(); + + // Create a NetConst object to carry the result. Give it the + // same name as the Concat object that we are replacing, and + // link the NetConst to the NetConcat object. Then delete the + // concat that is now replaced. + NetConst*result_obj = new NetConst(scope, obj->name(), result); + result_obj->set_line(*obj); + des->add_node(result_obj); + connect(obj->pin(0), result_obj->pin(0)); + + // Note that this will leave the const inputs to dangle. They + // will be reaped by other passes of cprop_functor. + delete obj; + + count += 1; +} + void cprop_functor::lpm_ff(Design*, NetFF*obj) { // Look for and count unlinked FF outputs. Note that if the @@ -256,6 +297,7 @@ void cprop_functor::lpm_part_select(Design*des, NetPartSelect*obj) NetConcat*concat = new NetConcat(scope, scope->local_symbol(), sig_width, part_count); + concat->set_line(*obj); des->add_node(concat); connect(concat->pin(0), obj->pin(1)); diff --git a/design_dump.cc b/design_dump.cc index f47155a27..9ad63954b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -519,9 +519,7 @@ void NetCaseCmp::dump_node(ostream&o, unsigned ind) const void NetConst::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "constant " << width_ << "'b"; - for (unsigned idx = width_ ; idx > 0 ; idx -= 1) - o << value_[idx-1]; + o << setw(ind) << "" << "constant " << value_; o << ": " << name(); if (rise_time()) o << " #(" << *rise_time() diff --git a/functor.cc b/functor.cc index 174aa3627..14a72c613 100644 --- a/functor.cc +++ b/functor.cc @@ -54,6 +54,10 @@ void functor_t::lpm_compare(Design*, NetCompare*) { } +void functor_t::lpm_concat(Design*, NetConcat*) +{ +} + void functor_t::lpm_const(Design*, NetConst*) { } @@ -191,6 +195,11 @@ void NetCompare::functor_node(Design*des, functor_t*fun) fun->lpm_compare(des, this); } +void NetConcat::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_concat(des, this); +} + void NetConst::functor_node(Design*des, functor_t*fun) { fun->lpm_const(des, this); diff --git a/functor.h b/functor.h index 9bd12c843..ea0431c0d 100644 --- a/functor.h +++ b/functor.h @@ -57,6 +57,9 @@ struct functor_t { /* This method is called for each structural comparator. */ virtual void lpm_compare(class Design*des, class NetCompare*); + /* This method is called for each structural concatenation. */ + virtual void lpm_concat(class Design*des, class NetConcat*); + /* This method is called for each structural constant. */ virtual void lpm_const(class Design*des, class NetConst*); diff --git a/link_const.cc b/link_const.cc index 258839bb1..867e71b92 100644 --- a/link_const.cc +++ b/link_const.cc @@ -21,6 +21,7 @@ # include "netlist.h" # include "netmisc.h" +# include "ivl_assert.h" /* * Scan the link for drivers. If there are only constant drivers, then @@ -172,3 +173,46 @@ verinum::V Nexus::driven_value() const return val; } + +verinum Nexus::driven_vector() const +{ + const Link*cur = list_; + + verinum val; + + for (cur = first_nlink() ; cur ; cur = cur->next_nlink()) { + + const NetConst*obj; + const NetNet*sig; + if ((obj = dynamic_cast(cur->get_obj()))) { + ivl_assert(*obj, cur->get_pin() == 0); + val = obj->value(); + + } else if ((sig = dynamic_cast(cur->get_obj()))) { + + // If we find an attached SUPPLY0/1, the we know + // from that what the driven value is. Stop now. + if (sig->type() == NetNet::SUPPLY0) { + driven_ = V0; + return verinum(verinum::V0, sig->vector_width()); + } + if (sig->type() == NetNet::SUPPLY1) { + driven_ = V1; + return verinum(verinum::V1, sig->vector_width()); + } + + // If we find an attached TRI0/1, then this is a + // good guess for the driven value, but keep + // looking for something better. + if (sig->type() == NetNet::TRI0) { + val = verinum(verinum::V0, sig->vector_width()); + } + if (sig->type() == NetNet::TRI1) { + val = verinum(verinum::V1, sig->vector_width()); + } + } + } + + return val; +} + diff --git a/netlist.cc b/netlist.cc index e0715c2f3..cdc76e35b 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2008,46 +2008,27 @@ NetProc* NetCondit::else_clause() } NetConst::NetConst(NetScope*s, perm_string n, verinum::V v) -: NetNode(s, n, 1), width_(1) +: NetNode(s, n, 1), value_(v, 1) { pin(0).set_dir(Link::OUTPUT); - value_ = new verinum::V[1]; - value_[0] = v; - is_string_ = false; } NetConst::NetConst(NetScope*s, perm_string n, const verinum&val) -: NetNode(s, n, 1), width_(val.len()) +: NetNode(s, n, 1), value_(val) { pin(0).set_dir(Link::OUTPUT); - value_ = new verinum::V[width_]; - for (unsigned idx = 0 ; idx < width_ ; idx += 1) { - value_[idx] = val.get(idx); - } - is_string_ = val.is_string(); } NetConst::~NetConst() { - delete[]value_; } verinum::V NetConst::value(unsigned idx) const { - assert(idx < width_); + assert(idx < width()); return value_[idx]; } -unsigned NetConst::width() const -{ - return width_; -} - -bool NetConst::is_string() const -{ - return is_string_; -} - NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const vector&po) : scope_(s), statement_(0), result_sig_(result), ports_(po) { diff --git a/netlist.h b/netlist.h index a22ec4b34..9e1bf3d31 100644 --- a/netlist.h +++ b/netlist.h @@ -379,6 +379,7 @@ class Nexus { /* Given the nexus has constant drivers, this method returns the value that has been driven. */ verinum::V driven_value() const; + verinum driven_vector() const; /* The code generator sets an ivl_nexus_t to attach code generation details to the nexus. */ @@ -1350,6 +1351,7 @@ class NetConcat : public NetNode { void dump_node(ostream&, unsigned ind) const; bool emit_node(struct target_t*) const; + void functor_node(Design*des, functor_t*fun); private: unsigned width_; @@ -2095,18 +2097,17 @@ class NetConst : public NetNode { explicit NetConst(NetScope*s, perm_string n, const verinum&val); ~NetConst(); + inline const verinum&value(void) const { return value_; } verinum::V value(unsigned idx) const; - unsigned width() const; - bool is_string() const; + inline unsigned width() const { return value_.len(); } + inline bool is_string() const { return value_.is_string(); } virtual bool emit_node(struct target_t*) const; virtual void functor_node(Design*, functor_t*); virtual void dump_node(ostream&, unsigned ind) const; private: - unsigned width_; - verinum::V*value_; - bool is_string_; + verinum value_; }; /* diff --git a/verinum.cc b/verinum.cc index 591769d59..685ffb4a7 100644 --- a/verinum.cc +++ b/verinum.cc @@ -367,6 +367,13 @@ verinum::V verinum::set(unsigned idx, verinum::V val) return bits_[idx] = val; } +void verinum::set(unsigned off, const verinum&val) +{ + assert(off + val.len() <= nbits_); + for (unsigned idx = 0 ; idx < val.len() ; idx += 1) + bits_[off+idx] = val[idx]; +} + unsigned long verinum::as_ulong() const { if (nbits_ == 0) diff --git a/verinum.h b/verinum.h index 9119cbb52..f8c5bcc46 100644 --- a/verinum.h +++ b/verinum.h @@ -90,6 +90,7 @@ class verinum { // methods. V get(unsigned idx) const; V set(unsigned idx, V val); + void set(unsigned idx, const verinum&val); V operator[] (unsigned idx) const { return get(idx); }