Reorganize signal part select handling, and add support for

indexed part selects.

 Expand expression constant propagation to eliminate extra
 sums in certain cases.
This commit is contained in:
steve 2005-11-10 13:28:11 +00:00
parent bebcc05aab
commit c02b3b8ac6
5 changed files with 398 additions and 172 deletions

29
PExpr.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.h,v 1.71 2005/10/04 04:09:25 steve Exp $"
#ident "$Id: PExpr.h,v 1.72 2005/11/10 13:28:11 steve Exp $"
#endif
# include <string>
@ -256,6 +256,26 @@ class PEIdent : public PExpr {
NetScope*scope,
const NetExpr*par,
NetScope*found) const;
NetExpr*elaborate_expr_net(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_part_(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_idx_up_(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_idx_do_(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
NetExpr*elaborate_expr_net_bit_(Design*des,
NetScope*scope,
NetNet*net,
NetScope*found) const;
hname_t path_;
public:
@ -523,6 +543,13 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.72 2005/11/10 13:28:11 steve
* Reorganize signal part select handling, and add support for
* indexed part selects.
*
* Expand expression constant propagation to eliminate extra
* sums in certain cases.
*
* Revision 1.71 2005/10/04 04:09:25 steve
* Add support for indexed select attached to parameters.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2005 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
@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_expr.cc,v 1.98 2005/10/04 04:09:25 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.99 2005/11/10 13:28:11 steve Exp $"
#endif
# include "config.h"
@ -504,157 +504,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
// If the identifier names a signal (a register or wire)
// then create a NetESignal node to handle it.
if (net != 0) {
if (net != 0)
return elaborate_expr_net(des, scope, net, found_in);
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from
// the foo[msb:lsb] expression in the original.
if (lsb_) {
assert(msb_);
assert(sel_ == SEL_PART);
verinum*lsn = lsb_->eval_const(des, scope);
verinum*msn = msb_->eval_const(des, scope);
if ((lsn == 0) || (msn == 0)) {
cerr << get_line() << ": error: "
"Part select expressions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
assert(lsn);
assert(msn);
/* The indices of part selects are signed
integers, so allow negative values. However,
the width that they represent is
unsigned. Remember that any order is possible,
i.e., [1:0], [-4,6], etc. */
long lsv = lsn->as_long();
long msv = msn->as_long();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->vector_width()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
assert(wid <= net->vector_width());
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of order."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
if (net->sb_to_idx(msv) >= net->vector_width()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range."
<< endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return tmp;
NetExpr*ex = new NetEConst(verinum(net->sb_to_idx(lsv)));
NetESelect*ss = new NetESelect(tmp, ex, wid);
ss->set_line(*this);
return ss;
}
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
verinum*msn;
if (msb_ && (msn = msb_->eval_const(des, scope))) {
assert(idx_ == 0);
long msv = msn->as_long();
unsigned idx = net->sb_to_idx(msv);
if (idx >= net->vector_width()) {
/* The bit select is out of range of the
vector. This is legal, but returns a
constant 1'bx value. */
verinum x (verinum::Vx);
NetEConst*tmp = new NetEConst(x);
tmp->set_line(*this);
cerr << get_line() << ": warning: Bit select ["
<< msv << "] out of range of vector "
<< net->name() << "[" << net->msb()
<< ":" << net->lsb() << "]." << endl;
cerr << get_line() << ": : Replacing "
<< "expression with a constant 1'bx." << endl;
delete msn;
return tmp;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the vector is only one bit, we are done. The
// bit select will return the scaler itself.
if (net->vector_width() == 1)
return tmp;
// Make an expression out of the index
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);
// Make a bit select with the canonical index
NetESelect*res = new NetESelect(tmp, idx_c, 1);
res->set_line(*net);
return res;
}
NetESignal*node = new NetESignal(net);
assert(idx_ == 0);
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
if (msb_) {
NetExpr*ex = msb_->elaborate_expr(des, scope);
if (net->msb() < net->lsb()) {
ex = make_sub_expr(net->lsb(), ex);
} else {
ex = make_add_expr(ex, - net->lsb());
}
NetESelect*ss = new NetESelect(node, ex, 1);
ss->set_line(*this);
return ss;
}
// All else fails, return the signal itself as the
// expression.
assert(msb_ == 0);
return node;
}
// If the identifier names a memory, then this is a
// memory reference and I must generate a NetEMemory
@ -915,6 +767,291 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
return tmp;
}
/*
* Handle part selects of NetNet identifiers.
*/
NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
verinum*lsn = lsb_->eval_const(des, scope);
verinum*msn = msb_->eval_const(des, scope);
if ((lsn == 0) || (msn == 0)) {
cerr << get_line() << ": error: "
"Part select expressions must be "
"constant expressions." << endl;
des->errors += 1;
return 0;
}
assert(lsn);
assert(msn);
/* The indices of part selects are signed integers, so allow
negative values. However, the width that they represent is
unsigned. Remember that any order is possible,
i.e., [1:0], [-4:6], etc. */
long lsv = lsn->as_long();
long msv = msn->as_long();
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
if (wid > net->vector_width()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
assert(wid <= net->vector_width());
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of order." << endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
if (net->sb_to_idx(msv) >= net->vector_width()) {
cerr << get_line() << ": error: part select ["
<< msv << ":" << lsv << "] out of range." << endl;
des->errors += 1;
delete lsn;
delete msn;
return 0;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return tmp;
NetExpr*ex = new NetEConst(verinum(net->sb_to_idx(lsv)));
NetESelect*ss = new NetESelect(tmp, ex, wid);
ss->set_line(*this);
return ss;
}
/*
* Part select indexed up, i.e. net[<m> +: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
NetExpr*base = elab_and_eval(des, scope, msb_);
NetExpr*wid_e = elab_and_eval(des, scope, lsb_);
NetEConst*wid_c = dynamic_cast<NetEConst*> (wid_e);
if (wid_c == 0) {
cerr << get_line() << ": error: Width of indexed part select "
<< "must be constant." << endl;
cerr << get_line() << ": : Width expression is: "
<< *wid_e << endl;
des->errors += 1;
return 0;
}
assert(wid_c != 0);
long wid = wid_c->value().as_long();
// Handle the special case that the base is constant as
// well. In this case it can be converted to a conventional
// part select.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
long lsv = base_c->value().as_long();
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == 0 && wid == net->vector_width())
return sig;
}
NetESelect*ss = new NetESelect(sig, base, wid);
ss->set_line(*this);
if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part "
<< "select base="<< *base << ", wid="<< wid << endl;
}
return ss;
}
/*
* Part select up, i.e. net[<m> +: <l>]
*/
NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in)const
{
assert(lsb_ != 0);
assert(msb_ != 0);
assert(idx_ == 0);
NetESignal*sig = new NetESignal(net);
sig->set_line(*this);
NetExpr*base = elab_and_eval(des, scope, msb_);
NetExpr*wid_e = elab_and_eval(des, scope, lsb_);
NetEConst*wid_c = dynamic_cast<NetEConst*> (wid_e);
if (wid_c == 0) {
cerr << get_line() << ": error: Width of indexed part select "
<< "must be constant." << endl;
cerr << get_line() << ": : Width expression is: "
<< *wid_e << endl;
des->errors += 1;
return 0;
}
assert(wid_c != 0);
long wid = wid_c->value().as_long();
// Handle the special case that the base is constant as
// well. In this case it can be converted to a conventional
// part select.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
long lsv = base_c->value().as_long();
// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (net->sb_to_idx(lsv) == (wid-1) && wid == net->vector_width())
return sig;
}
NetExpr*base_adjusted = wid > 1? make_add_expr(base,1-wid) : base;
NetESelect*ss = new NetESelect(sig, base_adjusted, wid);
ss->set_line(*this);
if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part "
<< "select base="<< *base << ", wid="<< wid << endl;
}
return ss;
}
NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in) const
{
assert(msb_ != 0);
assert(lsb_ == 0);
assert(idx_ == 0);
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
if (verinum*msn = msb_->eval_const(des, scope)) {
long msv = msn->as_long();
unsigned idx = net->sb_to_idx(msv);
if (idx >= net->vector_width()) {
/* The bit select is out of range of the
vector. This is legal, but returns a
constant 1'bx value. */
verinum x (verinum::Vx);
NetEConst*tmp = new NetEConst(x);
tmp->set_line(*this);
cerr << get_line() << ": warning: Bit select ["
<< msv << "] out of range of vector "
<< net->name() << "[" << net->msb()
<< ":" << net->lsb() << "]." << endl;
cerr << get_line() << ": : Replacing "
<< "expression with a constant 1'bx." << endl;
delete msn;
return tmp;
}
NetESignal*tmp = new NetESignal(net);
tmp->set_line(*this);
// If the vector is only one bit, we are done. The
// bit select will return the scaler itself.
if (net->vector_width() == 1)
return tmp;
// Make an expression out of the index
NetEConst*idx_c = new NetEConst(verinum(idx));
idx_c->set_line(*net);
// Make a bit select with the canonical index
NetESelect*res = new NetESelect(tmp, idx_c, 1);
res->set_line(*net);
return res;
}
NetESignal*node = new NetESignal(net);
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
NetExpr*ex = msb_->elaborate_expr(des, scope);
if (net->msb() < net->lsb()) {
ex = make_sub_expr(net->lsb(), ex);
} else {
ex = make_add_expr(ex, - net->lsb());
}
NetESelect*ss = new NetESelect(node, ex, 1);
ss->set_line(*this);
return ss;
}
NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
NetNet*net, NetScope*found_in) const
{
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from
// the foo[msb:lsb] expression in the original.
if (sel_ == SEL_PART)
return elaborate_expr_net_part_(des, scope, net, found_in);
if (sel_ == SEL_BIT)
return elaborate_expr_net_bit_(des, scope, net, found_in);
if (sel_ == SEL_IDX_UP)
return elaborate_expr_net_idx_up_(des, scope, net, found_in);
if (sel_ == SEL_IDX_DO)
return elaborate_expr_net_idx_do_(des, scope, net, found_in);
// It's not anything else, so this must be a simple identifier
// expression with no part or bit select. Return the signal
// itself as the expression.
assert(sel_ == SEL_NONE);
assert(msb_ == 0);
assert(lsb_ == 0);
assert(idx_ == 0);
NetESignal*node = new NetESignal(net);
node->set_line(*this);
return node;
}
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, bool) const
{
assert(value_);
@ -1091,6 +1228,13 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const
/*
* $Log: elab_expr.cc,v $
* Revision 1.99 2005/11/10 13:28:11 steve
* Reorganize signal part select handling, and add support for
* indexed part selects.
*
* Expand expression constant propagation to eliminate extra
* sums in certain cases.
*
* Revision 1.98 2005/10/04 04:09:25 steve
* Add support for indexed select attached to parameters.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elaborate.cc,v 1.330 2005/09/27 04:51:37 steve Exp $"
#ident "$Id: elaborate.cc,v 1.331 2005/11/10 13:28:11 steve Exp $"
#endif
# include "config.h"
@ -587,7 +587,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
if (debug_elaborate) {
cerr << get_line() << ": debug: Instantiate module "
<< rmod->mod_name() << " With instance name "
<< rmod->mod_name() << " with instance name "
<< get_name() << " in scope " << scope->name() << endl;
}
@ -3028,6 +3028,13 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.331 2005/11/10 13:28:11 steve
* Reorganize signal part select handling, and add support for
* indexed part selects.
*
* Expand expression constant propagation to eliminate extra
* sums in certain cases.
*
* Revision 1.330 2005/09/27 04:51:37 steve
* Error message for invalid for-loop index variable.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: eval_tree.cc,v 1.65 2005/09/14 02:53:14 steve Exp $"
#ident "$Id: eval_tree.cc,v 1.66 2005/11/10 13:28:12 steve Exp $"
#endif
# include "config.h"
@ -55,26 +55,64 @@ NetEConst* NetEBAdd::eval_tree()
{
eval_sub_tree_();
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
if (lc == 0) return 0;
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (rc == 0) return 0;
verinum lval = lc->value();
verinum rval = rc->value();
/* If both operands are constant, then replace the entire
expression with a constant value. */
if (lc != 0 && rc != 0) {
verinum lval = lc->value();
verinum rval = rc->value();
verinum val;
switch (op_) {
case '+':
val = lval + rval;
break;
case '-':
val = lval - rval;
break;
default:
verinum val;
switch (op_) {
case '+':
val = lval + rval;
break;
case '-':
val = lval - rval;
break;
default:
return 0;
}
return new NetEConst(val);
}
/* Try to combine a right constant value with the right
constant value of a sub-expression add. For example, the
expression (a + 2) - 1 can be rewritten as a + 1. */
NetEBAdd*se = dynamic_cast<NetEBAdd*>(left_);
lc = se? dynamic_cast<NetEConst*>(se->right_) : 0;
if (lc != 0 && rc != 0) {
assert(se != 0);
verinum lval = lc->value();
verinum rval = rc->value();
verinum val;
if (op_ == se->op_) {
/* (a + lval) + rval --> a + (rval+lval) */
/* (a - lval) - rval --> a - (rval+lval) */
val = rval + lval;
} else {
/* (a - lval) + rval --> a + (rval-lval) */
/* (a + lval) - rval --> a - (rval-lval) */
val = rval - lval;
}
NetEConst*tmp = new NetEConst(val);
left_ = se->left_->dup_expr();
delete se;
delete right_;
right_ = tmp;
/* We've changed the subexpression, but the result is
still not constant, so return nil here anyhow. */
return 0;
}
return new NetEConst(val);
/* Nothing more to be done, the value is not constant. */
return 0;
}
NetEConst* NetEBBits::eval_tree()
@ -1561,6 +1599,13 @@ NetEConst* NetEUReduce::eval_tree()
/*
* $Log: eval_tree.cc,v $
* Revision 1.66 2005/11/10 13:28:12 steve
* Reorganize signal part select handling, and add support for
* indexed part selects.
*
* Expand expression constant propagation to eliminate extra
* sums in certain cases.
*
* Revision 1.65 2005/09/14 02:53:14 steve
* Support bool expressions and compares handle them optimally.
*

View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-2004 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2005 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
@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: parse.y,v 1.206 2005/10/04 04:09:25 steve Exp $"
#ident "$Id: parse.y,v 1.207 2005/11/10 13:28:12 steve Exp $"
#endif
# include "config.h"
@ -985,6 +985,7 @@ expr_primary
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
tmp->msb_ = $3;
tmp->sel_ = PEIdent::SEL_BIT;
delete $1;
$$ = tmp;
}
@ -1455,6 +1456,7 @@ lavalue
} else {
tmp->msb_ = sel;
}
tmp->sel_ = PEIdent::SEL_BIT;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;
@ -1465,6 +1467,7 @@ lavalue
assert($2->count() == 2);
tmp->msb_ = (*$2)[0];
tmp->lsb_ = (*$2)[1];
tmp->sel_ = PEIdent::SEL_PART;
tmp->set_file(@1.text);
tmp->set_lineno(@1.first_line);
delete $1;