diff --git a/dup_expr.cc b/dup_expr.cc index f40dad8ff..494afd37e 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -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. - */ - diff --git a/elab_expr.cc b/elab_expr.cc index e200e29eb..fa46fca0e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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; diff --git a/elab_net.cc b/elab_net.cc index 83c79545b..a28faf698 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -29,26 +29,6 @@ # include # 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(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(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 '!': diff --git a/eval_tree.cc b/eval_tree.cc index 76be1ca3f..539eaa886 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -65,7 +65,7 @@ bool NetEBinary::get_real_arguments_(verireal&lval, verireal&rval) NetEConst*lc = dynamic_cast(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(right_); if (rc == 0) return 0; verinum tmp = rc->value(); - rval = verireal(tmp.as_long()); + rval = verireal(tmp.as_double()); break; } diff --git a/expr_synth.cc b/expr_synth.cc index cd80f7aca..0c1f2d065 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -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 @@ -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(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 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; +} diff --git a/netlist.cc b/netlist.cc index 8d737d4ad..8921c4a98 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1918,8 +1918,9 @@ const NetExpr* NetSTask::parm(unsigned idx) const return parms_[idx]; } -NetEUFunc::NetEUFunc(NetScope*def, NetESignal*res, svector&p) -: func_(def), result_sig_(res), parms_(p) +NetEUFunc::NetEUFunc(NetScope*scope, NetScope*def, NetESignal*res, + svector&p) +: scope_(scope), func_(def), result_sig_(res), parms_(p) { expr_width(result_sig_->expr_width()); } diff --git a/netlist.h b/netlist.h index 123b28da2..066ba09c2 100644 --- a/netlist.h +++ b/netlist.h @@ -2492,7 +2492,7 @@ class NetTaskDef { class NetEUFunc : public NetExpr { public: - NetEUFunc(NetScope*, NetESignal*, svector&); + NetEUFunc(NetScope*, NetScope*, NetESignal*, svector&); ~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 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_; diff --git a/netmisc.cc b/netmisc.cc index 87b6e3150..47ac976dc 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -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 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; +} diff --git a/netmisc.h b/netmisc.h index 70c2bad98..3f9e00717 100644 --- a/netmisc.h +++ b/netmisc.h @@ -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 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