Handle widths of real value arguments to user functions.

The arguments to user defined functions are self-determined. And if
the result is real valued, we can call them lossless self-determined.
Treat these arguments like r-value elaboration for assignments.

Also clean up the binary divide elaboration a little bit.

Also, floating point literals are unsized with width==1.
This commit is contained in:
Stephen Williams 2008-09-25 20:37:18 -07:00
parent 873ed60ff8
commit d3f17f27c1
2 changed files with 82 additions and 17 deletions

View File

@ -211,6 +211,9 @@ class PEFNumber : public PExpr {
/* A PEFNumber is a constant, so this returns true. */
virtual bool is_constant(Module*) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const;
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const;
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const;
@ -454,6 +457,7 @@ class PEBinary : public PExpr {
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_div_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;

View File

@ -42,6 +42,34 @@ static 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,
PExpr*expr)
{
int expr_wid = 0;
bool unsized_flag = false;
switch (data_type_lv) {
case IVL_VT_REAL:
expr_wid = -2;
expr_wid_lv = -1;
break;
case IVL_VT_BOOL:
case IVL_VT_LOGIC:
expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, unsized_flag);
break;
case IVL_VT_VOID:
case IVL_VT_NO_TYPE:
ivl_assert(*expr, 0);
expr_wid = -2;
expr_wid_lv = -1;
break;
}
NetExpr*result = elab_and_eval(des, scope, expr, expr_wid, expr_wid_lv);
return result;
}
/*
* The default behavior for the test_width method is to just return the
* minimum width that is passed in.
@ -224,21 +252,8 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break;
case '%':
/* The % operator does not support real arguments in
baseline Verilog. But we allow it in our extended
form of Verilog. */
if (! gn_icarus_misc_flag) {
if (lp->expr_type()==IVL_VT_REAL ||
rp->expr_type()==IVL_VT_REAL) {
cerr << get_fileline() << ": error: Modulus operator "
"may not have REAL operands." << endl;
des->errors += 1;
}
}
/* Fall through to handle the % with the / operator. */
case '/':
tmp = new NetEBDiv(op_, lp, rp);
tmp->set_line(*this);
tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid);
break;
case 'l': // <<
@ -310,6 +325,28 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_div_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
/* The % operator does not support real arguments in
baseline Verilog. But we allow it in our extended
form of Verilog. */
if (op_ == '%' && ! gn_icarus_misc_flag) {
if (lp->expr_type()==IVL_VT_REAL ||
rp->expr_type()==IVL_VT_REAL) {
cerr << get_fileline() << ": error: Modulus operator "
"may not have REAL operands." << endl;
des->errors += 1;
}
}
NetEBDiv*tmp = new NetEBDiv(op_, lp, rp);
tmp->set_line(*this);
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
@ -689,6 +726,9 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
if (peek_tail_name(path_)[0] == '$')
return test_width_sfunc_(des, scope, min, lval, unsized_flag);
// The width of user defined functions depends only on the
// width of the return value. The arguments are entirely
// self-determined.
NetFuncDef*def = des->find_function(scope, path_);
if (def == 0) {
if (debug_elaborate)
@ -706,6 +746,10 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
cerr << get_fileline() << ": debug: test_width "
<< "of function returns width " << res->vector_width()
<< "." << endl;
if (! type_is_vectorable(res->data_type()))
unsized_flag = true;
return res->vector_width();
}
@ -973,13 +1017,15 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
PExpr*tmp = parms_[idx];
if (tmp) {
int argwid = def->port(idx)->vector_width();
parms[idx] = elab_and_eval(des, scope, tmp, argwid);
parms[idx] = elaborate_rval_expr(des, scope,
def->port(idx)->data_type(),
def->port(idx)->vector_width(),
tmp);
if (debug_elaborate)
cerr << get_fileline() << ": debug:"
<< " function " << path_
<< " arg " << (idx+1)
<< " argwid=" << argwid
<< " argwid=" << parms[idx]->expr_width()
<< ": " << *parms[idx] << endl;
} else {
@ -1125,6 +1171,21 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
return tmp;
}
/*
* Floating point literals are not vectorable. It's not particularly
* clear what to do about an actual width to return, but whatever the
* width, it is unsigned.
*
* Absent any better idea, we call all real valued results a width of 1.
*/
unsigned PEFNumber::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const
{
unsized_flag = true;
return 1;
}
NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, int, bool) const
{
NetECReal*tmp = new NetECReal(*value_);