Add user function synth and clean up expression code.

This patch adds synthesize() for user functions. It also cleans up a
number of inconsistencies and missing checks in the expression code.
This commit is contained in:
Cary R 2008-02-22 14:51:53 -08:00 committed by Stephen Williams
parent 11a33a0907
commit fac1cc5a1c
9 changed files with 387 additions and 276 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2002 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: dup_expr.cc,v 1.21 2006/11/04 06:10:13 steve Exp $"
#endif
# include "config.h"
@ -112,7 +109,7 @@ NetEUFunc* NetEUFunc::dup_expr() const
tmp_parms[idx] = parms_[idx]->dup_expr();
}
tmp = new NetEUFunc(func_, result_sig_->dup_expr(), tmp_parms);
tmp = new NetEUFunc(scope_, func_, result_sig_->dup_expr(), tmp_parms);
assert(tmp);
return tmp;
@ -131,77 +128,3 @@ NetEUReduce* NetEUReduce::dup_expr() const
assert(tmp);
return tmp;
}
/*
* $Log: dup_expr.cc,v $
* Revision 1.21 2006/11/04 06:10:13 steve
* Handle dup of pad as well as normal select.
*
* Revision 1.20 2005/07/11 16:56:50 steve
* Remove NetVariable and ivl_variable_t structures.
*
* Revision 1.19 2004/12/11 02:31:25 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
* down this path.
*
* Revision 1.18 2004/06/17 16:06:18 steve
* Help system function signedness survive elaboration.
*
* Revision 1.17 2004/05/31 23:34:36 steve
* Rewire/generalize parsing an elaboration of
* function return values to allow for better
* speed and more type support.
*
* Revision 1.16 2003/10/31 02:47:11 steve
* NetEUReduce has its own dup_expr method.
*
* Revision 1.15 2003/05/30 02:55:32 steve
* Support parameters in real expressions and
* as real expressions, and fix multiply and
* divide with real results.
*
* Revision 1.14 2003/04/22 04:48:29 steve
* Support event names as expressions elements.
*
* Revision 1.13 2003/03/15 18:08:43 steve
* Comparison operators do have defined width.
*
* Revision 1.12 2003/03/15 04:46:28 steve
* Better organize the NetESFunc return type guesses.
*
* Revision 1.11 2003/03/10 23:40:53 steve
* Keep parameter constants for the ivl_target API.
*
* Revision 1.10 2003/01/26 21:15:58 steve
* Rework expression parsing and elaboration to
* accommodate real/realtime values and expressions.
*
* Revision 1.9 2002/11/09 00:25:27 steve
* Add dup_expr for user defined function calls.
*
* Revision 1.8 2002/08/12 01:34:58 steve
* conditional ident string using autoconfig.
*
* Revision 1.7 2002/01/28 00:52:41 steve
* Add support for bit select of parameters.
* This leads to a NetESelect node and the
* vvp code generator to support that.
*
* Revision 1.6 2001/11/19 01:54:14 steve
* Port close cropping behavior from mcrgb
* Move window array reset to libmc.
*
* Revision 1.5 2001/07/25 03:10:48 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.4 2000/05/07 18:20:07 steve
* Import MCD support from Stephen Tell, and add
* system function parameter support to the IVL core.
*
* Revision 1.3 2000/05/04 03:37:58 steve
* Add infrastructure for system functions, move
* $time to that structure and add $random.
*/

View File

@ -197,9 +197,10 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
baseline Verilog. But we allow it in our extended
form of Verilog. */
if (generation_flag < GN_VER2001X) {
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;
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;
}
}
@ -237,10 +238,11 @@ NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
case 'E': /* === */
case 'N': /* !== */
if (lp->expr_type() == IVL_VT_REAL
|| rp->expr_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: Case equality may not "
<< "have real operands." << endl;
if (lp->expr_type() == IVL_VT_REAL ||
rp->expr_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: "
<< human_readable_op(op_)
<< "may not have real operands." << endl;
return 0;
}
/* Fall through... */
@ -628,7 +630,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
if (NetNet*res = dscope->find_signal(dscope->basename())) {
NetESignal*eres = new NetESignal(res);
NetEUFunc*func = new NetEUFunc(dscope, eres, parms);
NetEUFunc*func = new NetEUFunc(scope, dscope, eres, parms);
func->set_line(*this);
func->cast_signed(res->get_signed());
return func;

View File

@ -29,26 +29,6 @@
# include <iostream>
# include "ivl_assert.h"
/*
* Human readable version of op_ used in NetEBinary and NetEUnary.
* XXX This isn't a complete list, but it's enough to cover the
* restricted cases it is used for.
*/
static const char *human_readable_op(const char op_)
{
const char *type;
switch (op_) {
case '^': type = "^"; break; // XOR
case 'X': type = "~^"; break; // XNOR
case '&': type = "&"; break; // AND
case 'A': type = "~&"; break; // NAND (~&)
case '|': type = "|"; break; // Bitwise OR
case 'O': type = "~|"; break; // Bitwise NOR
default: assert(0);
}
return type;
}
/*
* This is a state flag that determines whether an elaborate_net must
* report an error when it encounters an unsized number. Normally, it
@ -158,18 +138,8 @@ NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope,
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
if (lsig == 0 || rsig == 0) return 0;
NetNet*osig;
@ -278,18 +248,8 @@ NetNet* PEBinary::elaborate_net_bit_(Design*des, NetScope*scope,
{
NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, width, 0, 0, 0);
if (lsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
if (lsig == 0 || rsig == 0) return 0;
if (lsig->vector_width() < rsig->vector_width())
lsig = pad_to_width(des, lsig, rsig->vector_width());
@ -494,21 +454,10 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
(so that the eval_tree method can reduce constant
expressions, including parameters) then turn those results
into synthesized nets. */
NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth);
if (lexp == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth),
*rexp = elab_and_eval(des, scope, right_, lwidth);
NetExpr*rexp = elab_and_eval(des, scope, right_, lwidth);
if (rexp == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
if (lexp == 0 || rexp == 0) return 0;
unsigned operand_width;
bool real_arg = false;
@ -539,12 +488,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (NetEConst*tmp = dynamic_cast<NetEConst*>(rexp)) {
lsig = lexp->synthesize(des);
if (lsig == 0) {
cerr << get_fileline() << ": internal error: "
"Cannot elaborate net for " << *lexp << endl;
return 0;
}
assert(lsig);
if (lsig == 0) return 0;
delete lexp;
lexp = 0;
@ -553,6 +497,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
NetECReal rlval(vrl);
rsig = rlval.synthesize(des);
delete rexp;
rexp = 0;
} else {
NetNet*osig = compare_eq_constant(des, scope,
lsig, tmp, op_,
@ -567,14 +512,16 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (NetEConst*tmp = dynamic_cast<NetEConst*>(lexp)) {
rsig = rexp->synthesize(des);
assert(rsig);
if (rsig == 0) return 0;
delete rexp;
rexp = 0;
if (real_arg) {
verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl);
lsig = rlval.synthesize(des);
delete lexp;
lexp = 0;
} else {
NetNet*osig = compare_eq_constant(des, scope,
rsig, tmp, op_,
@ -588,13 +535,13 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (lsig == 0) {
lsig = lexp->synthesize(des);
assert(lsig);
if (lsig == 0) return 0;
delete lexp;
}
if (rsig == 0) {
rsig = rexp->synthesize(des);
assert(rsig);
if (rsig == 0) return 0;
delete rexp;
}
@ -614,6 +561,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
lsig->data_type() != IVL_VT_REAL)) {
cerr << get_fileline() << ": sorry: comparing bit based signals "
"and real values is not supported." << endl;
des->errors += 1;
return 0;
}
@ -661,6 +609,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (real_arg) {
cerr << get_fileline() << ": error: Case equality may not "
"have real operands." << endl;
des->errors += 1;
return 0;
}
gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, true);
@ -673,6 +622,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (real_arg) {
cerr << get_fileline() << ": error: Case inequality may not "
"have real operands." << endl;
des->errors += 1;
return 0;
}
gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, false);
@ -757,11 +707,10 @@ NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
NetNet*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (rsig == 0) return 0;
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
// Check the l-value width. If it is unspecified, then use the
// largest operand width as the l-value width. Restrict the
@ -841,10 +790,10 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0);
if (lsig == 0) return 0;
NetNet*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
if (rsig == 0) return 0;
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
/* The arguments of a modulus must have the same type. */
if (lsig->data_type() != rsig->data_type()) {
@ -911,35 +860,16 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0);
NetNet*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
if (lsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
left_->dump(cerr);
cerr << endl;
return 0;
}
if (rsig == 0) {
cerr << get_fileline() << ": error: Cannot elaborate ";
right_->dump(cerr);
cerr << endl;
return 0;
}
NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
if (rsig->data_type() == IVL_VT_REAL ||
lsig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": sorry: ";
switch (op_) {
case 'a':
cerr << "&&";
break;
case 'o':
cerr << "||";
break;
default:
assert(0);
}
cerr << " is currently unsupported for real values." << endl;
cerr << get_fileline() << ": sorry: " << human_readable_op(op_)
<< " is currently unsupported for real values." << endl;
des->errors += 1;
return 0;
}
@ -1057,10 +987,10 @@ NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope,
return osig;
}
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
NetNet*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (rsig == 0) return 0;
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
/* The arguments of a multiply must have the same type. */
if (lsig->data_type() != rsig->data_type()) {
@ -1107,7 +1037,7 @@ NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope,
connect(mult->pin_DataA(), lsig->pin(0));
connect(mult->pin_DataB(), rsig->pin(0));
// Make a signal to carry the output from the multiply.
/* Make a signal to carry the output from the multiply. */
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, rwidth);
osig->data_type( lsig->data_type() );
@ -1123,10 +1053,10 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
const NetExpr* fall,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
NetNet*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (rsig == 0) return 0;
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0 || rsig == 0) return 0;
/* The arguments of a power must have the same type. */
if (lsig->data_type() != rsig->data_type()) {
@ -1139,7 +1069,7 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
return 0;
}
// The power is signed if either its operands are signed.
/* The power is signed if either of its operands are signed. */
bool arith_is_signed = lsig->get_signed() || rsig->get_signed();
unsigned rwidth = lwidth;
@ -1174,7 +1104,7 @@ NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope,
connect(powr->pin_DataA(), lsig->pin(0));
connect(powr->pin_DataB(), rsig->pin(0));
// Make a signal to carry the output from the power.
/* Make a signal to carry the output from the power. */
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, rwidth);
osig->data_type( lsig->data_type() );
@ -1191,12 +1121,14 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope,
const NetExpr* decay) const
{
NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
if (lsig == 0) return 0;
/* Cannot shift a real value. */
if (lsig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: shift operators "
"cannot shift a real value." << endl;
cerr << get_fileline() << ": error: shift operators ("
<< human_readable_op(op_)
<< ") cannot shift a real value." << endl;
des->errors += 1;
return 0;
}
@ -1358,6 +1290,7 @@ NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope,
dwid += 1;
NetNet*rsig = right_->elaborate_net(des, scope, dwid, 0, 0, 0);
if (rsig == 0) return 0;
/* You cannot shift a value by a real amount. */
@ -1441,7 +1374,6 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
des->errors += 1;
return 0;
}
assert(def);
NetScope*dscope = def->scope();
assert(dscope);
@ -1470,6 +1402,7 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
<< "port " << idx << " of call to " << path_ <<
"." << endl;
errors += 1;
des->errors += 1;
continue;
}
@ -1477,8 +1410,7 @@ NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
eparms[idx] = tmp;
}
if (errors > 0)
return 0;
if (errors > 0) return 0;
NetUserFunc*net = new NetUserFunc(scope,
scope->local_symbol(),
@ -1591,6 +1523,7 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope,
connect(net->pin(0), osig->pin(0));
unsigned errors = 0;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0,
0, 0, 0,
@ -1599,11 +1532,16 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope,
cerr << get_fileline() << ": error: Unable to elaborate "
<< "port " << idx << " of call to " << path_ <<
"." << endl;
errors += 1;
des->errors += 1;
continue;
}
connect(net->pin(1+idx), tmp->pin(0));
}
if (errors > 0) return 0;
return osig;
}
@ -1702,7 +1640,7 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (nets[idx]) delete nets[idx];
}
des->errors += 1;
des->errors += errors;
return 0;
}
@ -2305,7 +2243,7 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
if (nets[idx]) delete nets[idx];
}
des->errors += 1;
des->errors += errors;
return 0;
}
@ -2997,13 +2935,11 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
Link::strength_t drive0,
Link::strength_t drive1) const
{
NetNet* expr_sig = expr_->elaborate_net(des, scope, 0, 0, 0, 0);
NetNet* tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
NetNet* fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
des->errors += 1;
return 0;
}
NetNet*expr_sig = expr_->elaborate_net(des, scope, 0, 0, 0, 0),
*tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0),
*fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0;
/* The type of the true and false expressions must
match. These become the type of the resulting
@ -3020,11 +2956,13 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
des->errors += 1;
expr_type = IVL_VT_NO_TYPE;
return 0;
} else if (expr_type == IVL_VT_NO_TYPE) {
cerr << get_fileline() << ": internal error: True and false "
<< "clauses of ternary both have NO TYPE." << endl;
des->errors += 1;
return 0;
}
/* The natural width of the expression is the width of the
@ -3200,11 +3138,8 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
}
NetNet* sub_sig = expr->synthesize(des);
if (sub_sig == 0) {
des->errors += 1;
return 0;
}
assert(sub_sig);
if (sub_sig == 0) return 0;
delete expr;
expr = 0;
@ -3442,12 +3377,9 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
}
NetNet* sub_sig = expr->synthesize(des);
if (sub_sig == 0) return 0;
delete expr;
if (sub_sig == 0) {
des->errors += 1;
return 0;
}
ivl_assert(*this, sub_sig);
NetNet*sig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, 1);
@ -3463,14 +3395,21 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
<< op_ << " expression with real values." << endl;
des->errors += 1;
break;
case '~':
cerr << get_fileline() << ": error: bit-wise negation ("
<< human_readable_op(op_)
<< ") may not have a REAL operand." << endl;
des->errors += 1;
break;
case '&':
case 'A':
case '|':
case 'N':
case '^':
case 'X':
cerr << get_fileline() << ": error: " << human_readable_op(op_)
<< " reduction operator may not have a REAL operand." << endl;
cerr << get_fileline() << ": error: reduction operator ("
<< human_readable_op(op_)
<< ") may not have a REAL operand." << endl;
des->errors += 1;
break;
case '!':

View File

@ -65,7 +65,7 @@ bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
NetEConst*lc = dynamic_cast<NetEConst*>(left_);
if (lc == 0) return false;
verinum tmp = lc->value();
lval = verireal(tmp.as_long());
lval = verireal(tmp.as_double());
break;
}
@ -86,7 +86,7 @@ bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval)
NetEConst*rc = dynamic_cast<NetEConst*>(right_);
if (rc == 0) return 0;
verinum tmp = rc->value();
rval = verireal(tmp.as_long());
rval = verireal(tmp.as_double());
break;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -18,6 +18,7 @@
*/
# include "config.h"
# include "compiler.h"
# include <iostream>
@ -25,6 +26,57 @@
# include "netmisc.h"
# include "ivl_assert.h"
NetNet* convert_to_real_const(Design*des, NetExpr*expr, NetExpr*obj)
{
NetNet* sig;
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl);
sig = rlval.synthesize(des);
} else {
cerr << obj->get_fileline() << ": sorry: Cannot convert "
"bit based value (" << *expr << ") to real." << endl;
des->errors += 1;
sig = 0;
}
return sig;
}
/* Note that lsig, rsig and real_args are references. */
bool process_binary_args(Design*des, NetExpr*left, NetExpr*right,
NetNet*&lsig, NetNet*&rsig, bool&real_args,
NetExpr*obj)
{
if (left->expr_type() == IVL_VT_REAL ||
right->expr_type() == IVL_VT_REAL) {
real_args = true;
/* Currently we will have a runtime assert if both expressions
are not real, though we can convert constants. */
if (left->expr_type() == IVL_VT_REAL) {
lsig = left->synthesize(des);
} else {
lsig = convert_to_real_const(des, left, obj);
}
if (right->expr_type() == IVL_VT_REAL) {
rsig = right->synthesize(des);
} else {
rsig = convert_to_real_const(des, right, obj);
}
} else {
real_args = false;
lsig = left->synthesize(des);
rsig = right->synthesize(des);
}
if (lsig == 0 || rsig == 0) return true;
else return false;
}
NetNet* NetExpr::synthesize(Design*des)
{
cerr << get_fileline() << ": internal error: cannot synthesize expression: "
@ -40,8 +92,12 @@ NetNet* NetEBAdd::synthesize(Design*des)
{
assert((op()=='+') || (op()=='-'));
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetNet *lsig=0, *rsig=0;
bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig,
real_args, this)) {
return 0;
}
assert(expr_width() >= lsig->vector_width());
assert(expr_width() >= rsig->vector_width());
@ -87,6 +143,17 @@ NetNet* NetEBBits::synthesize(Design*des)
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
if (lsig == 0 || rsig == 0) return 0;
/* You cannot do bitwise operations on real values. */
if (lsig->data_type() == IVL_VT_REAL ||
rsig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: " << human_readable_op(op_)
<< " operator may not have REAL operands." << endl;
des->errors += 1;
return 0;
}
NetScope*scope = lsig->scope();
assert(scope);
@ -98,6 +165,7 @@ NetNet* NetEBBits::synthesize(Design*des)
<< lsig->vector_width() << ": " << *left_ << endl;
cerr << get_fileline() << ": : width="
<< rsig->vector_width() << ": " << *right_ << endl;
des->errors += 1;
return 0;
}
@ -115,6 +183,9 @@ NetNet* NetEBBits::synthesize(Design*des)
case '&':
gate = new NetLogic(scope, oname, 3, NetLogic::AND, wid);
break;
case 'A':
gate = new NetLogic(scope, oname, 3, NetLogic::NAND, wid);
break;
case '|':
gate = new NetLogic(scope, oname, 3, NetLogic::OR, wid);
break;
@ -144,19 +215,27 @@ NetNet* NetEBBits::synthesize(Design*des)
NetNet* NetEBComp::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetNet *lsig=0, *rsig=0;
unsigned width;
bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig,
real_args, this)) {
return 0;
}
if (real_args) {
width = 1;
} else {
width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width);
rsig = pad_to_width(des, rsig, width);
}
NetScope*scope = lsig->scope();
assert(scope);
unsigned width = lsig->vector_width();
if (rsig->vector_width() > width)
width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width);
rsig = pad_to_width(des, rsig, width);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
osig->set_line(*this);
@ -165,7 +244,7 @@ NetNet* NetEBComp::synthesize(Design*des)
/* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */
if ((width == 1) && ((op_ == 'e') || (op_ == 'E'))) {
if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XNOR, 1);
gate->set_line(*this);
@ -179,7 +258,7 @@ NetNet* NetEBComp::synthesize(Design*des)
/* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */
if ((width == 1) && ((op_ == 'n') || (op_ == 'N'))) {
if ((width == 1) && ((op_ == 'n') || (op_ == 'N')) && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XOR, 1);
gate->set_line(*this);
@ -206,8 +285,14 @@ NetNet* NetEBComp::synthesize(Design*des)
case '>':
connect(dev->pin_AGB(), osig->pin(0));
break;
case 'e': // ==
case 'E': // === ?
if (real_args) {
cerr << get_fileline() << ": error: Case equality may "
"not have real operands." << endl;
des->errors += 1;
return 0;
}
case 'e': // ==
connect(dev->pin_AEB(), osig->pin(0));
break;
case 'G': // >=
@ -216,8 +301,14 @@ NetNet* NetEBComp::synthesize(Design*des)
case 'L': // <=
connect(dev->pin_ALEB(), osig->pin(0));
break;
case 'n': // !=
case 'N': // !==
if (real_args) {
cerr << get_fileline() << ": error: Case inequality may "
"not have real operands." << endl;
des->errors += 1;
return 0;
}
case 'n': // !=
connect(dev->pin_ANEB(), osig->pin(0));
break;
@ -241,20 +332,22 @@ NetNet* NetEBPow::synthesize(Design*des)
NetNet* NetEBMult::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
if (lsig == 0)
NetNet *lsig=0, *rsig=0;
unsigned width;
bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig,
real_args, this)) {
return 0;
}
if (rsig == 0)
return 0;
if (real_args) width = 1;
else width = expr_width();
NetScope*scope = lsig->scope();
assert(scope);
NetMult*mult = new NetMult(scope, scope->local_symbol(),
expr_width(),
width,
lsig->vector_width(),
rsig->vector_width());
des->add_node(mult);
@ -266,7 +359,7 @@ NetNet* NetEBMult::synthesize(Design*des)
connect(mult->pin_DataB(), rsig->pin(0));
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, expr_width());
NetNet::IMPLICIT, width);
osig->data_type(lsig->data_type());
osig->set_line(*this);
osig->data_type(expr_type());
@ -279,13 +372,21 @@ NetNet* NetEBMult::synthesize(Design*des)
NetNet* NetEBDiv::synthesize(Design*des)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetNet *lsig=0, *rsig=0;
unsigned width;
bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig,
real_args, this)) {
return 0;
}
if (real_args) width = 1;
else width = expr_width();
NetScope*scope = lsig->scope();
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, expr_width());
NetNet::IMPLICIT, width);
osig->set_line(*this);
osig->data_type(lsig->data_type());
osig->local_flag(true);
@ -294,7 +395,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
case '/': {
NetDivide*div = new NetDivide(scope, scope->local_symbol(),
expr_width(),
width,
lsig->vector_width(),
rsig->vector_width());
div->set_line(*this);
@ -307,8 +408,16 @@ NetNet* NetEBDiv::synthesize(Design*des)
}
case '%': {
/* Baseline Verilog does not support the % operator with
real arguments, but we allow it in our extended form. */
if (real_args && generation_flag < GN_VER2001X) {
cerr << get_fileline() << ": error: Modulus operator "
"may not have REAL operands." << endl;
des->errors += 1;
return 0;
}
NetModulo*div = new NetModulo(scope, scope->local_symbol(),
expr_width(),
width,
lsig->vector_width(),
rsig->vector_width());
div->set_line(*this);
@ -339,11 +448,16 @@ NetNet* NetEBLogic::synthesize(Design*des)
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
if (lsig == 0)
return 0;
if (lsig == 0 || rsig == 0) return 0;
if (rsig == 0)
/* You cannot currently do logical operations on real values. */
if (lsig->data_type() == IVL_VT_REAL ||
rsig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": sorry: " << human_readable_op(op_)
<< " is currently unsupported for real values." << endl;
des->errors += 1;
return 0;
}
NetScope*scope = lsig->scope();
assert(scope);
@ -420,8 +534,17 @@ NetNet* NetEBShift::synthesize(Design*des)
}
NetNet*lsig = left_->synthesize(des);
if (lsig == 0)
if (lsig == 0) return 0;
/* Cannot shift a real values. */
if (lsig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: shift operator ("
<< human_readable_op(op_)
<< ") cannot shift a real values." << endl;
des->errors += 1;
return 0;
}
bool right_flag = op_ == 'r' || op_ == 'R';
bool signed_flag = op_ == 'R';
@ -508,8 +631,8 @@ NetNet* NetEBShift::synthesize(Design*des)
}
NetNet*rsig = right_->synthesize(des);
if (rsig == 0)
return 0;
if (rsig == 0) return 0;
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, expr_width());
@ -627,6 +750,16 @@ NetNet* NetEUBits::synthesize(Design*des)
{
NetNet*isig = expr_->synthesize(des);
if (isig == 0) return 0;
if (isig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: bit-wise negation ("
<< human_readable_op(op_)
<< ") may not have a REAL operand." << endl;
des->errors += 1;
return 0;
}
NetScope*scope = isig->scope();
assert(scope);
@ -659,6 +792,16 @@ NetNet* NetEUReduce::synthesize(Design*des)
{
NetNet*isig = expr_->synthesize(des);
if (isig == 0) return 0;
if (isig->data_type() == IVL_VT_REAL) {
cerr << get_fileline() << ": error: reduction operator ("
<< human_readable_op(op_)
<< ") may not have a REAL operand." << endl;
des->errors += 1;
return 0;
}
NetScope*scope = isig->scope();
assert(scope);
@ -710,8 +853,8 @@ NetNet* NetESelect::synthesize(Design *des)
{
NetNet*sub = expr_->synthesize(des);
if (sub == 0)
return 0;
if (sub == 0) return 0;
NetScope*scope = sub->scope();
@ -803,9 +946,27 @@ NetNet* NetESelect::synthesize(Design *des)
*/
NetNet* NetETernary::synthesize(Design *des)
{
NetNet*csig = cond_->synthesize(des);
NetNet*tsig = true_val_->synthesize(des);
NetNet*fsig = false_val_->synthesize(des);
NetNet*csig = cond_->synthesize(des),
*tsig = true_val_->synthesize(des),
*fsig = false_val_->synthesize(des);
if (csig == 0 || tsig == 0 || fsig == 0) return 0;
if (tsig->data_type() != fsig->data_type()) {
cerr << get_fileline() << ": error: True and False clauses of "
"ternary expression have different types." << endl;
cerr << get_fileline() << ": : True clause is: "
<< tsig->data_type() << endl;
cerr << get_fileline() << ": : False clause is: "
<< fsig->data_type() << endl;
des->errors += 1;
return 0;
} else if (tsig->data_type() == IVL_VT_NO_TYPE) {
cerr << get_fileline() << ": internal error: True and False "
"clauses of ternary both have NO TYPE." << endl;
des->errors += 1;
return 0;
}
perm_string path = csig->scope()->local_symbol();
@ -876,3 +1037,53 @@ NetNet* NetESignal::synthesize(Design*des)
}
return tmp;
}
NetNet* NetESFunc::synthesize(Design*des)
{
cerr << get_fileline() << ": sorry: cannot synthesize system function: "
<< *this << " in this context" << endl;
des->errors += 1;
return 0;
}
NetNet* NetEUFunc::synthesize(Design*des)
{
svector<NetNet*> eparms (parms_.count());
/* Synthesize the arguments. */
bool errors = false;
for (unsigned idx = 0; idx < eparms.count(); idx += 1) {
NetNet*tmp = parms_[idx]->synthesize(des);
if (tmp == 0) {
cerr << get_fileline() << ": error: Unable to synthesize "
"port " << idx << " of call to "
<< func_->basename() << "." << endl;
errors = true;
des->errors += 1;
continue;
}
eparms[idx] = tmp;
}
if (errors) return 0;
NetUserFunc*net = new NetUserFunc(scope_, scope_->local_symbol(), func_);
net->set_line(*this);
des->add_node(net);
/* Create an output signal and connect it to the function. */
NetNet*osig = new NetNet(scope_, scope_->local_symbol(), NetNet::WIRE,
result_sig_->vector_width());
osig->local_flag(true);
osig->data_type(result_sig_->expr_type());
connect(net->pin(0), osig->pin(0));
/* Connect the pins to the arguments. */
NetFuncDef*def = func_->func_def();
for (unsigned idx = 0; idx < eparms.count(); idx += 1) {
NetNet*tmp = pad_to_width(des, eparms[idx],
def->port(idx)->vector_width());
connect(net->pin(idx+1), tmp->pin(0));
}
return osig;
}

View File

@ -1918,8 +1918,9 @@ const NetExpr* NetSTask::parm(unsigned idx) const
return parms_[idx];
}
NetEUFunc::NetEUFunc(NetScope*def, NetESignal*res, svector<NetExpr*>&p)
: func_(def), result_sig_(res), parms_(p)
NetEUFunc::NetEUFunc(NetScope*scope, NetScope*def, NetESignal*res,
svector<NetExpr*>&p)
: scope_(scope), func_(def), result_sig_(res), parms_(p)
{
expr_width(result_sig_->expr_width());
}

View File

@ -2492,7 +2492,7 @@ class NetTaskDef {
class NetEUFunc : public NetExpr {
public:
NetEUFunc(NetScope*, NetESignal*, svector<NetExpr*>&);
NetEUFunc(NetScope*, NetScope*, NetESignal*, svector<NetExpr*>&);
~NetEUFunc();
const NetESignal*result_sig() const;
@ -2509,8 +2509,10 @@ class NetEUFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEUFunc*dup_expr() const;
virtual NexusSet* nex_input(bool rem_out = true);
virtual NetNet* synthesize(Design*des);
private:
NetScope*scope_;
NetScope*func_;
NetESignal*result_sig_;
svector<NetExpr*> parms_;
@ -3067,6 +3069,7 @@ class NetESFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetESFunc*dup_expr() const;
virtual NetNet*synthesize(Design*);
private:
const char* name_;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2008 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
@ -191,3 +191,33 @@ std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
return res;
}
/*
* Human readable version of op. Used in elaboration error messages.
*/
const char *human_readable_op(const char op)
{
const char *type;
switch (op) {
case '~': type = "~"; break; // Negation
case '^': type = "^"; break; // XOR
case 'X': type = "~^"; break; // XNOR
case '&': type = "&"; break; // Bitwise AND
case 'A': type = "~&"; break; // NAND (~&)
case '|': type = "|"; break; // Bitwise OR
case 'O': type = "~|"; break; // NOR
case 'a': type = "&&"; break; // Logical AND
case 'o': type = "||"; break; // Logical OR
case 'E': type = "==="; break; // Case equality
case 'N': type = "!=="; break; // Case inequality
case 'l': type = "<<(<)"; break; // Left shifts
case 'r': type = ">>"; break; // Logical right shift
case 'R': type = ">>>"; break; // Arithmetic right shift
default: assert(0);
}
return type;
}

View File

@ -1,7 +1,7 @@
#ifndef __netmisc_H
#define __netmisc_H
/*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2008 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
@ -18,9 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netmisc.h,v 1.31 2007/06/02 03:42:13 steve Exp $"
#endif
# include "netlist.h"
@ -133,4 +130,9 @@ bool eval_as_long(long&value, NetExpr*expr);
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
const pform_name_t&path);
/*
* Return a human readable version of the operator.
*/
const char *human_readable_op(const char op);
#endif