1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2003-02-08 20:49:21 +01:00
|
|
|
* Copyright (c) 1998-2003 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
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2003-09-04 22:28:05 +02:00
|
|
|
#ident "$Id: elaborate.cc,v 1.287 2003/09/04 20:28:05 steve Exp $"
|
1998-11-04 00:28:49 +01:00
|
|
|
#endif
|
|
|
|
|
|
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>
|
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"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "netlist.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"
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
|
2000-05-07 06:37:55 +02:00
|
|
|
static Link::strength_t drive_type(PGate::strength_t drv)
|
|
|
|
|
{
|
|
|
|
|
switch (drv) {
|
|
|
|
|
case PGate::HIGHZ:
|
|
|
|
|
return Link::HIGHZ;
|
|
|
|
|
case PGate::WEAK:
|
|
|
|
|
return Link::WEAK;
|
|
|
|
|
case PGate::PULL:
|
|
|
|
|
return Link::PULL;
|
|
|
|
|
case PGate::STRONG:
|
|
|
|
|
return Link::STRONG;
|
|
|
|
|
case PGate::SUPPLY:
|
|
|
|
|
return Link::SUPPLY;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
return Link::STRONG;
|
|
|
|
|
}
|
2000-04-28 18:50:53 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGate::elaborate(Design*des, NetScope*scope) 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);
|
|
|
|
|
|
1999-08-01 23:18:55 +02:00
|
|
|
unsigned long 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 23:18:55 +02:00
|
|
|
|
2000-05-07 06:37:55 +02:00
|
|
|
Link::strength_t drive0 = drive_type(strength0());
|
|
|
|
|
Link::strength_t drive1 = drive_type(strength1());
|
|
|
|
|
|
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. */
|
2001-11-07 05:26:46 +01:00
|
|
|
NetNet*lval = pin(0)->elaborate_lnet(des, scope);
|
1999-05-20 06:31:45 +02:00
|
|
|
if (lval == 0) {
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
|
2000-05-08 07:28:29 +02:00
|
|
|
/* Handle the special case that the rval is simply an
|
|
|
|
|
identifier. Get the rval as a NetNet, then use NetBUFZ
|
|
|
|
|
objects to connect it to the l-value. This is necessary to
|
|
|
|
|
direct drivers. This is how I attach strengths to the
|
|
|
|
|
assignment operation. */
|
|
|
|
|
if (const PEIdent*id = dynamic_cast<const PEIdent*>(pin(1))) {
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*rid = id->elaborate_net(des, scope, lval->pin_count(),
|
2000-05-08 07:28:29 +02:00
|
|
|
0, 0, 0, Link::STRONG,
|
|
|
|
|
Link::STRONG);
|
2001-05-17 05:35:22 +02:00
|
|
|
if (rid == 0) {
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-08 07:28:29 +02:00
|
|
|
assert(rid);
|
2000-07-14 08:12:56 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If the right hand net is the same type as the left
|
2003-01-27 06:09:17 +01:00
|
|
|
side net (i.e., WIRE/WIRE) then it is enough to just
|
2000-07-14 08:12:56 +02:00
|
|
|
connect them together. Otherwise, put a bufz between
|
2000-09-07 03:29:44 +02:00
|
|
|
them to carry strengths from the rval.
|
2000-07-14 08:12:56 +02:00
|
|
|
|
2000-09-07 03:29:44 +02:00
|
|
|
While we are at it, handle the case where the r-value
|
2003-08-28 06:11:17 +02:00
|
|
|
is not as wide as the l-value by padding with a
|
2000-09-07 03:29:44 +02:00
|
|
|
constant-0. */
|
|
|
|
|
|
|
|
|
|
unsigned cnt = lval->pin_count();
|
|
|
|
|
if (rid->pin_count() < cnt)
|
|
|
|
|
cnt = rid->pin_count();
|
|
|
|
|
|
2002-07-18 04:06:37 +02:00
|
|
|
bool need_driver_flag = false;
|
|
|
|
|
|
|
|
|
|
/* If the device is linked to itself, a driver is
|
|
|
|
|
needed. Should I print a warning here? */
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
|
|
|
|
if (lval->pin(idx) .is_linked (rid->pin(idx))) {
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
break;
|
2002-07-18 02:24:22 +02:00
|
|
|
}
|
2002-07-18 04:06:37 +02:00
|
|
|
}
|
|
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
/* If the nets are different type (i.e., reg vs tri) then
|
2002-07-18 04:06:37 +02:00
|
|
|
a driver is needed. */
|
|
|
|
|
if (rid->type() != lval->type())
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
|
|
|
|
|
/* If there is a delay, then I need a driver to carry
|
|
|
|
|
it. */
|
|
|
|
|
if (rise_time || fall_time || decay_time)
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
|
|
|
|
|
/* If there is a strength to be carried, then I need a
|
|
|
|
|
driver to carry that strength. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
|
|
|
|
|
if (rid->pin(idx).drive0() != drive0) {
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (rid->pin(idx).drive1() != drive1) {
|
|
|
|
|
need_driver_flag = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! need_driver_flag) {
|
|
|
|
|
/* Don't need a driver, presumably because the
|
|
|
|
|
r-value already has the needed drivers. Just
|
2003-03-29 06:51:25 +01:00
|
|
|
hook things up. If the r-value is too narrow
|
|
|
|
|
for the l-value, then sign extend it or zero
|
|
|
|
|
extend it, whichever makes sense. */
|
2002-07-18 04:06:37 +02:00
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < cnt; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), rid->pin(idx));
|
2000-09-07 03:29:44 +02:00
|
|
|
|
|
|
|
|
if (cnt < lval->pin_count()) {
|
2003-03-29 06:51:25 +01:00
|
|
|
if (lval->get_signed() && rid->get_signed()) {
|
|
|
|
|
for (idx = cnt
|
|
|
|
|
; idx < lval->pin_count()
|
|
|
|
|
; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), rid->pin(cnt-1));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
verinum tmpv (0UL, lval->pin_count()-cnt);
|
|
|
|
|
NetConst*tmp = new NetConst(scope,
|
|
|
|
|
scope->local_symbol(),
|
|
|
|
|
tmpv);
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
for (idx = cnt
|
|
|
|
|
; idx < lval->pin_count()
|
|
|
|
|
; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), tmp->pin(idx-cnt));
|
|
|
|
|
}
|
2000-07-14 08:12:56 +02:00
|
|
|
}
|
|
|
|
|
|
2000-09-07 03:29:44 +02:00
|
|
|
} else {
|
2002-07-18 04:06:37 +02:00
|
|
|
/* Do need a driver. Use BUFZ objects to carry the
|
|
|
|
|
strength and delays. */
|
2000-09-07 03:29:44 +02:00
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < cnt ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetBUFZ*dev = new NetBUFZ(scope,
|
2003-03-06 01:28:41 +01:00
|
|
|
scope->local_symbol());
|
2000-07-14 08:12:56 +02:00
|
|
|
connect(lval->pin(idx), dev->pin(0));
|
|
|
|
|
connect(rid->pin(idx), dev->pin(1));
|
2000-12-10 07:41:59 +01:00
|
|
|
dev->rise_time(rise_time);
|
|
|
|
|
dev->fall_time(fall_time);
|
|
|
|
|
dev->decay_time(decay_time);
|
2000-07-14 08:12:56 +02:00
|
|
|
dev->pin(0).drive0(drive0);
|
|
|
|
|
dev->pin(0).drive1(drive1);
|
|
|
|
|
des->add_node(dev);
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-07 03:29:44 +02:00
|
|
|
if (cnt < lval->pin_count()) {
|
2003-03-29 06:51:25 +01:00
|
|
|
if (lval->get_signed() && rid->get_signed()) {
|
|
|
|
|
for (idx = cnt
|
|
|
|
|
; idx < lval->pin_count()
|
|
|
|
|
; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), lval->pin(cnt-1));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
NetConst*dev = new NetConst(scope,
|
|
|
|
|
scope->local_symbol(),
|
|
|
|
|
verinum::V0);
|
2000-09-07 03:29:44 +02:00
|
|
|
|
2003-03-29 06:51:25 +01:00
|
|
|
des->add_node(dev);
|
|
|
|
|
dev->pin(0).drive0(drive0);
|
|
|
|
|
dev->pin(0).drive1(drive1);
|
|
|
|
|
for (idx = cnt
|
|
|
|
|
; idx < lval->pin_count()
|
|
|
|
|
; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), dev->pin(0));
|
|
|
|
|
}
|
2000-09-07 03:29:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-08 07:28:29 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
/* Elaborate the r-value. Account for the initial decays,
|
|
|
|
|
which are going to be attached to the last gate before the
|
|
|
|
|
generated NetNet. */
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*rval = pin(1)->elaborate_net(des, scope,
|
1999-10-31 05:11:27 +01:00
|
|
|
lval->pin_count(),
|
2000-05-07 06:37:55 +02:00
|
|
|
rise_time, fall_time, decay_time,
|
|
|
|
|
drive0, drive1);
|
1999-05-20 06:31:45 +02:00
|
|
|
if (rval == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Unable to elaborate r-value: "
|
|
|
|
|
<< *pin(1) << endl;
|
1999-05-20 06:31:45 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
assert(lval && rval);
|
|
|
|
|
|
2001-11-05 00:12:29 +01:00
|
|
|
|
|
|
|
|
/* If the r-value insists on being smaller then the l-value
|
|
|
|
|
(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. */
|
|
|
|
|
if (lval->pin_count() > rval->pin_count())
|
|
|
|
|
rval = pad_to_width(des, rval, lval->pin_count());
|
1999-06-13 01:16:37 +02:00
|
|
|
|
1999-10-08 19:27:23 +02:00
|
|
|
for (unsigned idx = 0 ; idx < lval->pin_count() ; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), rval->pin(idx));
|
|
|
|
|
|
|
|
|
|
if (lval->local_flag())
|
|
|
|
|
delete lval;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
/*
|
|
|
|
|
* Elaborate a Builtin gate. These normally get translated into
|
|
|
|
|
* NetLogic nodes that reflect the particular logic function.
|
|
|
|
|
*/
|
2001-11-22 07:20:59 +01:00
|
|
|
void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-02-15 03:06:15 +01:00
|
|
|
unsigned count = 1;
|
1999-08-08 22:06:06 +02:00
|
|
|
unsigned low = 0, high = 0;
|
1998-11-09 19:55:33 +01:00
|
|
|
string name = get_name();
|
2000-10-07 21:45:42 +02:00
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
if (name == "")
|
2003-03-06 01:28:41 +01:00
|
|
|
name = scope->local_symbol();
|
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
|
1999-02-15 03:06:15 +01:00
|
|
|
gates, then I am expected to make more then one
|
|
|
|
|
gate. Figure out how many are desired. */
|
|
|
|
|
if (msb_) {
|
2001-11-07 05:01:59 +01:00
|
|
|
verinum*msb = msb_->eval_const(des, scope);
|
|
|
|
|
verinum*lsb = lsb_->eval_const(des, scope);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
|
|
|
|
if (msb == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Unable to evaluate "
|
|
|
|
|
"expression " << *msb_ << endl;
|
1999-02-15 03:06:15 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lsb == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Unable to evaluate "
|
|
|
|
|
"expression " << *lsb_ << endl;
|
1999-02-15 03:06:15 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
|
2003-01-30 17:23:07 +01:00
|
|
|
/* Allocate all the netlist nodes for the gates. */
|
1999-02-15 03:06:15 +01:00
|
|
|
NetLogic**cur = new NetLogic*[count];
|
1998-11-04 00:28:49 +01:00
|
|
|
assert(cur);
|
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. */
|
|
|
|
|
|
|
|
|
|
unsigned long 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
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
struct attrib_list_t*attrib_list = 0;
|
|
|
|
|
unsigned attrib_list_n = 0;
|
|
|
|
|
attrib_list = evaluate_attributes(attributes, attrib_list_n,
|
|
|
|
|
des, scope);
|
|
|
|
|
|
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. */
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
for (unsigned idx = 0 ; idx < count ; idx += 1) {
|
2003-01-14 22:16:18 +01:00
|
|
|
ostringstream tmp;
|
1999-02-15 03:06:15 +01:00
|
|
|
unsigned index;
|
|
|
|
|
if (low < high)
|
|
|
|
|
index = low + idx;
|
|
|
|
|
else
|
|
|
|
|
index = low - idx;
|
|
|
|
|
|
2003-01-14 22:16:18 +01:00
|
|
|
tmp << name << "<" << index << ">";
|
1999-02-15 03:06:15 +01:00
|
|
|
const string inm = tmp.str();
|
|
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case AND:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::AND);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case BUF:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::BUF);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case BUFIF0:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::BUFIF0);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case BUFIF1:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::BUFIF1);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case NAND:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NAND);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
2000-11-11 02:52:09 +01:00
|
|
|
case NMOS:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NMOS);
|
|
|
|
|
break;
|
1999-02-15 03:06:15 +01:00
|
|
|
case NOR:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NOR);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case NOT:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NOT);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
2000-11-11 02:52:09 +01:00
|
|
|
case NOTIF0:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NOTIF0);
|
|
|
|
|
break;
|
|
|
|
|
case NOTIF1:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::NOTIF1);
|
|
|
|
|
break;
|
1999-02-15 03:06:15 +01:00
|
|
|
case OR:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::OR);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
2000-11-11 02:52:09 +01:00
|
|
|
case RNMOS:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::RNMOS);
|
|
|
|
|
break;
|
|
|
|
|
case RPMOS:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::RPMOS);
|
|
|
|
|
break;
|
|
|
|
|
case PMOS:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::PMOS);
|
|
|
|
|
break;
|
2001-04-29 22:19:10 +02:00
|
|
|
case PULLDOWN:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::PULLDOWN);
|
|
|
|
|
break;
|
|
|
|
|
case PULLUP:
|
|
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::PULLUP);
|
|
|
|
|
break;
|
1999-02-15 03:06:15 +01:00
|
|
|
case XNOR:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::XNOR);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
|
|
|
|
case XOR:
|
2000-10-07 21:45:42 +02:00
|
|
|
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
|
|
|
|
NetLogic::XOR);
|
1999-02-15 03:06:15 +01:00
|
|
|
break;
|
2000-01-09 06:50:48 +01:00
|
|
|
default:
|
|
|
|
|
cerr << get_line() << ": internal error: unhandled "
|
|
|
|
|
"gate type." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
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);
|
|
|
|
|
|
1999-08-01 18:34:50 +02:00
|
|
|
cur[idx]->rise_time(rise_time);
|
|
|
|
|
cur[idx]->fall_time(fall_time);
|
|
|
|
|
cur[idx]->decay_time(decay_time);
|
|
|
|
|
|
2000-05-08 07:28:29 +02:00
|
|
|
cur[idx]->pin(0).drive0(drive_type(strength0()));
|
|
|
|
|
cur[idx]->pin(0).drive1(drive_type(strength1()));
|
|
|
|
|
|
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) {
|
|
|
|
|
const PExpr*ex = pin(idx);
|
2003-08-05 05:01:58 +02:00
|
|
|
NetNet*sig = (idx == 0)
|
|
|
|
|
? ex->elaborate_lnet(des, scope, true)
|
|
|
|
|
: ex->elaborate_net(des, scope, 0, 0, 0, 0);
|
1999-09-14 03:50:52 +02:00
|
|
|
if (sig == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
assert(sig);
|
1999-02-15 03:06:15 +01:00
|
|
|
|
|
|
|
|
if (sig->pin_count() == 1)
|
|
|
|
|
for (unsigned gdx = 0 ; gdx < count ; gdx += 1)
|
|
|
|
|
connect(cur[gdx]->pin(idx), sig->pin(0));
|
|
|
|
|
|
|
|
|
|
else if (sig->pin_count() == count)
|
|
|
|
|
for (unsigned gdx = 0 ; gdx < count ; gdx += 1)
|
|
|
|
|
connect(cur[gdx]->pin(idx), sig->pin(gdx));
|
|
|
|
|
|
|
|
|
|
else {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Gate count of " <<
|
|
|
|
|
count << " does not match net width of " <<
|
1999-02-15 03:06:15 +01:00
|
|
|
sig->pin_count() << " at pin " << idx << "."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-19 06:20:03 +02:00
|
|
|
if (NetSubnet*tmp = dynamic_cast<NetSubnet*>(sig))
|
1998-11-04 00:28:49 +01:00
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
{
|
1999-12-15 00:42:16 +01:00
|
|
|
// Missing module instance names have already been rejected.
|
1999-08-03 06:14:49 +02:00
|
|
|
assert(get_name() != "");
|
1999-12-15 00:42:16 +01:00
|
|
|
|
2000-02-18 06:15:02 +01:00
|
|
|
if (msb_) {
|
|
|
|
|
cerr << get_line() << ": sorry: Module instantiation arrays "
|
|
|
|
|
"are not yet supported." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
// I know a priori that the elaborate_scope created the scope
|
|
|
|
|
// already, so just look it up as a child of the current scope.
|
|
|
|
|
NetScope*my_scope = scope->child(get_name());
|
|
|
|
|
assert(my_scope);
|
1998-11-21 20:19:44 +01:00
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
const svector<PExpr*>*pins;
|
|
|
|
|
|
|
|
|
|
// 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_) {
|
1999-08-03 06:14:49 +02:00
|
|
|
unsigned nexp = rmod->port_count();
|
1999-05-29 04:36:17 +02:00
|
|
|
svector<PExpr*>*exp = new svector<PExpr*>(nexp);
|
|
|
|
|
|
|
|
|
|
// 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.
|
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) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": 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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-03 06:14:49 +02:00
|
|
|
// 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.
|
1999-05-29 04:36:17 +02:00
|
|
|
if ((*exp)[pidx]) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": 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.
|
|
|
|
|
(*exp)[pidx] = pins_[idx].parm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pins = exp;
|
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
|
|
svector<PExpr*>*tmp = new svector<PExpr*>(rmod->port_count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < rmod->port_count() ; idx += 1)
|
|
|
|
|
(*tmp)[idx] = 0;
|
|
|
|
|
|
|
|
|
|
pins = tmp;
|
|
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
} else {
|
|
|
|
|
|
2001-08-01 07:17:31 +02:00
|
|
|
/* Otherwise, this is a positional list of fort
|
|
|
|
|
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()) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": 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();
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// Elaborate this instance of the module. The recursive
|
|
|
|
|
// elaboration causes the module to generate a netlist with
|
|
|
|
|
// the ports represented by NetNet objects. I will find them
|
|
|
|
|
// later.
|
2000-03-08 05:36:53 +01:00
|
|
|
rmod->elaborate(des, my_scope);
|
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.
|
|
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
for (unsigned idx = 0 ; idx < pins->count() ; idx += 1) {
|
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
|
|
|
|
|
|
|
|
if ((*pins)[idx] == 0) {
|
|
|
|
|
|
|
|
|
|
// While we're here, look to see if this
|
|
|
|
|
// unconnected (from the outside) port is an
|
|
|
|
|
// input. If so, consider printing a port binding
|
|
|
|
|
// warning.
|
|
|
|
|
if (warn_portbinding) {
|
|
|
|
|
svector<PEIdent*> mport = rmod->get_port(idx);
|
|
|
|
|
if (mport.count() == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
NetNet*tmp = des->find_signal(my_scope,
|
|
|
|
|
mport[0]->path());
|
|
|
|
|
assert(tmp);
|
|
|
|
|
|
|
|
|
|
if (tmp->port_type() == NetNet::PINPUT) {
|
|
|
|
|
cerr << get_line() << ": warning: "
|
|
|
|
|
<< "Instantiating module "
|
|
|
|
|
<< rmod->mod_name()
|
|
|
|
|
<< " with dangling input port "
|
|
|
|
|
<< rmod->ports[idx]->name
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
continue;
|
2003-02-22 05:12:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-08-04 04:13:02 +02:00
|
|
|
|
2000-11-05 07:05:59 +01:00
|
|
|
// Inside the module, the port is zero or more signals
|
|
|
|
|
// that were already elaborated. List all those signals
|
2003-01-27 06:09:17 +01:00
|
|
|
// and the NetNet equivalents.
|
2000-05-16 06:05:15 +02:00
|
|
|
svector<PEIdent*> mport = rmod->get_port(idx);
|
1999-08-04 04:13:02 +02:00
|
|
|
svector<NetNet*>prts (mport.count());
|
|
|
|
|
|
2000-11-05 07:05:59 +01:00
|
|
|
// Count the internal pins of the port.
|
1999-08-04 04:13:02 +02:00
|
|
|
unsigned prts_pin_count = 0;
|
|
|
|
|
for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) {
|
2000-05-16 06:05:15 +02:00
|
|
|
PEIdent*pport = mport[ldx];
|
2000-11-05 07:05:59 +01:00
|
|
|
assert(pport);
|
2000-05-16 06:05:15 +02:00
|
|
|
prts[ldx] = pport->elaborate_port(des, my_scope);
|
2000-08-18 06:38:57 +02:00
|
|
|
if (prts[ldx] == 0)
|
2000-05-16 06:05:15 +02:00
|
|
|
continue;
|
2000-08-18 06:38:57 +02:00
|
|
|
|
1999-08-04 04:13:02 +02:00
|
|
|
assert(prts[ldx]);
|
|
|
|
|
prts_pin_count += prts[ldx]->pin_count();
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2000-11-05 07:05:59 +01:00
|
|
|
// If I find that the port in unconnected inside the
|
|
|
|
|
// module, then there is nothing to connect. Skip the
|
2003-01-27 06:09:17 +01:00
|
|
|
// parameter.
|
2000-11-05 07:05:59 +01:00
|
|
|
if (prts_pin_count == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-19 05:43:15 +02:00
|
|
|
// Elaborate the expression that connects to the module
|
|
|
|
|
// port. sig is the thing outside the module that
|
|
|
|
|
// connects to the port.
|
|
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
NetNet*sig;
|
|
|
|
|
if ((prts.count() >= 1)
|
|
|
|
|
&& (prts[0]->port_type() != NetNet::PINPUT)) {
|
|
|
|
|
|
|
|
|
|
sig = (*pins)[idx]->elaborate_lnet(des, scope, true);
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << (*pins)[idx]->get_line() << ": error: "
|
|
|
|
|
<< "Output port expression must support "
|
|
|
|
|
<< "continuous assignment." << endl;
|
2003-04-24 07:25:55 +02:00
|
|
|
cerr << (*pins)[idx]->get_line() << ": : "
|
|
|
|
|
<< "Port of " << rmod->mod_name()
|
|
|
|
|
<< " is " << rmod->ports[idx]->name << endl;
|
2002-11-09 20:20:48 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
sig = (*pins)[idx]->elaborate_net(des, scope,
|
|
|
|
|
prts_pin_count,
|
|
|
|
|
0, 0, 0);
|
|
|
|
|
if (sig == 0) {
|
2003-03-26 07:16:38 +01:00
|
|
|
cerr << (*pins)[idx]->get_line()
|
|
|
|
|
<< ": internal error: Port expression "
|
|
|
|
|
<< "too complicated for elaboration." << endl;
|
2002-11-09 20:20:48 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
1999-10-31 05:11:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
if ((prts.count() >= 1)
|
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
|
|
|
|
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.
|
1999-08-04 04:13:02 +02:00
|
|
|
if (prts_pin_count != sig->pin_count()) {
|
2002-08-01 01:55:38 +02:00
|
|
|
cerr << get_line() << ": warning: Port " << (idx+1)
|
|
|
|
|
<< " (" << rmod->ports[idx]->name << ") of "
|
1999-10-07 07:25:33 +02:00
|
|
|
<< type_ << " expects " << prts_pin_count <<
|
2002-08-01 01:55:38 +02:00
|
|
|
" bits, got " << sig->pin_count() << "." << endl;
|
2001-01-09 06:58:47 +01:00
|
|
|
|
|
|
|
|
if (prts_pin_count > sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": : Leaving "
|
|
|
|
|
<< (prts_pin_count-sig->pin_count())
|
|
|
|
|
<< " high bits of the port unconnected."
|
|
|
|
|
<< endl;
|
|
|
|
|
} else {
|
|
|
|
|
cerr << get_line() << ": : Leaving "
|
|
|
|
|
<< (sig->pin_count()-prts_pin_count)
|
2002-08-01 01:55:38 +02:00
|
|
|
<< " high bits of the expression dangling."
|
2001-01-09 06:58:47 +01:00
|
|
|
<< endl;
|
|
|
|
|
}
|
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
|
|
|
|
|
// is too small, the reduce the number of connects.
|
|
|
|
|
unsigned ccount = prts_pin_count;
|
|
|
|
|
if (sig->pin_count() < ccount)
|
|
|
|
|
ccount = sig->pin_count();
|
|
|
|
|
|
|
|
|
|
// Now scan the concatenation that makes up the port,
|
|
|
|
|
// connecting pins until we run out of port pins or sig
|
|
|
|
|
// pins.
|
|
|
|
|
|
|
|
|
|
unsigned spin = 0;
|
|
|
|
|
for (unsigned ldx = prts.count() ; ldx > 0 ; ldx -= 1) {
|
|
|
|
|
unsigned cnt = prts[ldx-1]->pin_count();
|
|
|
|
|
if (cnt > ccount)
|
|
|
|
|
cnt = ccount;
|
|
|
|
|
for (unsigned p = 0 ; p < cnt ; p += 1) {
|
|
|
|
|
connect(sig->pin(spin), prts[ldx-1]->pin(p));
|
|
|
|
|
ccount -= 1;
|
|
|
|
|
spin += 1;
|
1999-08-04 04:13:02 +02:00
|
|
|
}
|
2001-01-09 06:58:47 +01:00
|
|
|
if (ccount == 0)
|
|
|
|
|
break;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2001-01-09 06:58:47 +01:00
|
|
|
|
2002-06-19 06:20:03 +02:00
|
|
|
if (NetSubnet*tmp = dynamic_cast<NetSubnet*>(sig))
|
1998-11-04 00:28:49 +01:00
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2001-04-29 01:18:08 +02:00
|
|
|
|
|
|
|
|
string my_name = get_name();
|
|
|
|
|
if (my_name == "")
|
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. */
|
|
|
|
|
unsigned long rise_time = 0, fall_time = 0, decay_time = 0;
|
|
|
|
|
if (overrides_) {
|
|
|
|
|
PDelays tmp_del;
|
2001-12-29 21:19:31 +01:00
|
|
|
tmp_del.set_delays(overrides_, false);
|
2001-12-06 06:04:49 +01:00
|
|
|
tmp_del.eval_delays(des, scope, rise_time, fall_time, decay_time);
|
2001-12-06 05:44:11 +01:00
|
|
|
}
|
|
|
|
|
|
2001-12-29 21:19:31 +01:00
|
|
|
|
2001-04-24 04:23:58 +02:00
|
|
|
NetUDP*net = new NetUDP(scope, my_name, udp->ports.count(), udp);
|
2001-12-06 05:44:11 +01:00
|
|
|
net->rise_time(rise_time);
|
|
|
|
|
net->fall_time(fall_time);
|
|
|
|
|
net->decay_time(decay_time);
|
1998-12-01 01:42:13 +01:00
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
struct attrib_list_t*attrib_list = 0;
|
|
|
|
|
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;
|
|
|
|
|
|
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. */
|
1998-12-01 01:42:13 +01:00
|
|
|
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
1998-12-02 05:37:13 +01:00
|
|
|
if (pin(idx) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*sig = pin(idx)->elaborate_net(des, scope, 1, 0, 0, 0);
|
1998-12-01 01:42:13 +01:00
|
|
|
if (sig == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << "internal error: Expression too complicated "
|
|
|
|
|
"for elaboration:" << *pin(idx) << endl;
|
1998-12-01 01:42:13 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect(sig->pin(0), net->pin(idx));
|
|
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
// Delete excess holding signal.
|
2002-06-19 06:20:03 +02:00
|
|
|
if (NetSubnet*tmp = dynamic_cast<NetSubnet*>(sig))
|
1998-12-01 01:42:13 +01:00
|
|
|
delete tmp;
|
|
|
|
|
}
|
2001-04-23 01:09:45 +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
|
|
|
|
|
{
|
|
|
|
|
// Look for the module type
|
2001-10-21 01:02:39 +02:00
|
|
|
map<string,Module*>::const_iterator mod = pform_modules.find(type_);
|
|
|
|
|
if (mod != pform_modules.end())
|
2000-05-02 18:27:38 +02:00
|
|
|
return elaborate_sig_mod_(des, scope, (*mod).second);
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
|
// Look for the module type
|
2001-10-21 01:02:39 +02:00
|
|
|
map<string,Module*>::const_iterator mod = pform_modules.find(type_);
|
|
|
|
|
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
|
2001-10-21 01:02:39 +02:00
|
|
|
map<string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
|
|
|
|
if (udp != pform_primitives.end()) {
|
2001-11-22 07:20:59 +01:00
|
|
|
elaborate_udp_(des, (*udp).second, scope);
|
1998-12-01 01:42:13 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
cerr << get_line() << ": internal error: Unknown module type: " <<
|
|
|
|
|
type_ << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PGModule::elaborate_scope(Design*des, NetScope*sc) const
|
|
|
|
|
{
|
|
|
|
|
// Look for the module type
|
2001-10-21 01:02:39 +02:00
|
|
|
map<string,Module*>::const_iterator mod = pform_modules.find(type_);
|
|
|
|
|
if (mod != pform_modules.end()) {
|
2000-03-08 05:36:53 +01:00
|
|
|
elaborate_scope_mod_(des, (*mod).second, sc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try a primitive type
|
2001-10-21 01:02:39 +02:00
|
|
|
map<string,PUdp*>::const_iterator udp = pform_primitives.find(type_);
|
|
|
|
|
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()) {
|
|
|
|
|
elaborate_scope_mod_(des, (*mod).second, sc);
|
|
|
|
|
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.
|
2000-03-08 05:36:53 +01:00
|
|
|
cerr << get_line() << ": error: Unknown module type: " << type_ << endl;
|
|
|
|
|
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
|
|
|
{
|
2001-11-22 07:20:59 +01:00
|
|
|
cerr << get_line() << ": internal error: elaborate: "
|
|
|
|
|
"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_);
|
2000-09-09 17:21:26 +02:00
|
|
|
return lval_->elaborate_lval(des, scope);
|
1999-06-14 01:51:16 +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)
|
|
|
|
|
{
|
|
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
NetExpr*dex = expr->elaborate_expr(des, scope);
|
|
|
|
|
if (NetExpr*tmp = dex->eval_tree()) {
|
|
|
|
|
delete dex;
|
|
|
|
|
dex = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)) {
|
|
|
|
|
verireal fn = tmp->value();
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
int shift = scope->time_unit() - des->get_precision();
|
2003-02-08 20:49:21 +01:00
|
|
|
long delay = fn.as_long(shift);
|
|
|
|
|
if (delay < 0)
|
|
|
|
|
delay = 0;
|
2002-04-22 00:31:02 +02:00
|
|
|
|
2003-02-08 20:49:21 +01:00
|
|
|
delete tmp;
|
|
|
|
|
return new NetEConst(verinum(delay));
|
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();
|
|
|
|
|
|
|
|
|
|
unsigned long delay =
|
|
|
|
|
des->scale_to_precision(fn.as_ulong(), scope);
|
|
|
|
|
|
|
|
|
|
delete tmp;
|
|
|
|
|
return new NetEConst(verinum(delay));
|
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. */
|
2002-04-22 00:31:02 +02:00
|
|
|
int shift = scope->time_unit() - des->get_precision();
|
|
|
|
|
if (shift > 0) {
|
|
|
|
|
unsigned long scale = 1;
|
|
|
|
|
while (shift > 0) {
|
|
|
|
|
scale *= 10;
|
|
|
|
|
shift -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*scal_val = new NetEConst(verinum(scale));
|
2003-02-08 20:49:21 +01:00
|
|
|
dex = new NetEBMult('*', dex, scal_val);
|
2002-04-22 00:31:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shift < 0) {
|
|
|
|
|
unsigned long scale = 1;
|
|
|
|
|
while (shift < 0) {
|
|
|
|
|
scale *= 10;
|
|
|
|
|
shift += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*scal_val = new NetEConst(verinum(scale));
|
2003-02-08 20:49:21 +01:00
|
|
|
dex = new NetEBDiv('/', dex, scal_val);
|
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
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
/* Elaborate the r-value expression, then try to evaluate it. */
|
1999-11-21 21:03:24 +01:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
assert(rval());
|
|
|
|
|
NetExpr*rv = rval()->elaborate_expr(des, scope);
|
|
|
|
|
if (rv == 0)
|
1999-04-19 03:59:36 +02:00
|
|
|
return 0;
|
1999-09-25 04:57:29 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(rv);
|
|
|
|
|
|
1999-09-22 23:25:42 +02:00
|
|
|
/* Try to evaluate the expression, at least as far as possible. */
|
|
|
|
|
if (NetExpr*tmp = rv->eval_tree()) {
|
|
|
|
|
delete rv;
|
|
|
|
|
rv = tmp;
|
|
|
|
|
}
|
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_) {
|
2001-08-26 01:50:02 +02:00
|
|
|
unsigned wid = lv->lwidth();
|
1999-07-17 20:06:02 +02:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
rv->set_width(wid);
|
|
|
|
|
rv = pad_to_width(rv, wid);
|
1999-09-22 23:25:42 +02:00
|
|
|
|
2003-05-04 22:04:08 +02:00
|
|
|
if (wid > rv->expr_width()) {
|
1999-09-22 23:25:42 +02:00
|
|
|
cerr << get_line() << ": error: Unable to match "
|
|
|
|
|
"expression width of " << rv->expr_width() <<
|
|
|
|
|
" to l-value width of " << wid << "." << endl;
|
1999-07-17 20:06:02 +02:00
|
|
|
//XXXX delete rv;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
NetNet::REG, wid);
|
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... */
|
2003-03-06 01:28:41 +01:00
|
|
|
string n = scope->local_hsymbol();
|
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
|
|
|
|
|
right NetPDelay object. */
|
|
|
|
|
NetProc*st;
|
|
|
|
|
if (event_) {
|
2001-11-22 07:20:59 +01:00
|
|
|
st = event_->elaborate_st(des, scope, a2);
|
1999-09-22 04:00:48 +02:00
|
|
|
if (st == 0) {
|
|
|
|
|
cerr << event_->get_line() << ": error: "
|
|
|
|
|
"unable to elaborate event expression."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(st);
|
|
|
|
|
|
|
|
|
|
} else {
|
2002-04-22 00:31:02 +02:00
|
|
|
NetPDelay*de = new NetPDelay(delay, a2);
|
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);
|
1999-09-22 04:00:48 +02:00
|
|
|
bl->append(st);
|
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
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
/* Based on the specific type of the l-value, do cleanup
|
|
|
|
|
processing on the r-value. */
|
2003-06-21 03:21:42 +02:00
|
|
|
if (lv->var()) {
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2003-06-13 21:10:20 +02:00
|
|
|
} else if (rv->expr_type() == NetExpr::ET_REAL) {
|
|
|
|
|
|
|
|
|
|
// The r-value is a real. Casting will happen in the
|
|
|
|
|
// code generator, so leave it.
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
} else {
|
|
|
|
|
unsigned wid = count_lval_width(lv);
|
|
|
|
|
rv->set_width(wid);
|
|
|
|
|
rv = pad_to_width(rv, wid);
|
|
|
|
|
assert(rv->expr_width() >= wid);
|
1999-06-14 01:51:16 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-06 22:45:38 +02:00
|
|
|
/*
|
|
|
|
|
* The l-value of a procedural assignment is a very much constrained
|
|
|
|
|
* expression. To wit, only identifiers, bit selects and part selects
|
|
|
|
|
* are allowed. I therefore can elaborate the l-value by hand, without
|
|
|
|
|
* the help of recursive elaboration.
|
|
|
|
|
*
|
|
|
|
|
* (For now, this does not yet support concatenation in the l-value.)
|
|
|
|
|
*/
|
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);
|
|
|
|
|
|
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
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(rval());
|
1999-06-06 22:45:38 +02:00
|
|
|
|
2002-08-28 20:54:36 +02:00
|
|
|
NetExpr*rv;
|
|
|
|
|
|
|
|
|
|
/* Evaluate the rval expression if possible, otherwise just
|
|
|
|
|
elaborate it. */
|
|
|
|
|
if (verinum*val = rval()->eval_const(des, scope)) {
|
|
|
|
|
rv = new NetEConst(*val);
|
|
|
|
|
delete val;
|
|
|
|
|
|
2003-06-21 03:21:42 +02:00
|
|
|
} else if ((rv = rval()->elaborate_expr(des, scope))) {
|
2002-08-28 20:54:36 +02:00
|
|
|
|
|
|
|
|
/* OK, go on. */
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Unable to elaborate expression. Retreat. */
|
1999-06-06 22:45:38 +02:00
|
|
|
return 0;
|
2002-08-28 20:54:36 +02:00
|
|
|
}
|
1999-09-25 04:57:29 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(rv);
|
1999-06-06 22:45:38 +02:00
|
|
|
|
2002-12-05 05:15:14 +01:00
|
|
|
/* Try to evaluate the expression, at least as far as possible. */
|
|
|
|
|
if (NetExpr*tmp = rv->eval_tree()) {
|
|
|
|
|
delete rv;
|
|
|
|
|
rv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-20 04:53:14 +02:00
|
|
|
{ unsigned wid = count_lval_width(lv);
|
2000-09-07 02:06:53 +02:00
|
|
|
rv->set_width(wid);
|
|
|
|
|
rv = pad_to_width(rv, wid);
|
1999-06-06 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-22 00:31:02 +02:00
|
|
|
NetExpr*delay = 0;
|
|
|
|
|
if (delay_ != 0)
|
|
|
|
|
delay = elaborate_delay_expr(delay_, des, scope);
|
1999-06-06 22:45:38 +02:00
|
|
|
|
|
|
|
|
/* All done with this node. mark its line number and check it in. */
|
2000-09-03 19:58:35 +02:00
|
|
|
NetAssignNB*cur = new NetAssignNB(lv, rv);
|
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);
|
|
|
|
|
|
1999-09-22 06:30:04 +02:00
|
|
|
NetBlock::Type type = (bl_type_==PBlock::BL_PAR)
|
|
|
|
|
? NetBlock::PARA
|
|
|
|
|
: NetBlock::SEQU;
|
1999-01-25 06:45:56 +01:00
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetScope*nscope = 0;
|
1999-12-15 00:42:16 +01:00
|
|
|
if (name_.length()) {
|
2000-03-08 05:36:53 +01:00
|
|
|
nscope = scope->child(name_);
|
2000-03-11 04:25:51 +01:00
|
|
|
if (nscope == 0) {
|
|
|
|
|
cerr << get_line() << ": internal error: "
|
|
|
|
|
"unable to find block scope " << scope->name()
|
|
|
|
|
<< "<" << name_ << ">" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
assert(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);
|
|
|
|
|
bool fail_flag = false;
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
if ((list_.count() == 1) && (name_.length() == 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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 06:24:18 +02:00
|
|
|
for (unsigned idx = 0 ; idx < list_.count() ; 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);
|
1999-01-25 06:45:56 +01:00
|
|
|
if (tmp == 0) {
|
|
|
|
|
fail_flag = true;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fail_flag) {
|
|
|
|
|
delete cur;
|
|
|
|
|
cur = 0;
|
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);
|
|
|
|
|
|
|
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, scope);
|
1999-06-10 06:03:52 +02:00
|
|
|
if (expr == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Unable to elaborate this case"
|
1999-06-10 06:03:52 +02:00
|
|
|
" expression." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-24 19:40:48 +02:00
|
|
|
/* Try to evaluate the case expression. */
|
|
|
|
|
if (! dynamic_cast<NetEConst*>(expr)) {
|
|
|
|
|
NetExpr*tmp = expr->eval_tree();
|
|
|
|
|
if (tmp != 0) {
|
|
|
|
|
delete expr;
|
|
|
|
|
expr = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
|
|
if (cur->expr.count() == 0)
|
|
|
|
|
icount += 1;
|
|
|
|
|
else
|
|
|
|
|
icount += cur->expr.count();
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
1999-06-15 07:38:39 +02:00
|
|
|
if (cur->expr.count() == 0) {
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
|
|
} else for (unsigned e = 0; e < cur->expr.count(); e += 1) {
|
|
|
|
|
|
|
|
|
|
/* 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.) */
|
|
|
|
|
NetExpr*gu = 0;
|
|
|
|
|
NetProc*st = 0;
|
|
|
|
|
assert(cur->expr[e]);
|
2000-03-08 05:36:53 +01:00
|
|
|
gu = cur->expr[e]->elaborate_expr(des, scope);
|
1999-06-15 07:38:39 +02:00
|
|
|
|
2002-01-19 21:09:56 +01:00
|
|
|
/* Try to evaluate the guard expression down to a
|
|
|
|
|
simple constant. */
|
|
|
|
|
if (! dynamic_cast<NetEConst*>(gu)) {
|
|
|
|
|
NetExpr*tmp = gu->eval_tree();
|
|
|
|
|
if (tmp != 0) {
|
|
|
|
|
delete gu;
|
|
|
|
|
gu = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
1999-06-03 07:16:25 +02:00
|
|
|
// Elaborate and try to evaluate the conditional expression.
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, scope);
|
1999-06-10 06:03:52 +02:00
|
|
|
if (expr == 0) {
|
1999-09-30 00:57:10 +02:00
|
|
|
cerr << get_line() << ": 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
|
|
|
NetExpr*tmp = expr->eval_tree();
|
|
|
|
|
if (tmp) {
|
|
|
|
|
delete expr;
|
|
|
|
|
expr = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
// else_ statement, the use an empty block as a noop.
|
|
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(expr)) {
|
|
|
|
|
verinum val = ce->value();
|
|
|
|
|
delete expr;
|
|
|
|
|
if (val[0] == verinum::V1)
|
2001-11-22 07:20:59 +01:00
|
|
|
return if_->elaborate(des, scope);
|
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
|
|
|
|
1999-09-16 02:33:45 +02:00
|
|
|
// If the condition expression is more then 1 bits, then
|
|
|
|
|
// 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) {
|
|
|
|
|
cerr << get_line() << ": internal error: "
|
|
|
|
|
"incomprehensible expression width (0)." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-07 22:47:13 +01:00
|
|
|
if (expr->expr_width() > 1) {
|
1999-09-16 02:33:45 +02:00
|
|
|
assert(expr->expr_width() > 1);
|
|
|
|
|
verinum zero (verinum::V0, expr->expr_width());
|
|
|
|
|
NetEConst*ezero = new NetEConst(zero);
|
|
|
|
|
ezero->set_width(expr->expr_width());
|
|
|
|
|
NetEBComp*cmp = new NetEBComp('n', expr, ezero);
|
|
|
|
|
expr = cmp;
|
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
|
|
|
{
|
2001-12-03 05:47:14 +01:00
|
|
|
if (path_.peek_name(0)[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);
|
|
|
|
|
|
2002-08-15 04:11:54 +02:00
|
|
|
unsigned parm_count = nparms();
|
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. */
|
|
|
|
|
if ((nparms() == 1) && (parm(0) == 0))
|
|
|
|
|
parm_count = 0;
|
|
|
|
|
|
|
|
|
|
svector<NetExpr*>eparms (parm_count);
|
1999-11-10 03:52:24 +01:00
|
|
|
|
2002-08-15 04:11:54 +02:00
|
|
|
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
PExpr*ex = parm(idx);
|
2002-04-13 04:33:17 +02:00
|
|
|
eparms[idx] = ex? ex->elaborate_expr(des, scope, true) : 0;
|
2002-12-05 05:15:14 +01:00
|
|
|
|
|
|
|
|
/* Attempt to pre-evaluate the parameters. It may be
|
|
|
|
|
possible to at least partially reduce the
|
|
|
|
|
expression. */
|
|
|
|
|
if (eparms[idx] && !dynamic_cast<NetEConst*>(eparms[idx])) {
|
|
|
|
|
NetExpr*tmp = eparms[idx]->eval_tree();
|
|
|
|
|
if (tmp != 0) {
|
|
|
|
|
delete eparms[idx];
|
|
|
|
|
eparms[idx] = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-03 04:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
2001-12-03 05:47:14 +01:00
|
|
|
NetSTask*cur = new NetSTask(path_.peek_name(0), eparms);
|
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);
|
|
|
|
|
|
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) {
|
|
|
|
|
cerr << get_line() << ": 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) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << get_line() << ": internal error: task " << path_
|
2001-10-22 04:05:20 +02:00
|
|
|
<< " doesn't have a definition in " << scope->name()
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(def);
|
2001-07-29 00:13:11 +02:00
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
if (nparms() != def->port_count()) {
|
1999-09-30 23:28:34 +02:00
|
|
|
cerr << get_line() << ": error: Port count mismatch in call to ``"
|
2001-12-03 05:47:14 +01:00
|
|
|
<< path_ << "''." << endl;
|
1999-07-24 04:11:19 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetUTask*cur;
|
|
|
|
|
|
|
|
|
|
/* Handle tasks with no parameters specially. There is no need
|
|
|
|
|
to make a sequential block to hold the generated code. */
|
|
|
|
|
if (nparms() == 0) {
|
2001-04-02 04:28:12 +02:00
|
|
|
cur = new NetUTask(task);
|
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);
|
1999-07-24 04:11:19 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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. */
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
NetNet*port = def->port(idx);
|
|
|
|
|
assert(port->port_type() != NetNet::NOT_A_PORT);
|
|
|
|
|
if (port->port_type() == NetNet::POUTPUT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*rv = parms_[idx]->elaborate_expr(des, scope);
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_*lv = new NetAssign_(port);
|
2000-09-03 01:40:12 +02:00
|
|
|
NetAssign*pr = new NetAssign(lv, rv);
|
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);
|
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. */
|
|
|
|
|
|
1999-07-24 04:11:19 +02:00
|
|
|
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
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]) {
|
|
|
|
|
lv = parms_[idx]->elaborate_lval(des, scope);
|
|
|
|
|
if (lv == 0) {
|
|
|
|
|
cerr << parms_[idx]->get_line() << ": error: "
|
|
|
|
|
<< "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
|
|
|
|
|
|
|
|
NetESignal*sig = new NetESignal(port);
|
|
|
|
|
|
|
|
|
|
/* Generate the assignment statement. */
|
2001-01-10 04:13:23 +01:00
|
|
|
NetAssign*ass = new NetAssign(lv, sig);
|
1999-07-24 21:19:06 +02:00
|
|
|
|
|
|
|
|
block->append(ass);
|
1999-07-24 04:11:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return block;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetCAssign* PCAssign::elaborate(Design*des, NetScope*scope) const
|
2000-05-12 01:37:26 +02:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2000-12-06 07:31:09 +01:00
|
|
|
NetNet*lval = lval_->elaborate_anet(des, scope);
|
2000-05-12 01:37:26 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*rval = expr_->elaborate_net(des, scope, lval->pin_count(),
|
2000-05-12 01:37:26 +02:00
|
|
|
0, 0, 0);
|
|
|
|
|
if (rval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (rval->pin_count() < lval->pin_count())
|
2001-02-15 07:59:35 +01:00
|
|
|
rval = pad_to_width(des, rval, lval->pin_count());
|
2000-05-12 01:37:26 +02:00
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetCAssign* dev = new NetCAssign(scope, scope->local_symbol(), lval);
|
2001-06-27 20:34:43 +02:00
|
|
|
dev->set_line(*this);
|
2000-05-12 01:37:26 +02:00
|
|
|
des->add_node(dev);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1)
|
|
|
|
|
connect(dev->pin(idx), rval->pin(idx));
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2002-01-23 06:56:22 +01:00
|
|
|
NetNet*lval = lval_->elaborate_anet(des, scope);
|
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);
|
|
|
|
|
|
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
|
|
|
|
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_)
|
2003-02-08 20:49:21 +01:00
|
|
|
return new NetPDelay(tmp->value().as_ulong(),
|
|
|
|
|
statement_->elaborate(des, scope));
|
2000-12-10 23:01:35 +01:00
|
|
|
else
|
2003-02-08 20:49:21 +01:00
|
|
|
return new NetPDelay(tmp->value().as_ulong(), 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_)
|
2003-02-08 20:49:21 +01:00
|
|
|
return new NetPDelay(dex, statement_->elaborate(des, scope));
|
2000-07-07 06:53:53 +02:00
|
|
|
else
|
2003-02-08 20:49:21 +01:00
|
|
|
return new NetPDelay(dex, 0);
|
1999-09-30 19:22:33 +02:00
|
|
|
}
|
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);
|
|
|
|
|
|
|
|
|
|
NetScope*target = des->find_scope(scope, scope_);
|
|
|
|
|
if (target == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot find scope "
|
|
|
|
|
<< scope_ << " in " << scope->name() << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (target->type()) {
|
|
|
|
|
case NetScope::FUNC:
|
|
|
|
|
cerr << get_line() << ": error: Cannot disable functions." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case NetScope::MODULE:
|
|
|
|
|
cerr << get_line() << ": error: Cannot disable modules." << endl;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
2000-04-09 18:43:50 +02:00
|
|
|
/* Handle the special case of an event name as an identifier
|
|
|
|
|
in an expression. Make a named event reference. */
|
2000-04-12 06:23:57 +02:00
|
|
|
|
2000-04-09 18:43:50 +02:00
|
|
|
if (expr_.count() == 1) {
|
2000-04-12 06:23:57 +02:00
|
|
|
assert(expr_[0]->expr());
|
2000-04-09 18:43:50 +02:00
|
|
|
PEIdent*id = dynamic_cast<PEIdent*>(expr_[0]->expr());
|
|
|
|
|
NetEvent*ev;
|
2002-07-03 07:34:59 +02:00
|
|
|
if (id && (ev = des->find_event(scope, id->path()))) {
|
2000-04-12 06:23:57 +02:00
|
|
|
NetEvWait*pr = new NetEvWait(enet);
|
|
|
|
|
pr->add_event(ev);
|
2000-04-09 18:43:50 +02:00
|
|
|
pr->set_line(*this);
|
|
|
|
|
return pr;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-01-25 06:45:56 +01:00
|
|
|
|
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. */
|
|
|
|
|
|
2003-03-01 07:25:30 +01:00
|
|
|
NetEvent*ev = new NetEvent(lex_strings.add(scope->local_symbol().c_str()));
|
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);
|
|
|
|
|
NexusSet*nset = enet->nex_input();
|
|
|
|
|
if (nset == 0) {
|
|
|
|
|
cerr << get_line() << ": internal error: No NexusSet"
|
|
|
|
|
<< " from statement." << endl;
|
|
|
|
|
enet->dump(cerr, 6);
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return enet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nset->count() == 0) {
|
|
|
|
|
cerr << get_line() << ": warning: No inputs to statement."
|
|
|
|
|
<< " Ignoring @*." << endl;
|
|
|
|
|
return enet;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
named event, then handle this case all at once at
|
|
|
|
|
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())) {
|
2002-07-03 07:34:59 +02:00
|
|
|
NetEvent*tmp = des->find_event(scope, id->path());
|
2000-04-12 06:23:57 +02:00
|
|
|
if (tmp) {
|
|
|
|
|
wa->add_event(tmp);
|
|
|
|
|
continue;
|
2000-04-09 18:43:50 +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. */
|
|
|
|
|
|
2002-04-22 02:53:39 +02:00
|
|
|
bool save_flag = error_implicit;
|
|
|
|
|
error_implicit = true;
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*expr = expr_[idx]->expr()->elaborate_net(des, scope,
|
1999-10-31 05:11:27 +01:00
|
|
|
0, 0, 0, 0);
|
2002-04-22 02:53:39 +02:00
|
|
|
error_implicit = save_flag;
|
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
|
|
|
|
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:
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
const PExpr *pe = expr_[0]->expr();
|
|
|
|
|
|
|
|
|
|
NetExpr*expr = pe->elaborate_expr(des, scope);
|
|
|
|
|
if (expr == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Unable to elaborate"
|
|
|
|
|
" wait condition expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(expr->expr_width() == 1);
|
|
|
|
|
expr = new NetEBComp('N', expr, new NetEConst(verinum(verinum::V1)));
|
|
|
|
|
NetExpr*tmp = expr->eval_tree();
|
|
|
|
|
if (tmp) {
|
|
|
|
|
delete expr;
|
|
|
|
|
expr = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
if (NetEConst*ce = dynamic_cast<NetEConst*>(expr)) {
|
|
|
|
|
verinum val = ce->value();
|
|
|
|
|
assert(val.len() == 1);
|
|
|
|
|
if (val[0] == verinum::V1) {
|
|
|
|
|
delete expr;
|
|
|
|
|
assert(enet);
|
|
|
|
|
return enet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << get_line() << ": warning: wait expression is "
|
|
|
|
|
<< "constant false." << endl;
|
|
|
|
|
cerr << get_line() << ": : The statement will "
|
|
|
|
|
<< "block permanently." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEvent*wait_event = new NetEvent(lex_strings.add(scope->local_symbol().c_str()));
|
|
|
|
|
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) {
|
|
|
|
|
cerr << get_line() << ": internal error: No NexusSet"
|
|
|
|
|
<< " from wait expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wait_set->count() == 0) {
|
|
|
|
|
cerr << get_line() << ": internal error: Empty NexusSet"
|
|
|
|
|
<< " 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);
|
|
|
|
|
|
|
|
|
|
/* If there is no real substatement (i.e. "wait (foo) ;") then
|
|
|
|
|
we are done. */
|
|
|
|
|
if (enet == 0)
|
|
|
|
|
return loop;
|
|
|
|
|
|
|
|
|
|
/* Create a sequential block to conbine the wait loop and the
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
return proc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc* PForce::elaborate(Design*des, NetScope*scope) const
|
2000-04-22 06:20:19 +02:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*lval = lval_->elaborate_net(des, scope, 0, 0, 0, 0);
|
2000-04-22 06:20:19 +02:00
|
|
|
if (lval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*rval = expr_->elaborate_net(des, scope, lval->pin_count(),
|
2000-04-22 06:20:19 +02:00
|
|
|
0, 0, 0);
|
|
|
|
|
if (rval == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (rval->pin_count() < lval->pin_count())
|
2001-02-15 07:59:35 +01:00
|
|
|
rval = pad_to_width(des, rval, lval->pin_count());
|
2000-04-22 06:20:19 +02:00
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetForce* dev = new NetForce(scope, scope->local_symbol(), lval);
|
2000-04-22 06:20:19 +02:00
|
|
|
des->add_node(dev);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < dev->pin_count() ; idx += 1)
|
|
|
|
|
connect(dev->pin(idx), rval->pin(idx));
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
const PEIdent*id2 = dynamic_cast<const PEIdent*>(name2_);
|
|
|
|
|
assert(id2);
|
|
|
|
|
|
2002-05-27 02:08:45 +02:00
|
|
|
NetBlock*top = new NetBlock(NetBlock::SEQU, 0);
|
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) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << id1->get_line() << ": register ``" << id1->path()
|
1999-06-06 22:45:38 +02:00
|
|
|
<< "'' unknown in this context." << endl;
|
|
|
|
|
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. */
|
|
|
|
|
etmp = expr1_->elaborate_expr(des, scope);
|
|
|
|
|
etmp->set_width(lv->lwidth());
|
|
|
|
|
|
|
|
|
|
NetAssign*init = new NetAssign(lv, etmp);
|
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);
|
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
|
|
|
|
1999-09-18 04:51:35 +02:00
|
|
|
/* Elaborate the increment assignment statement at the end of
|
|
|
|
|
the for loop. This is also a very specific assignment
|
|
|
|
|
statement. Put this into the "body" block. */
|
2001-12-03 05:47:14 +01:00
|
|
|
sig = des->find_signal(scope, id2->path());
|
1998-11-09 19:55:33 +01:00
|
|
|
assert(sig);
|
2001-08-26 01:50:02 +02:00
|
|
|
lv = new NetAssign_(sig);
|
2001-02-07 22:47:13 +01:00
|
|
|
|
|
|
|
|
/* Make the rvalue of the increment expression, and size it
|
|
|
|
|
for the lvalue. */
|
|
|
|
|
etmp = expr2_->elaborate_expr(des, scope);
|
|
|
|
|
etmp->set_width(lv->lwidth());
|
|
|
|
|
NetAssign*step = new NetAssign(lv, etmp);
|
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. */
|
2000-03-08 05:36:53 +01:00
|
|
|
NetExpr*ce = cond_->elaborate_expr(des, scope);
|
1999-10-18 02:02:21 +02:00
|
|
|
if (ce == 0) {
|
|
|
|
|
delete top;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-18 03:53:08 +02:00
|
|
|
if (NetExpr*tmp = ce->eval_tree()) {
|
2001-02-09 06:44:23 +01:00
|
|
|
if (dynamic_cast<NetEConst*>(tmp)) {
|
1999-09-18 03:53:08 +02:00
|
|
|
cerr << get_line() << ": warning: condition expression "
|
2001-02-09 06:44:23 +01:00
|
|
|
"of for-loop is constant." << endl;
|
|
|
|
|
}
|
1999-09-18 03:53:08 +02:00
|
|
|
ce = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* All done, build up the loop. */
|
|
|
|
|
|
|
|
|
|
NetWhile*loop = new NetWhile(ce, body);
|
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
|
|
|
{
|
2001-12-03 05:47:14 +01:00
|
|
|
NetFuncDef*def = scope->func_def();
|
1999-09-01 22:46:19 +02:00
|
|
|
assert(def);
|
|
|
|
|
|
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) {
|
1999-09-30 23:28:34 +02:00
|
|
|
cerr << statement_->get_line() << ": error: Unable to elaborate "
|
2000-03-08 05:36:53 +01:00
|
|
|
"statement in function " << def->name() << "." << endl;
|
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);
|
|
|
|
|
|
2001-11-08 06:15:50 +01:00
|
|
|
NetNet*lval = lval_->elaborate_net(des, scope, 0, 0, 0, 0);
|
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);
|
|
|
|
|
|
|
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, scope);
|
1999-06-19 23:06:16 +02:00
|
|
|
if (expr == 0) {
|
|
|
|
|
cerr << get_line() << ": Unable to elaborate"
|
|
|
|
|
" repeat expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
NetExpr*tmp = expr->eval_tree();
|
|
|
|
|
if (tmp) {
|
|
|
|
|
delete expr;
|
|
|
|
|
expr = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
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)) {
|
|
|
|
|
verinum val = ce->value();
|
|
|
|
|
switch (val.as_ulong()) {
|
|
|
|
|
case 0:
|
|
|
|
|
delete expr;
|
|
|
|
|
delete stat;
|
2002-05-27 02:08:45 +02:00
|
|
|
return new NetBlock(NetBlock::SEQU, 0);
|
1999-06-19 23:06:16 +02:00
|
|
|
case 1:
|
|
|
|
|
delete expr;
|
|
|
|
|
return stat;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetRepeat*proc = new NetRepeat(expr, stat);
|
|
|
|
|
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
|
|
|
{
|
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) {
|
|
|
|
|
cerr << get_line() << ": warning: task has no statement." << endl;
|
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) {
|
|
|
|
|
cerr << statement_->get_line() << ": Unable to elaborate "
|
2001-11-22 07:20:59 +01:00
|
|
|
"statement in task " << task->name()
|
|
|
|
|
<< " at " << get_line() << "." << 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);
|
|
|
|
|
|
2002-07-03 07:34:59 +02:00
|
|
|
NetEvent*ev = des->find_event(scope, event_);
|
2000-04-04 05:20:15 +02:00
|
|
|
if (ev == 0) {
|
|
|
|
|
cerr << get_line() << ": error: event <" << event_ << ">"
|
|
|
|
|
<< " not found." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEvTrig*trig = new NetEvTrig(ev);
|
|
|
|
|
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
|
|
|
{
|
2000-03-08 05:36:53 +01:00
|
|
|
NetWhile*loop = new NetWhile(cond_->elaborate_expr(des, scope),
|
2001-11-22 07:20:59 +01:00
|
|
|
statement_->elaborate(des, scope));
|
1998-11-11 04:13:04 +01:00
|
|
|
return loop;
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
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;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-08-26 00:22:41 +02:00
|
|
|
// Elaborate functions.
|
|
|
|
|
typedef map<string,PFunction*>::const_iterator mfunc_it_t;
|
1999-09-01 22:46:19 +02:00
|
|
|
for (mfunc_it_t cur = funcs_.begin()
|
|
|
|
|
; cur != funcs_.end() ; cur ++) {
|
2000-03-08 05:36:53 +01:00
|
|
|
|
|
|
|
|
NetScope*fscope = scope->child((*cur).first);
|
|
|
|
|
assert(fscope);
|
2000-07-30 20:25:43 +02:00
|
|
|
(*cur).second->elaborate(des, fscope);
|
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.
|
|
|
|
|
typedef map<string,PTask*>::const_iterator mtask_it_t;
|
1999-09-30 23:28:34 +02:00
|
|
|
for (mtask_it_t cur = tasks_.begin()
|
|
|
|
|
; cur != tasks_.end() ; cur ++) {
|
2001-11-22 07:20:59 +01:00
|
|
|
|
|
|
|
|
NetScope*tscope = scope->child((*cur).first);
|
|
|
|
|
assert(tscope);
|
|
|
|
|
(*cur).second->elaborate(des, tscope);
|
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()
|
|
|
|
|
; gt != gl.end()
|
|
|
|
|
; gt ++ ) {
|
|
|
|
|
|
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.
|
1998-11-04 00:28:49 +01:00
|
|
|
const list<PProcess*>&sl = get_behaviors();
|
|
|
|
|
|
|
|
|
|
for (list<PProcess*>::const_iterator st = sl.begin()
|
|
|
|
|
; st != sl.end()
|
|
|
|
|
; st ++ ) {
|
|
|
|
|
|
2001-11-22 07:20:59 +01:00
|
|
|
NetProc*cur = (*st)->statement()->elaborate(des, scope);
|
1999-01-25 06:45:56 +01:00
|
|
|
if (cur == 0) {
|
|
|
|
|
result_flag = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-21 03:21:42 +02:00
|
|
|
NetProcTop*top=NULL;
|
1998-11-04 00:28:49 +01:00
|
|
|
switch ((*st)->type()) {
|
|
|
|
|
case PProcess::PR_INITIAL:
|
2000-10-28 02:51:41 +02:00
|
|
|
top = new NetProcTop(scope, NetProcTop::KINITIAL, cur);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
case PProcess::PR_ALWAYS:
|
2000-10-28 02:51:41 +02:00
|
|
|
top = new NetProcTop(scope, NetProcTop::KALWAYS, cur);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2003-06-21 03:21:42 +02:00
|
|
|
assert(top);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-05-26 03:39:02 +02:00
|
|
|
// Evaluate the attributes for this process, if there
|
|
|
|
|
// are any. These attributes are to be attached to the
|
|
|
|
|
// NetProcTop object.
|
|
|
|
|
struct attrib_list_t*attrib_list = 0;
|
|
|
|
|
unsigned attrib_list_n = 0;
|
|
|
|
|
attrib_list = evaluate_attributes((*st)->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;
|
|
|
|
|
|
1999-02-01 01:26:48 +01:00
|
|
|
top->set_line(*(*st));
|
1998-11-04 00:28:49 +01:00
|
|
|
des->add_process(top);
|
2003-09-04 22:28:05 +02:00
|
|
|
|
|
|
|
|
/* 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 {
|
|
|
|
|
if (top->type() != NetProcTop::KALWAYS)
|
|
|
|
|
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("_ivl_schedule_push", verinum(1));
|
|
|
|
|
} while (0);
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
1999-01-25 06:45:56 +01:00
|
|
|
|
|
|
|
|
return result_flag;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
struct root_elem {
|
|
|
|
|
Module *mod;
|
|
|
|
|
NetScope *scope;
|
|
|
|
|
};
|
|
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
Design* elaborate(list<const char*>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;
|
|
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
for (list<const char*>::const_iterator root = roots.begin()
|
|
|
|
|
; 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.
|
|
|
|
|
map<string,Module*>::const_iterator mod = pform_modules.find(*root);
|
|
|
|
|
if (mod == pform_modules.end()) {
|
2001-10-23 01:26:37 +02:00
|
|
|
cerr << "error: Unable to find the root module \""
|
|
|
|
|
<< (*root) << "\" in the Verilog source." << endl;
|
|
|
|
|
cerr << " : Perhaps ``-s " << (*root)
|
|
|
|
|
<< "'' is incorrect?" << endl;
|
2001-10-19 23:53:24 +02:00
|
|
|
des->errors++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Module *rmod = (*mod).second;
|
|
|
|
|
|
|
|
|
|
// Make the root scope, then scan the pform looking for scopes
|
|
|
|
|
// and parameters.
|
|
|
|
|
NetScope*scope = des->make_root_scope(*root);
|
|
|
|
|
scope->time_unit(rmod->time_unit);
|
|
|
|
|
scope->time_precision(rmod->time_precision);
|
|
|
|
|
des->set_precision(rmod->time_precision);
|
|
|
|
|
if (! rmod->elaborate_scope(des, scope)) {
|
|
|
|
|
delete des;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2001-10-31 04:22:31 +01:00
|
|
|
// Errors already? Probably missing root modules. Just give up
|
|
|
|
|
// now and return nothing.
|
|
|
|
|
if (des->errors > 0) {
|
|
|
|
|
delete des;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-10 07:20:48 +01: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
|
2003-01-27 06:09:17 +01:00
|
|
|
// can assign to a parameter declared *after* it.
|
2000-03-08 05:36:53 +01:00
|
|
|
des->run_defparams();
|
2000-03-10 07:20:48 +01:00
|
|
|
|
|
|
|
|
|
2003-01-30 17:23:07 +01:00
|
|
|
// At this point, all parameter overrides are done. Scan the
|
2000-03-10 07:20:48 +01:00
|
|
|
// scopes and evaluate the parameters all the way down to
|
|
|
|
|
// constants.
|
2000-03-08 05:36:53 +01:00
|
|
|
des->evaluate_parameters();
|
|
|
|
|
|
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++) {
|
|
|
|
|
Module *rmod = root_elems[i]->mod;
|
|
|
|
|
NetScope *scope = root_elems[i]->scope;
|
2000-03-10 07:20:48 +01:00
|
|
|
|
2001-10-19 23:53:24 +02:00
|
|
|
if (! rmod->elaborate_sig(des, scope)) {
|
|
|
|
|
delete des;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
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);
|
2000-05-02 18:27:38 +02:00
|
|
|
}
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
if (rc == false) {
|
|
|
|
|
delete des;
|
|
|
|
|
des = 0;
|
|
|
|
|
}
|
2000-03-08 05:36:53 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
return des;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: elaborate.cc,v $
|
2003-09-04 22:28:05 +02:00
|
|
|
* Revision 1.287 2003/09/04 20:28:05 steve
|
|
|
|
|
* Support time0 resolution of combinational threads.
|
|
|
|
|
*
|
2003-08-28 06:11:17 +02:00
|
|
|
* Revision 1.286 2003/08/28 04:11:17 steve
|
|
|
|
|
* Spelling patch.
|
|
|
|
|
*
|
2003-08-05 05:01:58 +02:00
|
|
|
* Revision 1.285 2003/08/05 03:01:58 steve
|
|
|
|
|
* Primitive outputs have same limitations as continuous assignment.
|
|
|
|
|
*
|
2003-07-02 06:19:16 +02:00
|
|
|
* Revision 1.284 2003/07/02 04:19:16 steve
|
|
|
|
|
* Elide empty begin-end in conditionals.
|
|
|
|
|
*
|
2003-06-21 03:21:42 +02:00
|
|
|
* Revision 1.283 2003/06/21 01:21:43 steve
|
|
|
|
|
* Harmless fixup of warnings.
|
|
|
|
|
*
|
2003-06-13 21:10:20 +02:00
|
|
|
* Revision 1.282 2003/06/13 19:10:20 steve
|
|
|
|
|
* Handle assign of real to vector.
|
|
|
|
|
*
|
2003-05-19 04:50:58 +02:00
|
|
|
* Revision 1.281 2003/05/19 02:50:58 steve
|
|
|
|
|
* Implement the wait statement behaviorally instead of as nets.
|
|
|
|
|
*
|
2003-05-04 22:04:08 +02:00
|
|
|
* Revision 1.280 2003/05/04 20:04:08 steve
|
|
|
|
|
* Fix truncation of signed constant in constant addition.
|
|
|
|
|
*
|
2003-04-24 07:25:55 +02:00
|
|
|
* Revision 1.279 2003/04/24 05:25:55 steve
|
|
|
|
|
* Include port name in port assignment error message.
|
|
|
|
|
*
|
2003-03-29 06:51:25 +01:00
|
|
|
* Revision 1.278 2003/03/29 05:51:25 steve
|
|
|
|
|
* Sign extend NetMult inputs if result is signed.
|
|
|
|
|
*
|
2003-03-26 07:16:38 +01:00
|
|
|
* Revision 1.277 2003/03/26 06:16:38 steve
|
|
|
|
|
* Some better internal error messages.
|
|
|
|
|
*
|
2003-03-06 01:28:41 +01:00
|
|
|
* Revision 1.276 2003/03/06 00:28:41 steve
|
|
|
|
|
* All NetObj objects have lex_string base names.
|
|
|
|
|
*
|
2003-03-01 07:25:30 +01:00
|
|
|
* Revision 1.275 2003/03/01 06:25:30 steve
|
|
|
|
|
* Add the lex_strings string handler, and put
|
|
|
|
|
* scope names and system task/function names
|
|
|
|
|
* into this table. Also, permallocate event
|
|
|
|
|
* names from the beginning.
|
|
|
|
|
*
|
2003-02-22 05:12:49 +01:00
|
|
|
* Revision 1.274 2003/02/22 04:12:49 steve
|
|
|
|
|
* Add the portbind warning.
|
|
|
|
|
*
|
2003-02-08 20:49:21 +01:00
|
|
|
* Revision 1.273 2003/02/08 19:49:21 steve
|
|
|
|
|
* Calculate delay statement delays using elaborated
|
|
|
|
|
* expressions instead of pre-elaborated expression
|
|
|
|
|
* trees.
|
|
|
|
|
*
|
|
|
|
|
* Remove the eval_pexpr methods from PExpr.
|
|
|
|
|
*
|
2003-02-07 03:49:24 +01:00
|
|
|
* Revision 1.272 2003/02/07 02:49:24 steve
|
|
|
|
|
* Rewrite delay statement elaboration of handle real expressions.
|
|
|
|
|
*
|
2003-01-30 17:23:07 +01:00
|
|
|
* Revision 1.271 2003/01/30 16:23:07 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2003-01-27 06:09:17 +01:00
|
|
|
* Revision 1.270 2003/01/27 05:09:17 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2003-01-26 22:15:58 +01:00
|
|
|
* Revision 1.269 2003/01/26 21:15:58 steve
|
|
|
|
|
* Rework expression parsing and elaboration to
|
|
|
|
|
* accommodate real/realtime values and expressions.
|
|
|
|
|
*
|
2003-01-14 22:16:18 +01:00
|
|
|
* Revision 1.268 2003/01/14 21:16:18 steve
|
|
|
|
|
* Move strstream to ostringstream for compatibility.
|
|
|
|
|
*
|
2002-12-21 20:42:17 +01:00
|
|
|
* Revision 1.267 2002/12/21 19:42:17 steve
|
|
|
|
|
* Account for local units in calculated delays.
|
|
|
|
|
*
|
2002-12-05 05:15:14 +01:00
|
|
|
* Revision 1.266 2002/12/05 04:15:14 steve
|
|
|
|
|
* precalculate r-values of nb assignments and task arguments.
|
|
|
|
|
*
|
2002-11-26 04:35:13 +01:00
|
|
|
* Revision 1.265 2002/11/26 03:35:13 steve
|
|
|
|
|
* Do not set width if width is already OK.
|
|
|
|
|
*
|
2002-11-09 20:20:48 +01:00
|
|
|
* Revision 1.264 2002/11/09 19:20:48 steve
|
|
|
|
|
* Port expressions for output ports are lnets, not nets.
|
|
|
|
|
*
|
2002-08-28 20:54:36 +02:00
|
|
|
* Revision 1.263 2002/08/28 18:54:36 steve
|
|
|
|
|
* Evaluate nonblocking assign r-values.
|
|
|
|
|
*
|
2002-08-15 04:11:54 +02:00
|
|
|
* Revision 1.262 2002/08/15 02:11:54 steve
|
|
|
|
|
* Handle special case of empty system task argument list.
|
|
|
|
|
*
|
2002-08-13 07:35:00 +02:00
|
|
|
* Revision 1.261 2002/08/13 05:35:00 steve
|
|
|
|
|
* Do not elide named blocks.
|
|
|
|
|
*
|
2002-08-12 03:34:58 +02:00
|
|
|
* Revision 1.260 2002/08/12 01:34:59 steve
|
|
|
|
|
* conditional ident string using autoconfig.
|
|
|
|
|
*
|
2002-08-01 01:55:38 +02:00
|
|
|
* Revision 1.259 2002/07/31 23:55:38 steve
|
|
|
|
|
* Add port name to pin size error message.
|
|
|
|
|
*
|
2002-07-24 18:22:59 +02:00
|
|
|
* Revision 1.258 2002/07/24 16:22:59 steve
|
|
|
|
|
* Save event matching for nodangle.
|
|
|
|
|
*
|
2002-07-18 04:06:37 +02:00
|
|
|
* Revision 1.257 2002/07/18 02:06:37 steve
|
|
|
|
|
* Need driver for sure in assign feedback and other cases.
|
|
|
|
|
*
|
2002-07-18 02:24:22 +02:00
|
|
|
* Revision 1.256 2002/07/18 00:24:22 steve
|
|
|
|
|
* Careful with assign to self.
|
|
|
|
|
*
|
2002-07-03 07:34:59 +02:00
|
|
|
* Revision 1.255 2002/07/03 05:34:59 steve
|
|
|
|
|
* Fix scope search for events.
|
|
|
|
|
*
|
2002-06-19 06:20:03 +02:00
|
|
|
* Revision 1.254 2002/06/19 04:20:03 steve
|
|
|
|
|
* Remove NetTmp and add NetSubnet class.
|
|
|
|
|
*
|
2002-06-05 05:44:25 +02:00
|
|
|
* Revision 1.253 2002/06/05 03:44:25 steve
|
|
|
|
|
* Add support for memory words in l-value of
|
|
|
|
|
* non-blocking assignments, and remove the special
|
|
|
|
|
* NetAssignMem_ and NetAssignMemNB classes.
|
|
|
|
|
*
|
2002-06-04 07:38:43 +02:00
|
|
|
* Revision 1.252 2002/06/04 05:38:44 steve
|
|
|
|
|
* Add support for memory words in l-value of
|
|
|
|
|
* blocking assignments, and remove the special
|
|
|
|
|
* NetAssignMem class.
|
|
|
|
|
*
|
2002-05-27 02:08:45 +02:00
|
|
|
* Revision 1.251 2002/05/27 00:08:45 steve
|
|
|
|
|
* Support carrying the scope of named begin-end
|
|
|
|
|
* blocks down to the code generator, and have
|
|
|
|
|
* the vvp code generator use that to support disable.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
|