1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2013-02-06 21:36:54 +01:00
|
|
|
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
|
1998-11-04 00:28:49 +01: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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* Elaboration takes as input a complete parse tree and the name of a
|
|
|
|
|
* root module, and generates as output the elaborated design. This
|
|
|
|
|
* elaborated design is presented as a Module, which does not
|
|
|
|
|
* reference any other modules. It is entirely self contained.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include <typeinfo>
|
2008-01-05 00:23:47 +01:00
|
|
|
# include <cstdlib>
|
2003-01-14 22:16:18 +01:00
|
|
|
# include <sstream>
|
2001-10-19 23:53:24 +02:00
|
|
|
# include <list>
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "pform.h"
|
2000-04-04 05:20:15 +02:00
|
|
|
# include "PEvent.h"
|
2006-04-10 02:37:42 +02:00
|
|
|
# include "PGenerate.h"
|
2013-02-17 23:42:07 +01:00
|
|
|
# include "PPackage.h"
|
2006-09-23 06:57:19 +02:00
|
|
|
# include "PSpec.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "netlist.h"
|
2012-09-15 19:27:43 +02:00
|
|
|
# include "netvector.h"
|
2012-11-22 20:08:13 +01:00
|
|
|
# include "netdarray.h"
|
|
|
|
|
# include "netclass.h"
|
1999-09-29 02:42:50 +02:00
|
|
|
# include "netmisc.h"
|
2000-04-28 18:50:53 +02:00
|
|
|
# include "util.h"
|
2001-10-21 01:02:39 +02:00
|
|
|
# include "parse_api.h"
|
2002-04-22 02:53:39 +02:00
|
|
|
# include "compiler.h"
|
2007-02-12 02:52:21 +01:00
|
|
|
# include "ivl_assert.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
|
2010-11-01 22:37:06 +01:00
|
|
|
void PGate::elaborate(Design*, NetScope*) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << "internal error: what kind of gate? " <<
|
|
|
|
|
typeid(*this).name() << endl;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate the continuous assign. (This is *not* the procedural
|
|
|
|
|
* assign.) Elaborate the lvalue and rvalue, and do the assignment.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGAssign::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-10-07 21:45:42 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2006-01-02 06:33:19 +01:00
|
|
|
NetExpr* rise_time, *fall_time, *decay_time;
|
2006-01-03 06:22:14 +01:00
|
|
|
eval_delays(des, scope, rise_time, fall_time, decay_time, true);
|
1999-08-01 23:18:55 +02:00
|
|
|
|
2010-03-16 23:16:53 +01:00
|
|
|
ivl_drive_t drive0 = strength0();
|
|
|
|
|
ivl_drive_t drive1 = strength1();
|
2000-05-07 06:37:55 +02:00
|
|
|
|
1999-06-10 06:03:52 +02:00
|
|
|
assert(pin(0));
|
|
|
|
|
assert(pin(1));
|
1999-05-20 06:31:45 +02:00
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
/* Elaborate the l-value. */
|
2008-03-19 04:50:40 +01:00
|
|
|
NetNet*lval = pin(0)->elaborate_lnet(des, scope);
|
1999-05-20 06:31:45 +02:00
|
|
|
if (lval == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-27 06:33:24 +02:00
|
|
|
ivl_assert(*this, lval->pin_count() == 1);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
2008-06-14 00:50:17 +02:00
|
|
|
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
|
2012-09-15 19:27:43 +02:00
|
|
|
<< " width=" << lval->vector_width() << endl;
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
1999-09-15 06:17:52 +02:00
|
|
|
|
2008-09-26 06:22:21 +02:00
|
|
|
NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->data_type(),
|
|
|
|
|
lval->vector_width(), pin(1));
|
2000-09-07 03:29:44 +02:00
|
|
|
|
2008-08-12 06:21:33 +02:00
|
|
|
if (rval_expr == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Unable to elaborate r-value: "
|
|
|
|
|
<< *pin(1) << endl;
|
|
|
|
|
des->errors += 1;
|
2000-05-08 07:28:29 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-03 07:02:35 +02:00
|
|
|
if (type_is_vectorable(rval_expr->expr_type())
|
|
|
|
|
&& type_is_vectorable(lval->data_type())
|
|
|
|
|
&& rval_expr->expr_width() < lval->vector_width()) {
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "r-value expressions width "<<rval_expr->expr_width()
|
|
|
|
|
<< " of " << (rval_expr->has_sign()? "signed":"unsigned")
|
|
|
|
|
<< " expression is to small for l-value width "
|
|
|
|
|
<< lval->vector_width() << "." << endl;
|
|
|
|
|
}
|
2008-11-19 02:17:19 +01:00
|
|
|
rval_expr = pad_to_width(rval_expr, lval->vector_width(), *this);
|
2008-10-03 07:02:35 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-22 22:48:34 +01:00
|
|
|
NetNet*rval = rval_expr->synthesize(des, scope, rval_expr);
|
2008-08-12 06:21:33 +02:00
|
|
|
|
1999-05-20 06:31:45 +02:00
|
|
|
if (rval == 0) {
|
2008-08-12 06:21:33 +02:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
|
|
|
|
<< "Failed to synthesize expression: " << *rval_expr << endl;
|
1999-05-20 06:31:45 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-30 02:42:05 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
|
2008-08-12 06:21:33 +02:00
|
|
|
<< " width="<< rval->vector_width()
|
2008-08-16 06:19:04 +02:00
|
|
|
<< ", type="<< rval->data_type()
|
|
|
|
|
<< ", expr=" << *rval_expr << endl;
|
2005-01-30 02:42:05 +01:00
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
assert(lval && rval);
|
2004-12-11 03:31:25 +01:00
|
|
|
assert(rval->pin_count() == 1);
|
2001-11-05 00:12:29 +01:00
|
|
|
|
2008-08-13 06:03:38 +02:00
|
|
|
// Detect the case that the rvalue-expression is a simple
|
|
|
|
|
// expression. In this case, we will need to create a driver
|
|
|
|
|
// (later) to carry strengths.
|
|
|
|
|
bool need_driver_flag = false;
|
|
|
|
|
if (dynamic_cast<NetESignal*>(rval_expr))
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
|
2008-06-21 03:11:11 +02:00
|
|
|
/* Cast the right side when needed. */
|
2010-10-16 19:53:20 +02:00
|
|
|
if ((lval->data_type() == IVL_VT_REAL) &&
|
|
|
|
|
(rval->data_type() != IVL_VT_REAL)) {
|
2008-06-21 03:11:11 +02:00
|
|
|
rval = cast_to_real(des, scope, rval);
|
2008-08-13 06:03:38 +02:00
|
|
|
need_driver_flag = false;
|
2010-10-16 19:53:20 +02:00
|
|
|
} else if ((lval->data_type() == IVL_VT_BOOL) &&
|
|
|
|
|
(rval->data_type() != IVL_VT_BOOL)) {
|
|
|
|
|
rval = cast_to_int2(des, scope, rval, lval->vector_width());
|
|
|
|
|
need_driver_flag = false;
|
|
|
|
|
} else if ((lval->data_type() != IVL_VT_REAL) &&
|
|
|
|
|
(rval->data_type() == IVL_VT_REAL)) {
|
|
|
|
|
rval = cast_to_int4(des, scope, rval, lval->vector_width());
|
2008-08-13 06:03:38 +02:00
|
|
|
need_driver_flag = false;
|
2008-02-13 23:02:35 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-11 20:27:54 +01:00
|
|
|
/* If the r-value insists on being smaller than the l-value
|
2001-11-05 00:12:29 +01:00
|
|
|
(perhaps it is explicitly sized) the pad it out to be the
|
|
|
|
|
right width so that something is connected to all the bits
|
|
|
|
|
of the l-value. */
|
2008-08-15 05:38:34 +02:00
|
|
|
if (lval->vector_width() > rval->vector_width()) {
|
|
|
|
|
if (rval->get_signed())
|
2008-11-19 02:17:19 +01:00
|
|
|
rval = pad_to_width_signed(des, rval, lval->vector_width(),
|
|
|
|
|
*this);
|
2008-08-15 05:38:34 +02:00
|
|
|
else
|
2008-11-19 02:17:19 +01:00
|
|
|
rval = pad_to_width(des, rval, lval->vector_width(), *this);
|
2008-08-15 05:38:34 +02:00
|
|
|
}
|
1999-06-13 01:16:37 +02:00
|
|
|
|
2006-04-26 06:43:50 +02:00
|
|
|
/* If, on the other hand, the r-value insists on being
|
2011-03-11 20:27:54 +01:00
|
|
|
LARGER than the l-value, use a part select to chop it down
|
2006-04-26 06:43:50 +02:00
|
|
|
down to size. */
|
|
|
|
|
if (lval->vector_width() < rval->vector_width()) {
|
|
|
|
|
NetPartSelect*tmp = new NetPartSelect(rval, 0,lval->vector_width(),
|
|
|
|
|
NetPartSelect::VP);
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
tmp->set_line(*this);
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*osig_vec = new netvector_t(rval->data_type(),
|
|
|
|
|
lval->vector_width()-1,0);
|
2006-04-26 06:43:50 +02:00
|
|
|
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::TRI, osig_vec);
|
2006-04-26 06:43:50 +02:00
|
|
|
osig->set_line(*this);
|
2008-08-13 06:31:39 +02:00
|
|
|
osig->local_flag(true);
|
2006-04-26 06:43:50 +02:00
|
|
|
connect(osig->pin(0), tmp->pin(0));
|
|
|
|
|
rval = osig;
|
2008-08-13 06:03:38 +02:00
|
|
|
need_driver_flag = false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-13 03:34:46 +01:00
|
|
|
/* When we are given a non-default strength value and if the drive
|
|
|
|
|
* source is a bit, part, indexed select or a concatenation we need
|
|
|
|
|
* to add a driver (BUFZ) to convey the strength information. */
|
2010-03-16 23:16:53 +01:00
|
|
|
if ((drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG) &&
|
2013-02-13 03:37:41 +01:00
|
|
|
((dynamic_cast<NetESelect*>(rval_expr)) ||
|
2013-02-13 03:34:46 +01:00
|
|
|
(dynamic_cast<NetEConcat*>(rval_expr)))) {
|
2009-04-03 02:20:41 +02:00
|
|
|
need_driver_flag = true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-13 06:03:38 +02:00
|
|
|
if (need_driver_flag) {
|
|
|
|
|
NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(),
|
2010-07-12 02:16:15 +02:00
|
|
|
rval->vector_width(), false);
|
2008-08-13 06:03:38 +02:00
|
|
|
driver->set_line(*this);
|
|
|
|
|
des->add_node(driver);
|
|
|
|
|
|
|
|
|
|
connect(rval->pin(0), driver->pin(1));
|
|
|
|
|
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*tmp_vec = new netvector_t(rval->data_type(),
|
|
|
|
|
rval->vector_width()-1,0);
|
2008-08-13 06:03:38 +02:00
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::WIRE, tmp_vec);
|
2008-08-13 06:03:38 +02:00
|
|
|
tmp->set_line(*this);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
|
|
|
|
|
connect(driver->pin(0), tmp->pin(0));
|
|
|
|
|
|
|
|
|
|
rval = tmp;
|
2006-04-26 06:43:50 +02:00
|
|
|
}
|
|
|
|
|
|
2008-08-12 06:21:33 +02:00
|
|
|
/* Set the drive and delays for the r-val. */
|
|
|
|
|
|
2010-03-16 23:16:53 +01:00
|
|
|
if (drive0 != IVL_DR_STRONG || drive1 != IVL_DR_STRONG)
|
2008-08-12 06:21:33 +02:00
|
|
|
rval->pin(0).drivers_drive(drive0, drive1);
|
|
|
|
|
|
|
|
|
|
if (rise_time || fall_time || decay_time)
|
2008-02-02 05:13:23 +01:00
|
|
|
rval->pin(0).drivers_delays(rise_time, fall_time, decay_time);
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
connect(lval->pin(0), rval->pin(0));
|
1999-10-08 19:27:23 +02:00
|
|
|
|
|
|
|
|
if (lval->local_flag())
|
|
|
|
|
delete lval;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
|
|
|
|
|
long&high, long&low) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-02-15 03:06:15 +01:00
|
|
|
unsigned count = 1;
|
2008-09-15 06:04:03 +02:00
|
|
|
high = 0;
|
|
|
|
|
low = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
/* If the Verilog source has a range specification for the
|
2007-03-22 17:08:14 +01:00
|
|
|
gates, then I am expected to make more than one
|
1999-02-15 03:06:15 +01:00
|
|
|
gate. Figure out how many are desired. */
|
|
|
|
|
if (msb_) {
|
2011-03-27 12:08:33 +02:00
|
|
|
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true);
|
|
|
|
|
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2003-09-20 08:00:37 +02:00
|
|
|
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
|
|
|
|
|
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
|
|
|
|
|
|
|
|
|
|
if (msb_con == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unable to evaluate "
|
1999-10-07 07:25:33 +02:00
|
|
|
"expression " << *msb_ << endl;
|
1999-02-15 03:06:15 +01:00
|
|
|
des->errors += 1;
|
2008-09-15 06:04:03 +02:00
|
|
|
return 0;
|
1999-02-15 03:06:15 +01:00
|
|
|
}
|
|
|
|
|
|
2003-09-20 08:00:37 +02:00
|
|
|
if (lsb_con == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unable to evaluate "
|
1999-10-07 07:25:33 +02:00
|
|
|
"expression " << *lsb_ << endl;
|
1999-02-15 03:06:15 +01:00
|
|
|
des->errors += 1;
|
2008-09-15 06:04:03 +02:00
|
|
|
return 0;
|
1999-02-15 03:06:15 +01:00
|
|
|
}
|
|
|
|
|
|
2003-09-20 08:00:37 +02:00
|
|
|
verinum msb = msb_con->value();
|
|
|
|
|
verinum lsb = lsb_con->value();
|
|
|
|
|
|
|
|
|
|
delete msb_exp;
|
|
|
|
|
delete lsb_exp;
|
|
|
|
|
|
|
|
|
|
if (msb.as_long() > lsb.as_long())
|
|
|
|
|
count = msb.as_long() - lsb.as_long() + 1;
|
1999-02-15 03:06:15 +01:00
|
|
|
else
|
2003-09-20 08:00:37 +02:00
|
|
|
count = lsb.as_long() - msb.as_long() + 1;
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2003-09-20 08:00:37 +02:00
|
|
|
low = lsb.as_long();
|
|
|
|
|
high = msb.as_long();
|
2004-12-30 00:55:43 +01:00
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
2008-06-12 19:04:29 +02:00
|
|
|
cerr << get_fileline() << ": debug: PGBuiltin: Make array "
|
2011-04-04 19:43:58 +02:00
|
|
|
<< "[" << high << ":" << low << "]" << " of "
|
|
|
|
|
<< count << " gates for " << get_name() << endl;
|
2004-12-30 00:55:43 +01:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count,
|
|
|
|
|
unsigned&lval_count) const
|
2008-09-15 06:04:03 +02:00
|
|
|
{
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case BUF:
|
|
|
|
|
case NOT:
|
2011-06-09 09:39:03 +02:00
|
|
|
if (pin_count() > 2) gate_count = pin_count() - 1;
|
|
|
|
|
else gate_count = 1;
|
|
|
|
|
lval_count = gate_count;
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
case PULLDOWN:
|
|
|
|
|
case PULLUP:
|
2011-06-09 09:39:03 +02:00
|
|
|
gate_count = pin_count();
|
|
|
|
|
lval_count = gate_count;
|
|
|
|
|
break;
|
|
|
|
|
case TRAN:
|
|
|
|
|
case RTRAN:
|
|
|
|
|
case TRANIF0:
|
|
|
|
|
case TRANIF1:
|
|
|
|
|
case RTRANIF0:
|
|
|
|
|
case RTRANIF1:
|
|
|
|
|
gate_count = 1;
|
|
|
|
|
lval_count = 2;
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
2011-06-09 09:39:03 +02:00
|
|
|
gate_count = 1;
|
|
|
|
|
lval_count = 1;
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
|
2010-07-13 19:01:32 +02:00
|
|
|
perm_string inst_name,
|
2008-09-15 06:04:03 +02:00
|
|
|
unsigned instance_width) const
|
|
|
|
|
{
|
|
|
|
|
NetNode*gate = 0;
|
|
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
|
|
|
|
|
case AND:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the AND "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::AND, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUF:
|
2008-12-08 19:55:02 +01:00
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the BUF "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, 2,
|
2008-12-08 19:55:02 +01:00
|
|
|
NetLogic::BUF, instance_width);
|
|
|
|
|
}
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUFIF0:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the BUFIF0 "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::BUFIF0, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUFIF1:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the BUFIF1 "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::BUFIF1, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CMOS:
|
|
|
|
|
if (pin_count() != 4) {
|
|
|
|
|
cerr << get_fileline() << ": error: the CMOS "
|
|
|
|
|
"primitive must have four arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::CMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NAND:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NAND "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::NAND, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMOS:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NMOS "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::NMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NOR:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NOR "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::NOR, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NOT:
|
2008-12-08 19:55:02 +01:00
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NOT "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, 2,
|
2008-12-08 19:55:02 +01:00
|
|
|
NetLogic::NOT, instance_width);
|
|
|
|
|
}
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NOTIF0:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NOTIF0 "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::NOTIF0, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NOTIF1:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the NOTIF1 "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::NOTIF1, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case OR:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the OR "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::OR, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RCMOS:
|
|
|
|
|
if (pin_count() != 4) {
|
|
|
|
|
cerr << get_fileline() << ": error: the RCMOS "
|
|
|
|
|
"primitive must have four arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::RCMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2004-12-30 00:55:43 +01:00
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
case RNMOS:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the RNMOS "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::RNMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RPMOS:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the RPMOS "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::RPMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PMOS:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: the PMOS "
|
|
|
|
|
"primitive must have three arguments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::PMOS, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PULLDOWN:
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, 1,
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::PULLDOWN, instance_width);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PULLUP:
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, 1,
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::PULLUP, instance_width);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case XNOR:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the XNOR "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::XNOR, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case XOR:
|
|
|
|
|
if (pin_count() < 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: the XOR "
|
|
|
|
|
"primitive must have an input." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2010-07-13 19:01:32 +02:00
|
|
|
gate = new NetLogic(scope, inst_name, pin_count(),
|
2008-09-15 06:04:03 +02:00
|
|
|
NetLogic::XOR, instance_width);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TRAN:
|
|
|
|
|
if (pin_count() != 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "tran device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_TRAN,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTRAN:
|
|
|
|
|
if (pin_count() != 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "rtran device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRAN,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TRANIF0:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "tranif0 device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTRANIF0:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "rtranif0 device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TRANIF1:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "tranif1 device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTRANIF1:
|
|
|
|
|
if (pin_count() != 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: Pin count for "
|
|
|
|
|
<< "rtranif1 device." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2012-01-02 19:14:20 +01:00
|
|
|
gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1,
|
|
|
|
|
instance_width);
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
cerr << get_fileline() << ": internal error: unhandled "
|
|
|
|
|
"gate type." << endl;
|
2007-08-30 02:29:56 +02:00
|
|
|
des->errors += 1;
|
2008-09-15 06:04:03 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return gate;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-13 19:01:32 +02:00
|
|
|
bool PGBuiltin::check_delay_count(Design*des) const
|
|
|
|
|
{
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case AND:
|
|
|
|
|
case NAND:
|
|
|
|
|
case OR:
|
|
|
|
|
case NOR:
|
|
|
|
|
case XOR:
|
|
|
|
|
case XNOR:
|
|
|
|
|
case BUF:
|
|
|
|
|
case NOT:
|
|
|
|
|
if (delay_count() > 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: More than two delays "
|
|
|
|
|
<< "given to a " << gate_name() << " gate." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUFIF0:
|
|
|
|
|
case NOTIF0:
|
|
|
|
|
case BUFIF1:
|
|
|
|
|
case NOTIF1:
|
|
|
|
|
if (delay_count() > 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: More than three delays "
|
|
|
|
|
<< "given to a " << gate_name() << " gate." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NMOS:
|
|
|
|
|
case RNMOS:
|
|
|
|
|
case PMOS:
|
|
|
|
|
case RPMOS:
|
|
|
|
|
case CMOS:
|
|
|
|
|
case RCMOS:
|
|
|
|
|
if (delay_count() > 3) {
|
|
|
|
|
cerr << get_fileline() << ": error: More than three delays "
|
|
|
|
|
<< "given to a " << gate_name() << " switch." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TRAN:
|
|
|
|
|
case RTRAN:
|
|
|
|
|
if (delay_count() != 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: A " << gate_name()
|
|
|
|
|
<< " switch does not take any delays." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TRANIF0:
|
|
|
|
|
case TRANIF1:
|
|
|
|
|
if (delay_count() > 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: More than two delays "
|
|
|
|
|
<< "given to a " << gate_name() << " switch." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTRANIF0:
|
|
|
|
|
case RTRANIF1:
|
|
|
|
|
if (delay_count() > 2) {
|
|
|
|
|
cerr << get_fileline() << ": error: More than two delays "
|
|
|
|
|
<< "given to an " << gate_name() << " switch." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PULLUP:
|
|
|
|
|
case PULLDOWN:
|
|
|
|
|
if (delay_count() != 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: A " << gate_name()
|
|
|
|
|
<< " source does not take any delays." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
cerr << get_fileline() << ": internal error: unhandled "
|
|
|
|
|
"gate type." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate a Builtin gate. These normally get translated into
|
|
|
|
|
* NetLogic nodes that reflect the particular logic function.
|
|
|
|
|
*/
|
|
|
|
|
void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
unsigned instance_width = 1;
|
|
|
|
|
perm_string name = get_name();
|
|
|
|
|
|
2011-04-04 19:43:58 +02:00
|
|
|
if (name == "") name = scope->local_symbol();
|
2008-09-15 06:04:03 +02:00
|
|
|
|
|
|
|
|
/* Calculate the array bounds and instance count for the gate,
|
|
|
|
|
as described in the Verilog source. If there is none, then
|
|
|
|
|
the count is 1, and high==low==0. */
|
|
|
|
|
|
|
|
|
|
long low=0, high=0;
|
|
|
|
|
unsigned array_count = calculate_array_count_(des, scope, high, low);
|
2011-04-04 19:43:58 +02:00
|
|
|
if (array_count == 0) return;
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
unsigned gate_count = 0, lval_count = 0;
|
|
|
|
|
calculate_gate_and_lval_count_(gate_count, lval_count);
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
/* Now we have a gate count. Elaborate the lval (output or
|
|
|
|
|
bi-directional) expressions only. We do it early so that
|
|
|
|
|
we can see if we can make wide gates instead of an array
|
|
|
|
|
of gates. */
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
vector<NetNet*>lval_sigs (lval_count);
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
for (unsigned idx = 0 ; idx < lval_count ; idx += 1) {
|
2008-09-15 06:04:03 +02:00
|
|
|
if (pin(idx) == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Logic gate port "
|
|
|
|
|
"expressions are not optional." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-06-09 09:39:03 +02:00
|
|
|
if (lval_count > gate_count)
|
|
|
|
|
lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope);
|
|
|
|
|
else
|
|
|
|
|
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope);
|
|
|
|
|
|
2009-04-02 03:31:29 +02:00
|
|
|
// The only way this should return zero is if an error
|
|
|
|
|
// happened, so for that case just return.
|
|
|
|
|
if (lval_sigs[idx] == 0) return;
|
2008-09-15 06:04:03 +02:00
|
|
|
|
|
|
|
|
// For now, assume all the outputs are the same width.
|
|
|
|
|
ivl_assert(*this, idx == 0 || lval_sigs[idx]->vector_width() == lval_sigs[0]->vector_width());
|
2007-08-30 02:29:56 +02:00
|
|
|
}
|
2004-12-30 00:55:43 +01:00
|
|
|
|
|
|
|
|
/* Detect the special case that the l-value width exactly
|
|
|
|
|
matches the gate count. In this case, we will make a single
|
2008-09-15 06:04:03 +02:00
|
|
|
gate that has the desired vector width.
|
|
|
|
|
|
|
|
|
|
NOTE: This assumes that all the outputs have the same
|
|
|
|
|
width. For gates with 1 output, this is trivially true. */
|
|
|
|
|
if (lval_sigs[0]->vector_width() == array_count) {
|
|
|
|
|
instance_width = array_count;
|
|
|
|
|
array_count = 1;
|
2004-12-30 00:55:43 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
if (debug_elaborate && instance_width != 1)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: PGBuiltin: "
|
2004-12-30 00:55:43 +01:00
|
|
|
"Collapsed gate array into single wide "
|
|
|
|
|
"(" << instance_width << ") instance." << endl;
|
|
|
|
|
}
|
1999-02-15 03:06:15 +01:00
|
|
|
|
1999-08-01 18:34:50 +02:00
|
|
|
/* Calculate the gate delays from the delay expressions
|
|
|
|
|
given in the source. For logic gates, the decay time
|
|
|
|
|
is meaningless because it can never go to high
|
2003-01-27 06:09:17 +01:00
|
|
|
impedance. However, the bufif devices can generate
|
1999-08-01 18:34:50 +02:00
|
|
|
'bz output, so we will pretend that anything can.
|
|
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
If only one delay value expression is given (i.e., #5
|
1999-08-01 18:34:50 +02:00
|
|
|
nand(foo,...)) then rise, fall and decay times are
|
|
|
|
|
all the same value. If two values are given, rise and
|
|
|
|
|
fall times are use, and the decay time is the minimum
|
|
|
|
|
of the rise and fall times. Finally, if all three
|
|
|
|
|
values are given, they are taken as specified. */
|
|
|
|
|
|
2010-07-13 19:01:32 +02:00
|
|
|
if (check_delay_count(des)) return;
|
2006-01-02 06:33:19 +01:00
|
|
|
NetExpr* rise_time, *fall_time, *decay_time;
|
2001-11-22 07:20:59 +01:00
|
|
|
eval_delays(des, scope, rise_time, fall_time, decay_time);
|
1999-08-01 18:34:50 +02:00
|
|
|
|
2012-11-13 03:13:41 +01:00
|
|
|
struct attrib_list_t*attrib_list;
|
2002-05-23 05:08:50 +02:00
|
|
|
unsigned attrib_list_n = 0;
|
|
|
|
|
attrib_list = evaluate_attributes(attributes, attrib_list_n,
|
|
|
|
|
des, scope);
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
/* Allocate all the netlist nodes for the gates. */
|
2011-06-09 09:39:03 +02:00
|
|
|
vector<NetNode*>cur (array_count*gate_count);
|
2008-09-15 06:04:03 +02:00
|
|
|
|
1999-08-01 18:34:50 +02:00
|
|
|
/* Now make as many gates as the bit count dictates. Give each
|
|
|
|
|
a unique name, and set the delay times. */
|
|
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
for (unsigned idx = 0 ; idx < array_count*gate_count ; idx += 1) {
|
|
|
|
|
unsigned array_idx = idx/gate_count;
|
|
|
|
|
unsigned gate_idx = idx%gate_count;
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2003-01-14 22:16:18 +01:00
|
|
|
ostringstream tmp;
|
2008-09-15 06:04:03 +02:00
|
|
|
unsigned index = (low < high)? (low+array_idx) : (low-array_idx);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
tmp << name << "<" << index << "." << gate_idx << ">";
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string inm = lex_strings.make(tmp.str());
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
cur[idx] = create_gate_for_output_(des, scope, inm, instance_width);
|
|
|
|
|
if (cur[idx] == 0)
|
2000-01-09 06:50:48 +01:00
|
|
|
return;
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
|
|
|
|
|
cur[idx]->attribute(attrib_list[adx].key,
|
|
|
|
|
attrib_list[adx].val);
|
|
|
|
|
|
2010-07-13 19:01:32 +02:00
|
|
|
/* Set the delays and drive strength for all built in gates. */
|
2010-07-13 01:04:22 +02:00
|
|
|
cur[idx]->rise_time(rise_time);
|
|
|
|
|
cur[idx]->fall_time(fall_time);
|
|
|
|
|
cur[idx]->decay_time(decay_time);
|
|
|
|
|
|
|
|
|
|
cur[idx]->pin(0).drive0(strength0());
|
|
|
|
|
cur[idx]->pin(0).drive1(strength1());
|
2000-05-08 07:28:29 +02:00
|
|
|
|
2008-05-20 06:42:52 +02:00
|
|
|
cur[idx]->set_line(*this);
|
1999-02-15 03:06:15 +01:00
|
|
|
des->add_node(cur[idx]);
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
|
|
|
|
|
delete[]attrib_list;
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
/* The gates have all been allocated, this loop runs through
|
|
|
|
|
the parameters and attaches the ports of the objects. */
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2008-11-27 00:37:38 +01:00
|
|
|
PExpr*ex = pin(idx);
|
2007-08-30 02:29:56 +02:00
|
|
|
if (ex == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Logic gate port "
|
2007-08-30 02:29:56 +02:00
|
|
|
"expressions are not optional." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-09-09 04:13:49 +02:00
|
|
|
NetNet*sig = 0;
|
2011-06-09 09:39:03 +02:00
|
|
|
if (idx < lval_count) {
|
2008-09-15 06:04:03 +02:00
|
|
|
sig = lval_sigs[idx];
|
2008-09-09 04:13:49 +02:00
|
|
|
|
|
|
|
|
} else {
|
2011-05-30 10:25:54 +02:00
|
|
|
// If this is an array, the port expression is required
|
|
|
|
|
// to be the exact width required (this will be checked
|
|
|
|
|
// later). But if this is a single instance, consensus
|
|
|
|
|
// is that we just take the LSB of the port expression.
|
|
|
|
|
NetExpr*tmp = elab_and_eval(des, scope, ex, msb_ ? -1 : 1);
|
|
|
|
|
if (tmp == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (msb_ == 0 && tmp->expr_width() != 1)
|
|
|
|
|
tmp = new NetESelect(tmp, make_const_0(1), 1,
|
|
|
|
|
IVL_SEL_IDX_UP);
|
2008-12-22 22:48:34 +01:00
|
|
|
sig = tmp->synthesize(des, scope, tmp);
|
2008-09-09 04:13:49 +02:00
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-14 03:50:52 +02:00
|
|
|
if (sig == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
ivl_assert(*this, sig);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
if (array_count == 1) {
|
2004-12-30 00:55:43 +01:00
|
|
|
/* Handle the case where there is one gate that
|
|
|
|
|
carries the whole vector width. */
|
2005-02-08 01:12:36 +01:00
|
|
|
|
2006-09-23 00:14:27 +02:00
|
|
|
if (1 == sig->vector_width() && instance_width != 1) {
|
2005-02-08 01:12:36 +01:00
|
|
|
|
|
|
|
|
assert(sig->vector_width() == 1);
|
|
|
|
|
NetReplicate*rep
|
|
|
|
|
= new NetReplicate(scope,
|
|
|
|
|
scope->local_symbol(),
|
|
|
|
|
instance_width,
|
|
|
|
|
instance_width);
|
|
|
|
|
rep->set_line(*this);
|
|
|
|
|
des->add_node(rep);
|
|
|
|
|
connect(rep->pin(1), sig->pin(0));
|
|
|
|
|
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*osig_vec = new netvector_t(IVL_VT_LOGIC,
|
|
|
|
|
instance_width-1,0);
|
2005-02-08 01:12:36 +01:00
|
|
|
sig = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::WIRE, osig_vec);
|
2011-02-10 06:03:08 +01:00
|
|
|
sig->set_line(*this);
|
2005-02-08 01:12:36 +01:00
|
|
|
sig->local_flag(true);
|
|
|
|
|
connect(rep->pin(0), sig->pin(0));
|
2006-09-23 00:14:27 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (instance_width != sig->vector_width()) {
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: "
|
2006-09-23 00:14:27 +02:00
|
|
|
<< "Expression width " << sig->vector_width()
|
|
|
|
|
<< " does not match width " << instance_width
|
2011-05-23 06:40:54 +02:00
|
|
|
<< " of logic gate array port " << idx+1
|
2006-09-23 00:14:27 +02:00
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
2005-02-08 01:12:36 +01:00
|
|
|
}
|
|
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
// There is only 1 instance, but there may be
|
|
|
|
|
// multiple outputs to that gate. That would
|
|
|
|
|
// potentially mean multiple actual gates.
|
|
|
|
|
// Although in Verilog proper a multiple
|
|
|
|
|
// output gate has only 1 input, this conditional
|
|
|
|
|
// handles gates with N outputs and M inputs.
|
2011-06-09 09:39:03 +02:00
|
|
|
if (idx < gate_count) {
|
2008-09-15 06:04:03 +02:00
|
|
|
connect(cur[idx]->pin(0), sig->pin(0));
|
|
|
|
|
} else {
|
2011-06-09 09:39:03 +02:00
|
|
|
for (unsigned dev = 0 ; dev < gate_count; dev += 1)
|
|
|
|
|
connect(cur[dev]->pin(idx-gate_count+1), sig->pin(0));
|
2008-09-15 06:04:03 +02:00
|
|
|
}
|
2004-12-30 00:55:43 +01:00
|
|
|
|
|
|
|
|
} else if (sig->vector_width() == 1) {
|
2008-09-15 06:04:03 +02:00
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
/* Handle the case where a single bit is connected
|
2008-09-17 06:03:26 +02:00
|
|
|
repetitively to all the instances. If idx is an
|
|
|
|
|
output port, connect it to all array_count
|
|
|
|
|
devices that have outputs at this
|
|
|
|
|
position. Otherwise, idx is an input to all
|
2011-06-09 09:39:03 +02:00
|
|
|
array_count*gate_count devices. */
|
2008-09-17 06:03:26 +02:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
if (idx < gate_count) {
|
2008-09-17 06:03:26 +02:00
|
|
|
for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) {
|
2011-06-09 09:39:03 +02:00
|
|
|
unsigned dev = gdx*gate_count;
|
2008-09-17 06:03:26 +02:00
|
|
|
connect(cur[dev+idx]->pin(0), sig->pin(0));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-06-09 09:39:03 +02:00
|
|
|
unsigned use_idx = idx - gate_count + 1;
|
2008-09-17 06:03:26 +02:00
|
|
|
for (unsigned gdx = 0 ; gdx < cur.size() ; gdx += 1)
|
|
|
|
|
connect(cur[gdx]->pin(use_idx), sig->pin(0));
|
|
|
|
|
}
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
} else if (sig->vector_width() == array_count) {
|
2004-12-30 00:55:43 +01:00
|
|
|
|
2011-06-09 09:39:03 +02:00
|
|
|
/* Bi-directional switches should get collapsed into
|
|
|
|
|
a single wide instance, so should never reach this
|
|
|
|
|
point. Check this is so, as the following code
|
|
|
|
|
doesn't handle bi-directional connections. */
|
|
|
|
|
ivl_assert(*this, lval_count == gate_count);
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
/* Handle the general case that each bit of the
|
|
|
|
|
value is connected to a different instance. In
|
|
|
|
|
this case, the output is handled slightly
|
|
|
|
|
different from the inputs. */
|
2011-06-09 09:39:03 +02:00
|
|
|
if (idx < gate_count) {
|
2004-12-30 00:55:43 +01:00
|
|
|
NetConcat*cc = new NetConcat(scope,
|
|
|
|
|
scope->local_symbol(),
|
|
|
|
|
sig->vector_width(),
|
2008-09-15 06:04:03 +02:00
|
|
|
array_count);
|
2011-02-10 06:03:08 +01:00
|
|
|
cc->set_line(*this);
|
2004-12-30 00:55:43 +01:00
|
|
|
des->add_node(cc);
|
|
|
|
|
|
|
|
|
|
/* Connect the concat to the signal. */
|
|
|
|
|
connect(cc->pin(0), sig->pin(0));
|
|
|
|
|
|
|
|
|
|
/* Connect the outputs of the gates to the concat. */
|
2008-09-15 06:04:03 +02:00
|
|
|
for (unsigned gdx = 0 ; gdx < array_count; gdx += 1) {
|
2011-06-09 09:39:03 +02:00
|
|
|
unsigned dev = gdx*gate_count;
|
2008-09-17 06:03:26 +02:00
|
|
|
connect(cur[dev+idx]->pin(0), cc->pin(gdx+1));
|
2004-12-30 00:55:43 +01:00
|
|
|
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*tmp2_vec = new netvector_t(IVL_VT_LOGIC);
|
2004-12-30 00:55:43 +01:00
|
|
|
NetNet*tmp2 = new NetNet(scope,
|
|
|
|
|
scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::WIRE, tmp2_vec);
|
2011-02-10 06:03:08 +01:00
|
|
|
tmp2->set_line(*this);
|
2006-05-01 22:47:58 +02:00
|
|
|
tmp2->local_flag(true);
|
2004-12-30 00:55:43 +01:00
|
|
|
connect(cc->pin(gdx+1), tmp2->pin(0));
|
|
|
|
|
}
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2008-09-15 06:04:03 +02:00
|
|
|
} else for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) {
|
2004-12-30 00:55:43 +01:00
|
|
|
/* Use part selects to get the bits
|
|
|
|
|
connected to the inputs of out gate. */
|
2005-01-09 21:16:00 +01:00
|
|
|
NetPartSelect*tmp1 = new NetPartSelect(sig, gdx, 1,
|
|
|
|
|
NetPartSelect::VP);
|
2004-12-30 00:55:43 +01:00
|
|
|
tmp1->set_line(*this);
|
|
|
|
|
des->add_node(tmp1);
|
|
|
|
|
connect(tmp1->pin(1), sig->pin(0));
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*tmp2_vec = new netvector_t(sig->data_type());
|
2004-12-30 00:55:43 +01:00
|
|
|
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::WIRE, tmp2_vec);
|
2011-02-10 06:03:08 +01:00
|
|
|
tmp2->set_line(*this);
|
2006-05-01 22:47:58 +02:00
|
|
|
tmp2->local_flag(true);
|
2004-12-30 00:55:43 +01:00
|
|
|
connect(tmp1->pin(0), tmp2->pin(0));
|
2011-06-09 09:39:03 +02:00
|
|
|
unsigned use_idx = idx - gate_count + 1;
|
|
|
|
|
unsigned dev = gdx*gate_count;
|
|
|
|
|
for (unsigned gdx2 = 0 ; gdx2 < gate_count ; gdx2 += 1)
|
2008-09-17 06:03:26 +02:00
|
|
|
connect(cur[dev+gdx2]->pin(use_idx), tmp1->pin(0));
|
2004-12-30 00:55:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Gate count of " <<
|
2008-09-15 06:04:03 +02:00
|
|
|
array_count << " does not match net width of " <<
|
2004-12-30 00:55:43 +01:00
|
|
|
sig->vector_width() << " at pin " << idx << "."
|
1999-02-15 03:06:15 +01:00
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-02 04:45:12 +02:00
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2007-09-10 06:14:52 +02:00
|
|
|
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
|
|
|
|
NetNet*sig, unsigned port_wid,
|
2008-10-03 03:38:53 +02:00
|
|
|
NetNet::PortType dir, bool as_signed) const
|
2007-09-10 06:14:52 +02:00
|
|
|
{
|
|
|
|
|
ivl_assert(*this, dir != NetNet::NOT_A_PORT);
|
|
|
|
|
ivl_assert(*this, dir != NetNet::PIMPLICIT);
|
|
|
|
|
|
2012-09-30 00:13:45 +02:00
|
|
|
netvector_t*tmp_type = new netvector_t(IVL_VT_LOGIC, port_wid-1, 0);
|
2007-09-10 06:14:52 +02:00
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
2012-09-30 00:13:45 +02:00
|
|
|
NetNet::WIRE, tmp_type);
|
2007-09-10 06:14:52 +02:00
|
|
|
tmp->local_flag(true);
|
2008-11-19 02:17:19 +01:00
|
|
|
tmp->set_line(*this);
|
2007-09-10 06:14:52 +02:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
// Handle the special case of a bi-directional part
|
|
|
|
|
// select. Create a NetTran(VP) instead of a uni-directional
|
|
|
|
|
// NetPartSelect node.
|
|
|
|
|
if (dir == NetNet::PINOUT) {
|
|
|
|
|
unsigned wida = sig->vector_width();
|
|
|
|
|
unsigned widb = tmp->vector_width();
|
|
|
|
|
bool part_b = widb < wida;
|
2008-10-03 03:38:53 +02:00
|
|
|
// This needs to pad the value!
|
|
|
|
|
// Also delete the inout specific warning when this is fixed.
|
|
|
|
|
// It is located just before this routine is called.
|
2008-06-03 20:16:25 +02:00
|
|
|
NetTran*node = new NetTran(scope, scope->local_symbol(),
|
|
|
|
|
part_b? wida : widb,
|
|
|
|
|
part_b? widb : wida,
|
|
|
|
|
0);
|
|
|
|
|
if (part_b) {
|
|
|
|
|
connect(node->pin(0), sig->pin(0));
|
|
|
|
|
connect(node->pin(1), tmp->pin(0));
|
2008-06-04 02:23:01 +02:00
|
|
|
} else {
|
|
|
|
|
connect(node->pin(0), tmp->pin(0));
|
|
|
|
|
connect(node->pin(1), sig->pin(0));
|
2008-06-03 20:16:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node->set_line(*this);
|
|
|
|
|
des->add_node(node);
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-03 03:38:53 +02:00
|
|
|
unsigned pwidth = tmp->vector_width();
|
|
|
|
|
unsigned swidth = sig->vector_width();
|
2007-09-10 06:14:52 +02:00
|
|
|
switch (dir) {
|
|
|
|
|
case NetNet::POUTPUT:
|
2008-10-03 03:38:53 +02:00
|
|
|
if (pwidth > swidth) {
|
|
|
|
|
NetPartSelect*node = new NetPartSelect(tmp, 0, swidth,
|
2007-09-10 06:14:52 +02:00
|
|
|
NetPartSelect::VP);
|
2008-01-11 03:20:21 +01:00
|
|
|
connect(node->pin(0), sig->pin(0));
|
2008-10-03 03:38:53 +02:00
|
|
|
des->add_node(node);
|
2007-09-10 06:14:52 +02:00
|
|
|
} else {
|
2008-10-03 03:38:53 +02:00
|
|
|
NetNet*osig;
|
|
|
|
|
if (as_signed) {
|
2008-11-19 02:17:19 +01:00
|
|
|
osig = pad_to_width_signed(des, tmp, swidth, *this);
|
2008-10-03 03:38:53 +02:00
|
|
|
} else {
|
2008-11-19 02:17:19 +01:00
|
|
|
osig = pad_to_width(des, tmp, swidth, *this);
|
2008-10-03 03:38:53 +02:00
|
|
|
}
|
|
|
|
|
connect(osig->pin(0), sig->pin(0));
|
2007-09-10 06:14:52 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NetNet::PINPUT:
|
2008-10-03 03:38:53 +02:00
|
|
|
if (pwidth > swidth) {
|
|
|
|
|
delete tmp;
|
|
|
|
|
if (as_signed) {
|
2008-11-19 02:17:19 +01:00
|
|
|
tmp = pad_to_width_signed(des, sig, pwidth, *this);
|
2008-10-03 03:38:53 +02:00
|
|
|
} else {
|
2008-11-19 02:17:19 +01:00
|
|
|
tmp = pad_to_width(des, sig, pwidth, *this);
|
2008-10-03 03:38:53 +02:00
|
|
|
}
|
2007-09-10 06:14:52 +02:00
|
|
|
} else {
|
2008-10-03 03:38:53 +02:00
|
|
|
NetPartSelect*node = new NetPartSelect(sig, 0, pwidth,
|
2007-09-10 06:14:52 +02:00
|
|
|
NetPartSelect::VP);
|
2008-01-11 05:47:06 +01:00
|
|
|
connect(node->pin(0), tmp->pin(0));
|
2008-10-03 03:38:53 +02:00
|
|
|
des->add_node(node);
|
2007-09-10 06:14:52 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NetNet::PINOUT:
|
2008-06-03 20:16:25 +02:00
|
|
|
ivl_assert(*this, 0);
|
2007-09-10 06:14:52 +02:00
|
|
|
break;
|
|
|
|
|
|
2012-02-25 19:19:48 +01:00
|
|
|
case NetNet::PREF:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
2007-09-10 06:14:52 +02:00
|
|
|
default:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-03 05:08:38 +01:00
|
|
|
static bool need_bufz_for_input_port(const vector<NetNet*>&prts)
|
2008-08-07 06:04:52 +02:00
|
|
|
{
|
|
|
|
|
if (prts[0]->port_type() != NetNet::PINPUT)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (prts[0]->pin(0).nexus()->drivers_present())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 22:41:54 +02:00
|
|
|
/*
|
|
|
|
|
* Convert a wire or tri to a tri0 or tri1 as needed to make
|
|
|
|
|
* an unconnected drive pull for floating inputs.
|
|
|
|
|
*/
|
|
|
|
|
static void convert_net(Design*des, const LineInfo *line,
|
|
|
|
|
NetNet *net, NetNet::Type type)
|
|
|
|
|
{
|
|
|
|
|
// If the types already match just return.
|
|
|
|
|
if (net->type() == type) return;
|
|
|
|
|
|
|
|
|
|
// We can only covert a wire or tri to have a default pull.
|
|
|
|
|
if (net->type() == NetNet::WIRE || net->type() == NetNet::TRI) {
|
|
|
|
|
net->type(type);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We may have to support this at some point in time!
|
|
|
|
|
cerr << line->get_fileline() << ": sorry: Can not pull floating "
|
|
|
|
|
"input type '" << net->type() << "'." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* Instantiate a module by recursively elaborating it. Set the path of
|
|
|
|
|
* the recursive elaboration so that signal names get properly
|
|
|
|
|
* set. Connect the ports of the instantiated module to the signals of
|
|
|
|
|
* the parameters. This is done with BUFZ gates so that they look just
|
|
|
|
|
* like continuous assignment connections.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-02-18 06:15:02 +01:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2005-02-10 05:56:58 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Instantiate module "
|
2005-11-10 14:28:11 +01:00
|
|
|
<< rmod->mod_name() << " with instance name "
|
2007-06-02 05:42:12 +02:00
|
|
|
<< get_name() << " in scope " << scope_path(scope) << endl;
|
2005-02-10 05:56:58 +01:00
|
|
|
}
|
|
|
|
|
|
2004-03-08 01:47:44 +01:00
|
|
|
// This is the array of pin expressions, shuffled to match the
|
|
|
|
|
// order of the declaration. If the source instantiation uses
|
2008-11-16 22:27:56 +01:00
|
|
|
// bind by order, this is the same as the source list. Otherwise,
|
2005-02-10 05:56:58 +01:00
|
|
|
// the source list is rearranged by name binding into this list.
|
2010-10-26 04:36:44 +02:00
|
|
|
vector<PExpr*>pins (rmod->port_count());
|
2009-11-26 18:39:21 +01:00
|
|
|
vector<bool>pins_fromwc (rmod->port_count(), false);
|
1999-05-29 04:36:17 +02:00
|
|
|
|
2005-02-10 05:56:58 +01:00
|
|
|
// If the instance has a pins_ member, then we know we are
|
|
|
|
|
// binding by name. Therefore, make up a pins array that
|
|
|
|
|
// reflects the positions of the named ports.
|
1999-05-29 04:36:17 +02:00
|
|
|
if (pins_) {
|
1999-08-03 06:14:49 +02:00
|
|
|
unsigned nexp = rmod->port_count();
|
1999-05-29 04:36:17 +02:00
|
|
|
|
|
|
|
|
// Scan the bindings, matching them with port names.
|
|
|
|
|
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
|
|
|
|
|
|
2009-11-26 18:39:21 +01:00
|
|
|
// Handle wildcard named port
|
|
|
|
|
if (pins_[idx].name[0] == '*') {
|
|
|
|
|
for (unsigned j = 0 ; j < nexp ; j += 1) {
|
|
|
|
|
if (!pins[j]) {
|
|
|
|
|
pins_fromwc[j] = true;
|
|
|
|
|
NetNet* net = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
|
|
|
|
pform_name_t path_;
|
|
|
|
|
path_.push_back(name_component_t(rmod->ports[j]->name));
|
|
|
|
|
symbol_search(this, des, scope,
|
|
|
|
|
path_, net, par, eve);
|
|
|
|
|
if (net != 0) {
|
|
|
|
|
pins[j] = new PEIdent(rmod->ports[j]->name, true);
|
|
|
|
|
pins[j]->set_lineno(get_lineno());
|
|
|
|
|
pins[j]->set_file(get_file());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
// Given a binding, look at the module port names
|
|
|
|
|
// for the position that matches the binding name.
|
1999-08-03 06:14:49 +02:00
|
|
|
unsigned pidx = rmod->find_port(pins_[idx].name);
|
1999-05-29 04:36:17 +02:00
|
|
|
|
1999-08-03 06:14:49 +02:00
|
|
|
// If the port name doesn't exist, the find_port
|
|
|
|
|
// method will return the port count. Detect that
|
|
|
|
|
// as an error.
|
1999-05-29 04:36:17 +02:00
|
|
|
if (pidx == nexp) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: port ``" <<
|
1999-05-29 04:36:17 +02:00
|
|
|
pins_[idx].name << "'' is not a port of "
|
|
|
|
|
<< get_name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-26 18:39:21 +01:00
|
|
|
// If I am overriding a wildcard port, delete and
|
|
|
|
|
// override it
|
|
|
|
|
if (pins_fromwc[pidx]) {
|
|
|
|
|
delete pins[pidx];
|
|
|
|
|
pins_fromwc[pidx] = false;
|
|
|
|
|
|
|
|
|
|
// If I already explicitely bound something to
|
|
|
|
|
// this port, then the pins array will already
|
|
|
|
|
// have a pointer value where I want to place this
|
|
|
|
|
// expression.
|
|
|
|
|
} else if (pins[pidx]) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: port ``" <<
|
1999-05-29 04:36:17 +02:00
|
|
|
pins_[idx].name << "'' already bound." <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-03 06:14:49 +02:00
|
|
|
// OK, do the binding by placing the expression in
|
1999-05-29 04:36:17 +02:00
|
|
|
// the right place.
|
2004-03-08 01:47:44 +01:00
|
|
|
pins[pidx] = pins_[idx].parm;
|
1999-05-29 04:36:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-08-01 07:17:31 +02:00
|
|
|
} else if (pin_count() == 0) {
|
|
|
|
|
|
|
|
|
|
/* Handle the special case that no ports are
|
|
|
|
|
connected. It is possible that this is an empty
|
2003-01-27 06:09:17 +01:00
|
|
|
connect-by-name list, so we'll allow it and assume
|
2001-08-01 07:17:31 +02:00
|
|
|
that is the case. */
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1)
|
2004-03-08 01:47:44 +01:00
|
|
|
pins[idx] = 0;
|
2001-08-01 07:17:31 +02:00
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
} else {
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
/* Otherwise, this is a positional list of port
|
2001-08-01 07:17:31 +02:00
|
|
|
connections. In this case, the port count must be
|
|
|
|
|
right. Check that is is, the get the pin list. */
|
|
|
|
|
|
1999-08-03 06:14:49 +02:00
|
|
|
if (pin_count() != rmod->port_count()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Wrong number "
|
2001-08-01 07:17:31 +02:00
|
|
|
"of ports. Expecting " << rmod->port_count() <<
|
1999-05-29 04:36:17 +02:00
|
|
|
", got " << pin_count() << "."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No named bindings, just use the positional list I
|
|
|
|
|
// already have.
|
1999-08-03 06:14:49 +02:00
|
|
|
assert(pin_count() == rmod->port_count());
|
1999-05-29 04:36:17 +02:00
|
|
|
pins = get_pins();
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-05 19:44:41 +02:00
|
|
|
// Elaborate these instances of the module. The recursive
|
1998-11-04 00:28:49 +01:00
|
|
|
// elaboration causes the module to generate a netlist with
|
|
|
|
|
// the ports represented by NetNet objects. I will find them
|
|
|
|
|
// later.
|
2004-09-05 19:44:41 +02:00
|
|
|
|
|
|
|
|
NetScope::scope_vec_t&instance = scope->instance_arrays[get_name()];
|
2008-11-16 22:27:56 +01:00
|
|
|
if (debug_elaborate) cerr << get_fileline() << ": debug: start "
|
|
|
|
|
"recursive elaboration of " << instance.size() << " instance(s) of " <<
|
|
|
|
|
get_name() << "..." << endl;
|
2008-11-03 05:08:38 +01:00
|
|
|
for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) {
|
2004-09-05 19:44:41 +02:00
|
|
|
rmod->elaborate(des, instance[inst]);
|
2012-06-04 21:43:33 +02:00
|
|
|
instance[inst]->set_num_ports( rmod->port_count() );
|
2004-09-05 19:44:41 +02:00
|
|
|
}
|
2008-11-16 22:27:56 +01:00
|
|
|
if (debug_elaborate) cerr << get_fileline() << ": debug: ...done." << endl;
|
2004-09-05 19:44:41 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
// Now connect the ports of the newly elaborated designs to
|
1999-05-29 04:36:17 +02:00
|
|
|
// the expressions that are the instantiation parameters. Scan
|
|
|
|
|
// the pins, elaborate the expressions attached to them, and
|
|
|
|
|
// bind them to the port of the elaborated module.
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2000-11-05 07:05:59 +01:00
|
|
|
// This can get rather complicated because the port can be
|
2003-01-27 06:09:17 +01:00
|
|
|
// unconnected (meaning an empty parameter is passed) connected
|
2000-11-05 07:05:59 +01:00
|
|
|
// to a concatenation, or connected to an internally
|
|
|
|
|
// unconnected port.
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
for (unsigned idx = 0 ; idx < pins.size() ; idx += 1) {
|
2011-03-21 22:29:20 +01:00
|
|
|
bool unconnected_port = false;
|
2000-11-05 07:05:59 +01:00
|
|
|
|
|
|
|
|
// Skip unconnected module ports. This happens when a
|
|
|
|
|
// null parameter is passed in.
|
2003-02-22 05:12:49 +01:00
|
|
|
|
2004-03-08 01:47:44 +01:00
|
|
|
if (pins[idx] == 0) {
|
2009-11-26 18:39:21 +01:00
|
|
|
|
|
|
|
|
if (pins_fromwc[idx]) {
|
|
|
|
|
cerr << get_fileline() << ": error: Wildcard named port " <<
|
|
|
|
|
"connection (.*) did not find a matching identifier " <<
|
|
|
|
|
"for port '" << rmod->ports[idx]->name << "'." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 22:41:54 +02:00
|
|
|
// We need this information to support the
|
|
|
|
|
// unconnected_drive directive and for a
|
|
|
|
|
// unconnected input warning when asked for.
|
|
|
|
|
vector<PEIdent*> mport = rmod->get_port(idx);
|
2010-04-14 06:29:15 +02:00
|
|
|
if (mport.empty()) continue;
|
2009-05-27 22:41:54 +02:00
|
|
|
|
|
|
|
|
perm_string pname = peek_tail_name(mport[0]->path());
|
|
|
|
|
|
|
|
|
|
NetNet*tmp = instance[0]->find_signal(pname);
|
|
|
|
|
assert(tmp);
|
|
|
|
|
|
|
|
|
|
if (tmp->port_type() == NetNet::PINPUT) {
|
|
|
|
|
// If we have an unconnected input convert it
|
|
|
|
|
// as needed if an unconnected_drive directive
|
|
|
|
|
// was given. This only works for tri or wire!
|
|
|
|
|
switch (rmod->uc_drive) {
|
|
|
|
|
case Module::UCD_PULL0:
|
|
|
|
|
convert_net(des, this, tmp, NetNet::TRI0);
|
|
|
|
|
break;
|
|
|
|
|
case Module::UCD_PULL1:
|
|
|
|
|
convert_net(des, this, tmp, NetNet::TRI1);
|
|
|
|
|
break;
|
|
|
|
|
case Module::UCD_NONE:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-02-22 05:12:49 +01:00
|
|
|
|
2009-05-27 22:41:54 +02:00
|
|
|
// Print a waring for an unconnected input.
|
|
|
|
|
if (warn_portbinding) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: "
|
2003-02-22 05:12:49 +01:00
|
|
|
<< "Instantiating module "
|
|
|
|
|
<< rmod->mod_name()
|
2009-05-27 22:41:54 +02:00
|
|
|
<< " with dangling input port '"
|
|
|
|
|
<< rmod->ports[idx]->name;
|
|
|
|
|
switch (rmod->uc_drive) {
|
|
|
|
|
case Module::UCD_PULL0:
|
|
|
|
|
cerr << "' (pulled low)." << endl;
|
|
|
|
|
break;
|
|
|
|
|
case Module::UCD_PULL1:
|
|
|
|
|
cerr << "' (pulled high)." << endl;
|
|
|
|
|
break;
|
|
|
|
|
case Module::UCD_NONE:
|
|
|
|
|
cerr << "' (floating)." << endl;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-02-22 05:12:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-03-21 22:29:20 +01:00
|
|
|
unconnected_port = true;
|
2003-02-22 05:12:49 +01:00
|
|
|
}
|
|
|
|
|
|
2012-06-04 21:43:33 +02:00
|
|
|
// Inside the module, the port connects zero or more signals
|
2000-11-05 07:05:59 +01:00
|
|
|
// that were already elaborated. List all those signals
|
2004-09-05 19:44:41 +02:00
|
|
|
// and the NetNet equivalents, for all the instances.
|
2008-11-03 05:08:38 +01:00
|
|
|
vector<PEIdent*> mport = rmod->get_port(idx);
|
|
|
|
|
vector<NetNet*> prts (mport.size() * instance.size());
|
1999-08-04 04:13:02 +02:00
|
|
|
|
2005-02-10 05:56:58 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: " << get_name()
|
2008-11-16 22:27:56 +01:00
|
|
|
<< ": Port " << (idx+1) << " has " << prts.size()
|
2005-02-10 05:56:58 +01:00
|
|
|
<< " sub-ports." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
// Count the internal vector bits of the port.
|
|
|
|
|
unsigned prts_vector_width = 0;
|
2000-08-18 06:38:57 +02:00
|
|
|
|
2008-11-03 05:08:38 +01:00
|
|
|
for (unsigned inst = 0 ; inst < instance.size() ; inst += 1) {
|
2008-03-07 05:37:08 +01:00
|
|
|
// Scan the instances from MSB to LSB. The port
|
|
|
|
|
// will be assembled in that order as well.
|
2008-11-03 05:08:38 +01:00
|
|
|
NetScope*inst_scope = instance[instance.size()-inst-1];
|
2004-09-05 19:44:41 +02:00
|
|
|
|
2012-06-04 21:43:33 +02:00
|
|
|
unsigned int prt_vector_width = 0;
|
|
|
|
|
PortType::Enum ptype = PortType::PIMPLICIT;
|
2004-09-05 19:44:41 +02:00
|
|
|
// Scan the module sub-ports for this instance...
|
2008-11-03 05:08:38 +01:00
|
|
|
for (unsigned ldx = 0 ; ldx < mport.size() ; ldx += 1) {
|
|
|
|
|
unsigned lbase = inst * mport.size();
|
2004-09-05 19:44:41 +02:00
|
|
|
PEIdent*pport = mport[ldx];
|
|
|
|
|
assert(pport);
|
2012-06-04 21:43:33 +02:00
|
|
|
NetNet *netnet = pport->elaborate_subport(des, inst_scope);
|
|
|
|
|
prts[lbase + ldx] = netnet;
|
|
|
|
|
if (netnet == 0)
|
2004-09-05 19:44:41 +02:00
|
|
|
continue;
|
|
|
|
|
|
2012-06-04 21:43:33 +02:00
|
|
|
assert(netnet);
|
|
|
|
|
prts_vector_width += netnet->vector_width();
|
|
|
|
|
prt_vector_width += netnet->vector_width();
|
|
|
|
|
ptype = PortType::merged(netnet->port_type(), ptype);
|
2004-09-05 19:44:41 +02:00
|
|
|
}
|
2012-06-04 21:43:33 +02:00
|
|
|
inst_scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width );
|
1999-08-04 04:13:02 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
// If I find that the port is unconnected inside the
|
2000-11-05 07:05:59 +01:00
|
|
|
// module, then there is nothing to connect. Skip the
|
2004-09-05 19:44:41 +02:00
|
|
|
// argument.
|
2011-03-21 22:29:20 +01:00
|
|
|
if ((prts_vector_width == 0) || unconnected_port) {
|
2000-11-05 07:05:59 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-05 19:44:41 +02:00
|
|
|
// We know by design that each instance has the same
|
|
|
|
|
// width port. Therefore, the prts_pin_count must be an
|
|
|
|
|
// even multiple of the instance count.
|
2008-11-03 05:08:38 +01:00
|
|
|
assert(prts_vector_width % instance.size() == 0);
|
2004-09-05 19:44:41 +02:00
|
|
|
|
2011-03-13 14:29:42 +01:00
|
|
|
if (!prts.empty() && (prts[0]->port_type() == NetNet::PINPUT)
|
|
|
|
|
&& prts[0]->pin(0).nexus()->drivers_present()
|
|
|
|
|
&& pins[idx]->is_collapsible_net(des, scope)) {
|
|
|
|
|
prts[0]->port_type(NetNet::PINOUT);
|
|
|
|
|
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": warning: input port "
|
|
|
|
|
<< prts[0]->name() << " is coerced to inout." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-05 19:44:41 +02:00
|
|
|
// Elaborate the expression that connects to the
|
|
|
|
|
// module[s] port. sig is the thing outside the module
|
|
|
|
|
// that connects to the port.
|
2001-07-19 05:43:15 +02:00
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
NetNet*sig;
|
2010-04-14 06:29:15 +02:00
|
|
|
if (prts.empty() || (prts[0]->port_type() == NetNet::PINPUT)) {
|
2002-11-09 20:20:48 +01:00
|
|
|
|
2005-08-06 19:58:16 +02:00
|
|
|
/* Input to module. elaborate the expression to
|
|
|
|
|
the desired width. If this in an instance
|
2008-06-24 17:46:16 +02:00
|
|
|
array, then let the net determine its own
|
2005-08-06 19:58:16 +02:00
|
|
|
width. We use that, then, to decide how to hook
|
|
|
|
|
it up.
|
|
|
|
|
|
2008-11-27 00:37:38 +01:00
|
|
|
NOTE that this also handles the case that the
|
2005-08-06 19:58:16 +02:00
|
|
|
port is actually empty on the inside. We assume
|
|
|
|
|
in that case that the port is input. */
|
|
|
|
|
|
2011-02-26 23:59:52 +01:00
|
|
|
NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], -1);
|
2008-09-09 04:13:49 +02:00
|
|
|
if (tmp_expr == 0) {
|
|
|
|
|
cerr << pins[idx]->get_fileline()
|
|
|
|
|
<< ": internal error: Port expression "
|
|
|
|
|
<< "too complicated for elaboration." << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2012-09-30 00:13:45 +02:00
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Elaborating INPUT port expression: " << *tmp_expr << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-22 22:48:34 +01:00
|
|
|
sig = tmp_expr->synthesize(des, scope, tmp_expr);
|
2005-08-06 19:58:16 +02:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline()
|
2005-08-06 19:58:16 +02:00
|
|
|
<< ": internal error: Port expression "
|
|
|
|
|
<< "too complicated for elaboration." << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-09 04:13:49 +02:00
|
|
|
delete tmp_expr;
|
2008-11-19 02:17:19 +01:00
|
|
|
if (!sig->get_lineno()) sig->set_line(*this);
|
2008-09-09 04:13:49 +02:00
|
|
|
|
2008-08-07 06:04:52 +02:00
|
|
|
if (need_bufz_for_input_port(prts)) {
|
|
|
|
|
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
|
2010-07-12 02:16:15 +02:00
|
|
|
sig->vector_width(), true);
|
2008-08-07 06:04:52 +02:00
|
|
|
des->add_node(tmp);
|
|
|
|
|
connect(tmp->pin(1), sig->pin(0));
|
|
|
|
|
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
|
|
|
|
|
sig->vector_width()-1,0);
|
2008-08-07 06:04:52 +02:00
|
|
|
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::WIRE, tmp2_vec);
|
2008-08-07 06:04:52 +02:00
|
|
|
tmp2->local_flag(true);
|
|
|
|
|
tmp2->set_line(*this);
|
|
|
|
|
connect(tmp->pin(0), tmp2->pin(0));
|
|
|
|
|
sig = tmp2;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-25 03:28:28 +01:00
|
|
|
// If we have a real signal driving a bit/vector port
|
|
|
|
|
// then we convert the real value using the appropriate
|
|
|
|
|
// width cast. Since a real is only one bit the whole
|
|
|
|
|
// thing needs to go to each instance when arrayed.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_REAL ) &&
|
2010-04-14 06:29:15 +02:00
|
|
|
!prts.empty() && (prts[0]->data_type() != IVL_VT_REAL )) {
|
2010-10-16 19:53:20 +02:00
|
|
|
sig = cast_to_int4(des, scope, sig,
|
2010-03-25 03:28:28 +01:00
|
|
|
prts_vector_width/instance.size());
|
|
|
|
|
}
|
|
|
|
|
// If we have a bit/vector signal driving a real port
|
|
|
|
|
// then we convert the value to a real.
|
|
|
|
|
if ((sig->data_type() != IVL_VT_REAL ) &&
|
2010-04-14 06:29:15 +02:00
|
|
|
!prts.empty() && (prts[0]->data_type() == IVL_VT_REAL )) {
|
2010-03-25 03:28:28 +01:00
|
|
|
sig = cast_to_real(des, scope, sig);
|
|
|
|
|
}
|
2013-02-25 23:13:05 +01:00
|
|
|
// If we have a 4-state bit/vector signal driving a
|
|
|
|
|
// 2-state port then we convert the value to 2-state.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_LOGIC ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() == IVL_VT_BOOL )) {
|
|
|
|
|
sig = cast_to_int2(des, scope, sig,
|
|
|
|
|
sig->vector_width());
|
|
|
|
|
}
|
2010-03-25 03:28:28 +01:00
|
|
|
|
2005-08-06 19:58:16 +02:00
|
|
|
} else if (prts[0]->port_type() == NetNet::PINOUT) {
|
|
|
|
|
|
|
|
|
|
/* Inout to/from module. This is a more
|
|
|
|
|
complicated case, where the expression must be
|
|
|
|
|
an lnet, but also an r-value net.
|
|
|
|
|
|
|
|
|
|
Normally, this winds up being the same as if we
|
|
|
|
|
just elaborated as an lnet, as passing a simple
|
|
|
|
|
identifier elaborates to the same NetNet in
|
|
|
|
|
both cases so the extra elaboration has no
|
|
|
|
|
effect. But if the expression passed to the
|
2008-06-12 19:04:29 +02:00
|
|
|
inout port is a part select, a special part
|
|
|
|
|
select must be created that can pass data in
|
2005-08-06 19:58:16 +02:00
|
|
|
both directions.
|
|
|
|
|
|
|
|
|
|
Use the elaborate_bi_net method to handle all
|
|
|
|
|
the possible cases. */
|
|
|
|
|
|
|
|
|
|
sig = pins[idx]->elaborate_bi_net(des, scope);
|
2002-11-09 20:20:48 +01:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
2005-08-06 19:58:16 +02:00
|
|
|
<< "Inout port expression must support "
|
2002-11-09 20:20:48 +01:00
|
|
|
<< "continuous assignment." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline() << ": : "
|
2011-02-25 05:58:15 +01:00
|
|
|
<< "Port " << rmod->ports[idx]->name << " of "
|
|
|
|
|
<< rmod->mod_name() << " is connected to "
|
|
|
|
|
<< *pins[idx] << endl;
|
2002-11-09 20:20:48 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-25 23:15:35 +02:00
|
|
|
// We do not support automatic bits to real conversion
|
|
|
|
|
// for inout ports.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_REAL ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() != IVL_VT_REAL )) {
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "Cannot automatically connect bit based "
|
|
|
|
|
"inout port " << rmod->ports[idx]->name
|
|
|
|
|
<< " of module " << rmod->mod_name() << " to real "
|
|
|
|
|
"signal " << sig->name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-10-02 20:02:27 +02:00
|
|
|
|
2010-04-25 23:15:35 +02:00
|
|
|
// We do not support real inout ports at all.
|
|
|
|
|
if (!prts.empty() && (prts[0]->data_type() == IVL_VT_REAL )) {
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "No support for connecting real inout ports ("
|
|
|
|
|
"port "
|
|
|
|
|
<< rmod->ports[idx]->name << " of module "
|
|
|
|
|
<< rmod->mod_name() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-06 19:58:16 +02:00
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
} else {
|
2004-09-05 19:44:41 +02:00
|
|
|
|
2005-08-06 19:58:16 +02:00
|
|
|
/* Port type must be OUTPUT here. */
|
2012-02-25 19:19:48 +01:00
|
|
|
ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT);
|
2005-08-06 19:58:16 +02:00
|
|
|
|
|
|
|
|
/* Output from module. Elaborate the port
|
|
|
|
|
expression as the l-value of a continuous
|
|
|
|
|
assignment, as the port will continuous assign
|
|
|
|
|
into the port. */
|
|
|
|
|
|
2008-03-19 04:50:40 +01:00
|
|
|
sig = pins[idx]->elaborate_lnet(des, scope);
|
2002-11-09 20:20:48 +01:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
2005-08-06 19:58:16 +02:00
|
|
|
<< "Output port expression must support "
|
|
|
|
|
<< "continuous assignment." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline() << ": : "
|
2011-02-25 05:58:15 +01:00
|
|
|
<< "Port " << rmod->ports[idx]->name << " of "
|
|
|
|
|
<< rmod->mod_name() << " is connected to "
|
|
|
|
|
<< *pins[idx] << endl;
|
2005-08-06 19:58:16 +02:00
|
|
|
des->errors += 1;
|
2002-11-09 20:20:48 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2005-08-06 19:58:16 +02:00
|
|
|
|
2010-04-25 23:15:35 +02:00
|
|
|
// If we have a real port driving a bit/vector signal
|
|
|
|
|
// then we convert the real value using the appropriate
|
|
|
|
|
// width cast. Since a real is only one bit the whole
|
|
|
|
|
// thing needs to go to each instance when arrayed.
|
|
|
|
|
if ((sig->data_type() != IVL_VT_REAL ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() == IVL_VT_REAL )) {
|
|
|
|
|
if (sig->vector_width() % instance.size() != 0) {
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
|
|
|
|
"When automatically converting a real "
|
|
|
|
|
"port of an arrayed instance to a bit "
|
|
|
|
|
"signal" << endl;
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": : "
|
|
|
|
|
"the signal width ("
|
|
|
|
|
<< sig->vector_width() << ") must be an "
|
|
|
|
|
"integer multiple of the instance count ("
|
|
|
|
|
<< instance.size() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
prts_vector_width = sig->vector_width();
|
2010-05-13 03:53:56 +02:00
|
|
|
for (unsigned pidx = 0; pidx < prts.size(); pidx += 1) {
|
|
|
|
|
prts[pidx]->port_type(NetNet::NOT_A_PORT);
|
2010-10-16 19:53:20 +02:00
|
|
|
prts[pidx] = cast_to_int4(des, scope, prts[pidx],
|
2010-06-02 04:24:09 +02:00
|
|
|
prts_vector_width /
|
|
|
|
|
instance.size());
|
2010-05-13 03:53:56 +02:00
|
|
|
prts[pidx]->port_type(NetNet::POUTPUT);
|
2010-04-25 23:15:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have a bit/vector port driving a single real
|
|
|
|
|
// signal then we convert the value to a real.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_REAL ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() != IVL_VT_REAL )) {
|
|
|
|
|
prts_vector_width -= prts[0]->vector_width() - 1;
|
|
|
|
|
prts[0]->port_type(NetNet::NOT_A_PORT);
|
|
|
|
|
prts[0] = cast_to_real(des, scope, prts[0]);
|
|
|
|
|
prts[0]->port_type(NetNet::POUTPUT);
|
|
|
|
|
// No support for multiple real drivers.
|
|
|
|
|
if (instance.size() != 1) {
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "Cannot connect an arrayed instance of "
|
|
|
|
|
"module " << rmod->mod_name() << " to "
|
|
|
|
|
"real signal " << sig->name() << "."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-25 23:13:05 +01:00
|
|
|
// If we have a 4-state bit/vector port driving a
|
|
|
|
|
// 2-state signal then we convert the value to 2-state.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_BOOL ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() == IVL_VT_LOGIC )) {
|
|
|
|
|
for (unsigned pidx = 0; pidx < prts.size(); pidx += 1) {
|
|
|
|
|
prts[pidx]->port_type(NetNet::NOT_A_PORT);
|
|
|
|
|
prts[pidx] = cast_to_int2(des, scope, prts[pidx],
|
|
|
|
|
prts[pidx]->vector_width());
|
|
|
|
|
prts[pidx]->port_type(NetNet::POUTPUT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-25 23:15:35 +02:00
|
|
|
// A real to real connection is not allowed for arrayed
|
|
|
|
|
// instances. You cannot have multiple real drivers.
|
|
|
|
|
if ((sig->data_type() == IVL_VT_REAL ) &&
|
|
|
|
|
!prts.empty() && (prts[0]->data_type() == IVL_VT_REAL ) &&
|
|
|
|
|
instance.size() != 1) {
|
|
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "An arrayed instance of " << rmod->mod_name()
|
|
|
|
|
<< " cannot have a real port ("
|
|
|
|
|
<< rmod->ports[idx]->name << ") connected to a "
|
|
|
|
|
"real signal (" << sig->name() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
#ifndef NDEBUG
|
2012-11-13 03:13:41 +01:00
|
|
|
if ((! prts.empty())
|
2001-07-19 05:43:15 +02:00
|
|
|
&& (prts[0]->port_type() != NetNet::PINPUT)) {
|
2002-11-09 20:20:48 +01:00
|
|
|
assert(sig->type() != NetNet::REG);
|
2001-07-19 05:43:15 +02:00
|
|
|
}
|
2002-11-09 20:20:48 +01:00
|
|
|
#endif
|
2000-11-05 07:05:59 +01:00
|
|
|
|
2004-09-05 19:44:41 +02:00
|
|
|
/* If we are working with an instance array, then the
|
|
|
|
|
signal width must match the port width exactly. */
|
2008-11-03 05:08:38 +01:00
|
|
|
if ((instance.size() != 1)
|
2005-01-09 21:16:00 +01:00
|
|
|
&& (sig->vector_width() != prts_vector_width)
|
2008-11-03 05:08:38 +01:00
|
|
|
&& (sig->vector_width() != prts_vector_width/instance.size())) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << pins[idx]->get_fileline() << ": error: "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< "Port expression width " << sig->vector_width()
|
|
|
|
|
<< " does not match expected width "<< prts_vector_width
|
2008-11-03 05:08:38 +01:00
|
|
|
<< " or " << (prts_vector_width/instance.size())
|
2004-09-05 19:44:41 +02:00
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-10 05:56:58 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: " << get_name()
|
2007-06-05 23:35:51 +02:00
|
|
|
<< ": Port " << (idx+1) << " has vector width of "
|
2005-02-10 05:56:58 +01:00
|
|
|
<< prts_vector_width << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
1999-02-01 01:26:48 +01:00
|
|
|
// Check that the parts have matching pin counts. If
|
2000-10-26 19:09:46 +02:00
|
|
|
// not, they are different widths. Note that idx is 0
|
|
|
|
|
// based, but users count parameter positions from 1.
|
2008-11-03 05:08:38 +01:00
|
|
|
if ((instance.size() == 1)
|
2005-01-09 21:16:00 +01:00
|
|
|
&& (prts_vector_width != sig->vector_width())) {
|
2007-06-05 23:35:51 +02:00
|
|
|
const char *tmp3 = rmod->ports[idx]->name.str();
|
2008-10-15 19:57:37 +02:00
|
|
|
bool as_signed = false;
|
|
|
|
|
|
2007-06-05 23:35:51 +02:00
|
|
|
if (tmp3 == 0) tmp3 = "???";
|
2008-10-15 19:57:37 +02:00
|
|
|
|
|
|
|
|
switch (prts[0]->port_type()) {
|
|
|
|
|
case NetNet::POUTPUT:
|
|
|
|
|
as_signed = prts[0]->get_signed();
|
|
|
|
|
break;
|
|
|
|
|
case NetNet::PINPUT:
|
|
|
|
|
as_signed = sig->get_signed();
|
|
|
|
|
break;
|
|
|
|
|
case NetNet::PINOUT:
|
|
|
|
|
/* This may not be correct! */
|
|
|
|
|
as_signed = prts[0]->get_signed() && sig->get_signed();
|
|
|
|
|
break;
|
2012-02-25 19:19:48 +01:00
|
|
|
case NetNet::PREF:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
break;
|
2008-10-15 19:57:37 +02:00
|
|
|
default:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: Port " << (idx+1)
|
2007-06-05 23:35:51 +02:00
|
|
|
<< " (" << tmp3 << ") of "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< type_ << " expects " << prts_vector_width <<
|
|
|
|
|
" bits, got " << sig->vector_width() << "." << endl;
|
2001-01-09 06:58:47 +01:00
|
|
|
|
2008-10-03 03:38:53 +02:00
|
|
|
// Delete this when inout ports pad correctly.
|
|
|
|
|
if (prts[0]->port_type() == NetNet::PINOUT) {
|
|
|
|
|
if (prts_vector_width > sig->vector_width()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : Leaving "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< (prts_vector_width-sig->vector_width())
|
2001-01-09 06:58:47 +01:00
|
|
|
<< " high bits of the port unconnected."
|
|
|
|
|
<< endl;
|
2008-10-03 03:38:53 +02:00
|
|
|
} else {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : Leaving "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< (sig->vector_width()-prts_vector_width)
|
2002-08-01 01:55:38 +02:00
|
|
|
<< " high bits of the expression dangling."
|
2001-01-09 06:58:47 +01:00
|
|
|
<< endl;
|
2008-10-03 03:38:53 +02:00
|
|
|
}
|
|
|
|
|
// Keep the if, but delete the "} else" when fixed.
|
|
|
|
|
} else if (prts_vector_width > sig->vector_width()) {
|
2008-10-15 19:57:37 +02:00
|
|
|
cerr << get_fileline() << ": : Padding ";
|
|
|
|
|
if (as_signed) cerr << "(signed) ";
|
|
|
|
|
cerr << (prts_vector_width-sig->vector_width())
|
2008-10-03 03:38:53 +02:00
|
|
|
<< " high bits of the port."
|
|
|
|
|
<< endl;
|
|
|
|
|
} else {
|
2011-03-13 20:01:10 +01:00
|
|
|
if (prts[0]->port_type() == NetNet::PINPUT) {
|
|
|
|
|
cerr << get_fileline() << ": : Pruning ";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << get_fileline() << ": : Padding ";
|
|
|
|
|
}
|
2008-10-15 19:57:37 +02:00
|
|
|
if (as_signed) cerr << "(signed) ";
|
|
|
|
|
cerr << (sig->vector_width()-prts_vector_width)
|
2008-10-03 03:38:53 +02:00
|
|
|
<< " high bits of the expression."
|
|
|
|
|
<< endl;
|
2001-01-09 06:58:47 +01:00
|
|
|
}
|
2007-09-10 06:14:52 +02:00
|
|
|
|
|
|
|
|
sig = resize_net_to_port_(des, scope, sig, prts_vector_width,
|
2008-10-15 19:57:37 +02:00
|
|
|
prts[0]->port_type(), as_signed);
|
1999-02-01 01:26:48 +01:00
|
|
|
}
|
|
|
|
|
|
1999-08-04 04:13:02 +02:00
|
|
|
// Connect the sig expression that is the context of the
|
2001-01-09 06:58:47 +01:00
|
|
|
// module instance to the ports of the elaborated module.
|
|
|
|
|
|
|
|
|
|
// The prts_pin_count variable is the total width of the
|
|
|
|
|
// port and is the maximum number of connections to
|
|
|
|
|
// make. sig is the elaborated expression that connects
|
|
|
|
|
// to that port. If sig has too few pins, then reduce
|
|
|
|
|
// the number of connections to make.
|
|
|
|
|
|
|
|
|
|
// Connect this many of the port pins. If the expression
|
2005-01-09 21:16:00 +01:00
|
|
|
// is too small, then reduce the number of connects.
|
|
|
|
|
unsigned ccount = prts_vector_width;
|
2008-11-03 05:08:38 +01:00
|
|
|
if (instance.size() == 1 && sig->vector_width() < ccount)
|
2005-01-09 21:16:00 +01:00
|
|
|
ccount = sig->vector_width();
|
2001-01-09 06:58:47 +01:00
|
|
|
|
|
|
|
|
// Now scan the concatenation that makes up the port,
|
|
|
|
|
// connecting pins until we run out of port pins or sig
|
2005-01-09 21:16:00 +01:00
|
|
|
// pins. The sig object is the NetNet that is connected
|
|
|
|
|
// to the port from the outside, and the prts object is
|
|
|
|
|
// an array of signals to be connected to the sig.
|
2001-01-09 06:58:47 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
NetConcat*ctmp;
|
|
|
|
|
|
2008-11-03 05:08:38 +01:00
|
|
|
if (prts.size() == 1) {
|
2005-01-09 21:16:00 +01:00
|
|
|
|
|
|
|
|
// The simplest case, there are no
|
|
|
|
|
// parts/concatenations on the inside of the
|
|
|
|
|
// module, so the port and sig need simply be
|
|
|
|
|
// connected directly.
|
|
|
|
|
connect(prts[0]->pin(0), sig->pin(0));
|
|
|
|
|
|
2008-11-03 05:08:38 +01:00
|
|
|
} else if (sig->vector_width()==prts_vector_width/instance.size()
|
|
|
|
|
&& prts.size()/instance.size() == 1) {
|
2005-02-10 05:56:58 +01:00
|
|
|
|
|
|
|
|
if (debug_elaborate){
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: " << get_name()
|
2005-02-10 05:56:58 +01:00
|
|
|
<< ": Replicating " << prts_vector_width
|
|
|
|
|
<< " bits across all "
|
2008-11-03 05:08:38 +01:00
|
|
|
<< prts_vector_width/instance.size()
|
2005-02-10 05:56:58 +01:00
|
|
|
<< " sub-ports." << endl;
|
|
|
|
|
}
|
2005-01-09 21:16:00 +01:00
|
|
|
|
|
|
|
|
// The signal width is exactly the width of a
|
|
|
|
|
// single instance of the port. In this case,
|
|
|
|
|
// connect the sig to all the ports identically.
|
2008-11-03 05:08:38 +01:00
|
|
|
for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1)
|
2005-01-09 21:16:00 +01:00
|
|
|
connect(prts[ldx]->pin(0), sig->pin(0));
|
|
|
|
|
|
|
|
|
|
} else switch (prts[0]->port_type()) {
|
|
|
|
|
case NetNet::POUTPUT:
|
|
|
|
|
ctmp = new NetConcat(scope, scope->local_symbol(),
|
2008-11-03 05:08:38 +01:00
|
|
|
prts_vector_width, prts.size());
|
2011-02-10 06:03:08 +01:00
|
|
|
ctmp->set_line(*this);
|
2005-01-09 21:16:00 +01:00
|
|
|
des->add_node(ctmp);
|
|
|
|
|
connect(ctmp->pin(0), sig->pin(0));
|
2008-11-03 05:08:38 +01:00
|
|
|
for (unsigned ldx = 0 ; ldx < prts.size() ; ldx += 1) {
|
2005-01-09 21:16:00 +01:00
|
|
|
connect(ctmp->pin(ldx+1),
|
2008-11-03 05:08:38 +01:00
|
|
|
prts[prts.size()-ldx-1]->pin(0));
|
1999-08-04 04:13:02 +02:00
|
|
|
}
|
2005-01-09 21:16:00 +01:00
|
|
|
break;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
case NetNet::PINPUT:
|
2005-02-10 05:56:58 +01:00
|
|
|
if (debug_elaborate){
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: " << get_name()
|
2005-02-10 05:56:58 +01:00
|
|
|
<< ": Dividing " << prts_vector_width
|
|
|
|
|
<< " bits across all "
|
2008-11-03 05:08:38 +01:00
|
|
|
<< prts_vector_width/instance.size()
|
2005-02-10 05:56:58 +01:00
|
|
|
<< " input sub-ports of port "
|
2008-11-16 22:27:56 +01:00
|
|
|
<< (idx+1) << "." << endl;
|
2005-02-10 05:56:58 +01:00
|
|
|
}
|
|
|
|
|
|
2011-06-23 19:36:26 +02:00
|
|
|
for (unsigned ldx = 0, spin = 0 ;
|
|
|
|
|
ldx < prts.size() ; ldx += 1) {
|
2008-11-03 05:08:38 +01:00
|
|
|
NetNet*sp = prts[prts.size()-ldx-1];
|
2005-01-09 21:16:00 +01:00
|
|
|
NetPartSelect*ptmp = new NetPartSelect(sig, spin,
|
|
|
|
|
sp->vector_width(),
|
|
|
|
|
NetPartSelect::VP);
|
2011-02-10 06:03:08 +01:00
|
|
|
ptmp->set_line(*this);
|
2005-01-09 21:16:00 +01:00
|
|
|
des->add_node(ptmp);
|
|
|
|
|
connect(ptmp->pin(0), sp->pin(0));
|
|
|
|
|
spin += sp->vector_width();
|
|
|
|
|
}
|
|
|
|
|
break;
|
2008-11-15 00:20:01 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
case NetNet::PINOUT:
|
2011-06-23 19:36:26 +02:00
|
|
|
for (unsigned ldx = 0, spin = 0 ;
|
|
|
|
|
ldx < prts.size() ; ldx += 1) {
|
2008-11-15 00:20:01 +01:00
|
|
|
NetNet*sp = prts[prts.size()-ldx-1];
|
|
|
|
|
NetTran*ttmp = new NetTran(scope,
|
|
|
|
|
scope->local_symbol(),
|
|
|
|
|
sig->vector_width(),
|
|
|
|
|
sp->vector_width(),
|
|
|
|
|
spin);
|
|
|
|
|
ttmp->set_line(*this);
|
2011-02-10 06:03:08 +01:00
|
|
|
des->add_node(ttmp);
|
2008-11-15 00:20:01 +01:00
|
|
|
connect(ttmp->pin(0), sig->pin(0));
|
|
|
|
|
connect(ttmp->pin(1), sp->pin(0));
|
|
|
|
|
spin += sp->vector_width();
|
|
|
|
|
}
|
2005-01-09 21:16:00 +01:00
|
|
|
break;
|
2008-11-15 00:20:01 +01:00
|
|
|
|
2012-02-25 19:19:48 +01:00
|
|
|
case NetNet::PREF:
|
|
|
|
|
cerr << get_fileline() << ": sorry: "
|
|
|
|
|
<< "Reference ports not supported yet." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
case NetNet::PIMPLICIT:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< "Unexpected IMPLICIT port" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
case NetNet::NOT_A_PORT:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< "Unexpected NOT_A_PORT port." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-01-09 06:58:47 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
2004-09-05 19:44:41 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-04 19:43:58 +02:00
|
|
|
unsigned PGModule::calculate_instance_count_(Design*des, NetScope*scope,
|
|
|
|
|
long&high, long&low,
|
|
|
|
|
perm_string name) const
|
|
|
|
|
{
|
|
|
|
|
unsigned count = 1;
|
|
|
|
|
high = 0;
|
|
|
|
|
low = 0;
|
|
|
|
|
|
|
|
|
|
/* If the Verilog source has a range specification for the UDP, then
|
|
|
|
|
* I am expected to make more than one gate. Figure out how many are
|
|
|
|
|
* desired. */
|
|
|
|
|
if (msb_) {
|
2011-04-07 04:48:41 +02:00
|
|
|
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true);
|
|
|
|
|
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true);
|
2011-04-04 19:43:58 +02:00
|
|
|
|
|
|
|
|
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
|
|
|
|
|
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
|
|
|
|
|
|
|
|
|
|
if (msb_con == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Unable to evaluate "
|
|
|
|
|
"expression " << *msb_ << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lsb_con == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Unable to evaluate "
|
|
|
|
|
"expression " << *lsb_ << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum msb = msb_con->value();
|
|
|
|
|
verinum lsb = lsb_con->value();
|
|
|
|
|
|
|
|
|
|
delete msb_exp;
|
|
|
|
|
delete lsb_exp;
|
|
|
|
|
|
|
|
|
|
if (msb.as_long() > lsb.as_long())
|
|
|
|
|
count = msb.as_long() - lsb.as_long() + 1;
|
|
|
|
|
else
|
|
|
|
|
count = lsb.as_long() - msb.as_long() + 1;
|
|
|
|
|
|
|
|
|
|
low = lsb.as_long();
|
|
|
|
|
high = msb.as_long();
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: PGModule: Make range "
|
|
|
|
|
<< "[" << high << ":" << low << "]" << " of "
|
|
|
|
|
<< count << " UDPs for " << name << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
/*
|
|
|
|
|
* From a UDP definition in the source, make a NetUDP
|
|
|
|
|
* object. Elaborate the pin expressions as netlists, then connect
|
|
|
|
|
* those networks to the pins.
|
|
|
|
|
*/
|
2001-04-23 01:09:45 +02:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
|
1998-12-01 01:42:13 +01:00
|
|
|
{
|
2006-01-02 06:33:19 +01:00
|
|
|
NetExpr*rise_expr =0, *fall_expr =0, *decay_expr =0;
|
2001-04-29 01:18:08 +02:00
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
perm_string my_name = get_name();
|
|
|
|
|
if (my_name == 0)
|
2003-03-06 01:28:41 +01:00
|
|
|
my_name = scope->local_symbol();
|
2001-04-29 01:18:08 +02:00
|
|
|
|
2001-12-06 05:44:11 +01:00
|
|
|
/* When the parser notices delay expressions in front of a
|
|
|
|
|
module or primitive, it interprets them as parameter
|
|
|
|
|
overrides. Correct that misconception here. */
|
|
|
|
|
if (overrides_) {
|
2010-10-26 04:36:44 +02:00
|
|
|
if (overrides_->size() > 2) {
|
2009-08-04 05:21:50 +02:00
|
|
|
cerr << get_fileline() << ": error: UDPs take at most two "
|
|
|
|
|
"delay arguments." << endl;
|
2006-01-02 06:33:19 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
2009-08-04 05:21:50 +02:00
|
|
|
PDelays tmp_del;
|
|
|
|
|
tmp_del.set_delays(overrides_, false);
|
|
|
|
|
tmp_del.eval_delays(des, scope, rise_expr, fall_expr,
|
|
|
|
|
decay_expr);
|
2006-01-02 06:33:19 +01:00
|
|
|
}
|
2001-12-06 05:44:11 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-04 19:43:58 +02:00
|
|
|
long low = 0, high = 0;
|
|
|
|
|
unsigned inst_count = calculate_instance_count_(des, scope, high, low,
|
|
|
|
|
my_name);
|
|
|
|
|
if (inst_count == 0) return;
|
|
|
|
|
|
|
|
|
|
if (inst_count != 1) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: UDPs with a range ("
|
|
|
|
|
<< my_name << " [" << high << ":" << low << "]) are "
|
|
|
|
|
<< "not supported." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
assert(udp);
|
2001-04-24 04:23:58 +02:00
|
|
|
NetUDP*net = new NetUDP(scope, my_name, udp->ports.count(), udp);
|
2011-02-10 06:03:08 +01:00
|
|
|
net->set_line(*this);
|
2006-01-02 06:33:19 +01:00
|
|
|
net->rise_time(rise_expr);
|
|
|
|
|
net->fall_time(fall_expr);
|
|
|
|
|
net->decay_time(decay_expr);
|
1998-12-01 01:42:13 +01:00
|
|
|
|
2012-11-13 03:13:41 +01:00
|
|
|
struct attrib_list_t*attrib_list;
|
2002-05-23 05:08:50 +02:00
|
|
|
unsigned attrib_list_n = 0;
|
|
|
|
|
attrib_list = evaluate_attributes(attributes, attrib_list_n,
|
|
|
|
|
des, scope);
|
|
|
|
|
|
|
|
|
|
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
|
|
|
|
|
net->attribute(attrib_list[adx].key, attrib_list[adx].val);
|
|
|
|
|
|
|
|
|
|
delete[]attrib_list;
|
|
|
|
|
|
2004-03-08 01:47:44 +01:00
|
|
|
|
|
|
|
|
// This is the array of pin expressions, shuffled to match the
|
|
|
|
|
// order of the declaration. If the source instantiation uses
|
|
|
|
|
// bind by order, this is the same as the source
|
|
|
|
|
// list. Otherwise, the source list is rearranged by name
|
|
|
|
|
// binding into this list.
|
2010-10-26 04:36:44 +02:00
|
|
|
vector<PExpr*>pins;
|
2004-03-08 01:47:44 +01:00
|
|
|
|
|
|
|
|
// Detect binding by name. If I am binding by name, then make
|
|
|
|
|
// up a pins array that reflects the positions of the named
|
|
|
|
|
// ports. If this is simply positional binding in the first
|
|
|
|
|
// place, then get the binding from the base class.
|
|
|
|
|
if (pins_) {
|
|
|
|
|
unsigned nexp = udp->ports.count();
|
2010-10-26 04:36:44 +02:00
|
|
|
pins = vector<PExpr*>(nexp);
|
2004-03-08 01:47:44 +01:00
|
|
|
|
|
|
|
|
// Scan the bindings, matching them with port names.
|
|
|
|
|
for (unsigned idx = 0 ; idx < npins_ ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
// Given a binding, look at the module port names
|
|
|
|
|
// for the position that matches the binding name.
|
|
|
|
|
unsigned pidx = udp->find_port(pins_[idx].name);
|
|
|
|
|
|
|
|
|
|
// If the port name doesn't exist, the find_port
|
|
|
|
|
// method will return the port count. Detect that
|
|
|
|
|
// as an error.
|
|
|
|
|
if (pidx == nexp) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: port ``" <<
|
2004-03-08 01:47:44 +01:00
|
|
|
pins_[idx].name << "'' is not a port of "
|
|
|
|
|
<< get_name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If I already bound something to this port, then
|
|
|
|
|
// the (*exp) array will already have a pointer
|
|
|
|
|
// value where I want to place this expression.
|
|
|
|
|
if (pins[pidx]) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: port ``" <<
|
2004-03-08 01:47:44 +01:00
|
|
|
pins_[idx].name << "'' already bound." <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OK, do the binding by placing the expression in
|
|
|
|
|
// the right place.
|
|
|
|
|
pins[pidx] = pins_[idx].parm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Otherwise, this is a positional list of port
|
|
|
|
|
connections. In this case, the port count must be
|
|
|
|
|
right. Check that is is, the get the pin list. */
|
|
|
|
|
|
|
|
|
|
if (pin_count() != udp->ports.count()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Wrong number "
|
2004-03-08 01:47:44 +01:00
|
|
|
"of ports. Expecting " << udp->ports.count() <<
|
|
|
|
|
", got " << pin_count() << "."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No named bindings, just use the positional list I
|
|
|
|
|
// already have.
|
|
|
|
|
assert(pin_count() == udp->ports.count());
|
|
|
|
|
pins = get_pins();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-03-08 01:10:29 +01:00
|
|
|
/* Handle the output port of the primitive special. It is an
|
|
|
|
|
output port (the only output port) so must be passed an
|
|
|
|
|
l-value net. */
|
2004-03-08 01:47:44 +01:00
|
|
|
if (pins[0] == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: output port unconnected."
|
2004-03-08 01:10:29 +01:00
|
|
|
<< endl;
|
|
|
|
|
|
|
|
|
|
} else {
|
2008-03-19 04:50:40 +01:00
|
|
|
NetNet*sig = pins[0]->elaborate_lnet(des, scope);
|
2004-03-08 01:10:29 +01:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: "
|
2004-03-08 01:10:29 +01:00
|
|
|
<< "Output port expression is not valid." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : Output "
|
2004-03-08 01:10:29 +01:00
|
|
|
<< "port of " << udp->name_
|
|
|
|
|
<< " is " << udp->ports[0] << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
} else {
|
|
|
|
|
connect(sig->pin(0), net->pin(0));
|
|
|
|
|
}
|
2011-02-07 04:47:11 +01:00
|
|
|
if (sig->vector_width() != 1) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "Output port expression " << *pins[0]
|
|
|
|
|
<< " is too wide (" << sig->vector_width()
|
|
|
|
|
<< ") expected 1." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
2004-03-08 01:10:29 +01:00
|
|
|
}
|
|
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
/* Run through the pins, making netlists for the pin
|
|
|
|
|
expressions and connecting them to the pin in question. All
|
|
|
|
|
of this is independent of the nature of the UDP. */
|
2004-03-08 01:10:29 +01:00
|
|
|
for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) {
|
2004-03-08 01:47:44 +01:00
|
|
|
if (pins[idx] == 0)
|
1998-12-02 05:37:13 +01:00
|
|
|
continue;
|
|
|
|
|
|
2011-02-26 23:59:52 +01:00
|
|
|
NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1);
|
2008-09-09 04:13:49 +02:00
|
|
|
if (expr_tmp == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << "internal error: Expression too complicated "
|
2011-02-07 04:47:11 +01:00
|
|
|
"for elaboration:" << *pins[idx] << endl;
|
1998-12-01 01:42:13 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2008-12-22 22:48:34 +01:00
|
|
|
NetNet*sig = expr_tmp->synthesize(des, scope, expr_tmp);
|
2008-09-09 04:13:49 +02:00
|
|
|
ivl_assert(*this, sig);
|
|
|
|
|
sig->set_line(*this);
|
|
|
|
|
|
|
|
|
|
delete expr_tmp;
|
1998-12-01 01:42:13 +01:00
|
|
|
|
|
|
|
|
connect(sig->pin(0), net->pin(idx));
|
2011-02-07 04:47:11 +01:00
|
|
|
if (sig->vector_width() != 1) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "Input port expression " << *pins[idx]
|
|
|
|
|
<< " is too wide (" << sig->vector_width()
|
|
|
|
|
<< ") expected 1." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
1998-12-01 01:42:13 +01:00
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
// All done. Add the object to the design.
|
1998-12-01 01:42:13 +01:00
|
|
|
des->add_node(net);
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-02 18:27:38 +02:00
|
|
|
|
|
|
|
|
bool PGModule::elaborate_sig(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2012-05-10 04:35:11 +02:00
|
|
|
if (bound_type_) {
|
|
|
|
|
return elaborate_sig_mod_(des, scope, bound_type_);
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-02 18:27:38 +02:00
|
|
|
// Look for the module type
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*>::const_iterator mod = pform_modules.find(type_);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (mod != pform_modules.end())
|
2000-05-02 18:27:38 +02:00
|
|
|
return elaborate_sig_mod_(des, scope, (*mod).second);
|
|
|
|
|
|
2010-11-01 22:37:06 +01:00
|
|
|
// elaborate_sig_udp_ currently always returns true so skip all this
|
|
|
|
|
// for now.
|
|
|
|
|
#if 0
|
2008-03-21 05:44:35 +01:00
|
|
|
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
|
|
|
|
if (udp != pform_primitives.end())
|
|
|
|
|
return elaborate_sig_udp_(des, scope, (*udp).second);
|
2010-11-01 22:37:06 +01:00
|
|
|
#endif
|
2008-03-21 05:44:35 +01:00
|
|
|
|
2000-05-02 18:27:38 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGModule::elaborate(Design*des, NetScope*scope) const
|
1998-12-01 01:42:13 +01:00
|
|
|
{
|
2012-05-10 04:35:11 +02:00
|
|
|
if (bound_type_) {
|
|
|
|
|
elaborate_mod_(des, bound_type_, scope);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
// Look for the module type
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*>::const_iterator mod = pform_modules.find(type_);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (mod != pform_modules.end()) {
|
2001-11-22 07:20:59 +01:00
|
|
|
elaborate_mod_(des, (*mod).second, scope);
|
1998-12-01 01:42:13 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try a primitive type
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (udp != pform_primitives.end()) {
|
2004-03-08 01:10:29 +01:00
|
|
|
assert((*udp).second);
|
2001-11-22 07:20:59 +01:00
|
|
|
elaborate_udp_(des, (*udp).second, scope);
|
1998-12-01 01:42:13 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: Unknown module type: " <<
|
2000-03-08 05:36:53 +01:00
|
|
|
type_ << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PGModule::elaborate_scope(Design*des, NetScope*sc) const
|
|
|
|
|
{
|
2012-05-10 04:35:11 +02:00
|
|
|
// If the module type is known by design, then go right to it.
|
|
|
|
|
if (bound_type_) {
|
|
|
|
|
elaborate_scope_mod_(des, bound_type_, sc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
// Look for the module type
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*>::const_iterator mod = pform_modules.find(type_);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (mod != pform_modules.end()) {
|
2012-05-10 04:35:11 +02:00
|
|
|
elaborate_scope_mod_(des, mod->second, sc);
|
2000-03-08 05:36:53 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try a primitive type
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (udp != pform_primitives.end())
|
2000-03-08 05:36:53 +01:00
|
|
|
return;
|
|
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
// Not a module or primitive that I know about yet, so try to
|
|
|
|
|
// load a library module file (which parses some new Verilog
|
|
|
|
|
// code) and try again.
|
2001-10-21 02:42:47 +02:00
|
|
|
if (load_module(type_)) {
|
2001-10-21 01:02:39 +02:00
|
|
|
|
|
|
|
|
// Try again to find the module type
|
|
|
|
|
mod = pform_modules.find(type_);
|
|
|
|
|
if (mod != pform_modules.end()) {
|
2012-05-10 04:35:11 +02:00
|
|
|
elaborate_scope_mod_(des, mod->second, sc);
|
2001-10-21 01:02:39 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
// Try again to find a primitive type
|
|
|
|
|
udp = pform_primitives.find(type_);
|
|
|
|
|
if (udp != pform_primitives.end())
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Not a module or primitive that I know about or can find by
|
|
|
|
|
// any means, so give up.
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unknown module type: " << type_ << endl;
|
2003-09-25 02:25:14 +02:00
|
|
|
missing_modules[type_] += 1;
|
2000-03-08 05:36:53 +01:00
|
|
|
des->errors += 1;
|
1998-12-01 01:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* Statement::elaborate(Design*des, NetScope*) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: elaborate: "
|
2001-11-22 07:20:59 +01:00
|
|
|
"What kind of statement? " << typeid(*this).name() << endl;
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc*cur = new NetProc;
|
2000-07-26 07:08:07 +02:00
|
|
|
des->errors += 1;
|
1998-11-04 00:28:49 +01:00
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2002-06-04 07:38:43 +02:00
|
|
|
assert(lval_);
|
2004-12-30 00:55:43 +01:00
|
|
|
return lval_->elaborate_lval(des, scope, false);
|
1999-06-14 01:51:16 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-01 03:03:10 +02:00
|
|
|
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
|
|
|
|
ivl_type_t net_type) const
|
|
|
|
|
{
|
|
|
|
|
ivl_assert(*this, rval_);
|
|
|
|
|
|
|
|
|
|
NetExpr*rv = rval_->elaborate_expr(des, scope, net_type, 0);
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, !is_constant_);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-21 06:47:07 +02:00
|
|
|
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
|
2008-09-23 06:09:06 +02:00
|
|
|
unsigned lv_width,
|
|
|
|
|
ivl_variable_type_t lv_type) const
|
2008-08-21 06:47:07 +02:00
|
|
|
{
|
|
|
|
|
ivl_assert(*this, rval_);
|
|
|
|
|
|
2011-03-27 12:08:33 +02:00
|
|
|
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval(),
|
|
|
|
|
is_constant_);
|
2008-08-21 06:47:07 +02:00
|
|
|
|
2008-10-04 16:30:34 +02:00
|
|
|
if (!is_constant_ || !rv) return rv;
|
|
|
|
|
|
|
|
|
|
if (dynamic_cast<NetEConst*>(rv)) return rv;
|
|
|
|
|
if (dynamic_cast<NetECReal*>(rv)) return rv;
|
|
|
|
|
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
"The RHS expression must be constant." << endl;
|
|
|
|
|
cerr << get_fileline() << " : "
|
|
|
|
|
"This expression violates the rule: " << *rv << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
delete rv;
|
|
|
|
|
return 0;
|
2008-08-21 06:47:07 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
/*
|
|
|
|
|
* This function elaborates delay expressions. This is a little
|
|
|
|
|
* different from normal elaboration because the result may need to be
|
|
|
|
|
* scaled.
|
|
|
|
|
*/
|
|
|
|
|
static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope)
|
|
|
|
|
{
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*dex = elab_and_eval(des, scope, expr, -1);
|
2003-02-08 20:49:21 +01:00
|
|
|
|
2009-04-14 03:06:17 +02:00
|
|
|
/* Print a warning if we find default and `timescale based
|
|
|
|
|
* delays in the design, since this is likely an error. */
|
|
|
|
|
if (scope->time_from_timescale()) dly_used_timescale = true;
|
|
|
|
|
else dly_used_no_timescale = true;
|
|
|
|
|
|
|
|
|
|
if (display_ts_dly_warning &&
|
|
|
|
|
dly_used_no_timescale && dly_used_timescale) {
|
|
|
|
|
cerr << "warning: Found both default and "
|
|
|
|
|
"`timescale based delays. Use" << endl;
|
|
|
|
|
cerr << " -Wtimescale to find the "
|
|
|
|
|
"module(s) with no `timescale." << endl;
|
|
|
|
|
display_ts_dly_warning = false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
/* If the delay expression is a real constant or vector
|
|
|
|
|
constant, then evaluate it, scale it to the local time
|
|
|
|
|
units, and return an adjusted NetEConst. */
|
|
|
|
|
|
|
|
|
|
if (NetECReal*tmp = dynamic_cast<NetECReal*>(dex)) {
|
2010-06-19 01:03:17 +02:00
|
|
|
uint64_t delay = get_scaled_time_from_real(des, scope, tmp);
|
2002-04-22 00:31:02 +02:00
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
delete tmp;
|
2010-06-19 01:03:17 +02:00
|
|
|
NetEConst*tmp2 = new NetEConst(verinum(delay, 64));
|
|
|
|
|
tmp2->set_line(*expr);
|
|
|
|
|
return tmp2;
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
if (NetEConst*tmp = dynamic_cast<NetEConst*>(dex)) {
|
|
|
|
|
verinum fn = tmp->value();
|
2010-06-19 01:03:17 +02:00
|
|
|
uint64_t delay = des->scale_to_precision(fn.as_ulong64(), scope);
|
2003-02-08 20:49:21 +01:00
|
|
|
|
|
|
|
|
delete tmp;
|
2010-06-19 01:03:17 +02:00
|
|
|
NetEConst*tmp2 = new NetEConst(verinum(delay, 64));
|
|
|
|
|
tmp2->set_line(*expr);
|
|
|
|
|
return tmp2;
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
/* The expression is not constant, so generate an expanded
|
|
|
|
|
expression that includes the necessary scale shifts, and
|
|
|
|
|
return that expression. */
|
2010-06-19 01:03:17 +02:00
|
|
|
ivl_assert(*expr, dex);
|
|
|
|
|
if (dex->expr_type() == IVL_VT_REAL) {
|
|
|
|
|
// Scale the real value.
|
|
|
|
|
int shift = scope->time_unit() - scope->time_precision();
|
|
|
|
|
assert(shift >= 0);
|
|
|
|
|
double round = 1;
|
|
|
|
|
for (int lp = 0; lp < shift; lp += 1) round *= 10.0;
|
|
|
|
|
|
|
|
|
|
NetExpr*scal_val = new NetECReal(verireal(round));
|
|
|
|
|
scal_val->set_line(*expr);
|
2011-02-26 23:59:52 +01:00
|
|
|
dex = new NetEBMult('*', dex, scal_val, 1, true);
|
2010-06-19 01:03:17 +02:00
|
|
|
dex->set_line(*expr);
|
|
|
|
|
|
|
|
|
|
// Cast this part of the expression to an integer.
|
2011-08-07 00:27:39 +02:00
|
|
|
dex = new NetECast('v', dex, 64, false);
|
2010-06-19 01:03:17 +02:00
|
|
|
dex->set_line(*expr);
|
|
|
|
|
|
|
|
|
|
// Now scale the integer value.
|
|
|
|
|
shift = scope->time_precision() - des->get_precision();
|
|
|
|
|
assert(shift >= 0);
|
2006-08-08 07:11:37 +02:00
|
|
|
uint64_t scale = 1;
|
2010-06-19 01:03:17 +02:00
|
|
|
for (int lp = 0; lp < shift; lp += 1) scale *= 10;
|
2002-04-22 00:31:02 +02:00
|
|
|
|
2010-06-19 01:03:17 +02:00
|
|
|
scal_val = new NetEConst(verinum(scale, 64));
|
|
|
|
|
scal_val->set_line(*expr);
|
2011-02-26 23:59:52 +01:00
|
|
|
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
2010-06-19 01:03:17 +02:00
|
|
|
dex->set_line(*expr);
|
|
|
|
|
} else {
|
|
|
|
|
int shift = scope->time_unit() - des->get_precision();
|
|
|
|
|
assert(shift >= 0);
|
|
|
|
|
uint64_t scale = 1;
|
|
|
|
|
for (int lp = 0; lp < shift; lp += 1) scale *= 10;
|
2002-04-22 00:31:02 +02:00
|
|
|
|
2010-06-19 01:03:17 +02:00
|
|
|
NetExpr*scal_val = new NetEConst(verinum(scale, 64));
|
|
|
|
|
scal_val->set_line(*expr);
|
2011-02-26 23:59:52 +01:00
|
|
|
dex = new NetEBMult('*', dex, scal_val, 64, false);
|
2010-06-19 01:03:17 +02:00
|
|
|
dex->set_line(*expr);
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
return dex;
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
2011-11-27 20:16:39 +01:00
|
|
|
NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
ivl_assert(*this, ! delay_);
|
|
|
|
|
ivl_assert(*this, ! count_);
|
|
|
|
|
ivl_assert(*this, ! event_);
|
|
|
|
|
|
|
|
|
|
NetAssign_*lv = elaborate_lval(des, scope);
|
|
|
|
|
if (lv == 0) return 0;
|
|
|
|
|
|
|
|
|
|
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
|
|
|
|
if (rv == 0) return 0;
|
|
|
|
|
|
2011-11-28 01:46:02 +01:00
|
|
|
NetAssign*cur = new NetAssign(lv, op_, rv);
|
2011-11-27 20:16:39 +01:00
|
|
|
cur->set_line(*this);
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 02:48:47 +02:00
|
|
|
static bool lval_not_program_variable(const NetAssign_*lv)
|
|
|
|
|
{
|
|
|
|
|
while (lv) {
|
|
|
|
|
NetScope*sig_scope = lv->sig()->scope();
|
|
|
|
|
if (! sig_scope->program_block())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
lv = lv->more;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
1999-06-14 01:51:16 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2011-11-27 20:16:39 +01:00
|
|
|
/* If this is a compressed assignment, then handle the
|
|
|
|
|
elaboration in a specialized function. */
|
|
|
|
|
if (op_ != 0)
|
|
|
|
|
return elaborate_compressed_(des, scope);
|
|
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
/* elaborate the lval. This detects any part selects and mux
|
|
|
|
|
expressions that might exist. */
|
2000-09-03 19:58:35 +02:00
|
|
|
NetAssign_*lv = elaborate_lval(des, scope);
|
|
|
|
|
if (lv == 0) return 0;
|
1999-06-14 01:51:16 +02:00
|
|
|
|
2012-05-14 02:48:47 +02:00
|
|
|
if (scope->program_block() && lval_not_program_variable(lv)) {
|
|
|
|
|
cerr << get_fileline() << ": error: Blocking assignments to "
|
|
|
|
|
<< "non-program variables are not allowed." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
/* If there is an internal delay expression, elaborate it. */
|
|
|
|
|
NetExpr*delay = 0;
|
|
|
|
|
if (delay_ != 0)
|
|
|
|
|
delay = elaborate_delay_expr(delay_, des, scope);
|
1999-07-12 02:59:36 +02:00
|
|
|
|
2012-10-01 03:03:10 +02:00
|
|
|
NetExpr*rv;
|
2012-11-22 20:08:13 +01:00
|
|
|
const ivl_type_s*lv_net_type = lv->net_type();
|
|
|
|
|
|
2013-01-27 21:30:38 +01:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": PAssign::elaborate: ";
|
|
|
|
|
if (lv_net_type)
|
|
|
|
|
cerr << "lv_net_type=" << *lv_net_type << endl;
|
|
|
|
|
else
|
|
|
|
|
cerr << "lv_net_type=<nil>" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-22 20:08:13 +01:00
|
|
|
/* If the l-value is a compound type of some sort, then use
|
|
|
|
|
the newer net_type form of the elaborate_rval_ method to
|
|
|
|
|
handle the new types. */
|
|
|
|
|
if (dynamic_cast<const netclass_t*> (lv_net_type)) {
|
|
|
|
|
ivl_assert(*this, lv->more==0);
|
|
|
|
|
rv = elaborate_rval_(des, scope, lv_net_type);
|
|
|
|
|
|
2013-01-27 21:30:38 +01:00
|
|
|
} else if (const netdarray_t*dtype = dynamic_cast<const netdarray_t*> (lv_net_type)) {
|
2012-11-22 20:08:13 +01:00
|
|
|
ivl_assert(*this, lv->more==0);
|
2013-01-27 21:30:38 +01:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
if (lv->word())
|
|
|
|
|
cerr << get_fileline() << ": PAssign::elaborate: "
|
|
|
|
|
<< "lv->word() = " << *lv->word() << endl;
|
|
|
|
|
else
|
|
|
|
|
cerr << get_fileline() << ": PAssign::elaborate: "
|
|
|
|
|
<< "lv->word() = <nil>" << endl;
|
|
|
|
|
}
|
|
|
|
|
ivl_type_t use_lv_type = lv_net_type;
|
|
|
|
|
if (lv->word())
|
|
|
|
|
use_lv_type = dtype->element_type();
|
|
|
|
|
|
|
|
|
|
rv = elaborate_rval_(des, scope, use_lv_type);
|
2012-11-12 02:42:31 +01:00
|
|
|
|
2012-10-01 03:03:10 +02:00
|
|
|
} else {
|
|
|
|
|
/* Elaborate the r-value expression, then try to evaluate it. */
|
|
|
|
|
rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
|
|
|
|
}
|
1999-06-14 01:51:16 +02:00
|
|
|
|
2004-06-01 01:34:36 +02:00
|
|
|
if (rv == 0) return 0;
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(rv);
|
|
|
|
|
|
2008-09-04 01:05:12 +02:00
|
|
|
if (count_) assert(event_);
|
2000-04-28 18:50:53 +02:00
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
/* Rewrite delayed assignments as assignments that are
|
1999-07-13 06:08:26 +02:00
|
|
|
delayed. For example, a = #<d> b; becomes:
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
tmp = b;
|
|
|
|
|
#<d> a = tmp;
|
|
|
|
|
end
|
|
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
If the delay is an event delay, then the transform is
|
|
|
|
|
similar, with the event delay replacing the time delay. It
|
|
|
|
|
is an event delay if the event_ member has a value.
|
|
|
|
|
|
1999-07-13 06:08:26 +02:00
|
|
|
This rewriting of the expression allows me to not bother to
|
|
|
|
|
actually and literally represent the delayed assign in the
|
1999-08-18 06:00:02 +02:00
|
|
|
netlist. The compound statement is exactly equivalent. */
|
1999-07-13 06:08:26 +02:00
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
if (delay || event_) {
|
2008-05-10 00:25:42 +02:00
|
|
|
unsigned wid = count_lval_width(lv);
|
1999-07-17 20:06:02 +02:00
|
|
|
|
2012-09-15 19:27:43 +02:00
|
|
|
netvector_t*tmp2_vec = new netvector_t(rv->expr_type(),wid-1,0);
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
2012-09-15 19:27:43 +02:00
|
|
|
NetNet::REG, tmp2_vec);
|
2007-12-28 00:47:01 +01:00
|
|
|
tmp->local_flag(true);
|
1999-07-13 06:08:26 +02:00
|
|
|
tmp->set_line(*this);
|
|
|
|
|
|
2000-09-03 19:58:35 +02:00
|
|
|
NetESignal*sig = new NetESignal(tmp);
|
|
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/* Generate an assignment of the l-value to the temporary... */
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_*lvt = new NetAssign_(tmp);
|
2000-09-03 01:40:12 +02:00
|
|
|
|
2000-09-03 19:58:35 +02:00
|
|
|
NetAssign*a1 = new NetAssign(lvt, rv);
|
2000-09-03 01:40:12 +02:00
|
|
|
a1->set_line(*this);
|
1999-07-12 02:59:36 +02:00
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/* Generate an assignment of the temporary to the r-value... */
|
2000-09-03 01:40:12 +02:00
|
|
|
NetAssign*a2 = new NetAssign(lv, sig);
|
|
|
|
|
a2->set_line(*this);
|
1999-07-13 06:08:26 +02:00
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
/* Generate the delay statement with the final
|
|
|
|
|
assignment attached to it. If this is an event delay,
|
|
|
|
|
elaborate the PEventStatement. Otherwise, create the
|
2008-09-04 01:05:12 +02:00
|
|
|
right NetPDelay object. For a repeat event control
|
|
|
|
|
repeat the event and then do the final assignment. */
|
1999-09-22 04:00:48 +02:00
|
|
|
NetProc*st;
|
|
|
|
|
if (event_) {
|
2008-09-04 01:05:12 +02:00
|
|
|
if (count_) {
|
|
|
|
|
NetExpr*count = elab_and_eval(des, scope, count_, -1);
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
cerr << get_fileline() << ": Unable to "
|
|
|
|
|
"elaborate repeat expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
st = event_->elaborate(des, scope);
|
|
|
|
|
if (st == 0) {
|
|
|
|
|
cerr << event_->get_fileline() << ": error: "
|
|
|
|
|
"unable to elaborate event expression."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-04-19 03:17:16 +02:00
|
|
|
st->set_line(*this);
|
1999-09-22 04:00:48 +02:00
|
|
|
|
2008-09-04 01:05:12 +02:00
|
|
|
// If the expression is a constant, handle
|
|
|
|
|
// certain special iteration counts.
|
|
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(count)) {
|
|
|
|
|
long val = ce->value().as_long();
|
|
|
|
|
// We only need the real statement.
|
|
|
|
|
if (val <= 0) {
|
|
|
|
|
delete count;
|
|
|
|
|
delete st;
|
|
|
|
|
st = 0;
|
|
|
|
|
|
|
|
|
|
// We don't need the repeat statement.
|
|
|
|
|
} else if (val == 1) {
|
|
|
|
|
delete count;
|
|
|
|
|
|
|
|
|
|
// We need a repeat statement.
|
|
|
|
|
} else {
|
|
|
|
|
st = new NetRepeat(count, st);
|
2011-02-28 04:20:16 +01:00
|
|
|
st->set_line(*this);
|
2008-09-04 01:05:12 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
st = new NetRepeat(count, st);
|
2011-02-28 04:20:16 +01:00
|
|
|
st->set_line(*this);
|
2008-09-04 01:05:12 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
st = event_->elaborate_st(des, scope, a2);
|
|
|
|
|
if (st == 0) {
|
|
|
|
|
cerr << event_->get_fileline() << ": error: "
|
|
|
|
|
"unable to elaborate event expression."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-04-19 03:17:16 +02:00
|
|
|
st->set_line(*this);
|
2008-09-04 01:05:12 +02:00
|
|
|
}
|
1999-09-22 04:00:48 +02:00
|
|
|
} else {
|
2002-04-22 00:31:02 +02:00
|
|
|
NetPDelay*de = new NetPDelay(delay, a2);
|
2004-06-30 17:32:02 +02:00
|
|
|
de->set_line(*this);
|
1999-09-22 04:00:48 +02:00
|
|
|
st = de;
|
|
|
|
|
}
|
1999-07-13 06:08:26 +02:00
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
/* And build up the complex statement. */
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*bl = new NetBlock(NetBlock::SEQU, 0);
|
1999-07-13 06:08:26 +02:00
|
|
|
bl->append(a1);
|
2008-09-04 01:05:12 +02:00
|
|
|
if (st) bl->append(st);
|
|
|
|
|
if (count_) bl->append(a2);
|
2011-02-10 06:03:08 +01:00
|
|
|
bl->set_line(*this);
|
1999-07-12 02:59:36 +02:00
|
|
|
|
1999-07-13 06:08:26 +02:00
|
|
|
return bl;
|
1999-07-12 02:59:36 +02:00
|
|
|
}
|
|
|
|
|
|
2010-10-20 04:09:06 +02:00
|
|
|
if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) {
|
|
|
|
|
if (debug_elaborate)
|
2012-10-08 05:29:24 +02:00
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Cast expression to int2" << endl;
|
2010-10-20 04:09:06 +02:00
|
|
|
rv = cast_to_int2(rv);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-08 05:29:24 +02:00
|
|
|
if (lv->expr_type() == IVL_VT_REAL && rv->expr_type() != IVL_VT_REAL) {
|
|
|
|
|
if (debug_elaborate)
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Cast expression to real." << endl;
|
|
|
|
|
rv = cast_to_real(rv);
|
|
|
|
|
}
|
2010-11-03 04:16:42 +01:00
|
|
|
if (lv->enumeration() && (lv->enumeration() != rv->enumeration())) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "Enumeration type mismatch in assignment." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
2011-03-03 05:23:02 +01:00
|
|
|
|
2000-09-03 19:58:35 +02:00
|
|
|
NetAssign*cur = new NetAssign(lv, rv);
|
1999-03-15 03:43:32 +01:00
|
|
|
cur->set_line(*this);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 02:48:47 +02:00
|
|
|
/*
|
|
|
|
|
* Return true if any lvalue parts are in a program block scope.
|
|
|
|
|
*/
|
|
|
|
|
static bool lval_is_program_variable(const NetAssign_*lv)
|
|
|
|
|
{
|
|
|
|
|
while (lv) {
|
|
|
|
|
NetScope*sig_scope = lv->sig()->scope();
|
|
|
|
|
if (sig_scope->program_block())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
lv = lv->more;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-06 22:45:38 +02:00
|
|
|
/*
|
2004-06-20 17:59:06 +02:00
|
|
|
* Elaborate non-blocking assignments. The statement is of the general
|
|
|
|
|
* form:
|
|
|
|
|
*
|
|
|
|
|
* <lval> <= #<delay> <rval> ;
|
1999-06-06 22:45:38 +02:00
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
|
1999-06-06 22:45:38 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-08-25 03:48:24 +02:00
|
|
|
if (scope->in_func()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: functions cannot have non "
|
2007-08-25 03:48:24 +02:00
|
|
|
"blocking assignment statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
if (scope->in_final()) {
|
|
|
|
|
cerr << get_fileline() << ": error: final procedures cannot have "
|
|
|
|
|
"non blocking assignment statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && lval()->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be assigned values using non-blocking "
|
|
|
|
|
"assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-20 08:08:53 +02:00
|
|
|
/* Elaborate the l-value. */
|
2000-09-03 19:58:35 +02:00
|
|
|
NetAssign_*lv = elaborate_lval(des, scope);
|
|
|
|
|
if (lv == 0) return 0;
|
1999-06-06 22:45:38 +02:00
|
|
|
|
2012-05-14 02:48:47 +02:00
|
|
|
if (scope->program_block() && lval_is_program_variable(lv)) {
|
|
|
|
|
cerr << get_fileline() << ": error: Non-blocking assignments to "
|
|
|
|
|
<< "program variables are not allowed." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
// This is an error, but we can let elaboration continue
|
|
|
|
|
// because it would necessarily trigger other errors.
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-23 06:09:06 +02:00
|
|
|
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
|
2008-11-15 00:43:49 +01:00
|
|
|
if (rv == 0) return 0;
|
1999-09-25 04:57:29 +02:00
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
NetExpr*delay = 0;
|
2008-09-11 04:37:11 +02:00
|
|
|
if (delay_ != 0) {
|
|
|
|
|
assert(count_ == 0 && event_ == 0);
|
2002-04-22 00:31:02 +02:00
|
|
|
delay = elaborate_delay_expr(delay_, des, scope);
|
2008-09-11 04:37:11 +02:00
|
|
|
}
|
1999-06-06 22:45:38 +02:00
|
|
|
|
2008-09-11 04:37:11 +02:00
|
|
|
NetExpr*count = 0;
|
|
|
|
|
NetEvWait*event = 0;
|
2008-09-04 01:05:12 +02:00
|
|
|
if (count_ != 0 || event_ != 0) {
|
|
|
|
|
if (count_ != 0) {
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && count_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically "
|
|
|
|
|
"allocated variables may not be referenced "
|
|
|
|
|
"in intra-assignment event controls of "
|
|
|
|
|
"non-blocking assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-04 01:05:12 +02:00
|
|
|
assert(event_ != 0);
|
|
|
|
|
count = elab_and_eval(des, scope, count_, -1);
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
cerr << get_fileline() << ": Unable to elaborate "
|
|
|
|
|
"repeat expression." << endl;
|
|
|
|
|
des->errors += 1;
|
2008-09-11 04:37:11 +02:00
|
|
|
return 0;
|
2008-09-04 01:05:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && event_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically "
|
|
|
|
|
"allocated variables may not be referenced "
|
|
|
|
|
"in intra-assignment event controls of "
|
|
|
|
|
"non-blocking assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-11 04:37:11 +02:00
|
|
|
NetProc*st = event_->elaborate(des, scope);
|
|
|
|
|
if (st == 0) {
|
2008-09-04 01:05:12 +02:00
|
|
|
cerr << get_fileline() << ": unable to elaborate "
|
|
|
|
|
"event expression." << endl;
|
|
|
|
|
des->errors += 1;
|
2008-09-11 04:37:11 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
event = dynamic_cast<NetEvWait*>(st) ;
|
|
|
|
|
assert(event);
|
|
|
|
|
|
|
|
|
|
// Some constant values are special.
|
|
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(count)) {
|
|
|
|
|
long val = ce->value().as_long();
|
|
|
|
|
// We only need the assignment statement.
|
|
|
|
|
if (val <= 0) {
|
|
|
|
|
delete count;
|
|
|
|
|
delete event;
|
|
|
|
|
count = 0;
|
|
|
|
|
event = 0;
|
|
|
|
|
// We only need the event.
|
|
|
|
|
} else if (val == 1) {
|
|
|
|
|
delete count;
|
|
|
|
|
count = 0;
|
|
|
|
|
}
|
2008-09-04 01:05:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-13 03:01:51 +02:00
|
|
|
/* All done with this node. Mark its line number and check it in. */
|
2008-09-11 04:37:11 +02:00
|
|
|
NetAssignNB*cur = new NetAssignNB(lv, rv, event, count);
|
2002-04-22 00:31:02 +02:00
|
|
|
cur->set_delay(delay);
|
1999-06-06 22:45:38 +02:00
|
|
|
cur->set_line(*this);
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
/*
|
|
|
|
|
* This is the elaboration method for a begin-end block. Try to
|
|
|
|
|
* elaborate the entire block, even if it fails somewhere. This way I
|
|
|
|
|
* get all the error messages out of it. Then, if I detected a failure
|
|
|
|
|
* then pass the failure up.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2012-05-20 02:34:13 +02:00
|
|
|
NetBlock::Type type;
|
|
|
|
|
switch (bl_type_) {
|
|
|
|
|
case PBlock::BL_SEQ:
|
|
|
|
|
type = NetBlock::SEQU;
|
|
|
|
|
break;
|
|
|
|
|
case PBlock::BL_PAR:
|
|
|
|
|
type = NetBlock::PARA;
|
|
|
|
|
break;
|
|
|
|
|
case PBlock::BL_JOIN_NONE:
|
|
|
|
|
type = NetBlock::PARA_JOIN_NONE;
|
|
|
|
|
break;
|
|
|
|
|
case PBlock::BL_JOIN_ANY:
|
|
|
|
|
type = NetBlock::PARA_JOIN_ANY;
|
|
|
|
|
break;
|
2012-09-24 19:26:58 +02:00
|
|
|
// Added to remove a "type" uninitialized compiler warning.
|
|
|
|
|
// This should never be reached since all the PBlock enumeration
|
|
|
|
|
// cases are handled above.
|
|
|
|
|
default:
|
|
|
|
|
type = NetBlock::SEQU;
|
|
|
|
|
assert(0);
|
2012-05-20 02:34:13 +02:00
|
|
|
}
|
1999-01-25 06:45:56 +01:00
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetScope*nscope = 0;
|
2008-02-16 06:20:24 +01:00
|
|
|
if (pscope_name() != 0) {
|
|
|
|
|
nscope = scope->child(hname_t(pscope_name()));
|
2000-03-11 04:25:51 +01:00
|
|
|
if (nscope == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2007-06-02 05:42:12 +02:00
|
|
|
"unable to find block scope " << scope_path(scope)
|
2008-06-18 06:45:37 +02:00
|
|
|
<< "." << pscope_name() << endl;
|
2000-03-11 04:25:51 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(nscope);
|
1999-12-15 00:42:16 +01:00
|
|
|
|
2008-03-04 05:49:52 +01:00
|
|
|
elaborate_behaviors_(des, nscope);
|
1999-12-15 00:42:16 +01:00
|
|
|
}
|
1999-06-24 06:24:18 +02:00
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*cur = new NetBlock(type, nscope);
|
|
|
|
|
|
|
|
|
|
if (nscope == 0)
|
|
|
|
|
nscope = scope;
|
|
|
|
|
|
1999-06-07 01:07:43 +02:00
|
|
|
// Handle the special case that the block contains only one
|
2002-08-13 07:35:00 +02:00
|
|
|
// statement. There is no need to keep the block node. Also,
|
|
|
|
|
// don't elide named blocks, because they might be referenced
|
|
|
|
|
// elsewhere.
|
2011-09-17 21:10:05 +02:00
|
|
|
if ((list_.size() == 1) && (pscope_name() == 0)) {
|
2001-10-22 04:05:20 +02:00
|
|
|
assert(list_[0]);
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*tmp = list_[0]->elaborate(des, nscope);
|
1999-06-07 01:07:43 +02:00
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-17 21:10:05 +02:00
|
|
|
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
|
2001-10-22 04:05:20 +02:00
|
|
|
assert(list_[idx]);
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*tmp = list_[idx]->elaborate(des, nscope);
|
2007-02-01 06:52:24 +01:00
|
|
|
// If the statement fails to elaborate, then simply
|
|
|
|
|
// ignore it. Presumably, the elaborate for the
|
|
|
|
|
// statement already generated an error message and
|
|
|
|
|
// marked the error count in the design so no need to
|
|
|
|
|
// do any of that here.
|
1999-01-25 06:45:56 +01:00
|
|
|
if (tmp == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2000-09-30 00:58:57 +02:00
|
|
|
|
|
|
|
|
// If the result turns out to be a noop, then skip it.
|
|
|
|
|
if (NetBlock*tbl = dynamic_cast<NetBlock*>(tmp))
|
|
|
|
|
if (tbl->proc_first() == 0) {
|
|
|
|
|
delete tbl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
cur->append(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-10 06:03:08 +01:00
|
|
|
cur->set_line(*this);
|
1998-11-04 00:28:49 +01:00
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-15 07:38:39 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate a case statement.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PCase::elaborate(Design*des, NetScope*scope) const
|
1999-02-03 05:20:11 +01:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
1999-06-10 06:03:52 +02:00
|
|
|
if (expr == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unable to elaborate this case"
|
1999-06-10 06:03:52 +02:00
|
|
|
" expression." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
/* Count the items in the case statement. Note that there may
|
2002-04-24 19:40:48 +02:00
|
|
|
be some cases that have multiple guards. Count each as a
|
|
|
|
|
separate item. */
|
1999-06-15 07:38:39 +02:00
|
|
|
unsigned icount = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
|
|
|
|
PCase::Item*cur = (*items_)[idx];
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
if (cur->expr.empty())
|
1999-06-15 07:38:39 +02:00
|
|
|
icount += 1;
|
|
|
|
|
else
|
2010-10-26 04:36:44 +02:00
|
|
|
icount += cur->expr.size();
|
1999-06-15 07:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
1999-09-29 20:36:02 +02:00
|
|
|
NetCase*res = new NetCase(type_, expr, icount);
|
|
|
|
|
res->set_line(*this);
|
1999-02-03 05:20:11 +01:00
|
|
|
|
2002-01-19 21:09:56 +01:00
|
|
|
/* Iterate over all the case items (guard/statement pairs)
|
|
|
|
|
elaborating them. If the guard has no expression, then this
|
|
|
|
|
is a "default" cause. Otherwise, the guard has one or more
|
|
|
|
|
expressions, and each guard is a case. */
|
1999-06-15 07:38:39 +02:00
|
|
|
unsigned inum = 0;
|
1999-06-06 22:45:38 +02:00
|
|
|
for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) {
|
1999-02-03 05:20:11 +01:00
|
|
|
|
1999-06-15 07:38:39 +02:00
|
|
|
assert(inum < icount);
|
|
|
|
|
PCase::Item*cur = (*items_)[idx];
|
1999-02-03 05:20:11 +01:00
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
if (cur->expr.empty()) {
|
1999-06-15 07:38:39 +02:00
|
|
|
/* If there are no expressions, then this is the
|
|
|
|
|
default case. */
|
|
|
|
|
NetProc*st = 0;
|
|
|
|
|
if (cur->stat)
|
2001-11-22 07:20:59 +01:00
|
|
|
st = cur->stat->elaborate(des, scope);
|
1999-06-15 07:38:39 +02:00
|
|
|
|
|
|
|
|
res->set_case(inum, 0, st);
|
|
|
|
|
inum += 1;
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
} else for (list<PExpr*>::iterator idx_expr = cur->expr.begin()
|
|
|
|
|
; idx_expr != cur->expr.end() ; ++idx_expr) {
|
1999-06-15 07:38:39 +02:00
|
|
|
|
|
|
|
|
/* If there are one or more expressions, then
|
|
|
|
|
iterate over the guard expressions, elaborating
|
|
|
|
|
a separate case for each. (Yes, the statement
|
|
|
|
|
will be elaborated again for each.) */
|
2010-10-26 04:36:44 +02:00
|
|
|
PExpr*cur_expr = *idx_expr;
|
2012-11-13 03:13:41 +01:00
|
|
|
NetExpr*gu;
|
1999-06-15 07:38:39 +02:00
|
|
|
NetProc*st = 0;
|
2010-10-26 04:36:44 +02:00
|
|
|
assert(cur_expr);
|
|
|
|
|
gu = elab_and_eval(des, scope, cur_expr, -1);
|
2002-01-19 21:09:56 +01:00
|
|
|
|
1999-06-15 07:38:39 +02:00
|
|
|
if (cur->stat)
|
2001-11-22 07:20:59 +01:00
|
|
|
st = cur->stat->elaborate(des, scope);
|
1999-06-15 07:38:39 +02:00
|
|
|
|
|
|
|
|
res->set_case(inum, gu, st);
|
|
|
|
|
inum += 1;
|
|
|
|
|
}
|
1999-02-03 05:20:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PCondit::elaborate(Design*des, NetScope*scope) const
|
1998-11-07 18:05:05 +01:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-06-28 07:05:36 +02:00
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate condition statement"
|
2007-06-28 07:05:36 +02:00
|
|
|
<< " with conditional: " << *expr_ << endl;
|
|
|
|
|
|
1999-06-03 07:16:25 +02:00
|
|
|
// Elaborate and try to evaluate the conditional expression.
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
1999-06-10 06:03:52 +02:00
|
|
|
if (expr == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unable to elaborate"
|
1999-06-10 06:03:52 +02:00
|
|
|
" condition expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1999-06-03 07:16:25 +02:00
|
|
|
|
|
|
|
|
// If the condition of the conditional statement is constant,
|
|
|
|
|
// then look at the value and elaborate either the if statement
|
|
|
|
|
// or the else statement. I don't need both. If there is no
|
2008-10-21 18:00:48 +02:00
|
|
|
// else_ statement, then use an empty block as a noop.
|
1999-06-03 07:16:25 +02:00
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(expr)) {
|
|
|
|
|
verinum val = ce->value();
|
2005-06-17 07:06:47 +02:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Condition expression "
|
2005-06-17 07:06:47 +02:00
|
|
|
<< "is a constant " << val << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-26 08:10:30 +01:00
|
|
|
verinum::V reduced = verinum::V0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < val.len() ; idx += 1)
|
|
|
|
|
reduced = reduced | val[idx];
|
|
|
|
|
|
1999-06-03 07:16:25 +02:00
|
|
|
delete expr;
|
2006-11-26 08:10:30 +01:00
|
|
|
if (reduced == verinum::V1)
|
2006-11-27 03:01:07 +01:00
|
|
|
if (if_) {
|
|
|
|
|
return if_->elaborate(des, scope);
|
|
|
|
|
} else {
|
|
|
|
|
NetBlock*tmp = new NetBlock(NetBlock::SEQU, 0);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
1999-06-03 07:16:25 +02:00
|
|
|
else if (else_)
|
2001-11-22 07:20:59 +01:00
|
|
|
return else_->elaborate(des, scope);
|
1999-06-03 07:16:25 +02:00
|
|
|
else
|
2002-05-27 02:08:45 +02:00
|
|
|
return new NetBlock(NetBlock::SEQU, 0);
|
1999-06-03 07:16:25 +02:00
|
|
|
}
|
1999-06-24 06:24:18 +02:00
|
|
|
|
2007-03-22 17:08:14 +01:00
|
|
|
// If the condition expression is more than 1 bits, then
|
1999-09-16 02:33:45 +02:00
|
|
|
// generate a comparison operator to get the result down to
|
|
|
|
|
// one bit. Turn <e> into <e> != 0;
|
|
|
|
|
|
1999-10-05 08:19:46 +02:00
|
|
|
if (expr->expr_width() < 1) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
1999-10-05 08:19:46 +02:00
|
|
|
"incomprehensible expression width (0)." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-23 06:03:18 +02:00
|
|
|
// Make sure the condition expression evaluates to a condition.
|
|
|
|
|
expr = condition_reduce(expr);
|
1999-06-24 06:24:18 +02:00
|
|
|
|
1999-06-03 07:16:25 +02:00
|
|
|
// Well, I actually need to generate code to handle the
|
|
|
|
|
// conditional, so elaborate.
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*i = if_? if_->elaborate(des, scope) : 0;
|
|
|
|
|
NetProc*e = else_? else_->elaborate(des, scope) : 0;
|
1998-11-07 18:05:05 +01:00
|
|
|
|
2003-07-02 06:19:16 +02:00
|
|
|
// Detect the special cases that the if or else statements are
|
|
|
|
|
// empty blocks. If this is the case, remove the blocks as
|
|
|
|
|
// null statements.
|
|
|
|
|
if (NetBlock*tmp = dynamic_cast<NetBlock*>(i)) {
|
|
|
|
|
if (tmp->proc_first() == 0) {
|
|
|
|
|
delete i;
|
|
|
|
|
i = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetBlock*tmp = dynamic_cast<NetBlock*>(e)) {
|
|
|
|
|
if (tmp->proc_first() == 0) {
|
|
|
|
|
delete e;
|
|
|
|
|
e = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
NetCondit*res = new NetCondit(expr, i, e);
|
2000-02-14 01:11:11 +01:00
|
|
|
res->set_line(*this);
|
1998-11-07 18:05:05 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PCallTask::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2007-05-24 06:07:11 +02:00
|
|
|
if (peek_tail_name(path_)[0] == '$')
|
2001-11-22 07:20:59 +01:00
|
|
|
return elaborate_sys(des, scope);
|
1999-07-03 04:12:51 +02:00
|
|
|
else
|
2001-11-22 07:20:59 +01:00
|
|
|
return elaborate_usr(des, scope);
|
1999-07-03 04:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A call to a system task involves elaborating all the parameters,
|
|
|
|
|
* then passing the list to the NetSTask object.
|
1999-11-10 03:52:24 +01:00
|
|
|
*XXXX
|
2002-08-15 04:11:54 +02:00
|
|
|
* There is a single special case in the call to a system
|
|
|
|
|
* task. Normally, an expression cannot take an unindexed
|
|
|
|
|
* memory. However, it is possible to take a system task parameter a
|
|
|
|
|
* memory if the expression is trivial.
|
1999-07-03 04:12:51 +02:00
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
1999-07-03 04:12:51 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2009-01-29 06:01:49 +01:00
|
|
|
if (path_.size() > 1) {
|
|
|
|
|
cerr << get_fileline() << ": error: Hierarchical system task names"
|
|
|
|
|
<< " make no sense: " << path_ << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-10 18:50:41 +01:00
|
|
|
unsigned parm_count = parms_.size();
|
1999-07-03 04:12:51 +02:00
|
|
|
|
2002-08-15 04:11:54 +02:00
|
|
|
/* Catch the special case that the system task has no
|
|
|
|
|
parameters. The "()" string will be parsed as a single
|
|
|
|
|
empty parameter, when we really mean no parameters at all. */
|
2012-03-10 18:50:41 +01:00
|
|
|
if ((parm_count== 1) && (parms_[0] == 0))
|
2002-08-15 04:11:54 +02:00
|
|
|
parm_count = 0;
|
|
|
|
|
|
2012-07-17 03:15:29 +02:00
|
|
|
vector<NetExpr*>eparms (parm_count);
|
1999-11-10 03:52:24 +01:00
|
|
|
|
2011-02-26 23:59:52 +01:00
|
|
|
perm_string name = peek_tail_name(path_);
|
|
|
|
|
|
2002-08-15 04:11:54 +02:00
|
|
|
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
2012-03-10 18:50:41 +01:00
|
|
|
PExpr*ex = parms_[idx];
|
2008-10-11 05:42:07 +02:00
|
|
|
if (ex != 0) {
|
2011-02-26 23:59:52 +01:00
|
|
|
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
2008-10-11 05:42:07 +02:00
|
|
|
} else {
|
|
|
|
|
eparms[idx] = 0;
|
|
|
|
|
}
|
1999-07-03 04:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
2009-01-29 06:01:49 +01:00
|
|
|
// Special case: Specify blocks are turned off, and this is an
|
|
|
|
|
// $sdf_annotate system task. There will be nothing for $sdf
|
|
|
|
|
// to annotate, and the user is intending to turn the behavior
|
|
|
|
|
// off anyhow, so replace the system task invocation with a no-op.
|
2011-02-26 23:59:52 +01:00
|
|
|
if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
|
2009-01-29 06:01:49 +01:00
|
|
|
|
2009-01-30 03:31:45 +01:00
|
|
|
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
|
|
|
|
|
<< "since specify blocks are being omitted." << endl;
|
2009-01-29 06:01:49 +01:00
|
|
|
NetBlock*noop = new NetBlock(NetBlock::SEQU, scope);
|
|
|
|
|
noop->set_line(*this);
|
|
|
|
|
return noop;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-26 23:59:52 +01:00
|
|
|
NetSTask*cur = new NetSTask(name, def_sfunc_as_task, eparms);
|
2007-12-22 15:31:24 +01:00
|
|
|
cur->set_line(*this);
|
1999-07-03 04:12:51 +02:00
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
/*
|
|
|
|
|
* A call to a user defined task is different from a call to a system
|
|
|
|
|
* task because a user task in a netlist has no parameters: the
|
|
|
|
|
* assignments are done by the calling thread. For example:
|
|
|
|
|
*
|
|
|
|
|
* task foo;
|
|
|
|
|
* input a;
|
|
|
|
|
* output b;
|
|
|
|
|
* [...]
|
|
|
|
|
* endtask;
|
|
|
|
|
*
|
|
|
|
|
* [...] foo(x, y);
|
|
|
|
|
*
|
|
|
|
|
* is really:
|
|
|
|
|
*
|
|
|
|
|
* task foo;
|
|
|
|
|
* reg a;
|
|
|
|
|
* reg b;
|
|
|
|
|
* [...]
|
|
|
|
|
* endtask;
|
|
|
|
|
*
|
|
|
|
|
* [...]
|
|
|
|
|
* begin
|
|
|
|
|
* a = x;
|
|
|
|
|
* foo;
|
|
|
|
|
* y = b;
|
|
|
|
|
* end
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
1999-07-03 04:12:51 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-08-25 03:48:24 +02:00
|
|
|
if (scope->in_func()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: functions cannot enable/call "
|
2007-08-25 03:48:24 +02:00
|
|
|
"tasks." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
if (scope->in_final()) {
|
|
|
|
|
cerr << get_fileline() << ": error: final procedures cannot "
|
|
|
|
|
"enable/call tasks." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetScope*task = des->find_task(scope, path_);
|
2001-07-29 00:13:11 +02:00
|
|
|
if (task == 0) {
|
2013-02-06 21:36:54 +01:00
|
|
|
// For SystemVerilog this may be a few other things.
|
2012-07-17 03:15:29 +02:00
|
|
|
if (gn_system_verilog()) {
|
2013-02-06 21:36:54 +01:00
|
|
|
NetProc *tmp;
|
|
|
|
|
// This could be a method attached to a signal?
|
|
|
|
|
tmp = elaborate_method_(des, scope);
|
|
|
|
|
if (tmp) return tmp;
|
|
|
|
|
// Or it could be a function call ignoring the return?
|
|
|
|
|
tmp = elaborate_function_(des, scope);
|
2012-07-17 03:15:29 +02:00
|
|
|
if (tmp) return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Enable of unknown task "
|
2001-12-03 05:47:14 +01:00
|
|
|
<< "``" << path_ << "''." << endl;
|
1999-07-03 04:12:51 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2001-07-29 00:13:11 +02:00
|
|
|
assert(task);
|
2001-10-22 04:05:20 +02:00
|
|
|
assert(task->type() == NetScope::TASK);
|
2001-07-29 00:13:11 +02:00
|
|
|
NetTaskDef*def = task->task_def();
|
2001-10-22 04:05:20 +02:00
|
|
|
if (def == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: task " << path_
|
2007-06-02 05:42:12 +02:00
|
|
|
<< " doesn't have a definition in " << scope_path(scope)
|
2001-10-22 04:05:20 +02:00
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(def);
|
2001-07-29 00:13:11 +02:00
|
|
|
|
2012-03-10 18:50:41 +01:00
|
|
|
|
|
|
|
|
unsigned parm_count = parms_.size();
|
|
|
|
|
|
|
|
|
|
// Handle special case that the definition has no arguments
|
|
|
|
|
// but the parser found a simgle nul argument. This is an
|
|
|
|
|
// argument of the parser allowing for the possibility of
|
|
|
|
|
// default values for argumets: The parser cannot tell the
|
|
|
|
|
// difference between "func()" and "func(<default>)".
|
|
|
|
|
if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0)
|
|
|
|
|
parm_count = 0;
|
|
|
|
|
|
|
|
|
|
if (parm_count != def->port_count()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Port count mismatch in call to ``"
|
2012-03-10 18:50:41 +01:00
|
|
|
<< path_ << "''. Got " << parm_count
|
2007-04-02 01:01:10 +02:00
|
|
|
<< " ports, expecting " << def->port_count() << " ports." << endl;
|
1999-07-24 04:11:19 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetUTask*cur;
|
|
|
|
|
|
2008-10-16 20:34:22 +02:00
|
|
|
/* Handle non-automatic tasks with no parameters specially. There is
|
|
|
|
|
no need to make a sequential block to hold the generated code. */
|
2012-03-10 18:50:41 +01:00
|
|
|
if ((parm_count == 0) && !task->is_auto()) {
|
2001-04-02 04:28:12 +02:00
|
|
|
cur = new NetUTask(task);
|
2007-04-15 22:45:40 +02:00
|
|
|
cur->set_line(*this);
|
1999-07-24 04:11:19 +02:00
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*block = new NetBlock(NetBlock::SEQU, 0);
|
2011-02-10 06:03:08 +01:00
|
|
|
block->set_line(*this);
|
2000-04-28 18:50:53 +02:00
|
|
|
|
2000-04-29 01:12:12 +02:00
|
|
|
/* Detect the case where the definition of the task is known
|
2000-04-29 00:17:47 +02:00
|
|
|
empty. In this case, we need not bother with calls to the
|
|
|
|
|
task, all the assignments, etc. Just return a no-op. */
|
|
|
|
|
|
|
|
|
|
if (const NetBlock*tp = dynamic_cast<const NetBlock*>(def->proc())) {
|
|
|
|
|
if (tp->proc_first() == 0)
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-27 01:54:13 +02:00
|
|
|
/* If this is an automatic task, generate a statement to
|
|
|
|
|
allocate the local storage. */
|
|
|
|
|
if (task->is_auto()) {
|
|
|
|
|
NetAlloc*ap = new NetAlloc(task);
|
2011-02-10 06:03:08 +01:00
|
|
|
ap->set_line(*this);
|
2008-09-27 01:54:13 +02:00
|
|
|
block->append(ap);
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
/* Generate assignment statement statements for the input and
|
1999-07-24 21:19:06 +02:00
|
|
|
INOUT ports of the task. These are managed by writing
|
|
|
|
|
assignments with the task port the l-value and the passed
|
2000-04-28 18:50:53 +02:00
|
|
|
expression the r-value. We know by definition that the port
|
|
|
|
|
is a reg type, so this elaboration is pretty obvious. */
|
|
|
|
|
|
2012-03-10 18:50:41 +01:00
|
|
|
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
if (parms_[idx] == 0 && !gn_system_verilog()) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "Missing argument " << (idx+1)
|
|
|
|
|
<< " of call to task." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parms_[idx] == 0) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: "
|
|
|
|
|
<< "Implicit arguments (arg " << (idx+1)
|
|
|
|
|
<< ") not supported." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1999-07-24 04:11:19 +02:00
|
|
|
|
|
|
|
|
NetNet*port = def->port(idx);
|
|
|
|
|
assert(port->port_type() != NetNet::NOT_A_PORT);
|
|
|
|
|
if (port->port_type() == NetNet::POUTPUT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_*lv = new NetAssign_(port);
|
2005-03-05 06:38:33 +01:00
|
|
|
unsigned wid = count_lval_width(lv);
|
2008-12-10 06:52:15 +01:00
|
|
|
ivl_variable_type_t lv_type = lv->expr_type();
|
2005-03-05 06:38:33 +01:00
|
|
|
|
2012-03-10 18:50:41 +01:00
|
|
|
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]);
|
2009-09-12 04:59:11 +02:00
|
|
|
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
|
|
|
|
|
cerr << evt->get_fileline() << ": error: An event '"
|
|
|
|
|
<< evt->event()->name() << "' can not be a user "
|
|
|
|
|
"task argument." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2008-11-27 00:37:38 +01:00
|
|
|
|
2000-09-03 01:40:12 +02:00
|
|
|
NetAssign*pr = new NetAssign(lv, rv);
|
2011-02-10 06:03:08 +01:00
|
|
|
pr->set_line(*this);
|
1999-07-24 04:11:19 +02:00
|
|
|
block->append(pr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate the task call proper... */
|
2001-04-02 04:28:12 +02:00
|
|
|
cur = new NetUTask(task);
|
2007-04-15 22:45:40 +02:00
|
|
|
cur->set_line(*this);
|
1999-07-24 04:11:19 +02:00
|
|
|
block->append(cur);
|
|
|
|
|
|
2000-04-28 18:50:53 +02:00
|
|
|
|
|
|
|
|
/* Generate assignment statements for the output and INOUT
|
|
|
|
|
ports of the task. The l-value in this case is the
|
1999-09-19 00:23:50 +02:00
|
|
|
expression passed as a parameter, and the r-value is the
|
2000-04-28 18:50:53 +02:00
|
|
|
port to be copied out.
|
|
|
|
|
|
|
|
|
|
We know by definition that the r-value of this copy-out is
|
|
|
|
|
the port, which is a reg. The l-value, however, may be any
|
|
|
|
|
expression that can be a target to a procedural
|
|
|
|
|
assignment, including a memory word. */
|
|
|
|
|
|
2012-03-10 18:50:41 +01:00
|
|
|
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
1999-07-24 04:11:19 +02:00
|
|
|
|
|
|
|
|
NetNet*port = def->port(idx);
|
2000-04-28 18:50:53 +02:00
|
|
|
|
|
|
|
|
/* Skip input ports. */
|
1999-07-24 04:11:19 +02:00
|
|
|
assert(port->port_type() != NetNet::NOT_A_PORT);
|
|
|
|
|
if (port->port_type() == NetNet::PINPUT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2000-04-28 18:50:53 +02:00
|
|
|
|
2002-03-09 05:02:26 +01:00
|
|
|
/* Elaborate an l-value version of the port expression
|
|
|
|
|
for output and inout ports. If the expression does
|
|
|
|
|
not exist then quietly skip it, but if the expression
|
|
|
|
|
is not a valid l-value print an error message. Note
|
|
|
|
|
that the elaborate_lval method already printed a
|
|
|
|
|
detailed message. */
|
|
|
|
|
NetAssign_*lv;
|
|
|
|
|
if (parms_[idx]) {
|
2004-12-30 00:55:43 +01:00
|
|
|
lv = parms_[idx]->elaborate_lval(des, scope, false);
|
2002-03-09 05:02:26 +01:00
|
|
|
if (lv == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << parms_[idx]->get_fileline() << ": error: "
|
2002-03-09 05:02:26 +01:00
|
|
|
<< "I give up on task port " << (idx+1)
|
|
|
|
|
<< " expression: " << *parms_[idx] << endl;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lv = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-10 04:13:23 +01:00
|
|
|
if (lv == 0)
|
|
|
|
|
continue;
|
1999-07-24 21:19:06 +02:00
|
|
|
|
2013-02-25 23:13:05 +01:00
|
|
|
NetExpr*rv = new NetESignal(port);
|
|
|
|
|
|
|
|
|
|
/* Handle any implicit cast. */
|
|
|
|
|
unsigned lv_width = count_lval_width(lv);
|
|
|
|
|
if (lv->expr_type() != rv->expr_type()) {
|
|
|
|
|
switch (lv->expr_type()) {
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
rv = cast_to_real(rv);
|
|
|
|
|
break;
|
|
|
|
|
case IVL_VT_BOOL:
|
|
|
|
|
rv = cast_to_int2(rv, lv_width);
|
|
|
|
|
break;
|
|
|
|
|
case IVL_VT_LOGIC:
|
|
|
|
|
rv = cast_to_int4(rv, lv_width);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* Don't yet know how to handle this. */
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rv = pad_to_width(rv, lv_width, *this);
|
1999-07-24 21:19:06 +02:00
|
|
|
|
|
|
|
|
/* Generate the assignment statement. */
|
2005-05-17 22:56:55 +02:00
|
|
|
NetAssign*ass = new NetAssign(lv, rv);
|
2011-02-10 06:03:08 +01:00
|
|
|
ass->set_line(*this);
|
1999-07-24 21:19:06 +02:00
|
|
|
|
|
|
|
|
block->append(ass);
|
1999-07-24 04:11:19 +02:00
|
|
|
}
|
|
|
|
|
|
2008-09-27 01:54:13 +02:00
|
|
|
/* If this is an automatic task, generate a statement to free
|
|
|
|
|
the local storage. */
|
|
|
|
|
if (task->is_auto()) {
|
|
|
|
|
NetFree*fp = new NetFree(task);
|
2011-02-10 06:03:08 +01:00
|
|
|
fp->set_line(*this);
|
2008-09-27 01:54:13 +02:00
|
|
|
block->append(fp);
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
return block;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2012-07-17 03:15:29 +02:00
|
|
|
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
pform_name_t use_path = path_;
|
|
|
|
|
perm_string method_name = peek_tail_name(use_path);
|
|
|
|
|
use_path.pop_back();
|
|
|
|
|
|
|
|
|
|
NetNet *net;
|
|
|
|
|
const NetExpr *par;
|
|
|
|
|
NetEvent *eve;
|
|
|
|
|
const NetExpr *ex1, *ex2;
|
|
|
|
|
|
2013-02-06 21:36:54 +01:00
|
|
|
// There is no signal to search for so this cannot be a method.
|
|
|
|
|
if (use_path.empty()) return 0;
|
|
|
|
|
|
2012-07-17 03:15:29 +02:00
|
|
|
symbol_search(this, des, scope, use_path,
|
|
|
|
|
net, par, eve, ex1, ex2);
|
|
|
|
|
|
|
|
|
|
if (net == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// Is this a delete method for dynamic arrays?
|
|
|
|
|
if (net->darray_type() && method_name=="delete") {
|
|
|
|
|
NetESignal*sig = new NetESignal(net);
|
|
|
|
|
|
|
|
|
|
vector<NetExpr*> argv (1);
|
|
|
|
|
argv[0] = sig;
|
|
|
|
|
|
|
|
|
|
NetSTask*sys = new NetSTask("$ivl_darray_method$delete",
|
|
|
|
|
IVL_SFUNC_AS_TASK_IGNORE, argv);
|
|
|
|
|
sys->set_line(*this);
|
|
|
|
|
return sys;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-06 21:36:54 +01:00
|
|
|
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
NetFuncDef*func = des->find_function(scope, path_);
|
|
|
|
|
// This is not a function, so this task call cannot be a function
|
|
|
|
|
// call with a missing return assignment.
|
|
|
|
|
if (! func) return 0;
|
|
|
|
|
|
|
|
|
|
// HERE: Should this be an assign to a dummy variable or something else?
|
|
|
|
|
cerr << get_fileline() << ": sorry: Icarus cannot currently call "
|
|
|
|
|
"functions like a tasks." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
/*
|
2004-12-12 19:13:39 +01:00
|
|
|
* Elaborate a procedural continuous assign. This really looks very
|
|
|
|
|
* much like other procedural assignments, at this point, but there
|
2004-12-11 03:31:25 +01:00
|
|
|
* is no delay to worry about. The code generator will take care of
|
|
|
|
|
* the differences between continuous assign and normal assignments.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
|
2000-05-12 01:37:26 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
NetCAssign*dev = 0;
|
2000-05-12 01:37:26 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be assigned values using procedural "
|
|
|
|
|
"continuous assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be referenced in procedural "
|
|
|
|
|
"continuous assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
|
2000-05-12 01:37:26 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2006-06-02 06:48:49 +02:00
|
|
|
unsigned lwid = count_lval_width(lval);
|
2008-11-27 00:37:38 +01:00
|
|
|
ivl_variable_type_t ltype = lval->expr_type();
|
2006-06-02 06:48:49 +02:00
|
|
|
|
2008-11-27 00:37:38 +01:00
|
|
|
NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_);
|
2004-12-11 03:31:25 +01:00
|
|
|
if (rexp == 0)
|
2000-05-12 01:37:26 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
dev = new NetCAssign(lval, rexp);
|
2000-05-12 01:37:26 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate cassign,"
|
2004-12-12 19:13:39 +01:00
|
|
|
<< " lval width=" << lwid
|
2004-12-11 03:31:25 +01:00
|
|
|
<< " rval width=" << rexp->expr_width()
|
|
|
|
|
<< " rval=" << *rexp
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
2000-05-12 01:37:26 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
dev->set_line(*this);
|
2000-05-12 01:37:26 +02:00
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetDeassign* PDeassign::elaborate(Design*des, NetScope*scope) const
|
2000-05-12 01:37:26 +02:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be assigned values using procedural "
|
|
|
|
|
"continuous assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_*lval = lval_->elaborate_lval(des, scope, false);
|
2000-05-12 01:37:26 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
NetDeassign*dev = new NetDeassign(lval);
|
|
|
|
|
dev->set_line( *this );
|
|
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-07 06:53:53 +02:00
|
|
|
/*
|
2003-01-27 06:09:17 +01:00
|
|
|
* Elaborate the delay statement (of the form #<expr> <statement>) as a
|
2000-07-07 06:53:53 +02:00
|
|
|
* NetPDelay object. If the expression is constant, evaluate it now
|
|
|
|
|
* and make a constant delay. If not, then pass an elaborated
|
|
|
|
|
* expression to the constructor of NetPDelay so that the code
|
|
|
|
|
* generator knows to evaluate the expression at run time.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PDelayStatement::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-07-07 06:53:53 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-08-25 03:48:24 +02:00
|
|
|
if (scope->in_func()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: functions cannot have "
|
2007-08-25 03:48:24 +02:00
|
|
|
"delay statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
if (scope->in_final()) {
|
|
|
|
|
cerr << get_fileline() << ": error: final procedures cannot "
|
|
|
|
|
"have delay statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
/* This call evaluates the delay expression to a NetEConst, if
|
|
|
|
|
possible. This includes transforming NetECReal values to
|
|
|
|
|
integers, and applying the proper scaling. */
|
|
|
|
|
NetExpr*dex = elaborate_delay_expr(delay_, des, scope);
|
2001-01-15 00:04:55 +01:00
|
|
|
|
2011-02-10 06:03:08 +01:00
|
|
|
NetPDelay *obj;
|
2003-02-08 20:49:21 +01:00
|
|
|
if (NetEConst*tmp = dynamic_cast<NetEConst*>(dex)) {
|
2000-12-10 23:01:35 +01:00
|
|
|
if (statement_)
|
2011-02-10 06:03:08 +01:00
|
|
|
obj = new NetPDelay(tmp->value().as_ulong64(),
|
|
|
|
|
statement_->elaborate(des, scope));
|
2000-12-10 23:01:35 +01:00
|
|
|
else
|
2011-02-10 06:03:08 +01:00
|
|
|
obj = new NetPDelay(tmp->value().as_ulong64(), 0);
|
2000-12-10 23:01:35 +01:00
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
delete dex;
|
2002-12-21 20:42:17 +01:00
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
} else {
|
2000-07-07 06:53:53 +02:00
|
|
|
if (statement_)
|
2011-02-10 06:03:08 +01:00
|
|
|
obj = new NetPDelay(dex, statement_->elaborate(des, scope));
|
2000-07-07 06:53:53 +02:00
|
|
|
else
|
2011-02-10 06:03:08 +01:00
|
|
|
obj = new NetPDelay(dex, 0);
|
1999-09-30 19:22:33 +02:00
|
|
|
}
|
2011-02-10 06:03:08 +01:00
|
|
|
obj->set_line(*this);
|
|
|
|
|
return obj;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2000-07-26 07:08:07 +02:00
|
|
|
/*
|
|
|
|
|
* The disable statement is not yet supported.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PDisable::elaborate(Design*des, NetScope*scope) const
|
2000-07-26 07:08:07 +02:00
|
|
|
{
|
2000-07-27 07:13:44 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-06-02 05:42:12 +02:00
|
|
|
list<hname_t> spath = eval_scope_path(des, scope, scope_);
|
|
|
|
|
|
|
|
|
|
NetScope*target = des->find_scope(scope, spath);
|
2000-07-27 07:13:44 +02:00
|
|
|
if (target == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Cannot find scope "
|
2007-06-02 05:42:12 +02:00
|
|
|
<< scope_ << " in " << scope_path(scope) << endl;
|
2000-07-27 07:13:44 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (target->type()) {
|
|
|
|
|
case NetScope::FUNC:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Cannot disable functions." << endl;
|
2000-07-27 07:13:44 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case NetScope::MODULE:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Cannot disable modules." << endl;
|
2000-07-27 07:13:44 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetDisable*obj = new NetDisable(target);
|
|
|
|
|
obj->set_line(*this);
|
|
|
|
|
return obj;
|
2000-07-26 07:08:07 +02:00
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2000-04-10 07:26:05 +02:00
|
|
|
* An event statement is an event delay of some sort, attached to a
|
|
|
|
|
* statement. Some Verilog examples are:
|
|
|
|
|
*
|
|
|
|
|
* @(posedge CLK) $display("clock rise");
|
|
|
|
|
* @event_1 $display("event triggered.");
|
|
|
|
|
* @(data or negedge clk) $display("data or clock fall.");
|
|
|
|
|
*
|
|
|
|
|
* The elaborated netlist uses the NetEvent, NetEvWait and NetEvProbe
|
|
|
|
|
* classes. The NetEvWait class represents the part of the netlist
|
|
|
|
|
* that is executed by behavioral code. The process starts waiting on
|
|
|
|
|
* the NetEvent when it executes the NetEvWait step. Net NetEvProbe
|
2003-01-27 06:09:17 +01:00
|
|
|
* and NetEvTrig are structural and behavioral equivalents that
|
2000-04-10 07:26:05 +02:00
|
|
|
* trigger the event, and awakens any processes blocking in the
|
|
|
|
|
* associated wait.
|
|
|
|
|
*
|
|
|
|
|
* The basic data structure is:
|
1999-02-01 01:26:48 +01:00
|
|
|
*
|
2000-04-10 07:26:05 +02:00
|
|
|
* NetEvWait ---/---> NetEvent <----\---- NetEvProbe
|
|
|
|
|
* ... | | ...
|
2000-04-12 06:23:57 +02:00
|
|
|
* NetEvWait ---+ +---- NetEvProbe
|
|
|
|
|
* | ...
|
|
|
|
|
* +---- NetEvTrig
|
2000-04-10 07:26:05 +02:00
|
|
|
*
|
|
|
|
|
* That is, many NetEvWait statements may wait on a single NetEvent
|
|
|
|
|
* object, and Many NetEvProbe objects may trigger the NetEvent
|
2000-04-12 06:23:57 +02:00
|
|
|
* object. The many NetEvWait objects pointing to the NetEvent object
|
|
|
|
|
* reflects the possibility of different places in the code blocking
|
|
|
|
|
* on the same named event, like so:
|
|
|
|
|
*
|
|
|
|
|
* event foo;
|
|
|
|
|
* [...]
|
|
|
|
|
* always begin @foo <statement1>; @foo <statement2> end
|
|
|
|
|
*
|
|
|
|
|
* This tends to not happen with signal edges. The multiple probes
|
|
|
|
|
* pointing to the same event reflect the possibility of many
|
|
|
|
|
* expressions in the same blocking statement, like so:
|
|
|
|
|
*
|
|
|
|
|
* wire reset, clk;
|
|
|
|
|
* [...]
|
|
|
|
|
* always @(reset or posedge clk) <stmt>;
|
|
|
|
|
*
|
|
|
|
|
* Conjunctions like this cause a NetEvent object be created to
|
2003-01-27 06:09:17 +01:00
|
|
|
* represent the overall conjunction, and NetEvProbe objects for each
|
2000-04-12 06:23:57 +02:00
|
|
|
* event expression.
|
|
|
|
|
*
|
|
|
|
|
* If the NetEvent object represents a named event from the source,
|
|
|
|
|
* then there are NetEvTrig objects that represent the trigger
|
|
|
|
|
* statements instead of the NetEvProbe objects representing signals.
|
|
|
|
|
* For example:
|
|
|
|
|
*
|
|
|
|
|
* event foo;
|
|
|
|
|
* always @foo <stmt>;
|
|
|
|
|
* initial begin
|
|
|
|
|
* [...]
|
|
|
|
|
* -> foo;
|
|
|
|
|
* [...]
|
|
|
|
|
* -> foo;
|
|
|
|
|
* [...]
|
|
|
|
|
* end
|
|
|
|
|
*
|
|
|
|
|
* Each trigger statement in the source generates a separate NetEvTrig
|
|
|
|
|
* object in the netlist. Those trigger objects are elaborated
|
|
|
|
|
* elsewhere.
|
|
|
|
|
*
|
|
|
|
|
* Additional complications arise when named events show up in
|
|
|
|
|
* conjunctions. An example of such a case is:
|
|
|
|
|
*
|
|
|
|
|
* event foo;
|
|
|
|
|
* wire bar;
|
|
|
|
|
* always @(foo or posedge bar) <stmt>;
|
|
|
|
|
*
|
|
|
|
|
* Since there is by definition a NetEvent object for the foo object,
|
|
|
|
|
* this is handled by allowing the NetEvWait object to point to
|
|
|
|
|
* multiple NetEvent objects. All the NetEvProbe based objects are
|
|
|
|
|
* collected and pointed as the synthetic NetEvent object, and all the
|
|
|
|
|
* named events are added into the list of NetEvent object that the
|
|
|
|
|
* NetEvWait object can refer to.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
2000-04-12 06:23:57 +02:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
|
2000-12-02 00:52:49 +01:00
|
|
|
NetProc*enet) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2000-04-04 05:20:15 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2007-08-25 03:48:24 +02:00
|
|
|
if (scope->in_func()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: functions cannot have "
|
2007-08-25 03:48:24 +02:00
|
|
|
"event statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
if (scope->in_final()) {
|
|
|
|
|
cerr << get_fileline() << ": error: final procedures cannot "
|
|
|
|
|
"have event statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
/* Create a single NetEvent and NetEvWait. Then, create a
|
2000-04-10 07:26:05 +02:00
|
|
|
NetEvProbe for each conjunctive event in the event
|
2003-01-27 06:09:17 +01:00
|
|
|
list. The NetEvProbe objects all refer back to the NetEvent
|
2000-04-10 07:26:05 +02:00
|
|
|
object. */
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
NetEvent*ev = new NetEvent(scope->local_symbol());
|
2000-04-12 06:23:57 +02:00
|
|
|
ev->set_line(*this);
|
|
|
|
|
unsigned expr_count = 0;
|
2000-04-10 07:26:05 +02:00
|
|
|
|
2000-04-12 06:23:57 +02:00
|
|
|
NetEvWait*wa = new NetEvWait(enet);
|
|
|
|
|
wa->set_line(*this);
|
1999-05-01 04:57:52 +02:00
|
|
|
|
2002-04-21 06:59:07 +02:00
|
|
|
/* If there are no expressions, this is a signal that it is an
|
|
|
|
|
@* statement. Generate an expression to use. */
|
|
|
|
|
|
|
|
|
|
if (expr_.count() == 0) {
|
|
|
|
|
assert(enet);
|
2007-10-25 22:31:00 +02:00
|
|
|
/* For synthesis we want just the inputs, but for the rest we
|
|
|
|
|
* want inputs and outputs that may cause a value to change. */
|
2007-10-31 03:14:09 +01:00
|
|
|
extern bool synthesis; /* Synthesis flag from main.cc */
|
2007-10-25 22:31:00 +02:00
|
|
|
bool rem_out = false;
|
2007-10-31 03:14:09 +01:00
|
|
|
if (synthesis) {
|
2007-10-25 22:31:00 +02:00
|
|
|
rem_out = true;
|
|
|
|
|
}
|
|
|
|
|
NexusSet*nset = enet->nex_input(rem_out);
|
2002-04-21 06:59:07 +02:00
|
|
|
if (nset == 0) {
|
2008-08-14 21:40:53 +02:00
|
|
|
cerr << get_fileline() << ": error: Unable to elaborate:"
|
|
|
|
|
<< endl;
|
2002-04-21 06:59:07 +02:00
|
|
|
enet->dump(cerr, 6);
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return enet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nset->count() == 0) {
|
2011-11-24 02:25:30 +01:00
|
|
|
cerr << get_fileline() << ": warning: @* found no "
|
|
|
|
|
"sensitivities so it will never trigger."
|
|
|
|
|
<< endl;
|
|
|
|
|
/* Add the currently unreferenced event to the scope. */
|
|
|
|
|
scope->add_event(ev);
|
|
|
|
|
/* Delete the current wait, create a new one with no
|
|
|
|
|
* statement and add the event to it. This creates a
|
|
|
|
|
* perpetual wait since nothing will ever trigger the
|
|
|
|
|
* unreferenced event. */
|
|
|
|
|
delete wa;
|
|
|
|
|
wa = new NetEvWait(0);
|
|
|
|
|
wa->set_line(*this);
|
|
|
|
|
wa->add_event(ev);
|
|
|
|
|
return wa;
|
2002-04-21 06:59:07 +02:00
|
|
|
}
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(),
|
2002-04-21 06:59:07 +02:00
|
|
|
ev, NetEvProbe::ANYEDGE,
|
|
|
|
|
nset->count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < nset->count() ; idx += 1)
|
|
|
|
|
connect(nset[0][idx], pr->pin(idx));
|
|
|
|
|
|
|
|
|
|
delete nset;
|
|
|
|
|
des->add_node(pr);
|
|
|
|
|
|
|
|
|
|
expr_count = 1;
|
|
|
|
|
|
|
|
|
|
} else for (unsigned idx = 0 ; idx < expr_.count() ; idx += 1) {
|
2000-04-12 06:23:57 +02:00
|
|
|
|
|
|
|
|
assert(expr_[idx]->expr());
|
|
|
|
|
|
|
|
|
|
/* If the expression is an identifier that matches a
|
2008-10-21 18:00:48 +02:00
|
|
|
named event, then handle this case all at once and
|
2000-04-12 06:23:57 +02:00
|
|
|
skip the rest of the expression handling. */
|
2000-04-02 00:14:19 +02:00
|
|
|
|
2000-04-09 18:43:50 +02:00
|
|
|
if (PEIdent*id = dynamic_cast<PEIdent*>(expr_[idx]->expr())) {
|
2003-09-20 03:05:35 +02:00
|
|
|
NetNet* sig = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
|
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
NetScope*found_in = symbol_search(this, des, scope,
|
|
|
|
|
id->path(),
|
2007-01-16 06:44:14 +01:00
|
|
|
sig, par, eve);
|
2003-09-20 03:05:35 +02:00
|
|
|
|
|
|
|
|
if (found_in && eve) {
|
|
|
|
|
wa->add_event(eve);
|
2010-03-13 20:12:00 +01:00
|
|
|
/* You can not look for the posedge or negedge of
|
|
|
|
|
* an event. */
|
|
|
|
|
if (expr_[idx]->type() != PEEvent::ANYEDGE) {
|
|
|
|
|
cerr << get_fileline() << ": error: ";
|
|
|
|
|
switch (expr_[idx]->type()) {
|
|
|
|
|
case PEEvent::POSEDGE:
|
|
|
|
|
cerr << "posedge";
|
|
|
|
|
break;
|
|
|
|
|
case PEEvent::NEGEDGE:
|
|
|
|
|
cerr << "negedge";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cerr << "unknown edge type!";
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
cerr << " can not be used with a named event ("
|
|
|
|
|
<< eve->name() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
2000-04-12 06:23:57 +02:00
|
|
|
continue;
|
2000-04-09 18:43:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-20 03:05:35 +02:00
|
|
|
|
2000-04-12 06:23:57 +02:00
|
|
|
/* So now we have a normal event expression. Elaborate
|
|
|
|
|
the sub-expression as a net and decide how to handle
|
|
|
|
|
the edge. */
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto()) {
|
|
|
|
|
if (! dynamic_cast<PEIdent*>(expr_[idx]->expr())) {
|
|
|
|
|
cerr << get_fileline() << ": sorry, complex event "
|
|
|
|
|
"expressions are not yet supported in "
|
|
|
|
|
"automatic tasks." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-26 23:59:52 +01:00
|
|
|
NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), -1);
|
2008-09-09 04:13:49 +02:00
|
|
|
if (tmp == 0) {
|
|
|
|
|
expr_[idx]->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-22 22:48:34 +01:00
|
|
|
NetNet*expr = tmp->synthesize(des, scope, tmp);
|
1999-05-01 04:57:52 +02:00
|
|
|
if (expr == 0) {
|
2000-04-10 07:26:05 +02:00
|
|
|
expr_[idx]->dump(cerr);
|
1999-05-01 04:57:52 +02:00
|
|
|
cerr << endl;
|
1999-05-10 02:16:57 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
1999-05-01 04:57:52 +02:00
|
|
|
}
|
|
|
|
|
assert(expr);
|
1999-05-01 22:43:55 +02:00
|
|
|
|
2008-09-09 04:13:49 +02:00
|
|
|
delete tmp;
|
|
|
|
|
|
2000-04-12 06:23:57 +02:00
|
|
|
unsigned pins = (expr_[idx]->type() == PEEvent::ANYEDGE)
|
1999-05-01 22:43:55 +02:00
|
|
|
? expr->pin_count() : 1;
|
|
|
|
|
|
2000-04-10 07:26:05 +02:00
|
|
|
NetEvProbe*pr;
|
|
|
|
|
switch (expr_[idx]->type()) {
|
2000-04-12 06:23:57 +02:00
|
|
|
case PEEvent::POSEDGE:
|
2003-03-06 01:28:41 +01:00
|
|
|
pr = new NetEvProbe(scope, scope->local_symbol(), ev,
|
2000-04-10 07:26:05 +02:00
|
|
|
NetEvProbe::POSEDGE, pins);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-04-12 06:23:57 +02:00
|
|
|
case PEEvent::NEGEDGE:
|
2003-03-06 01:28:41 +01:00
|
|
|
pr = new NetEvProbe(scope, scope->local_symbol(), ev,
|
2000-04-10 07:26:05 +02:00
|
|
|
NetEvProbe::NEGEDGE, pins);
|
|
|
|
|
break;
|
1999-04-29 04:16:26 +02:00
|
|
|
|
2000-04-12 06:23:57 +02:00
|
|
|
case PEEvent::ANYEDGE:
|
2003-03-06 01:28:41 +01:00
|
|
|
pr = new NetEvProbe(scope, scope->local_symbol(), ev,
|
2000-04-10 07:26:05 +02:00
|
|
|
NetEvProbe::ANYEDGE, pins);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2009-12-10 22:58:50 +01:00
|
|
|
pr = NULL;
|
2000-04-10 07:26:05 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned p = 0 ; p < pr->pin_count() ; p += 1)
|
|
|
|
|
connect(pr->pin(p), expr->pin(p));
|
|
|
|
|
|
|
|
|
|
des->add_node(pr);
|
2000-04-12 06:23:57 +02:00
|
|
|
expr_count += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there was at least one conjunction that was an
|
|
|
|
|
expression (and not a named event) then add this
|
|
|
|
|
event. Otherwise, we didn't use it so delete it. */
|
|
|
|
|
if (expr_count > 0) {
|
2002-07-24 18:22:59 +02:00
|
|
|
scope->add_event(ev);
|
|
|
|
|
wa->add_event(ev);
|
|
|
|
|
/* NOTE: This event that I am adding to the wait may be
|
|
|
|
|
a duplicate of another event somewhere else. However,
|
|
|
|
|
I don't know that until all the modules are hooked
|
|
|
|
|
up, so it is best to leave find_similar_event to
|
|
|
|
|
after elaboration. */
|
2000-04-12 06:23:57 +02:00
|
|
|
} else {
|
|
|
|
|
delete ev;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2000-04-10 07:26:05 +02:00
|
|
|
return wa;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2003-05-19 04:50:58 +02:00
|
|
|
/*
|
|
|
|
|
* This is the special case of the event statement, the wait
|
|
|
|
|
* statement. This is elaborated into a slightly more complicated
|
|
|
|
|
* statement that uses non-wait statements:
|
|
|
|
|
*
|
|
|
|
|
* wait (<expr>) <statement>
|
|
|
|
|
*
|
|
|
|
|
* becomes
|
|
|
|
|
*
|
|
|
|
|
* begin
|
|
|
|
|
* while (1 !== <expr>)
|
|
|
|
|
* @(<expr inputs>) <noop>;
|
|
|
|
|
* <statement>;
|
|
|
|
|
* end
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
|
|
|
|
|
NetProc*enet) const
|
|
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
assert(expr_.count() == 1);
|
|
|
|
|
|
2007-08-25 03:48:24 +02:00
|
|
|
if (scope->in_func()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: functions cannot have "
|
2007-08-25 03:48:24 +02:00
|
|
|
"wait statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
if (scope->in_final()) {
|
|
|
|
|
cerr << get_fileline() << ": error: final procedures cannot "
|
|
|
|
|
"have wait statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-27 00:37:38 +01:00
|
|
|
PExpr *pe = expr_[0]->expr();
|
2003-05-19 04:50:58 +02:00
|
|
|
|
2004-03-07 21:04:10 +01:00
|
|
|
/* Elaborate wait expression. Don't eval yet, we will do that
|
|
|
|
|
shortly, after we apply a reduction or. */
|
2008-11-27 00:37:38 +01:00
|
|
|
|
2011-10-05 18:49:00 +02:00
|
|
|
PExpr::width_mode_t mode = PExpr::SIZED;
|
2011-02-26 23:59:52 +01:00
|
|
|
pe->test_width(des, scope, mode);
|
2011-03-27 12:08:33 +02:00
|
|
|
NetExpr*expr = pe->elaborate_expr(des, scope, pe->expr_width(),
|
|
|
|
|
PExpr::NO_FLAGS);
|
2003-05-19 04:50:58 +02:00
|
|
|
if (expr == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Unable to elaborate"
|
2003-05-19 04:50:58 +02:00
|
|
|
" wait condition expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-22 17:08:14 +01:00
|
|
|
// If the condition expression is more than 1 bits, then
|
2004-05-25 05:42:58 +02:00
|
|
|
// generate a reduction operator to get the result down to
|
|
|
|
|
// one bit. In other words, Turn <e> into |<e>;
|
2004-01-13 04:42:49 +01:00
|
|
|
|
|
|
|
|
if (expr->expr_width() < 1) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2004-01-13 04:42:49 +01:00
|
|
|
"incomprehensible wait expression width (0)." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expr->expr_width() > 1) {
|
|
|
|
|
assert(expr->expr_width() > 1);
|
|
|
|
|
NetEUReduce*cmp = new NetEUReduce('|', expr);
|
|
|
|
|
expr = cmp;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-05 23:07:26 +02:00
|
|
|
/* precalculate as much as possible of the wait expression. */
|
2008-03-08 03:51:50 +01:00
|
|
|
eval_expr(expr);
|
2004-09-05 23:07:26 +02:00
|
|
|
|
2003-05-19 04:50:58 +02:00
|
|
|
/* Detect the unusual case that the wait expression is
|
|
|
|
|
constant. Constant true is OK (it becomes transparent) but
|
|
|
|
|
constant false is almost certainly not what is intended. */
|
2004-05-25 05:42:58 +02:00
|
|
|
assert(expr->expr_width() == 1);
|
2003-05-19 04:50:58 +02:00
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(expr)) {
|
|
|
|
|
verinum val = ce->value();
|
|
|
|
|
assert(val.len() == 1);
|
2004-05-25 05:42:58 +02:00
|
|
|
|
|
|
|
|
/* Constant true -- wait(1) <s1> reduces to <s1>. */
|
2003-05-19 04:50:58 +02:00
|
|
|
if (val[0] == verinum::V1) {
|
|
|
|
|
delete expr;
|
|
|
|
|
assert(enet);
|
|
|
|
|
return enet;
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-25 05:42:58 +02:00
|
|
|
/* Otherwise, false. wait(0) blocks permanently. */
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: wait expression is "
|
2003-05-19 04:50:58 +02:00
|
|
|
<< "constant false." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : The statement will "
|
2003-05-19 04:50:58 +02:00
|
|
|
<< "block permanently." << endl;
|
2004-05-25 05:42:58 +02:00
|
|
|
|
|
|
|
|
/* Create an event wait and an otherwise unreferenced
|
|
|
|
|
event variable to force a perpetual wait. */
|
|
|
|
|
NetEvent*wait_event = new NetEvent(scope->local_symbol());
|
|
|
|
|
scope->add_event(wait_event);
|
|
|
|
|
|
|
|
|
|
NetEvWait*wait = new NetEvWait(0);
|
|
|
|
|
wait->add_event(wait_event);
|
|
|
|
|
wait->set_line(*this);
|
|
|
|
|
|
|
|
|
|
delete expr;
|
|
|
|
|
delete enet;
|
|
|
|
|
return wait;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Invert the sense of the test with an exclusive NOR. In
|
|
|
|
|
other words, if this adjusted expression returns TRUE, then
|
|
|
|
|
wait. */
|
|
|
|
|
assert(expr->expr_width() == 1);
|
|
|
|
|
expr = new NetEBComp('N', expr, new NetEConst(verinum(verinum::V1)));
|
2008-03-08 03:51:50 +01:00
|
|
|
eval_expr(expr);
|
2003-05-19 04:50:58 +02:00
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
NetEvent*wait_event = new NetEvent(scope->local_symbol());
|
2003-05-19 04:50:58 +02:00
|
|
|
scope->add_event(wait_event);
|
|
|
|
|
|
|
|
|
|
NetEvWait*wait = new NetEvWait(0 /* noop */);
|
|
|
|
|
wait->add_event(wait_event);
|
|
|
|
|
wait->set_line(*this);
|
|
|
|
|
|
|
|
|
|
NexusSet*wait_set = expr->nex_input();
|
|
|
|
|
if (wait_set == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: No NexusSet"
|
2003-05-19 04:50:58 +02:00
|
|
|
<< " from wait expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wait_set->count() == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: Empty NexusSet"
|
2003-05-19 04:50:58 +02:00
|
|
|
<< " from wait expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEvProbe*wait_pr = new NetEvProbe(scope, scope->local_symbol(),
|
|
|
|
|
wait_event, NetEvProbe::ANYEDGE,
|
|
|
|
|
wait_set->count());
|
|
|
|
|
for (unsigned idx = 0; idx < wait_set->count() ; idx += 1)
|
|
|
|
|
connect(wait_set[0][idx], wait_pr->pin(idx));
|
|
|
|
|
|
|
|
|
|
delete wait_set;
|
|
|
|
|
des->add_node(wait_pr);
|
|
|
|
|
|
|
|
|
|
NetWhile*loop = new NetWhile(expr, wait);
|
|
|
|
|
loop->set_line(*this);
|
|
|
|
|
|
2003-09-13 03:01:51 +02:00
|
|
|
/* If there is no real substatement (i.e., "wait (foo) ;") then
|
2003-05-19 04:50:58 +02:00
|
|
|
we are done. */
|
|
|
|
|
if (enet == 0)
|
|
|
|
|
return loop;
|
|
|
|
|
|
2004-05-25 05:42:58 +02:00
|
|
|
/* Create a sequential block to combine the wait loop and the
|
2003-05-19 04:50:58 +02:00
|
|
|
delayed statement. */
|
|
|
|
|
NetBlock*block = new NetBlock(NetBlock::SEQU, 0);
|
|
|
|
|
block->append(loop);
|
|
|
|
|
block->append(enet);
|
|
|
|
|
block->set_line(*this);
|
|
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PEventStatement::elaborate(Design*des, NetScope*scope) const
|
1999-09-22 04:00:48 +02:00
|
|
|
{
|
|
|
|
|
NetProc*enet = 0;
|
|
|
|
|
if (statement_) {
|
2001-11-22 07:20:59 +01:00
|
|
|
enet = statement_->elaborate(des, scope);
|
1999-09-22 04:00:48 +02:00
|
|
|
if (enet == 0)
|
|
|
|
|
return 0;
|
2004-09-05 23:07:26 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
enet = new NetBlock(NetBlock::SEQU, 0);
|
|
|
|
|
enet->set_line(*this);
|
1999-09-22 04:00:48 +02:00
|
|
|
}
|
|
|
|
|
|
2003-05-19 04:50:58 +02:00
|
|
|
if ((expr_.count() == 1) && (expr_[0]->type() == PEEvent::POSITIVE))
|
|
|
|
|
return elaborate_wait(des, scope, enet);
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
return elaborate_st(des, scope, enet);
|
1999-09-22 04:00:48 +02:00
|
|
|
}
|
|
|
|
|
|
1999-06-19 23:06:16 +02:00
|
|
|
/*
|
|
|
|
|
* Forever statements are represented directly in the netlist. It is
|
|
|
|
|
* theoretically possible to use a while structure with a constant
|
|
|
|
|
* expression to represent the loop, but why complicate the code
|
|
|
|
|
* generators so?
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PForever::elaborate(Design*des, NetScope*scope) const
|
1999-06-19 23:06:16 +02:00
|
|
|
{
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*stat = statement_->elaborate(des, scope);
|
1999-06-19 23:06:16 +02:00
|
|
|
if (stat == 0) return 0;
|
|
|
|
|
|
|
|
|
|
NetForever*proc = new NetForever(stat);
|
2011-02-10 06:03:08 +01:00
|
|
|
proc->set_line(*this);
|
1999-06-19 23:06:16 +02:00
|
|
|
return proc;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
/*
|
2008-01-29 21:19:59 +01:00
|
|
|
* Force is like a procedural assignment, most notably procedural
|
2004-12-30 00:55:43 +01:00
|
|
|
* continuous assignment:
|
|
|
|
|
*
|
|
|
|
|
* force <lval> = <rval>
|
|
|
|
|
*
|
|
|
|
|
* The <lval> can be anything that a normal behavioral assignment can
|
2011-03-11 20:27:54 +01:00
|
|
|
* take, plus net signals. This is a little bit more lax than the
|
2008-01-25 22:34:51 +01:00
|
|
|
* other procedural assignments.
|
2004-12-30 00:55:43 +01:00
|
|
|
*/
|
2004-12-11 03:31:25 +01:00
|
|
|
NetForce* PForce::elaborate(Design*des, NetScope*scope) const
|
2000-04-22 06:20:19 +02:00
|
|
|
{
|
2004-12-11 03:31:25 +01:00
|
|
|
NetForce*dev = 0;
|
2000-04-22 06:20:19 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be assigned values using procedural "
|
|
|
|
|
"force statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scope->is_auto() && expr_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be referenced in procedural force "
|
|
|
|
|
"statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
|
2000-04-22 06:20:19 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2006-06-02 06:48:49 +02:00
|
|
|
unsigned lwid = count_lval_width(lval);
|
2008-11-27 00:37:38 +01:00
|
|
|
ivl_variable_type_t ltype = lval->expr_type();
|
2006-06-02 06:48:49 +02:00
|
|
|
|
2008-11-27 00:37:38 +01:00
|
|
|
NetExpr*rexp = elaborate_rval_expr(des, scope, ltype, lwid, expr_);
|
2004-12-11 03:31:25 +01:00
|
|
|
if (rexp == 0)
|
2000-04-22 06:20:19 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2010-10-20 04:09:06 +02:00
|
|
|
if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) {
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Cast force rvalue to int2" << endl;
|
|
|
|
|
}
|
|
|
|
|
rexp = cast_to_int2(rexp);
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
dev = new NetForce(lval, rexp);
|
2000-04-22 06:20:19 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if (debug_elaborate) {
|
2008-06-24 17:46:16 +02:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate force,"
|
2004-12-11 03:31:25 +01:00
|
|
|
<< " lval width=" << lval->lwidth()
|
|
|
|
|
<< " rval width=" << rexp->expr_width()
|
|
|
|
|
<< " rval=" << *rexp
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
2000-04-22 06:20:19 +02:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
dev->set_line(*this);
|
2000-04-22 06:20:19 +02:00
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
/*
|
1999-08-18 06:00:02 +02:00
|
|
|
* elaborate the for loop as the equivalent while loop. This eases the
|
1998-11-09 19:55:33 +01:00
|
|
|
* task for the target code generator. The structure is:
|
|
|
|
|
*
|
1999-09-18 04:51:35 +02:00
|
|
|
* begin : top
|
1998-11-09 19:55:33 +01:00
|
|
|
* name1_ = expr1_;
|
1999-09-18 04:51:35 +02:00
|
|
|
* while (cond_) begin : body
|
1998-11-09 19:55:33 +01:00
|
|
|
* statement_;
|
|
|
|
|
* name2_ = expr2_;
|
|
|
|
|
* end
|
|
|
|
|
* end
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const
|
1998-11-09 19:55:33 +01:00
|
|
|
{
|
2001-02-07 22:47:13 +01:00
|
|
|
NetExpr*etmp;
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
const PEIdent*id1 = dynamic_cast<const PEIdent*>(name1_);
|
|
|
|
|
assert(id1);
|
|
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
2003-10-26 05:49:51 +01:00
|
|
|
top->set_line(*this);
|
1999-09-18 04:51:35 +02:00
|
|
|
|
|
|
|
|
/* make the expression, and later the initial assignment to
|
|
|
|
|
the condition variable. The statement in the for loop is
|
|
|
|
|
very specifically an assignment. */
|
2001-12-03 05:47:14 +01:00
|
|
|
NetNet*sig = des->find_signal(scope, id1->path());
|
1999-06-06 22:45:38 +02:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << id1->get_fileline() << ": register ``" << id1->path()
|
2008-02-25 04:40:54 +01:00
|
|
|
<< "'' unknown in " << scope_path(scope) << "." << endl;
|
1999-06-06 22:45:38 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1998-11-09 19:55:33 +01:00
|
|
|
assert(sig);
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_*lv = new NetAssign_(sig);
|
2001-02-07 22:47:13 +01:00
|
|
|
|
|
|
|
|
/* Make the r-value of the initial assignment, and size it
|
|
|
|
|
properly. Then use it to build the assignment statement. */
|
2011-03-03 05:23:02 +01:00
|
|
|
etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(),
|
2011-02-26 23:59:52 +01:00
|
|
|
expr1_);
|
2005-05-17 22:56:55 +02:00
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: FOR initial assign: "
|
2005-05-17 22:56:55 +02:00
|
|
|
<< sig->name() << " = " << *etmp << endl;
|
2008-03-25 22:06:16 +01:00
|
|
|
}
|
|
|
|
|
|
2001-02-07 22:47:13 +01:00
|
|
|
NetAssign*init = new NetAssign(lv, etmp);
|
2003-10-26 05:49:51 +01:00
|
|
|
init->set_line(*this);
|
1999-06-13 18:30:06 +02:00
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
top->append(init);
|
|
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*body = new NetBlock(NetBlock::SEQU, 0);
|
2003-10-26 05:49:51 +01:00
|
|
|
body->set_line(*this);
|
1998-11-09 19:55:33 +01:00
|
|
|
|
1999-09-18 04:51:35 +02:00
|
|
|
/* Elaborate the statement that is contained in the for
|
|
|
|
|
loop. If there is an error, this will return 0 and I should
|
|
|
|
|
skip the append. No need to worry, the error has been
|
|
|
|
|
reported so it's OK that the netlist is bogus. */
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*tmp = statement_->elaborate(des, scope);
|
1999-09-18 04:51:35 +02:00
|
|
|
if (tmp)
|
|
|
|
|
body->append(tmp);
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
|
2012-02-25 18:28:20 +01:00
|
|
|
/* Now elaborate the for_step statement. I really should do
|
|
|
|
|
some error checking here to make sure the step statement
|
|
|
|
|
really does step the variable. */
|
2011-02-26 23:59:52 +01:00
|
|
|
if (debug_elaborate) {
|
2012-02-25 18:28:20 +01:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate for_step statement "
|
2011-02-26 23:59:52 +01:00
|
|
|
<< sig->name() << " = " << *etmp << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-25 18:28:20 +01:00
|
|
|
NetProc*step = step_->elaborate(des, scope);
|
1999-06-13 18:30:06 +02:00
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
body->append(step);
|
|
|
|
|
|
1999-09-18 03:53:08 +02:00
|
|
|
|
|
|
|
|
/* Elaborate the condition expression. Try to evaluate it too,
|
|
|
|
|
in case it is a constant. This is an interesting case
|
|
|
|
|
worthy of a warning. */
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*ce = elab_and_eval(des, scope, cond_, -1);
|
1999-10-18 02:02:21 +02:00
|
|
|
if (ce == 0) {
|
|
|
|
|
delete top;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-03-07 21:04:10 +01:00
|
|
|
if (dynamic_cast<NetEConst*>(ce)) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: condition expression "
|
2004-03-07 21:04:10 +01:00
|
|
|
"of for-loop is constant." << endl;
|
1999-09-18 03:53:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* All done, build up the loop. */
|
|
|
|
|
|
|
|
|
|
NetWhile*loop = new NetWhile(ce, body);
|
2003-10-26 05:49:51 +01:00
|
|
|
loop->set_line(*this);
|
1998-11-09 19:55:33 +01:00
|
|
|
top->append(loop);
|
|
|
|
|
return top;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 22:46:19 +02:00
|
|
|
/*
|
2000-05-02 02:58:11 +02:00
|
|
|
* (See the PTask::elaborate methods for basic common stuff.)
|
|
|
|
|
*
|
|
|
|
|
* The return value of a function is represented as a reg variable
|
|
|
|
|
* within the scope of the function that has the name of the
|
|
|
|
|
* function. So for example with the function:
|
|
|
|
|
*
|
|
|
|
|
* function [7:0] incr;
|
|
|
|
|
* input [7:0] in1;
|
|
|
|
|
* incr = in1 + 1;
|
|
|
|
|
* endfunction
|
2000-03-08 05:36:53 +01:00
|
|
|
*
|
2000-05-02 02:58:11 +02:00
|
|
|
* The scope of the function is <parent>.incr and there is a reg
|
|
|
|
|
* variable <parent>.incr.incr. The elaborate_1 method is called with
|
|
|
|
|
* the scope of the function, so the return reg is easily located.
|
|
|
|
|
*
|
|
|
|
|
* The function parameters are all inputs, except for the synthetic
|
|
|
|
|
* output parameter that is the return value. The return value goes
|
|
|
|
|
* into port 0, and the parameters are all the remaining ports.
|
1999-09-01 22:46:19 +02:00
|
|
|
*/
|
1999-09-01 00:38:29 +02:00
|
|
|
|
2000-07-30 20:25:43 +02:00
|
|
|
void PFunction::elaborate(Design*des, NetScope*scope) const
|
1999-09-01 22:46:19 +02:00
|
|
|
{
|
2011-04-05 21:43:54 +02:00
|
|
|
if (scope->elab_stage() > 2)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
scope->set_elab_stage(3);
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetFuncDef*def = scope->func_def();
|
2004-06-01 01:34:36 +02:00
|
|
|
if (def == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2004-06-01 01:34:36 +02:00
|
|
|
<< "No function definition for function "
|
2007-06-02 05:42:12 +02:00
|
|
|
<< scope_path(scope) << endl;
|
2008-02-28 05:54:47 +01:00
|
|
|
des->errors += 1;
|
2004-06-01 01:34:36 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 22:46:19 +02:00
|
|
|
assert(def);
|
|
|
|
|
|
2011-09-17 21:10:05 +02:00
|
|
|
ivl_assert(*this, statement_);
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*st = statement_->elaborate(des, scope);
|
1999-09-01 22:46:19 +02:00
|
|
|
if (st == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << statement_->get_fileline() << ": error: Unable to elaborate "
|
2007-06-02 05:42:12 +02:00
|
|
|
"statement in function " << scope->basename() << "." << endl;
|
2011-04-05 21:43:54 +02:00
|
|
|
scope->is_const_func(true); // error recovery
|
1999-09-01 22:46:19 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def->set_proc(st);
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PRelease::elaborate(Design*des, NetScope*scope) const
|
2000-04-22 06:20:19 +02:00
|
|
|
{
|
2000-04-23 05:45:24 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
if (scope->is_auto() && lval_->has_aa_term(des, scope)) {
|
|
|
|
|
cerr << get_fileline() << ": error: automatically allocated "
|
|
|
|
|
"variables may not be assigned values using procedural "
|
|
|
|
|
"force statements." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_*lval = lval_->elaborate_lval(des, scope, true);
|
2000-04-23 05:45:24 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
NetRelease*dev = new NetRelease(lval);
|
|
|
|
|
dev->set_line( *this );
|
|
|
|
|
return dev;
|
2000-04-22 06:20:19 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
|
1999-06-19 23:06:16 +02:00
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*expr = elab_and_eval(des, scope, expr_, -1);
|
1999-06-19 23:06:16 +02:00
|
|
|
if (expr == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": Unable to elaborate"
|
1999-06-19 23:06:16 +02:00
|
|
|
" repeat expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*stat = statement_->elaborate(des, scope);
|
1999-06-19 23:06:16 +02:00
|
|
|
if (stat == 0) return 0;
|
|
|
|
|
|
|
|
|
|
// If the expression is a constant, handle certain special
|
|
|
|
|
// iteration counts.
|
|
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(expr)) {
|
2008-09-04 01:05:12 +02:00
|
|
|
long val = ce->value().as_long();
|
|
|
|
|
if (val <= 0) {
|
1999-06-19 23:06:16 +02:00
|
|
|
delete expr;
|
|
|
|
|
delete stat;
|
2002-05-27 02:08:45 +02:00
|
|
|
return new NetBlock(NetBlock::SEQU, 0);
|
2008-09-04 01:05:12 +02:00
|
|
|
} else if (val == 1) {
|
1999-06-19 23:06:16 +02:00
|
|
|
delete expr;
|
|
|
|
|
return stat;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetRepeat*proc = new NetRepeat(expr, stat);
|
2011-02-10 06:03:08 +01:00
|
|
|
proc->set_line( *this );
|
1999-06-19 23:06:16 +02:00
|
|
|
return proc;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-03 04:12:51 +02:00
|
|
|
/*
|
|
|
|
|
* A task definition is elaborated by elaborating the statement that
|
1999-07-24 04:11:19 +02:00
|
|
|
* it contains, and connecting its ports to NetNet objects. The
|
|
|
|
|
* netlist doesn't really need the array of parameters once elaboration
|
|
|
|
|
* is complete, but this is the best place to store them.
|
2000-05-02 02:58:11 +02:00
|
|
|
*
|
|
|
|
|
* The first elaboration pass finds the reg objects that match the
|
|
|
|
|
* port names, and creates the NetTaskDef object. The port names are
|
|
|
|
|
* in the form task.port.
|
|
|
|
|
*
|
|
|
|
|
* task foo;
|
|
|
|
|
* output blah;
|
|
|
|
|
* begin <body> end
|
|
|
|
|
* endtask
|
|
|
|
|
*
|
|
|
|
|
* So in the foo example, the PWire objects that represent the ports
|
|
|
|
|
* of the task will include a foo.blah for the blah port. This port is
|
2000-07-30 20:25:43 +02:00
|
|
|
* bound to a NetNet object by looking up the name. All of this is
|
|
|
|
|
* handled by the PTask::elaborate_sig method and the results stashed
|
2003-01-27 06:09:17 +01:00
|
|
|
* in the created NetTaskDef attached to the scope.
|
2000-05-02 02:58:11 +02:00
|
|
|
*
|
|
|
|
|
* Elaboration pass 2 for the task definition causes the statement of
|
|
|
|
|
* the task to be elaborated and attached to the NetTaskDef object
|
|
|
|
|
* created in pass 1.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: I am not sure why I bothered to prepend the task name to the
|
|
|
|
|
* port name when making the port list. It is not really useful, but
|
|
|
|
|
* that is what I did in pform_make_task_ports, so there it is.
|
1999-07-03 04:12:51 +02:00
|
|
|
*/
|
2000-04-28 18:50:53 +02:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
void PTask::elaborate(Design*des, NetScope*task) const
|
1999-09-30 23:28:34 +02:00
|
|
|
{
|
2008-03-04 05:49:52 +01:00
|
|
|
// Elaborate any processes that are part of this scope that
|
|
|
|
|
// aren't the definition itself. This can happen, for example,
|
|
|
|
|
// with variable initialization statements in this scope.
|
|
|
|
|
elaborate_behaviors_(des, task);
|
|
|
|
|
|
2001-04-02 04:28:12 +02:00
|
|
|
NetTaskDef*def = task->task_def();
|
1999-09-30 23:28:34 +02:00
|
|
|
assert(def);
|
|
|
|
|
|
1999-09-30 04:43:01 +02:00
|
|
|
NetProc*st;
|
|
|
|
|
if (statement_ == 0) {
|
2002-05-27 02:08:45 +02:00
|
|
|
st = new NetBlock(NetBlock::SEQU, 0);
|
1999-09-30 04:43:01 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
st = statement_->elaborate(des, task);
|
1999-09-30 04:43:01 +02:00
|
|
|
if (st == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << statement_->get_fileline() << ": Unable to elaborate "
|
2007-06-02 05:42:12 +02:00
|
|
|
"statement in task " << scope_path(task)
|
2007-12-20 18:31:01 +01:00
|
|
|
<< " at " << get_fileline() << "." << endl;
|
1999-09-30 04:43:01 +02:00
|
|
|
return;
|
|
|
|
|
}
|
1999-07-03 04:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
1999-09-30 23:28:34 +02:00
|
|
|
def->set_proc(st);
|
1999-07-03 04:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
|
2000-04-01 21:31:57 +02:00
|
|
|
{
|
2000-04-04 05:20:15 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
2003-09-20 03:05:35 +02:00
|
|
|
NetNet* sig = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
|
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
NetScope*found_in = symbol_search(this, des, scope, event_,
|
2007-01-16 06:44:14 +01:00
|
|
|
sig, par, eve);
|
2003-09-20 03:05:35 +02:00
|
|
|
|
|
|
|
|
if (found_in == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: event <" << event_ << ">"
|
2000-04-04 05:20:15 +02:00
|
|
|
<< " not found." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-20 03:05:35 +02:00
|
|
|
if (eve == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: <" << event_ << ">"
|
2003-09-20 03:05:35 +02:00
|
|
|
<< " is not a named event." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEvTrig*trig = new NetEvTrig(eve);
|
2000-04-04 05:20:15 +02:00
|
|
|
trig->set_line(*this);
|
|
|
|
|
return trig;
|
2000-04-01 21:31:57 +02:00
|
|
|
}
|
|
|
|
|
|
1998-11-11 04:13:04 +01:00
|
|
|
/*
|
|
|
|
|
* The while loop is fairly directly represented in the netlist.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
|
1998-11-11 04:13:04 +01:00
|
|
|
{
|
2008-11-27 00:37:38 +01:00
|
|
|
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
|
2011-02-28 04:20:16 +01:00
|
|
|
tmp->set_line(*this);
|
2008-11-27 00:37:38 +01:00
|
|
|
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
|
2011-02-28 04:20:16 +01:00
|
|
|
loop->set_line(*this);
|
1998-11-11 04:13:04 +01:00
|
|
|
return loop;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-05 06:59:10 +01:00
|
|
|
bool PProcess::elaborate(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2011-03-30 08:42:26 +02:00
|
|
|
scope->in_final(type() == IVL_PR_FINAL);
|
2007-03-05 06:59:10 +01:00
|
|
|
NetProc*cur = statement_->elaborate(des, scope);
|
2011-03-30 08:42:26 +02:00
|
|
|
scope->in_final(false);
|
2007-03-05 06:59:10 +01:00
|
|
|
if (cur == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 07:15:49 +02:00
|
|
|
NetProcTop*top=new NetProcTop(scope, type(), cur);
|
2007-03-05 06:59:10 +01:00
|
|
|
ivl_assert(*this, top);
|
|
|
|
|
|
|
|
|
|
// Evaluate the attributes for this process, if there
|
|
|
|
|
// are any. These attributes are to be attached to the
|
|
|
|
|
// NetProcTop object.
|
2012-11-13 03:13:41 +01:00
|
|
|
struct attrib_list_t*attrib_list;
|
2007-03-05 06:59:10 +01:00
|
|
|
unsigned attrib_list_n = 0;
|
|
|
|
|
attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope);
|
|
|
|
|
|
|
|
|
|
for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1)
|
|
|
|
|
top->attribute(attrib_list[adx].key,
|
|
|
|
|
attrib_list[adx].val);
|
|
|
|
|
|
|
|
|
|
delete[]attrib_list;
|
|
|
|
|
|
|
|
|
|
top->set_line(*this);
|
|
|
|
|
des->add_process(top);
|
|
|
|
|
|
|
|
|
|
/* Detect the special case that this is a combinational
|
|
|
|
|
always block. We want to attach an _ivl_schedule_push
|
|
|
|
|
attribute to this process so that it starts up and
|
|
|
|
|
gets into its wait statement before non-combinational
|
|
|
|
|
code is executed. */
|
|
|
|
|
do {
|
2008-10-22 07:15:49 +02:00
|
|
|
if (top->type() != IVL_PR_ALWAYS)
|
2007-03-05 06:59:10 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
NetEvWait*st = dynamic_cast<NetEvWait*>(top->statement());
|
|
|
|
|
if (st == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (st->nevents() != 1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
NetEvent*ev = st->event(0);
|
|
|
|
|
|
|
|
|
|
if (ev->nprobe() == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
bool anyedge_test = true;
|
|
|
|
|
for (unsigned idx = 0 ; anyedge_test && (idx<ev->nprobe())
|
|
|
|
|
; idx += 1) {
|
|
|
|
|
const NetEvProbe*pr = ev->probe(idx);
|
|
|
|
|
if (pr->edge() != NetEvProbe::ANYEDGE)
|
|
|
|
|
anyedge_test = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! anyedge_test)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
top->attribute(perm_string::literal("_ivl_schedule_push"),
|
|
|
|
|
verinum(1));
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
uint64_t delay_value[12];
|
|
|
|
|
unsigned ndelays = 0;
|
|
|
|
|
|
2006-09-28 06:35:18 +02:00
|
|
|
/* Do not elaborate specify delay paths if this feature is
|
|
|
|
|
turned off. */
|
2009-06-09 22:12:45 +02:00
|
|
|
if (!gn_specify_blocks_flag) return;
|
2006-09-28 06:35:18 +02:00
|
|
|
|
2007-02-12 02:52:21 +01:00
|
|
|
ivl_assert(*this, conditional || (condition==0));
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
ndelays = delays.size();
|
2009-06-09 22:12:45 +02:00
|
|
|
if (ndelays > 12) ndelays = 12;
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2009-04-14 03:06:17 +02:00
|
|
|
/* Print a warning if we find default and `timescale based
|
|
|
|
|
* delays in the design, since this is likely an error. */
|
|
|
|
|
if (scope->time_from_timescale()) dly_used_timescale = true;
|
|
|
|
|
else dly_used_no_timescale = true;
|
|
|
|
|
|
|
|
|
|
if (display_ts_dly_warning &&
|
|
|
|
|
dly_used_no_timescale && dly_used_timescale) {
|
|
|
|
|
cerr << "warning: Found both default and "
|
|
|
|
|
"`timescale based delays. Use" << endl;
|
|
|
|
|
cerr << " -Wtimescale to find the "
|
|
|
|
|
"module(s) with no `timescale." << endl;
|
|
|
|
|
display_ts_dly_warning = false;
|
|
|
|
|
}
|
2006-10-03 07:06:00 +02:00
|
|
|
|
|
|
|
|
/* Elaborate the delay values themselves. Remember to scale
|
|
|
|
|
them for the timescale/precision of the scope. */
|
2006-09-23 06:57:19 +02:00
|
|
|
for (unsigned idx = 0 ; idx < ndelays ; idx += 1) {
|
|
|
|
|
PExpr*exp = delays[idx];
|
2011-02-26 23:59:52 +01:00
|
|
|
NetExpr*cur = elab_and_eval(des, scope, exp, -1);
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2010-06-19 01:03:17 +02:00
|
|
|
if (NetEConst*con = dynamic_cast<NetEConst*> (cur)) {
|
|
|
|
|
verinum fn = con->value();
|
|
|
|
|
delay_value[idx] = des->scale_to_precision(fn.as_ulong64(),
|
|
|
|
|
scope);
|
2006-10-03 07:06:00 +02:00
|
|
|
|
2010-06-19 01:03:17 +02:00
|
|
|
} else if (NetECReal*rcon = dynamic_cast<NetECReal*>(cur)) {
|
|
|
|
|
delay_value[idx] = get_scaled_time_from_real(des, scope,
|
|
|
|
|
rcon);
|
2006-10-03 07:06:00 +02:00
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
} else {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Path delay value "
|
2010-06-19 01:03:17 +02:00
|
|
|
<< "must be constant (" << *cur << ")." << endl;
|
2006-09-23 06:57:19 +02:00
|
|
|
delay_value[idx] = 0;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
delete cur;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-19 00:18:27 +02:00
|
|
|
switch (delays.size()) {
|
2006-09-23 06:57:19 +02:00
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
case 6:
|
|
|
|
|
case 12:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Incorrect delay configuration."
|
2008-04-19 00:18:27 +02:00
|
|
|
<< " Given " << delays.size() << " delay expressions." << endl;
|
2006-09-23 06:57:19 +02:00
|
|
|
ndelays = 1;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-01 07:19:38 +01:00
|
|
|
NetNet*condit_sig = 0;
|
2008-04-29 04:00:29 +02:00
|
|
|
if (conditional && condition) {
|
2007-03-01 07:19:38 +01:00
|
|
|
|
|
|
|
|
NetExpr*tmp = elab_and_eval(des, scope, condition, -1);
|
|
|
|
|
ivl_assert(*condition, tmp);
|
|
|
|
|
|
|
|
|
|
// FIXME: Look for constant expressions here?
|
|
|
|
|
|
|
|
|
|
// Get a net form.
|
2008-12-22 22:48:34 +01:00
|
|
|
condit_sig = tmp->synthesize(des, scope, tmp);
|
2007-03-01 07:19:38 +01:00
|
|
|
ivl_assert(*condition, condit_sig);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-08 03:29:27 +01:00
|
|
|
/* A parallel connection does not support more than a one to one
|
|
|
|
|
connection (source/destination). */
|
2011-11-23 04:38:36 +01:00
|
|
|
if (! full_flag_ && ((src.size() != 1) || (dst.size() != 1))) {
|
2011-11-08 03:29:27 +01:00
|
|
|
/* To be compatible with NC-Verilog we allow a parallel connection
|
|
|
|
|
* with multiple sources/destinations if all the paths are only a
|
|
|
|
|
* single bit wide (a scalar or a one bit vector). */
|
|
|
|
|
bool all_single = true;
|
|
|
|
|
typedef std::vector<perm_string>::const_iterator str_vec_iter;
|
|
|
|
|
for (str_vec_iter cur = src.begin();
|
|
|
|
|
( cur != src.end() && all_single); ++ cur) {
|
|
|
|
|
NetNet *psig = scope->find_signal(*cur);
|
|
|
|
|
/* We will report a missing signal as invalid later. For
|
|
|
|
|
* now assume it's a single bit. */
|
|
|
|
|
if (psig == 0) continue;
|
|
|
|
|
if (psig->vector_width() != 1) all_single = false;
|
|
|
|
|
}
|
|
|
|
|
for (str_vec_iter cur = dst.begin();
|
|
|
|
|
( cur != dst.end() && all_single); ++ cur) {
|
|
|
|
|
NetNet *psig = scope->find_signal(*cur);
|
|
|
|
|
/* The same as above for source paths. */
|
|
|
|
|
if (psig == 0) continue;
|
|
|
|
|
if (psig->vector_width() != 1) all_single = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! all_single) {
|
|
|
|
|
cerr << get_fileline() << ": error: Parallel connections "
|
|
|
|
|
"only support one source/destination path found ("
|
|
|
|
|
<< src.size() << "/" << dst.size() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
/* Create all the various paths from the path specifier. */
|
|
|
|
|
typedef std::vector<perm_string>::const_iterator str_vector_iter;
|
|
|
|
|
for (str_vector_iter cur = dst.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != dst.end() ; ++ cur ) {
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Path to " << (*cur);
|
2007-03-01 07:19:38 +01:00
|
|
|
if (condit_sig)
|
|
|
|
|
cerr << " if " << condit_sig->name();
|
2008-04-29 04:00:29 +02:00
|
|
|
else if (conditional)
|
|
|
|
|
cerr << " ifnone";
|
|
|
|
|
cerr << " from ";
|
2006-09-23 06:57:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*dst_sig = scope->find_signal(*cur);
|
|
|
|
|
if (dst_sig == 0) {
|
2011-11-08 03:29:27 +01:00
|
|
|
cerr << get_fileline() << ": error: No wire '"
|
|
|
|
|
<< *cur << "' in this module." << endl;
|
2006-09-23 06:57:19 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 18:17:20 +01:00
|
|
|
unsigned long dst_wid = dst_sig->vector_width();
|
|
|
|
|
|
2007-03-03 06:56:55 +01:00
|
|
|
if (dst_sig->port_type() != NetNet::POUTPUT
|
|
|
|
|
&& dst_sig->port_type() != NetNet::PINOUT) {
|
|
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Path destination "
|
2007-03-03 06:56:55 +01:00
|
|
|
<< *cur << " must be an output or inout port." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
NetDelaySrc*path = new NetDelaySrc(scope, scope->local_symbol(),
|
2008-04-29 04:00:29 +02:00
|
|
|
src.size(), condit_sig,
|
|
|
|
|
conditional);
|
2006-09-23 06:57:19 +02:00
|
|
|
path->set_line(*this);
|
|
|
|
|
|
2007-04-13 04:34:35 +02:00
|
|
|
// The presence of the data_source_expression indicates
|
|
|
|
|
// that this is an edge sensitive path. If so, then set
|
|
|
|
|
// the edges. Note that edge==0 is BOTH edges.
|
|
|
|
|
if (data_source_expression) {
|
|
|
|
|
if (edge >= 0) path->set_posedge();
|
|
|
|
|
if (edge <= 0) path->set_negedge();
|
|
|
|
|
}
|
2007-03-02 07:13:22 +01:00
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
switch (ndelays) {
|
|
|
|
|
case 12:
|
|
|
|
|
path->set_delays(delay_value[0], delay_value[1],
|
|
|
|
|
delay_value[2], delay_value[3],
|
|
|
|
|
delay_value[4], delay_value[5],
|
|
|
|
|
delay_value[6], delay_value[7],
|
|
|
|
|
delay_value[8], delay_value[9],
|
|
|
|
|
delay_value[10], delay_value[11]);
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
path->set_delays(delay_value[0], delay_value[1],
|
|
|
|
|
delay_value[2], delay_value[3],
|
|
|
|
|
delay_value[4], delay_value[5]);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
path->set_delays(delay_value[0], delay_value[1],
|
|
|
|
|
delay_value[2]);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
path->set_delays(delay_value[0], delay_value[1]);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
path->set_delays(delay_value[0]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned idx = 0;
|
|
|
|
|
for (str_vector_iter cur_src = src.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur_src != src.end() ; ++ cur_src ) {
|
2006-09-23 06:57:19 +02:00
|
|
|
NetNet*src_sig = scope->find_signal(*cur_src);
|
2011-11-08 03:29:27 +01:00
|
|
|
if (src_sig == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: No wire '"
|
|
|
|
|
<< *cur_src << "' in this module." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2008-04-29 04:00:29 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
if (cur_src != src.begin()) cerr << " and ";
|
|
|
|
|
cerr << src_sig->name();
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-05 04:21:26 +01:00
|
|
|
if ( (src_sig->port_type() != NetNet::PINPUT)
|
|
|
|
|
&& (src_sig->port_type() != NetNet::PINOUT) ) {
|
2007-03-03 06:56:55 +01:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Path source "
|
2007-03-03 06:56:55 +01:00
|
|
|
<< *cur_src << " must be an input or inout port."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-06 18:17:20 +01:00
|
|
|
// For a parallel connection the source and destination
|
|
|
|
|
// must be the same width.
|
2011-11-23 04:38:36 +01:00
|
|
|
if (! full_flag_) {
|
2011-11-06 18:17:20 +01:00
|
|
|
unsigned long src_wid = src_sig->vector_width();
|
|
|
|
|
if (src_wid != dst_wid) {
|
|
|
|
|
cerr << get_fileline() << ": error: For a "
|
|
|
|
|
"parallel connection the "
|
|
|
|
|
"source/destination width must match "
|
|
|
|
|
"found (" << src_wid << "/" << dst_wid
|
|
|
|
|
<< ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
connect(src_sig->pin(0), path->pin(idx));
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
2008-04-29 04:00:29 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << endl;
|
|
|
|
|
}
|
2006-09-23 06:57:19 +02:00
|
|
|
|
2007-03-01 07:19:38 +01:00
|
|
|
if (condit_sig)
|
|
|
|
|
connect(condit_sig->pin(0), path->pin(idx));
|
|
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
dst_sig->add_delay_path(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-19 06:54:58 +02:00
|
|
|
static void elaborate_functions(Design*des, NetScope*scope,
|
|
|
|
|
const map<perm_string,PFunction*>&funcs)
|
|
|
|
|
{
|
|
|
|
|
typedef map<perm_string,PFunction*>::const_iterator mfunc_it_t;
|
|
|
|
|
for (mfunc_it_t cur = funcs.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != funcs.end() ; ++ cur ) {
|
2008-06-19 06:54:58 +02:00
|
|
|
|
|
|
|
|
hname_t use_name ( (*cur).first );
|
|
|
|
|
NetScope*fscope = scope->child(use_name);
|
|
|
|
|
assert(fscope);
|
|
|
|
|
(*cur).second->elaborate(des, fscope);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void elaborate_tasks(Design*des, NetScope*scope,
|
|
|
|
|
const map<perm_string,PTask*>&tasks)
|
|
|
|
|
{
|
|
|
|
|
typedef map<perm_string,PTask*>::const_iterator mtask_it_t;
|
|
|
|
|
for (mtask_it_t cur = tasks.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != tasks.end() ; ++ cur ) {
|
2008-06-19 06:54:58 +02:00
|
|
|
|
|
|
|
|
hname_t use_name ( (*cur).first );
|
|
|
|
|
NetScope*tscope = scope->child(use_name);
|
|
|
|
|
assert(tscope);
|
|
|
|
|
(*cur).second->elaborate(des, tscope);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-04 05:20:15 +02:00
|
|
|
/*
|
|
|
|
|
* When a module is instantiated, it creates the scope then uses this
|
|
|
|
|
* method to elaborate the contents of the module.
|
|
|
|
|
*/
|
2012-06-04 21:43:33 +02:00
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
bool Module::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-01-25 06:45:56 +01:00
|
|
|
bool result_flag = true;
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
// Elaborate within the generate blocks.
|
|
|
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
|
|
|
|
for (generate_it_t cur = generate_schemes.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != generate_schemes.end() ; ++ cur ) {
|
2007-06-22 04:04:48 +02:00
|
|
|
(*cur)->elaborate(des, scope);
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-08-26 00:22:41 +02:00
|
|
|
// Elaborate functions.
|
2008-06-19 06:54:58 +02:00
|
|
|
elaborate_functions(des, scope, funcs);
|
1999-08-26 00:22:41 +02:00
|
|
|
|
1999-07-03 04:12:51 +02:00
|
|
|
// Elaborate the task definitions. This is done before the
|
|
|
|
|
// behaviors so that task calls may reference these, and after
|
|
|
|
|
// the signals so that the tasks can reference them.
|
2008-06-19 06:54:58 +02:00
|
|
|
elaborate_tasks(des, scope, tasks);
|
1999-07-03 04:12:51 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// Get all the gates of the module and elaborate them by
|
|
|
|
|
// connecting them to the signals. The gate may be simple or
|
|
|
|
|
// complex.
|
|
|
|
|
const list<PGate*>&gl = get_gates();
|
|
|
|
|
|
|
|
|
|
for (list<PGate*>::const_iterator gt = gl.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; gt != gl.end() ; ++ gt ) {
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
(*gt)->elaborate(des, scope);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2002-05-26 03:39:02 +02:00
|
|
|
// Elaborate the behaviors, making processes out of them. This
|
|
|
|
|
// involves scanning the PProcess* list, creating a NetProcTop
|
|
|
|
|
// for each process.
|
2008-03-04 05:49:52 +01:00
|
|
|
result_flag &= elaborate_behaviors_(des, scope);
|
1999-01-25 06:45:56 +01:00
|
|
|
|
2006-09-23 06:57:19 +02:00
|
|
|
// Elaborate the specify paths of the module.
|
|
|
|
|
|
|
|
|
|
for (list<PSpecPath*>::const_iterator sp = specify_paths.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; sp != specify_paths.end() ; ++ sp ) {
|
2006-09-23 06:57:19 +02:00
|
|
|
|
|
|
|
|
(*sp)->elaborate(des, scope);
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
return result_flag;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2007-06-22 04:04:48 +02:00
|
|
|
bool PGenerate::elaborate(Design*des, NetScope*container) const
|
2006-04-10 02:37:42 +02:00
|
|
|
{
|
2008-11-28 04:45:22 +01:00
|
|
|
if (direct_nested_)
|
|
|
|
|
return elaborate_direct_(des, container);
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
|
2012-05-01 01:00:25 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": PGenerate::elaborate: "
|
|
|
|
|
"generate " << scheme_type
|
|
|
|
|
<< " elaborating in scope " << scope_path(container)
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-10 07:19:42 +01:00
|
|
|
// Handle the special case that this is a CASE scheme. In this
|
|
|
|
|
// case the PGenerate itself does not have the generated
|
|
|
|
|
// item. Look instead for the case ITEM that has a scope
|
|
|
|
|
// generated for it.
|
|
|
|
|
if (scheme_type == PGenerate::GS_CASE) {
|
|
|
|
|
|
|
|
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
2008-06-18 06:45:37 +02:00
|
|
|
for (generate_it_t cur = generate_schemes.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != generate_schemes.end() ; ++ cur ) {
|
2008-02-10 07:19:42 +01:00
|
|
|
PGenerate*item = *cur;
|
2008-11-28 04:45:22 +01:00
|
|
|
if (item->direct_nested_ || !item->scope_list_.empty()) {
|
2008-02-10 07:19:42 +01:00
|
|
|
flag &= item->elaborate(des, container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
typedef list<NetScope*>::const_iterator scope_list_it_t;
|
|
|
|
|
for (scope_list_it_t cur = scope_list_.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != scope_list_.end() ; ++ cur ) {
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2007-06-22 04:04:48 +02:00
|
|
|
NetScope*scope = *cur;
|
|
|
|
|
// Check that this scope is one that is contained in the
|
|
|
|
|
// container that the caller passed in.
|
|
|
|
|
if (scope->parent() != container)
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-11-17 19:17:23 +01:00
|
|
|
// If this was an unnamed generate block, replace its
|
|
|
|
|
// temporary name with a name generated using the naming
|
|
|
|
|
// scheme defined in the Verilog-2005 standard.
|
|
|
|
|
const char*name = scope_name.str();
|
|
|
|
|
if (name[0] == '$') {
|
|
|
|
|
if (!scope->auto_name("genblk", '0', name + 4)) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: Couldn't build"
|
2007-11-17 19:17:23 +01:00
|
|
|
<< " unique name for unnamed generate block"
|
|
|
|
|
<< " - using internal name " << name << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-10 02:37:42 +02:00
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate in "
|
2007-06-22 04:04:48 +02:00
|
|
|
<< "scope " << scope_path(scope) << endl;
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2007-06-22 04:04:48 +02:00
|
|
|
flag = elaborate_(des, scope) & flag;
|
2006-04-10 02:37:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-28 04:45:22 +01:00
|
|
|
bool PGenerate::elaborate_direct_(Design*des, NetScope*container) const
|
|
|
|
|
{
|
2012-05-01 01:00:25 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
2008-11-28 04:45:22 +01:00
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Direct nesting elaborate in scope "
|
2012-05-01 01:00:25 +02:00
|
|
|
<< scope_path(container)
|
|
|
|
|
<< ", scheme_type=" << scheme_type << endl;
|
|
|
|
|
}
|
2008-11-28 04:45:22 +01:00
|
|
|
|
|
|
|
|
// Elaborate for a direct nested generated scheme knows
|
|
|
|
|
// that there are only sub_schemes to be elaborated. There
|
|
|
|
|
// should be exactly 1 active generate scheme, search for it
|
|
|
|
|
// using this loop.
|
|
|
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
|
|
|
|
for (generate_it_t cur = generate_schemes.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != generate_schemes.end() ; ++ cur ) {
|
2008-11-28 04:45:22 +01:00
|
|
|
PGenerate*item = *cur;
|
2012-05-01 01:00:25 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": PGenerate::elaborate_direct_: "
|
|
|
|
|
<< "item->scope_name=" << item->scope_name
|
|
|
|
|
<< ", item->scheme_type=" << item->scheme_type
|
|
|
|
|
<< ", item->direct_nested_=" << item->direct_nested_
|
|
|
|
|
<< ", item->scope_list_.size()=" << item->scope_list_.size()
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Special case: If this is a case generate scheme, then
|
|
|
|
|
// the PGenerate object (item) does not acctually
|
|
|
|
|
// contain anything. Instead scan the case items, which
|
|
|
|
|
// are listed as sub-schemes of the item.
|
|
|
|
|
if (item->scheme_type == PGenerate::GS_CASE) {
|
|
|
|
|
for (generate_it_t icur = item->generate_schemes.begin()
|
|
|
|
|
; icur != item->generate_schemes.end() ; ++ icur ) {
|
|
|
|
|
PGenerate*case_item = *icur;
|
|
|
|
|
if (case_item->direct_nested_ || !case_item->scope_list_.empty()) {
|
|
|
|
|
flag &= case_item->elaborate(des, container);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (item->direct_nested_ || !item->scope_list_.empty()) {
|
|
|
|
|
// Found the item, and it is direct nested.
|
|
|
|
|
flag &= item->elaborate(des, container);
|
|
|
|
|
}
|
2008-11-28 04:45:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
bool PGenerate::elaborate_(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2008-06-19 06:54:58 +02:00
|
|
|
elaborate_functions(des, scope, funcs);
|
|
|
|
|
elaborate_tasks(des, scope, tasks);
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
typedef list<PGate*>::const_iterator gates_it_t;
|
2010-10-23 23:57:59 +02:00
|
|
|
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; ++ cur )
|
2007-03-05 06:59:10 +01:00
|
|
|
(*cur)->elaborate(des, scope);
|
2006-04-10 02:37:42 +02:00
|
|
|
|
2007-03-05 06:59:10 +01:00
|
|
|
typedef list<PProcess*>::const_iterator proc_it_t;
|
2010-10-23 23:57:59 +02:00
|
|
|
for (proc_it_t cur = behaviors.begin(); cur != behaviors.end(); ++ cur )
|
2006-04-10 02:37:42 +02:00
|
|
|
(*cur)->elaborate(des, scope);
|
|
|
|
|
|
2007-10-28 13:07:25 +01:00
|
|
|
typedef list<PGenerate*>::const_iterator generate_it_t;
|
2008-06-18 06:45:37 +02:00
|
|
|
for (generate_it_t cur = generate_schemes.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != generate_schemes.end() ; ++ cur ) {
|
2007-10-28 13:07:25 +01:00
|
|
|
(*cur)->elaborate(des, scope);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-04 05:49:52 +01:00
|
|
|
bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
bool result_flag = true;
|
|
|
|
|
|
|
|
|
|
// Elaborate the behaviors, making processes out of them. This
|
|
|
|
|
// involves scanning the PProcess* list, creating a NetProcTop
|
|
|
|
|
// for each process.
|
|
|
|
|
for (list<PProcess*>::const_iterator st = behaviors.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; st != behaviors.end() ; ++ st ) {
|
2008-03-04 05:49:52 +01:00
|
|
|
|
|
|
|
|
result_flag &= (*st)->elaborate(des, scope);
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-22 07:15:49 +02:00
|
|
|
for (list<AProcess*>::const_iterator st = analog_behaviors.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; st != analog_behaviors.end() ; ++ st ) {
|
2008-10-22 07:15:49 +02:00
|
|
|
|
|
|
|
|
result_flag &= (*st)->elaborate(des, scope);
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-04 05:49:52 +01:00
|
|
|
return result_flag;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
struct root_elem {
|
|
|
|
|
Module *mod;
|
|
|
|
|
NetScope *scope;
|
|
|
|
|
};
|
|
|
|
|
|
2013-02-17 23:42:07 +01:00
|
|
|
class elaborate_package_t : public elaborator_work_item_t {
|
|
|
|
|
public:
|
|
|
|
|
elaborate_package_t(Design*d, NetScope*scope, PPackage*p)
|
|
|
|
|
: elaborator_work_item_t(d), scope_(scope), package_(p)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
~elaborate_package_t() { }
|
|
|
|
|
|
|
|
|
|
virtual void elaborate_runrun()
|
|
|
|
|
{
|
|
|
|
|
if (! package_->elaborate_scope(des, scope_))
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
NetScope*scope_;
|
|
|
|
|
PPackage*package_;
|
|
|
|
|
};
|
|
|
|
|
|
2008-06-25 05:28:08 +02:00
|
|
|
class elaborate_root_scope_t : public elaborator_work_item_t {
|
|
|
|
|
public:
|
2008-10-13 18:51:05 +02:00
|
|
|
elaborate_root_scope_t(Design*des__, NetScope*scope, Module*rmod)
|
|
|
|
|
: elaborator_work_item_t(des__), scope_(scope), rmod_(rmod)
|
2008-06-25 05:28:08 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
~elaborate_root_scope_t() { }
|
|
|
|
|
|
|
|
|
|
virtual void elaborate_runrun()
|
|
|
|
|
{
|
2009-08-06 23:42:13 +02:00
|
|
|
Module::replace_t root_repl;
|
|
|
|
|
for (list<Module::named_expr_t>::iterator cur = Module::user_defparms.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != Module::user_defparms.end() ; ++ cur ) {
|
2009-08-06 23:42:13 +02:00
|
|
|
|
|
|
|
|
pform_name_t tmp_name = cur->first;
|
|
|
|
|
if (peek_head_name(tmp_name) != scope_->basename())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
tmp_name.pop_front();
|
|
|
|
|
if (tmp_name.size() != 1)
|
|
|
|
|
continue;
|
|
|
|
|
|
2010-12-05 22:28:17 +01:00
|
|
|
root_repl[peek_head_name(tmp_name)] = cur->second;
|
2009-08-06 23:42:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! rmod_->elaborate_scope(des, scope_, root_repl))
|
2008-06-25 05:28:08 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
NetScope*scope_;
|
|
|
|
|
Module*rmod_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class top_defparams : public elaborator_work_item_t {
|
|
|
|
|
public:
|
2008-10-13 18:51:05 +02:00
|
|
|
top_defparams(Design*des__)
|
|
|
|
|
: elaborator_work_item_t(des__)
|
2008-06-25 05:28:08 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
~top_defparams() { }
|
|
|
|
|
|
|
|
|
|
virtual void elaborate_runrun()
|
|
|
|
|
{
|
2012-05-18 17:07:27 +02:00
|
|
|
if (debug_scopes) {
|
|
|
|
|
cerr << "debug: top_defparams::elaborate_runrun()" << endl;
|
|
|
|
|
}
|
2008-06-25 05:28:08 +02:00
|
|
|
// This method recurses through the scopes, looking for
|
|
|
|
|
// defparam assignments to apply to the parameters in the
|
|
|
|
|
// various scopes. This needs to be done after all the scopes
|
|
|
|
|
// and basic parameters are taken care of because the defparam
|
|
|
|
|
// can assign to a parameter declared *after* it.
|
|
|
|
|
des->run_defparams();
|
|
|
|
|
|
|
|
|
|
// At this point, all parameter overrides are done. Scan the
|
|
|
|
|
// scopes and evaluate the parameters all the way down to
|
|
|
|
|
// constants.
|
|
|
|
|
des->evaluate_parameters();
|
2012-05-18 17:07:27 +02:00
|
|
|
|
|
|
|
|
if (debug_scopes) {
|
|
|
|
|
cerr << "debug: top_defparams::elaborate_runrun() done" << endl;
|
|
|
|
|
}
|
2008-06-25 05:28:08 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
class later_defparams : public elaborator_work_item_t {
|
|
|
|
|
public:
|
2008-10-13 18:51:05 +02:00
|
|
|
later_defparams(Design*des__)
|
|
|
|
|
: elaborator_work_item_t(des__)
|
2008-06-30 03:46:46 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
~later_defparams() { }
|
|
|
|
|
|
|
|
|
|
virtual void elaborate_runrun()
|
|
|
|
|
{
|
2012-05-18 17:07:27 +02:00
|
|
|
if (debug_scopes) {
|
|
|
|
|
cerr << "debug: later_defparams::elaborate_runrun()" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
list<NetScope*>tmp_list;
|
|
|
|
|
for (set<NetScope*>::iterator cur = des->defparams_later.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; cur != des->defparams_later.end() ; ++ cur )
|
2008-06-30 03:46:46 +02:00
|
|
|
tmp_list.push_back(*cur);
|
|
|
|
|
|
|
|
|
|
des->defparams_later.clear();
|
|
|
|
|
|
|
|
|
|
while (! tmp_list.empty()) {
|
|
|
|
|
NetScope*cur = tmp_list.front();
|
|
|
|
|
tmp_list.pop_front();
|
|
|
|
|
cur->run_defparams_later(des);
|
|
|
|
|
}
|
2012-05-18 17:07:27 +02:00
|
|
|
|
|
|
|
|
// The overridden parameters will be evaluated later in
|
|
|
|
|
// a top_defparams work item.
|
|
|
|
|
|
|
|
|
|
if (debug_scopes) {
|
|
|
|
|
cerr << "debuf: later_defparams::elaborate_runrun() done" << endl;
|
|
|
|
|
}
|
2008-06-30 03:46:46 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2011-03-30 08:42:26 +02:00
|
|
|
bool Design::check_proc_delay() const
|
2008-08-29 00:05:19 +02:00
|
|
|
{
|
|
|
|
|
bool result_flag = true;
|
|
|
|
|
|
|
|
|
|
for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) {
|
|
|
|
|
/* If this is an always block and we have no or zero delay then
|
|
|
|
|
* a runtime infinite loop will happen. If we possible have some
|
|
|
|
|
* delay then print a warning that an infinite loop is possible.
|
|
|
|
|
*/
|
2008-10-22 07:15:49 +02:00
|
|
|
if (pr->type() == IVL_PR_ALWAYS) {
|
2008-08-29 00:05:19 +02:00
|
|
|
DelayType dly_type = pr->statement()->delay_type();
|
|
|
|
|
|
|
|
|
|
if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) {
|
|
|
|
|
cerr << pr->get_fileline() << ": error: always"
|
|
|
|
|
<< " statement does not have any delay." << endl;
|
|
|
|
|
cerr << pr->get_fileline() << ": : A runtime"
|
|
|
|
|
<< " infinite loop will occur." << endl;
|
|
|
|
|
result_flag = false;
|
|
|
|
|
|
|
|
|
|
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
|
|
|
|
|
cerr << pr->get_fileline() << ": warning: always"
|
|
|
|
|
<< " statement may not have any delay." << endl;
|
|
|
|
|
cerr << pr->get_fileline() << ": : A runtime"
|
|
|
|
|
<< " infinite loop may be possible." << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-30 08:42:26 +02:00
|
|
|
|
|
|
|
|
/* If this is a final block it must not have a delay,
|
|
|
|
|
but this should have been caught by the statement
|
|
|
|
|
elaboration, so maybe this should be an internal
|
|
|
|
|
error? */
|
|
|
|
|
if (pr->type() == IVL_PR_FINAL) {
|
|
|
|
|
DelayType dly_type = pr->statement()->delay_type();
|
|
|
|
|
|
|
|
|
|
if (dly_type != NO_DELAY && dly_type != ZERO_DELAY) {
|
|
|
|
|
cerr << pr->get_fileline() << ": error: final"
|
|
|
|
|
<< " statement contains a delay." << endl;
|
|
|
|
|
result_flag = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-29 00:05:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result_flag;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-22 03:36:46 +02:00
|
|
|
/*
|
|
|
|
|
* This function is the root of all elaboration. The input is the list
|
|
|
|
|
* of root module names. The function locates the Module definitions
|
|
|
|
|
* for each root, does the whole elaboration sequence, and fills in
|
|
|
|
|
* the resulting Design.
|
|
|
|
|
*/
|
2004-02-18 18:11:54 +01:00
|
|
|
Design* elaborate(list<perm_string>roots)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
2001-10-19 23:53:24 +02:00
|
|
|
svector<root_elem*> root_elems(roots.size());
|
|
|
|
|
bool rc = true;
|
|
|
|
|
unsigned i = 0;
|
1998-12-01 01:42:13 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// This is the output design. I fill it in as I scan the root
|
|
|
|
|
// module and elaborate what I find.
|
|
|
|
|
Design*des = new Design;
|
|
|
|
|
|
2013-02-17 23:42:07 +01:00
|
|
|
// Elaborate the packages. Package elaboration is simpler
|
|
|
|
|
// because there are fewer sub-scopes involved.
|
|
|
|
|
for (map<perm_string,PPackage*>::iterator pac = pform_packages.begin()
|
|
|
|
|
; pac != pform_packages.end() ; ++ pac) {
|
|
|
|
|
|
|
|
|
|
NetScope*scope = des->make_package_scope(pac->first);
|
|
|
|
|
scope->set_line(pac->second);
|
|
|
|
|
|
|
|
|
|
elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second);
|
|
|
|
|
des->elaboration_work_list.push_back(es);
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-22 03:36:46 +02:00
|
|
|
// Scan the root modules by name, and elaborate their scopes.
|
2004-02-18 18:11:54 +01:00
|
|
|
for (list<perm_string>::const_iterator root = roots.begin()
|
2010-10-23 23:57:59 +02:00
|
|
|
; root != roots.end() ; ++ root ) {
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
// Look for the root module in the list.
|
2004-02-18 18:11:54 +01:00
|
|
|
map<perm_string,Module*>::const_iterator mod = pform_modules.find(*root);
|
2001-10-21 01:02:39 +02:00
|
|
|
if (mod == pform_modules.end()) {
|
2001-10-23 01:26:37 +02:00
|
|
|
cerr << "error: Unable to find the root module \""
|
2004-10-04 03:10:51 +02:00
|
|
|
<< (*root) << "\" in the Verilog source." << endl;
|
2001-10-23 01:26:37 +02:00
|
|
|
cerr << " : Perhaps ``-s " << (*root)
|
|
|
|
|
<< "'' is incorrect?" << endl;
|
2001-10-19 23:53:24 +02:00
|
|
|
des->errors++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-10 02:37:42 +02:00
|
|
|
// Get the module definition for this root instance.
|
2001-10-19 23:53:24 +02:00
|
|
|
Module *rmod = (*mod).second;
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2008-08-28 18:01:43 +02:00
|
|
|
// Make the root scope. This makes a NetScope object and
|
2008-06-22 03:36:46 +02:00
|
|
|
// pushes it into the list of root scopes in the Design.
|
2012-05-14 02:48:47 +02:00
|
|
|
NetScope*scope = des->make_root_scope(*root, rmod->program_block);
|
2008-06-22 03:36:46 +02:00
|
|
|
|
|
|
|
|
// Collect some basic properties of this scope from the
|
|
|
|
|
// Module definition.
|
2008-04-30 03:58:25 +02:00
|
|
|
scope->set_line(rmod);
|
2001-10-19 23:53:24 +02:00
|
|
|
scope->time_unit(rmod->time_unit);
|
|
|
|
|
scope->time_precision(rmod->time_precision);
|
2009-04-14 03:06:17 +02:00
|
|
|
scope->time_from_timescale(rmod->time_from_timescale);
|
2001-10-19 23:53:24 +02:00
|
|
|
des->set_precision(rmod->time_precision);
|
2006-03-30 03:49:07 +02:00
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
|
2008-08-28 18:01:43 +02:00
|
|
|
// Save this scope, along with its definition, in the
|
2008-06-22 03:36:46 +02:00
|
|
|
// "root_elems" list for later passes.
|
2001-10-19 23:53:24 +02:00
|
|
|
struct root_elem *r = new struct root_elem;
|
|
|
|
|
r->mod = rmod;
|
|
|
|
|
r->scope = scope;
|
|
|
|
|
root_elems[i++] = r;
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2008-06-25 05:28:08 +02:00
|
|
|
// Arrange for these scopes to be elaborated as root
|
|
|
|
|
// scopes. Create an "elaborate_root_scope" object to
|
|
|
|
|
// contain the work item, and append it to the scope
|
|
|
|
|
// elaborations work list.
|
|
|
|
|
elaborator_work_item_t*es = new elaborate_root_scope_t(des, scope, rmod);
|
|
|
|
|
des->elaboration_work_list.push_back(es);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the work list of scope elaborations until the list is
|
|
|
|
|
// empty. This list is initially populated above where the
|
|
|
|
|
// initial root scopes are primed.
|
|
|
|
|
while (! des->elaboration_work_list.empty()) {
|
2009-12-06 16:56:02 +01:00
|
|
|
// Push a work item to process the defparams of any scopes
|
|
|
|
|
// that are elaborated during this pass. For the first pass
|
|
|
|
|
// this will be all the root scopes. For subsequent passes
|
|
|
|
|
// it will be any scopes created during the previous pass
|
|
|
|
|
// by a generate construct or instance array.
|
|
|
|
|
des->elaboration_work_list.push_back(new top_defparams(des));
|
|
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
// Transfer the queue to a temporary queue.
|
|
|
|
|
list<elaborator_work_item_t*> cur_queue;
|
|
|
|
|
while (! des->elaboration_work_list.empty()) {
|
|
|
|
|
cur_queue.push_back(des->elaboration_work_list.front());
|
|
|
|
|
des->elaboration_work_list.pop_front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run from the temporary queue. If the temporary queue
|
|
|
|
|
// items create new work queue items, they will show up
|
|
|
|
|
// in the elaboration_work_list and then we get to run
|
|
|
|
|
// through them in the next pass.
|
|
|
|
|
while (! cur_queue.empty()) {
|
|
|
|
|
elaborator_work_item_t*tmp = cur_queue.front();
|
|
|
|
|
cur_queue.pop_front();
|
|
|
|
|
tmp->elaborate_runrun();
|
|
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! des->elaboration_work_list.empty()) {
|
|
|
|
|
des->elaboration_work_list.push_back(new later_defparams(des));
|
|
|
|
|
}
|
2008-06-22 03:36:46 +02:00
|
|
|
}
|
|
|
|
|
|
2008-06-30 03:46:46 +02:00
|
|
|
// Look for residual defparams (that point to a non-existent
|
|
|
|
|
// scope) and clean them out.
|
|
|
|
|
des->residual_defparams();
|
|
|
|
|
|
2001-10-31 04:22:31 +01:00
|
|
|
// Errors already? Probably missing root modules. Just give up
|
|
|
|
|
// now and return nothing.
|
2003-09-25 02:25:14 +02:00
|
|
|
if (des->errors > 0)
|
|
|
|
|
return des;
|
2001-10-31 04:22:31 +01:00
|
|
|
|
2001-10-22 04:05:20 +02:00
|
|
|
// With the parameters evaluated down to constants, we have
|
|
|
|
|
// what we need to elaborate signals and memories. This pass
|
|
|
|
|
// creates all the NetNet and NetMemory objects for declared
|
|
|
|
|
// objects.
|
2001-10-19 23:53:24 +02:00
|
|
|
for (i = 0; i < root_elems.count(); i++) {
|
2012-06-04 21:43:33 +02:00
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
Module *rmod = root_elems[i]->mod;
|
|
|
|
|
NetScope *scope = root_elems[i]->scope;
|
2012-06-04 21:43:33 +02:00
|
|
|
scope->set_num_ports( rmod->port_count() );
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << "<toplevel>" << ": debug: " << rmod->mod_name()
|
|
|
|
|
<< ": port elaboration root "
|
|
|
|
|
<< rmod->port_count() << " ports" << endl;
|
|
|
|
|
}
|
2000-03-10 07:20:48 +01:00
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
if (! rmod->elaborate_sig(des, scope)) {
|
2012-06-04 21:43:33 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << "<toplevel>" << ": debug: " << rmod->mod_name()
|
|
|
|
|
<< ": elaborate_sig failed!!!" << endl;
|
|
|
|
|
}
|
2001-10-19 23:53:24 +02:00
|
|
|
delete des;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-03-21 22:29:20 +01:00
|
|
|
|
|
|
|
|
// Some of the generators need to have the ports correctly
|
|
|
|
|
// defined for the root modules. This code does that.
|
|
|
|
|
for (unsigned idx = 0; idx < rmod->port_count(); idx += 1) {
|
|
|
|
|
vector<PEIdent*> mport = rmod->get_port(idx);
|
2012-06-04 21:43:33 +02:00
|
|
|
unsigned int prt_vector_width = 0;
|
|
|
|
|
PortType::Enum ptype = PortType::PIMPLICIT;
|
2011-03-21 22:29:20 +01:00
|
|
|
for (unsigned pin = 0; pin < mport.size(); pin += 1) {
|
2011-04-15 23:44:05 +02:00
|
|
|
// This really does more than we need and adds extra
|
2011-03-21 22:29:20 +01:00
|
|
|
// stuff to the design that should be cleaned later.
|
2012-06-04 21:43:33 +02:00
|
|
|
NetNet *netnet = mport[pin]->elaborate_subport(des, scope);
|
2012-08-08 22:33:27 +02:00
|
|
|
if (netnet != 0) {
|
2012-06-04 21:43:33 +02:00
|
|
|
// Elaboration may actually fail with erroneous input source
|
|
|
|
|
prt_vector_width += netnet->vector_width();
|
|
|
|
|
ptype = PortType::merged(netnet->port_type(), ptype);
|
|
|
|
|
}
|
2011-03-21 22:29:20 +01:00
|
|
|
}
|
2012-06-04 21:43:33 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << "<toplevel>" << ": debug: " << rmod->mod_name()
|
|
|
|
|
<< ": adding module port "
|
|
|
|
|
<< rmod->get_port_name(idx) << endl;
|
|
|
|
|
}
|
|
|
|
|
scope->add_module_port_info(idx, rmod->get_port_name(idx), ptype, prt_vector_width );
|
2011-03-21 22:29:20 +01:00
|
|
|
}
|
2001-10-22 04:05:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that the structure and parameters are taken care of,
|
|
|
|
|
// run through the pform again and generate the full netlist.
|
|
|
|
|
for (i = 0; i < root_elems.count(); i++) {
|
|
|
|
|
Module *rmod = root_elems[i]->mod;
|
|
|
|
|
NetScope *scope = root_elems[i]->scope;
|
|
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
rc &= rmod->elaborate(des, scope);
|
2009-06-09 22:12:45 +02:00
|
|
|
delete root_elems[i];
|
2000-05-02 18:27:38 +02:00
|
|
|
}
|
|
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
if (rc == false) {
|
2008-08-29 00:05:19 +02:00
|
|
|
delete des;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that everything is fully elaborated verify that we do
|
2011-03-30 08:42:26 +02:00
|
|
|
// not have an always block with no delay (an infinite loop),
|
|
|
|
|
// or a final block with a delay.
|
|
|
|
|
if (des->check_proc_delay() == false) {
|
1999-01-25 06:45:56 +01:00
|
|
|
delete des;
|
|
|
|
|
des = 0;
|
|
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
|
2012-06-04 21:43:33 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << "<toplevel>" << ": debug: "
|
|
|
|
|
<< " finishing with "
|
|
|
|
|
<< des->find_root_scopes().size() << " root scopes " << endl;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
return des;
|
|
|
|
|
}
|