1999-09-20 04:21:10 +02:00
|
|
|
/*
|
2003-01-26 22:15:58 +01:00
|
|
|
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
|
1999-09-20 04:21:10 +02:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2003-01-27 06:09:17 +01:00
|
|
|
#ident "$Id: elab_expr.cc,v 1.69 2003/01/27 05:09:17 steve Exp $"
|
1999-09-20 04:21:10 +02:00
|
|
|
#endif
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
|
|
|
|
|
# include "pform.h"
|
|
|
|
|
# include "netlist.h"
|
2001-02-10 21:29:39 +01:00
|
|
|
# include "netmisc.h"
|
2001-06-23 21:53:03 +02:00
|
|
|
# include "util.h"
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, bool) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
2000-12-10 23:01:35 +01:00
|
|
|
cerr << get_line() << ": internal error: I do not know how to elaborate"
|
|
|
|
|
<< " expression. " << endl;
|
|
|
|
|
cerr << get_line() << ": : Expression is: " << *this
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
2000-03-08 05:36:53 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-30 00:57:10 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate binary expressions. This involves elaborating the left
|
|
|
|
|
* and right sides, and creating one of a variety of different NetExpr
|
|
|
|
|
* types.
|
|
|
|
|
*/
|
2002-04-13 04:33:17 +02:00
|
|
|
NetEBinary* PEBinary::elaborate_expr(Design*des, NetScope*scope, bool) const
|
1999-09-30 00:57:10 +02:00
|
|
|
{
|
2001-11-19 02:54:14 +01:00
|
|
|
assert(left_);
|
|
|
|
|
assert(right_);
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*lp = left_->elaborate_expr(des, scope);
|
|
|
|
|
NetExpr*rp = right_->elaborate_expr(des, scope);
|
1999-09-30 00:57:10 +02:00
|
|
|
if ((lp == 0) || (rp == 0)) {
|
|
|
|
|
delete lp;
|
|
|
|
|
delete rp;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 03:54:12 +01:00
|
|
|
|
1999-09-30 00:57:10 +02:00
|
|
|
/* If either expression can be evaluated ahead of time, then
|
|
|
|
|
do so. This can prove helpful later. */
|
|
|
|
|
{ NetExpr*tmp;
|
|
|
|
|
tmp = lp->eval_tree();
|
|
|
|
|
if (tmp) {
|
|
|
|
|
delete lp;
|
|
|
|
|
lp = tmp;
|
|
|
|
|
}
|
2001-11-19 03:54:12 +01:00
|
|
|
|
1999-09-30 00:57:10 +02:00
|
|
|
tmp = rp->eval_tree();
|
|
|
|
|
if (tmp) {
|
|
|
|
|
delete rp;
|
|
|
|
|
rp = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-12 19:22:11 +01:00
|
|
|
NetEBinary*tmp = elaborate_expr_base_(des, lp, rp);
|
2000-03-29 06:06:28 +02:00
|
|
|
return tmp;
|
2000-03-12 19:22:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is common elaboration of the operator. It presumes that the
|
|
|
|
|
* operands are elaborated as necessary, and all I need to do is make
|
|
|
|
|
* the correct NetEBinary object and connect the parameters.
|
|
|
|
|
*/
|
|
|
|
|
NetEBinary* PEBinary::elaborate_expr_base_(Design*des,
|
|
|
|
|
NetExpr*lp, NetExpr*rp) const
|
|
|
|
|
{
|
|
|
|
|
bool flag;
|
1999-09-30 00:57:10 +02:00
|
|
|
NetEBinary*tmp;
|
2000-03-12 19:22:11 +01:00
|
|
|
|
1999-09-30 00:57:10 +02:00
|
|
|
switch (op_) {
|
|
|
|
|
default:
|
|
|
|
|
tmp = new NetEBinary(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'o':
|
|
|
|
|
tmp = new NetEBLogic(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-01-13 04:35:35 +01:00
|
|
|
case '*':
|
|
|
|
|
tmp = new NetEBMult(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-04-28 20:43:23 +02:00
|
|
|
case '/':
|
|
|
|
|
case '%':
|
|
|
|
|
tmp = new NetEBDiv(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
1999-09-30 00:57:10 +02:00
|
|
|
case 'l':
|
|
|
|
|
case 'r':
|
|
|
|
|
tmp = new NetEBShift(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '^':
|
|
|
|
|
case '&':
|
|
|
|
|
case '|':
|
2002-09-18 06:08:45 +02:00
|
|
|
case 'O': // NOR (~|)
|
2002-09-12 17:49:43 +02:00
|
|
|
case 'A': // NAND (~&)
|
1999-09-30 04:43:01 +02:00
|
|
|
case 'X':
|
1999-09-30 00:57:10 +02:00
|
|
|
tmp = new NetEBBits(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
case '-':
|
|
|
|
|
tmp = new NetEBAdd(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'e': /* == */
|
|
|
|
|
case 'E': /* === */
|
|
|
|
|
case 'n': /* != */
|
|
|
|
|
case 'N': /* !== */
|
|
|
|
|
case 'L': /* <= */
|
|
|
|
|
case 'G': /* >= */
|
|
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
tmp = new NetEBComp(op_, lp, rp);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
flag = tmp->set_width(1);
|
|
|
|
|
if (flag == false) {
|
|
|
|
|
cerr << get_line() << ": internal error: "
|
|
|
|
|
"expression bit width of comparison != 1." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-09 06:44:23 +01:00
|
|
|
/*
|
|
|
|
|
* Given a call to a system function, generate the proper expression
|
|
|
|
|
* nodes to represent the call in the netlist. Since we don't support
|
|
|
|
|
* size_tf functions, make assumptions about widths based on some
|
|
|
|
|
* known function names.
|
|
|
|
|
*/
|
2000-05-07 20:20:07 +02:00
|
|
|
NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope) const
|
1999-09-25 04:57:29 +02:00
|
|
|
{
|
2001-12-31 01:08:14 +01:00
|
|
|
|
|
|
|
|
/* Catch the special case that the system function is the
|
|
|
|
|
$signed function. This function is special, in that it does
|
|
|
|
|
not lead to executable code but takes the single parameter
|
|
|
|
|
and makes it into a signed expression. No bits are changed,
|
|
|
|
|
it just changes the interpretation. */
|
|
|
|
|
if (strcmp(path_.peek_name(0), "$signed") == 0) {
|
|
|
|
|
if ((parms_.count() != 1) || (parms_[0] == 0)) {
|
|
|
|
|
cerr << get_line() << ": error: The $signed() function "
|
|
|
|
|
<< "takes exactly one(1) argument." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PExpr*expr = parms_[0];
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr*sub = expr->elaborate_expr(des, scope, true);
|
2001-12-31 01:08:14 +01:00
|
|
|
sub->cast_signed(true);
|
|
|
|
|
return sub;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-05 23:11:49 +02:00
|
|
|
/* Interpret the internal $sizeof system function to return
|
|
|
|
|
the bit width of the sub-expression. The value of the
|
|
|
|
|
sub-expression is not used, so the expression itself can be
|
|
|
|
|
deleted. */
|
2002-05-24 02:44:54 +02:00
|
|
|
if ((strcmp(path_.peek_name(0), "$sizeof") == 0)
|
|
|
|
|
|| (strcmp(path_.peek_name(0), "$bits") == 0)) {
|
2002-05-05 23:11:49 +02:00
|
|
|
if ((parms_.count() != 1) || (parms_[0] == 0)) {
|
2002-05-24 02:44:54 +02:00
|
|
|
cerr << get_line() << ": error: The $bits() function "
|
2002-05-05 23:11:49 +02:00
|
|
|
<< "takes exactly one(1) argument." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-24 02:44:54 +02:00
|
|
|
if (strcmp(path_.peek_name(0), "$sizeof") == 0)
|
|
|
|
|
cerr << get_line() << ": warning: $sizeof is deprecated."
|
|
|
|
|
<< " Use $bits() instead." << endl;
|
|
|
|
|
|
2002-05-05 23:11:49 +02:00
|
|
|
PExpr*expr = parms_[0];
|
|
|
|
|
NetExpr*sub = expr->elaborate_expr(des, scope, true);
|
2002-08-19 04:39:16 +02:00
|
|
|
verinum val (sub->expr_width(), 8*sizeof(unsigned));
|
2002-05-05 23:11:49 +02:00
|
|
|
delete sub;
|
|
|
|
|
|
|
|
|
|
sub = new NetEConst(val);
|
|
|
|
|
sub->set_line(*this);
|
|
|
|
|
|
|
|
|
|
return sub;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-07 20:20:07 +02:00
|
|
|
unsigned wid = 32;
|
2000-05-04 05:37:58 +02:00
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
if (strcmp(path_.peek_name(0), "$time") == 0)
|
2000-05-07 20:20:07 +02:00
|
|
|
wid = 64;
|
2002-12-21 01:55:57 +01:00
|
|
|
if (strcmp(path_.peek_name(0), "$simtime") == 0)
|
|
|
|
|
wid = 64;
|
2002-01-11 06:25:45 +01:00
|
|
|
if (strcmp(path_.peek_name(0), "$stime") == 0)
|
|
|
|
|
wid = 32;
|
2000-05-04 05:37:58 +02:00
|
|
|
|
2001-02-09 06:44:23 +01:00
|
|
|
|
|
|
|
|
/* How many parameters are there? The Verilog language allows
|
|
|
|
|
empty parameters in certain contexts, so the parser will
|
|
|
|
|
allow things like func(1,,3). It will also cause func() to
|
|
|
|
|
be interpreted as a single empty parameter.
|
|
|
|
|
|
|
|
|
|
Functions cannot really take empty parameters, but the
|
2003-01-27 06:09:17 +01:00
|
|
|
case ``func()'' is the same as no parameters at all. So
|
2001-02-09 06:44:23 +01:00
|
|
|
catch that special case here. */
|
|
|
|
|
unsigned nparms = parms_.count();
|
|
|
|
|
if ((nparms == 1) && (parms_[0] == 0))
|
|
|
|
|
nparms = 0;
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetESFunc*fun = new NetESFunc(path_.peek_name(0), wid, nparms);
|
2001-02-09 06:44:23 +01:00
|
|
|
|
|
|
|
|
/* Now run through the expected parameters. If we find that
|
2001-02-10 21:29:39 +01:00
|
|
|
there are missing parameters, print an error message.
|
|
|
|
|
|
|
|
|
|
While we're at it, try to evaluate the function parameter
|
|
|
|
|
expression as much as possible, and use the reduced
|
|
|
|
|
expression if one is created. */
|
2001-02-09 06:44:23 +01:00
|
|
|
|
|
|
|
|
unsigned missing_parms = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
2000-05-07 20:20:07 +02:00
|
|
|
PExpr*expr = parms_[idx];
|
2001-02-09 06:44:23 +01:00
|
|
|
if (expr) {
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr*tmp1 = expr->elaborate_expr(des, scope, true);
|
2001-02-10 21:29:39 +01:00
|
|
|
if (NetExpr*tmp2 = tmp1->eval_tree()) {
|
|
|
|
|
delete tmp1;
|
|
|
|
|
fun->parm(idx, tmp2);
|
|
|
|
|
} else {
|
|
|
|
|
fun->parm(idx, tmp1);
|
|
|
|
|
}
|
2001-02-09 06:44:23 +01:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
missing_parms += 1;
|
|
|
|
|
fun->parm(idx, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (missing_parms > 0) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << get_line() << ": error: The function "
|
|
|
|
|
<< path_.peek_name(0)
|
2001-02-09 06:44:23 +01:00
|
|
|
<< " has been called with empty parameters." << endl;
|
|
|
|
|
cerr << get_line() << ": : Verilog doesn't allow "
|
|
|
|
|
<< "passing empty parameters to functions." << endl;
|
|
|
|
|
des->errors += 1;
|
2000-05-07 20:20:07 +02:00
|
|
|
}
|
2000-05-04 05:37:58 +02:00
|
|
|
|
2000-05-07 20:20:07 +02:00
|
|
|
return fun;
|
1999-09-25 04:57:29 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, bool) const
|
1999-09-25 04:57:29 +02:00
|
|
|
{
|
2001-12-03 05:47:14 +01:00
|
|
|
if (path_.peek_name(0)[0] == '$')
|
2000-03-08 05:36:53 +01:00
|
|
|
return elaborate_sfunc_(des, scope);
|
1999-09-25 04:57:29 +02:00
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetFuncDef*def = des->find_function(scope, path_);
|
1999-09-25 04:57:29 +02:00
|
|
|
if (def == 0) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << get_line() << ": error: No function " << path_ <<
|
2000-03-08 05:36:53 +01:00
|
|
|
" in this context (" << scope->name() << ")." << endl;
|
1999-09-25 04:57:29 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(def);
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetScope*dscope = def->scope();
|
2000-05-02 05:13:30 +02:00
|
|
|
assert(dscope);
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2002-03-09 03:10:22 +01:00
|
|
|
if (! check_call_matches_definition_(des, dscope))
|
|
|
|
|
return 0;
|
2001-01-13 23:20:08 +01:00
|
|
|
|
|
|
|
|
unsigned parms_count = parms_.count();
|
|
|
|
|
if ((parms_count == 1) && (parms_[0] == 0))
|
|
|
|
|
parms_count = 0;
|
|
|
|
|
|
2002-03-09 03:10:22 +01:00
|
|
|
|
2001-06-30 23:28:35 +02:00
|
|
|
|
2001-01-13 23:20:08 +01:00
|
|
|
svector<NetExpr*> parms (parms_count);
|
1999-09-25 04:57:29 +02:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
/* Elaborate the input expressions for the function. This is
|
|
|
|
|
done in the scope of the function call, and not the scope
|
|
|
|
|
of the function being called. The scope of the called
|
|
|
|
|
function is elaborated when the definition is elaborated. */
|
|
|
|
|
|
2001-02-09 06:44:23 +01:00
|
|
|
unsigned missing_parms = 0;
|
1999-09-25 04:57:29 +02:00
|
|
|
for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) {
|
2001-01-13 23:20:08 +01:00
|
|
|
PExpr*tmp = parms_[idx];
|
2001-02-09 06:44:23 +01:00
|
|
|
if (tmp) {
|
|
|
|
|
parms[idx] = tmp->elaborate_expr(des, scope);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
missing_parms += 1;
|
|
|
|
|
parms[idx] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (missing_parms > 0) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << get_line() << ": error: The function " << path_
|
2001-02-09 06:44:23 +01:00
|
|
|
<< " has been called with empty parameters." << endl;
|
|
|
|
|
cerr << get_line() << ": : Verilog doesn't allow "
|
|
|
|
|
<< "passing empty parameters to functions." << endl;
|
|
|
|
|
des->errors += 1;
|
1999-09-25 04:57:29 +02:00
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
|
|
|
|
|
/* Look for the return value signal for the called
|
|
|
|
|
function. This return value is a magic signal in the scope
|
|
|
|
|
of the function, that has the name of the function. The
|
2001-06-23 21:53:03 +02:00
|
|
|
function code assigns to this signal to return a value.
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2001-06-23 21:53:03 +02:00
|
|
|
dscope, in this case, is the scope of the function, so the
|
|
|
|
|
return value is the name within that scope. */
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetNet*res = dscope->find_signal(dscope->basename());
|
1999-09-25 04:57:29 +02:00
|
|
|
if (res == 0) {
|
|
|
|
|
cerr << get_line() << ": internal error: Unable to locate "
|
2001-12-03 05:47:14 +01:00
|
|
|
"function return value for " << path_ << " in " <<
|
1999-09-25 04:57:29 +02:00
|
|
|
def->name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(res);
|
|
|
|
|
NetESignal*eres = new NetESignal(res);
|
|
|
|
|
assert(eres);
|
2001-04-06 04:28:02 +02:00
|
|
|
NetEUFunc*func = new NetEUFunc(dscope, eres, parms);
|
1999-09-25 04:57:29 +02:00
|
|
|
return func;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, bool) const
|
2000-01-01 07:18:00 +01:00
|
|
|
{
|
2002-05-05 23:11:49 +02:00
|
|
|
NetExpr* repeat = 0;
|
2000-01-01 07:18:00 +01:00
|
|
|
|
|
|
|
|
/* If there is a repeat expression, then evaluate the constant
|
|
|
|
|
value and set the repeat count. */
|
|
|
|
|
if (repeat_) {
|
2001-02-10 21:29:39 +01:00
|
|
|
NetExpr*tmp = elab_and_eval(des, scope, repeat_);
|
|
|
|
|
assert(tmp);
|
|
|
|
|
NetEConst*rep = dynamic_cast<NetEConst*>(tmp);
|
|
|
|
|
|
|
|
|
|
if (rep == 0) {
|
2000-01-01 07:18:00 +01:00
|
|
|
cerr << get_line() << ": error: "
|
|
|
|
|
"concatenation repeat expression cannot be evaluated."
|
|
|
|
|
<< endl;
|
2001-02-10 21:29:39 +01:00
|
|
|
cerr << get_line() << ": : The expression is: "
|
|
|
|
|
<< *tmp << endl;
|
2000-01-01 07:18:00 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-05 23:11:49 +02:00
|
|
|
repeat = rep;
|
2000-01-01 07:18:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the empty concat expression. */
|
|
|
|
|
NetEConcat*tmp = new NetEConcat(parms_.count(), repeat);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
|
2002-06-14 23:38:41 +02:00
|
|
|
unsigned wid_sum = 0;
|
|
|
|
|
|
2000-01-01 07:18:00 +01:00
|
|
|
/* Elaborate all the parameters and attach them to the concat node. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
|
|
|
|
|
assert(parms_[idx]);
|
2002-05-06 04:30:27 +02:00
|
|
|
NetExpr*ex = elab_and_eval(des, scope, parms_[idx]);
|
2000-01-01 07:18:00 +01:00
|
|
|
if (ex == 0) continue;
|
2000-09-26 07:05:58 +02:00
|
|
|
|
2000-01-01 07:18:00 +01:00
|
|
|
ex->set_line(*parms_[idx]);
|
2000-09-26 07:05:58 +02:00
|
|
|
|
|
|
|
|
if (! ex->has_width()) {
|
|
|
|
|
cerr << ex->get_line() << ": error: operand of "
|
|
|
|
|
<< "concatenation has indefinite width: "
|
|
|
|
|
<< *ex << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-14 23:38:41 +02:00
|
|
|
wid_sum += ex->expr_width();
|
2000-01-01 07:18:00 +01:00
|
|
|
tmp->set(idx, ex);
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-14 23:38:41 +02:00
|
|
|
tmp->set_width(wid_sum * tmp->repeat());
|
|
|
|
|
|
2000-01-01 07:18:00 +01:00
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, bool) const
|
2001-01-15 00:04:55 +01:00
|
|
|
{
|
2003-01-26 22:15:58 +01:00
|
|
|
NetECReal*tmp = new NetECReal(*value_);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
2001-01-15 00:04:55 +01:00
|
|
|
}
|
|
|
|
|
|
2001-12-29 21:41:30 +01:00
|
|
|
/*
|
|
|
|
|
* Elaborate an identifier in an expression. The identifier can be a
|
|
|
|
|
* parameter name, a signal name or a memory name. It can also be a
|
|
|
|
|
* scope name (Return a NetEScope) but only certain callers can use
|
|
|
|
|
* scope names. However, we still support it here.
|
|
|
|
|
*
|
|
|
|
|
* Function names are not handled here, they are detected by the
|
|
|
|
|
* parser and are elaborated by PECallFunction.
|
|
|
|
|
*
|
|
|
|
|
* The signal name may be escaped, but that affects nothing here.
|
|
|
|
|
*/
|
2002-04-13 04:33:17 +02:00
|
|
|
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|
|
|
|
bool sys_task_arg) const
|
1999-09-20 04:21:10 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
1999-09-20 04:21:10 +02:00
|
|
|
|
|
|
|
|
// If the identifier name is a parameter name, then return
|
|
|
|
|
// a reference to the parameter expression.
|
2001-12-03 05:47:14 +01:00
|
|
|
if (const NetExpr*ex = des->find_parameter(scope, path_)) {
|
1999-09-20 04:21:10 +02:00
|
|
|
NetExpr*tmp;
|
|
|
|
|
if (dynamic_cast<const NetExpr*>(ex))
|
|
|
|
|
tmp = ex->dup_expr();
|
|
|
|
|
else
|
2001-12-03 05:47:14 +01:00
|
|
|
tmp = new NetEParam(des, scope, path_);
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2002-01-28 01:52:41 +01:00
|
|
|
if (msb_ && lsb_) {
|
2002-04-27 04:38:04 +02:00
|
|
|
/* If the parameter has a part select, we support
|
|
|
|
|
it by pulling the right bits out and making a
|
|
|
|
|
sized unsigned constant. This code assumes the
|
|
|
|
|
lsb of a parameter is 0 and the msb is the
|
|
|
|
|
width of the parameter. */
|
|
|
|
|
|
|
|
|
|
verinum*lsn = lsb_->eval_const(des, scope);
|
|
|
|
|
verinum*msn = msb_->eval_const(des, scope);
|
|
|
|
|
if ((lsn == 0) || (msn == 0)) {
|
|
|
|
|
cerr << get_line() << ": error: "
|
2003-01-27 06:09:17 +01:00
|
|
|
"Part select expressions must be "
|
2002-04-27 04:38:04 +02:00
|
|
|
"constant expressions." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long lsb = lsn->as_long();
|
|
|
|
|
long msb = msn->as_long();
|
|
|
|
|
if ((lsb < 0) || (msb < lsb)) {
|
|
|
|
|
cerr << get_line() << ": error: invalid part "
|
|
|
|
|
<< "select: " << path_
|
|
|
|
|
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
|
|
|
|
assert(le);
|
|
|
|
|
|
|
|
|
|
verinum result (verinum::V0, msb-lsb+1, true);
|
|
|
|
|
verinum exl = le->value();
|
|
|
|
|
|
|
|
|
|
/* Pull the bits from the parameter, one at a
|
|
|
|
|
time. If the bit is within the range, simply
|
|
|
|
|
copy it to the result. If the bit is outside
|
|
|
|
|
the range, we sign extend signed unsized
|
|
|
|
|
numbers, zero extend unsigned unsigned numbers,
|
|
|
|
|
and X extend sized numbers. */
|
|
|
|
|
for (long idx = lsb ; idx <= msb ; idx += 1) {
|
|
|
|
|
if (idx < exl.len())
|
|
|
|
|
result.set(idx-lsb, exl.get(idx));
|
2002-04-27 07:03:46 +02:00
|
|
|
else if (exl.is_string())
|
|
|
|
|
result.set(idx-lsb, verinum::V0);
|
2002-04-27 04:38:04 +02:00
|
|
|
else if (exl.has_len())
|
|
|
|
|
result.set(idx-lsb, verinum::Vx);
|
|
|
|
|
else if (exl.has_sign())
|
|
|
|
|
result.set(idx-lsb, exl.get(exl.len()-1));
|
|
|
|
|
else
|
|
|
|
|
result.set(idx-lsb, verinum::V0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-27 07:03:46 +02:00
|
|
|
/* If the input is a string, and the part select
|
|
|
|
|
is working on byte boundaries, then the result
|
|
|
|
|
can be made into a string. */
|
|
|
|
|
if (exl.is_string()
|
|
|
|
|
&& (lsb%8 == 0)
|
|
|
|
|
&& (result.len()%8 == 0))
|
|
|
|
|
result = verinum(result.as_string());
|
|
|
|
|
|
2002-04-27 04:38:04 +02:00
|
|
|
delete tmp;
|
|
|
|
|
tmp = new NetEConst(result);
|
2002-01-28 01:52:41 +01:00
|
|
|
|
|
|
|
|
} else if (msb_) {
|
|
|
|
|
/* Handle the case where a parameter has a bit
|
|
|
|
|
select attached to it. Generate a NetESelect
|
|
|
|
|
object to select the bit as desired. */
|
|
|
|
|
NetExpr*mtmp = msb_->elaborate_expr(des, scope);
|
2002-04-25 07:04:31 +02:00
|
|
|
if (! dynamic_cast<NetEConst*>(mtmp)) {
|
|
|
|
|
NetExpr*re = mtmp->eval_tree();
|
|
|
|
|
if (re) {
|
|
|
|
|
delete mtmp;
|
|
|
|
|
mtmp = re;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Let's first try to get constant values for both
|
|
|
|
|
the parameter and the bit select. If they are
|
|
|
|
|
both constant, then evaluate the bit select and
|
|
|
|
|
return instead a single-bit constant. */
|
|
|
|
|
|
|
|
|
|
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
|
|
|
|
NetEConst*re = dynamic_cast<NetEConst*>(mtmp);
|
|
|
|
|
if (le && re) {
|
|
|
|
|
|
|
|
|
|
verinum lv = le->value();
|
|
|
|
|
verinum rv = re->value();
|
|
|
|
|
verinum::V rb = verinum::Vx;
|
|
|
|
|
|
|
|
|
|
long ridx = rv.as_long();
|
|
|
|
|
if ((ridx >= 0) && (ridx < lv.len())) {
|
|
|
|
|
rb = lv[ridx];
|
|
|
|
|
|
|
|
|
|
} else if ((ridx >= 0) && (!lv.has_len())) {
|
|
|
|
|
if (lv.has_sign())
|
|
|
|
|
rb = lv[lv.len()-1];
|
|
|
|
|
else
|
|
|
|
|
rb = verinum::V0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*re = new NetEConst(verinum(rb, 1));
|
|
|
|
|
delete tmp;
|
|
|
|
|
delete mtmp;
|
|
|
|
|
tmp = re;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
NetESelect*stmp = new NetESelect(tmp, mtmp, 1);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
tmp = stmp;
|
|
|
|
|
}
|
2002-01-28 01:52:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the identifier names a signal (a register or wire)
|
|
|
|
|
// then create a NetESignal node to handle it.
|
2001-12-03 05:47:14 +01:00
|
|
|
if (NetNet*net = des->find_signal(scope, path_)) {
|
1999-09-20 04:21:10 +02:00
|
|
|
|
|
|
|
|
// If this is a part select of a signal, then make a new
|
|
|
|
|
// temporary signal that is connected to just the
|
2000-08-26 03:31:29 +02:00
|
|
|
// selected bits. The lsb_ and msb_ expressions are from
|
|
|
|
|
// the foo[msb:lsb] expression in the original.
|
1999-09-20 04:21:10 +02:00
|
|
|
if (lsb_) {
|
|
|
|
|
assert(msb_);
|
2001-11-07 05:01:59 +01:00
|
|
|
verinum*lsn = lsb_->eval_const(des, scope);
|
|
|
|
|
verinum*msn = msb_->eval_const(des, scope);
|
1999-09-20 04:21:10 +02:00
|
|
|
if ((lsn == 0) || (msn == 0)) {
|
1999-09-25 04:57:29 +02:00
|
|
|
cerr << get_line() << ": error: "
|
2003-01-27 06:09:17 +01:00
|
|
|
"Part select expressions must be "
|
1999-09-25 04:57:29 +02:00
|
|
|
"constant expressions." << endl;
|
1999-09-20 04:21:10 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(lsn);
|
|
|
|
|
assert(msn);
|
2000-08-26 03:31:29 +02:00
|
|
|
|
|
|
|
|
/* The indices of part selects are signed
|
|
|
|
|
integers, so allow negative values. However,
|
|
|
|
|
the width that they represent is
|
|
|
|
|
unsigned. Remember that any order is possible,
|
2003-01-27 06:09:17 +01:00
|
|
|
i.e., [1:0], [-4,6], etc. */
|
2000-08-26 03:31:29 +02:00
|
|
|
|
|
|
|
|
long lsv = lsn->as_long();
|
|
|
|
|
long msv = msn->as_long();
|
1999-09-20 04:21:10 +02:00
|
|
|
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
2000-08-26 03:31:29 +02:00
|
|
|
if (wid > net->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": error: part select ["
|
|
|
|
|
<< msv << ":" << lsv << "] out of range."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
delete lsn;
|
|
|
|
|
delete msn;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1999-09-20 04:21:10 +02:00
|
|
|
assert(wid <= net->pin_count());
|
2000-08-26 03:31:29 +02:00
|
|
|
|
|
|
|
|
if (net->sb_to_idx(msv) < net->sb_to_idx(lsv)) {
|
|
|
|
|
cerr << get_line() << ": error: part select ["
|
|
|
|
|
<< msv << ":" << lsv << "] out of order."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
delete lsn;
|
|
|
|
|
delete msn;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (net->sb_to_idx(msv) >= net->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": error: part select ["
|
|
|
|
|
<< msv << ":" << lsv << "] out of range."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
delete lsn;
|
|
|
|
|
delete msn;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2001-07-27 06:51:44 +02:00
|
|
|
NetESignal*tmp = new NetESignal(net,
|
|
|
|
|
net->sb_to_idx(msv),
|
|
|
|
|
net->sb_to_idx(lsv));
|
1999-11-29 00:42:02 +01:00
|
|
|
tmp->set_line(*this);
|
1999-09-20 04:21:10 +02:00
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the bit select is constant, then treat it similar
|
|
|
|
|
// to the part select, so that I save the effort of
|
|
|
|
|
// making a mux part in the netlist.
|
|
|
|
|
verinum*msn;
|
2001-11-07 05:01:59 +01:00
|
|
|
if (msb_ && (msn = msb_->eval_const(des, scope))) {
|
1999-09-20 04:21:10 +02:00
|
|
|
assert(idx_ == 0);
|
|
|
|
|
unsigned long msv = msn->as_ulong();
|
2000-03-20 17:57:22 +01:00
|
|
|
unsigned idx = net->sb_to_idx(msv);
|
|
|
|
|
|
|
|
|
|
if (idx >= net->pin_count()) {
|
2002-09-21 23:28:18 +02:00
|
|
|
/* The bit select is out of range of the
|
|
|
|
|
vector. This is legal, but returns a
|
|
|
|
|
constant 1'bx value. */
|
|
|
|
|
verinum x (verinum::Vx);
|
|
|
|
|
NetEConst*tmp = new NetEConst(x);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
|
|
|
|
|
cerr << get_line() << ": warning: Bit select ["
|
|
|
|
|
<< msv << "] out of range of vector "
|
2000-03-20 17:57:22 +01:00
|
|
|
<< net->name() << "[" << net->msb()
|
|
|
|
|
<< ":" << net->lsb() << "]." << endl;
|
2002-09-21 23:28:18 +02:00
|
|
|
cerr << get_line() << ": : Replacing "
|
|
|
|
|
<< "expression with a constant 1'bx." << endl;
|
|
|
|
|
delete msn;
|
|
|
|
|
return tmp;
|
2000-03-20 17:57:22 +01:00
|
|
|
}
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2001-07-27 06:51:44 +02:00
|
|
|
NetESignal*tmp = new NetESignal(net, idx, idx);
|
1999-09-20 04:21:10 +02:00
|
|
|
tmp->set_line(*this);
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetESignal*node = new NetESignal(net);
|
|
|
|
|
assert(idx_ == 0);
|
|
|
|
|
|
|
|
|
|
// Non-constant bit select? punt and make a subsignal
|
|
|
|
|
// device to mux the bit in the net.
|
|
|
|
|
if (msb_) {
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*ex = msb_->elaborate_expr(des, scope);
|
2001-07-27 06:51:44 +02:00
|
|
|
NetEBitSel*ss = new NetEBitSel(node, ex);
|
1999-09-20 04:21:10 +02:00
|
|
|
ss->set_line(*this);
|
|
|
|
|
return ss;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All else fails, return the signal itself as the
|
|
|
|
|
// expression.
|
|
|
|
|
assert(msb_ == 0);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the identifier names a memory, then this is a
|
|
|
|
|
// memory reference and I must generate a NetEMemory
|
|
|
|
|
// object to handle it.
|
2001-12-03 05:47:14 +01:00
|
|
|
if (NetMemory*mem = des->find_memory(scope, path_)) {
|
1999-10-18 02:02:21 +02:00
|
|
|
if (msb_ == 0) {
|
2002-04-13 04:33:17 +02:00
|
|
|
|
|
|
|
|
// If this memory is an argument to a system task,
|
|
|
|
|
// then it is OK for it to not have an index.
|
|
|
|
|
if (sys_task_arg) {
|
|
|
|
|
NetEMemory*node = new NetEMemory(mem);
|
|
|
|
|
node->set_line(*this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If it is not a simple system task argument,
|
|
|
|
|
// this a missing index is an error.
|
|
|
|
|
cerr << get_line() << ": error: memory " << mem->name()
|
|
|
|
|
<< " needs an index in this context." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
1999-10-18 02:02:21 +02:00
|
|
|
}
|
2002-04-13 04:33:17 +02:00
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
assert(msb_ != 0);
|
2000-05-19 03:55:09 +02:00
|
|
|
if (lsb_) {
|
|
|
|
|
cerr << get_line() << ": error: part select of a memory: "
|
|
|
|
|
<< mem->name() << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
assert(lsb_ == 0);
|
|
|
|
|
assert(idx_ == 0);
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*i = msb_->elaborate_expr(des, scope);
|
1999-11-10 03:52:24 +01:00
|
|
|
if (msb_ && i == 0) {
|
2002-09-18 06:08:45 +02:00
|
|
|
cerr << get_line() << ": error: Unable to elaborate "
|
1999-09-20 04:21:10 +02:00
|
|
|
"index expression `" << *msb_ << "'" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEMemory*node = new NetEMemory(mem, i);
|
|
|
|
|
node->set_line(*this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
// If the identifier names a variable of some sort, then this
|
|
|
|
|
// is a variable reference.
|
|
|
|
|
if (NetVariable*var = des->find_variable(scope, path_)) {
|
|
|
|
|
|
|
|
|
|
NetEVariable*node = new NetEVariable(var);
|
|
|
|
|
node->set_line(*this);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-30 00:22:40 +02:00
|
|
|
// Finally, if this is a scope name, then return that. Look
|
|
|
|
|
// first to see if this is a name of a local scope. Failing
|
2003-01-27 06:09:17 +01:00
|
|
|
// that, search globally for a hierarchical name.
|
2001-12-03 05:47:14 +01:00
|
|
|
if ((path_.peek_name(1) == 0))
|
|
|
|
|
if (NetScope*nsc = scope->child(path_.peek_name(0))) {
|
|
|
|
|
NetEScope*tmp = new NetEScope(nsc);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
2001-07-30 00:22:40 +02:00
|
|
|
|
|
|
|
|
// NOTE: This search pretty much assumes that text_ is a
|
|
|
|
|
// complete hierarchical name, since there is no mention of
|
|
|
|
|
// the current scope in the call to find_scope.
|
2001-12-03 05:47:14 +01:00
|
|
|
if (NetScope*nsc = des->find_scope(path_)) {
|
1999-11-30 05:54:01 +01:00
|
|
|
NetEScope*tmp = new NetEScope(nsc);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
// I cannot interpret this identifier. Error message.
|
1999-09-25 04:57:29 +02:00
|
|
|
cerr << get_line() << ": error: Unable to bind wire/reg/memory "
|
2001-12-03 05:47:14 +01:00
|
|
|
"`" << path_ << "' in `" << scope->name() << "'" << endl;
|
1999-09-20 04:21:10 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, bool) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
|
|
|
|
assert(value_);
|
|
|
|
|
NetEConst*tmp = new NetEConst(*value_);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-13 04:33:17 +02:00
|
|
|
NetEConst* PEString::elaborate_expr(Design*des, NetScope*, bool) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
|
|
|
|
NetEConst*tmp = new NetEConst(value());
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-30 02:48:49 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate the Ternary operator. I know that the expressions were
|
|
|
|
|
* parsed so I can presume that they exist, and call elaboration
|
|
|
|
|
* methods. If any elaboration fails, then give up and return 0.
|
|
|
|
|
*/
|
2002-04-13 04:33:17 +02:00
|
|
|
NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, bool) const
|
1999-09-30 02:48:49 +02:00
|
|
|
{
|
|
|
|
|
assert(expr_);
|
|
|
|
|
assert(tru_);
|
|
|
|
|
assert(fal_);
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*con = expr_->elaborate_expr(des, scope);
|
1999-09-30 02:48:49 +02:00
|
|
|
if (con == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*tru = tru_->elaborate_expr(des, scope);
|
1999-09-30 02:48:49 +02:00
|
|
|
if (tru == 0) {
|
|
|
|
|
delete con;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*fal = fal_->elaborate_expr(des, scope);
|
1999-09-30 02:48:49 +02:00
|
|
|
if (fal == 0) {
|
|
|
|
|
delete con;
|
|
|
|
|
delete tru;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetETernary*res = new NetETernary(con, tru, fal);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-14 05:55:25 +02:00
|
|
|
NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, bool) const
|
2000-03-08 05:36:53 +01:00
|
|
|
{
|
|
|
|
|
NetExpr*ip = expr_->elaborate_expr(des, scope);
|
|
|
|
|
if (ip == 0) return 0;
|
|
|
|
|
|
|
|
|
|
/* Should we evaluate expressions ahead of time,
|
|
|
|
|
* just like in PEBinary::elaborate_expr() ?
|
|
|
|
|
*/
|
|
|
|
|
|
2002-04-14 05:55:25 +02:00
|
|
|
NetExpr*tmp;
|
2000-03-08 05:36:53 +01:00
|
|
|
switch (op_) {
|
|
|
|
|
default:
|
|
|
|
|
tmp = new NetEUnary(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
2002-04-14 05:55:25 +02:00
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
|
if (NetEConst*ipc = dynamic_cast<NetEConst*>(ip)) {
|
2003-01-26 22:15:58 +01:00
|
|
|
/* When taking the - of a number, turn it into a
|
|
|
|
|
signed expression and extend it one bit to
|
|
|
|
|
accommodate a possible sign bit. */
|
2002-04-14 05:55:25 +02:00
|
|
|
verinum val = ipc->value();
|
2003-01-26 22:15:58 +01:00
|
|
|
verinum zero (verinum::V0, val.len()+1, val.has_len());
|
2002-04-14 05:55:25 +02:00
|
|
|
val = zero - val;
|
2003-01-26 22:15:58 +01:00
|
|
|
val.has_sign(true);
|
2002-04-14 05:55:25 +02:00
|
|
|
tmp = new NetEConst(val);
|
|
|
|
|
delete ip;
|
|
|
|
|
} else {
|
|
|
|
|
tmp = new NetEUnary(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
tmp = ip;
|
|
|
|
|
break;
|
|
|
|
|
|
2000-11-29 06:24:00 +01:00
|
|
|
case '!': // Logical NOT
|
2002-04-14 23:16:48 +02:00
|
|
|
/* If the operand to unary ! is a constant, then I can
|
|
|
|
|
evaluate this expression here and return a logical
|
|
|
|
|
constant in its place. */
|
|
|
|
|
if (NetEConst*ipc = dynamic_cast<NetEConst*>(ip)) {
|
|
|
|
|
verinum val = ipc->value();
|
|
|
|
|
unsigned v1 = 0;
|
|
|
|
|
unsigned vx = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
|
|
|
|
switch (val[idx]) {
|
|
|
|
|
case verinum::V0:
|
|
|
|
|
break;
|
|
|
|
|
case verinum::V1:
|
|
|
|
|
v1 += 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
vx += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum::V res;
|
|
|
|
|
if (v1 > 0)
|
|
|
|
|
res = verinum::V0;
|
|
|
|
|
else if (vx > 0)
|
|
|
|
|
res = verinum::Vx;
|
|
|
|
|
else
|
|
|
|
|
res = verinum::V1;
|
|
|
|
|
|
|
|
|
|
verinum vres (res, 1, true);
|
|
|
|
|
tmp = new NetEConst(vres);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
delete ip;
|
|
|
|
|
} else {
|
|
|
|
|
tmp = new NetEUReduce(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2000-11-29 06:24:00 +01:00
|
|
|
case '&': // Reduction AND
|
2001-01-02 05:21:13 +01:00
|
|
|
case '|': // Reduction OR
|
2000-11-29 06:24:00 +01:00
|
|
|
case '^': // Reduction XOR
|
|
|
|
|
case 'A': // Reduction NAND (~&)
|
|
|
|
|
case 'N': // Reduction NOR (~|)
|
|
|
|
|
case 'X': // Reduction NXOR (~^)
|
|
|
|
|
tmp = new NetEUReduce(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
2002-04-14 05:55:25 +02:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
case '~':
|
|
|
|
|
tmp = new NetEUBits(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-11-19 03:54:12 +01:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
/*
|
|
|
|
|
* $Log: elab_expr.cc,v $
|
2003-01-27 06:09:17 +01:00
|
|
|
* Revision 1.69 2003/01/27 05:09:17 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2003-01-26 22:15:58 +01:00
|
|
|
* Revision 1.68 2003/01/26 21:15:58 steve
|
|
|
|
|
* Rework expression parsing and elaboration to
|
|
|
|
|
* accommodate real/realtime values and expressions.
|
|
|
|
|
*
|
2002-12-21 01:55:57 +01:00
|
|
|
* Revision 1.67 2002/12/21 00:55:57 steve
|
|
|
|
|
* The $time system task returns the integer time
|
|
|
|
|
* scaled to the local units. Change the internal
|
|
|
|
|
* implementation of vpiSystemTime the $time functions
|
|
|
|
|
* to properly account for this. Also add $simtime
|
|
|
|
|
* to get the simulation time.
|
|
|
|
|
*
|
2002-09-21 23:28:18 +02:00
|
|
|
* Revision 1.66 2002/09/21 21:28:18 steve
|
|
|
|
|
* Allow constant bit selects out of range.
|
|
|
|
|
*
|
2002-09-18 06:08:45 +02:00
|
|
|
* Revision 1.65 2002/09/18 04:08:45 steve
|
|
|
|
|
* Spelling errors.
|
|
|
|
|
*
|
2002-09-12 17:49:43 +02:00
|
|
|
* Revision 1.64 2002/09/12 15:49:43 steve
|
|
|
|
|
* Add support for binary nand operator.
|
|
|
|
|
*
|
2002-08-19 04:39:16 +02:00
|
|
|
* Revision 1.63 2002/08/19 02:39:16 steve
|
|
|
|
|
* Support parameters with defined ranges.
|
|
|
|
|
*
|
2002-08-12 03:34:58 +02:00
|
|
|
* Revision 1.62 2002/08/12 01:34:58 steve
|
|
|
|
|
* conditional ident string using autoconfig.
|
|
|
|
|
*
|
2002-06-14 23:38:41 +02:00
|
|
|
* Revision 1.61 2002/06/14 21:38:41 steve
|
|
|
|
|
* Fix expression width for repeat concatenations.
|
|
|
|
|
*
|
2002-05-24 02:44:54 +02:00
|
|
|
* Revision 1.60 2002/05/24 00:44:54 steve
|
|
|
|
|
* Add support for $bits (SystemVerilog)
|
|
|
|
|
*
|
2002-05-06 04:30:27 +02:00
|
|
|
* Revision 1.59 2002/05/06 02:30:27 steve
|
|
|
|
|
* Allow parameters in concatenation of widths are defined.
|
|
|
|
|
*
|
2002-05-05 23:11:49 +02:00
|
|
|
* Revision 1.58 2002/05/05 21:11:49 steve
|
|
|
|
|
* Put off evaluation of concatenation repeat expresions
|
|
|
|
|
* until after parameters are defined. This allows parms
|
|
|
|
|
* to be used in repeat expresions.
|
|
|
|
|
*
|
|
|
|
|
* Add the builtin $signed system function.
|
|
|
|
|
*
|
2002-04-27 07:03:46 +02:00
|
|
|
* Revision 1.57 2002/04/27 05:03:46 steve
|
|
|
|
|
* Preserve stringiness string part select and concatenation.
|
|
|
|
|
*
|
2002-04-27 04:38:04 +02:00
|
|
|
* Revision 1.56 2002/04/27 02:38:04 steve
|
|
|
|
|
* Support selecting bits from parameters.
|
|
|
|
|
*
|
2002-04-25 07:04:31 +02:00
|
|
|
* Revision 1.55 2002/04/25 05:04:31 steve
|
|
|
|
|
* Evaluate constant bit select of constants.
|
|
|
|
|
*
|
2002-04-14 23:16:48 +02:00
|
|
|
* Revision 1.54 2002/04/14 21:16:48 steve
|
|
|
|
|
* Evaluate logical not at elaboration time.
|
|
|
|
|
*
|
2002-04-14 05:55:25 +02:00
|
|
|
* Revision 1.53 2002/04/14 03:55:25 steve
|
|
|
|
|
* Precalculate unary - if possible.
|
|
|
|
|
*
|
2002-04-13 04:33:17 +02:00
|
|
|
* Revision 1.52 2002/04/13 02:33:17 steve
|
|
|
|
|
* Detect missing indices to memories (PR#421)
|
|
|
|
|
*
|
2002-03-09 03:10:22 +01:00
|
|
|
* Revision 1.51 2002/03/09 02:10:22 steve
|
|
|
|
|
* Add the NetUserFunc netlist node.
|
|
|
|
|
*
|
2002-01-28 01:52:41 +01:00
|
|
|
* Revision 1.50 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.
|
|
|
|
|
*
|
2002-01-11 06:25:45 +01:00
|
|
|
* Revision 1.49 2002/01/11 05:25:45 steve
|
|
|
|
|
* The stime system function is 32bits.
|
1999-09-20 04:21:10 +02:00
|
|
|
*/
|
|
|
|
|
|