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:
parent
873ed60ff8
commit
d3f17f27c1
4
PExpr.h
4
PExpr.h
|
|
@ -211,6 +211,9 @@ class PEFNumber : public PExpr {
|
||||||
/* A PEFNumber is a constant, so this returns true. */
|
/* A PEFNumber is a constant, so this returns true. */
|
||||||
virtual bool is_constant(Module*) const;
|
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*,
|
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||||
int expr_width, bool sys_task_arg) const;
|
int expr_width, bool sys_task_arg) const;
|
||||||
virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) 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_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_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_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_rshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||||
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
|
||||||
|
|
|
||||||
95
elab_expr.cc
95
elab_expr.cc
|
|
@ -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
|
* The default behavior for the test_width method is to just return the
|
||||||
* minimum width that is passed in.
|
* minimum width that is passed in.
|
||||||
|
|
@ -224,21 +252,8 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
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 '/':
|
case '/':
|
||||||
tmp = new NetEBDiv(op_, lp, rp);
|
tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid);
|
||||||
tmp->set_line(*this);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l': // <<
|
case 'l': // <<
|
||||||
|
|
@ -310,6 +325,28 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
|
||||||
return tmp;
|
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* PEBinary::elaborate_expr_base_lshift_(Design*des,
|
||||||
NetExpr*lp, NetExpr*rp,
|
NetExpr*lp, NetExpr*rp,
|
||||||
int expr_wid) const
|
int expr_wid) const
|
||||||
|
|
@ -689,6 +726,9 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
|
||||||
if (peek_tail_name(path_)[0] == '$')
|
if (peek_tail_name(path_)[0] == '$')
|
||||||
return test_width_sfunc_(des, scope, min, lval, unsized_flag);
|
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_);
|
NetFuncDef*def = des->find_function(scope, path_);
|
||||||
if (def == 0) {
|
if (def == 0) {
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
|
|
@ -706,6 +746,10 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope,
|
||||||
cerr << get_fileline() << ": debug: test_width "
|
cerr << get_fileline() << ": debug: test_width "
|
||||||
<< "of function returns width " << res->vector_width()
|
<< "of function returns width " << res->vector_width()
|
||||||
<< "." << endl;
|
<< "." << endl;
|
||||||
|
|
||||||
|
if (! type_is_vectorable(res->data_type()))
|
||||||
|
unsized_flag = true;
|
||||||
|
|
||||||
return res->vector_width();
|
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) {
|
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
|
||||||
PExpr*tmp = parms_[idx];
|
PExpr*tmp = parms_[idx];
|
||||||
if (tmp) {
|
if (tmp) {
|
||||||
int argwid = def->port(idx)->vector_width();
|
parms[idx] = elaborate_rval_expr(des, scope,
|
||||||
parms[idx] = elab_and_eval(des, scope, tmp, argwid);
|
def->port(idx)->data_type(),
|
||||||
|
def->port(idx)->vector_width(),
|
||||||
|
tmp);
|
||||||
if (debug_elaborate)
|
if (debug_elaborate)
|
||||||
cerr << get_fileline() << ": debug:"
|
cerr << get_fileline() << ": debug:"
|
||||||
<< " function " << path_
|
<< " function " << path_
|
||||||
<< " arg " << (idx+1)
|
<< " arg " << (idx+1)
|
||||||
<< " argwid=" << argwid
|
<< " argwid=" << parms[idx]->expr_width()
|
||||||
<< ": " << *parms[idx] << endl;
|
<< ": " << *parms[idx] << endl;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1125,6 +1171,21 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||||
return tmp;
|
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
|
NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, int, bool) const
|
||||||
{
|
{
|
||||||
NetECReal*tmp = new NetECReal(*value_);
|
NetECReal*tmp = new NetECReal(*value_);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue