1999-10-31 21:08:24 +01:00
|
|
|
/*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
|
1999-10-31 21:08:24 +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)
|
2000-11-04 06:06:04 +01:00
|
|
|
#ident "$Id: elab_net.cc,v 1.54 2000/11/04 05:06:04 steve Exp $"
|
1999-10-31 21:08:24 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "PExpr.h"
|
|
|
|
|
# include "netlist.h"
|
2000-02-16 04:58:27 +01:00
|
|
|
# include "netmisc.h"
|
2000-03-17 22:50:25 +01:00
|
|
|
# include "compiler.h"
|
1999-10-31 21:08:24 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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,
|
|
|
|
|
unsigned width,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
1999-10-31 21:08:24 +01:00
|
|
|
{
|
|
|
|
|
switch (op_) {
|
2000-01-13 04:35:35 +01:00
|
|
|
case '*':
|
|
|
|
|
return elaborate_net_mul_(des, path, width, rise, fall, decay);
|
2000-09-17 23:26:15 +02:00
|
|
|
case '%':
|
|
|
|
|
return elaborate_net_mod_(des, path, width, rise, fall, decay);
|
2000-04-01 23:40:22 +02:00
|
|
|
case '/':
|
|
|
|
|
return elaborate_net_div_(des, path, width, rise, fall, decay);
|
1999-10-31 21:08:24 +01:00
|
|
|
case '+':
|
|
|
|
|
case '-':
|
|
|
|
|
return elaborate_net_add_(des, path, width, rise, fall, decay);
|
2000-02-16 04:58:27 +01:00
|
|
|
case '|': // Bitwise OR
|
|
|
|
|
case '&':
|
|
|
|
|
case '^':
|
|
|
|
|
case 'X': // Exclusing NOR
|
|
|
|
|
return elaborate_net_bit_(des, path, width, rise, fall, decay);
|
1999-11-05 22:45:19 +01:00
|
|
|
case 'E':
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'n':
|
1999-11-15 00:43:45 +01:00
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
case 'L': // <=
|
|
|
|
|
case 'G': // >=
|
1999-11-05 22:45:19 +01:00
|
|
|
return elaborate_net_cmp_(des, path, width, rise, fall, decay);
|
1999-12-16 04:46:39 +01:00
|
|
|
case 'a': // && (logical and)
|
|
|
|
|
case 'o': // || (logical or)
|
|
|
|
|
return elaborate_net_log_(des, path, width, rise, fall, decay);
|
1999-11-14 21:24:28 +01:00
|
|
|
case 'l': // <<
|
|
|
|
|
case 'r': // >>
|
|
|
|
|
return elaborate_net_shift_(des, path, width, rise, fall, decay);
|
1999-10-31 21:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path, width, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*osig;
|
|
|
|
|
NetNode*gate;
|
|
|
|
|
NetNode*gate_t;
|
|
|
|
|
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '^': // XOR
|
2000-01-18 05:53:40 +01:00
|
|
|
case 'X': // XNOR
|
1999-10-31 21:08:24 +01:00
|
|
|
case '&': // AND
|
|
|
|
|
case '|': // Bitwise OR
|
2000-02-16 04:58:27 +01:00
|
|
|
assert(0);
|
1999-10-31 21:08:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'E': // === (Case equals)
|
|
|
|
|
case 'e': // ==
|
|
|
|
|
case 'n': // !=
|
1999-11-15 00:43:45 +01:00
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
case 'G': // >=
|
|
|
|
|
case 'L': // <=
|
1999-11-05 22:45:19 +01:00
|
|
|
assert(0);
|
1999-10-31 21:08:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
|
case 'r':
|
1999-11-14 21:24:28 +01:00
|
|
|
assert(0);
|
1999-10-31 21:08:24 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cerr << get_line() << ": internal error: unsupported"
|
|
|
|
|
" combinational operator (" << op_ << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
osig = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Elaborate the structural +/- as an AddSub object. Connect DataA and
|
|
|
|
|
* DataB to the parameters, and connect the output signal to the
|
|
|
|
|
* Result. In this context, the device is a combinational adder with
|
|
|
|
|
* fixed direction, so leave Add_Sub unconnected and set the
|
|
|
|
|
* LPM_Direction property.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net_add_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
1999-10-31 21:08:24 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path, lwidth, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*osig;
|
|
|
|
|
NetNode*gate;
|
|
|
|
|
NetNode*gate_t;
|
|
|
|
|
|
|
|
|
|
string name = des->local_symbol(path);
|
|
|
|
|
unsigned width = lsig->pin_count();
|
|
|
|
|
if (rsig->pin_count() > lsig->pin_count())
|
|
|
|
|
width = rsig->pin_count();
|
|
|
|
|
|
1999-12-16 03:42:14 +01:00
|
|
|
// If the desired output size if creater then the largest
|
|
|
|
|
// operand, then include the carry of the adder as an output.
|
|
|
|
|
unsigned owidth = width;
|
|
|
|
|
if (lwidth > owidth)
|
|
|
|
|
owidth = width + 1;
|
|
|
|
|
|
2000-04-28 23:00:28 +02:00
|
|
|
// Pad out the operands, if necessary, the match the width of
|
|
|
|
|
// the adder device.
|
|
|
|
|
if (lsig->pin_count() < width)
|
|
|
|
|
lsig = pad_to_width(des, path, lsig, width);
|
|
|
|
|
|
|
|
|
|
if (rsig->pin_count() < width)
|
|
|
|
|
rsig = pad_to_width(des, path, rsig, width);
|
|
|
|
|
|
1999-10-31 21:08:24 +01:00
|
|
|
// Make the adder as wide as the widest operand
|
2000-06-03 04:13:15 +02:00
|
|
|
osig = new NetTmp(scope, des->local_symbol(path), owidth);
|
1999-10-31 21:08:24 +01:00
|
|
|
NetAddSub*adder = new NetAddSub(name, width);
|
|
|
|
|
|
|
|
|
|
// Connect the adder to the various parts.
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(lsig->pin(idx), adder->pin_DataA(idx));
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(rsig->pin(idx), adder->pin_DataB(idx));
|
1999-12-16 03:42:14 +01:00
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
1999-10-31 21:08:24 +01:00
|
|
|
connect(osig->pin(idx), adder->pin_Result(idx));
|
1999-12-16 03:42:14 +01:00
|
|
|
if (owidth > width)
|
|
|
|
|
connect(osig->pin(width), adder->pin_Cout());
|
1999-10-31 21:08:24 +01:00
|
|
|
|
|
|
|
|
gate = adder;
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '+':
|
|
|
|
|
gate->attribute("LPM_Direction", "ADD");
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
gate->attribute("LPM_Direction", "SUB");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-02-16 04:58:27 +01:00
|
|
|
/*
|
|
|
|
|
* Elaborate various bitwise logic operators. These are all similar in
|
|
|
|
|
* that they take operants of equal width, and each bit does not
|
|
|
|
|
* affect any other bits. Also common about all this is how bit widths
|
|
|
|
|
* of the operands are handled, when they do not match.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net_bit_(Design*des, const string&path,
|
|
|
|
|
unsigned width,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
2000-02-16 04:58:27 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, width, 0, 0, 0),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path, width, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (lsig->pin_count() < rsig->pin_count())
|
|
|
|
|
lsig = pad_to_width(des, path, lsig, rsig->pin_count());
|
|
|
|
|
if (rsig->pin_count() < lsig->pin_count())
|
|
|
|
|
rsig = pad_to_width(des, path, rsig, lsig->pin_count());
|
|
|
|
|
|
|
|
|
|
if (lsig->pin_count() != rsig->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": internal error: lsig pin count ("
|
|
|
|
|
<< lsig->pin_count() << ") != rsig pin count ("
|
|
|
|
|
<< rsig->pin_count() << ")." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(lsig->pin_count() == rsig->pin_count());
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE,
|
2000-02-16 04:58:27 +01:00
|
|
|
lsig->pin_count());
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '^': // XOR
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::XOR);
|
2000-02-16 04:58:27 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(idx));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(idx));
|
|
|
|
|
connect(gate->pin(0), osig->pin(idx));
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'X': // XNOR
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::XNOR);
|
2000-02-16 04:58:27 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(idx));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(idx));
|
|
|
|
|
connect(gate->pin(0), osig->pin(idx));
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '&': // AND
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::AND);
|
2000-02-16 04:58:27 +01:00
|
|
|
connect(gate->pin(1), lsig->pin(idx));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(idx));
|
|
|
|
|
connect(gate->pin(0), osig->pin(idx));
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '|': // Bitwise OR
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*gate = new NetLogic(scope, des->local_symbol(path),
|
2000-02-16 04:58:27 +01:00
|
|
|
3, NetLogic::OR);
|
|
|
|
|
connect(gate->pin(1), lsig->pin(idx));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(idx));
|
|
|
|
|
connect(gate->pin(0), osig->pin(idx));
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(lsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(rsig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-05 22:45:19 +01:00
|
|
|
/*
|
2000-01-11 05:20:57 +01:00
|
|
|
* Elaborate the various binary comparison operators. The comparison
|
|
|
|
|
* operators return a single bit result, no matter what, so the left
|
|
|
|
|
* and right values can have their own size. The only restriction is
|
|
|
|
|
* that they have the same size.
|
1999-11-05 22:45:19 +01:00
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net_cmp_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
1999-11-05 22:45:19 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-11 05:20:57 +01:00
|
|
|
unsigned dwidth = lsig->pin_count();
|
|
|
|
|
if (rsig->pin_count() > dwidth) dwidth = rsig->pin_count();
|
|
|
|
|
|
|
|
|
|
NetNet*zero = 0;
|
|
|
|
|
if (lsig->pin_count() != rsig->pin_count()) {
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), verinum::V0);
|
|
|
|
|
des->add_node(tmp);
|
2000-05-02 02:58:11 +02:00
|
|
|
zero = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-11 05:20:57 +01:00
|
|
|
connect(tmp->pin(0), zero->pin(0));
|
|
|
|
|
}
|
1999-11-05 22:45:19 +01:00
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
1999-11-05 22:45:19 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
NetNode*gate;
|
2000-01-11 05:20:57 +01:00
|
|
|
//NetNode*gate_t;
|
1999-11-05 22:45:19 +01:00
|
|
|
|
|
|
|
|
switch (op_) {
|
1999-11-15 00:43:45 +01:00
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
case 'L':
|
|
|
|
|
case 'G': {
|
2000-01-11 05:20:57 +01:00
|
|
|
NetCompare*cmp = new
|
|
|
|
|
NetCompare(des->local_symbol(path), dwidth);
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
1999-11-15 00:43:45 +01:00
|
|
|
connect(cmp->pin_DataA(idx), lsig->pin(idx));
|
2000-01-11 05:20:57 +01:00
|
|
|
for (unsigned idx = lsig->pin_count(); idx < dwidth ; idx += 1)
|
|
|
|
|
connect(cmp->pin_DataA(idx), zero->pin(0));
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
1999-11-15 00:43:45 +01:00
|
|
|
connect(cmp->pin_DataB(idx), rsig->pin(idx));
|
2000-01-11 05:20:57 +01:00
|
|
|
for (unsigned idx = rsig->pin_count(); idx < dwidth ; idx += 1)
|
|
|
|
|
connect(cmp->pin_DataB(idx), zero->pin(0));
|
|
|
|
|
|
1999-11-15 00:43:45 +01:00
|
|
|
switch (op_) {
|
|
|
|
|
case '<':
|
|
|
|
|
connect(cmp->pin_ALB(), osig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
case '>':
|
|
|
|
|
connect(cmp->pin_AGB(), osig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
case 'L':
|
|
|
|
|
connect(cmp->pin_ALEB(), osig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
case 'G':
|
|
|
|
|
connect(cmp->pin_AGEB(), osig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
gate = cmp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-05 22:45:19 +01:00
|
|
|
case 'E': // Case equals (===)
|
|
|
|
|
// The comparison generates gates to bitwise compare
|
|
|
|
|
// each pair, and AND all the comparison results.
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
1999-11-05 22:45:19 +01:00
|
|
|
1+lsig->pin_count(),
|
|
|
|
|
NetLogic::AND);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
2000-01-11 05:20:57 +01:00
|
|
|
for (unsigned idx = 0 ; idx < dwidth ; idx += 1) {
|
|
|
|
|
NetCaseCmp*cmp = new NetCaseCmp(des->local_symbol(path));
|
|
|
|
|
|
|
|
|
|
if (idx < lsig->pin_count())
|
|
|
|
|
connect(cmp->pin(1), lsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(1), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
if (idx < rsig->pin_count())
|
|
|
|
|
connect(cmp->pin(2), rsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(2), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
connect(cmp->pin(0), gate->pin(idx+1));
|
|
|
|
|
des->add_node(cmp);
|
1999-11-05 22:45:19 +01:00
|
|
|
|
|
|
|
|
// Attach a label to this intermediate wire
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
1999-11-05 22:45:19 +01:00
|
|
|
NetNet::WIRE);
|
|
|
|
|
tmp->local_flag(true);
|
2000-01-11 05:20:57 +01:00
|
|
|
connect(cmp->pin(0), tmp->pin(0));
|
1999-11-05 22:45:19 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'e': // ==
|
2000-07-08 06:59:20 +02:00
|
|
|
|
|
|
|
|
/* Handle the special case of single bit compare with a
|
|
|
|
|
single XNOR gate. This is easy and direct. */
|
|
|
|
|
if (dwidth == 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
2000-07-08 06:59:20 +02:00
|
|
|
3, NetLogic::XNOR);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Oh well, do the general case. */
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
1+dwidth,NetLogic::AND);
|
1999-11-05 22:45:19 +01:00
|
|
|
connect(gate->pin(0), osig->pin(0));
|
2000-01-11 05:20:57 +01:00
|
|
|
for (unsigned idx = 0 ; idx < dwidth ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*cmp = new NetLogic(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
3, NetLogic::XNOR);
|
|
|
|
|
if (idx < lsig->pin_count())
|
|
|
|
|
connect(cmp->pin(1), lsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(1), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
if (idx < rsig->pin_count())
|
|
|
|
|
connect(cmp->pin(2), rsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(2), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
connect(cmp->pin(0), gate->pin(idx+1));
|
|
|
|
|
des->add_node(cmp);
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
NetNet::WIRE);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
connect(cmp->pin(0), tmp->pin(0));
|
1999-11-05 22:45:19 +01:00
|
|
|
}
|
2000-07-08 06:59:20 +02:00
|
|
|
|
1999-11-05 22:45:19 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'n': // !=
|
2000-07-08 06:59:20 +02:00
|
|
|
|
|
|
|
|
/* Handle the special case of single bit compare with a
|
|
|
|
|
single XOR gate. This is easy and direct. */
|
|
|
|
|
if (dwidth == 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
2000-07-08 06:59:20 +02:00
|
|
|
3, NetLogic::XOR);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
1+dwidth, NetLogic::OR);
|
1999-11-05 22:45:19 +01:00
|
|
|
connect(gate->pin(0), osig->pin(0));
|
2000-07-06 20:13:24 +02:00
|
|
|
for (unsigned idx = 0 ; idx < dwidth ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*cmp = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::XOR);
|
2000-01-11 05:20:57 +01:00
|
|
|
if (idx < lsig->pin_count())
|
|
|
|
|
connect(cmp->pin(1), lsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(1), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
if (idx < rsig->pin_count())
|
|
|
|
|
connect(cmp->pin(2), rsig->pin(idx));
|
|
|
|
|
else
|
|
|
|
|
connect(cmp->pin(2), zero->pin(0));
|
|
|
|
|
|
|
|
|
|
connect(cmp->pin(0), gate->pin(idx+1));
|
|
|
|
|
des->add_node(cmp);
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
NetNet::WIRE);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
connect(cmp->pin(0), tmp->pin(0));
|
1999-11-05 22:45:19 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-01 23:40:22 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate a divider gate.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net_div_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
2000-04-01 23:40:22 +02:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) return 0;
|
|
|
|
|
NetNet*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (rsig == 0) return 0;
|
|
|
|
|
|
|
|
|
|
unsigned rwidth = lsig->pin_count();
|
|
|
|
|
if (rsig->pin_count() > rwidth)
|
|
|
|
|
rwidth = rsig->pin_count();
|
|
|
|
|
NetDivide*div = new NetDivide(des->local_symbol(path), rwidth,
|
|
|
|
|
lsig->pin_count(),
|
|
|
|
|
rsig->pin_count());
|
|
|
|
|
des->add_node(div);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(div->pin_DataA(idx), lsig->pin(idx));
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(div->pin_DataB(idx), rsig->pin(idx));
|
|
|
|
|
|
|
|
|
|
if (lwidth == 0) lwidth = rwidth;
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
2000-04-01 23:40:22 +02:00
|
|
|
NetNet::IMPLICIT, lwidth);
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
unsigned cnt = osig->pin_count();
|
|
|
|
|
if (cnt > rwidth) cnt = rwidth;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
|
|
|
|
connect(div->pin_Result(idx), osig->pin(idx));
|
|
|
|
|
|
|
|
|
|
/* If the lvalue is larger then the result, then pad the
|
|
|
|
|
output with constant 0. */
|
|
|
|
|
if (cnt < osig->pin_count()) {
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), verinum::V0);
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
for (unsigned idx = cnt ; idx < osig->pin_count() ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), tmp->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-17 23:26:15 +02:00
|
|
|
/*
|
|
|
|
|
* Elaborate a modulo gate.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEBinary::elaborate_net_mod_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
|
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) return 0;
|
|
|
|
|
NetNet*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (rsig == 0) return 0;
|
|
|
|
|
|
|
|
|
|
unsigned rwidth = lsig->pin_count();
|
|
|
|
|
if (rsig->pin_count() > rwidth)
|
|
|
|
|
rwidth = rsig->pin_count();
|
|
|
|
|
NetModulo*mod = new NetModulo(des->local_symbol(path), rwidth,
|
|
|
|
|
lsig->pin_count(),
|
|
|
|
|
rsig->pin_count());
|
|
|
|
|
des->add_node(mod);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(mod->pin_DataA(idx), lsig->pin(idx));
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(mod->pin_DataB(idx), rsig->pin(idx));
|
|
|
|
|
|
|
|
|
|
if (lwidth == 0) lwidth = rwidth;
|
|
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
|
|
|
|
NetNet::IMPLICIT, lwidth);
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
unsigned cnt = osig->pin_count();
|
|
|
|
|
if (cnt > rwidth) cnt = rwidth;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
|
|
|
|
connect(mod->pin_Result(idx), osig->pin(idx));
|
|
|
|
|
|
|
|
|
|
/* If the lvalue is larger then the result, then pad the
|
|
|
|
|
output with constant 0. */
|
|
|
|
|
if (cnt < osig->pin_count()) {
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), verinum::V0);
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
for (unsigned idx = cnt ; idx < osig->pin_count() ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), tmp->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
NetNet* PEBinary::elaborate_net_log_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0),
|
|
|
|
|
*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
left_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (rsig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Cannot elaborate ";
|
|
|
|
|
right_->dump(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetLogic*gate;
|
|
|
|
|
NetLogic*gate_t;
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case 'a':
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::AND);
|
1999-12-16 04:46:39 +01:00
|
|
|
break;
|
|
|
|
|
case 'o':
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
3, NetLogic::OR);
|
1999-12-16 04:46:39 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
|
|
|
|
|
// The first OR gate returns 1 if the left value is true...
|
|
|
|
|
if (lsig->pin_count() > 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
gate_t = new NetLogic(scope, des->local_symbol(path),
|
1999-12-16 04:46:39 +01:00
|
|
|
1+lsig->pin_count(), NetLogic::OR);
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(gate_t->pin(idx+1), lsig->pin(idx));
|
2000-03-16 20:03:03 +01:00
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
connect(gate->pin(1), gate_t->pin(0));
|
2000-03-16 20:03:03 +01:00
|
|
|
|
|
|
|
|
/* The reduced logical value is a new nexus, create a
|
|
|
|
|
temporary signal to represent it. */
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*tmp = new NetTmp(scope, des->local_symbol(path));
|
2000-03-16 20:03:03 +01:00
|
|
|
connect(gate->pin(1), tmp->pin(0));
|
|
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
des->add_node(gate_t);
|
2000-03-16 20:03:03 +01:00
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
} else {
|
|
|
|
|
connect(gate->pin(1), lsig->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The second OR gate returns 1 if the right value is true...
|
|
|
|
|
if (rsig->pin_count() > 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
gate_t = new NetLogic(scope, des->local_symbol(path),
|
1999-12-16 04:46:39 +01:00
|
|
|
1+rsig->pin_count(), NetLogic::OR);
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(gate_t->pin(idx+1), rsig->pin(idx));
|
|
|
|
|
connect(gate->pin(2), gate_t->pin(0));
|
2000-03-16 20:03:03 +01:00
|
|
|
|
|
|
|
|
/* The reduced logical value is a new nexus, create a
|
|
|
|
|
temporary signal to represent it. */
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*tmp = new NetTmp(scope, des->local_symbol(path));
|
2000-03-16 20:03:03 +01:00
|
|
|
connect(gate->pin(2), tmp->pin(0));
|
|
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
des->add_node(gate_t);
|
2000-03-16 20:03:03 +01:00
|
|
|
|
1999-12-16 04:46:39 +01:00
|
|
|
} else {
|
|
|
|
|
connect(gate->pin(2), rsig->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The output is the AND/OR of the two logic values.
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
1999-12-16 04:46:39 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
connect(gate->pin(0), osig->pin(0));
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-13 04:35:35 +01:00
|
|
|
NetNet* PEBinary::elaborate_net_mul_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2000-01-13 04:35:35 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) return 0;
|
|
|
|
|
NetNet*rsig = right_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (rsig == 0) return 0;
|
|
|
|
|
|
|
|
|
|
unsigned rwidth = lsig->pin_count() + rsig->pin_count();
|
|
|
|
|
NetMult*mult = new NetMult(des->local_symbol(path), rwidth,
|
|
|
|
|
lsig->pin_count(),
|
|
|
|
|
rsig->pin_count());
|
|
|
|
|
des->add_node(mult);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(mult->pin_DataA(idx), lsig->pin(idx));
|
|
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(mult->pin_DataB(idx), rsig->pin(idx));
|
|
|
|
|
|
|
|
|
|
if (lwidth == 0) lwidth = rwidth;
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
2000-01-13 04:35:35 +01:00
|
|
|
NetNet::IMPLICIT, lwidth);
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
unsigned cnt = osig->pin_count();
|
|
|
|
|
if (cnt > rwidth) cnt = rwidth;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < cnt ; idx += 1)
|
|
|
|
|
connect(mult->pin_Result(idx), osig->pin(idx));
|
|
|
|
|
|
|
|
|
|
/* If the lvalue is larger then the result, then pad the
|
|
|
|
|
output with constant 0. */
|
|
|
|
|
if (cnt < osig->pin_count()) {
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), verinum::V0);
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
for (unsigned idx = cnt ; idx < osig->pin_count() ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), tmp->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-14 21:24:28 +01:00
|
|
|
NetNet* PEBinary::elaborate_net_shift_(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
1999-11-14 21:24:28 +01:00
|
|
|
NetNet*lsig = left_->elaborate_net(des, path, lwidth, 0, 0, 0);
|
|
|
|
|
if (lsig == 0) return 0;
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
if (lsig->pin_count() > lwidth)
|
|
|
|
|
lwidth = lsig->pin_count();
|
|
|
|
|
|
1999-11-14 21:24:28 +01:00
|
|
|
/* Handle the special case of a constant shift amount. There
|
|
|
|
|
is no reason in this case to create a gate at all, just
|
|
|
|
|
connect the lsig to the osig with the bit positions
|
|
|
|
|
shifted. */
|
|
|
|
|
if (verinum*rval = right_->eval_const(des, path)) {
|
|
|
|
|
assert(rval->is_defined());
|
|
|
|
|
unsigned dist = rval->as_ulong();
|
|
|
|
|
if (dist > lsig->pin_count())
|
|
|
|
|
dist = lsig->pin_count();
|
|
|
|
|
|
|
|
|
|
/* Very special case, constant 0 shift. */
|
|
|
|
|
if (dist == 0) return lsig;
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
|
|
|
|
NetNet::WIRE, lsig->pin_count());
|
1999-11-14 21:24:28 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
|
|
|
|
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
|
|
|
|
|
des->add_node(zero);
|
|
|
|
|
|
|
|
|
|
if (op_ == 'l') {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < dist ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), zero->pin(0));
|
|
|
|
|
for (idx = dist ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), lsig->pin(idx-dist));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
assert(op_ == 'r');
|
|
|
|
|
unsigned idx;
|
|
|
|
|
unsigned keep = lsig->pin_count()-dist;
|
|
|
|
|
for (idx = 0 ; idx < keep ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), lsig->pin(idx+dist));
|
|
|
|
|
for (idx = keep ; idx < lsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(osig->pin(idx), zero->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
// Calculate the number of useful bits for the shift amount,
|
|
|
|
|
// and elaborate the right_ expression as the shift amount.
|
1999-11-14 21:24:28 +01:00
|
|
|
unsigned dwid = 0;
|
2000-01-02 22:45:31 +01:00
|
|
|
while ((1 << dwid) < lwidth)
|
1999-11-14 21:24:28 +01:00
|
|
|
dwid += 1;
|
|
|
|
|
|
|
|
|
|
NetNet*rsig = right_->elaborate_net(des, path, dwid, 0, 0, 0);
|
|
|
|
|
if (rsig == 0) return 0;
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
// Make the shift device itself, and the output
|
|
|
|
|
// NetNet. Connect the Result output pins to the osig signal
|
1999-11-14 21:24:28 +01:00
|
|
|
NetCLShift*gate = new NetCLShift(des->local_symbol(path),
|
2000-01-02 22:45:31 +01:00
|
|
|
lwidth, rsig->pin_count());
|
1999-11-14 21:24:28 +01:00
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
2000-01-02 22:45:31 +01:00
|
|
|
NetNet::WIRE, lwidth);
|
1999-11-14 21:24:28 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
for (unsigned idx = 0 ; idx < lwidth ; idx += 1)
|
1999-11-14 21:24:28 +01:00
|
|
|
connect(osig->pin(idx), gate->pin_Result(idx));
|
2000-01-02 22:45:31 +01:00
|
|
|
|
|
|
|
|
// Connect the lsig (the left expression) to the Data input,
|
|
|
|
|
// and pad it if necessary with constant zeros.
|
|
|
|
|
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
|
1999-11-14 21:24:28 +01:00
|
|
|
connect(lsig->pin(idx), gate->pin_Data(idx));
|
2000-01-02 22:45:31 +01:00
|
|
|
|
|
|
|
|
if (lsig->pin_count() < lwidth) {
|
|
|
|
|
NetConst*zero = new NetConst(des->local_symbol(path), verinum::V0);
|
2000-05-02 02:58:11 +02:00
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path));
|
2000-01-02 22:45:31 +01:00
|
|
|
des->add_node(zero);
|
2000-01-02 23:07:09 +01:00
|
|
|
connect(zero->pin(0), tmp->pin(0));
|
2000-01-02 22:45:31 +01:00
|
|
|
for (unsigned idx = lsig->pin_count() ; idx < lwidth ; idx += 1)
|
|
|
|
|
connect(zero->pin(0), gate->pin_Data(idx));
|
1999-11-14 21:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
// Connect the rsig (the shift amount expression) to the
|
|
|
|
|
// Distance input.
|
1999-11-14 21:24:28 +01:00
|
|
|
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
|
|
|
|
|
connect(rsig->pin(idx), gate->pin_Distance(idx));
|
|
|
|
|
|
|
|
|
|
if (op_ == 'r') {
|
2000-05-07 21:40:26 +02:00
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path));
|
1999-11-14 21:24:28 +01:00
|
|
|
NetConst*dir = new NetConst(des->local_symbol(path), verinum::V1);
|
|
|
|
|
connect(dir->pin(0), gate->pin_Direction());
|
2000-05-07 21:40:26 +02:00
|
|
|
connect(tmp->pin(0), gate->pin_Direction());
|
1999-11-14 21:24:28 +01:00
|
|
|
des->add_node(dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-02 05:08:10 +01:00
|
|
|
/*
|
|
|
|
|
* The concatenation operator, as a net, is a wide signal that is
|
|
|
|
|
* connected to all the pins of the elaborated expression nets.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEConcat::elaborate_net(Design*des, const string&path,
|
|
|
|
|
unsigned,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
1999-12-02 05:08:10 +01:00
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
1999-12-02 05:08:10 +01:00
|
|
|
svector<NetNet*>nets (parms_.count());
|
|
|
|
|
unsigned pins = 0;
|
|
|
|
|
unsigned errors = 0;
|
2000-10-08 06:59:36 +02:00
|
|
|
unsigned repeat = 1;
|
1999-12-02 05:08:10 +01:00
|
|
|
|
|
|
|
|
if (repeat_) {
|
|
|
|
|
verinum*rep = repeat_->eval_const(des, path);
|
|
|
|
|
if (rep == 0) {
|
|
|
|
|
cerr << get_line() << ": internal error: Unable to "
|
|
|
|
|
<< "evaluate constant repeat expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-08 06:59:36 +02:00
|
|
|
repeat = rep->as_ulong();
|
1999-12-02 05:08:10 +01:00
|
|
|
|
2000-10-08 06:59:36 +02:00
|
|
|
if (repeat == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Invalid repeat value."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
delete rep;
|
|
|
|
|
return 0;
|
1999-12-02 05:08:10 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elaborate the operands of the concatenation. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
2000-09-26 07:05:58 +02:00
|
|
|
|
2000-10-14 04:23:02 +02:00
|
|
|
if (parms_[idx] == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Empty expressions "
|
|
|
|
|
<< "not allowed in concatenations." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-26 07:05:58 +02:00
|
|
|
/* Look for the special case of an unsized number in a
|
|
|
|
|
concatenation expression. Mark this as an error, but
|
|
|
|
|
allow elaboration to continue to see if I can find
|
|
|
|
|
more errors. */
|
|
|
|
|
|
|
|
|
|
if (PENumber*tmp = dynamic_cast<PENumber*>(parms_[idx])) {
|
|
|
|
|
if (tmp->value().has_len() == false) {
|
|
|
|
|
cerr << get_line() << ": error: Number "
|
|
|
|
|
<< tmp->value() << " with indefinite size"
|
|
|
|
|
<< " in concatenation." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-02 05:08:10 +01:00
|
|
|
nets[idx] = parms_[idx]->elaborate_net(des, path, 0,
|
|
|
|
|
rise,fall,decay);
|
|
|
|
|
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,
|
2000-10-08 06:59:36 +02:00
|
|
|
which is opposite from how they are given in the list.
|
|
|
|
|
|
|
|
|
|
Allow for a repeat count other then 1 by repeating the
|
|
|
|
|
connect loop as many times as necessary. */
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetNet(scope, des->local_symbol(path),
|
2000-10-08 06:59:36 +02:00
|
|
|
NetNet::IMPLICIT, pins * repeat);
|
|
|
|
|
|
1999-12-02 05:08:10 +01:00
|
|
|
pins = 0;
|
2000-10-08 06:59:36 +02:00
|
|
|
for (unsigned rpt = 0 ; rpt < repeat ; rpt += 1)
|
|
|
|
|
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;
|
|
|
|
|
}
|
1999-12-02 05:08:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
osig->local_flag(true);
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
NetNet* PEIdent::elaborate_net(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
1999-11-21 01:13:08 +01:00
|
|
|
{
|
1999-11-30 05:33:41 +01:00
|
|
|
NetScope*scope = des->find_scope(path);
|
2000-05-02 05:13:30 +02:00
|
|
|
NetNet*sig = des->find_signal(scope, text_);
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
/* If the identifier is a memory instead of a signal,
|
|
|
|
|
then handle it elsewhere. Create a RAM. */
|
2000-05-02 05:13:30 +02:00
|
|
|
if (NetMemory*mem = des->find_memory(scope, text_))
|
1999-11-21 01:13:08 +01:00
|
|
|
return elaborate_net_ram_(des, path, mem, lwidth,
|
|
|
|
|
rise, fall, decay);
|
|
|
|
|
|
|
|
|
|
|
2000-03-08 05:36:53 +01:00
|
|
|
if (const NetExpr*pe = des->find_parameter(scope, text_)) {
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
const NetEConst*pc = dynamic_cast<const NetEConst*>(pe);
|
|
|
|
|
assert(pc);
|
|
|
|
|
verinum pvalue = pc->value();
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT,
|
1999-11-21 01:13:08 +01:00
|
|
|
pc->expr_width());
|
1999-12-17 04:38:46 +01:00
|
|
|
NetConst*cp = new NetConst(des->local_symbol(path), pvalue);
|
|
|
|
|
des->add_node(cp);
|
|
|
|
|
for (unsigned idx = 0; idx < sig->pin_count(); idx += 1)
|
|
|
|
|
connect(sig->pin(idx), cp->pin(idx));
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
1999-11-30 05:33:41 +01:00
|
|
|
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
|
2000-03-17 22:50:25 +01:00
|
|
|
|
|
|
|
|
if (warn_implicit)
|
|
|
|
|
cerr << get_line() << ": warning: implicit "
|
|
|
|
|
" definition of wire " << path << "." <<
|
|
|
|
|
text_ << "." << endl;
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
if (msb_ && lsb_) {
|
|
|
|
|
verinum*mval = msb_->eval_const(des, path);
|
|
|
|
|
if (mval == 0) {
|
|
|
|
|
cerr << msb_->get_line() << ": error: unable to "
|
|
|
|
|
"evaluate constant expression: " << *msb_ <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum*lval = lsb_->eval_const(des, path);
|
|
|
|
|
if (lval == 0) {
|
|
|
|
|
cerr << lsb_->get_line() << ": error: unable to "
|
|
|
|
|
"evaluate constant expression: " << *lsb_ <<
|
|
|
|
|
endl;
|
|
|
|
|
delete mval;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(mval);
|
|
|
|
|
assert(lval);
|
|
|
|
|
unsigned midx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
|
|
|
|
|
2000-07-15 07:13:43 +02:00
|
|
|
/* This is a part select, create a new NetNet object
|
|
|
|
|
that connects to just the desired parts of the
|
|
|
|
|
identifier. Make sure the NetNet::Type is compatible
|
2000-10-30 22:35:40 +01:00
|
|
|
with the sig type.
|
|
|
|
|
|
|
|
|
|
Be careful to check the bit ordering. If the msb is
|
|
|
|
|
less significant then the msb, then the source is
|
|
|
|
|
broken. I can hack it in order to go on, but report
|
|
|
|
|
an error. */
|
|
|
|
|
|
|
|
|
|
if (midx < lidx) {
|
|
|
|
|
cerr << get_line() << ": error: part select "
|
|
|
|
|
<< sig->name() << "[" << mval->as_long() << ":"
|
|
|
|
|
<< lval->as_long() << "] "
|
|
|
|
|
<< "has bit order reversed." << endl;
|
|
|
|
|
des->errors += 1;
|
1999-11-21 01:13:08 +01:00
|
|
|
|
2000-10-30 22:35:40 +01:00
|
|
|
unsigned tmp = midx;
|
|
|
|
|
midx = lidx;
|
|
|
|
|
lidx = tmp;
|
|
|
|
|
}
|
1999-11-21 01:13:08 +01:00
|
|
|
|
2000-10-30 22:35:40 +01:00
|
|
|
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
|
|
|
|
sig->type(), midx-lidx+1);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
if (tmp->pin_count() > sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": bit select out of "
|
|
|
|
|
<< "range for " << sig->name() << endl;
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
1999-11-21 01:13:08 +01:00
|
|
|
|
2000-10-30 22:35:40 +01:00
|
|
|
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
|
|
|
|
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
2000-07-15 07:13:43 +02:00
|
|
|
|
2000-10-30 22:35:40 +01:00
|
|
|
sig = tmp;
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (msb_) {
|
|
|
|
|
verinum*mval = msb_->eval_const(des, path);
|
|
|
|
|
if (mval == 0) {
|
|
|
|
|
cerr << get_line() << ": index of " << text_ <<
|
|
|
|
|
" needs to be constant in this context." <<
|
|
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(mval);
|
|
|
|
|
unsigned idx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
if (idx >= sig->pin_count()) {
|
2000-03-27 06:38:15 +02:00
|
|
|
cerr << get_line() << ": index " << sig->name() <<
|
1999-11-21 01:13:08 +01:00
|
|
|
"[" << mval->as_long() << "] out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
2000-07-15 07:13:43 +02:00
|
|
|
|
|
|
|
|
/* This is a bit select, create a compatible NetNet with
|
|
|
|
|
a single bit that links to the selected bit of the
|
|
|
|
|
expression. */
|
|
|
|
|
NetNet*tmp = new NetNet(scope, des->local_symbol(path),
|
|
|
|
|
sig->type(), 1);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
connect(tmp->pin(0), sig->pin(idx));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When I run into an identifier in an expression that referrs to a
|
|
|
|
|
* memory, create a RAM port object.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEIdent::elaborate_net_ram_(Design*des, const string&path,
|
|
|
|
|
NetMemory*mem, unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
|
|
|
|
unsigned long decay) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
if (msb_ == 0) {
|
|
|
|
|
cerr << get_line() << ": error: memory reference without"
|
|
|
|
|
" the required index expression." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet*adr = msb_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
if (adr == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NetRamDq*ram = new NetRamDq(des->local_symbol(mem->name()),
|
|
|
|
|
mem, adr->pin_count());
|
|
|
|
|
des->add_node(ram);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
|
|
|
|
|
connect(ram->pin_Address(idx), adr->pin(idx));
|
|
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*osig = new NetTmp(scope, des->local_symbol(mem->name()),
|
|
|
|
|
ram->width());
|
1999-11-21 01:13:08 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < osig->pin_count() ; idx += 1)
|
|
|
|
|
connect(ram->pin_Q(idx), osig->pin(idx));
|
|
|
|
|
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Identifiers in continuous assignment l-values are limited to wires
|
|
|
|
|
* and that ilk. Detect registers and memories here and report errors.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const
|
|
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2000-05-02 05:13:30 +02:00
|
|
|
NetNet*sig = des->find_signal(scope, text_);
|
1999-11-21 01:13:08 +01:00
|
|
|
if (sig == 0) {
|
|
|
|
|
/* Don't allow memories here. Is it a memory? */
|
2000-05-02 05:13:30 +02:00
|
|
|
if (des->find_memory(scope, text_)) {
|
1999-11-21 01:13:08 +01:00
|
|
|
cerr << get_line() << ": error: memories (" << text_
|
|
|
|
|
<< ") cannot be l-values in continuous "
|
|
|
|
|
<< "assignments." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fine, create an implicit wire as an l-value. */
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, path+"."+text_, NetNet::IMPLICIT, 1);
|
2000-03-17 22:50:25 +01:00
|
|
|
|
|
|
|
|
if (warn_implicit)
|
|
|
|
|
cerr << get_line() << ": warning: implicit "
|
|
|
|
|
" definition of wire " << path << "." <<
|
|
|
|
|
text_ << "." << endl;
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
/* Don't allow registers as assign l-values. */
|
|
|
|
|
if (sig->type() == NetNet::REG) {
|
|
|
|
|
cerr << get_line() << ": error: registers (" << sig->name()
|
|
|
|
|
<< ") cannot be l-values in continuous"
|
|
|
|
|
<< " assignments." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (msb_ && lsb_) {
|
|
|
|
|
/* Detect a part select. Evaluate the bits and elaborate
|
|
|
|
|
the l-value by creating a sub-net that links to just
|
|
|
|
|
the right pins. */
|
|
|
|
|
verinum*mval = msb_->eval_const(des, path);
|
|
|
|
|
assert(mval);
|
|
|
|
|
verinum*lval = lsb_->eval_const(des, path);
|
|
|
|
|
assert(lval);
|
|
|
|
|
unsigned midx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
unsigned lidx = sig->sb_to_idx(lval->as_long());
|
|
|
|
|
|
|
|
|
|
if (midx >= lidx) {
|
2000-05-02 02:58:11 +02:00
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path),
|
1999-11-21 01:13:08 +01:00
|
|
|
midx-lidx+1);
|
|
|
|
|
if (tmp->pin_count() > sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": bit select out of "
|
|
|
|
|
<< "range for " << sig->name() << endl;
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
|
|
|
|
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
sig = tmp;
|
|
|
|
|
|
|
|
|
|
} else {
|
2000-05-02 02:58:11 +02:00
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path),
|
1999-11-21 01:13:08 +01:00
|
|
|
lidx-midx+1);
|
|
|
|
|
assert(tmp->pin_count() <= sig->pin_count());
|
|
|
|
|
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(des, path);
|
|
|
|
|
if (mval == 0) {
|
|
|
|
|
cerr << get_line() << ": index of " << text_ <<
|
2000-09-02 22:54:20 +02:00
|
|
|
" needs to be constant in l-value of assignment." <<
|
1999-11-21 01:13:08 +01:00
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(mval);
|
|
|
|
|
unsigned idx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
if (idx >= sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << "; index " << sig->name() <<
|
|
|
|
|
"[" << mval->as_long() << "] out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
2000-05-02 02:58:11 +02:00
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path), 1);
|
1999-11-21 01:13:08 +01:00
|
|
|
connect(tmp->pin(0), sig->pin(idx));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-16 06:05:15 +02:00
|
|
|
/*
|
|
|
|
|
* This method is used to elaborate identifiers that are ports to a
|
|
|
|
|
* scope. The scope is presumed to be that of the module that has the
|
|
|
|
|
* port.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
const string path = scope->name();
|
|
|
|
|
|
|
|
|
|
NetNet*sig = des->find_signal(scope, text_);
|
|
|
|
|
if (sig == 0) {
|
|
|
|
|
cerr << get_line() << ": error: no wire/reg " << text_
|
|
|
|
|
<< " in module " << scope->name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-18 06:38:57 +02:00
|
|
|
switch (sig->port_type()) {
|
|
|
|
|
case NetNet::PINPUT:
|
|
|
|
|
case NetNet::POUTPUT:
|
|
|
|
|
case NetNet::PINOUT:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* If the name matches, but the signal is not a port,
|
|
|
|
|
then the user declared the object but there is no
|
|
|
|
|
matching input/output/inout declaration. */
|
|
|
|
|
|
|
|
|
|
case NetNet::NOT_A_PORT:
|
|
|
|
|
cerr << get_line() << ": error: signal " << text_ << " in"
|
|
|
|
|
<< " module " << scope->name() << " is not a port." << endl;
|
|
|
|
|
cerr << get_line() << ": : Are you missing an input/"
|
|
|
|
|
<< "output/inout declaration?" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* This should not happen. A PWire can only become
|
|
|
|
|
PIMPLICIT if this is a udp reg port, and the make_udp
|
|
|
|
|
function should turn it into an output.... I think. */
|
|
|
|
|
|
|
|
|
|
case NetNet::PIMPLICIT:
|
|
|
|
|
cerr << get_line() << ": internal error: signal " << text_
|
|
|
|
|
<< " in module " << scope->name() << " is left as "
|
|
|
|
|
<< "port type PIMPLICIT." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-16 06:05:15 +02:00
|
|
|
|
|
|
|
|
if (msb_ && lsb_) {
|
|
|
|
|
/* Detect a part select. Evaluate the bits and elaborate
|
|
|
|
|
the l-value by creating a sub-net that links to just
|
|
|
|
|
the right pins. */
|
|
|
|
|
verinum*mval = msb_->eval_const(des, path);
|
|
|
|
|
assert(mval);
|
|
|
|
|
verinum*lval = lsb_->eval_const(des, path);
|
|
|
|
|
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(scope, des->local_symbol(path),
|
|
|
|
|
midx-lidx+1);
|
|
|
|
|
if (tmp->pin_count() > sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << ": bit select out of "
|
|
|
|
|
<< "range for " << sig->name() << endl;
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
|
|
|
|
|
connect(tmp->pin(idx-lidx), sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
sig = tmp;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path),
|
|
|
|
|
lidx-midx+1);
|
|
|
|
|
assert(tmp->pin_count() <= sig->pin_count());
|
|
|
|
|
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(des, path);
|
|
|
|
|
if (mval == 0) {
|
|
|
|
|
cerr << get_line() << ": index of " << text_ <<
|
2000-09-02 22:54:20 +02:00
|
|
|
" needs to be constant in port context." <<
|
2000-05-16 06:05:15 +02:00
|
|
|
endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(mval);
|
|
|
|
|
unsigned idx = sig->sb_to_idx(mval->as_long());
|
|
|
|
|
if (idx >= sig->pin_count()) {
|
|
|
|
|
cerr << get_line() << "; index " << sig->name() <<
|
|
|
|
|
"[" << mval->as_long() << "] out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
|
|
|
|
NetTmp*tmp = new NetTmp(scope, des->local_symbol(path), 1);
|
|
|
|
|
connect(tmp->pin(0), sig->pin(idx));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-11-05 22:45:19 +01:00
|
|
|
/*
|
|
|
|
|
* Elaborate a number as a NetConst object.
|
|
|
|
|
*/
|
|
|
|
|
NetNet* PENumber::elaborate_net(Design*des, const string&path,
|
|
|
|
|
unsigned lwidth,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
1999-11-05 22:45:19 +01:00
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2000-01-11 05:20:57 +01:00
|
|
|
/* If we are constrained by a l-value size, then just make a
|
|
|
|
|
number constant with the correct size and set as many bits
|
|
|
|
|
in that constant as make sense. Pad excess with zeros. */
|
|
|
|
|
if (lwidth > 0) {
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*net = new NetNet(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
NetNet::IMPLICIT, lwidth);
|
|
|
|
|
net->local_flag(true);
|
|
|
|
|
|
2000-08-02 00:44:26 +02:00
|
|
|
/* when expanding a constant to fit into the net, extend
|
|
|
|
|
the Vx or Vz values if they are in the sign position,
|
|
|
|
|
otherwise extend the number with 0 bits. */
|
|
|
|
|
verinum::V top_v = verinum::V0;
|
|
|
|
|
switch (value_->get(value_->len()-1)) {
|
|
|
|
|
case verinum::Vx:
|
|
|
|
|
top_v = verinum::Vx;
|
|
|
|
|
break;
|
|
|
|
|
case verinum::Vz:
|
|
|
|
|
top_v = verinum::Vz;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum num(top_v, net->pin_count());
|
2000-01-11 05:20:57 +01:00
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < num.len() && idx < value_->len(); idx += 1)
|
|
|
|
|
num.set(idx, value_->get(idx));
|
|
|
|
|
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), num);
|
2000-05-07 06:37:55 +02:00
|
|
|
for (idx = 0 ; idx < net->pin_count() ; idx += 1) {
|
|
|
|
|
tmp->pin(idx).drive0(drive0);
|
|
|
|
|
tmp->pin(idx).drive1(drive1);
|
2000-01-11 05:20:57 +01:00
|
|
|
connect(net->pin(idx), tmp->pin(idx));
|
2000-05-07 06:37:55 +02:00
|
|
|
}
|
2000-01-11 05:20:57 +01:00
|
|
|
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the number has a length, then use that to size the
|
|
|
|
|
number. Generate a constant object of exactly the user
|
|
|
|
|
specified size. */
|
|
|
|
|
if (value_->has_len()) {
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*net = new NetNet(scope, des->local_symbol(path),
|
2000-01-11 05:20:57 +01:00
|
|
|
NetNet::IMPLICIT, value_->len());
|
|
|
|
|
net->local_flag(true);
|
|
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), *value_);
|
|
|
|
|
for (unsigned idx = 0 ; idx < value_->len() ; idx += 1)
|
|
|
|
|
connect(net->pin(idx), tmp->pin(idx));
|
|
|
|
|
|
|
|
|
|
des->add_node(tmp);
|
|
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-26 07:05:58 +02:00
|
|
|
cerr << get_line() << ": warning: Number with indefinite size "
|
|
|
|
|
<< "in self-determined context." << endl;
|
|
|
|
|
|
2000-01-11 05:20:57 +01:00
|
|
|
/* None of the above tight constraints are present, so make a
|
|
|
|
|
plausible choice for the width. Try to reduce the width as
|
|
|
|
|
much as possible by eliminating high zeros of unsigned
|
|
|
|
|
numbers. */
|
1999-11-05 22:45:19 +01:00
|
|
|
unsigned width = value_->len();
|
2000-01-11 05:20:57 +01:00
|
|
|
|
|
|
|
|
if (value_->has_sign() && (value_->get(width-1) == verinum::V0)) {
|
|
|
|
|
|
|
|
|
|
/* If the number is signed, but known to be positive,
|
|
|
|
|
then reduce it down as if it were unsigned. */
|
|
|
|
|
while (width > 1) {
|
|
|
|
|
if (value_->get(width-1) != verinum::V0)
|
|
|
|
|
break;
|
|
|
|
|
width -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (value_->has_sign() == false) {
|
|
|
|
|
while ( (width > 1) && (value_->get(width-1) == verinum::V0))
|
|
|
|
|
width -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum num (verinum::V0, width);
|
|
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
|
|
|
|
num.set(idx, value_->get(idx));
|
1999-11-05 22:45:19 +01:00
|
|
|
|
2000-05-02 02:58:11 +02:00
|
|
|
NetNet*net = new NetNet(scope, des->local_symbol(path),
|
1999-11-05 22:45:19 +01:00
|
|
|
NetNet::IMPLICIT, width);
|
|
|
|
|
net->local_flag(true);
|
2000-01-11 05:20:57 +01:00
|
|
|
NetConst*tmp = new NetConst(des->local_symbol(path), num);
|
1999-12-17 04:38:46 +01:00
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1)
|
|
|
|
|
connect(net->pin(idx), tmp->pin(idx));
|
1999-11-05 22:45:19 +01:00
|
|
|
|
1999-12-17 04:38:46 +01:00
|
|
|
des->add_node(tmp);
|
1999-11-05 22:45:19 +01:00
|
|
|
return net;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-11-04 04:53:26 +01:00
|
|
|
/*
|
|
|
|
|
* Elaborate the ternary operator in a netlist by creating a LPM_MUX
|
2000-05-03 23:21:36 +02:00
|
|
|
* with width matching the result, size == 2 and 1 select input. These
|
|
|
|
|
* expressions come from code like:
|
|
|
|
|
*
|
|
|
|
|
* res = test ? a : b;
|
|
|
|
|
*
|
|
|
|
|
* The res has the width requested of this method, and the a and b
|
|
|
|
|
* expressions have their own similar widths. The test expression is
|
|
|
|
|
* only a single bit wide. The output from this function is a NetNet
|
|
|
|
|
* object the width of the <res> expression and connected to the
|
|
|
|
|
* Result pins of the LPM_MUX device. Any width not covered by the
|
|
|
|
|
* width of the mux is padded with a NetConst device.
|
1999-11-04 04:53:26 +01:00
|
|
|
*/
|
|
|
|
|
NetNet* PETernary::elaborate_net(Design*des, const string&path,
|
|
|
|
|
unsigned width,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
1999-11-04 04:53:26 +01:00
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
1999-11-04 04:53:26 +01:00
|
|
|
NetNet* expr_sig = expr_->elaborate_net(des, path, 0, 0, 0, 0);
|
|
|
|
|
NetNet* tru_sig = tru_->elaborate_net(des, path, width, 0, 0, 0);
|
|
|
|
|
NetNet* fal_sig = fal_->elaborate_net(des, path, width, 0, 0, 0);
|
|
|
|
|
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-07 23:28:51 +02:00
|
|
|
|
|
|
|
|
/* The natural width of the expression is the width of the
|
|
|
|
|
largest condition. Normally they should be the same size,
|
|
|
|
|
but if we do not get a size from the context, or the
|
|
|
|
|
expressions resist, we need to cope. */
|
|
|
|
|
unsigned iwidth = tru_sig->pin_count();
|
|
|
|
|
if (fal_sig->pin_count() > iwidth)
|
|
|
|
|
iwidth = fal_sig->pin_count();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If the width is not passed from the context, then take the
|
|
|
|
|
widest result as our width. */
|
2000-05-03 23:21:36 +02:00
|
|
|
if (width == 0)
|
2000-09-07 23:28:51 +02:00
|
|
|
width = iwidth;
|
2000-05-03 23:21:36 +02:00
|
|
|
|
|
|
|
|
assert(width >= tru_sig->pin_count());
|
2000-05-26 07:26:11 +02:00
|
|
|
|
|
|
|
|
/* If the expression has width, then generate a boolean result
|
|
|
|
|
by connecting an OR gate to calculate the truth value of
|
2000-09-07 23:28:51 +02:00
|
|
|
the result. In the end, the result needs to be a single bit. */
|
2000-05-26 07:26:11 +02:00
|
|
|
if (expr_sig->pin_count() > 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
NetLogic*log = new NetLogic(scope, des->local_symbol(path),
|
2000-05-26 07:26:11 +02:00
|
|
|
expr_sig->pin_count()+1,
|
|
|
|
|
NetLogic::OR);
|
|
|
|
|
for (unsigned idx = 0; idx < expr_sig->pin_count(); idx += 1)
|
|
|
|
|
connect(log->pin(idx+1), expr_sig->pin(idx));
|
|
|
|
|
|
|
|
|
|
NetNet*tmp = new NetTmp(scope, des->local_symbol(path));
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
connect(tmp->pin(0), log->pin(0));
|
|
|
|
|
des->add_node(log);
|
|
|
|
|
|
|
|
|
|
expr_sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-04 04:53:26 +01:00
|
|
|
assert(expr_sig->pin_count() == 1);
|
|
|
|
|
|
2000-05-03 23:21:36 +02:00
|
|
|
/* This is the width of the LPM_MUX device that I'm about to
|
|
|
|
|
create. It may be smaller then the desired output, but I'll
|
|
|
|
|
handle padding below.
|
|
|
|
|
|
2000-11-04 06:06:04 +01:00
|
|
|
Create a NetNet object wide enough to hold the
|
|
|
|
|
result. Also, pad the result values (if necessary) so that
|
|
|
|
|
the mux inputs can be fully connected. */
|
2000-05-03 23:21:36 +02:00
|
|
|
|
2000-09-07 23:28:51 +02:00
|
|
|
unsigned dwidth = (iwidth > width)? width : iwidth;
|
2000-05-03 23:21:36 +02:00
|
|
|
|
2000-09-07 23:28:51 +02:00
|
|
|
NetNet*sig = new NetNet(scope, des->local_symbol(path),
|
|
|
|
|
NetNet::WIRE, width);
|
1999-11-04 04:53:26 +01:00
|
|
|
sig->local_flag(true);
|
|
|
|
|
|
2000-11-04 06:06:04 +01:00
|
|
|
if (fal_sig->pin_count() < dwidth)
|
|
|
|
|
fal_sig = pad_to_width(des, path, fal_sig, dwidth);
|
|
|
|
|
|
|
|
|
|
if (tru_sig->pin_count() < dwidth)
|
|
|
|
|
tru_sig = pad_to_width(des, path, tru_sig, dwidth);
|
|
|
|
|
|
2000-05-03 23:21:36 +02:00
|
|
|
|
|
|
|
|
/* Make the device and connect its outputs to the osig and
|
|
|
|
|
inputs to the tru and false case nets. Also connect the
|
2000-09-07 23:28:51 +02:00
|
|
|
selector bit to the sel input.
|
|
|
|
|
|
|
|
|
|
The inputs are the 0 (false) connected to fal_sig and 1
|
2000-11-04 06:06:04 +01:00
|
|
|
(true) connected to tru_sig. */
|
2000-05-03 23:21:36 +02:00
|
|
|
|
|
|
|
|
NetMux*mux = new NetMux(des->local_symbol(path), dwidth, 2, 1);
|
1999-11-04 04:53:26 +01:00
|
|
|
connect(mux->pin_Sel(0), expr_sig->pin(0));
|
|
|
|
|
|
2000-05-03 23:21:36 +02:00
|
|
|
for (unsigned idx = 0 ; idx < dwidth ; idx += 1) {
|
1999-11-04 04:53:26 +01:00
|
|
|
connect(mux->pin_Result(idx), sig->pin(idx));
|
2000-11-04 06:06:04 +01:00
|
|
|
connect(mux->pin_Data(idx,0), fal_sig->pin(idx));
|
|
|
|
|
connect(mux->pin_Data(idx,1), tru_sig->pin(idx));
|
1999-11-04 04:53:26 +01:00
|
|
|
}
|
1999-11-06 00:36:31 +01:00
|
|
|
|
2000-09-07 23:28:51 +02:00
|
|
|
|
|
|
|
|
/* If the MUX device result is too narrow to fill out the
|
|
|
|
|
desired result, pad with zeros by creating a NetConst device. */
|
2000-05-03 23:21:36 +02:00
|
|
|
|
|
|
|
|
if (dwidth < width) {
|
|
|
|
|
verinum vpad (verinum::V0, width-dwidth);
|
2000-11-04 06:06:04 +01:00
|
|
|
NetConst*pad = new NetConst(des->local_symbol(path), vpad);
|
2000-05-03 23:21:36 +02:00
|
|
|
des->add_node(pad);
|
|
|
|
|
for (unsigned idx = dwidth ; idx < width ; idx += 1)
|
|
|
|
|
connect(sig->pin(idx), pad->pin(idx-dwidth));
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-06 00:36:31 +01:00
|
|
|
des->add_node(mux);
|
|
|
|
|
|
|
|
|
|
return sig;
|
1999-11-04 04:53:26 +01:00
|
|
|
}
|
|
|
|
|
|
2000-01-02 20:39:03 +01:00
|
|
|
NetNet* PEUnary::elaborate_net(Design*des, const string&path,
|
|
|
|
|
unsigned width,
|
|
|
|
|
unsigned long rise,
|
|
|
|
|
unsigned long fall,
|
2000-05-07 06:37:55 +02:00
|
|
|
unsigned long decay,
|
|
|
|
|
Link::strength_t drive0,
|
|
|
|
|
Link::strength_t drive1) const
|
2000-01-02 20:39:03 +01:00
|
|
|
{
|
2000-05-02 02:58:11 +02:00
|
|
|
NetScope*scope = des->find_scope(path);
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2000-02-14 07:04:52 +01:00
|
|
|
NetNet* sub_sig = expr_->elaborate_net(des, path,
|
|
|
|
|
op_=='~'?width:0,
|
2000-01-02 20:39:03 +01:00
|
|
|
0, 0, 0);
|
|
|
|
|
if (sub_sig == 0) {
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(sub_sig);
|
|
|
|
|
|
|
|
|
|
NetNet* sig;
|
|
|
|
|
NetLogic*gate;
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '~': // Bitwise NOT
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE,
|
2000-01-02 20:39:03 +01:00
|
|
|
sub_sig->pin_count());
|
|
|
|
|
sig->local_flag(true);
|
|
|
|
|
for (unsigned idx = 0 ; idx < sub_sig->pin_count() ; idx += 1) {
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
2, NetLogic::NOT);
|
2000-01-02 20:39:03 +01:00
|
|
|
connect(gate->pin(1), sub_sig->pin(idx));
|
|
|
|
|
connect(gate->pin(0), sig->pin(idx));
|
|
|
|
|
des->add_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'N': // Reduction NOR
|
|
|
|
|
case '!': // Reduction NOT
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 20:39:03 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::NOR);
|
2000-01-02 20:39:03 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '&': // Reduction AND
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 20:39:03 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::AND);
|
2000-01-02 20:39:03 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '|': // Reduction OR
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 20:39:03 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::OR);
|
2000-01-02 20:39:03 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '^': // Reduction XOR
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 20:39:03 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::XOR);
|
2000-01-02 20:39:03 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-01-02 22:45:31 +01:00
|
|
|
case 'A': // Reduction NAND (~&)
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 22:45:31 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::NAND);
|
2000-01-02 22:45:31 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 'X': // Reduction XNOR (~^)
|
2000-05-02 02:58:11 +02:00
|
|
|
sig = new NetNet(scope, des->local_symbol(path), NetNet::WIRE);
|
2000-01-02 20:39:03 +01:00
|
|
|
sig->local_flag(true);
|
2000-10-07 21:45:42 +02:00
|
|
|
gate = new NetLogic(scope, des->local_symbol(path),
|
|
|
|
|
1+sub_sig->pin_count(), NetLogic::XNOR);
|
2000-01-02 20:39:03 +01:00
|
|
|
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_node(gate);
|
|
|
|
|
gate->rise_time(rise);
|
|
|
|
|
gate->fall_time(fall);
|
|
|
|
|
gate->decay_time(decay);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
|
|
|
|
|
sig = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NetTmp*tmp = dynamic_cast<NetTmp*>(sub_sig))
|
|
|
|
|
delete tmp;
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-31 21:08:24 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: elab_net.cc,v $
|
2000-11-04 06:06:04 +01:00
|
|
|
* Revision 1.54 2000/11/04 05:06:04 steve
|
|
|
|
|
* pad different width inputs to muxes. (PR#14)
|
|
|
|
|
*
|
2000-10-30 22:35:40 +01:00
|
|
|
* Revision 1.53 2000/10/30 21:35:40 steve
|
|
|
|
|
* Detect reverse bit order in part select. (PR#33)
|
|
|
|
|
*
|
2000-10-30 21:55:53 +01:00
|
|
|
* Revision 1.52 2000/10/30 20:55:53 steve
|
|
|
|
|
* get width right for reversed part select net. (PR#33)
|
|
|
|
|
*
|
2000-10-14 04:23:02 +02:00
|
|
|
* Revision 1.51 2000/10/14 02:23:02 steve
|
|
|
|
|
* Check for missing concat subexpressions (PR#11)
|
|
|
|
|
*
|
2000-10-08 06:59:36 +02:00
|
|
|
* Revision 1.50 2000/10/08 04:59:36 steve
|
|
|
|
|
* Fix repeat concatenation with multiple expressions (PR#10)
|
|
|
|
|
*
|
2000-10-07 21:45:42 +02:00
|
|
|
* Revision 1.49 2000/10/07 19:45:42 steve
|
|
|
|
|
* Put logic devices into scopes.
|
|
|
|
|
*
|
2000-09-26 07:05:58 +02:00
|
|
|
* Revision 1.48 2000/09/26 05:05:58 steve
|
|
|
|
|
* Detect indefinite widths where definite widths are required.
|
|
|
|
|
*
|
2000-09-17 23:26:15 +02:00
|
|
|
* Revision 1.47 2000/09/17 21:26:15 steve
|
|
|
|
|
* Add support for modulus (Eric Aardoom)
|
|
|
|
|
*
|
2000-09-07 23:28:51 +02:00
|
|
|
* Revision 1.46 2000/09/07 21:28:51 steve
|
|
|
|
|
* more robust abut ternary bit widths.
|
|
|
|
|
*
|
2000-09-02 22:54:20 +02:00
|
|
|
* Revision 1.45 2000/09/02 20:54:20 steve
|
|
|
|
|
* Rearrange NetAssign to make NetAssign_ separate.
|
|
|
|
|
*
|
2000-08-18 06:38:57 +02:00
|
|
|
* Revision 1.44 2000/08/18 04:38:57 steve
|
|
|
|
|
* Proper error messages when port direction is missing.
|
|
|
|
|
*
|
2000-08-02 00:44:26 +02:00
|
|
|
* Revision 1.43 2000/08/01 22:44:26 steve
|
|
|
|
|
* Extend x or z that is top bit of a constant.
|
|
|
|
|
*
|
2000-07-15 07:13:43 +02:00
|
|
|
* Revision 1.42 2000/07/15 05:13:43 steve
|
|
|
|
|
* Detect muxing Vz as a bufufN.
|
|
|
|
|
*
|
2000-07-08 06:59:20 +02:00
|
|
|
* Revision 1.41 2000/07/08 04:59:20 steve
|
|
|
|
|
* Eleminate reduction gate for 1-bit compares.
|
|
|
|
|
*
|
2000-07-06 20:13:24 +02:00
|
|
|
* Revision 1.40 2000/07/06 18:13:24 steve
|
|
|
|
|
* Connect all the l and r bits of a NE expression.
|
|
|
|
|
*
|
2000-06-03 04:13:15 +02:00
|
|
|
* Revision 1.39 2000/06/03 02:13:15 steve
|
|
|
|
|
* Output signal of + is a temporary.
|
|
|
|
|
*
|
2000-05-26 07:26:11 +02:00
|
|
|
* Revision 1.38 2000/05/26 05:26:11 steve
|
|
|
|
|
* Handle wide conditions in ternary operator.
|
|
|
|
|
*
|
2000-05-16 06:05:15 +02:00
|
|
|
* Revision 1.37 2000/05/16 04:05:15 steve
|
|
|
|
|
* Module ports are really special PEIdent
|
|
|
|
|
* expressions, because a name can be used
|
|
|
|
|
* many places in the port list.
|
|
|
|
|
*
|
2000-05-07 22:48:14 +02:00
|
|
|
* Revision 1.36 2000/05/07 20:48:14 steve
|
|
|
|
|
* Properly elaborate repeat concatenations.
|
|
|
|
|
*
|
2000-05-07 21:40:26 +02:00
|
|
|
* Revision 1.35 2000/05/07 19:40:26 steve
|
|
|
|
|
* Fix connection of Direction of LMP_CLSHIFT
|
|
|
|
|
* to constant values. Remember to add a signal
|
|
|
|
|
* to the nexus and connect the receiver in vvm.
|
|
|
|
|
*
|
2000-05-07 06:37:55 +02:00
|
|
|
* Revision 1.34 2000/05/07 04:37:56 steve
|
|
|
|
|
* Carry strength values from Verilog source to the
|
|
|
|
|
* pform and netlist for gates.
|
|
|
|
|
*
|
|
|
|
|
* Change vvm constants to use the driver_t to drive
|
|
|
|
|
* a constant value. This works better if there are
|
|
|
|
|
* multiple drivers on a signal.
|
|
|
|
|
*
|
2000-05-03 23:21:36 +02:00
|
|
|
* Revision 1.33 2000/05/03 21:21:36 steve
|
|
|
|
|
* Allow ternary result to be padded to result width.
|
|
|
|
|
*
|
2000-05-02 05:13:30 +02:00
|
|
|
* Revision 1.32 2000/05/02 03:13:31 steve
|
|
|
|
|
* Move memories to the NetScope object.
|
|
|
|
|
*
|
2000-05-02 02:58:11 +02:00
|
|
|
* Revision 1.31 2000/05/02 00:58:11 steve
|
|
|
|
|
* Move signal tables to the NetScope class.
|
|
|
|
|
*
|
2000-04-28 23:00:28 +02:00
|
|
|
* Revision 1.30 2000/04/28 21:00:29 steve
|
|
|
|
|
* Over agressive signal elimination in constant probadation.
|
|
|
|
|
*
|
2000-04-01 23:40:22 +02:00
|
|
|
* Revision 1.29 2000/04/01 21:40:22 steve
|
|
|
|
|
* Add support for integer division.
|
|
|
|
|
*
|
2000-03-27 06:38:15 +02:00
|
|
|
* Revision 1.28 2000/03/27 04:38:15 steve
|
|
|
|
|
* Speling error.
|
|
|
|
|
*
|
2000-03-20 18:54:10 +01:00
|
|
|
* Revision 1.27 2000/03/20 17:54:10 steve
|
|
|
|
|
* Remove dangerous tmp signal delete.
|
|
|
|
|
*
|
2000-03-17 22:50:25 +01:00
|
|
|
* Revision 1.26 2000/03/17 21:50:25 steve
|
|
|
|
|
* Switch to control warnings.
|
|
|
|
|
*
|
2000-03-16 20:03:03 +01:00
|
|
|
* Revision 1.25 2000/03/16 19:03:03 steve
|
|
|
|
|
* Revise the VVM backend to use nexus objects so that
|
|
|
|
|
* drivers and resolution functions can be used, and
|
|
|
|
|
* the t-vvm module doesn't need to write a zillion
|
|
|
|
|
* output functions.
|
|
|
|
|
*
|
2000-03-08 05:36:53 +01:00
|
|
|
* Revision 1.24 2000/03/08 04:36:53 steve
|
|
|
|
|
* Redesign the implementation of scopes and parameters.
|
|
|
|
|
* I now generate the scopes and notice the parameters
|
|
|
|
|
* in a separate pass over the pform. Once the scopes
|
|
|
|
|
* are generated, I can process overrides and evalutate
|
|
|
|
|
* paremeters before elaboration begins.
|
|
|
|
|
*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Revision 1.23 2000/02/23 02:56:54 steve
|
|
|
|
|
* Macintosh compilers do not support ident.
|
|
|
|
|
*
|
2000-02-16 04:58:27 +01:00
|
|
|
* Revision 1.22 2000/02/16 03:58:27 steve
|
|
|
|
|
* Fix up width matching in structural bitwise operators.
|
|
|
|
|
*
|
2000-02-14 07:04:52 +01:00
|
|
|
* Revision 1.21 2000/02/14 06:04:52 steve
|
|
|
|
|
* Unary reduction operators do not set their operand width
|
|
|
|
|
*
|
2000-01-18 05:53:40 +01:00
|
|
|
* Revision 1.20 2000/01/18 04:53:40 steve
|
|
|
|
|
* Support structural XNOR.
|
|
|
|
|
*
|
2000-01-13 04:35:35 +01:00
|
|
|
* Revision 1.19 2000/01/13 03:35:35 steve
|
|
|
|
|
* Multiplication all the way to simulation.
|
|
|
|
|
*
|
2000-01-11 05:20:57 +01:00
|
|
|
* Revision 1.18 2000/01/11 04:20:57 steve
|
|
|
|
|
* Elaborate net widths of constants to as small
|
|
|
|
|
* as is possible, obeying context constraints.
|
|
|
|
|
*
|
|
|
|
|
* Comparison operators can handle operands with
|
|
|
|
|
* different widths.
|
|
|
|
|
*
|
2000-01-02 23:07:09 +01:00
|
|
|
* Revision 1.17 2000/01/02 22:07:09 steve
|
|
|
|
|
* Add a signal to nexus of padding constant.
|
|
|
|
|
*
|
2000-01-02 22:45:31 +01:00
|
|
|
* Revision 1.16 2000/01/02 21:45:31 steve
|
|
|
|
|
* Add structural reduction NAND,
|
|
|
|
|
* Fix size coercion of structural shifts.
|
|
|
|
|
*
|
2000-01-02 20:39:03 +01:00
|
|
|
* Revision 1.15 2000/01/02 19:39:03 steve
|
|
|
|
|
* Structural reduction XNOR.
|
|
|
|
|
*
|
1999-12-17 04:38:46 +01:00
|
|
|
* Revision 1.14 1999/12/17 03:38:46 steve
|
|
|
|
|
* NetConst can now hold wide constants.
|
|
|
|
|
*
|
1999-12-16 04:46:39 +01:00
|
|
|
* Revision 1.13 1999/12/16 03:46:39 steve
|
|
|
|
|
* Structural logical or.
|
|
|
|
|
*
|
1999-12-16 03:42:14 +01:00
|
|
|
* Revision 1.12 1999/12/16 02:42:14 steve
|
|
|
|
|
* Simulate carry output on adders.
|
|
|
|
|
*
|
1999-12-02 05:08:10 +01:00
|
|
|
* Revision 1.11 1999/12/02 04:08:10 steve
|
|
|
|
|
* Elaborate net repeat concatenations.
|
|
|
|
|
*
|
1999-11-30 05:33:41 +01:00
|
|
|
* Revision 1.10 1999/11/30 04:33:41 steve
|
|
|
|
|
* Put implicitly defined signals in the scope.
|
|
|
|
|
*
|
1999-11-27 20:07:57 +01:00
|
|
|
* Revision 1.9 1999/11/27 19:07:57 steve
|
|
|
|
|
* Support the creation of scopes.
|
|
|
|
|
*
|
1999-11-21 18:35:37 +01:00
|
|
|
* Revision 1.8 1999/11/21 17:35:37 steve
|
|
|
|
|
* Memory name lookup handles scopes.
|
|
|
|
|
*
|
1999-11-21 01:13:08 +01:00
|
|
|
* Revision 1.7 1999/11/21 00:13:08 steve
|
|
|
|
|
* Support memories in continuous assignments.
|
|
|
|
|
*
|
1999-11-15 00:43:45 +01:00
|
|
|
* Revision 1.6 1999/11/14 23:43:45 steve
|
|
|
|
|
* Support combinatorial comparators.
|
|
|
|
|
*
|
1999-11-14 21:24:28 +01:00
|
|
|
* Revision 1.5 1999/11/14 20:24:28 steve
|
|
|
|
|
* Add support for the LPM_CLSHIFT device.
|
|
|
|
|
*
|
1999-11-06 00:36:31 +01:00
|
|
|
* Revision 1.4 1999/11/05 23:36:31 steve
|
|
|
|
|
* Forgot to return the mux for use after elaboration.
|
|
|
|
|
*
|
1999-11-05 22:45:19 +01:00
|
|
|
* Revision 1.3 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.2 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.1 1999/10/31 20:08:24 steve
|
|
|
|
|
* Include subtraction in LPM_ADD_SUB device.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|