diff --git a/PExpr.cc b/PExpr.cc index 75f6dba84..931c03b89 100644 --- a/PExpr.cc +++ b/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. * diff --git a/PExpr.h b/PExpr.h index f518f67cc..67440005a 100644 --- a/PExpr.h +++ b/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 @@ -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. * diff --git a/elab_expr.cc b/elab_expr.cc index 94ab72504..9f735cfe8 100644 --- a/elab_expr.cc +++ b/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_ - << "["<errors += 1; - return 0; - } - unsigned long ulsb=lsb; - unsigned long umsb=msb; - - NetEConst*le = dynamic_cast(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(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(tmp); - NetEConst*re = dynamic_cast(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(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_ + << "["<errors += 1; + return 0; + } + unsigned long ulsb=lsb; + unsigned long umsb=msb; + + NetEConst*le = dynamic_cast(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 (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(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(tmp); + NetEConst*re = dynamic_cast(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(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. * diff --git a/parse.y b/parse.y index c95fd933c..8f1127a9d 100644 --- a/parse.y +++ b/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); diff --git a/pform_dump.cc b/pform_dump.cc index 7e9c876b7..ad9a7404a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -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. *