Add support for indexed select attached to parameters.
This commit is contained in:
parent
16dc3ab4d4
commit
a652719876
7
PExpr.cc
7
PExpr.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: PExpr.cc,v 1.36 2005/08/06 17:58:16 steve Exp $"
|
||||
#ident "$Id: PExpr.cc,v 1.37 2005/10/04 04:09:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -148,7 +148,7 @@ bool PEFNumber::is_constant(Module*) const
|
|||
}
|
||||
|
||||
PEIdent::PEIdent(const hname_t&s)
|
||||
: path_(s), msb_(0), lsb_(0), idx_(0)
|
||||
: path_(s), msb_(0), lsb_(0), sel_(SEL_NONE), idx_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +270,9 @@ bool PEUnary::is_constant(Module*m) const
|
|||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.37 2005/10/04 04:09:25 steve
|
||||
* Add support for indexed select attached to parameters.
|
||||
*
|
||||
* Revision 1.36 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
|
|
|
|||
11
PExpr.h
11
PExpr.h
|
|
@ -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.70 2005/08/06 17:58:16 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.71 2005/10/04 04:09:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
|
@ -252,6 +252,10 @@ class PEIdent : public PExpr {
|
|||
const hname_t& path() const;
|
||||
|
||||
private:
|
||||
NetExpr*elaborate_expr_param(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found) const;
|
||||
hname_t path_;
|
||||
|
||||
public:
|
||||
|
|
@ -259,6 +263,8 @@ class PEIdent : public PExpr {
|
|||
PExpr*msb_;
|
||||
PExpr*lsb_;
|
||||
|
||||
enum { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO } sel_;
|
||||
|
||||
// If this is a reference to a memory, this is the index
|
||||
// expression.
|
||||
PExpr*idx_;
|
||||
|
|
@ -517,6 +523,9 @@ class PECallFunction : public PExpr {
|
|||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.71 2005/10/04 04:09:25 steve
|
||||
* Add support for indexed select attached to parameters.
|
||||
*
|
||||
* Revision 1.70 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
|
|
|
|||
318
elab_expr.cc
318
elab_expr.cc
|
|
@ -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.97 2005/09/19 21:45:35 steve Exp $"
|
||||
#ident "$Id: elab_expr.cc,v 1.98 2005/10/04 04:09:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -498,142 +498,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
// If the identifier name is a parameter name, then return
|
||||
// a reference to the parameter expression.
|
||||
if (par != 0) {
|
||||
NetExpr*tmp;
|
||||
if (par != 0)
|
||||
return elaborate_expr_param(des, scope, par, found_in);
|
||||
|
||||
tmp = par->dup_expr();
|
||||
|
||||
if (msb_ && lsb_) {
|
||||
/* If the parameter has a part select, we support
|
||||
it by pulling the right bits out and making a
|
||||
sized unsigned constant. This code assumes the
|
||||
lsb of a parameter is 0 and the msb is the
|
||||
width of the parameter. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
long lsb = lsn->as_long();
|
||||
long msb = msn->as_long();
|
||||
if ((lsb < 0) || (msb < lsb)) {
|
||||
cerr << get_line() << ": error: invalid part "
|
||||
<< "select: " << path_
|
||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long ulsb=lsb;
|
||||
unsigned long umsb=msb;
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
assert(le);
|
||||
|
||||
verinum result (verinum::V0, msb-lsb+1, true);
|
||||
verinum exl = le->value();
|
||||
|
||||
/* Pull the bits from the parameter, one at a
|
||||
time. If the bit is within the range, simply
|
||||
copy it to the result. If the bit is outside
|
||||
the range, we sign extend signed unsized
|
||||
numbers, zero extend unsigned unsigned numbers,
|
||||
and X extend sized numbers. */
|
||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
||||
if (idx < exl.len())
|
||||
result.set(idx-lsb, exl.get(idx));
|
||||
else if (exl.is_string())
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
else if (exl.has_len())
|
||||
result.set(idx-lsb, verinum::Vx);
|
||||
else if (exl.has_sign())
|
||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
||||
else
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
}
|
||||
|
||||
/* If the input is a string, and the part select
|
||||
is working on byte boundaries, then the result
|
||||
can be made into a string. */
|
||||
if (exl.is_string()
|
||||
&& (lsb%8 == 0)
|
||||
&& (result.len()%8 == 0))
|
||||
result = verinum(result.as_string());
|
||||
|
||||
delete tmp;
|
||||
tmp = new NetEConst(result);
|
||||
|
||||
} else if (msb_) {
|
||||
/* Handle the case where a parameter has a bit
|
||||
select attached to it. Generate a NetESelect
|
||||
object to select the bit as desired. */
|
||||
NetExpr*mtmp = msb_->elaborate_expr(des, scope);
|
||||
if (! dynamic_cast<NetEConst*>(mtmp)) {
|
||||
NetExpr*re = mtmp->eval_tree();
|
||||
if (re) {
|
||||
delete mtmp;
|
||||
mtmp = re;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's first try to get constant values for both
|
||||
the parameter and the bit select. If they are
|
||||
both constant, then evaluate the bit select and
|
||||
return instead a single-bit constant. */
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
NetEConst*re = dynamic_cast<NetEConst*>(mtmp);
|
||||
if (le && re) {
|
||||
|
||||
verinum lv = le->value();
|
||||
verinum rv = re->value();
|
||||
verinum::V rb = verinum::Vx;
|
||||
|
||||
long ridx = rv.as_long();
|
||||
if ((ridx >= 0) && ((unsigned long) ridx < lv.len())) {
|
||||
rb = lv[ridx];
|
||||
|
||||
} else if ((ridx >= 0) && (!lv.has_len())) {
|
||||
if (lv.has_sign())
|
||||
rb = lv[lv.len()-1];
|
||||
else
|
||||
rb = verinum::V0;
|
||||
}
|
||||
|
||||
NetEConst*re = new NetEConst(verinum(rb, 1));
|
||||
delete tmp;
|
||||
delete mtmp;
|
||||
tmp = re;
|
||||
|
||||
} else {
|
||||
|
||||
NetESelect*stmp = new NetESelect(tmp, mtmp, 1);
|
||||
tmp->set_line(*this);
|
||||
tmp = stmp;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* No bit or part select. Make the constant into a
|
||||
NetEConstParam if possible. */
|
||||
NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp);
|
||||
if (ctmp != 0) {
|
||||
perm_string name
|
||||
= lex_strings.make(path_.peek_tail_name());
|
||||
NetEConstParam*ptmp
|
||||
= new NetEConstParam(found_in, name, ctmp->value());
|
||||
delete tmp;
|
||||
tmp = ptmp;
|
||||
}
|
||||
}
|
||||
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the identifier names a signal (a register or wire)
|
||||
// then create a NetESignal node to handle it.
|
||||
|
|
@ -645,6 +512,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
// 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)) {
|
||||
|
|
@ -872,6 +740,181 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in) const
|
||||
{
|
||||
NetExpr*tmp;
|
||||
|
||||
tmp = par->dup_expr();
|
||||
|
||||
if (sel_ == SEL_PART) {
|
||||
assert(msb_ && lsb_);
|
||||
|
||||
/* If the parameter has a part select, we support
|
||||
it by pulling the right bits out and making a
|
||||
sized unsigned constant. This code assumes the
|
||||
lsb of a parameter is 0 and the msb is the
|
||||
width of the parameter. */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
long lsb = lsn->as_long();
|
||||
long msb = msn->as_long();
|
||||
if ((lsb < 0) || (msb < lsb)) {
|
||||
cerr << get_line() << ": error: invalid part "
|
||||
<< "select: " << path_
|
||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long ulsb=lsb;
|
||||
unsigned long umsb=msb;
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
assert(le);
|
||||
|
||||
verinum result (verinum::V0, msb-lsb+1, true);
|
||||
verinum exl = le->value();
|
||||
|
||||
/* Pull the bits from the parameter, one at a
|
||||
time. If the bit is within the range, simply
|
||||
copy it to the result. If the bit is outside
|
||||
the range, we sign extend signed unsized
|
||||
numbers, zero extend unsigned unsigned numbers,
|
||||
and X extend sized numbers. */
|
||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
||||
if (idx < exl.len())
|
||||
result.set(idx-lsb, exl.get(idx));
|
||||
else if (exl.is_string())
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
else if (exl.has_len())
|
||||
result.set(idx-lsb, verinum::Vx);
|
||||
else if (exl.has_sign())
|
||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
||||
else
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
}
|
||||
|
||||
/* If the input is a string, and the part select
|
||||
is working on byte boundaries, then the result
|
||||
can be made into a string. */
|
||||
if (exl.is_string()
|
||||
&& (lsb%8 == 0)
|
||||
&& (result.len()%8 == 0))
|
||||
result = verinum(result.as_string());
|
||||
|
||||
delete tmp;
|
||||
tmp = new NetEConst(result);
|
||||
|
||||
} else if (sel_ == SEL_IDX_UP || sel_ == SEL_IDX_DO) {
|
||||
assert(msb_);
|
||||
assert(lsb_);
|
||||
|
||||
/* Get and evaluate the width of the index
|
||||
select. This must be constant. */
|
||||
NetExpr*wid_ex = elab_and_eval(des, scope, lsb_);
|
||||
NetEConst*wid_ec = dynamic_cast<NetEConst*> (wid_ex);
|
||||
if (wid_ec == 0) {
|
||||
cerr << lsb_->get_line() << ": error: "
|
||||
<< "Second expression of indexed part select "
|
||||
<< "most be constant." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned wid = wid_ec->value().as_ulong();
|
||||
|
||||
NetExpr*idx_ex = elab_and_eval(des, scope, msb_);
|
||||
if (idx_ex == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sel_ == SEL_IDX_DO && wid > 1) {
|
||||
idx_ex = make_add_expr(idx_ex, 1-(long)wid);
|
||||
}
|
||||
|
||||
|
||||
/* Wrap the param expression with a part select. */
|
||||
tmp = new NetESelect(tmp, idx_ex, wid);
|
||||
|
||||
|
||||
} else if (msb_) {
|
||||
/* Handle the case where a parameter has a bit
|
||||
select attached to it. Generate a NetESelect
|
||||
object to select the bit as desired. */
|
||||
NetExpr*mtmp = msb_->elaborate_expr(des, scope);
|
||||
if (! dynamic_cast<NetEConst*>(mtmp)) {
|
||||
NetExpr*re = mtmp->eval_tree();
|
||||
if (re) {
|
||||
delete mtmp;
|
||||
mtmp = re;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's first try to get constant values for both
|
||||
the parameter and the bit select. If they are
|
||||
both constant, then evaluate the bit select and
|
||||
return instead a single-bit constant. */
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
NetEConst*re = dynamic_cast<NetEConst*>(mtmp);
|
||||
if (le && re) {
|
||||
|
||||
verinum lv = le->value();
|
||||
verinum rv = re->value();
|
||||
verinum::V rb = verinum::Vx;
|
||||
|
||||
long ridx = rv.as_long();
|
||||
if ((ridx >= 0) && ((unsigned long) ridx < lv.len())) {
|
||||
rb = lv[ridx];
|
||||
|
||||
} else if ((ridx >= 0) && (!lv.has_len())) {
|
||||
if (lv.has_sign())
|
||||
rb = lv[lv.len()-1];
|
||||
else
|
||||
rb = verinum::V0;
|
||||
}
|
||||
|
||||
NetEConst*re = new NetEConst(verinum(rb, 1));
|
||||
delete tmp;
|
||||
delete mtmp;
|
||||
tmp = re;
|
||||
|
||||
} else {
|
||||
|
||||
NetESelect*stmp = new NetESelect(tmp, mtmp, 1);
|
||||
tmp->set_line(*this);
|
||||
tmp = stmp;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* No bit or part select. Make the constant into a
|
||||
NetEConstParam if possible. */
|
||||
NetEConst*ctmp = dynamic_cast<NetEConst*>(tmp);
|
||||
if (ctmp != 0) {
|
||||
perm_string name
|
||||
= lex_strings.make(path_.peek_tail_name());
|
||||
NetEConstParam*ptmp
|
||||
= new NetEConstParam(found_in, name, ctmp->value());
|
||||
delete tmp;
|
||||
tmp = ptmp;
|
||||
}
|
||||
}
|
||||
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, bool) const
|
||||
{
|
||||
assert(value_);
|
||||
|
|
@ -1048,6 +1091,9 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const
|
|||
|
||||
/*
|
||||
* $Log: elab_expr.cc,v $
|
||||
* Revision 1.98 2005/10/04 04:09:25 steve
|
||||
* Add support for indexed select attached to parameters.
|
||||
*
|
||||
* Revision 1.97 2005/09/19 21:45:35 steve
|
||||
* Spelling patches from Larry.
|
||||
*
|
||||
|
|
|
|||
40
parse.y
40
parse.y
|
|
@ -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.205 2005/07/27 14:54:51 steve Exp $"
|
||||
#ident "$Id: parse.y,v 1.206 2005/10/04 04:09:25 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -988,15 +988,47 @@ expr_primary
|
|||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* There are 3 kinds of part selects. The basic part select has the
|
||||
usual [M:L] syntax. The indexed part selects use +: or -: in
|
||||
place of the : in the basic part select, and the first expression
|
||||
is not limited to constant values. */
|
||||
|
||||
| identifier '[' expression ':' expression ']'
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
tmp->msb_ = $3;
|
||||
tmp->lsb_ = $5;
|
||||
tmp->sel_ = PEIdent::SEL_PART;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier '[' expression K_PO_POS expression ']'
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
tmp->msb_ = $3;
|
||||
tmp->lsb_ = $5;
|
||||
tmp->sel_ = PEIdent::SEL_IDX_UP;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
| identifier '[' expression K_PO_NEG expression ']'
|
||||
{ PEIdent*tmp = new PEIdent(*$1);
|
||||
tmp->set_file(@1.text);
|
||||
tmp->set_lineno(@1.first_line);
|
||||
tmp->msb_ = $3;
|
||||
tmp->lsb_ = $5;
|
||||
tmp->sel_ = PEIdent::SEL_IDX_DO;
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* An identifer followed by an expression list in parentheses is a
|
||||
function call. If a system identifier, then a system function
|
||||
call. */
|
||||
|
||||
| identifier '(' expression_list ')'
|
||||
{ PECallFunction*tmp = new PECallFunction(*$1, *$3);
|
||||
tmp->set_file(@1.text);
|
||||
|
|
@ -1010,8 +1042,14 @@ expr_primary
|
|||
tmp->set_lineno(@1.first_line);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* Parenthesized expressions are primaries. */
|
||||
|
||||
| '(' expression ')'
|
||||
{ $$ = $2; }
|
||||
|
||||
/* Various kinds of concatenation expressions. */
|
||||
|
||||
| '{' expression_list '}'
|
||||
{ PEConcat*tmp = new PEConcat(*$2);
|
||||
tmp->set_file(@1.text);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: pform_dump.cc,v 1.90 2005/07/11 16:56:51 steve Exp $"
|
||||
#ident "$Id: pform_dump.cc,v 1.91 2005/10/04 04:09:26 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -145,8 +145,19 @@ void PEIdent::dump(ostream&out) const
|
|||
out << path_;
|
||||
if (msb_) {
|
||||
out << "[" << *msb_;
|
||||
if (lsb_) {
|
||||
if (lsb_) switch (sel_) {
|
||||
case SEL_IDX_UP:
|
||||
out << "+:" << *lsb_;
|
||||
break;
|
||||
case SEL_IDX_DO:
|
||||
out << "-:" << *lsb_;
|
||||
break;
|
||||
case SEL_PART:
|
||||
out << ":" << *lsb_;
|
||||
break;
|
||||
default:
|
||||
out << ":?:" << *lsb_;
|
||||
break;
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
|
@ -903,6 +914,9 @@ void PUdp::dump(ostream&out) const
|
|||
|
||||
/*
|
||||
* $Log: pform_dump.cc,v $
|
||||
* Revision 1.91 2005/10/04 04:09:26 steve
|
||||
* Add support for indexed select attached to parameters.
|
||||
*
|
||||
* Revision 1.90 2005/07/11 16:56:51 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue