Collapse concatenation of constants into concatenated constant.

This commit is contained in:
Stephen Williams 2012-12-20 11:02:29 -08:00
parent 367d7bf94b
commit 679ef3a380
9 changed files with 119 additions and 33 deletions

View File

@ -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));

View File

@ -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()

View File

@ -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);

View File

@ -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*);

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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_;
};
/*

View File

@ -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)

View File

@ -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); }