Expression widths with unsized literals are pseudo-infinite width.

This commit is contained in:
steve 2006-10-30 05:44:49 +00:00
parent 2a8b960b06
commit 2302693201
9 changed files with 312 additions and 28 deletions

View File

@ -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.37 2005/10/04 04:09:25 steve Exp $"
#ident "$Id: PExpr.cc,v 1.38 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -75,6 +75,24 @@ bool PEBinary::is_constant(Module*mod) const
return left_->is_constant(mod) && right_->is_constant(mod);
}
PEBComp::PEBComp(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r)
{
}
PEBComp::~PEBComp()
{
}
PEBShift::PEBShift(char op, PExpr*l, PExpr*r)
: PEBinary(op, l, r)
{
}
PEBShift::~PEBShift()
{
}
PECallFunction::PECallFunction(const hname_t&n, const svector<PExpr *> &parms)
: path_(n), parms_(parms)
{
@ -270,6 +288,9 @@ bool PEUnary::is_constant(Module*m) const
/*
* $Log: PExpr.cc,v $
* Revision 1.38 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.37 2005/10/04 04:09:25 steve
* Add support for indexed select attached to parameters.
*

79
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.83 2006/06/18 04:15:50 steve Exp $"
#ident "$Id: PExpr.h,v 1.84 2006/10/30 05:44:49 steve Exp $"
#endif
# include <string>
@ -51,6 +51,29 @@ class PExpr : public LineInfo {
virtual void dump(ostream&) const;
// This method tests the width that the expression wants to
// be. It is used by elaboration of assignments to figure out
// the width of the expression.
//
// The "min" is the width of the local context, so it the
// minimum width that this function should return. Initially
// this is the same as the lval width.
//
// The "lval" is the width of the destination where this
// result is going to go. This can be used to constrain the
// amount that an expression can reasonably expand. For
// example, there is no point expanding an addition to beyond
// the lval. This extra bit of information allows the
// expression to optimize itself a bit. If the lval==0, then
// the subexpression should not make l-value related
// optimizations.
//
// The unsigned_flag is set to true if the expression is
// unsized and therefore expandable. This happens if a
// sub-expression is an unsized literal. Some expressions make
// special use of that.
virtual unsigned test_width(unsigned min, unsigned lval, bool&unsized_flag) const;
// Procedural elaboration of the expression. The expr_width is
// the width of the context of the expression (i.e. the
// l-value width of an assignment) or -1 if the expression is
@ -128,6 +151,8 @@ class PEConcat : public PExpr {
virtual verinum* eval_const(const Design*des, NetScope*sc) const;
virtual void dump(ostream&) const;
//virtual int test_width(bool) const;
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
bool implicit_net_ok =false) const;
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
@ -177,6 +202,8 @@ class PEEvent : public PExpr {
virtual void dump(ostream&) const;
//virtual int test_width(bool) const;
private:
edge_t type_;
PExpr *expr_;
@ -193,6 +220,8 @@ class PEFNumber : public PExpr {
const verireal& value() const;
//virtual int test_width(bool) const;
/* The eval_const method as applied to a floating point number
gets the *integer* value of the number. This accounts for
any rounding that is needed to get the value. */
@ -226,6 +255,9 @@ class PEIdent : public PExpr {
~PEIdent();
virtual void dump(ostream&) const;
virtual unsigned test_width(unsigned min, unsigned lval, bool&unsized_flag) const;
//virtual int test_width(bool) const;
// Identifiers are allowed (with restrictions) is assign l-values.
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
@ -344,6 +376,8 @@ class PENumber : public PExpr {
const verinum& value() const;
virtual void dump(ostream&) const;
virtual unsigned test_width(unsigned min, unsigned lval, bool&unsized_flag) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned lwidth,
const NetExpr* rise,
@ -382,6 +416,8 @@ class PEString : public PExpr {
string value() const;
virtual void dump(ostream&) const;
//virtual int test_width(bool) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@ -407,6 +443,8 @@ class PEUnary : public PExpr {
~PEUnary();
virtual void dump(ostream&out) const;
//virtual int test_width(bool) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@ -433,8 +471,12 @@ class PEBinary : public PExpr {
~PEBinary();
virtual bool is_constant(Module*) const;
//virtual int test_width(bool) const;
virtual void dump(ostream&out) const;
virtual unsigned test_width(unsigned min, unsigned lval, bool&unsized_flag) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@ -447,13 +489,15 @@ class PEBinary : public PExpr {
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(const Design*des, NetScope*sc) const;
private:
protected:
char op_;
PExpr*left_;
PExpr*right_;
NetEBinary*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const;
NetEBinary*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp) const;
private:
NetNet* elaborate_net_add_(Design*des, NetScope*scope,
unsigned lwidth,
const NetExpr* rise,
@ -496,6 +540,31 @@ class PEBinary : public PExpr {
const NetExpr* decay) const;
};
/*
* Here are a few specilized classes for handling specific binary
* operators.
*/
class PEBComp : public PEBinary {
public:
explicit PEBComp(char op, PExpr*l, PExpr*r);
~PEBComp();
virtual unsigned test_width(unsigned min, unsigned lval, bool&flag) const;
NetEBinary* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const;
};
class PEBShift : public PEBinary {
public:
explicit PEBShift(char op, PExpr*l, PExpr*r);
~PEBShift();
virtual unsigned test_width(unsigned min, unsigned lval, bool&flag) const;
};
/*
* This class supports the ternary (?:) operator. The operator takes
* three expressions, the test, the true result and the false result.
@ -507,6 +576,7 @@ class PETernary : public PExpr {
~PETernary();
virtual bool is_constant(Module*) const;
//virtual int test_width(bool) const;
virtual void dump(ostream&out) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
@ -539,6 +609,8 @@ class PECallFunction : public PExpr {
~PECallFunction();
virtual void dump(ostream &) const;
//virtual int test_width(bool) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
unsigned width,
const NetExpr* rise,
@ -567,6 +639,9 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.84 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.83 2006/06/18 04:15:50 steve
* Add support for system functions in continuous assignments.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: design_dump.cc,v 1.170 2006/10/03 05:06:00 steve Exp $"
#ident "$Id: design_dump.cc,v 1.171 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -1162,8 +1162,10 @@ void NetEParam::dump(ostream&o) const
{
if (scope_ != 0)
o << "<" << scope_->name() << "." << name_ << ">";
else
else if (name_)
o << "<" << name_ << ">";
else
o << "<???>";
}
void NetETernary::dump(ostream&o) const
@ -1229,6 +1231,9 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.171 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.170 2006/10/03 05:06:00 steve
* Support real valued specify delays, properly scaled.
*

View File

@ -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.113 2006/10/15 03:25:57 steve Exp $"
#ident "$Id: elab_expr.cc,v 1.114 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -28,6 +28,19 @@
# include "netmisc.h"
# include "util.h"
/*
* The default behavor for the test_width method is to just return the
* minimum width that is passed in.
*/
unsigned PExpr::test_width(unsigned min, unsigned lval, bool&) const
{
if (debug_elaborate) {
cerr << get_line() << ": debug: test_width defaults to "
<< min << ", ignoring unsized_flag" << endl;
}
return min;
}
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const
{
cerr << get_line() << ": internal error: I do not know how to elaborate"
@ -38,6 +51,42 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const
return 0;
}
unsigned PEBinary::test_width(unsigned min, unsigned lval, bool&unsized_flag) const
{
bool flag_left = false;
bool flag_right = false;
unsigned wid_left = left_->test_width(min, lval, flag_left);
unsigned wid_right = right_->test_width(min, lval, flag_right);
if (flag_left || flag_right)
unsized_flag = true;
switch (op_) {
case '+':
case '-':
if (unsized_flag) {
wid_left += 1;
wid_right += 1;
}
if (wid_left > min)
min = wid_left;
if (wid_right > min)
min = wid_right;
if (lval > 0 && min > lval)
min = lval;
break;
default:
if (wid_left > min)
min = wid_left;
if (wid_right > min)
min = wid_right;
break;
}
return min;
}
/*
* Elaborate binary expressions. This involves elaborating the left
* and right sides, and creating one of a variety of different NetExpr
@ -57,7 +106,14 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
NetEBinary*tmp = elaborate_eval_expr_base_(des, lp, rp);
return tmp;
}
NetEBinary* PEBinary::elaborate_eval_expr_base_(Design*des,
NetExpr*lp,
NetExpr*rp) const
{
/* If either expression can be evaluated ahead of time, then
do so. This can prove helpful later. */
{ NetExpr*tmp;
@ -74,8 +130,7 @@ NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope,
}
}
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
return tmp;
return elaborate_expr_base_(des, lp, rp);
}
/*
@ -87,6 +142,7 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp) const
{
bool flag;
NetEBinary*tmp;
switch (op_) {
@ -189,6 +245,50 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
return tmp;
}
unsigned PEBComp::test_width(unsigned, unsigned, bool&) const
{
return 1;
}
NetEBinary* PEBComp::elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const
{
assert(left_);
assert(right_);
/* Width of operands is self-determined. */
int use_wid = -1;
NetExpr*lp = left_->elaborate_expr(des, scope, use_wid, false);
NetExpr*rp = right_->elaborate_expr(des, scope, use_wid, false);
if ((lp == 0) || (rp == 0)) {
delete lp;
delete rp;
return 0;
}
/* If we find that one of the operands are indefinitely wide,
then go ahead and relax the width of the operand to
eliminate loss. */
if (! lp->has_width())
rp->relax_width();
if (! rp->has_width())
lp->relax_width();
return elaborate_eval_expr_base_(des, lp, rp);
}
unsigned PEBShift::test_width(unsigned min, unsigned lval, bool&unsized_flag) const
{
unsigned wid_left = left_->test_width(min, 0, unsized_flag);
// The right expression is self-determined and has no impact
// on the expression size that is generated.
return wid_left;
}
/*
* Given a call to a system function, generate the proper expression
* nodes to represent the call in the netlist. Since we don't support
@ -491,6 +591,12 @@ NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, int, bool) const
return tmp;
}
unsigned PEIdent::test_width(unsigned min, unsigned lval, bool&unsized_flag) const
{
return min;
}
/*
* Elaborate an identifier in an expression. The identifier can be a
* parameter name, a signal name or a memory name. It can also be a
@ -1229,6 +1335,18 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
return node;
}
unsigned PENumber::test_width(unsigned min, unsigned lval, bool&unsized_flag) const
{
unsigned use_wid = value_->len();
if (min > use_wid)
use_wid = min;
if (! value_->has_len())
unsized_flag = true;
return use_wid;
}
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*,
int expr_width, bool) const
{
@ -1427,6 +1545,9 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
/*
* $Log: elab_expr.cc,v $
* Revision 1.114 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.113 2006/10/15 03:25:57 steve
* More detailed internal error message.
*

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.347 2006/10/03 15:33:49 steve Exp $"
#ident "$Id: elaborate.cc,v 1.348 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -1419,10 +1419,19 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
delay = elaborate_delay_expr(delay_, des, scope);
assert(rval());
/* Elaborate the r-value expression, then try to evaluate it. */
assert(rval());
NetExpr*rv = elab_and_eval(des, scope, rval(), lv->lwidth());
/* Find out what the r-value width is going to be. We guess it
will be the l-value width, but it may turn out to be
something else based on self-determined widths inside. */
unsigned use_width = lv->lwidth();
bool unsized_flag = false;
use_width = rval()->test_width(use_width, use_width, unsized_flag);
/* Now elaborate to the expected width. */
NetExpr*rv = elab_and_eval(des, scope, rval(), use_width);
if (rv == 0) return 0;
assert(rv);
@ -3311,6 +3320,9 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.348 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.347 2006/10/03 15:33:49 steve
* no-specify turns of specparam elaboration.
*

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.70 2006/09/19 23:00:15 steve Exp $"
#ident "$Id: eval_tree.cc,v 1.71 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -1236,8 +1236,15 @@ NetExpr* NetEMemory::eval_tree()
NetExpr* NetEParam::eval_tree()
{
if (des_ == 0)
if (des_ == 0) {
assert(scope_ == 0);
return 0;
}
if (debug_elaborate) {
cerr << get_line() << ": debug: evaluating expression: "
<< *this << endl;
}
assert(scope_);
const NetExpr*expr_msb;
@ -1670,6 +1677,9 @@ NetEConst* NetEUReduce::eval_tree()
/*
* $Log: eval_tree.cc,v $
* Revision 1.71 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.70 2006/09/19 23:00:15 steve
* Use elab_and_eval for bit select expressions.
*

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.h,v 1.363 2006/10/03 05:06:00 steve Exp $"
#ident "$Id: netlist.h,v 1.364 2006/10/30 05:44:49 steve Exp $"
#endif
/*
@ -1134,6 +1134,12 @@ class NetExpr : public LineInfo {
// width to the l-value width, if possible.
virtual bool set_width(unsigned wid, bool last_chance =false);
// This is similar to set_width, but allows the expression to
// set the width for itself, it a way that eliminates
// loss. This is used by elaboration in expressions where the
// expression width is determined to be "indefinitely large".
virtual void relax_width(void);
// This method returns true if the expression is
// signed. Unsigned expressions return false.
bool has_sign() const;
@ -2676,6 +2682,7 @@ class NetEBAdd : public NetEBinary {
virtual ivl_variable_type_t expr_type() const;
virtual bool set_width(unsigned w, bool last_chance);
virtual void relax_width(void);
virtual NetEBAdd* dup_expr() const;
virtual NetEConst* eval_tree();
virtual NetNet* synthesize(Design*);
@ -3567,6 +3574,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.364 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.363 2006/10/03 05:06:00 steve
* Support real valued specify delays, properly scaled.
*

24
parse.y
View File

@ -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.220 2006/09/23 04:57:19 steve Exp $"
#ident "$Id: parse.y,v 1.221 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -879,67 +879,67 @@ expression
$$ = tmp;
}
| expression '<' expression
{ PEBinary*tmp = new PEBinary('<', $1, $3);
{ PEBinary*tmp = new PEBComp('<', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression '>' expression
{ PEBinary*tmp = new PEBinary('>', $1, $3);
{ PEBinary*tmp = new PEBComp('>', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_LS expression
{ PEBinary*tmp = new PEBinary('l', $1, $3);
{ PEBinary*tmp = new PEBShift('l', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_RS expression
{ PEBinary*tmp = new PEBinary('r', $1, $3);
{ PEBinary*tmp = new PEBShift('r', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_RSS expression
{ PEBinary*tmp = new PEBinary('R', $1, $3);
{ PEBinary*tmp = new PEBShift('R', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_EQ expression
{ PEBinary*tmp = new PEBinary('e', $1, $3);
{ PEBinary*tmp = new PEBComp('e', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_CEQ expression
{ PEBinary*tmp = new PEBinary('E', $1, $3);
{ PEBinary*tmp = new PEBComp('E', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_LE expression
{ PEBinary*tmp = new PEBinary('L', $1, $3);
{ PEBinary*tmp = new PEBComp('L', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_GE expression
{ PEBinary*tmp = new PEBinary('G', $1, $3);
{ PEBinary*tmp = new PEBComp('G', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_NE expression
{ PEBinary*tmp = new PEBinary('n', $1, $3);
{ PEBinary*tmp = new PEBComp('n', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;
}
| expression K_CNE expression
{ PEBinary*tmp = new PEBinary('N', $1, $3);
{ PEBinary*tmp = new PEBComp('N', $1, $3);
tmp->set_file(@2.text);
tmp->set_lineno(@2.first_line);
$$ = tmp;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2006 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: set_width.cc,v 1.39 2006/07/31 03:50:17 steve Exp $"
#ident "$Id: set_width.cc,v 1.40 2006/10/30 05:44:49 steve Exp $"
#endif
# include "config.h"
@ -33,6 +33,7 @@
*/
# include "netlist.h"
# include "netmisc.h"
# include "compiler.h"
# include <typeinfo>
@ -45,6 +46,14 @@ bool NetExpr::set_width(unsigned w, bool)
return false;
}
/*
* The default relax_width method does nothing, and leaves the
* previously elaborated width.
*/
void NetExpr::relax_width(void)
{
}
bool NetEBinary::set_width(unsigned w, bool)
{
bool flag = true;
@ -108,6 +117,24 @@ bool NetEBAdd::set_width(unsigned w, bool)
return wid == w;
}
void NetEBAdd::relax_width(void)
{
unsigned wid = left_->expr_width();
if (right_->expr_width() > wid)
wid = right_->expr_width();
// Allow space for the carry.
wid += 1;
if (debug_elaborate)
cerr << get_line() << ": debug: "
<< "Relax addition width to " << wid << endl;
left_->set_width(wid);
right_->set_width(wid);
expr_width(wid);
}
/*
* The bitwise logical operators have operands the same size as the
* result. Anything else is a mess. I first try to get the operands to
@ -440,6 +467,9 @@ bool NetEUReduce::set_width(unsigned w, bool)
/*
* $Log: set_width.cc,v $
* Revision 1.40 2006/10/30 05:44:49 steve
* Expression widths with unsized literals are pseudo-infinite width.
*
* Revision 1.39 2006/07/31 03:50:17 steve
* Add support for power in constant expressions.
*