1998-11-04 00:28:49 +01:00
|
|
|
/*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Copyright (c) 1998-2000 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
|
|
|
|
|
*/
|
2000-02-23 03:56:53 +01:00
|
|
|
#if !defined(WINNT) && !defined(macintosh)
|
|
|
|
|
#ident "$Id: elaborate.cc,v 1.145 2000/02/23 02:56:54 steve Exp $"
|
1998-11-04 00:28:49 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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>
|
|
|
|
|
# include <strstream>
|
|
|
|
|
# include "pform.h"
|
|
|
|
|
# include "netlist.h"
|
1999-09-29 02:42:50 +02:00
|
|
|
# include "netmisc.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
string Design::local_symbol(const string&path)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
|
|
|
|
strstream res;
|
1998-12-07 05:53:16 +01:00
|
|
|
res << "_L" << (lcounter_++) << ends;
|
1998-11-04 00:28:49 +01:00
|
|
|
return path + "." + res.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Urff, I don't like this global variable. I *will* figure out a
|
|
|
|
|
// way to get rid of it. But, for now the PGModule::elaborate method
|
|
|
|
|
// needs it to find the module definition.
|
1998-12-01 01:42:13 +01:00
|
|
|
static const map<string,Module*>* modlist = 0;
|
|
|
|
|
static const map<string,PUdp*>* udplist = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate a source wire. The "wire" is the declaration of wires,
|
|
|
|
|
* registers, ports and memories. The parser has already merged the
|
|
|
|
|
* multiple properties of a wire (i.e. "input wire") so come the
|
|
|
|
|
* elaboration this creates an object in the design that represent the
|
|
|
|
|
* defined item.
|
|
|
|
|
*/
|
1999-11-27 20:07:57 +01:00
|
|
|
void PWire::elaborate(Design*des, NetScope*scope) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-11-27 20:07:57 +01:00
|
|
|
const string path = scope->name();
|
1999-06-17 07:34:42 +02:00
|
|
|
NetNet::Type wtype = type_;
|
1998-11-04 00:28:49 +01:00
|
|
|
if (wtype == NetNet::IMPLICIT)
|
|
|
|
|
wtype = NetNet::WIRE;
|
1999-07-24 04:11:19 +02:00
|
|
|
if (wtype == NetNet::IMPLICIT_REG)
|
|
|
|
|
wtype = NetNet::REG;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
unsigned wid = 1;
|
1999-09-13 05:10:59 +02:00
|
|
|
long lsb = 0, msb = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-06-17 07:34:42 +02:00
|
|
|
if (msb_.count()) {
|
|
|
|
|
svector<long>mnum (msb_.count());
|
|
|
|
|
svector<long>lnum (msb_.count());
|
|
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/* There may be multiple declarations of ranges, because
|
|
|
|
|
the symbol may have its range declared in i.e. input
|
|
|
|
|
and reg declarations. Calculate *all* the numbers
|
|
|
|
|
here. I will resolve the values later. */
|
|
|
|
|
|
1999-06-17 07:34:42 +02:00
|
|
|
for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) {
|
|
|
|
|
verinum*mval = msb_[idx]->eval_const(des,path);
|
|
|
|
|
if (mval == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << msb_[idx]->get_line() << ": error: "
|
|
|
|
|
"Unable to evaluate constant expression ``" <<
|
1999-06-17 07:34:42 +02:00
|
|
|
*msb_[idx] << "''." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
verinum*lval = lsb_[idx]->eval_const(des, path);
|
|
|
|
|
if (mval == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << lsb_[idx]->get_line() << ": error: "
|
|
|
|
|
"Unable to evaluate constant expression ``" <<
|
1999-06-17 07:34:42 +02:00
|
|
|
*lsb_[idx] << "''." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mnum[idx] = mval->as_long();
|
|
|
|
|
lnum[idx] = lval->as_long();
|
|
|
|
|
delete mval;
|
|
|
|
|
delete lval;
|
1999-05-10 02:16:57 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/* Make sure all the values for msb and lsb match by
|
|
|
|
|
value. If not, report an error. */
|
1999-06-17 07:34:42 +02:00
|
|
|
for (unsigned idx = 1 ; idx < msb_.count() ; idx += 1) {
|
|
|
|
|
if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Inconsistent width, "
|
1999-06-17 07:34:42 +02:00
|
|
|
"[" << mnum[idx] << ":" << lnum[idx] << "]"
|
|
|
|
|
" vs. [" << mnum[0] << ":" << lnum[0] << "]"
|
|
|
|
|
" for signal ``" << name_ << "''" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
lsb = lnum[0];
|
|
|
|
|
msb = mnum[0];
|
1999-06-17 07:34:42 +02:00
|
|
|
if (mnum[0] > lnum[0])
|
|
|
|
|
wid = mnum[0] - lnum[0] + 1;
|
1998-11-04 00:28:49 +01:00
|
|
|
else
|
1999-06-17 07:34:42 +02:00
|
|
|
wid = lnum[0] - mnum[0] + 1;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-17 07:34:42 +02:00
|
|
|
if (lidx_ || ridx_) {
|
|
|
|
|
assert(lidx_ && ridx_);
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
// If the register has indices, then this is a
|
|
|
|
|
// memory. Create the memory object.
|
1999-06-17 07:34:42 +02:00
|
|
|
verinum*lval = lidx_->eval_const(des, path);
|
1999-04-19 03:59:36 +02:00
|
|
|
assert(lval);
|
1999-06-17 07:34:42 +02:00
|
|
|
verinum*rval = ridx_->eval_const(des, path);
|
1999-04-19 03:59:36 +02:00
|
|
|
assert(rval);
|
|
|
|
|
|
|
|
|
|
long lnum = lval->as_long();
|
|
|
|
|
long rnum = rval->as_long();
|
|
|
|
|
delete lval;
|
|
|
|
|
delete rval;
|
1999-06-17 07:34:42 +02:00
|
|
|
NetMemory*sig = new NetMemory(path+"."+name_, wid, lnum, rnum);
|
1999-04-19 03:59:36 +02:00
|
|
|
sig->set_attributes(attributes);
|
|
|
|
|
des->add_memory(sig);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
1999-11-27 20:07:57 +01:00
|
|
|
NetNet*sig = new NetNet(scope, path + "." + name_, wtype, msb, lsb);
|
1999-06-02 17:38:46 +02:00
|
|
|
sig->set_line(*this);
|
1999-06-17 07:34:42 +02:00
|
|
|
sig->port_type(port_type_);
|
1999-04-19 03:59:36 +02:00
|
|
|
sig->set_attributes(attributes);
|
1999-07-10 05:00:05 +02:00
|
|
|
|
|
|
|
|
verinum::V iv = verinum::Vz;
|
|
|
|
|
if (wtype == NetNet::REG)
|
|
|
|
|
iv = verinum::Vx;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
|
|
|
|
sig->set_ival(idx, iv);
|
|
|
|
|
|
1999-04-19 03:59:36 +02:00
|
|
|
des->add_signal(sig);
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PGate::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
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.
|
|
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
void PGAssign::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-08-01 23:18:55 +02:00
|
|
|
unsigned long rise_time, fall_time, decay_time;
|
|
|
|
|
eval_delays(des, path, rise_time, fall_time, decay_time);
|
|
|
|
|
|
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. */
|
|
|
|
|
NetNet*lval = pin(0)->elaborate_lnet(des, path);
|
1999-05-20 06:31:45 +02:00
|
|
|
if (lval == 0) {
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
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. */
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*rval = pin(1)->elaborate_net(des, path,
|
|
|
|
|
lval->pin_count(),
|
|
|
|
|
rise_time, fall_time, decay_time);
|
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);
|
|
|
|
|
|
1999-10-08 19:27:23 +02:00
|
|
|
if (lval->pin_count() > rval->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": sorry: lval width (" <<
|
1999-10-31 05:11:27 +01:00
|
|
|
lval->pin_count() << ") > rval width (" <<
|
1999-06-13 01:16:37 +02:00
|
|
|
rval->pin_count() << ")." << endl;
|
|
|
|
|
delete lval;
|
|
|
|
|
delete rval;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
void PGBuiltin::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
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();
|
|
|
|
|
if (name == "")
|
1998-12-07 05:53:16 +01:00
|
|
|
name = des->local_symbol(path);
|
2000-02-07 00:13:14 +01:00
|
|
|
else
|
|
|
|
|
name = path+"."+name;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
/* If the verilog source has a range specification for the
|
|
|
|
|
gates, then I am expected to make more then one
|
|
|
|
|
gate. Figure out how many are desired. */
|
|
|
|
|
if (msb_) {
|
1999-05-10 02:16:57 +02:00
|
|
|
verinum*msb = msb_->eval_const(des, path);
|
|
|
|
|
verinum*lsb = lsb_->eval_const(des, path);
|
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
|
|
|
|
|
|
|
|
/* Allocate all the getlist nodes for the gates. */
|
|
|
|
|
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
|
|
|
|
|
impedence. However, the bufif devices can generate
|
|
|
|
|
'bz output, so we will pretend that anything can.
|
|
|
|
|
|
|
|
|
|
If only one delay value expression is given (i.e. #5
|
|
|
|
|
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;
|
1999-08-01 23:18:55 +02:00
|
|
|
eval_delays(des, path, rise_time, fall_time, decay_time);
|
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) {
|
|
|
|
|
strstream tmp;
|
|
|
|
|
unsigned index;
|
|
|
|
|
if (low < high)
|
|
|
|
|
index = low + idx;
|
|
|
|
|
else
|
|
|
|
|
index = low - idx;
|
|
|
|
|
|
1999-11-21 02:16:51 +01:00
|
|
|
tmp << name << "<" << index << ">" << ends;
|
1999-02-15 03:06:15 +01:00
|
|
|
const string inm = tmp.str();
|
|
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case AND:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::AND);
|
|
|
|
|
break;
|
|
|
|
|
case BUF:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::BUF);
|
|
|
|
|
break;
|
|
|
|
|
case BUFIF0:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::BUFIF0);
|
|
|
|
|
break;
|
|
|
|
|
case BUFIF1:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::BUFIF1);
|
|
|
|
|
break;
|
|
|
|
|
case NAND:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::NAND);
|
|
|
|
|
break;
|
|
|
|
|
case NOR:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::NOR);
|
|
|
|
|
break;
|
|
|
|
|
case NOT:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::NOT);
|
|
|
|
|
break;
|
|
|
|
|
case OR:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::OR);
|
|
|
|
|
break;
|
|
|
|
|
case XNOR:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::XNOR);
|
|
|
|
|
break;
|
|
|
|
|
case XOR:
|
|
|
|
|
cur[idx] = new NetLogic(inm, pin_count(), NetLogic::XOR);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
1999-12-11 06:45:41 +01:00
|
|
|
cur[idx]->set_attributes(attributes);
|
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);
|
|
|
|
|
|
1999-02-15 03:06:15 +01:00
|
|
|
des->add_node(cur[idx]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*sig = ex->elaborate_net(des, path, 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;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
|
|
|
|
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.
|
|
|
|
|
*/
|
1998-12-01 01:42:13 +01:00
|
|
|
void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) 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
|
|
|
// Check for duplicate scopes.
|
|
|
|
|
if (NetScope*tmp = des->find_scope(path + "." + get_name())) {
|
|
|
|
|
cerr << get_line() << ": error: Instance/Scope name " <<
|
|
|
|
|
get_name() << " already used in this context." <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-27 20:07:57 +01:00
|
|
|
NetScope*my_scope = des->make_scope(path, NetScope::MODULE, get_name());
|
|
|
|
|
const string my_name = my_scope -> name();
|
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;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
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 "
|
1999-08-03 06:14:49 +02:00
|
|
|
"of parameters. 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-01-09 06:50:48 +01:00
|
|
|
rmod->elaborate(des, my_scope, parms_, nparms_, overrides_);
|
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
|
|
|
|
1999-05-29 04:36:17 +02:00
|
|
|
for (unsigned idx = 0 ; idx < pins->count() ; idx += 1) {
|
1998-11-09 19:55:33 +01:00
|
|
|
// Skip unconnected module ports.
|
1999-05-29 04:36:17 +02:00
|
|
|
if ((*pins)[idx] == 0)
|
1998-11-09 19:55:33 +01:00
|
|
|
continue;
|
1999-08-04 04:13:02 +02:00
|
|
|
|
|
|
|
|
// Inside the module, the port is one or more signals,
|
|
|
|
|
// that were already elaborated. List all those signals,
|
|
|
|
|
// and I will connect them up later.
|
|
|
|
|
svector<PWire*> mport = rmod->get_port(idx);
|
|
|
|
|
svector<NetNet*>prts (mport.count());
|
|
|
|
|
|
|
|
|
|
unsigned prts_pin_count = 0;
|
|
|
|
|
for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) {
|
1999-09-17 04:06:25 +02:00
|
|
|
PWire*pport = mport[ldx];
|
1999-08-04 04:13:02 +02:00
|
|
|
prts[ldx] = des->find_signal(my_name, pport->name());
|
|
|
|
|
assert(prts[ldx]);
|
|
|
|
|
prts_pin_count += prts[ldx]->pin_count();
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*sig = (*pins)[idx]->elaborate_net(des, path,
|
|
|
|
|
prts_pin_count,
|
|
|
|
|
0, 0, 0);
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << "internal error: Expression too complicated "
|
|
|
|
|
"for elaboration." << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
1999-02-01 01:26:48 +01:00
|
|
|
// Check that the parts have matching pin counts. If
|
|
|
|
|
// not, they are different widths.
|
1999-08-04 04:13:02 +02:00
|
|
|
if (prts_pin_count != sig->pin_count()) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Port " << idx << " of "
|
|
|
|
|
<< type_ << " expects " << prts_pin_count <<
|
|
|
|
|
" pins, got " << sig->pin_count() << " from "
|
|
|
|
|
<< sig->name() << endl;
|
1999-02-01 01:26:48 +01:00
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-04 04:13:02 +02:00
|
|
|
// Connect the sig expression that is the context of the
|
|
|
|
|
// module instance to the ports of the elaborated
|
|
|
|
|
// module.
|
1999-01-25 06:45:56 +01:00
|
|
|
|
1999-08-04 04:13:02 +02:00
|
|
|
assert(prts_pin_count == sig->pin_count());
|
|
|
|
|
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1) {
|
|
|
|
|
for (unsigned p = 0 ; p < prts[ldx]->pin_count() ; p += 1) {
|
|
|
|
|
prts_pin_count -= 1;
|
|
|
|
|
connect(sig->pin(prts_pin_count),
|
|
|
|
|
prts[ldx]->pin(prts[ldx]->pin_count()-p-1));
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
|
|
|
|
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.
|
|
|
|
|
*/
|
1998-12-01 01:42:13 +01:00
|
|
|
void PGModule::elaborate_udp_(Design*des, PUdp*udp, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
const string my_name = path+"."+get_name();
|
1999-06-15 05:44:53 +02:00
|
|
|
NetUDP*net = new NetUDP(my_name, udp->ports.count(), udp->sequential);
|
1998-12-01 01:42:13 +01:00
|
|
|
net->set_attributes(udp->attributes);
|
|
|
|
|
|
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;
|
|
|
|
|
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*sig = pin(idx)->elaborate_net(des, path, 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.
|
1998-12-01 01:42:13 +01:00
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1998-12-14 03:01:34 +01:00
|
|
|
/* Build up the truth table for the netlist from the input
|
|
|
|
|
strings. */
|
1999-06-15 05:44:53 +02:00
|
|
|
for (unsigned idx = 0 ; idx < udp->tinput.count() ; idx += 1) {
|
1998-12-14 03:01:34 +01:00
|
|
|
string input = udp->sequential
|
|
|
|
|
? (string("") + udp->tcurrent[idx] + udp->tinput[idx])
|
|
|
|
|
: udp->tinput[idx];
|
|
|
|
|
|
|
|
|
|
net->set_table(input, udp->toutput[idx]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
net->cleanup_table();
|
|
|
|
|
|
|
|
|
|
if (udp->sequential) switch (udp->initial) {
|
|
|
|
|
case verinum::V0:
|
|
|
|
|
net->set_initial('0');
|
|
|
|
|
break;
|
|
|
|
|
case verinum::V1:
|
|
|
|
|
net->set_initial('1');
|
|
|
|
|
break;
|
|
|
|
|
case verinum::Vx:
|
|
|
|
|
case verinum::Vz:
|
|
|
|
|
net->set_initial('x');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All done. Add the object to the design.
|
1998-12-01 01:42:13 +01:00
|
|
|
des->add_node(net);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PGModule::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
// Look for the module type
|
|
|
|
|
map<string,Module*>::const_iterator mod = modlist->find(type_);
|
|
|
|
|
if (mod != modlist->end()) {
|
|
|
|
|
elaborate_mod_(des, (*mod).second, path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try a primitive type
|
|
|
|
|
map<string,PUdp*>::const_iterator udp = udplist->find(type_);
|
|
|
|
|
if (udp != udplist->end()) {
|
|
|
|
|
elaborate_udp_(des, (*udp).second, path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: Unknown module: " << type_ << endl;
|
1998-12-01 01:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
1999-09-15 06:17:52 +02:00
|
|
|
/*
|
|
|
|
|
* The concatenation is also OK an an l-value. This method elaborates
|
|
|
|
|
* it as a structural l-value.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEConcat::elaborate_lnet(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
svector<NetNet*>nets (parms_.count());
|
|
|
|
|
unsigned pins = 0;
|
|
|
|
|
unsigned errors = 0;
|
|
|
|
|
|
|
|
|
|
if (repeat_) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": sorry: I do not know how to"
|
1999-09-15 06:17:52 +02:00
|
|
|
" elaborate repeat concatenation nets." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elaborate the operands of the concatenation. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
|
|
|
|
nets[idx] = parms_[idx]->elaborate_lnet(des, path);
|
|
|
|
|
if (nets[idx] == 0)
|
|
|
|
|
errors += 1;
|
|
|
|
|
else
|
|
|
|
|
pins += nets[idx]->pin_count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If any of the sub expressions failed to elaborate, then
|
|
|
|
|
delete all those that did and abort myself. */
|
|
|
|
|
if (errors) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
|
|
|
|
if (nets[idx]) delete nets[idx];
|
|
|
|
|
}
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the temporary signal that connects to all the
|
|
|
|
|
operands, and connect it up. Scan the operands of the
|
|
|
|
|
concat operator from least significant to most significant,
|
|
|
|
|
which is opposite from how they are given in the list. */
|
1999-11-27 20:07:57 +01:00
|
|
|
NetNet*osig = new NetNet(0, des->local_symbol(path),
|
1999-09-15 06:17:52 +02:00
|
|
|
NetNet::IMPLICIT, pins);
|
|
|
|
|
pins = 0;
|
|
|
|
|
for (unsigned idx = nets.count() ; idx > 0 ; idx -= 1) {
|
|
|
|
|
NetNet*cur = nets[idx-1];
|
|
|
|
|
for (unsigned pin = 0 ; pin < cur->pin_count() ; pin += 1) {
|
|
|
|
|
connect(osig->pin(pins), cur->pin(pin));
|
|
|
|
|
pins += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
des->add_signal(osig);
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetExpr* PENumber::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
assert(value_);
|
1999-05-16 07:08:42 +02:00
|
|
|
NetEConst*tmp = new NetEConst(*value_);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PEString::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-05-27 06:13:08 +02:00
|
|
|
NetEConst*tmp = new NetEConst(value());
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
return tmp;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PExpr::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-06-09 05:00:05 +02:00
|
|
|
cerr << get_line() << ": I do not know how to elaborate expression: "
|
|
|
|
|
<< *this << endl;
|
1999-05-16 07:08:42 +02:00
|
|
|
return 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PEUnary::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-11-04 04:53:26 +01:00
|
|
|
NetExpr*ip = expr_->elaborate_expr(des, path);
|
|
|
|
|
if (ip == 0) return 0;
|
|
|
|
|
|
|
|
|
|
/* Should we evaluate expressions ahead of time,
|
|
|
|
|
* just like in PEBinary::elaborate_expr() ?
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
NetEUnary*tmp;
|
|
|
|
|
switch (op_) {
|
|
|
|
|
default:
|
|
|
|
|
tmp = new NetEUnary(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
case '~':
|
|
|
|
|
tmp = new NetEUBits(op_, ip);
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
break;
|
|
|
|
|
}
|
1999-05-27 06:13:08 +02:00
|
|
|
return tmp;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* Statement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << "internal error: elaborate: What kind of statement? " <<
|
1998-11-09 19:55:33 +01:00
|
|
|
typeid(*this).name() << endl;
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc*cur = new NetProc;
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
NetProc* PAssign::assign_to_memory_(NetMemory*mem, PExpr*ix,
|
|
|
|
|
Design*des, const string&path) const
|
|
|
|
|
{
|
1999-06-14 01:51:16 +02:00
|
|
|
NetExpr*rv = rval()->elaborate_expr(des, path);
|
1999-09-25 04:57:29 +02:00
|
|
|
if (rv == 0)
|
1999-05-10 02:16:57 +02:00
|
|
|
return 0;
|
1999-09-25 04:57:29 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(rv);
|
1999-05-10 02:16:57 +02:00
|
|
|
|
1999-08-01 23:48:11 +02:00
|
|
|
rv->set_width(mem->width());
|
1999-12-05 03:24:08 +01:00
|
|
|
NetNet*idx = ix->elaborate_net(des, path, 0, 0, 0, 0);
|
1999-05-10 02:16:57 +02:00
|
|
|
assert(idx);
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
NetAssignMem*am = new NetAssignMem(mem, idx, rv);
|
1999-05-10 02:16:57 +02:00
|
|
|
am->set_line(*this);
|
|
|
|
|
return am;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate an l-value as a NetNet (it may already exist) and make up
|
|
|
|
|
* the part select stuff for where the assignment is going to be made.
|
|
|
|
|
*/
|
1999-06-14 01:51:16 +02:00
|
|
|
NetNet* PAssign_::elaborate_lval(Design*des, const string&path,
|
|
|
|
|
unsigned&msb, unsigned&lsb,
|
|
|
|
|
NetExpr*&mux) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-06-14 01:51:16 +02:00
|
|
|
/* Get the l-value, and assume that it is an identifier. */
|
|
|
|
|
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
|
1999-07-10 04:19:26 +02:00
|
|
|
|
1999-10-05 04:00:06 +02:00
|
|
|
/* If the l-value is not a register, then make a structural
|
|
|
|
|
elaboration. Make a synthetic register that connects to the
|
|
|
|
|
generated circuit and return that as the l-value. */
|
1999-07-10 04:19:26 +02:00
|
|
|
if (id == 0) {
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*ll = lval_->elaborate_net(des, path, 0, 0, 0, 0);
|
1999-07-10 04:19:26 +02:00
|
|
|
if (ll == 0) {
|
|
|
|
|
cerr << get_line() << ": Assignment l-value too complex."
|
|
|
|
|
<< endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lsb = 0;
|
|
|
|
|
msb = ll->pin_count()-1;
|
|
|
|
|
mux = 0;
|
|
|
|
|
return ll;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-10 02:16:57 +02:00
|
|
|
assert(id);
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
/* Get the signal referenced by the identifier, and make sure
|
1999-10-05 04:00:06 +02:00
|
|
|
it is a register. (Wires are not allows in this context. */
|
1999-06-24 06:24:18 +02:00
|
|
|
NetNet*reg = des->find_signal(path, id->name());
|
1999-05-10 02:16:57 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
if (reg == 0) {
|
1999-09-30 02:48:49 +02:00
|
|
|
cerr << get_line() << ": error: Could not match signal ``" <<
|
1999-06-24 06:24:18 +02:00
|
|
|
id->name() << "'' in ``" << path << "''" << endl;
|
1999-09-30 02:48:49 +02:00
|
|
|
des->errors += 1;
|
1999-01-25 06:45:56 +01:00
|
|
|
return 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
assert(reg);
|
1999-01-25 06:45:56 +01:00
|
|
|
|
1999-08-05 06:58:57 +02:00
|
|
|
if ((reg->type() != NetNet::REG) && (reg->type() != NetNet::INTEGER)) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << get_line() << ": error: " << *lval() <<
|
|
|
|
|
" is not a register." << endl;
|
|
|
|
|
des->errors += 1;
|
1999-01-25 06:45:56 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
if (id->msb_ && id->lsb_) {
|
1999-10-05 04:00:06 +02:00
|
|
|
/* This handles part selects. In this case, there are
|
|
|
|
|
two bit select expressions, and both must be
|
|
|
|
|
constant. Evaluate them and pass the results back to
|
|
|
|
|
the caller. */
|
1999-06-14 01:51:16 +02:00
|
|
|
verinum*vl = id->lsb_->eval_const(des, path);
|
|
|
|
|
if (vl == 0) {
|
1999-09-30 02:48:49 +02:00
|
|
|
cerr << id->lsb_->get_line() << ": error: "
|
|
|
|
|
"Expression must be constant in this context: "
|
|
|
|
|
<< *id->lsb_;
|
1999-06-14 01:51:16 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
verinum*vm = id->msb_->eval_const(des, path);
|
|
|
|
|
if (vl == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << id->msb_->get_line() << ": error: "
|
|
|
|
|
"Expression must be constant in this context: "
|
|
|
|
|
<< *id->msb_;
|
1999-06-14 01:51:16 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msb = vm->as_ulong();
|
|
|
|
|
lsb = vl->as_ulong();
|
|
|
|
|
mux = 0;
|
|
|
|
|
|
|
|
|
|
} else if (id->msb_) {
|
1999-10-05 04:00:06 +02:00
|
|
|
|
|
|
|
|
/* If there is only a single select expression, it is a
|
|
|
|
|
bit select. Evaluate the constant value and treat it
|
|
|
|
|
as a part select with a bit width of 1. If the
|
|
|
|
|
expression it not constant, then return the
|
|
|
|
|
expression as a mux. */
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(id->lsb_ == 0);
|
|
|
|
|
verinum*v = id->msb_->eval_const(des, path);
|
|
|
|
|
if (v == 0) {
|
|
|
|
|
NetExpr*m = id->msb_->elaborate_expr(des, path);
|
|
|
|
|
assert(m);
|
|
|
|
|
msb = 0;
|
|
|
|
|
lsb = 0;
|
|
|
|
|
mux = m;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
msb = v->as_ulong();
|
|
|
|
|
lsb = v->as_ulong();
|
|
|
|
|
mux = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
1999-10-05 04:00:06 +02:00
|
|
|
|
|
|
|
|
/* No select expressions, so presume a part select the
|
|
|
|
|
width of the register. */
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(id->msb_ == 0);
|
|
|
|
|
assert(id->lsb_ == 0);
|
1999-09-13 05:10:59 +02:00
|
|
|
msb = reg->msb();
|
|
|
|
|
lsb = reg->lsb();
|
1999-06-14 01:51:16 +02:00
|
|
|
mux = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* PAssign::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
/* Catch the case where the lvalue is a reference to a memory
|
|
|
|
|
item. These are handled differently. */
|
|
|
|
|
do {
|
|
|
|
|
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
|
|
|
|
|
if (id == 0) break;
|
|
|
|
|
|
1999-11-21 18:35:37 +01:00
|
|
|
if (NetMemory*mem = des->find_memory(path, id->name()))
|
1999-06-14 01:51:16 +02:00
|
|
|
return assign_to_memory_(mem, id->msb_, des, path);
|
|
|
|
|
|
|
|
|
|
} while(0);
|
|
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
|
|
|
|
|
/* elaborate the lval. This detects any part selects and mux
|
|
|
|
|
expressions that might exist. */
|
1999-06-14 01:51:16 +02:00
|
|
|
unsigned lsb, msb;
|
|
|
|
|
NetExpr*mux;
|
|
|
|
|
NetNet*reg = elaborate_lval(des, path, msb, lsb, mux);
|
|
|
|
|
if (reg == 0) return 0;
|
|
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
/* If there is a delay expression, elaborate it. */
|
1999-09-04 21:11:45 +02:00
|
|
|
unsigned long rise_time, fall_time, decay_time;
|
|
|
|
|
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
|
1999-07-12 02:59:36 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
/* Elaborate the r-value expression. */
|
|
|
|
|
assert(rval());
|
1999-11-21 21:03:24 +01:00
|
|
|
|
|
|
|
|
NetExpr*rv;
|
|
|
|
|
|
|
|
|
|
if (verinum*val = rval()->eval_const(des,path)) {
|
|
|
|
|
rv = new NetEConst(*val);
|
|
|
|
|
delete val;
|
|
|
|
|
|
|
|
|
|
} else if (rv = rval()->elaborate_expr(des, path)) {
|
|
|
|
|
|
|
|
|
|
/* OK, go on. */
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Unable to elaborate expression. Retreat. */
|
1999-04-19 03:59:36 +02:00
|
|
|
return 0;
|
1999-11-21 21:03:24 +01:00
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
NetAssign*cur;
|
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
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
if (rise_time || event_) {
|
1999-07-13 06:08:26 +02:00
|
|
|
string n = des->local_symbol(path);
|
1999-09-13 05:10:59 +02:00
|
|
|
unsigned wid = reg->pin_count();
|
1999-07-17 20:06:02 +02:00
|
|
|
|
1999-09-22 23:25:42 +02:00
|
|
|
rv->set_width(reg->pin_count());
|
|
|
|
|
rv = pad_to_width(rv, reg->pin_count());
|
|
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
if (! rv->set_width(reg->pin_count())) {
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-27 20:07:57 +01:00
|
|
|
NetNet*tmp = new NetNet(0, n, NetNet::REG, wid);
|
1999-07-13 06:08:26 +02:00
|
|
|
tmp->set_line(*this);
|
|
|
|
|
des->add_signal(tmp);
|
|
|
|
|
|
1999-09-13 05:10:59 +02:00
|
|
|
/* Generate an assignment of the l-value to the temporary... */
|
1999-07-13 06:08:26 +02:00
|
|
|
n = des->local_symbol(path);
|
|
|
|
|
NetAssign*a1 = new NetAssign(n, des, wid, rv);
|
|
|
|
|
a1->set_line(*this);
|
|
|
|
|
des->add_node(a1);
|
|
|
|
|
|
1999-07-12 02:59:36 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
1999-07-13 06:08:26 +02:00
|
|
|
connect(a1->pin(idx), tmp->pin(idx));
|
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... */
|
1999-07-13 06:08:26 +02:00
|
|
|
n = des->local_symbol(path);
|
1999-07-18 23:17:50 +02:00
|
|
|
NetESignal*sig = new NetESignal(tmp);
|
1999-07-13 06:08:26 +02:00
|
|
|
NetAssign*a2 = new NetAssign(n, des, wid, sig);
|
|
|
|
|
a2->set_line(*this);
|
|
|
|
|
des->add_node(a2);
|
1999-07-12 02:59:36 +02:00
|
|
|
|
1999-07-13 06:08:26 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
1999-09-13 05:10:59 +02:00
|
|
|
connect(a2->pin(idx), reg->pin(idx));
|
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_) {
|
|
|
|
|
st = event_->elaborate_st(des, path, a2);
|
|
|
|
|
if (st == 0) {
|
|
|
|
|
cerr << event_->get_line() << ": error: "
|
|
|
|
|
"unable to elaborate event expression."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(st);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
NetPDelay*de = new NetPDelay(rise_time, a2);
|
|
|
|
|
st = de;
|
|
|
|
|
}
|
1999-07-13 06:08:26 +02:00
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
/* And build up the complex statement. */
|
1999-07-13 06:08:26 +02:00
|
|
|
NetBlock*bl = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
if (mux == 0) {
|
1999-09-13 05:10:59 +02:00
|
|
|
/* This is a simple assign to a register. There may be a
|
|
|
|
|
part select, so take care that the width is of the
|
|
|
|
|
part, and using the lsb, make sure the correct range
|
|
|
|
|
of bits is assigned. */
|
|
|
|
|
unsigned wid = (msb >= lsb)? (msb-lsb+1) : (lsb-msb+1);
|
|
|
|
|
assert(wid <= reg->pin_count());
|
1999-07-17 20:06:02 +02:00
|
|
|
|
1999-09-08 06:05:30 +02:00
|
|
|
rv->set_width(wid);
|
1999-09-13 05:10:59 +02:00
|
|
|
rv = pad_to_width(rv, wid);
|
|
|
|
|
assert(rv->expr_width() >= wid);
|
1999-07-17 20:06:02 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
cur = new NetAssign(des->local_symbol(path), des, wid, rv);
|
1999-09-13 05:10:59 +02:00
|
|
|
unsigned off = reg->sb_to_idx(lsb);
|
|
|
|
|
assert((off+wid) <= reg->pin_count());
|
1999-06-14 01:51:16 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
1999-09-13 05:10:59 +02:00
|
|
|
connect(cur->pin(idx), reg->pin(idx+off));
|
1999-06-14 01:51:16 +02:00
|
|
|
|
|
|
|
|
} else {
|
1999-10-05 04:00:06 +02:00
|
|
|
|
|
|
|
|
assert(msb == lsb);
|
1999-10-07 07:25:33 +02:00
|
|
|
cur = new NetAssign(des->local_symbol(path), des,
|
|
|
|
|
reg->pin_count(), mux, rv);
|
|
|
|
|
for (unsigned idx = 0 ; idx < reg->pin_count() ; idx += 1)
|
|
|
|
|
connect(cur->pin(idx), reg->pin(idx));
|
1999-06-14 01:51:16 +02:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-06-13 18:30:06 +02:00
|
|
|
|
1999-03-15 03:43:32 +01:00
|
|
|
cur->set_line(*this);
|
1998-11-04 00:28:49 +01:00
|
|
|
des->add_node(cur);
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-15 03:55:06 +02:00
|
|
|
/*
|
|
|
|
|
* I do not really know how to elaborate mem[x] <= expr, so this
|
|
|
|
|
* method pretends it is a blocking assign and elaborates
|
|
|
|
|
* that. However, I report an error so that the design isn't actually
|
|
|
|
|
* executed by anyone.
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PAssignNB::assign_to_memory_(NetMemory*mem, PExpr*ix,
|
|
|
|
|
Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
/* Elaborate the r-value expression, ... */
|
|
|
|
|
NetExpr*rv = rval()->elaborate_expr(des, path);
|
1999-09-25 04:57:29 +02:00
|
|
|
if (rv == 0)
|
1999-09-15 03:55:06 +02:00
|
|
|
return 0;
|
1999-09-25 04:57:29 +02:00
|
|
|
|
1999-09-15 03:55:06 +02:00
|
|
|
assert(rv);
|
|
|
|
|
rv->set_width(mem->width());
|
|
|
|
|
|
|
|
|
|
/* Elaborate the expression to calculate the index, ... */
|
1999-12-05 03:24:08 +01:00
|
|
|
NetNet*idx = ix->elaborate_net(des, path, 0, 0, 0, 0);
|
1999-09-15 03:55:06 +02:00
|
|
|
assert(idx);
|
|
|
|
|
|
|
|
|
|
/* And connect them together in an assignment NetProc. */
|
|
|
|
|
NetAssignMemNB*am = new NetAssignMemNB(mem, idx, rv);
|
|
|
|
|
am->set_line(*this);
|
|
|
|
|
|
|
|
|
|
return am;
|
|
|
|
|
}
|
|
|
|
|
|
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.)
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PAssignNB::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-09-15 03:55:06 +02:00
|
|
|
/* Catch the case where the lvalue is a reference to a memory
|
|
|
|
|
item. These are handled differently. */
|
|
|
|
|
do {
|
|
|
|
|
const PEIdent*id = dynamic_cast<const PEIdent*>(lval());
|
|
|
|
|
if (id == 0) break;
|
|
|
|
|
|
1999-11-21 18:35:37 +01:00
|
|
|
if (NetMemory*mem = des->find_memory(path, id->name()))
|
1999-09-15 03:55:06 +02:00
|
|
|
return assign_to_memory_(mem, id->msb_, des, path);
|
|
|
|
|
|
|
|
|
|
} while(0);
|
|
|
|
|
|
|
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
unsigned lsb, msb;
|
|
|
|
|
NetExpr*mux;
|
|
|
|
|
NetNet*reg = elaborate_lval(des, path, msb, lsb, mux);
|
|
|
|
|
if (reg == 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
|
|
|
|
|
|
|
|
/* Elaborate the r-value expression. This generates a
|
|
|
|
|
procedural expression that I attach to the assignment. */
|
1999-06-14 01:51:16 +02:00
|
|
|
NetExpr*rv = rval()->elaborate_expr(des, path);
|
1999-09-25 04:57:29 +02:00
|
|
|
if (rv == 0)
|
1999-06-06 22:45:38 +02:00
|
|
|
return 0;
|
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
|
|
|
|
|
|
|
|
NetAssignNB*cur;
|
1999-06-14 01:51:16 +02:00
|
|
|
if (mux == 0) {
|
|
|
|
|
unsigned wid = msb - lsb + 1;
|
1999-09-12 03:16:51 +02:00
|
|
|
|
|
|
|
|
rv->set_width(wid);
|
1999-09-13 05:10:59 +02:00
|
|
|
rv = pad_to_width(rv, wid);
|
|
|
|
|
assert(wid <= rv->expr_width());
|
1999-09-12 03:16:51 +02:00
|
|
|
|
1999-06-14 01:51:16 +02:00
|
|
|
cur = new NetAssignNB(des->local_symbol(path), des, wid, rv);
|
1999-06-13 06:46:54 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
2000-01-02 19:25:37 +01:00
|
|
|
connect(cur->pin(idx), reg->pin(idx));
|
1999-06-06 22:45:38 +02:00
|
|
|
|
|
|
|
|
} else {
|
1999-06-14 01:51:16 +02:00
|
|
|
assert(reg->pin_count() == 1);
|
|
|
|
|
cur = new NetAssignNB(des->local_symbol(path), des, 1, mux, rv);
|
|
|
|
|
connect(cur->pin(0), reg->pin(0));
|
1999-06-06 22:45:38 +02:00
|
|
|
}
|
|
|
|
|
|
1999-09-04 21:11:45 +02:00
|
|
|
unsigned long rise_time, fall_time, decay_time;
|
|
|
|
|
delay_.eval_delays(des, path, rise_time, fall_time, decay_time);
|
|
|
|
|
cur->rise_time(rise_time);
|
|
|
|
|
cur->fall_time(fall_time);
|
|
|
|
|
cur->decay_time(decay_time);
|
|
|
|
|
|
1999-06-06 22:45:38 +02:00
|
|
|
|
|
|
|
|
/* All done with this node. mark its line number and check it in. */
|
|
|
|
|
cur->set_line(*this);
|
|
|
|
|
des->add_node(cur);
|
|
|
|
|
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.
|
|
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc* PBlock::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-09-22 06:30:04 +02:00
|
|
|
NetBlock::Type type = (bl_type_==PBlock::BL_PAR)
|
|
|
|
|
? NetBlock::PARA
|
|
|
|
|
: NetBlock::SEQU;
|
|
|
|
|
NetBlock*cur = new NetBlock(type);
|
1999-01-25 06:45:56 +01:00
|
|
|
bool fail_flag = false;
|
|
|
|
|
|
1999-12-15 00:42:16 +01:00
|
|
|
string npath;
|
|
|
|
|
if (name_.length()) {
|
|
|
|
|
// Check for duplicate scopes.
|
|
|
|
|
if (NetScope*tmp = des->find_scope(path + "." + name_)) {
|
|
|
|
|
cerr << get_line() << ": error: Instance/Scope name " <<
|
|
|
|
|
name_ << " already used in this context." <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// Make this new scope.
|
|
|
|
|
npath = des->make_scope(path, NetScope::BEGIN_END, name_)->name();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
npath = path;
|
|
|
|
|
}
|
1999-06-24 06:24:18 +02:00
|
|
|
|
1999-06-07 01:07:43 +02:00
|
|
|
// Handle the special case that the block contains only one
|
|
|
|
|
// statement. There is no need to keep the block node.
|
1999-06-24 06:24:18 +02:00
|
|
|
if (list_.count() == 1) {
|
|
|
|
|
NetProc*tmp = list_[0]->elaborate(des, npath);
|
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) {
|
|
|
|
|
NetProc*tmp = list_[idx]->elaborate(des, npath);
|
1999-01-25 06:45:56 +01:00
|
|
|
if (tmp == 0) {
|
|
|
|
|
fail_flag = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
*/
|
1999-02-03 05:20:11 +01:00
|
|
|
NetProc* PCase::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, path);
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
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)
|
|
|
|
|
st = cur->stat->elaborate(des, path);
|
|
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
gu = cur->expr[e]->elaborate_expr(des, path);
|
|
|
|
|
|
|
|
|
|
if (cur->stat)
|
|
|
|
|
st = cur->stat->elaborate(des, path);
|
|
|
|
|
|
|
|
|
|
res->set_case(inum, gu, st);
|
|
|
|
|
inum += 1;
|
|
|
|
|
}
|
1999-02-03 05:20:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
NetProc* PCondit::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-06-03 07:16:25 +02:00
|
|
|
// Elaborate and try to evaluate the conditional expression.
|
1998-11-07 18:05:05 +01:00
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, path);
|
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)
|
|
|
|
|
return if_->elaborate(des, path);
|
|
|
|
|
else if (else_)
|
|
|
|
|
return else_->elaborate(des, path);
|
|
|
|
|
else
|
|
|
|
|
return new NetBlock(NetBlock::SEQU);
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 06:24:18 +02:00
|
|
|
if (! expr->set_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.
|
1999-09-08 04:24:39 +02:00
|
|
|
NetProc*i = if_? if_->elaborate(des, path) : 0;
|
1999-02-03 05:20:11 +01:00
|
|
|
NetProc*e = else_? else_->elaborate(des, path) : 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;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc* PCallTask::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-07-03 04:12:51 +02:00
|
|
|
if (name_[0] == '$')
|
|
|
|
|
return elaborate_sys(des, path);
|
|
|
|
|
else
|
|
|
|
|
return elaborate_usr(des, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
* There is a single special 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
|
|
|
*/
|
|
|
|
|
NetProc* PCallTask::elaborate_sys(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
svector<NetExpr*>eparms (nparms());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
|
|
|
|
PExpr*ex = parm(idx);
|
1999-11-10 03:52:24 +01:00
|
|
|
|
1999-07-03 04:12:51 +02:00
|
|
|
eparms[idx] = ex? ex->elaborate_expr(des, path) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetSTask*cur = new NetSTask(name(), eparms);
|
|
|
|
|
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
|
|
|
|
|
*/
|
1999-07-03 04:12:51 +02:00
|
|
|
NetProc* PCallTask::elaborate_usr(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-09-30 23:28:34 +02:00
|
|
|
NetTaskDef*def = des->find_task(path, name_);
|
1999-07-03 04:12:51 +02:00
|
|
|
if (def == 0) {
|
1999-09-30 23:28:34 +02:00
|
|
|
cerr << get_line() << ": error: Enable of unknown task ``" <<
|
|
|
|
|
path << "." << name_ << "''." << endl;
|
1999-07-03 04:12:51 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
1998-11-04 00:28:49 +01: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 ``"
|
1999-07-24 04:11:19 +02:00
|
|
|
<< name_ << "''." << endl;
|
|
|
|
|
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) {
|
|
|
|
|
cur = new NetUTask(def);
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetBlock*block = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
expression the r-value. */
|
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;
|
|
|
|
|
|
|
|
|
|
NetExpr*rv = parms_[idx]->elaborate_expr(des, path);
|
|
|
|
|
NetAssign*pr = new NetAssign("@", des, port->pin_count(), rv);
|
|
|
|
|
for (unsigned pi = 0 ; pi < port->pin_count() ; pi += 1)
|
|
|
|
|
connect(port->pin(pi), pr->pin(pi));
|
|
|
|
|
des->add_node(pr);
|
|
|
|
|
block->append(pr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate the task call proper... */
|
|
|
|
|
cur = new NetUTask(def);
|
|
|
|
|
block->append(cur);
|
|
|
|
|
|
|
|
|
|
/* Generate assignment statement statements for the output and
|
1999-09-19 00:23:50 +02:00
|
|
|
INOUT ports of the task. The l-value in this case is the
|
|
|
|
|
expression passed as a parameter, and the r-value is the
|
1999-07-24 21:19:06 +02:00
|
|
|
port to be copied out. */
|
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::PINPUT)
|
|
|
|
|
continue;
|
|
|
|
|
|
1999-07-24 21:19:06 +02:00
|
|
|
/* Elaborate the parameter expression as a net so that
|
1999-08-06 06:05:28 +02:00
|
|
|
it can be used as an l-value. Then check that the
|
|
|
|
|
parameter width match up. */
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*val = parms_[idx]->elaborate_net(des, path,
|
|
|
|
|
0, 0, 0, 0);
|
1999-07-24 21:19:06 +02:00
|
|
|
assert(val);
|
|
|
|
|
|
|
|
|
|
|
1999-09-19 00:23:50 +02:00
|
|
|
/* Make an expression out of the actual task port. If
|
|
|
|
|
the port is smaller then the expression to redeive
|
|
|
|
|
the result, then expand the port by padding with
|
|
|
|
|
zeros. */
|
1999-07-24 21:19:06 +02:00
|
|
|
NetESignal*sig = new NetESignal(port);
|
1999-09-19 00:23:50 +02:00
|
|
|
NetExpr*pexp = sig;
|
|
|
|
|
if (sig->expr_width() < val->pin_count()) {
|
|
|
|
|
unsigned cwid = val->pin_count()-sig->expr_width();
|
|
|
|
|
verinum pad (verinum::V0, cwid);
|
|
|
|
|
NetEConst*cp = new NetEConst(pad);
|
|
|
|
|
cp->set_width(cwid);
|
|
|
|
|
|
|
|
|
|
NetEConcat*con = new NetEConcat(2);
|
|
|
|
|
con->set(0, cp);
|
|
|
|
|
con->set(1, sig);
|
|
|
|
|
con->set_width(val->pin_count());
|
|
|
|
|
pexp = con;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-24 21:19:06 +02:00
|
|
|
|
|
|
|
|
/* Generate the assignment statement. */
|
1999-09-19 00:23:50 +02:00
|
|
|
NetAssign*ass = new NetAssign("@", des, val->pin_count(), pexp);
|
1999-07-24 21:19:06 +02:00
|
|
|
for (unsigned pi = 0 ; pi < val->pin_count() ; pi += 1)
|
|
|
|
|
connect(val->pin(pi), ass->pin(pi));
|
|
|
|
|
|
|
|
|
|
des->add_node(ass);
|
|
|
|
|
block->append(ass);
|
1999-07-24 04:11:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return block;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* PDelayStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1999-05-10 02:16:57 +02:00
|
|
|
verinum*num = delay_->eval_const(des, path);
|
1999-09-30 19:22:33 +02:00
|
|
|
if (num == 0) {
|
|
|
|
|
cerr << get_line() << ": sorry: delay expression "
|
|
|
|
|
"must be constant." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
assert(num);
|
|
|
|
|
|
|
|
|
|
unsigned long val = num->as_ulong();
|
1999-05-05 05:04:46 +02:00
|
|
|
if (statement_)
|
|
|
|
|
return new NetPDelay(val, statement_->elaborate(des, path));
|
|
|
|
|
else
|
|
|
|
|
return new NetPDelay(val, 0);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* An event statement gets elaborated as a gate net that drives a
|
|
|
|
|
* special node, the NetPEvent. The NetPEvent is also a NetProc class
|
1999-02-01 01:26:48 +01:00
|
|
|
* because execution flows through it. Thus, the NetPEvent connects
|
1998-11-04 00:28:49 +01:00
|
|
|
* the structural and the behavioral.
|
1999-02-01 01:26:48 +01:00
|
|
|
*
|
|
|
|
|
* Note that it is possible for the statement_ pointer to be 0. This
|
|
|
|
|
* happens when the source has something like "@(E) ;". Note the null
|
|
|
|
|
* statement.
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
1999-09-22 04:00:48 +02:00
|
|
|
NetProc* PEventStatement::elaborate_st(Design*des, const string&path,
|
|
|
|
|
NetProc*enet) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-01-25 06:45:56 +01:00
|
|
|
|
1999-05-01 04:57:52 +02:00
|
|
|
/* Create a single NetPEvent, and a unique NetNEvent for each
|
1999-05-01 22:43:55 +02:00
|
|
|
conjuctive event. An NetNEvent can have many pins only if
|
|
|
|
|
it is an ANYEDGE detector. Otherwise, only connect to the
|
|
|
|
|
least significant bit of the expression. */
|
1999-05-01 04:57:52 +02:00
|
|
|
|
|
|
|
|
NetPEvent*pe = new NetPEvent(des->local_symbol(path), enet);
|
|
|
|
|
for (unsigned idx = 0 ; idx < expr_.count() ; idx += 1) {
|
1999-10-31 05:11:27 +01:00
|
|
|
NetNet*expr = expr_[idx]->expr()->elaborate_net(des, path,
|
|
|
|
|
0, 0, 0, 0);
|
1999-05-01 04:57:52 +02:00
|
|
|
if (expr == 0) {
|
|
|
|
|
expr_[0]->dump(cerr);
|
|
|
|
|
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
|
|
|
|
|
|
|
|
unsigned pins = (expr_[idx]->type() == NetNEvent::ANYEDGE)
|
|
|
|
|
? expr->pin_count() : 1;
|
1999-05-01 04:57:52 +02:00
|
|
|
NetNEvent*ne = new NetNEvent(des->local_symbol(path),
|
1999-05-01 22:43:55 +02:00
|
|
|
pins, expr_[idx]->type(), pe);
|
|
|
|
|
|
|
|
|
|
for (unsigned p = 0 ; p < pins ; p += 1)
|
|
|
|
|
connect(ne->pin(p), expr->pin(p));
|
1999-04-29 04:16:26 +02:00
|
|
|
|
1999-05-01 04:57:52 +02:00
|
|
|
des->add_node(ne);
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-05-01 04:57:52 +02:00
|
|
|
return pe;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1999-09-22 04:00:48 +02:00
|
|
|
NetProc* PEventStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetProc*enet = 0;
|
|
|
|
|
if (statement_) {
|
|
|
|
|
enet = statement_->elaborate(des, path);
|
|
|
|
|
if (enet == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return elaborate_st(des, path, enet);
|
|
|
|
|
}
|
|
|
|
|
|
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?
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PForever::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetProc*stat = statement_->elaborate(des, path);
|
|
|
|
|
if (stat == 0) return 0;
|
|
|
|
|
|
|
|
|
|
NetForever*proc = new NetForever(stat);
|
|
|
|
|
return proc;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PForStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
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);
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
NetBlock*top = new NetBlock(NetBlock::SEQU);
|
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. */
|
1999-06-24 06:24:18 +02:00
|
|
|
NetNet*sig = des->find_signal(path, id1->name());
|
1999-06-06 22:45:38 +02:00
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << id1->get_line() << ": register ``" << id1->name()
|
|
|
|
|
<< "'' unknown in this context." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1998-11-09 19:55:33 +01:00
|
|
|
assert(sig);
|
1999-06-14 01:51:16 +02:00
|
|
|
NetAssign*init = new NetAssign("@for-assign", des, sig->pin_count(),
|
1999-05-27 06:13:08 +02:00
|
|
|
expr1_->elaborate_expr(des, path));
|
1999-06-13 18:30:06 +02:00
|
|
|
for (unsigned idx = 0 ; idx < init->pin_count() ; idx += 1)
|
|
|
|
|
connect(init->pin(idx), sig->pin(idx));
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
top->append(init);
|
|
|
|
|
|
|
|
|
|
NetBlock*body = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
|
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. */
|
|
|
|
|
NetProc*tmp = statement_->elaborate(des, path);
|
|
|
|
|
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. */
|
1999-06-24 06:24:18 +02:00
|
|
|
sig = des->find_signal(path, id2->name());
|
1998-11-09 19:55:33 +01:00
|
|
|
assert(sig);
|
1999-06-14 01:51:16 +02:00
|
|
|
NetAssign*step = new NetAssign("@for-assign", des, sig->pin_count(),
|
1999-05-27 06:13:08 +02:00
|
|
|
expr2_->elaborate_expr(des, path));
|
1999-06-13 18:30:06 +02:00
|
|
|
for (unsigned idx = 0 ; idx < step->pin_count() ; idx += 1)
|
|
|
|
|
connect(step->pin(idx), sig->pin(idx));
|
|
|
|
|
|
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. */
|
|
|
|
|
NetExpr*ce = cond_->elaborate_expr(des, path);
|
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()) {
|
|
|
|
|
if (dynamic_cast<NetEConst*>(tmp))
|
|
|
|
|
cerr << get_line() << ": warning: condition expression "
|
|
|
|
|
"is constant." << endl;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
|
* Elaborating function definitions takes 2 passes. The first creates
|
|
|
|
|
* the NetFuncDef object and attaches the ports to it. The second pass
|
|
|
|
|
* (elaborate_2) elaborates the statement that is contained
|
|
|
|
|
* within. These passes are needed because the statement may invoke
|
|
|
|
|
* the function itself (or other functions) so can't be elaborated
|
|
|
|
|
* until all the functions are partially elaborated.
|
|
|
|
|
*/
|
|
|
|
|
void PFunction::elaborate_1(Design*des, const string&path) const
|
1999-08-26 00:22:41 +02:00
|
|
|
{
|
1999-09-01 00:38:29 +02:00
|
|
|
/* Translate the wires that are ports to NetNet pointers by
|
|
|
|
|
presuming that the name is already elaborated, and look it
|
|
|
|
|
up in the design. Then save that pointer for later use by
|
|
|
|
|
calls to the task. (Remember, the task itself does not need
|
|
|
|
|
these ports.) */
|
|
|
|
|
svector<NetNet*>ports (ports_? ports_->count()+1 : 1);
|
|
|
|
|
ports[0] = des->find_signal(path, path);
|
|
|
|
|
for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) {
|
|
|
|
|
NetNet*tmp = des->find_signal(path, (*ports_)[idx]->name());
|
|
|
|
|
|
|
|
|
|
ports[idx+1] = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-01 22:46:19 +02:00
|
|
|
NetFuncDef*def = new NetFuncDef(path, ports);
|
1999-09-01 00:38:29 +02:00
|
|
|
des->add_function(path, def);
|
1999-08-26 00:22:41 +02:00
|
|
|
}
|
|
|
|
|
|
1999-09-01 22:46:19 +02:00
|
|
|
void PFunction::elaborate_2(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetFuncDef*def = des->find_function(path);
|
|
|
|
|
assert(def);
|
|
|
|
|
|
|
|
|
|
NetProc*st = statement_->elaborate(des, path);
|
|
|
|
|
if (st == 0) {
|
1999-09-30 23:28:34 +02:00
|
|
|
cerr << statement_->get_line() << ": error: Unable to elaborate "
|
1999-09-01 22:46:19 +02:00
|
|
|
"statement in function " << path << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def->set_proc(st);
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-19 23:06:16 +02:00
|
|
|
NetProc* PRepeat::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, path);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc*stat = statement_->elaborate(des, path);
|
|
|
|
|
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;
|
|
|
|
|
return new NetBlock(NetBlock::SEQU);
|
|
|
|
|
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.
|
1999-07-03 04:12:51 +02:00
|
|
|
*/
|
1999-09-30 23:28:34 +02:00
|
|
|
void PTask::elaborate_1(Design*des, const string&path) const
|
1999-07-03 04:12:51 +02:00
|
|
|
{
|
1999-09-30 23:28:34 +02:00
|
|
|
/* Translate the wires that are ports to NetNet pointers by
|
|
|
|
|
presuming that the name is already elaborated, and look it
|
|
|
|
|
up in the design. Then save that pointer for later use by
|
|
|
|
|
calls to the task. (Remember, the task itself does not need
|
|
|
|
|
these ports.) */
|
|
|
|
|
svector<NetNet*>ports (ports_? ports_->count() : 0);
|
|
|
|
|
for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) {
|
|
|
|
|
NetNet*tmp = des->find_signal(path, (*ports_)[idx]->name());
|
|
|
|
|
|
|
|
|
|
ports[idx] = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetTaskDef*def = new NetTaskDef(path, ports);
|
|
|
|
|
des->add_task(path, def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PTask::elaborate_2(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetTaskDef*def = des->find_task(path);
|
|
|
|
|
assert(def);
|
|
|
|
|
|
1999-09-30 04:43:01 +02:00
|
|
|
NetProc*st;
|
|
|
|
|
if (statement_ == 0) {
|
|
|
|
|
cerr << get_line() << ": warning: task has no statement." << endl;
|
|
|
|
|
st = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
st = statement_->elaborate(des, path);
|
|
|
|
|
if (st == 0) {
|
|
|
|
|
cerr << statement_->get_line() << ": Unable to elaborate "
|
|
|
|
|
"statement in task " << path << " at " << get_line()
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
1998-11-11 04:13:04 +01:00
|
|
|
/*
|
|
|
|
|
* The while loop is fairly directly represented in the netlist.
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PWhile::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetWhile*loop = new NetWhile(cond_->elaborate_expr(des, path),
|
|
|
|
|
statement_->elaborate(des, path));
|
|
|
|
|
return loop;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-09 06:50:48 +01:00
|
|
|
bool Module::elaborate(Design*des, NetScope*scope,
|
|
|
|
|
named<PExpr*>*parms, unsigned nparms,
|
|
|
|
|
svector<PExpr*>*overrides_) const
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
1999-11-27 20:07:57 +01:00
|
|
|
const string path = scope->name();
|
1999-01-25 06:45:56 +01:00
|
|
|
bool result_flag = true;
|
|
|
|
|
|
1999-02-21 18:01:57 +01:00
|
|
|
// Generate all the parameters that this instance of this
|
1999-09-20 04:21:10 +02:00
|
|
|
// module introduce to the design. This needs to be done in
|
|
|
|
|
// two passes. The first pass marks the parameter names as
|
|
|
|
|
// available so that they can be discovered when the second
|
|
|
|
|
// pass references them during elaboration.
|
1999-02-21 18:01:57 +01:00
|
|
|
typedef map<string,PExpr*>::const_iterator mparm_it_t;
|
1999-09-20 04:21:10 +02:00
|
|
|
|
2000-01-10 02:35:23 +01:00
|
|
|
// So this loop elaborates the parameters, but doesn't
|
|
|
|
|
// evaluate references to parameters. This scan practically
|
|
|
|
|
// locates all the parameters and puts them in the parameter
|
|
|
|
|
// table in the design. No expressions are evaluated.
|
1999-09-20 04:21:10 +02:00
|
|
|
for (mparm_it_t cur = parameters.begin()
|
|
|
|
|
; cur != parameters.end() ; cur ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
|
|
|
|
des->set_parameter(pname, new NetEParam);
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-10 02:35:23 +01:00
|
|
|
// The replace map contains replacement expressions for the
|
|
|
|
|
// parameters. If there is a replacement expression, use that
|
|
|
|
|
// instead of the default expression. Otherwise, use the
|
|
|
|
|
// default expression.
|
|
|
|
|
|
|
|
|
|
// Replacement expressions can come from the ordered list of
|
|
|
|
|
// overrides, or from the parameter replace by name list.
|
1999-02-21 18:01:57 +01:00
|
|
|
|
2000-01-10 02:35:23 +01:00
|
|
|
map<string,PExpr*> replace;
|
1999-08-23 18:48:39 +02:00
|
|
|
|
|
|
|
|
if (overrides_) {
|
2000-01-09 06:50:48 +01:00
|
|
|
assert(parms == 0);
|
2000-01-10 02:35:23 +01:00
|
|
|
list<string>::const_iterator cur = param_names.begin();
|
|
|
|
|
for (unsigned idx = 0
|
|
|
|
|
; idx < overrides_->count()
|
|
|
|
|
; idx += 1, cur++) {
|
|
|
|
|
replace[*cur] = (*overrides_)[idx];
|
|
|
|
|
}
|
2000-01-09 06:50:48 +01:00
|
|
|
|
|
|
|
|
} else if (parms) {
|
|
|
|
|
|
2000-01-10 02:35:23 +01:00
|
|
|
for (unsigned idx = 0 ; idx < nparms ; idx += 1)
|
|
|
|
|
replace[parms[idx].name] = parms[idx].parm;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ... and this loop elaborates the expressions. The parameter
|
|
|
|
|
// expressions are reduced to ordinary expressions that do not
|
|
|
|
|
// include references to other parameters. Take careful note
|
|
|
|
|
// of the fact that override expressions are elaborated in the
|
|
|
|
|
// *parent* scope.
|
|
|
|
|
|
|
|
|
|
for (mparm_it_t cur = parameters.begin()
|
|
|
|
|
; cur != parameters.end() ; cur ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
|
|
|
|
NetExpr*expr;
|
|
|
|
|
|
|
|
|
|
if (PExpr*tmp = replace[(*cur).first])
|
|
|
|
|
expr = tmp->elaborate_expr(des, scope->parent()->name());
|
|
|
|
|
else
|
|
|
|
|
expr = (*cur).second->elaborate_expr(des, path);
|
|
|
|
|
|
|
|
|
|
des->set_parameter(pname, expr);
|
1999-08-23 18:48:39 +02:00
|
|
|
}
|
|
|
|
|
|
2000-01-09 06:50:48 +01:00
|
|
|
|
1999-09-20 04:21:10 +02:00
|
|
|
// Finally, evaluate the parameter value. This step collapses
|
|
|
|
|
// the parameters to NetEConst values.
|
|
|
|
|
for (mparm_it_t cur = parameters.begin()
|
|
|
|
|
; cur != parameters.end() ; cur ++) {
|
|
|
|
|
|
|
|
|
|
// Get the NetExpr for the parameter.
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
|
|
|
|
const NetExpr*expr = des->find_parameter(path, (*cur).first);
|
|
|
|
|
assert(expr);
|
|
|
|
|
|
|
|
|
|
// If it's already a NetEConst, then this parameter is done.
|
|
|
|
|
if (dynamic_cast<const NetEConst*>(expr))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// Get a non-constant copy of the expression to evaluate...
|
|
|
|
|
NetExpr*nexpr = expr->dup_expr();
|
|
|
|
|
if (nexpr == 0) {
|
|
|
|
|
cerr << (*cur).second->get_line() << ": internal error: "
|
|
|
|
|
"unable to dup expression: " << *expr << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to evaluate the expression.
|
|
|
|
|
nexpr = nexpr->eval_tree();
|
|
|
|
|
if (nexpr == 0) {
|
|
|
|
|
cerr << (*cur).second->get_line() << ": internal error: "
|
|
|
|
|
"unable to evaluate parm expression: " <<
|
|
|
|
|
*expr << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The evaluate worked, replace the old expression with
|
|
|
|
|
// this constant value.
|
|
|
|
|
assert(nexpr);
|
|
|
|
|
des->set_parameter(pname, nexpr);
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
// Get all the explicitly declared wires of the module and
|
|
|
|
|
// start the signals list with them.
|
2000-01-09 21:37:57 +01:00
|
|
|
const map<string,PWire*>&wl = get_wires();
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2000-01-09 21:37:57 +01:00
|
|
|
for (map<string,PWire*>::const_iterator wt = wl.begin()
|
1998-11-04 00:28:49 +01:00
|
|
|
; wt != wl.end()
|
|
|
|
|
; wt ++ ) {
|
|
|
|
|
|
2000-01-09 21:37:57 +01:00
|
|
|
(*wt).second->elaborate(des, scope);
|
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
|
|
|
|
1999-08-26 00:22:41 +02:00
|
|
|
for (mfunc_it_t cur = funcs_.begin()
|
|
|
|
|
; cur != funcs_.end() ; cur ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
1999-09-01 22:46:19 +02:00
|
|
|
(*cur).second->elaborate_1(des, pname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (mfunc_it_t cur = funcs_.begin()
|
|
|
|
|
; cur != funcs_.end() ; cur ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
|
|
|
|
(*cur).second->elaborate_2(des, pname);
|
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 ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
|
|
|
|
(*cur).second->elaborate_1(des, pname);
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-03 04:12:51 +02:00
|
|
|
for (mtask_it_t cur = tasks_.begin()
|
|
|
|
|
; cur != tasks_.end() ; cur ++) {
|
|
|
|
|
string pname = path + "." + (*cur).first;
|
1999-09-30 23:28:34 +02:00
|
|
|
(*cur).second->elaborate_2(des, pname);
|
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 ++ ) {
|
|
|
|
|
|
|
|
|
|
(*gt)->elaborate(des, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Elaborate the behaviors, making processes out of them.
|
|
|
|
|
const list<PProcess*>&sl = get_behaviors();
|
|
|
|
|
|
|
|
|
|
for (list<PProcess*>::const_iterator st = sl.begin()
|
|
|
|
|
; st != sl.end()
|
|
|
|
|
; st ++ ) {
|
|
|
|
|
|
|
|
|
|
NetProc*cur = (*st)->statement()->elaborate(des, path);
|
1999-01-25 06:45:56 +01:00
|
|
|
if (cur == 0) {
|
1999-10-07 07:25:33 +02:00
|
|
|
cerr << (*st)->get_line() << ": error: Elaboration "
|
1999-01-25 06:45:56 +01:00
|
|
|
"failed for this process." << endl;
|
|
|
|
|
result_flag = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProcTop*top;
|
|
|
|
|
switch ((*st)->type()) {
|
|
|
|
|
case PProcess::PR_INITIAL:
|
|
|
|
|
top = new NetProcTop(NetProcTop::KINITIAL, cur);
|
|
|
|
|
break;
|
|
|
|
|
case PProcess::PR_ALWAYS:
|
|
|
|
|
top = new NetProcTop(NetProcTop::KALWAYS, cur);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1999-02-01 01:26:48 +01:00
|
|
|
top->set_line(*(*st));
|
1998-11-04 00:28:49 +01:00
|
|
|
des->add_process(top);
|
|
|
|
|
}
|
1999-01-25 06:45:56 +01:00
|
|
|
|
|
|
|
|
return result_flag;
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
Design* elaborate(const map<string,Module*>&modules,
|
|
|
|
|
const map<string,PUdp*>&primitives,
|
|
|
|
|
const string&root)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
|
|
|
|
// Look for the root module in the list.
|
1998-12-01 01:42:13 +01:00
|
|
|
map<string,Module*>::const_iterator mod = modules.find(root);
|
|
|
|
|
if (mod == modules.end())
|
1998-11-04 00:28:49 +01:00
|
|
|
return 0;
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
Module*rmod = (*mod).second;
|
|
|
|
|
|
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;
|
|
|
|
|
|
1999-11-27 20:07:57 +01:00
|
|
|
NetScope*scope = des->make_root_scope(root);
|
1999-11-24 05:01:58 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
modlist = &modules;
|
1998-12-01 01:42:13 +01:00
|
|
|
udplist = &primitives;
|
2000-01-09 06:50:48 +01:00
|
|
|
bool rc = rmod->elaborate(des, scope, 0, 0, (svector<PExpr*>*)0);
|
1998-11-04 00:28:49 +01:00
|
|
|
modlist = 0;
|
1998-12-01 01:42:13 +01:00
|
|
|
udplist = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-01-25 06:45:56 +01:00
|
|
|
if (rc == false) {
|
|
|
|
|
delete des;
|
|
|
|
|
des = 0;
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
return des;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: elaborate.cc,v $
|
2000-02-23 03:56:53 +01:00
|
|
|
* Revision 1.145 2000/02/23 02:56:54 steve
|
|
|
|
|
* Macintosh compilers do not support ident.
|
|
|
|
|
*
|
2000-02-18 06:15:02 +01:00
|
|
|
* Revision 1.144 2000/02/18 05:15:02 steve
|
|
|
|
|
* Catch module instantiation arrays.
|
|
|
|
|
*
|
2000-02-14 01:11:11 +01:00
|
|
|
* Revision 1.143 2000/02/14 00:11:11 steve
|
|
|
|
|
* Mark the line numbers of NetCondit nodes.
|
|
|
|
|
*
|
2000-02-07 00:13:14 +01:00
|
|
|
* Revision 1.142 2000/02/06 23:13:14 steve
|
|
|
|
|
* Include the scope in named gates.
|
|
|
|
|
*
|
2000-01-10 02:35:23 +01:00
|
|
|
* Revision 1.141 2000/01/10 01:35:23 steve
|
|
|
|
|
* Elaborate parameters afer binding of overrides.
|
|
|
|
|
*
|
2000-01-09 21:37:57 +01:00
|
|
|
* Revision 1.140 2000/01/09 20:37:57 steve
|
|
|
|
|
* Careful with wires connected to multiple ports.
|
|
|
|
|
*
|
2000-01-09 06:50:48 +01:00
|
|
|
* Revision 1.139 2000/01/09 05:50:48 steve
|
|
|
|
|
* Support named parameter override lists.
|
|
|
|
|
*
|
2000-01-02 20:39:03 +01:00
|
|
|
* Revision 1.138 2000/01/02 19:39:03 steve
|
|
|
|
|
* Structural reduction XNOR.
|
|
|
|
|
*
|
2000-01-02 19:25:37 +01:00
|
|
|
* Revision 1.137 2000/01/02 18:25:37 steve
|
|
|
|
|
* Do not overrun the pin index when the LSB != 0.
|
|
|
|
|
*
|
2000-01-01 07:18:00 +01:00
|
|
|
* Revision 1.136 2000/01/01 06:18:00 steve
|
|
|
|
|
* Handle synthesis of concatenation.
|
|
|
|
|
*
|
1999-12-15 00:42:16 +01:00
|
|
|
* Revision 1.135 1999/12/14 23:42:16 steve
|
|
|
|
|
* Detect duplicate scopes.
|
|
|
|
|
*
|
1999-12-11 06:45:41 +01:00
|
|
|
* Revision 1.134 1999/12/11 05:45:41 steve
|
|
|
|
|
* Fix support for attaching attributes to primitive gates.
|
|
|
|
|
*
|
1999-12-05 03:24:08 +01:00
|
|
|
* Revision 1.133 1999/12/05 02:24:08 steve
|
|
|
|
|
* Synthesize LPM_RAM_DQ for writes into memories.
|
|
|
|
|
*
|
1999-12-02 05:08:10 +01:00
|
|
|
* Revision 1.132 1999/12/02 04:08:10 steve
|
|
|
|
|
* Elaborate net repeat concatenations.
|
|
|
|
|
*
|
1999-11-29 00:42:02 +01:00
|
|
|
* Revision 1.131 1999/11/28 23:42:02 steve
|
|
|
|
|
* NetESignal object no longer need to be NetNode
|
|
|
|
|
* objects. Let them keep a pointer to NetNet objects.
|
|
|
|
|
*
|
1999-11-27 20:07:57 +01:00
|
|
|
* Revision 1.130 1999/11/27 19:07:57 steve
|
|
|
|
|
* Support the creation of scopes.
|
|
|
|
|
*
|
1999-11-24 05:01:58 +01:00
|
|
|
* Revision 1.129 1999/11/24 04:01:58 steve
|
|
|
|
|
* Detect and list scope names.
|
|
|
|
|
*
|
1999-11-21 21:03:24 +01:00
|
|
|
* Revision 1.128 1999/11/21 20:03:24 steve
|
|
|
|
|
* Handle multiply in constant expressions.
|
|
|
|
|
*
|
1999-11-21 18:35:37 +01:00
|
|
|
* Revision 1.127 1999/11/21 17:35:37 steve
|
|
|
|
|
* Memory name lookup handles scopes.
|
|
|
|
|
*
|
1999-11-21 02:16:51 +01:00
|
|
|
* Revision 1.126 1999/11/21 01:16:51 steve
|
|
|
|
|
* Fix coding errors handling names of logic devices,
|
|
|
|
|
* and add support for buf device in vvm.
|
|
|
|
|
*
|
1999-11-21 01:13:08 +01:00
|
|
|
* Revision 1.125 1999/11/21 00:13:08 steve
|
|
|
|
|
* Support memories in continuous assignments.
|
|
|
|
|
*
|
1999-11-18 04:52:19 +01:00
|
|
|
* Revision 1.124 1999/11/18 03:52:19 steve
|
|
|
|
|
* Turn NetTmp objects into normal local NetNet objects,
|
|
|
|
|
* and add the nodangle functor to clean up the local
|
|
|
|
|
* symbols generated by elaboration and other steps.
|
|
|
|
|
*
|
1999-11-10 03:52:24 +01:00
|
|
|
* Revision 1.123 1999/11/10 02:52:24 steve
|
|
|
|
|
* Create the vpiMemory handle type.
|
|
|
|
|
*
|
1999-11-05 22:45:19 +01:00
|
|
|
* Revision 1.122 1999/11/05 21:45:19 steve
|
|
|
|
|
* Fix NetConst being set to zero width, and clean
|
|
|
|
|
* up elaborate_set_cmp_ for NetEBinary.
|
|
|
|
|
*
|
1999-11-04 04:53:26 +01:00
|
|
|
* Revision 1.121 1999/11/04 03:53:26 steve
|
|
|
|
|
* Patch to synthesize unary ~ and the ternary operator.
|
|
|
|
|
* Thanks to Larry Doolittle <LRDoolittle@lbl.gov>.
|
|
|
|
|
*
|
|
|
|
|
* Add the LPM_MUX device, and integrate it with the
|
|
|
|
|
* ternary synthesis from Larry. Replace the lpm_mux
|
|
|
|
|
* generator in t-xnf.cc to use XNF EQU devices to
|
|
|
|
|
* put muxs into function units.
|
|
|
|
|
*
|
|
|
|
|
* Rewrite elaborate_net for the PETernary class to
|
|
|
|
|
* also use the LPM_MUX device.
|
|
|
|
|
*
|
1999-10-31 21:08:24 +01:00
|
|
|
* Revision 1.120 1999/10/31 20:08:24 steve
|
|
|
|
|
* Include subtraction in LPM_ADD_SUB device.
|
|
|
|
|
*
|
1999-10-31 05:11:27 +01:00
|
|
|
* Revision 1.119 1999/10/31 04:11:27 steve
|
|
|
|
|
* Add to netlist links pin name and instance number,
|
|
|
|
|
* and arrange in vvm for pin connections by name
|
|
|
|
|
* and instance number.
|
|
|
|
|
*
|
1999-10-18 02:02:21 +02:00
|
|
|
* Revision 1.118 1999/10/18 00:02:21 steve
|
|
|
|
|
* Catch unindexed memory reference.
|
|
|
|
|
*
|
1999-10-13 05:16:36 +02:00
|
|
|
* Revision 1.117 1999/10/13 03:16:36 steve
|
|
|
|
|
* Remove commented out do_assign.
|
|
|
|
|
*
|
1999-10-10 03:59:54 +02:00
|
|
|
* Revision 1.116 1999/10/10 01:59:54 steve
|
|
|
|
|
* Structural case equals device.
|
|
|
|
|
*
|
1999-10-09 23:30:16 +02:00
|
|
|
* Revision 1.115 1999/10/09 21:30:16 steve
|
|
|
|
|
* Support parameters in continuous assignments.
|
|
|
|
|
*
|
1999-10-09 21:24:04 +02:00
|
|
|
* Revision 1.114 1999/10/09 19:24:04 steve
|
|
|
|
|
* Better message for combinational operators.
|
|
|
|
|
*
|
1999-10-08 19:48:08 +02:00
|
|
|
* Revision 1.113 1999/10/08 17:48:08 steve
|
|
|
|
|
* Support + in constant expressions.
|
|
|
|
|
*
|
1999-10-08 19:27:23 +02:00
|
|
|
* Revision 1.112 1999/10/08 17:27:23 steve
|
|
|
|
|
* Accept adder parameters with different widths,
|
|
|
|
|
* and simplify continuous assign construction.
|
|
|
|
|
*
|
1999-10-07 07:25:33 +02:00
|
|
|
* Revision 1.111 1999/10/07 05:25:33 steve
|
|
|
|
|
* Add non-const bit select in l-value of assignment.
|
|
|
|
|
*
|
1999-10-06 02:39:00 +02:00
|
|
|
* Revision 1.110 1999/10/06 00:39:00 steve
|
|
|
|
|
* == and != connected to the wrong pins of the compare.
|
|
|
|
|
*
|
1999-10-05 08:19:46 +02:00
|
|
|
* Revision 1.109 1999/10/05 06:19:46 steve
|
|
|
|
|
* Add support for reduction NOR.
|
|
|
|
|
*
|
1999-10-05 04:00:06 +02:00
|
|
|
* Revision 1.108 1999/10/05 02:00:06 steve
|
|
|
|
|
* sorry message for non-constant l-value bit select.
|
|
|
|
|
*
|
1999-09-30 23:28:34 +02:00
|
|
|
* Revision 1.107 1999/09/30 21:28:34 steve
|
|
|
|
|
* Handle mutual reference of tasks by elaborating
|
|
|
|
|
* task definitions in two passes, like functions.
|
|
|
|
|
*
|
1999-09-30 19:22:33 +02:00
|
|
|
* Revision 1.106 1999/09/30 17:22:33 steve
|
|
|
|
|
* catch non-constant delays as unsupported.
|
|
|
|
|
*
|
1999-09-30 04:43:01 +02:00
|
|
|
* Revision 1.105 1999/09/30 02:43:02 steve
|
|
|
|
|
* Elaborate ~^ and ~| operators.
|
|
|
|
|
*
|
1999-09-30 02:48:49 +02:00
|
|
|
* Revision 1.104 1999/09/30 00:48:50 steve
|
|
|
|
|
* Cope with errors during ternary operator elaboration.
|
|
|
|
|
*
|
1999-09-30 00:57:10 +02:00
|
|
|
* Revision 1.103 1999/09/29 22:57:10 steve
|
|
|
|
|
* Move code to elab_expr.cc
|
|
|
|
|
*
|
1999-09-29 20:36:02 +02:00
|
|
|
* Revision 1.102 1999/09/29 18:36:03 steve
|
|
|
|
|
* Full case support
|
|
|
|
|
*
|
1999-09-29 02:42:50 +02:00
|
|
|
* Revision 1.101 1999/09/29 00:42:50 steve
|
|
|
|
|
* Allow expanding of additive operators.
|
|
|
|
|
*
|
1999-09-25 04:57:29 +02:00
|
|
|
* Revision 1.100 1999/09/25 02:57:30 steve
|
1998-11-04 00:28:49 +01:00
|
|
|
*/
|
|
|
|
|
|