1998-11-04 00:28:49 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 1998 Stephen Williams (steve@icarus.com)
|
|
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
#if !defined(WINNT)
|
1998-12-07 05:53:16 +01:00
|
|
|
#ident "$Id: elaborate.cc,v 1.9 1998/12/07 04:53:17 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"
|
|
|
|
|
|
1998-12-07 05:53:16 +01:00
|
|
|
string Design::local_symbol(const string&path)
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
|
|
|
|
string result = "_L";
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void do_assign(Design*des, const string&path,
|
|
|
|
|
NetNet*lval, NetNet*rval)
|
|
|
|
|
{
|
|
|
|
|
assert(lval->pin_count() == rval->pin_count());
|
|
|
|
|
const unsigned pin_count = lval->pin_count();
|
|
|
|
|
|
|
|
|
|
if (NetTmp* tmp = dynamic_cast<NetTmp*>(rval)) {
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), tmp->pin(idx));
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
if ((tmp = dynamic_cast<NetTmp*>(lval)))
|
1998-11-04 00:28:49 +01:00
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
} else if (NetTmp* tmp = dynamic_cast<NetTmp*>(lval)) {
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
|
|
|
|
connect(tmp->pin(idx), rval->pin(idx));
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
} else if (rval->local_flag()) {
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), rval->pin(idx));
|
|
|
|
|
delete rval;
|
|
|
|
|
|
|
|
|
|
} else if (lval->local_flag()) {
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count ; idx += 1)
|
|
|
|
|
connect(lval->pin(idx), rval->pin(idx));
|
|
|
|
|
delete lval;
|
|
|
|
|
|
|
|
|
|
} else for (unsigned idx = 0 ; idx < pin_count ; idx += 1) {
|
1998-12-07 05:53:16 +01:00
|
|
|
NetBUFZ*cur = new NetBUFZ(des->local_symbol(path));
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
connect(cur->pin(0), lval->pin(idx));
|
|
|
|
|
connect(cur->pin(1), rval->pin(idx));
|
|
|
|
|
|
|
|
|
|
des->add_node(cur);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
/* Elaborate a source wire. Generally pretty easy. */
|
|
|
|
|
void PWire::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet::Type wtype = type;
|
|
|
|
|
if (wtype == NetNet::IMPLICIT)
|
|
|
|
|
wtype = NetNet::WIRE;
|
|
|
|
|
|
|
|
|
|
unsigned wid = 1;
|
|
|
|
|
|
|
|
|
|
if (msb && lsb) {
|
|
|
|
|
verinum*mval = msb->eval_const();
|
|
|
|
|
assert(mval);
|
|
|
|
|
verinum*lval = lsb->eval_const();
|
|
|
|
|
assert(lval);
|
|
|
|
|
|
|
|
|
|
long mnum = mval->as_long();
|
|
|
|
|
long lnum = lval->as_long();
|
|
|
|
|
delete mval;
|
|
|
|
|
delete lval;
|
|
|
|
|
|
|
|
|
|
if (mnum > lnum)
|
|
|
|
|
wid = mnum - lnum + 1;
|
|
|
|
|
else
|
|
|
|
|
wid = lnum - mnum + 1;
|
|
|
|
|
|
|
|
|
|
} else if (msb) {
|
|
|
|
|
verinum*val = msb->eval_const();
|
|
|
|
|
assert(val);
|
|
|
|
|
assert(val->as_ulong() > 0);
|
|
|
|
|
wid = val->as_ulong();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*sig = new NetNet(path + "." + name, wtype, wid);
|
|
|
|
|
sig->port_type(port_type);
|
1998-11-23 01:20:22 +01:00
|
|
|
sig->set_attributes(attributes);
|
1998-11-04 00:28:49 +01:00
|
|
|
des->add_signal(sig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PGate::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
cerr << "what kind of gate? " << typeid(*this).name() << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elaborate the continuous assign. (This is *not* the procedural
|
|
|
|
|
assign.) Elaborate the lvalue and rvalue, and do the assignment. */
|
|
|
|
|
void PGAssign::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet*lval = pin(0)->elaborate_net(des, path);
|
|
|
|
|
NetNet*rval = pin(1)->elaborate_net(des, path);
|
|
|
|
|
assert(lval && rval);
|
|
|
|
|
|
|
|
|
|
do_assign(des, path, lval, rval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elaborate a Builtin gate. These normally get translated into
|
|
|
|
|
NetLogic nodes that reflect the particular logic function. */
|
|
|
|
|
void PGBuiltin::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetLogic*cur = 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);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
|
case AND:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::AND);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
1998-12-07 05:53:16 +01:00
|
|
|
case BUF:
|
|
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::BUF);
|
|
|
|
|
break;
|
1998-11-04 00:28:49 +01:00
|
|
|
case NAND:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::NAND);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
case NOR:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::NOR);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
case NOT:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::NOT);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
case OR:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::OR);
|
|
|
|
|
break;
|
|
|
|
|
case XNOR:
|
|
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::XNOR);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
case XOR:
|
1998-11-09 19:55:33 +01:00
|
|
|
cur = new NetLogic(name, pin_count(), NetLogic::XOR);
|
1998-11-04 00:28:49 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(cur);
|
|
|
|
|
cur->delay1(get_delay());
|
|
|
|
|
cur->delay2(get_delay());
|
|
|
|
|
cur->delay3(get_delay());
|
|
|
|
|
des->add_node(cur);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
|
|
|
|
const PExpr*ex = pin(idx);
|
|
|
|
|
NetNet*sig = ex->elaborate_net(des, path);
|
|
|
|
|
assert(sig);
|
|
|
|
|
connect(cur->pin(idx), sig->pin(0));
|
|
|
|
|
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
|
|
|
{
|
1998-11-21 20:19:44 +01:00
|
|
|
string my_name;
|
|
|
|
|
if (get_name() == "")
|
1998-12-07 05:53:16 +01:00
|
|
|
my_name = des->local_symbol(path);
|
1998-11-21 20:19:44 +01:00
|
|
|
else
|
|
|
|
|
my_name = path + "." + get_name();
|
|
|
|
|
|
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.
|
1998-11-21 20:19:44 +01:00
|
|
|
rmod->elaborate(des, my_name);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
// Now connect the ports of the newly elaborated designs to
|
|
|
|
|
// the expressions that are the instantiation parameters.
|
|
|
|
|
|
|
|
|
|
assert(pin_count() == rmod->ports.size());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
1998-11-09 19:55:33 +01:00
|
|
|
// Skip unconnected module ports.
|
|
|
|
|
if (pin(idx) == 0)
|
|
|
|
|
continue;
|
1998-11-04 00:28:49 +01:00
|
|
|
NetNet*sig = pin(idx)->elaborate_net(des, path);
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << "Expression too complicated for elaboration." << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
1998-11-21 20:19:44 +01:00
|
|
|
NetNet*prt = des->find_signal(my_name + "." +
|
1998-11-04 00:28:49 +01:00
|
|
|
rmod->ports[idx]->name);
|
|
|
|
|
assert(prt);
|
|
|
|
|
|
|
|
|
|
assert(prt->pin_count() == sig->pin_count());
|
|
|
|
|
switch (prt->port_type()) {
|
|
|
|
|
case NetNet::PINPUT:
|
|
|
|
|
do_assign(des, path, prt, sig);
|
|
|
|
|
break;
|
|
|
|
|
case NetNet::POUTPUT:
|
|
|
|
|
do_assign(des, path, sig, prt);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
|
NetUDP*net = new NetUDP(my_name, udp->ports.size());
|
|
|
|
|
net->set_attributes(udp->attributes);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
1998-12-02 05:37:13 +01:00
|
|
|
if (pin(idx) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
1998-12-01 01:42:13 +01:00
|
|
|
NetNet*sig = pin(idx)->elaborate_net(des, path);
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << "Expression too complicated for elaboration:"
|
|
|
|
|
<< *pin(idx) << endl;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect(sig->pin(0), net->pin(idx));
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cerr << "Unknown module: " << type_ << endl;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetNet* PExpr::elaborate_net(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
cerr << "Don't know how to elaborate `" << *this << "' as gates." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Elaborating binary operations generally involves elaborating the
|
|
|
|
|
* left and right expressions, then making an output wire and
|
|
|
|
|
* connecting the lot together with the right kind of gate.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet*lsig = left_->elaborate_net(des, path),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << "Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << "Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*osig;
|
|
|
|
|
NetLogic*gate;
|
|
|
|
|
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '^': // XOR
|
|
|
|
|
assert(lsig->pin_count() == 1);
|
|
|
|
|
assert(rsig->pin_count() == 1);
|
1998-12-07 05:53:16 +01:00
|
|
|
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::XOR);
|
1998-11-04 00:28:49 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
1998-12-07 05:53:16 +01:00
|
|
|
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
1998-11-04 00:28:49 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
des->add_signal(osig);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '&': // AND
|
|
|
|
|
assert(lsig->pin_count() == 1);
|
|
|
|
|
assert(rsig->pin_count() == 1);
|
1998-12-07 05:53:16 +01:00
|
|
|
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::AND);
|
1998-11-04 00:28:49 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
1998-12-07 05:53:16 +01:00
|
|
|
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
1998-11-04 00:28:49 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
des->add_signal(osig);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
break;
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
case 'e': // ==
|
|
|
|
|
assert(lsig->pin_count() == 1);
|
|
|
|
|
assert(rsig->pin_count() == 1);
|
1998-12-07 05:53:16 +01:00
|
|
|
gate = new NetLogic(des->local_symbol(path), 3, NetLogic::XNOR);
|
1998-11-09 19:55:33 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
1998-12-07 05:53:16 +01:00
|
|
|
osig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
1998-11-09 19:55:33 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
des->add_signal(osig);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
break;
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
default:
|
|
|
|
|
cerr << "Unhandled BINARY '" << op_ << "'" << endl;
|
|
|
|
|
osig = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet* PEIdent::elaborate_net(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet*sig = des->find_signal(path+"."+text_);
|
|
|
|
|
|
|
|
|
|
if (msb_ && lsb_) {
|
|
|
|
|
verinum*mval = msb_->eval_const();
|
|
|
|
|
assert(mval);
|
|
|
|
|
verinum*lval = lsb_->eval_const();
|
|
|
|
|
assert(lval);
|
|
|
|
|
unsigned midx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
|
|
|
|
|
|
|
|
|
if (midx >= lidx) {
|
|
|
|
|
NetTmp*tmp = new NetTmp(midx-lidx+1);
|
|
|
|
|
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
|
|
|
|
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
sig = tmp;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
NetTmp*tmp = new NetTmp(lidx-midx+1);
|
|
|
|
|
for (unsigned idx = lidx ; idx >= midx ; idx -= 1)
|
|
|
|
|
connect(tmp->pin(idx-midx), sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (msb_) {
|
|
|
|
|
verinum*mval = msb_->eval_const();
|
|
|
|
|
assert(mval);
|
|
|
|
|
unsigned idx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
NetTmp*tmp = new NetTmp(1);
|
|
|
|
|
connect(tmp->pin(0), sig->pin(idx));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
/*
|
|
|
|
|
* XXXX For now, only generate a single bit. I am going to have to add
|
|
|
|
|
* code to properly calculate expression bit widths, eventually.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PENumber::elaborate_net(Design*des, const string&path) const
|
|
|
|
|
{
|
1998-12-07 05:53:16 +01:00
|
|
|
NetNet*net = new NetNet(des->local_symbol(path), NetNet::IMPLICIT);
|
1998-11-09 19:55:33 +01:00
|
|
|
net->local_flag(true);
|
1998-12-07 05:53:16 +01:00
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), value_->get(0));
|
1998-11-09 19:55:33 +01:00
|
|
|
des->add_node(tmp);
|
|
|
|
|
des->add_signal(net);
|
|
|
|
|
connect(net->pin(0), tmp->pin(0));
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetNet* PEUnary::elaborate_net(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet* sub_sig = expr_->elaborate_net(des, path);
|
|
|
|
|
assert(sub_sig);
|
|
|
|
|
|
|
|
|
|
NetNet* sig;
|
|
|
|
|
NetLogic*gate;
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '~': // Bitwise NOT
|
|
|
|
|
assert(sub_sig->pin_count() == 1);
|
1998-12-07 05:53:16 +01:00
|
|
|
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
1998-11-04 00:28:49 +01:00
|
|
|
sig->local_flag(true);
|
1998-12-07 05:53:16 +01:00
|
|
|
gate = new NetLogic(des->local_symbol(path), 2, NetLogic::NOT);
|
1998-11-04 00:28:49 +01:00
|
|
|
connect(gate->pin(0), sig->pin(0));
|
|
|
|
|
connect(gate->pin(1), sub_sig->pin(0));
|
|
|
|
|
des->add_signal(sig);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '&': // Reduction AND
|
1998-12-07 05:53:16 +01:00
|
|
|
sig = new NetNet(des->local_symbol(path), NetNet::WIRE);
|
1998-11-04 00:28:49 +01:00
|
|
|
sig->local_flag(true);
|
1998-12-07 05:53:16 +01:00
|
|
|
gate = new NetLogic(des->local_symbol(path),
|
1998-11-04 00:28:49 +01:00
|
|
|
1+sub_sig->pin_count(),
|
|
|
|
|
NetLogic::AND);
|
|
|
|
|
connect(gate->pin(0), sig->pin(0));
|
|
|
|
|
for (unsigned idx = 0 ; idx < sub_sig->pin_count() ; idx += 1)
|
|
|
|
|
connect(gate->pin(idx+1), sub_sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
des->add_signal(sig);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
cerr << "Unhandled UNARY '" << op_ << "'" << endl;
|
|
|
|
|
sig = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sub_sig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
NetExpr* PEBinary::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
return new NetEBinary(op_, left_->elaborate_expr(des, path),
|
|
|
|
|
right_->elaborate_expr(des, path));
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetExpr* PENumber::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
assert(value_);
|
|
|
|
|
return new NetEConst(*value_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PEString::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
return new NetEConst(value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
if (text_[0] == '$')
|
1998-11-07 18:05:05 +01:00
|
|
|
return new NetEIdent(text_, 64);
|
|
|
|
|
else {
|
|
|
|
|
string name = path+"."+text_;
|
|
|
|
|
NetNet*net = des->find_signal(name);
|
|
|
|
|
assert(net);
|
|
|
|
|
return new NetESignal(net);
|
|
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PExpr::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
cerr << "Cannot elaborate expression: " << *this << endl;
|
|
|
|
|
return new NetEConst(verinum());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr* PEUnary::elaborate_expr(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
return new NetEUnary(op_, expr_->elaborate_expr(des, path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* Statement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
1998-11-09 19:55:33 +01:00
|
|
|
cerr << "elaborate: What kind of statement? " <<
|
|
|
|
|
typeid(*this).name() << endl;
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc*cur = new NetProc;
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* PAssign::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetNet*reg = des->find_signal(path+"."+lval());
|
|
|
|
|
if (reg == 0) {
|
|
|
|
|
cerr << "Could not match signal: " << lval() << endl;
|
|
|
|
|
return new NetProc;
|
|
|
|
|
}
|
|
|
|
|
assert(reg);
|
|
|
|
|
assert(reg->type() == NetNet::REG);
|
|
|
|
|
assert(expr_);
|
|
|
|
|
|
|
|
|
|
NetExpr*rval = expr_->elaborate_expr(des, path);
|
|
|
|
|
assert(rval);
|
|
|
|
|
|
|
|
|
|
NetAssign*cur = new NetAssign(reg, rval);
|
|
|
|
|
des->add_node(cur);
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* PBlock::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetBlock*cur = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
for (unsigned idx = 0 ; idx < size() ; idx += 1) {
|
|
|
|
|
cur->append(stat(idx)->elaborate(des, path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-07 18:05:05 +01:00
|
|
|
NetProc* PCondit::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetExpr*expr = expr_->elaborate_expr(des, path);
|
|
|
|
|
NetProc*i = if_->elaborate(des, path);
|
|
|
|
|
NetProc*e = else_->elaborate(des, path);
|
|
|
|
|
|
|
|
|
|
NetCondit*res = new NetCondit(expr, i, e);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
NetProc* PCallTask::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetTask*cur = new NetTask(name(), nparms());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
|
|
|
|
PExpr*ex = parm(idx);
|
|
|
|
|
cur->parm(idx, ex? ex->elaborate_expr(des, path) : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetProc* PDelayStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
verinum*num = delay_->eval_const();
|
|
|
|
|
assert(num);
|
|
|
|
|
|
|
|
|
|
unsigned long val = num->as_ulong();
|
|
|
|
|
return new NetPDelay(val, statement_->elaborate(des, path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* An event statement gets elaborated as a gate net that drives a
|
|
|
|
|
* special node, the NetPEvent. The NetPEvent is also a NetProc class
|
|
|
|
|
* becuase execution flows through it. Thus, the NetPEvent connects
|
|
|
|
|
* the structural and the behavioral.
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PEventStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetProc*enet = statement_->elaborate(des, path);
|
1998-12-07 05:53:16 +01:00
|
|
|
NetPEvent*ev = new NetPEvent(des->local_symbol(path), type_, enet);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
NetNet*expr = expr_->elaborate_net(des, path);
|
|
|
|
|
if (expr == 0) {
|
|
|
|
|
cerr << "Failed to elaborate expression: ";
|
|
|
|
|
expr_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
assert(expr);
|
|
|
|
|
connect(ev->pin(0), expr->pin(0));
|
|
|
|
|
|
|
|
|
|
des->add_node(ev);
|
|
|
|
|
return ev;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-09 19:55:33 +01:00
|
|
|
/*
|
|
|
|
|
* elaborate the for loop as the equivilent while loop. This eases the
|
|
|
|
|
* task for the target code generator. The structure is:
|
|
|
|
|
*
|
|
|
|
|
* begin
|
|
|
|
|
* name1_ = expr1_;
|
|
|
|
|
* while (cond_) begin
|
|
|
|
|
* statement_;
|
|
|
|
|
* name2_ = expr2_;
|
|
|
|
|
* end
|
|
|
|
|
* end
|
|
|
|
|
*/
|
|
|
|
|
NetProc* PForStatement::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
NetBlock*top = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
NetNet*sig = des->find_signal(path+"."+name1_);
|
|
|
|
|
assert(sig);
|
|
|
|
|
NetAssign*init = new NetAssign(sig, expr1_->elaborate_expr(des, path));
|
|
|
|
|
top->append(init);
|
|
|
|
|
|
|
|
|
|
NetBlock*body = new NetBlock(NetBlock::SEQU);
|
|
|
|
|
|
|
|
|
|
body->append(statement_->elaborate(des, path));
|
|
|
|
|
|
|
|
|
|
sig = des->find_signal(path+"."+name2_);
|
|
|
|
|
assert(sig);
|
|
|
|
|
NetAssign*step = new NetAssign(sig, expr2_->elaborate_expr(des, path));
|
|
|
|
|
body->append(step);
|
|
|
|
|
|
|
|
|
|
NetWhile*loop = new NetWhile(cond_->elaborate_expr(des, path), body);
|
|
|
|
|
top->append(loop);
|
|
|
|
|
return top;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
void Module::elaborate(Design*des, const string&path) const
|
|
|
|
|
{
|
|
|
|
|
// Get all the explicitly declared wires of the module and
|
|
|
|
|
// start the signals list with them.
|
|
|
|
|
const list<PWire*>&wl = get_wires();
|
|
|
|
|
|
|
|
|
|
for (list<PWire*>::const_iterator wt = wl.begin()
|
|
|
|
|
; wt != wl.end()
|
|
|
|
|
; wt ++ ) {
|
|
|
|
|
|
|
|
|
|
(*wt)->elaborate(des, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
des->add_process(top);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
modlist = &modules;
|
1998-12-01 01:42:13 +01:00
|
|
|
udplist = &primitives;
|
1998-11-04 00:28:49 +01:00
|
|
|
rmod->elaborate(des, root);
|
|
|
|
|
modlist = 0;
|
1998-12-01 01:42:13 +01:00
|
|
|
udplist = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
return des;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: elaborate.cc,v $
|
1998-12-07 05:53:16 +01:00
|
|
|
* Revision 1.9 1998/12/07 04:53:17 steve
|
|
|
|
|
* Generate OBUF or IBUF attributes (and the gates
|
|
|
|
|
* to garry them) where a wire is a pad. This involved
|
|
|
|
|
* figuring out enough of the netlist to know when such
|
|
|
|
|
* was needed, and to generate new gates and signales
|
|
|
|
|
* to handle what's missing.
|
|
|
|
|
*
|
1998-12-02 05:37:13 +01:00
|
|
|
* Revision 1.8 1998/12/02 04:37:13 steve
|
|
|
|
|
* Add the nobufz function to eliminate bufz objects,
|
|
|
|
|
* Object links are marked with direction,
|
|
|
|
|
* constant propagation is more careful will wide links,
|
|
|
|
|
* Signal folding is aware of attributes, and
|
|
|
|
|
* the XNF target can dump UDP objects based on LCA
|
|
|
|
|
* attributes.
|
|
|
|
|
*
|
1998-12-01 01:42:13 +01:00
|
|
|
* Revision 1.7 1998/12/01 00:42:14 steve
|
|
|
|
|
* Elaborate UDP devices,
|
|
|
|
|
* Support UDP type attributes, and
|
|
|
|
|
* pass those attributes to nodes that
|
|
|
|
|
* are instantiated by elaboration,
|
|
|
|
|
* Put modules into a map instead of
|
|
|
|
|
* a simple list.
|
|
|
|
|
*
|
1998-11-23 01:20:22 +01:00
|
|
|
* Revision 1.6 1998/11/23 00:20:22 steve
|
|
|
|
|
* NetAssign handles lvalues as pin links
|
|
|
|
|
* instead of a signal pointer,
|
|
|
|
|
* Wire attributes added,
|
|
|
|
|
* Ability to parse UDP descriptions added,
|
|
|
|
|
* XNF generates EXT records for signals with
|
|
|
|
|
* the PAD attribute.
|
|
|
|
|
*
|
1998-11-21 20:19:44 +01:00
|
|
|
* Revision 1.5 1998/11/21 19:19:44 steve
|
|
|
|
|
* Give anonymous modules a name when elaborated.
|
|
|
|
|
*
|
1998-11-11 04:13:04 +01:00
|
|
|
* Revision 1.4 1998/11/11 03:13:04 steve
|
|
|
|
|
* Handle while loops.
|
|
|
|
|
*
|
1998-11-09 19:55:33 +01:00
|
|
|
* Revision 1.3 1998/11/09 18:55:34 steve
|
|
|
|
|
* Add procedural while loops,
|
|
|
|
|
* Parse procedural for loops,
|
|
|
|
|
* Add procedural wait statements,
|
|
|
|
|
* Add constant nodes,
|
|
|
|
|
* Add XNOR logic gate,
|
|
|
|
|
* Make vvm output look a bit prettier.
|
|
|
|
|
*
|
1998-11-07 18:05:05 +01:00
|
|
|
* Revision 1.2 1998/11/07 17:05:05 steve
|
|
|
|
|
* Handle procedural conditional, and some
|
|
|
|
|
* of the conditional expressions.
|
|
|
|
|
*
|
|
|
|
|
* Elaborate signals and identifiers differently,
|
|
|
|
|
* allowing the netlist to hold signal information.
|
|
|
|
|
*
|
1998-11-04 00:28:49 +01:00
|
|
|
* Revision 1.1 1998/11/03 23:28:56 steve
|
|
|
|
|
* Introduce verilog to CVS.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|