Collapse concatenation of constants into concatenated constant.
This commit is contained in:
parent
367d7bf94b
commit
679ef3a380
48
cprop.cc
48
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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<const NetConst*>(cur->get_obj()))) {
|
||||
ivl_assert(*obj, cur->get_pin() == 0);
|
||||
val = obj->value();
|
||||
|
||||
} else if ((sig = dynamic_cast<const NetNet*>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
25
netlist.cc
25
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<NetNet*>&po)
|
||||
: scope_(s), statement_(0), result_sig_(result), ports_(po)
|
||||
{
|
||||
|
|
|
|||
11
netlist.h
11
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_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue