1999-10-31 21:08:24 +01:00
|
|
|
/*
|
2012-04-11 18:13:14 +02:00
|
|
|
* Copyright (c) 1999-2012 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
|
|
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
1999-10-31 21:08:24 +01:00
|
|
|
# include "PExpr.h"
|
|
|
|
|
# include "netlist.h"
|
2000-02-16 04:58:27 +01:00
|
|
|
# include "netmisc.h"
|
2012-01-01 02:27:30 +01:00
|
|
|
# include "netstruct.h"
|
2000-03-17 22:50:25 +01:00
|
|
|
# include "compiler.h"
|
1999-10-31 21:08:24 +01:00
|
|
|
|
2008-01-05 00:23:47 +01:00
|
|
|
# include <cstdlib>
|
|
|
|
|
# include <cstring>
|
2001-07-25 05:10:48 +02:00
|
|
|
# include <iostream>
|
2007-01-31 05:21:10 +01:00
|
|
|
# include "ivl_assert.h"
|
2001-07-25 05:10:48 +02:00
|
|
|
|
2002-11-09 20:20:48 +01:00
|
|
|
/*
|
|
|
|
|
* The concatenation is also OK an an l-value. This method elaborates
|
2004-12-11 03:31:25 +01:00
|
|
|
* it as a structural l-value. The return values is the *input* net of
|
|
|
|
|
* the l-value, which may feed via part selects to the final
|
|
|
|
|
* destination. The caller can connect gate outputs to this signal to
|
|
|
|
|
* make the l-value connections.
|
2002-11-09 20:20:48 +01:00
|
|
|
*/
|
2006-04-28 06:28:35 +02:00
|
|
|
NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|
|
|
|
bool bidirectional_flag) const
|
2002-11-09 20:20:48 +01:00
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
svector<NetNet*>nets (parms_.size());
|
2004-12-11 03:31:25 +01:00
|
|
|
unsigned width = 0;
|
2002-11-09 20:20:48 +01:00
|
|
|
unsigned errors = 0;
|
|
|
|
|
|
|
|
|
|
if (repeat_) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": sorry: I do not know how to"
|
2002-11-09 20:20:48 +01:00
|
|
|
" elaborate repeat concatenation nets." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elaborate the operands of the concatenation. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
2003-01-19 01:35:39 +01:00
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if (debug_elaborate) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Elaborate subexpression "
|
2004-12-11 03:31:25 +01:00
|
|
|
<< idx << " of " << nets.count() << " l-values: "
|
|
|
|
|
<< *parms_[idx] << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-19 01:35:39 +01:00
|
|
|
if (parms_[idx] == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Empty expressions "
|
2003-01-19 01:35:39 +01:00
|
|
|
<< "not allowed in concatenations." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-28 06:28:35 +02:00
|
|
|
if (bidirectional_flag) {
|
|
|
|
|
nets[idx] = parms_[idx]->elaborate_bi_net(des, scope);
|
|
|
|
|
} else {
|
2008-03-19 04:50:40 +01:00
|
|
|
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
|
2006-04-28 06:28:35 +02:00
|
|
|
}
|
2009-04-02 19:03:07 +02:00
|
|
|
|
2011-03-13 14:29:42 +01:00
|
|
|
if (nets[idx] == 0) {
|
|
|
|
|
errors += 1;
|
|
|
|
|
} else if (nets[idx]->data_type() == IVL_VT_REAL) {
|
2009-04-02 19:03:07 +02:00
|
|
|
cerr << parms_[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "concatenation operand can no be real: "
|
|
|
|
|
<< *parms_[idx] << endl;
|
2002-11-09 20:20:48 +01:00
|
|
|
errors += 1;
|
2009-04-02 19:03:07 +02:00
|
|
|
continue;
|
2011-03-13 14:29:42 +01:00
|
|
|
} else {
|
|
|
|
|
width += nets[idx]->vector_width();
|
|
|
|
|
}
|
2002-11-09 20:20:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (errors) {
|
2008-02-22 23:51:53 +01:00
|
|
|
des->errors += errors;
|
2002-11-09 20:20:48 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the temporary signal that connects to all the
|
|
|
|
|
operands, and connect it up. Scan the operands of the
|
2004-12-11 03:31:25 +01:00
|
|
|
concat operator from most significant to least significant,
|
|
|
|
|
which is the order they are given in the concat list. */
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*osig = new NetNet(scope, scope->local_symbol(),
|
2004-12-11 03:31:25 +01:00
|
|
|
NetNet::IMPLICIT, width);
|
|
|
|
|
|
2006-04-30 07:17:48 +02:00
|
|
|
/* Assume that the data types of the nets are all the same, so
|
|
|
|
|
we can take the data type of any, the first will do. */
|
|
|
|
|
osig->data_type(nets[0]->data_type());
|
2007-02-05 02:42:31 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
osig->set_line(*this);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
if (bidirectional_flag) {
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: Generating tran(VP) "
|
|
|
|
|
<< "to connect input l-value to subexpressions."
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
2002-11-09 20:20:48 +01:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
|
|
|
|
unsigned wid = nets[idx]->vector_width();
|
|
|
|
|
unsigned off = width - wid;
|
|
|
|
|
NetTran*ps = new NetTran(scope, scope->local_symbol(),
|
|
|
|
|
osig->vector_width(), wid, off);
|
|
|
|
|
des->add_node(ps);
|
|
|
|
|
ps->set_line(*this);
|
2006-04-28 06:28:35 +02:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
connect(ps->pin(0), osig->pin(0));
|
|
|
|
|
connect(ps->pin(1), nets[idx]->pin(0));
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, wid <= width);
|
|
|
|
|
width -= wid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: Generating part selects "
|
|
|
|
|
<< "to connect input l-value to subexpressions."
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
|
|
|
|
unsigned wid = nets[idx]->vector_width();
|
|
|
|
|
unsigned off = width - wid;
|
|
|
|
|
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
|
|
|
|
des->add_node(ps);
|
|
|
|
|
ps->set_line(*this);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
connect(ps->pin(1), osig->pin(0));
|
|
|
|
|
connect(ps->pin(0), nets[idx]->pin(0));
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
assert(wid <= width);
|
|
|
|
|
width -= wid;
|
|
|
|
|
}
|
|
|
|
|
assert(width == 0);
|
2004-12-11 03:31:25 +01:00
|
|
|
}
|
|
|
|
|
|
2006-05-01 22:47:58 +02:00
|
|
|
osig->data_type(nets[0]->data_type());
|
2002-11-09 20:20:48 +01:00
|
|
|
osig->local_flag(true);
|
|
|
|
|
return osig;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-19 04:50:40 +01:00
|
|
|
NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope) const
|
2006-04-28 06:28:35 +02:00
|
|
|
{
|
2008-03-19 04:50:40 +01:00
|
|
|
return elaborate_lnet_common_(des, scope, false);
|
2006-04-28 06:28:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2008-03-19 04:50:40 +01:00
|
|
|
return elaborate_lnet_common_(des, scope, true);
|
2006-04-28 06:28:35 +02:00
|
|
|
}
|
|
|
|
|
|
2011-03-13 14:29:42 +01:00
|
|
|
bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
// Repeat concatenations are not currently supported.
|
|
|
|
|
if (repeat_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Test the operands of the concatenation.
|
|
|
|
|
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
// Empty expressions are not allowed in concatenations
|
|
|
|
|
if (parms_[idx] == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!parms_[idx]->is_collapsible_net(des, scope))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
/*
|
|
|
|
|
* This private method evaluates the part selects (if any) for the
|
|
|
|
|
* signal. The sig argument is the NetNet already located for the
|
|
|
|
|
* PEIdent name. The midx and lidx arguments are loaded with the
|
|
|
|
|
* results, which may be the whole vector, or a single bit, or
|
|
|
|
|
* anything in between. The values are in canonical indices.
|
|
|
|
|
*/
|
|
|
|
|
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
2008-05-10 02:42:37 +02:00
|
|
|
long&midx, long&lidx) const
|
2005-01-09 21:16:00 +01:00
|
|
|
{
|
2012-02-11 02:17:59 +01:00
|
|
|
list<long> prefix_indices;
|
|
|
|
|
bool rc = calculate_packed_indices_(des, scope, sig, prefix_indices);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
// Only treat as part/bit selects any index that is beyond the
|
|
|
|
|
// word selects for an array. This is not an array, then
|
|
|
|
|
// dimensions==0 and any index is treated as a select.
|
|
|
|
|
if (name_tail.index.size() <= sig->array_dimensions()) {
|
|
|
|
|
midx = sig->vector_width()-1;
|
|
|
|
|
lidx = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, !name_tail.index.empty());
|
|
|
|
|
|
|
|
|
|
const index_component_t&index_tail = name_tail.index.back();
|
|
|
|
|
|
|
|
|
|
switch (index_tail.sel) {
|
2006-04-24 07:15:07 +02:00
|
|
|
default:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2007-05-24 06:07:11 +02:00
|
|
|
<< "Unexpected sel_ value = " << index_tail.sel << endl;
|
|
|
|
|
ivl_assert(*this, 0);
|
2006-04-24 07:15:07 +02:00
|
|
|
break;
|
2005-01-09 21:16:00 +01:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
case index_component_t::SEL_IDX_DO:
|
|
|
|
|
case index_component_t::SEL_IDX_UP: {
|
2011-03-27 12:08:33 +02:00
|
|
|
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1, true);
|
2006-04-24 07:15:07 +02:00
|
|
|
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
|
2007-11-07 20:26:56 +01:00
|
|
|
if (!tmp) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: indexed part select of "
|
2007-11-07 20:26:56 +01:00
|
|
|
<< sig->name()
|
|
|
|
|
<< " must be a constant in this context." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2005-01-09 21:16:00 +01:00
|
|
|
|
2007-07-03 05:53:02 +02:00
|
|
|
/* The width (a constant) is calculated here. */
|
|
|
|
|
unsigned long wid = 0;
|
|
|
|
|
bool flag = calculate_up_do_width_(des, scope, wid);
|
2009-08-29 01:50:59 +02:00
|
|
|
if (! flag) return false;
|
|
|
|
|
|
|
|
|
|
/* We have an undefined index and that is out of range. */
|
|
|
|
|
if (! tmp->value().is_defined()) {
|
|
|
|
|
if (warn_ob_select) {
|
|
|
|
|
cerr << get_fileline() << ": warning: "
|
|
|
|
|
<< sig->name();
|
|
|
|
|
if (sig->array_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << "['bx";
|
|
|
|
|
if (index_tail.sel ==
|
|
|
|
|
index_component_t::SEL_IDX_UP) {
|
|
|
|
|
cerr << "+:";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "-:";
|
|
|
|
|
}
|
|
|
|
|
cerr << wid << "] is always outside vector."
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
2007-07-03 05:53:02 +02:00
|
|
|
return false;
|
2009-08-29 01:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long midx_val = tmp->value().as_long();
|
2012-02-11 02:17:59 +01:00
|
|
|
midx = sig->sb_to_idx(prefix_indices, midx_val);
|
2009-08-29 01:50:59 +02:00
|
|
|
delete tmp_ex;
|
2006-04-24 07:15:07 +02:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
if (index_tail.sel == index_component_t::SEL_IDX_UP)
|
2012-02-11 02:17:59 +01:00
|
|
|
lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
|
2006-04-24 07:15:07 +02:00
|
|
|
else
|
2012-02-11 02:17:59 +01:00
|
|
|
lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
|
2006-04-24 07:15:07 +02:00
|
|
|
|
|
|
|
|
if (midx < lidx) {
|
2008-10-13 18:51:05 +02:00
|
|
|
long tmpx = midx;
|
2006-04-24 07:15:07 +02:00
|
|
|
midx = lidx;
|
2008-10-13 18:51:05 +02:00
|
|
|
lidx = tmpx;
|
2006-04-24 07:15:07 +02:00
|
|
|
}
|
|
|
|
|
|
2008-10-15 02:03:50 +02:00
|
|
|
/* Warn about an indexed part select that is out of range. */
|
2009-08-29 01:50:59 +02:00
|
|
|
if (warn_ob_select && (lidx < 0)) {
|
|
|
|
|
cerr << get_fileline() << ": warning: " << sig->name();
|
|
|
|
|
if (sig->array_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << "[" << midx_val;
|
|
|
|
|
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
|
|
|
|
|
cerr << "+:";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "-:";
|
|
|
|
|
}
|
|
|
|
|
cerr << wid << "] is selecting before vector." << endl;
|
|
|
|
|
}
|
|
|
|
|
if (warn_ob_select && (midx >= (long)sig->vector_width())) {
|
|
|
|
|
cerr << get_fileline() << ": warning: " << sig->name();
|
2008-10-15 02:03:50 +02:00
|
|
|
if (sig->array_dimensions() > 0) {
|
|
|
|
|
cerr << "[]";
|
|
|
|
|
}
|
|
|
|
|
cerr << "[" << midx_val;
|
|
|
|
|
if (index_tail.sel == index_component_t::SEL_IDX_UP) {
|
|
|
|
|
cerr << "+:";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "-:";
|
|
|
|
|
}
|
2009-08-29 01:50:59 +02:00
|
|
|
cerr << wid << "] is selecting after vector." << endl;
|
2008-10-15 02:03:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is completely out side the signal so just skip it. */
|
|
|
|
|
if (lidx >= (long)sig->vector_width() || midx < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-24 07:15:07 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
case index_component_t::SEL_PART: {
|
2006-04-24 07:15:07 +02:00
|
|
|
|
2007-07-03 05:53:02 +02:00
|
|
|
long msb, lsb;
|
2009-01-02 01:20:41 +01:00
|
|
|
bool part_defined_flag;
|
|
|
|
|
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
|
|
|
|
|
ivl_assert(*this, part_defined_flag);
|
2006-04-24 07:15:07 +02:00
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
|
|
|
|
|
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
|
2006-04-24 07:15:07 +02:00
|
|
|
/* Detect reversed indices of a part select. */
|
2008-05-10 02:42:37 +02:00
|
|
|
if (lidx_tmp > midx_tmp) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Part select "
|
2007-07-03 05:53:02 +02:00
|
|
|
<< sig->name() << "[" << msb << ":"
|
|
|
|
|
<< lsb << "] indices reversed." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : Did you mean "
|
2007-07-03 05:53:02 +02:00
|
|
|
<< sig->name() << "[" << lsb << ":"
|
|
|
|
|
<< msb << "]?" << endl;
|
2008-05-10 02:42:37 +02:00
|
|
|
long tmp = midx_tmp;
|
|
|
|
|
midx_tmp = lidx_tmp;
|
|
|
|
|
lidx_tmp = tmp;
|
2006-04-24 07:15:07 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-15 02:03:50 +02:00
|
|
|
/* Warn about a part select that is out of range. */
|
2008-05-10 02:42:37 +02:00
|
|
|
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
|
|
|
|
|
cerr << get_fileline() << ": warning: Part select "
|
2008-10-15 02:03:50 +02:00
|
|
|
<< sig->name();
|
|
|
|
|
if (sig->array_dimensions() > 0) {
|
|
|
|
|
cerr << "[]";
|
|
|
|
|
}
|
|
|
|
|
cerr << "[" << msb << ":" << lsb
|
|
|
|
|
<< "] is out of range." << endl;
|
2008-05-10 02:42:37 +02:00
|
|
|
#if 0
|
|
|
|
|
midx_tmp = sig->vector_width() - 1;
|
|
|
|
|
lidx_tmp = 0;
|
2006-04-24 07:15:07 +02:00
|
|
|
des->errors += 1;
|
2008-05-10 02:42:37 +02:00
|
|
|
#endif
|
2008-10-15 02:03:50 +02:00
|
|
|
}
|
|
|
|
|
/* This is completely out side the signal so just skip it. */
|
|
|
|
|
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
|
|
|
|
|
return false;
|
2006-04-24 07:15:07 +02:00
|
|
|
}
|
2008-05-10 02:42:37 +02:00
|
|
|
|
|
|
|
|
midx = midx_tmp;
|
|
|
|
|
lidx = lidx_tmp;
|
2006-04-24 07:15:07 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
case index_component_t::SEL_BIT:
|
|
|
|
|
if (name_tail.index.size() > sig->array_dimensions()) {
|
2012-04-30 20:48:33 +02:00
|
|
|
long msb;
|
|
|
|
|
bool bit_defined_flag;
|
|
|
|
|
/* bool flag = */ calculate_bits_(des, scope, msb, bit_defined_flag);
|
|
|
|
|
ivl_assert(*this, bit_defined_flag);
|
|
|
|
|
midx = sig->sb_to_idx(prefix_indices, msb);
|
2008-05-10 02:42:37 +02:00
|
|
|
if (midx >= (long)sig->vector_width()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Index " << sig->name()
|
2012-04-30 20:48:33 +02:00
|
|
|
<< "[" << msb << "] is out of range."
|
2006-04-24 07:15:07 +02:00
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
midx = 0;
|
|
|
|
|
}
|
|
|
|
|
lidx = midx;
|
|
|
|
|
|
|
|
|
|
} else {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
2007-05-24 06:07:11 +02:00
|
|
|
<< "Bit select " << path_ << endl;
|
|
|
|
|
ivl_assert(*this, 0);
|
2006-04-24 07:15:07 +02:00
|
|
|
midx = sig->vector_width() - 1;
|
|
|
|
|
lidx = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2005-01-09 21:16:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
/*
|
2005-08-06 19:58:16 +02:00
|
|
|
* This is the common code for l-value nets and bi-directional
|
|
|
|
|
* nets. There is very little that is different between the two cases,
|
|
|
|
|
* so most of the work for both is done here.
|
1999-11-21 01:13:08 +01:00
|
|
|
*/
|
2005-08-06 19:58:16 +02:00
|
|
|
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|
|
|
|
bool bidirectional_flag) const
|
1999-11-21 01:13:08 +01:00
|
|
|
{
|
2003-09-19 05:50:12 +02:00
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
NetNet* sig = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
2012-01-01 02:27:30 +01:00
|
|
|
perm_string method_name;
|
2003-09-19 05:50:12 +02:00
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
symbol_search(this, des, scope, path_, sig, par, eve);
|
2003-09-19 05:50:12 +02:00
|
|
|
|
|
|
|
|
if (eve != 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: named events (" << path_
|
2003-09-19 05:50:12 +02:00
|
|
|
<< ") cannot be l-values in continuous "
|
|
|
|
|
<< "assignments." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-01 02:27:30 +01:00
|
|
|
/* If the signal is not found, check to see if this is a
|
|
|
|
|
member of a struct. Take the name of the form "a.b.member",
|
|
|
|
|
remove the member and store it into method_name, and retry
|
|
|
|
|
the search with "a.b". */
|
|
|
|
|
if (sig == 0 && path_.size() >= 2) {
|
|
|
|
|
pform_name_t use_path = path_;
|
|
|
|
|
method_name = peek_tail_name(use_path);
|
|
|
|
|
use_path.pop_back();
|
|
|
|
|
symbol_search(this, des, scope, use_path, sig, par, eve);
|
2012-01-04 02:38:08 +01:00
|
|
|
|
|
|
|
|
// Whoops, not a struct signal, so give up on this avenue.
|
|
|
|
|
if (sig && sig->struct_type() == 0) {
|
|
|
|
|
method_name = perm_string();
|
|
|
|
|
sig = 0;
|
|
|
|
|
}
|
2012-01-01 02:27:30 +01:00
|
|
|
}
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
if (sig == 0) {
|
2008-03-19 04:50:40 +01:00
|
|
|
cerr << get_fileline() << ": error: Net " << path_
|
|
|
|
|
<< " is not defined in this context." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
2010-10-08 05:13:11 +02:00
|
|
|
/* If this is SystemVerilog and the variable is not yet
|
|
|
|
|
assigned by anything, then convert it to an unresolved
|
|
|
|
|
wire. */
|
|
|
|
|
if (gn_var_can_be_uwire()
|
|
|
|
|
&& (sig->type() == NetNet::REG)
|
2012-04-16 03:04:09 +02:00
|
|
|
&& (sig->peek_lref() == 0) ) {
|
2010-10-08 05:13:11 +02:00
|
|
|
sig->type(NetNet::UNRESOLVED_WIRE);
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-21 01:13:08 +01:00
|
|
|
/* Don't allow registers as assign l-values. */
|
|
|
|
|
if (sig->type() == NetNet::REG) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: reg " << sig->name()
|
2003-08-05 05:01:58 +02:00
|
|
|
<< "; cannot be driven by primitives"
|
|
|
|
|
<< " or continuous assignment." << endl;
|
|
|
|
|
des->errors += 1;
|
1999-11-21 01:13:08 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
// Default part select is the entire word.
|
|
|
|
|
unsigned midx = sig->vector_width()-1, lidx = 0;
|
|
|
|
|
// The default word select is the first.
|
2009-07-04 00:37:44 +02:00
|
|
|
long widx = 0;
|
2009-08-06 20:59:34 +02:00
|
|
|
// The widx_val is the word select as entered in the source
|
|
|
|
|
// code. It's used for error messages.
|
|
|
|
|
long widx_val = 0;
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
|
2012-01-01 02:27:30 +01:00
|
|
|
netstruct_t*struct_type = 0;
|
|
|
|
|
if ((struct_type = sig->struct_type()) && !method_name.nil()) {
|
|
|
|
|
|
|
|
|
|
// Detect the variable is a structure and there was a
|
2012-04-11 18:13:14 +02:00
|
|
|
// method name detected.
|
2012-01-01 02:27:30 +01:00
|
|
|
if (debug_elaborate)
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Signal " << sig->name() << " is a structure, "
|
|
|
|
|
<< "try to match member " << method_name << endl;
|
|
|
|
|
|
|
|
|
|
unsigned long member_off = 0;
|
|
|
|
|
const struct netstruct_t::member_t*member = struct_type->packed_member(method_name, member_off);
|
|
|
|
|
ivl_assert(*this, member);
|
|
|
|
|
|
|
|
|
|
// Rewrite a member select of a packed structure as a
|
|
|
|
|
// part select of the base variable.
|
|
|
|
|
lidx = member_off;
|
|
|
|
|
midx = lidx + member->width() - 1;
|
|
|
|
|
|
|
|
|
|
} else if (sig->array_dimensions() > 0) {
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2007-11-07 20:26:56 +01:00
|
|
|
if (name_tail.index.empty()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: array " << sig->name()
|
2007-11-07 20:26:56 +01:00
|
|
|
<< " must be used with an index." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-05-24 06:07:11 +02:00
|
|
|
|
|
|
|
|
const index_component_t&index_head = name_tail.index.front();
|
2007-11-06 22:01:11 +01:00
|
|
|
if (index_head.sel == index_component_t::SEL_PART) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: cannot perform a part "
|
2007-11-06 22:01:11 +01:00
|
|
|
<< "select on array " << sig->name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-05-24 06:07:11 +02:00
|
|
|
ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
|
|
|
|
|
|
2011-03-27 12:08:33 +02:00
|
|
|
NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1, true);
|
2007-01-16 06:44:14 +01:00
|
|
|
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
|
2007-11-07 03:15:08 +01:00
|
|
|
if (!tmp) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: array " << sig->name()
|
2007-11-07 03:15:08 +01:00
|
|
|
<< " index must be a constant in this context." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2009-08-06 20:59:34 +02:00
|
|
|
widx_val = tmp->value().as_long();
|
|
|
|
|
if (sig->array_index_is_valid(widx_val))
|
|
|
|
|
widx = sig->array_index_to_address(widx_val);
|
|
|
|
|
else
|
|
|
|
|
widx = -1;
|
2007-01-16 06:44:14 +01:00
|
|
|
delete tmp_ex;
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Use [" << widx << "]"
|
2007-01-16 06:44:14 +01:00
|
|
|
<< " to index l-value array." << endl;
|
|
|
|
|
|
2007-11-07 03:15:08 +01:00
|
|
|
/* The array has a part/bit select at the end. */
|
2007-11-07 20:26:56 +01:00
|
|
|
if (name_tail.index.size() > sig->array_dimensions()) {
|
2009-04-15 01:08:27 +02:00
|
|
|
if (sig->get_scalar()) {
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << get_fileline() << ": error: "
|
2009-04-15 01:08:27 +02:00
|
|
|
<< "can not select part of ";
|
|
|
|
|
if (sig->data_type() == IVL_VT_REAL) cerr << "real";
|
|
|
|
|
else cerr << "scalar";
|
|
|
|
|
cerr << " array word: " << sig->name()
|
|
|
|
|
<< "[" << widx_val << "]" << endl;
|
2009-04-02 03:31:29 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-10 02:42:37 +02:00
|
|
|
long midx_tmp, lidx_tmp;
|
|
|
|
|
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
2007-11-07 03:15:08 +01:00
|
|
|
return 0;
|
2008-10-15 02:03:50 +02:00
|
|
|
|
|
|
|
|
if (lidx_tmp < 0) {
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << get_fileline() << ": sorry: part selects "
|
2008-10-15 02:03:50 +02:00
|
|
|
"straddling the start of signal (" << path_
|
|
|
|
|
<< ") are not currently supported." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2008-05-10 02:42:37 +02:00
|
|
|
midx = midx_tmp;
|
|
|
|
|
lidx = lidx_tmp;
|
2007-11-07 03:15:08 +01:00
|
|
|
}
|
2007-05-24 06:07:11 +02:00
|
|
|
} else if (!name_tail.index.empty()) {
|
2009-04-15 01:08:27 +02:00
|
|
|
if (sig->get_scalar()) {
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << get_fileline() << ": error: "
|
2009-04-15 01:08:27 +02:00
|
|
|
<< "can not select part of ";
|
|
|
|
|
if (sig->data_type() == IVL_VT_REAL) cerr << "real: ";
|
|
|
|
|
else cerr << "scalar: ";
|
|
|
|
|
cerr << sig->name() << endl;
|
2009-04-02 03:31:29 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-10 02:42:37 +02:00
|
|
|
long midx_tmp, lidx_tmp;
|
|
|
|
|
if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
|
2007-01-16 06:44:14 +01:00
|
|
|
return 0;
|
2008-05-10 02:42:37 +02:00
|
|
|
|
2008-10-15 02:03:50 +02:00
|
|
|
if (lidx_tmp < 0) {
|
2010-10-02 20:02:27 +02:00
|
|
|
cerr << get_fileline() << ": sorry: part selects "
|
2008-10-15 02:03:50 +02:00
|
|
|
"straddling the start of signal (" << path_
|
|
|
|
|
<< ") are not currently supported." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2008-05-10 02:42:37 +02:00
|
|
|
midx = midx_tmp;
|
|
|
|
|
lidx = lidx_tmp;
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
2000-12-01 03:55:37 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
unsigned subnet_wid = midx-lidx+1;
|
|
|
|
|
|
2012-01-28 19:20:09 +01:00
|
|
|
/* Check if the l-value bits are double-driven. */
|
|
|
|
|
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) {
|
|
|
|
|
cerr << get_fileline() << ": error: Unresolved net/uwire "
|
|
|
|
|
<< sig->name() << " cannot have multiple drivers." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
if (sig->pin_count() > 1) {
|
2009-07-04 00:37:44 +02:00
|
|
|
if (widx < 0 || widx >= (long) sig->pin_count()) {
|
|
|
|
|
cerr << get_fileline() << ": warning: ignoring out of "
|
|
|
|
|
"bounds l-value array access "
|
2009-08-06 20:59:34 +02:00
|
|
|
<< sig->name() << "[" << widx_val << "]." << endl;
|
2009-07-04 00:37:44 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-01-16 06:44:14 +01:00
|
|
|
|
|
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
sig->type(), sig->vector_width());
|
|
|
|
|
tmp->set_line(*this);
|
|
|
|
|
tmp->local_flag(true);
|
2008-09-26 06:21:00 +02:00
|
|
|
tmp->data_type( sig->data_type() );
|
2007-01-16 06:44:14 +01:00
|
|
|
connect(sig->pin(widx), tmp->pin(0));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-11 20:27:54 +01:00
|
|
|
/* If the desired l-value vector is narrower than the
|
2005-01-09 21:16:00 +01:00
|
|
|
signal itself, then use a NetPartSelect node to
|
|
|
|
|
arrange for connection to the desired bits. All this
|
2011-03-11 20:27:54 +01:00
|
|
|
can be skipped if the desired width matches the
|
2005-01-09 21:16:00 +01:00
|
|
|
original vector. */
|
|
|
|
|
|
|
|
|
|
if (subnet_wid != sig->vector_width()) {
|
2005-08-06 19:58:16 +02:00
|
|
|
/* If we are processing a tran or inout, then the
|
|
|
|
|
partselect is bi-directional. Otherwise, it is a
|
|
|
|
|
Part-to-Vector select. */
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: "
|
2005-01-09 21:16:00 +01:00
|
|
|
<< "Elaborate lnet part select "
|
|
|
|
|
<< sig->name()
|
|
|
|
|
<< "[base=" << lidx
|
|
|
|
|
<< " wid=" << subnet_wid <<"]"
|
|
|
|
|
<< endl;
|
1999-11-21 01:13:08 +01:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
NetNet*subsig = new NetNet(sig->scope(),
|
|
|
|
|
sig->scope()->local_symbol(),
|
|
|
|
|
NetNet::WIRE, subnet_wid);
|
2005-07-15 06:13:25 +02:00
|
|
|
subsig->data_type( sig->data_type() );
|
2007-02-05 02:42:31 +01:00
|
|
|
subsig->local_flag(true);
|
|
|
|
|
subsig->set_line(*this);
|
1999-11-21 01:13:08 +01:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
if (bidirectional_flag) {
|
|
|
|
|
// Make a tran(VP)
|
|
|
|
|
NetTran*sub = new NetTran(scope, scope->local_symbol(),
|
|
|
|
|
sig->vector_width(),
|
|
|
|
|
subnet_wid, lidx);
|
|
|
|
|
sub->set_line(*this);
|
|
|
|
|
des->add_node(sub);
|
|
|
|
|
connect(sub->pin(0), sig->pin(0));
|
|
|
|
|
connect(sub->pin(1), subsig->pin(0));
|
2002-06-19 06:20:03 +02:00
|
|
|
|
2008-06-03 20:16:25 +02:00
|
|
|
} else {
|
|
|
|
|
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
|
|
|
|
NetPartSelect::PV);
|
|
|
|
|
des->add_node(sub);
|
|
|
|
|
sub->set_line(*this);
|
|
|
|
|
connect(sub->pin(0), subsig->pin(0));
|
2011-04-04 02:21:43 +02:00
|
|
|
collapse_partselect_pv_to_concat(des, sig);
|
2008-06-03 20:16:25 +02:00
|
|
|
}
|
2005-01-09 21:16:00 +01:00
|
|
|
sig = subsig;
|
1999-11-21 01:13:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sig;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-06 19:58:16 +02:00
|
|
|
/*
|
|
|
|
|
* Identifiers in continuous assignment l-values are limited to wires
|
|
|
|
|
* and that ilk. Detect registers and memories here and report errors.
|
|
|
|
|
*/
|
2008-03-19 04:50:40 +01:00
|
|
|
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope) const
|
2005-08-06 19:58:16 +02:00
|
|
|
{
|
2008-03-19 04:50:40 +01:00
|
|
|
return elaborate_lnet_common_(des, scope, false);
|
2005-08-06 19:58:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2008-03-19 04:50:40 +01:00
|
|
|
return elaborate_lnet_common_(des, scope, true);
|
2005-08-06 19:58:16 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
2005-01-09 21:16:00 +01:00
|
|
|
* port. This elaboration is done inside the module, and is only done
|
|
|
|
|
* to PEIdent objects. This method is used by elaboration of a module
|
|
|
|
|
* instantiation (PGModule::elaborate_mod_) to get NetNet objects for
|
|
|
|
|
* the port.
|
2000-05-16 06:05:15 +02:00
|
|
|
*/
|
|
|
|
|
NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
2011-03-07 20:18:23 +01:00
|
|
|
assert(scope->type() == NetScope::MODULE);
|
2001-12-03 05:47:14 +01:00
|
|
|
NetNet*sig = des->find_signal(scope, path_);
|
2000-05-16 06:05:15 +02:00
|
|
|
if (sig == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: no wire/reg " << path_
|
2007-06-02 05:42:12 +02:00
|
|
|
<< " in module " << scope_path(scope) << "." << endl;
|
2000-05-16 06:05:15 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
/* Check the port_type of the signal to make sure it is really
|
|
|
|
|
a port, and its direction is resolved. */
|
2000-08-18 06:38:57 +02:00
|
|
|
switch (sig->port_type()) {
|
|
|
|
|
case NetNet::PINPUT:
|
|
|
|
|
case NetNet::POUTPUT:
|
|
|
|
|
case NetNet::PINOUT:
|
2012-02-25 19:19:48 +01:00
|
|
|
case NetNet::PREF:
|
2000-08-18 06:38:57 +02:00
|
|
|
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:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: signal " << path_ << " in"
|
2007-06-02 05:42:12 +02:00
|
|
|
<< " module " << scope_path(scope) << " is not a port." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": : Are you missing an input/"
|
2000-08-18 06:38:57 +02:00
|
|
|
<< "output/inout declaration?" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* This should not happen. A PWire can only become
|
2008-01-15 19:54:04 +01:00
|
|
|
PIMPLICIT if this is a UDP reg port, and the make_udp
|
2000-08-18 06:38:57 +02:00
|
|
|
function should turn it into an output.... I think. */
|
|
|
|
|
|
|
|
|
|
case NetNet::PIMPLICIT:
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": internal error: signal " << path_
|
2007-06-02 05:42:12 +02:00
|
|
|
<< " in module " << scope_path(scope) << " is left as "
|
2000-08-18 06:38:57 +02:00
|
|
|
<< "port type PIMPLICIT." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-10 02:42:37 +02:00
|
|
|
long midx;
|
|
|
|
|
long lidx;
|
2000-05-16 06:05:15 +02:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
/* Evaluate the part/bit select expressions, to get the part
|
|
|
|
|
select of the signal that attaches to the port. Also handle
|
|
|
|
|
range and direction checking here. */
|
2000-05-16 06:05:15 +02:00
|
|
|
|
2005-01-09 21:16:00 +01:00
|
|
|
if (! eval_part_select_(des, scope, sig, midx, lidx))
|
|
|
|
|
return 0;
|
2002-06-19 06:20:03 +02:00
|
|
|
|
2008-12-12 06:35:28 +01:00
|
|
|
/* If this is a part select of the entire signal (or no part
|
|
|
|
|
select at all) then we're done. */
|
2011-03-07 20:18:23 +01:00
|
|
|
if ((lidx == 0) && (midx == (long)sig->vector_width()-1)) {
|
|
|
|
|
scope->add_module_port(sig);
|
2008-12-12 06:35:28 +01:00
|
|
|
return sig;
|
2011-03-07 20:18:23 +01:00
|
|
|
}
|
2008-12-12 06:35:28 +01:00
|
|
|
|
|
|
|
|
unsigned swid = abs(midx - lidx) + 1;
|
|
|
|
|
ivl_assert(*this, swid > 0 && swid < sig->vector_width());
|
|
|
|
|
|
|
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
NetNet::WIRE, swid);
|
|
|
|
|
tmp->port_type(sig->port_type());
|
|
|
|
|
tmp->data_type(sig->data_type());
|
|
|
|
|
tmp->set_line(*this);
|
2011-03-07 20:18:23 +01:00
|
|
|
tmp->local_flag(true);
|
2008-12-12 06:35:28 +01:00
|
|
|
NetNode*ps = 0;
|
|
|
|
|
switch (sig->port_type()) {
|
|
|
|
|
|
|
|
|
|
case NetNet::PINPUT:
|
2011-03-03 03:14:57 +01:00
|
|
|
ps = new NetPartSelect(sig, lidx, swid, NetPartSelect::PV);
|
2008-12-12 06:35:28 +01:00
|
|
|
connect(tmp->pin(0), ps->pin(0));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NetNet::POUTPUT:
|
2011-03-03 03:14:57 +01:00
|
|
|
ps = new NetPartSelect(sig, lidx, swid, NetPartSelect::VP);
|
2008-12-12 06:35:28 +01:00
|
|
|
connect(tmp->pin(0), ps->pin(0));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
break;
|
2000-05-16 06:05:15 +02:00
|
|
|
|
2012-02-25 19:19:48 +01:00
|
|
|
case NetNet::PREF:
|
|
|
|
|
// For the purposes of module ports, treat ref ports
|
|
|
|
|
// just like inout ports.
|
2008-12-12 06:35:28 +01:00
|
|
|
case NetNet::PINOUT:
|
|
|
|
|
ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(),
|
2011-03-03 03:14:57 +01:00
|
|
|
swid, lidx);
|
2008-12-12 06:35:28 +01:00
|
|
|
connect(sig->pin(0), ps->pin(0));
|
|
|
|
|
connect(tmp->pin(0), ps->pin(1));
|
|
|
|
|
sig = tmp;
|
|
|
|
|
break;
|
2000-05-16 06:05:15 +02:00
|
|
|
|
2008-12-12 06:35:28 +01:00
|
|
|
default:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
break;
|
2000-05-16 06:05:15 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-12 06:35:28 +01:00
|
|
|
ps->set_line(*this);
|
|
|
|
|
des->add_node(ps);
|
|
|
|
|
|
2011-03-07 20:18:23 +01:00
|
|
|
scope->add_module_port(sig);
|
2000-05-16 06:05:15 +02:00
|
|
|
return sig;
|
|
|
|
|
}
|
2011-03-13 14:29:42 +01:00
|
|
|
|
|
|
|
|
bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
assert(scope);
|
|
|
|
|
|
|
|
|
|
NetNet* sig = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
|
|
|
|
|
|
|
|
|
symbol_search(this, des, scope, path_, sig, par, eve);
|
|
|
|
|
|
|
|
|
|
if (eve != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (sig == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
/* If this is SystemVerilog and the variable is not yet
|
|
|
|
|
assigned by anything, then convert it to an unresolved
|
|
|
|
|
wire. */
|
|
|
|
|
if (gn_var_can_be_uwire()
|
|
|
|
|
&& (sig->type() == NetNet::REG)
|
|
|
|
|
&& (sig->peek_eref() == 0) ) {
|
|
|
|
|
sig->type(NetNet::UNRESOLVED_WIRE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (sig->type() == NetNet::REG)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|