Merge test_width rework

This collection of patches fixes a variety of bugs with the handling
of signed-ness in exprsesions.
This commit is contained in:
Stephen Williams 2008-10-13 20:23:50 -07:00
commit 1a3e655285
14 changed files with 310 additions and 167 deletions

View File

@ -28,6 +28,7 @@
PExpr::PExpr()
{
expr_type_ = IVL_VT_NO_TYPE;
}
PExpr::~PExpr()

41
PExpr.h
View File

@ -73,7 +73,12 @@ class PExpr : public LineInfo {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
// After the test_width method is complete, these methods
// return valid results.
ivl_variable_type_t expr_type() const { return expr_type_; }
unsigned expr_width() const { return expr_width_; }
// During the elaborate_sig phase, we may need to scan
// expressions to find implicit net declarations.
@ -128,6 +133,13 @@ class PExpr : public LineInfo {
// expressions that must be structurally "identical".
virtual bool is_the_same(const PExpr*that) const;
protected:
// The derived class test_width methods should fill these in.
ivl_variable_type_t expr_type_;
unsigned expr_width_;
static void suppress_binary_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);
private: // not implemented
PExpr(const PExpr&);
PExpr& operator= (const PExpr&);
@ -207,7 +219,7 @@ class PEFNumber : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
@ -233,7 +245,7 @@ class PEIdent : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
@ -348,7 +360,7 @@ class PENumber : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
int expr_width, bool) const;
@ -384,7 +396,7 @@ class PEString : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual NetEConst*elaborate_expr(Design*des, NetScope*,
int expr_width, bool) const;
@ -406,7 +418,7 @@ class PEUnary : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
@ -415,6 +427,9 @@ class PEUnary : public PExpr {
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const;
private:
NetExpr* elaborate_expr_bits_(NetExpr*operand, int expr_wid) const;
private:
char op_;
PExpr*expr_;
@ -431,7 +446,7 @@ class PEBinary : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
@ -455,8 +470,6 @@ class PEBinary : public PExpr {
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);
};
/*
@ -472,7 +485,7 @@ class PEBComp : public PEBinary {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&flag) const;
bool&flag);
NetExpr* elaborate_expr(Design*des, NetScope*scope,
int expr_width, bool sys_task_arg) const;
@ -487,7 +500,7 @@ class PEBShift : public PEBinary {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&flag) const;
bool&flag);
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const;
};
@ -506,7 +519,7 @@ class PETernary : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
@ -548,7 +561,7 @@ class PECallFunction : public PExpr {
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
private:
pform_name_t path_;
@ -561,7 +574,7 @@ class PECallFunction : public PExpr {
unsigned test_width_sfunc_(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const;
bool&unsized_flag);
};
#endif

View File

@ -80,7 +80,7 @@ class PGate : public LineInfo {
bool as_net_flag =false) const;
unsigned pin_count() const { return pins_? pins_->count() : 0; }
const PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
PExpr*pin(unsigned idx) const { return (*pins_)[idx]; }
strength_t strength0() const;
strength_t strength1() const;

View File

@ -99,7 +99,7 @@ class PAssign_ : public Statement {
virtual ~PAssign_() =0;
const PExpr* lval() const { return lval_; }
const PExpr* rval() const { return rval_; }
PExpr* rval() const { return rval_; }
protected:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;

View File

@ -343,7 +343,9 @@ void NetCLShift::dump_node(ostream&o, unsigned ind) const
void NetCompare::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "LPM_COMPARE (NetCompare): " << name() << endl;
o << setw(ind) << "" << "LPM_COMPARE (NetCompare "
<< (get_signed()? "signed" : "unsigned") << "): "
<< name() << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}

View File

@ -44,12 +44,25 @@ bool type_is_vectorable(ivl_variable_type_t type)
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_variable_type_t data_type_lv, int expr_wid_lv,
const PExpr*expr)
PExpr*expr)
{
int expr_wid = 0;
bool unsized_flag = false;
bool unsized_flag = type_is_vectorable(data_type_lv)? true : false;
ivl_variable_type_t rval_type = IVL_VT_NO_TYPE;
/* 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. */
int expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag);
if (debug_elaborate) {
cerr << expr->get_fileline() << ": debug: r-value tested "
<< "type=" << rval_type
<< ", width=" << expr_wid
<< ", min=" << expr_wid_lv
<< ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
}
switch (data_type_lv) {
case IVL_VT_REAL:
unsized_flag = true;
@ -58,19 +71,6 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
break;
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
/* 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. */
expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag);
if (debug_elaborate) {
cerr << expr->get_fileline() << ": debug: r-value tested "
<< "width is " << expr_wid
<< ", min=" << expr_wid_lv
<< ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
}
break;
case IVL_VT_VOID:
case IVL_VT_NO_TYPE:
@ -90,7 +90,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
*/
unsigned PExpr::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&, bool&) const
ivl_variable_type_t&, bool&)
{
if (debug_elaborate) {
cerr << get_fileline() << ": debug: test_width defaults to "
@ -113,7 +113,7 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const
unsigned PEBinary::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE;
ivl_variable_type_t expr_type_right= IVL_VT_NO_TYPE;
@ -126,23 +126,23 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
if (flag_right && !flag_left) {
flag_left = flag_right;
wid_left = left_->test_width(des, scope, min, 0, expr_type_right, flag_right);
wid_left = left_->test_width(des, scope, min, 0, expr_type_left, flag_right);
}
if (flag_left || flag_right)
unsized_flag = true;
if (expr_type_left == IVL_VT_REAL || expr_type_right == IVL_VT_REAL)
expr_type = IVL_VT_REAL;
expr_type_ = IVL_VT_REAL;
else if (expr_type_left==IVL_VT_LOGIC || expr_type_right==IVL_VT_LOGIC)
expr_type = IVL_VT_LOGIC;
expr_type_ = IVL_VT_LOGIC;
else
expr_type = IVL_VT_BOOL;
expr_type_ = IVL_VT_BOOL;
switch (op_) {
case '+':
case '-':
if (unsized_flag && type_is_vectorable(expr_type)) {
if (unsized_flag && type_is_vectorable(expr_type_)) {
wid_left += 1;
wid_right += 1;
}
@ -186,7 +186,13 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope,
break;
}
return min;
if (type_is_vectorable(expr_type_))
expr_width_ = min;
else
expr_width_ = 1;
expr_type = expr_type_;
return expr_width_;
}
/*
@ -230,8 +236,15 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope,
return tmp;
}
void PEBinary::suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp)
void PExpr::suppress_binary_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp)
{
// If an argument is a non-vector type, then this type
// suppression does not apply.
if (! type_is_vectorable(lp->expr_type()))
return;
if (! type_is_vectorable(rp->expr_type()))
return;
// If either operand is unsigned, then treat the whole
// expression as unsigned. This test needs to be done here
// instead of in *_expr_base_ because it needs to be done
@ -670,6 +683,12 @@ NetExpr* PEBinary::elaborate_expr_base_mult_(Design*des,
}
}
// If this expression is unsigned, then make sure the
// arguments are unsigned so that the padding below doesn't
// cause any sign extension to happen.
suppress_binary_operand_sign_if_needed_(lp, rp);
// Multiply will guess a width that is the sum of the
// widths of the operand. If that sum is too small, then
// pad one of the arguments enough that the sum is the
@ -701,6 +720,11 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
if (! type_is_vectorable(rp->expr_type()))
use_lossless_flag = false;
// If the expression is unsigned, then force the operands to
// unsigned so taht the set_width below doesn't cause them to
// be sign-extended.
suppress_binary_operand_sign_if_needed_(lp, rp);
tmp = new NetEBAdd(op_, lp, rp, use_lossless_flag);
if (expr_wid > 0 && type_is_vectorable(tmp->expr_type()))
tmp->set_width(expr_wid);
@ -711,7 +735,7 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned,
ivl_variable_type_t&expr_type,
bool&) const
bool&)
{
expr_type = IVL_VT_LOGIC;
return 1;
@ -754,7 +778,15 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
suppress_operand_sign_if_needed_(lp, rp);
suppress_binary_operand_sign_if_needed_(lp, rp);
// The arguments of a compare need to have matching widths, so
// pad the width here. This matters because if the arguments
// are signed, then this padding will do sign extension.
if (type_is_vectorable(lp->expr_type()))
lp = pad_to_width(lp, use_wid);
if (type_is_vectorable(rp->expr_type()))
rp = pad_to_width(rp, use_wid);
return elaborate_eval_expr_base_(des, lp, rp, use_wid);
}
@ -762,7 +794,7 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
unsigned PEBShift::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type, unsized_flag);
@ -808,7 +840,7 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope,
unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
perm_string name = peek_tail_name(path_);
@ -824,14 +856,32 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
return wid;
}
// Run through the arguments of the system function and make
// sure their widths/types are calculated. They are all self-
// determined.
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
PExpr*expr = parms_[idx];
ivl_variable_type_t sub_type = IVL_VT_NO_TYPE;
bool flag = false;
unsigned wid = expr->test_width(des,scope,0,0,sub_type,flag);
if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width"
<< " of " << name << " argument " << idx+1
<< " returns type=" << sub_type
<< ", wid=" << wid << endl;
}
if (name=="$sizeof" || name=="$bits") {
if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width"
<< " of $sizeof/$bits returns test_width"
<< " of compiler integer." << endl;
expr_type = IVL_VT_BOOL;
return integer_width;
expr_type_ = IVL_VT_BOOL;
expr_width_= integer_width;
expr_type = expr_type_;
return expr_width_;
}
if (name=="$is_signed") {
@ -840,8 +890,10 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
<< " of $is_signed returns test_width"
<< " of 1." << endl;
expr_type = IVL_VT_BOOL;
return 1;
expr_type_ = IVL_VT_BOOL;
expr_width_ = 1;
expr_type = expr_type_;
return expr_width_;
}
/* Get the return type of the system function by looking it up
@ -849,22 +901,24 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
const struct sfunc_return_type*sfunc_info
= lookup_sys_func(peek_tail_name(path_));
expr_type = sfunc_info->type;
unsigned wid = sfunc_info->wid;
expr_type_ = sfunc_info->type;
expr_width_ = sfunc_info->wid;
expr_type = expr_type_;
if (debug_elaborate)
cerr << get_fileline() << ": debug: test_width "
<< "of system function " << name
<< " returns wid=" << wid
<< ", type=" << expr_type << "." << endl;
<< " returns wid=" << expr_width_
<< ", type=" << expr_type_ << "." << endl;
return wid;
return expr_width_;
}
unsigned PECallFunction::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
if (peek_tail_name(path_)[0] == '$')
return test_width_sfunc_(des, scope, min, lval, expr_type, unsized_flag);
@ -1326,10 +1380,13 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
unsigned PEFNumber::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
expr_type = IVL_VT_REAL;
expr_type_ = IVL_VT_REAL;
expr_width_ = 1;
unsized_flag = true;
expr_type = expr_type_;
return 1;
}
@ -1356,11 +1413,19 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
ivl_assert(*this, index_tail.sel == index_component_t::SEL_PART);
ivl_assert(*this, index_tail.msb && index_tail.lsb);
ivl_variable_type_t tmp_type = IVL_VT_NO_TYPE;
bool tmp_flag = false;
int msb_wid = index_tail.msb->test_width(des, scope, 0, 0, tmp_type, tmp_flag);
tmp_type = IVL_VT_NO_TYPE;
tmp_flag = false;
int lsb_wid = index_tail.lsb->test_width(des, scope, 0, 0, tmp_type, tmp_flag);
/* This handles part selects. In this case, there are
two bit select expressions, and both must be
constant. Evaluate them and pass the results back to
the caller. */
NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
NetExpr*lsb_ex = elab_and_eval(des, scope, index_tail.lsb, lsb_wid);
NetEConst*lsb_c = dynamic_cast<NetEConst*>(lsb_ex);
if (lsb_c == 0) {
cerr << index_tail.lsb->get_fileline() << ": error: "
@ -1376,7 +1441,7 @@ bool PEIdent::calculate_parts_(Design*des, NetScope*scope,
lsb = lsb_c->value().as_long();
}
NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, -1);
NetExpr*msb_ex = elab_and_eval(des, scope, index_tail.msb, msb_wid);
NetEConst*msb_c = dynamic_cast<NetEConst*>(msb_ex);
if (msb_c == 0) {
cerr << index_tail.msb->get_fileline() << ": error: "
@ -1476,7 +1541,7 @@ bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
unsigned PEIdent::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
NetNet* net = 0;
const NetExpr*par = 0;
@ -1486,14 +1551,21 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
symbol_search(des, scope, path_, net, par, eve, ex1, ex2);
if (net != 0)
expr_type_ = net->data_type();
expr_type = expr_type;
// If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the
// name is.
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
if (!name_tail.index.empty()) {
const index_component_t&index_tail = name_tail.index.back();
use_sel = index_tail.sel;
}
unsigned use_width = UINT_MAX;
switch (use_sel) {
@ -1524,15 +1596,18 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
// The width of a signal expression is the width of the signal.
if (net != 0) {
expr_type = net->data_type();
return max(net->vector_width(), (unsigned long)min);
expr_type_ = net->data_type();
expr_width_= max(net->vector_width(), (unsigned long)min);
expr_type = expr_type_;
return expr_width_;
}
// The width of a parameter name is the width of the range for
// the parameter name, if a range is declared. Otherwise, the
// width is undefined.
if (par != 0) {
expr_type = par->expr_type();
expr_type_ = par->expr_type();
expr_type = expr_type_;
if (ex1) {
ivl_assert(*this, ex2);
const NetEConst*ex1_const = dynamic_cast<const NetEConst*> (ex1);
@ -1542,19 +1617,22 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
long msb = ex1_const->value().as_long();
long lsb = ex2_const->value().as_long();
if (msb >= lsb)
return msb - lsb + 1;
expr_width_ = msb - lsb + 1;
else
return lsb - msb + 1;
expr_width_ = lsb - msb + 1;
return expr_width_;
}
// This is a parameter. If it is sized (meaning it was
// declared with range expresions) then the range
// expressions would have been caught above. So if we
// got there there we know this is an unsized constant.
expr_width_ = par->expr_width();
unsized_flag = true;
return par->expr_width();
return expr_width_;
}
expr_width_ = min;
return min;
}
@ -2410,9 +2488,9 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
unsigned PENumber::test_width(Design*, NetScope*,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
expr_type = IVL_VT_LOGIC;
expr_type_ = IVL_VT_LOGIC;
unsigned use_wid = value_->len();
if (min > use_wid)
use_wid = min;
@ -2423,6 +2501,8 @@ unsigned PENumber::test_width(Design*, NetScope*,
if (lval > 0 && lval < use_wid)
use_wid = lval;
expr_type = expr_type_;
expr_width_ = use_wid;
return use_wid;
}
@ -2453,7 +2533,7 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*,
unsigned PEString::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
expr_type = IVL_VT_BOOL;
unsigned use_wid = text_? 8*strlen(text_) : 0;
@ -2474,7 +2554,7 @@ NetEConst* PEString::elaborate_expr(Design*des, NetScope*,
unsigned PETernary::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&flag) const
bool&flag)
{
ivl_variable_type_t tru_type = IVL_VT_NO_TYPE;
unsigned tru_wid = tru_->test_width(des, scope, min, lval, tru_type,flag);
@ -2495,13 +2575,16 @@ unsigned PETernary::test_width(Design*des, NetScope*scope,
}
if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL)
expr_type = IVL_VT_REAL;
expr_type_ = IVL_VT_REAL;
else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC)
expr_type = IVL_VT_LOGIC;
expr_type_ = IVL_VT_LOGIC;
else
expr_type = tru_type;
return max(tru_wid,fal_wid);
expr_type_ = tru_type;
expr_width_ = max(tru_wid,fal_wid);
expr_type = expr_type_;
return expr_width_;
}
bool NetETernary::test_operand_compat(ivl_variable_type_t l,
@ -2538,13 +2621,11 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
int use_wid = expr_wid >= 0? expr_wid : 0;
if (expr_wid < 0) {
bool flag = expr_wid == -2;
ivl_variable_type_t expr_type = IVL_VT_NO_TYPE;
use_wid = this->test_width(des, scope, 0, 0, expr_type, flag);
use_wid = expr_width();
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Self-sized ternary chooses wid="<< use_wid
<< ", type=" << expr_type
<< ", type=" << expr_type()
<< endl;
ivl_assert(*this, use_wid > 0);
}
@ -2616,6 +2697,8 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
suppress_binary_operand_sign_if_needed_(tru, fal);
/* Whatever the width we choose for the ternary operator, we
need to make sure the operands match. */
tru = pad_to_width(tru, use_wid);
@ -2629,7 +2712,7 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
unsigned PEUnary::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
ivl_variable_type_t&expr_type,
bool&unsized_flag) const
bool&unsized_flag)
{
switch (op_) {
case '!':
@ -2651,6 +2734,7 @@ unsigned PEUnary::test_width(Design*des, NetScope*scope,
// then the tested width.
case '-':
case '+':
case '~':
if (test_wid < min)
test_wid = min;
break;
@ -2789,10 +2873,38 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
break;
case '~':
tmp = new NetEUBits(op_, ip);
tmp->set_line(*this);
tmp = elaborate_expr_bits_(ip, expr_wid);
break;
}
return tmp;
}
NetExpr* PEUnary::elaborate_expr_bits_(NetExpr*operand, int expr_wid) const
{
// Handle the special case that the operand is a
// constant. Simply calculate the constant results of the
// expression and return that.
if (NetEConst*ctmp = dynamic_cast<NetEConst*> (operand)) {
verinum value = ctmp->value();
if (expr_wid > (int)value.len())
value = pad_to_width(value, expr_wid);
// The only operand that I know can get here is the
// unary not (~).
ivl_assert(*this, op_ == '~');
value = v_not(value);
ctmp = new NetEConst(value);
ctmp->set_line(*this);
delete operand;
return ctmp;
}
if (expr_wid > (int)operand->expr_width())
operand = pad_to_width(operand, expr_wid);
NetEUBits*tmp = new NetEUBits(op_, operand);
tmp->set_line(*this);
return tmp;
}

View File

@ -2332,12 +2332,30 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
PExpr*ex = parm(idx);
eparms[idx] = ex? ex->elaborate_expr(des, scope, -1, true) : 0;
if (ex != 0) {
ivl_variable_type_t use_type;
bool flag = false;
int use_wid = ex->test_width(des,scope,0,0, use_type, flag);
if (debug_elaborate)
cerr << ex->get_fileline() << ": debug: "
<< "Argument " << (idx+1)
<< " of system task tests its width as " << use_wid
<< ", type=" << use_type
<< ", unsized_flag=" << flag << endl;
/* Attempt to pre-evaluate the parameters. It may be
possible to at least partially reduce the
expression. */
if (eparms[idx]) eval_expr(eparms[idx]);
// If the argument expression is unsized, then
// elaborate as self-determined *lossless* instead
// of sized.
if (flag==true)
use_wid = -2;
eparms[idx] = ex->elaborate_expr(des, scope, use_wid, true);
if (eparms[idx])
eval_expr(eparms[idx]);
} else {
eparms[idx] = 0;
}
}
NetSTask*cur = new NetSTask(peek_tail_name(path_), eparms);

View File

@ -245,7 +245,18 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
osig->local_flag(true);
osig->data_type(IVL_VT_LOGIC);
bool signed_compare = lsig->get_signed() && rsig->get_signed();
// Test if the comparison is signed.
//
// Note 1: This is not the same as asking if the result is
// signed. In fact, the result will typically be UNsigned. The
// decision to make the comparison signed depends on the
// operand expressions.
//
// Note 2: The operand expressions may be signed even if the
// sig that comes out of synthesis is unsigned. The $signed()
// function markes the expression but doesn't change the
// underlying signals.
bool signed_compare = left_->has_sign() && right_->has_sign();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Comparison (" << op_ << ")"
<< " is " << (signed_compare? "signed" : "unsigned")

View File

@ -992,8 +992,9 @@ extern unsigned ivl_lpm_lineno(ivl_lpm_t net);
* more than the width of the output, although the possibility of
* overflow exists at run time.
*
* Multiply may be signed. If so, the output should be sign extended
* to fill in its result.
* The inputs are always treated as unsigned. If the expression is
* supposed to be signed, elaboration will generate the necessary sign
* extension, so the target need not (must not) consider signedness.
*
* - Power (IVL_LPM_POW)
* The power takes two inputs and generates an output. Unlike other

View File

@ -56,42 +56,54 @@ NetEBAdd::NetEBAdd(char op__, NetExpr*l, NetExpr*r, bool lossless_flag)
&& (! tmp->has_width())
&& (tmp->expr_width() > l->expr_width() || integer_width > l->expr_width()) ) {
unsigned target_width = l->expr_width() + 1;
verinum tmp_v = trim_vnum(tmp->value());
unsigned target_width = l->expr_width();
if (target_width < tmp_v.len())
target_width = tmp_v.len();
if (lossless_flag)
target_width += 1;
if (target_width < integer_width)
target_width = integer_width;
r->set_width(target_width);
/* Note: This constant value will not gain a defined
width from this. Make sure. */
assert(! r->has_width() );
expr_width(target_width);
} else if ( (tmp = dynamic_cast<NetEConst*>(l))
&& (! tmp->has_width())
&& (tmp->expr_width() > r->expr_width() || integer_width > r->expr_width()) ) {
unsigned target_width = r->expr_width() + 1;
verinum tmp_v = trim_vnum(tmp->value());
unsigned target_width = r->expr_width();
if (target_width < tmp_v.len())
target_width = tmp_v.len();
if (lossless_flag)
target_width += 1;
if (target_width < integer_width)
target_width = integer_width;
l->set_width(target_width);
/* Note: This constant value will not gain a defined
width from this. Make sure. */
assert(! l->has_width() );
}
expr_width(target_width);
unsigned pad_width = lossless_flag? 1 : 0;
cast_signed(l->has_sign() && r->has_sign());
/* Now that we have the operand sizes the way we like, or as
good as we are going to get them, set the size of myself. */
if (r->expr_width() > l->expr_width()) {
expr_width(r->expr_width() + pad_width);
} else if (r->expr_width() > l->expr_width()) {
unsigned loss_pad = lossless_flag? 1 : 0;
expr_width(r->expr_width() + loss_pad);
} else {
expr_width(l->expr_width() + pad_width);
unsigned loss_pad = lossless_flag? 1 : 0;
expr_width(l->expr_width() + loss_pad);
}
cast_signed(l->has_sign() && r->has_sign());
}
NetEBAdd::~NetEBAdd()
@ -250,14 +262,10 @@ NetEBMult::NetEBMult(char op__, NetExpr*l, NetExpr*r)
else
expr_width(l->expr_width() + r->expr_width());
cast_signed(l->has_sign() && r->has_sign());
/* If it turns out that this is not a signed expression, then
cast the signedness out of the operands as well. */
if (! has_sign()) {
l->cast_signed(false);
r->cast_signed(false);
}
if (expr_type() == IVL_VT_REAL)
cast_signed(true);
else
cast_signed(l->has_sign() && r->has_sign());
}
NetEBMult::~NetEBMult()

View File

@ -1276,19 +1276,17 @@ const Link& NetCLShift::pin_Distance() const
}
NetCompare::NetCompare(NetScope*s, perm_string n, unsigned wi)
: NetNode(s, n, 10), width_(wi)
: NetNode(s, n, 8), width_(wi)
{
signed_flag_ = false;
pin(0).set_dir(Link::INPUT); // Aclr
pin(1).set_dir(Link::INPUT); // Clock
pin(2).set_dir(Link::OUTPUT); // AGB
pin(3).set_dir(Link::OUTPUT); // AGEB
pin(4).set_dir(Link::OUTPUT); // AEB
pin(5).set_dir(Link::OUTPUT); // ANEB
pin(6).set_dir(Link::OUTPUT); // ALB
pin(7).set_dir(Link::OUTPUT); // ALEB
pin(8).set_dir(Link::INPUT); // DataA
pin(9).set_dir(Link::INPUT); // DataB
pin(0).set_dir(Link::OUTPUT); // AGB
pin(1).set_dir(Link::OUTPUT); // AGEB
pin(2).set_dir(Link::OUTPUT); // AEB
pin(3).set_dir(Link::OUTPUT); // ANEB
pin(4).set_dir(Link::OUTPUT); // ALB
pin(5).set_dir(Link::OUTPUT); // ALEB
pin(6).set_dir(Link::INPUT); // DataA
pin(7).set_dir(Link::INPUT); // DataB
}
NetCompare::~NetCompare()
@ -1311,104 +1309,84 @@ void NetCompare::set_signed(bool flag)
}
Link& NetCompare::pin_Aclr()
{
return pin(0);
}
const Link& NetCompare::pin_Aclr() const
{
return pin(0);
}
Link& NetCompare::pin_Clock()
{
return pin(1);
}
const Link& NetCompare::pin_Clock() const
{
return pin(1);
}
Link& NetCompare::pin_AGB()
{
return pin(2);
return pin(0);
}
const Link& NetCompare::pin_AGB() const
{
return pin(2);
return pin(0);
}
Link& NetCompare::pin_AGEB()
{
return pin(3);
return pin(1);
}
const Link& NetCompare::pin_AGEB() const
{
return pin(3);
return pin(1);
}
Link& NetCompare::pin_AEB()
{
return pin(4);
return pin(2);
}
const Link& NetCompare::pin_AEB() const
{
return pin(4);
return pin(2);
}
Link& NetCompare::pin_ANEB()
{
return pin(5);
return pin(3);
}
const Link& NetCompare::pin_ANEB() const
{
return pin(5);
return pin(3);
}
Link& NetCompare::pin_ALB()
{
return pin(6);
return pin(4);
}
const Link& NetCompare::pin_ALB() const
{
return pin(6);
return pin(4);
}
Link& NetCompare::pin_ALEB()
{
return pin(7);
return pin(5);
}
const Link& NetCompare::pin_ALEB() const
{
return pin(7);
return pin(5);
}
Link& NetCompare::pin_DataA()
{
return pin(8);
return pin(6);
}
const Link& NetCompare::pin_DataA() const
{
return pin(8);
return pin(6);
}
Link& NetCompare::pin_DataB()
{
return pin(9);
return pin(7);
}
const Link& NetCompare::pin_DataB() const
{
return pin(9);
return pin(7);
}
NetDivide::NetDivide(NetScope*sc, perm_string n, unsigned wr,

View File

@ -1040,6 +1040,9 @@ class NetCLShift : public NetNode {
* inputs is narrower then the other, it is up to the generator to
* make sure all the data pins are properly driven.
*
* The signed() property is true if the comparison is to be done to
* signed arguments. The result is always UNsigned.
*
* NOTE: This is not the same as the device used to support case
* compare. Case comparisons handle Vx and Vz values, whereas this
* device need not.
@ -1055,8 +1058,6 @@ class NetCompare : public NetNode {
bool get_signed() const;
void set_signed(bool);
Link& pin_Aclr();
Link& pin_Clock();
Link& pin_AGB();
Link& pin_AGEB();
Link& pin_AEB();
@ -1067,8 +1068,6 @@ class NetCompare : public NetNode {
Link& pin_DataA();
Link& pin_DataB();
const Link& pin_Aclr() const;
const Link& pin_Clock() const;
const Link& pin_AGB() const;
const Link& pin_AGEB() const;
const Link& pin_AEB() const;

View File

@ -157,7 +157,7 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
*/
extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_variable_type_t data_type_lv,
int expr_wid_lv, const PExpr*expr);
int expr_wid_lv, PExpr*expr);
/*
* This procedure elaborates an expression and if the elaboration is
* successful the original expression is replaced with the new one.

View File

@ -336,13 +336,13 @@ void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
}
long a;
if (! vector4_to_value(op_a_, a, true, true)) {
if (! vector4_to_value(op_a_, a, false, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}
long b;
if (! vector4_to_value(op_b_, b, true, true)) {
if (! vector4_to_value(op_b_, b, false, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}