2000-09-09 17:21:26 +02:00
|
|
|
/*
|
2013-01-25 19:25:12 +01:00
|
|
|
* Copyright (c) 2000-2013 Stephen Williams (steve@icarus.com)
|
2012-08-06 01:28:40 +02:00
|
|
|
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
2000-09-09 17:21:26 +02: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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2000-09-09 17:21:26 +02:00
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
# include "PExpr.h"
|
2013-04-08 01:38:48 +02:00
|
|
|
# include "PPackage.h"
|
2000-09-09 17:21:26 +02:00
|
|
|
# include "netlist.h"
|
2003-09-19 05:30:04 +02:00
|
|
|
# include "netmisc.h"
|
2012-01-04 02:38:08 +01:00
|
|
|
# include "netstruct.h"
|
2012-11-25 19:13:05 +01:00
|
|
|
# include "netclass.h"
|
2013-01-27 21:30:38 +01:00
|
|
|
# include "netdarray.h"
|
2007-01-16 06:44:14 +01:00
|
|
|
# include "compiler.h"
|
2008-01-05 00:23:47 +01:00
|
|
|
# include <cstdlib>
|
2001-07-25 05:10:48 +02:00
|
|
|
# include <iostream>
|
2008-01-07 22:10:18 +01:00
|
|
|
# include <climits>
|
2007-03-05 06:59:10 +01:00
|
|
|
# include "ivl_assert.h"
|
2001-07-25 05:10:48 +02:00
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
/*
|
|
|
|
|
* These methods generate a NetAssign_ object for the l-value of the
|
2003-01-27 06:09:17 +01:00
|
|
|
* assignment. This is common code for the = and <= statements.
|
2000-09-09 17:21:26 +02:00
|
|
|
*
|
|
|
|
|
* What gets generated depends on the structure of the l-value. If the
|
2008-01-29 21:19:59 +01:00
|
|
|
* l-value is a simple name (i.e., foo <= <value>) then the NetAssign_
|
2000-09-09 17:21:26 +02:00
|
|
|
* is created the width of the foo reg and connected to all the
|
|
|
|
|
* bits.
|
|
|
|
|
*
|
2003-01-27 06:09:17 +01:00
|
|
|
* If there is a part select (i.e., foo[3:1] <= <value>) the NetAssign_
|
2000-09-09 17:21:26 +02:00
|
|
|
* is made only as wide as it needs to be (3 bits in this example) and
|
|
|
|
|
* connected to the correct bits of foo. A constant bit select is a
|
2004-10-04 03:10:51 +02:00
|
|
|
* special case of the part select.
|
2000-09-09 17:21:26 +02:00
|
|
|
*
|
2003-01-27 06:09:17 +01:00
|
|
|
* If the bit-select is non-constant (i.e., foo[<expr>] = <value>) the
|
2000-09-09 17:21:26 +02:00
|
|
|
* NetAssign_ is made wide enough to connect to all the bits of foo,
|
|
|
|
|
* then the mux expression is elaborated and attached to the
|
|
|
|
|
* NetAssign_ node as a b_mux value. The target must interpret the
|
2003-01-27 06:09:17 +01:00
|
|
|
* presence of a bmux value as taking a single bit and assigning it to
|
2000-09-09 17:21:26 +02:00
|
|
|
* the bit selected by the bmux expression.
|
|
|
|
|
*
|
|
|
|
|
* If the l-value expression is non-trivial, but can be fully
|
|
|
|
|
* evaluated at compile time (meaning any bit selects are constant)
|
|
|
|
|
* then elaboration will make a single NetAssign_ that connects to a
|
|
|
|
|
* synthetic reg that in turn connects to all the proper pins of the
|
|
|
|
|
* l-value.
|
|
|
|
|
*
|
|
|
|
|
* This last case can turn up in statements like: {a, b[1]} = c;
|
2011-03-11 20:27:54 +01:00
|
|
|
* rather than create a NetAssign_ for each item in the concatenation,
|
2000-09-09 17:21:26 +02:00
|
|
|
* elaboration makes a single NetAssign_ and connects it up properly.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The default interpretation of an l-value to a procedural assignment
|
|
|
|
|
* is to try to make a net elaboration, and see if the result is
|
|
|
|
|
* suitable for assignment.
|
|
|
|
|
*/
|
2010-11-01 22:37:06 +01:00
|
|
|
NetAssign_* PExpr::elaborate_lval(Design*, NetScope*, bool) const
|
2000-09-09 17:21:26 +02:00
|
|
|
{
|
2002-06-04 07:38:43 +02:00
|
|
|
NetNet*ll = 0;
|
2000-09-09 17:21:26 +02:00
|
|
|
if (ll == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": Assignment l-value too complex."
|
2000-09-09 17:21:26 +02:00
|
|
|
<< endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_*lv = new NetAssign_(ll);
|
2000-09-09 17:21:26 +02:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Concatenation expressions can appear as l-values. Handle them here.
|
2000-09-10 05:59:59 +02:00
|
|
|
*
|
|
|
|
|
* If adjacent l-values in the concatenation are not bit selects, then
|
|
|
|
|
* merge them into a single NetAssign_ object. This can happen is code
|
|
|
|
|
* like ``{ ...a, b, ...}''. As long as "a" and "b" do not have bit
|
|
|
|
|
* selects (or the bit selects are constant) we can merge the
|
|
|
|
|
* NetAssign_ objects.
|
|
|
|
|
*
|
|
|
|
|
* Be careful to get the bit order right. In the expression ``{a, b}''
|
|
|
|
|
* a is the MSB and b the LSB. Connect the LSB to the low pins of the
|
|
|
|
|
* NetAssign_ object.
|
2000-09-09 17:21:26 +02:00
|
|
|
*/
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_* PEConcat::elaborate_lval(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
bool is_force) const
|
2000-09-09 17:21:26 +02:00
|
|
|
{
|
2000-09-10 17:43:59 +02:00
|
|
|
if (repeat_) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Repeat concatenations make "
|
2000-09-10 17:43:59 +02:00
|
|
|
"no sense in l-value expressions. I refuse." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2000-09-10 05:59:59 +02:00
|
|
|
|
2000-09-10 04:18:16 +02:00
|
|
|
NetAssign_*res = 0;
|
2000-09-10 05:59:59 +02:00
|
|
|
|
2010-10-26 04:36:44 +02:00
|
|
|
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
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;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force);
|
2000-10-26 19:09:46 +02:00
|
|
|
|
2011-09-26 21:04:28 +02:00
|
|
|
/* If the l-value doesn't elaborate, the error was
|
|
|
|
|
already detected and printed. We just skip it and let
|
|
|
|
|
the compiler catch more errors. */
|
|
|
|
|
if (tmp == 0) continue;
|
|
|
|
|
|
2009-04-02 19:03:07 +02:00
|
|
|
if (tmp->expr_type() == IVL_VT_REAL) {
|
|
|
|
|
cerr << parms_[idx]->get_fileline() << ": error: "
|
|
|
|
|
<< "concatenation operand can not be real: "
|
|
|
|
|
<< *parms_[idx] << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
/* Link the new l-value to the previous one. */
|
|
|
|
|
NetAssign_*last = tmp;
|
|
|
|
|
while (last->more)
|
|
|
|
|
last = last->more;
|
2000-09-10 05:59:59 +02:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
last->more = res;
|
|
|
|
|
res = tmp;
|
2000-09-10 04:18:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
2000-09-09 17:21:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle the ident as an l-value. This includes bit and part selects
|
|
|
|
|
* of that ident.
|
|
|
|
|
*/
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
bool is_force) const
|
2000-09-09 17:21:26 +02:00
|
|
|
{
|
2003-09-19 05:30:04 +02:00
|
|
|
NetNet* reg = 0;
|
|
|
|
|
const NetExpr*par = 0;
|
|
|
|
|
NetEvent* eve = 0;
|
2012-01-04 02:38:08 +01:00
|
|
|
perm_string method_name;
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2013-03-15 04:08:32 +01:00
|
|
|
/* Try to detect the special case that we are in a method and
|
|
|
|
|
the identifier is a member of the class. */
|
|
|
|
|
if (NetAssign_*tmp = elaborate_lval_method_class_member_(des, scope))
|
|
|
|
|
return tmp;
|
|
|
|
|
|
2013-04-08 01:38:48 +02:00
|
|
|
NetScope*use_scope = scope;
|
|
|
|
|
if (package_) {
|
|
|
|
|
use_scope = des->find_package(package_->pscope_name());
|
|
|
|
|
ivl_assert(*this, use_scope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
symbol_search(this, des, use_scope, path_, reg, par, eve);
|
2012-01-04 02:38:08 +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 (reg == 0 && path_.size() >= 2) {
|
|
|
|
|
pform_name_t use_path = path_;
|
2012-11-25 19:13:05 +01:00
|
|
|
perm_string tmp_name = peek_tail_name(use_path);
|
2012-01-04 02:38:08 +01:00
|
|
|
use_path.pop_back();
|
2013-04-08 01:38:48 +02:00
|
|
|
symbol_search(this, des, use_scope, use_path, reg, par, eve);
|
2012-01-04 02:38:08 +01:00
|
|
|
|
2012-11-25 19:13:05 +01:00
|
|
|
if (reg && reg->struct_type()) {
|
|
|
|
|
method_name = tmp_name;
|
|
|
|
|
|
|
|
|
|
} else if (reg && reg->class_type()) {
|
|
|
|
|
method_name = tmp_name;
|
|
|
|
|
|
|
|
|
|
} else {
|
2012-01-04 02:38:08 +01:00
|
|
|
reg = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-19 05:30:04 +02:00
|
|
|
if (reg == 0) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Could not find variable ``"
|
2007-06-02 05:42:12 +02:00
|
|
|
<< path_ << "'' in ``" << scope_path(scope) <<
|
2002-06-04 07:38:43 +02:00
|
|
|
"''" << endl;
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
ivl_assert(*this, reg);
|
2012-02-11 02:17:59 +01:00
|
|
|
// We are processing the tail of a string of names. For
|
|
|
|
|
// example, the verilog may be "a.b.c", so we are processing
|
2012-11-25 19:13:05 +01:00
|
|
|
// "c" at this point. (Note that if method_name is not nil,
|
|
|
|
|
// then this is "a.b.c.method" and "a.b.c" is a struct or class.)
|
2007-05-24 06:07:11 +02:00
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
// Use the last index to determine what kind of select
|
|
|
|
|
// (bit/part/etc) we are processing. For example, the verilog
|
|
|
|
|
// may be "a.b.c[1][2][<index>]". All but the last index must
|
|
|
|
|
// be simple expressions, only the <index> may be a part
|
|
|
|
|
// select etc., so look at it to determine how we will be
|
|
|
|
|
// proceeding.
|
2007-05-24 06:07:11 +02:00
|
|
|
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
|
|
|
|
if (!name_tail.index.empty())
|
|
|
|
|
use_sel = name_tail.index.back().sel;
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
// Special case: The l-value is an entire memory, or array
|
|
|
|
|
// slice. This is, in fact, an error in l-values. Detect the
|
2012-04-07 01:38:38 +02:00
|
|
|
// situation by noting if the index count is less than the
|
2012-02-11 02:17:59 +01:00
|
|
|
// array dimensions (unpacked).
|
2012-05-26 00:58:29 +02:00
|
|
|
if (reg->unpacked_dimensions() > name_tail.index.size()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Cannot assign to array "
|
2007-03-14 06:06:49 +01:00
|
|
|
<< path_ << ". Did you forget a word index?" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-19 18:32:53 +01:00
|
|
|
/* Get the signal referenced by the identifier, and make sure
|
2012-02-11 02:17:59 +01:00
|
|
|
it is a register. Wires are not allowed in this context,
|
2009-02-19 18:32:53 +01:00
|
|
|
unless this is the l-value of a force. */
|
|
|
|
|
if ((reg->type() != NetNet::REG) && !is_force) {
|
|
|
|
|
cerr << get_fileline() << ": error: " << path_ <<
|
2013-04-08 01:38:48 +02:00
|
|
|
" is not a valid l-value in " << scope_path(use_scope) <<
|
2009-02-19 18:32:53 +01:00
|
|
|
"." << endl;
|
|
|
|
|
cerr << reg->get_fileline() << ": : " << path_ <<
|
|
|
|
|
" is declared here as " << reg->type() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-04 02:38:08 +01:00
|
|
|
if (reg->struct_type() && !method_name.nil()) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
2013-04-08 01:38:48 +02:00
|
|
|
elaborate_lval_net_packed_member_(des, use_scope, lv, method_name);
|
2012-01-04 02:38:08 +01:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-25 19:13:05 +01:00
|
|
|
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
2013-04-08 01:38:48 +02:00
|
|
|
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
|
2012-11-25 19:13:05 +01:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Past this point, we should have taken care of the cases
|
|
|
|
|
// where the name is a member/method of a struct/class.
|
|
|
|
|
ivl_assert(*this, method_name.nil());
|
|
|
|
|
|
2012-05-26 00:58:29 +02:00
|
|
|
if (reg->unpacked_dimensions() > 0)
|
2007-01-16 06:44:14 +01:00
|
|
|
return elaborate_lval_net_word_(des, scope, reg);
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2010-10-02 20:02:27 +02:00
|
|
|
// This must be after the array word elaboration above!
|
2009-04-15 01:08:27 +02:00
|
|
|
if (reg->get_scalar() &&
|
2009-04-02 03:31:29 +02:00
|
|
|
use_sel != index_component_t::SEL_NONE) {
|
2009-04-15 01:08:27 +02:00
|
|
|
cerr << get_fileline() << ": error: can not select part of ";
|
|
|
|
|
if (reg->data_type() == IVL_VT_REAL) cerr << "real: ";
|
|
|
|
|
else cerr << "scalar: ";
|
|
|
|
|
cerr << reg->name() << endl;
|
2009-04-02 03:31:29 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
if (use_sel == index_component_t::SEL_PART) {
|
2007-01-16 06:44:14 +01:00
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_net_part_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2007-11-07 20:26:56 +01:00
|
|
|
if (use_sel == index_component_t::SEL_IDX_UP ||
|
|
|
|
|
use_sel == index_component_t::SEL_IDX_DO) {
|
2007-01-16 06:44:14 +01:00
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
2007-11-07 20:26:56 +01:00
|
|
|
elaborate_lval_net_idx_(des, scope, lv, use_sel);
|
2007-01-16 06:44:14 +01:00
|
|
|
return lv;
|
|
|
|
|
}
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
if (use_sel == index_component_t::SEL_BIT) {
|
2012-07-21 17:59:29 +02:00
|
|
|
if (reg->darray_type()) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_darray_bit_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
} else {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_net_bit_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
2000-09-09 17:21:26 +02:00
|
|
|
}
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
/* No select expressions. */
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
2000-09-09 17:21:26 +02:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-15 04:08:32 +01:00
|
|
|
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
|
|
|
|
NetScope*scope) const
|
|
|
|
|
{
|
|
|
|
|
if (!gn_system_verilog())
|
|
|
|
|
return 0;
|
|
|
|
|
if (scope->parent() == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
if (path_.size() != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
const netclass_t*class_type = scope->parent()->class_def();
|
|
|
|
|
if (class_type == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
perm_string member_name = peek_tail_name(path_);
|
|
|
|
|
int pidx = class_type->property_idx_from_name(member_name);
|
|
|
|
|
if (pidx < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
NetNet*this_net = scope->find_signal(perm_string::literal("@"));
|
|
|
|
|
if (this_net == 0) {
|
|
|
|
|
cerr << get_fileline() << ": internal error: "
|
|
|
|
|
<< "Unable to find 'this' port of " << scope_path(scope)
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetAssign_*this_lval = new NetAssign_(this_net);
|
|
|
|
|
this_lval->set_property(member_name);
|
|
|
|
|
|
|
|
|
|
return this_lval;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
2006-04-16 02:54:04 +02:00
|
|
|
NetScope*scope,
|
|
|
|
|
NetNet*reg) const
|
2007-01-16 06:44:14 +01:00
|
|
|
{
|
2007-05-24 06:07:11 +02:00
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
ivl_assert(*this, !name_tail.index.empty());
|
|
|
|
|
|
2012-05-26 00:58:29 +02:00
|
|
|
if (name_tail.index.size() < reg->unpacked_dimensions()) {
|
|
|
|
|
cerr << get_fileline() << ": error: Array " << reg->name()
|
|
|
|
|
<< " needs " << reg->unpacked_dimensions() << " indices,"
|
|
|
|
|
<< " but got only " << name_tail.index.size() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure there are enough indices to address an array element.
|
2007-05-24 06:07:11 +02:00
|
|
|
const index_component_t&index_head = name_tail.index.front();
|
2007-11-07 20:26:56 +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-07 20:26:56 +01:00
|
|
|
<< "select on array " << reg->name() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2012-05-26 00:58:29 +02:00
|
|
|
// Evaluate all the index expressions into an
|
|
|
|
|
// "unpacked_indices" array.
|
|
|
|
|
list<NetExpr*>unpacked_indices;
|
|
|
|
|
list<long> unpacked_indices_const;
|
|
|
|
|
bool flag = indices_to_expressions(des, scope, this,
|
|
|
|
|
name_tail.index, reg->unpacked_dimensions(),
|
|
|
|
|
false,
|
|
|
|
|
unpacked_indices,
|
|
|
|
|
unpacked_indices_const);
|
|
|
|
|
|
|
|
|
|
NetExpr*canon_index = 0;
|
|
|
|
|
if (flag) {
|
|
|
|
|
ivl_assert(*this, unpacked_indices_const.size() == reg->unpacked_dimensions());
|
|
|
|
|
canon_index = normalize_variable_unpacked(reg, unpacked_indices_const);
|
|
|
|
|
if (canon_index == 0) {
|
|
|
|
|
cerr << get_fileline() << ": warning: "
|
|
|
|
|
<< "ignoring out of bounds l-value array access " << reg->name();
|
|
|
|
|
for (list<long>::const_iterator cur = unpacked_indices_const.begin()
|
|
|
|
|
; cur != unpacked_indices_const.end() ; ++cur) {
|
|
|
|
|
cerr << "[" << *cur << "]";
|
|
|
|
|
}
|
|
|
|
|
cerr << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ivl_assert(*this, unpacked_indices.size() == reg->unpacked_dimensions());
|
|
|
|
|
canon_index = normalize_variable_unpacked(reg, unpacked_indices);
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-26 00:58:29 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
2012-05-26 00:58:29 +02:00
|
|
|
lv->set_word(canon_index);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
|
|
|
|
if (debug_elaborate)
|
2012-05-26 00:58:29 +02:00
|
|
|
cerr << get_fileline() << ": debug: Set array word=" << *canon_index << endl;
|
|
|
|
|
|
2007-02-27 06:14:38 +01:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
/* An array word may also have part selects applied to them. */
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
2012-05-26 00:58:29 +02:00
|
|
|
if (name_tail.index.size() > reg->unpacked_dimensions())
|
2007-05-24 06:07:11 +02:00
|
|
|
use_sel = name_tail.index.back().sel;
|
|
|
|
|
|
2009-04-15 01:08:27 +02:00
|
|
|
if (reg->get_scalar() &&
|
2009-04-02 03:31:29 +02:00
|
|
|
use_sel != index_component_t::SEL_NONE) {
|
2009-04-15 01:08:27 +02:00
|
|
|
cerr << get_fileline() << ": error: can not select part of ";
|
|
|
|
|
if (reg->data_type() == IVL_VT_REAL) cerr << "real";
|
|
|
|
|
else cerr << "scalar";
|
|
|
|
|
cerr << " array word: " << reg->name()
|
2012-05-26 00:58:29 +02:00
|
|
|
<< "[" << *canon_index << "]" << endl;
|
2009-04-02 03:31:29 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-31 03:52:25 +02:00
|
|
|
if (use_sel == index_component_t::SEL_BIT)
|
|
|
|
|
elaborate_lval_net_bit_(des, scope, lv);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
if (use_sel == index_component_t::SEL_PART)
|
2007-01-16 06:44:14 +01:00
|
|
|
elaborate_lval_net_part_(des, scope, lv);
|
|
|
|
|
|
2007-11-07 20:26:56 +01:00
|
|
|
if (use_sel == index_component_t::SEL_IDX_UP ||
|
|
|
|
|
use_sel == index_component_t::SEL_IDX_DO)
|
|
|
|
|
elaborate_lval_net_idx_(des, scope, lv, use_sel);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv) const
|
|
|
|
|
{
|
2012-02-11 02:17:59 +01:00
|
|
|
list<long>prefix_indices;
|
|
|
|
|
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
2012-02-12 20:16:31 +01:00
|
|
|
if (!rc) return false;
|
2012-02-11 02:17:59 +01:00
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
const name_component_t&name_tail = path_.back();
|
2012-02-11 02:17:59 +01:00
|
|
|
ivl_assert(*this, !name_tail.index.empty());
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
const index_component_t&index_tail = name_tail.index.back();
|
|
|
|
|
ivl_assert(*this, index_tail.msb != 0);
|
|
|
|
|
ivl_assert(*this, index_tail.lsb == 0);
|
|
|
|
|
|
|
|
|
|
NetNet*reg = lv->sig();
|
2013-01-25 19:25:12 +01:00
|
|
|
ivl_assert(*this, reg);
|
2008-06-15 06:22:55 +02:00
|
|
|
|
2009-07-04 00:37:44 +02:00
|
|
|
// Bit selects have a single select expression. Evaluate the
|
2008-06-15 06:22:55 +02:00
|
|
|
// constant value and treat it as a part select with a bit
|
|
|
|
|
// width of 1.
|
|
|
|
|
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
|
|
|
|
|
long lsb = 0;
|
|
|
|
|
|
|
|
|
|
if (NetEConst*index_con = dynamic_cast<NetEConst*> (mux)) {
|
2013-01-25 19:25:12 +01:00
|
|
|
// The index has a constant defined value.
|
|
|
|
|
if (index_con->value().is_defined()) {
|
|
|
|
|
lsb = index_con->value().as_long();
|
|
|
|
|
mux = 0;
|
|
|
|
|
// The index is undefined and this is a packed array.
|
|
|
|
|
} else if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
|
|
|
|
|
long loff;
|
|
|
|
|
unsigned long lwid;
|
|
|
|
|
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
|
|
|
|
ivl_assert(*this, rcl);
|
|
|
|
|
cerr << get_fileline() << ": warning: L-value packed array "
|
|
|
|
|
<< "select of " << reg->name();
|
|
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << " has an undefined index." << endl;
|
|
|
|
|
|
|
|
|
|
lv->set_part(new NetEConst(verinum(verinum::Vx)), lwid);
|
|
|
|
|
return true;
|
|
|
|
|
// The index is undefined and this is a bit select.
|
|
|
|
|
} else {
|
|
|
|
|
cerr << get_fileline() << ": warning: L-value bit select of "
|
|
|
|
|
<< reg->name();
|
|
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << " has an undefined index." << endl;
|
2008-06-15 06:22:55 +02:00
|
|
|
|
2013-01-25 19:25:12 +01:00
|
|
|
lv->set_part(new NetEConst(verinum(verinum::Vx)), 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-02-07 02:47:53 +01:00
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
|
|
|
|
|
// Special case: this is a slice of a multi-dimensional
|
|
|
|
|
// packed array. For example:
|
|
|
|
|
// reg [3:0][7:0] x;
|
|
|
|
|
// x[2] = ...
|
|
|
|
|
// This shows up as the prefix_indices being too short
|
|
|
|
|
// for the packed dimensions of the vector. What we do
|
|
|
|
|
// here is convert to a "slice" of the vector.
|
|
|
|
|
if (mux == 0) {
|
|
|
|
|
long loff;
|
|
|
|
|
unsigned long lwid;
|
|
|
|
|
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
|
|
|
|
ivl_assert(*this, rcl);
|
|
|
|
|
|
|
|
|
|
lv->set_part(new NetEConst(verinum(loff)), lwid);
|
|
|
|
|
} else {
|
|
|
|
|
unsigned long lwid;
|
|
|
|
|
mux = normalize_variable_slice_base(prefix_indices, mux,
|
|
|
|
|
reg, lwid);
|
|
|
|
|
lv->set_part(mux, lwid);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-01 20:44:47 +02:00
|
|
|
} else if (reg->data_type() == IVL_VT_STRING) {
|
|
|
|
|
// Special case: This is a select of a string
|
|
|
|
|
// variable. The target of the assignment is a character
|
|
|
|
|
// select of a string. Force the r-value to be an 8bit
|
|
|
|
|
// vector and set the "part" to be the character select
|
|
|
|
|
// expression. The code generator knows what to do with
|
|
|
|
|
// this.
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: "
|
|
|
|
|
<< "Bit select of string becomes character select." << endl;
|
|
|
|
|
}
|
|
|
|
|
if (mux)
|
|
|
|
|
lv->set_part(mux, 8);
|
|
|
|
|
else
|
|
|
|
|
lv->set_part(new NetEConst(verinum(lsb)), 8);
|
|
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
} else if (mux) {
|
2008-06-15 06:22:55 +02:00
|
|
|
// Non-constant bit mux. Correct the mux for the range
|
2012-02-07 02:47:53 +01:00
|
|
|
// of the vector, then set the l-value part select
|
|
|
|
|
// expression.
|
2012-02-12 19:13:20 +01:00
|
|
|
mux = normalize_variable_bit_base(prefix_indices, mux, reg);
|
2008-06-15 06:22:55 +02:00
|
|
|
lv->set_part(mux, 1);
|
|
|
|
|
|
2012-02-11 02:17:59 +01:00
|
|
|
} else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) {
|
2008-06-15 06:22:55 +02:00
|
|
|
// Constant bit mux that happens to select the only bit
|
|
|
|
|
// of the l-value. Don't bother with any select at all.
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// Constant bit select that does something useful.
|
2012-02-11 02:17:59 +01:00
|
|
|
long loff = reg->sb_to_idx(prefix_indices,lsb);
|
2008-06-15 06:22:55 +02:00
|
|
|
|
|
|
|
|
if (loff < 0 || loff >= (long)reg->vector_width()) {
|
|
|
|
|
cerr << get_fileline() << ": error: bit select "
|
|
|
|
|
<< reg->name() << "[" <<lsb<<"]"
|
|
|
|
|
<< " is out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lv->set_part(new NetEConst(verinum(loff)), 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-21 17:59:29 +02:00
|
|
|
bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*lv)const
|
|
|
|
|
{
|
|
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
ivl_assert(*this, !name_tail.index.empty());
|
|
|
|
|
|
|
|
|
|
// For now, only support single-dimension dynamic arrays.
|
|
|
|
|
ivl_assert(*this, name_tail.index.size() == 1);
|
|
|
|
|
|
|
|
|
|
const index_component_t&index_tail = name_tail.index.back();
|
|
|
|
|
ivl_assert(*this, index_tail.msb != 0);
|
|
|
|
|
ivl_assert(*this, index_tail.lsb == 0);
|
|
|
|
|
|
|
|
|
|
// Evaluate the select expression...
|
|
|
|
|
NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1);
|
|
|
|
|
|
|
|
|
|
lv->set_word(mux);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
bool PEIdent::elaborate_lval_net_part_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv) const
|
2006-04-16 02:54:04 +02:00
|
|
|
{
|
2012-02-11 02:17:59 +01:00
|
|
|
list<long> prefix_indices;
|
|
|
|
|
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
// The range expressions of a part select must be
|
|
|
|
|
// constant. The calculate_parts_ function calculates the
|
|
|
|
|
// values into msb and lsb.
|
2006-11-04 07:19:24 +01:00
|
|
|
long msb, lsb;
|
2009-01-02 01:20:41 +01:00
|
|
|
bool parts_defined_flag;
|
|
|
|
|
bool flag = calculate_parts_(des, scope, msb, lsb, parts_defined_flag);
|
2013-01-25 19:25:12 +01:00
|
|
|
if (!flag) return false;
|
2009-01-02 01:20:41 +01:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
NetNet*reg = lv->sig();
|
2012-02-07 02:47:53 +01:00
|
|
|
ivl_assert(*this, reg);
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2013-01-25 19:25:12 +01:00
|
|
|
if (! parts_defined_flag) {
|
|
|
|
|
cerr << get_fileline() << ": warning: L-value part select of "
|
|
|
|
|
<< reg->name();
|
|
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << " has an undefined index." << endl;
|
|
|
|
|
// Use a width of two here so we can distinguish between an
|
|
|
|
|
// undefined bit or part select.
|
|
|
|
|
lv->set_part(new NetEConst(verinum(verinum::Vx)), 2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 00:13:45 +02:00
|
|
|
const vector<netrange_t>&packed = reg->packed_dims();
|
2012-02-07 02:47:53 +01:00
|
|
|
|
2013-02-14 04:50:05 +01:00
|
|
|
long loff, moff;
|
|
|
|
|
long wid;
|
2012-02-11 03:48:12 +01:00
|
|
|
if (prefix_indices.size()+1 < packed.size()) {
|
2013-02-14 04:50:05 +01:00
|
|
|
// If there are fewer indices then there are packed
|
|
|
|
|
// dimensions, then this is a range of slices. Calculate
|
|
|
|
|
// it into a big slice.
|
|
|
|
|
bool lrc;
|
|
|
|
|
unsigned long tmp_lwid, tmp_mwid;
|
|
|
|
|
lrc = reg->sb_to_slice(prefix_indices,lsb, loff, tmp_lwid);
|
|
|
|
|
lrc = reg->sb_to_slice(prefix_indices,msb, moff, tmp_mwid);
|
|
|
|
|
|
|
|
|
|
if (loff < moff) {
|
|
|
|
|
moff = moff + tmp_mwid - 1;
|
|
|
|
|
} else {
|
|
|
|
|
long ltmp = moff;
|
|
|
|
|
moff = loff + tmp_lwid - 1;
|
|
|
|
|
loff = ltmp;
|
|
|
|
|
}
|
|
|
|
|
wid = moff - loff + 1;
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2013-02-14 04:50:05 +01:00
|
|
|
} else {
|
|
|
|
|
loff = reg->sb_to_idx(prefix_indices,lsb);
|
|
|
|
|
moff = reg->sb_to_idx(prefix_indices,msb);
|
|
|
|
|
wid = moff - loff + 1;
|
|
|
|
|
|
|
|
|
|
if (moff < loff) {
|
|
|
|
|
cerr << get_fileline() << ": error: part select "
|
|
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is reversed." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-02-11 03:48:12 +01:00
|
|
|
}
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2012-02-11 03:48:12 +01:00
|
|
|
// Special case: The range winds up selecting the entire
|
|
|
|
|
// vector. Treat this as no part select at all.
|
2012-02-23 00:08:24 +01:00
|
|
|
if (loff == 0 && moff == (long)(reg->vector_width()-1)) {
|
2012-02-11 03:48:12 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2012-02-11 03:48:12 +01:00
|
|
|
/* If the part select extends beyond the extremes of the
|
|
|
|
|
variable, then report an error. Note that loff is
|
|
|
|
|
converted to normalized form so is relative the
|
|
|
|
|
variable pins. */
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2012-02-23 00:08:24 +01:00
|
|
|
if (loff < 0 || moff >= (long)reg->vector_width()) {
|
2012-02-11 03:48:12 +01:00
|
|
|
cerr << get_fileline() << ": warning: Part select "
|
|
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is out of range." << endl;
|
2006-04-16 02:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
2012-02-11 03:48:12 +01:00
|
|
|
lv->set_part(new NetEConst(verinum(loff)), wid);
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
return true;
|
2006-04-16 02:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
2007-11-07 20:26:56 +01:00
|
|
|
bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv,
|
|
|
|
|
index_component_t::ctype_t use_sel) const
|
2006-04-16 02:15:43 +02:00
|
|
|
{
|
2012-02-11 02:17:59 +01:00
|
|
|
list<long>prefix_indices;
|
|
|
|
|
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
const name_component_t&name_tail = path_.back();;
|
|
|
|
|
ivl_assert(*this, !name_tail.index.empty());
|
|
|
|
|
|
|
|
|
|
const index_component_t&index_tail = name_tail.index.back();
|
|
|
|
|
ivl_assert(*this, index_tail.msb != 0);
|
|
|
|
|
ivl_assert(*this, index_tail.lsb != 0);
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
NetNet*reg = lv->sig();
|
|
|
|
|
assert(reg);
|
|
|
|
|
|
2006-04-16 02:15:43 +02:00
|
|
|
if (reg->type() != NetNet::REG) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: " << path_ <<
|
2007-06-02 05:42:12 +02:00
|
|
|
" is not a reg/integer/time in " << scope_path(scope) <<
|
2006-04-16 02:15:43 +02:00
|
|
|
"." << endl;
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << reg->get_fileline() << ": : " << path_ <<
|
2006-04-16 02:15:43 +02:00
|
|
|
" is declared here as " << reg->type() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2006-04-16 02:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
2006-11-04 07:19:24 +01:00
|
|
|
unsigned long wid;
|
|
|
|
|
calculate_up_do_width_(des, scope, wid);
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
2011-02-23 18:15:36 +01:00
|
|
|
ivl_select_type_t sel_type = IVL_SEL_OTHER;
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2009-08-29 01:50:59 +02:00
|
|
|
// Handle the special case that the base is constant. For this
|
|
|
|
|
// case we can reduce the expression.
|
|
|
|
|
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
|
|
|
|
// For the undefined case just let the constant pass and
|
|
|
|
|
// we will handle it in the code generator.
|
|
|
|
|
if (base_c->value().is_defined()) {
|
|
|
|
|
long lsv = base_c->value().as_long();
|
|
|
|
|
long offset = 0;
|
2012-02-12 21:03:43 +01:00
|
|
|
// Get the signal range.
|
2012-09-30 00:13:45 +02:00
|
|
|
const vector<netrange_t>&packed = reg->packed_dims();
|
2012-02-12 21:03:43 +01:00
|
|
|
ivl_assert(*this, packed.size() == prefix_indices.size()+1);
|
2012-02-07 02:47:53 +01:00
|
|
|
|
2012-02-12 21:03:43 +01:00
|
|
|
// We want the last range, which is where we work.
|
2012-03-26 02:59:05 +02:00
|
|
|
const netrange_t&rng = packed.back();
|
2012-07-14 03:41:41 +02:00
|
|
|
if (((rng.get_msb() < rng.get_lsb()) &&
|
2009-08-29 01:50:59 +02:00
|
|
|
use_sel == index_component_t::SEL_IDX_UP) ||
|
2012-07-14 03:41:41 +02:00
|
|
|
((rng.get_msb() > rng.get_lsb()) &&
|
2009-08-29 01:50:59 +02:00
|
|
|
use_sel == index_component_t::SEL_IDX_DO)) {
|
|
|
|
|
offset = -wid + 1;
|
|
|
|
|
}
|
|
|
|
|
delete base;
|
2012-02-11 02:17:59 +01:00
|
|
|
long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset;
|
2009-09-18 04:06:40 +02:00
|
|
|
/* If we cover the entire lvalue just skip the select. */
|
|
|
|
|
if (rel_base == 0 && wid == reg->vector_width()) return true;
|
|
|
|
|
base = new NetEConst(verinum(rel_base));
|
2009-08-29 01:50:59 +02:00
|
|
|
if (warn_ob_select) {
|
|
|
|
|
if (rel_base < 0) {
|
|
|
|
|
cerr << get_fileline() << ": warning: " << reg->name();
|
2012-05-26 00:58:29 +02:00
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
2009-08-29 01:50:59 +02:00
|
|
|
cerr << "[" << lsv;
|
|
|
|
|
if (use_sel == index_component_t::SEL_IDX_UP) {
|
|
|
|
|
cerr << "+:";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "-:";
|
|
|
|
|
}
|
|
|
|
|
cerr << wid << "] is selecting before vector." << endl;
|
|
|
|
|
}
|
|
|
|
|
if (rel_base + wid > reg->vector_width()) {
|
|
|
|
|
cerr << get_fileline() << ": warning: " << reg->name();
|
2012-05-26 00:58:29 +02:00
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
2009-08-29 01:50:59 +02:00
|
|
|
cerr << "[" << lsv;
|
|
|
|
|
if (use_sel == index_component_t::SEL_IDX_UP) {
|
|
|
|
|
cerr << "+:";
|
|
|
|
|
} else {
|
|
|
|
|
cerr << "-:";
|
|
|
|
|
}
|
|
|
|
|
cerr << wid << "] is selecting after vector." << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2013-01-25 19:25:12 +01:00
|
|
|
cerr << get_fileline() << ": warning: L-value indexed part "
|
|
|
|
|
<< "select of " << reg->name();
|
|
|
|
|
if (reg->unpacked_dimensions() > 0) cerr << "[]";
|
|
|
|
|
cerr << " has an undefined base." << endl;
|
2009-08-29 01:50:59 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2012-02-12 23:52:47 +01:00
|
|
|
ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size());
|
2009-08-29 01:50:59 +02:00
|
|
|
/* Correct the mux for the range of the vector. */
|
|
|
|
|
if (use_sel == index_component_t::SEL_IDX_UP) {
|
2012-02-12 23:52:47 +01:00
|
|
|
base = normalize_variable_part_base(prefix_indices, base,
|
|
|
|
|
reg, wid, true);
|
2011-02-23 18:15:36 +01:00
|
|
|
sel_type = IVL_SEL_IDX_UP;
|
2009-08-29 01:50:59 +02:00
|
|
|
} else {
|
|
|
|
|
// This is assumed to be a SEL_IDX_DO.
|
2012-02-12 23:52:47 +01:00
|
|
|
base = normalize_variable_part_base(prefix_indices, base,
|
|
|
|
|
reg, wid, false);
|
2011-02-23 18:15:36 +01:00
|
|
|
sel_type = IVL_SEL_IDX_DOWN;
|
2009-08-29 01:50:59 +02:00
|
|
|
}
|
2007-11-07 20:26:56 +01:00
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Set part select width="
|
2007-01-16 06:44:14 +01:00
|
|
|
<< wid << ", base=" << *base << endl;
|
|
|
|
|
|
2011-02-23 18:15:36 +01:00
|
|
|
lv->set_part(base, wid, sel_type);
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
return true;
|
2006-04-16 02:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 01:38:48 +02:00
|
|
|
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
|
2012-11-25 19:13:05 +01:00
|
|
|
NetAssign_*lv,
|
|
|
|
|
const perm_string&method_name) const
|
|
|
|
|
{
|
|
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
|
|
|
|
|
<< "l-value is property " << method_name
|
|
|
|
|
<< " of " << lv->sig()->name() << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
netclass_t*class_type = lv->sig()->class_type();
|
|
|
|
|
ivl_assert(*this, class_type);
|
|
|
|
|
|
|
|
|
|
/* Make sure the property is really present in the class. If
|
|
|
|
|
not, then generate an error message and return an error. */
|
|
|
|
|
const ivl_type_s*ptype = class_type->get_property(method_name);
|
|
|
|
|
if (ptype == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Class " << class_type->get_name()
|
|
|
|
|
<< " does not have a property " << method_name << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lv->set_property(method_name);
|
2013-01-27 21:30:38 +01:00
|
|
|
|
|
|
|
|
const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype);
|
|
|
|
|
if (mtype) {
|
|
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
if (name_tail.index.size() > 0) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: "
|
|
|
|
|
<< "Array index of array properties not supported."
|
|
|
|
|
<< endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-25 19:13:05 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-18 02:26:19 +01:00
|
|
|
|
2012-03-26 02:59:05 +02:00
|
|
|
bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
2012-01-04 02:38:08 +01:00
|
|
|
NetAssign_*lv,
|
|
|
|
|
const perm_string&member_name) const
|
|
|
|
|
{
|
|
|
|
|
NetNet*reg = lv->sig();
|
|
|
|
|
ivl_assert(*this, reg);
|
|
|
|
|
|
2012-09-30 00:13:45 +02:00
|
|
|
const netstruct_t*struct_type = reg->struct_type();
|
2012-01-04 02:38:08 +01:00
|
|
|
ivl_assert(*this, struct_type);
|
|
|
|
|
|
2012-08-06 01:28:40 +02:00
|
|
|
if (debug_elaborate) {
|
|
|
|
|
cerr << get_fileline() << ": debug: elaborate lval packed member: "
|
|
|
|
|
<< "path_=" << path_ << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-04 02:38:08 +01:00
|
|
|
if (! struct_type->packed()) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: Only packed structures "
|
|
|
|
|
<< "are supported in l-value." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-06 01:28:40 +02:00
|
|
|
// Shouldn't be seeing unpacked arrays of packed structs...
|
|
|
|
|
ivl_assert(*this, reg->unpacked_dimensions() == 0);
|
|
|
|
|
|
|
|
|
|
// This is a packed member, so the name is of the form
|
|
|
|
|
// "a.b[...].c[...]" which means that the path_ must have at
|
|
|
|
|
// least 2 components. We are processing "c[...]" at that
|
|
|
|
|
// point (otherwise known as member_name) so we'll save a
|
|
|
|
|
// reference to it in name_tail. We are also processing "b[]"
|
|
|
|
|
// so save that as name_base.
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, path_.size() >= 2);
|
|
|
|
|
|
|
|
|
|
pform_name_t::const_reverse_iterator name_idx = path_.rbegin();
|
|
|
|
|
ivl_assert(*this, name_idx->name == member_name);
|
|
|
|
|
const name_component_t&name_tail = *name_idx;
|
|
|
|
|
++ name_idx;
|
|
|
|
|
const name_component_t&name_base = *name_idx;
|
|
|
|
|
|
2012-08-20 02:27:48 +02:00
|
|
|
// Calculate the offset within the packed structure of the
|
|
|
|
|
// member, and any indices. We will add in the offset of the
|
|
|
|
|
// struct into the packed array later.
|
2012-01-04 02:38:08 +01:00
|
|
|
unsigned long off;
|
|
|
|
|
const netstruct_t::member_t* member = struct_type->packed_member(member_name, off);
|
|
|
|
|
|
|
|
|
|
if (member == 0) {
|
|
|
|
|
cerr << get_fileline() << ": error: Member " << member_name
|
|
|
|
|
<< " is not a member of variable " << reg->name() << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-26 02:59:05 +02:00
|
|
|
unsigned long use_width = member->width();
|
|
|
|
|
|
|
|
|
|
if (name_tail.index.size() > member->packed_dims.size()) {
|
2012-09-04 00:56:40 +02:00
|
|
|
cerr << get_fileline() << ": error: Too many index expressions for member." << endl;
|
2012-03-26 02:59:05 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the index component type. At this point, we only
|
|
|
|
|
// support bit select or none.
|
|
|
|
|
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
|
|
|
|
if (!name_tail.index.empty())
|
|
|
|
|
use_sel = name_tail.index.back().sel;
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT);
|
|
|
|
|
|
2012-08-08 20:26:46 +02:00
|
|
|
if (! name_tail.index.empty()) {
|
2012-03-26 02:59:05 +02:00
|
|
|
// Evaluate all but the last index expression, into prefix_indices.
|
|
|
|
|
list<long>prefix_indices;
|
|
|
|
|
bool rc = evaluate_index_prefix(des, scope, prefix_indices, name_tail.index);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
|
|
|
|
|
// Evaluate the last index expression into a constant long.
|
|
|
|
|
NetExpr*texpr = elab_and_eval(des, scope, name_tail.index.back().msb, -1, true);
|
|
|
|
|
long tmp;
|
|
|
|
|
if (texpr == 0 || !eval_as_long(tmp, texpr)) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
"Array index expressions must be constant here." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete texpr;
|
|
|
|
|
|
|
|
|
|
// Now use the prefix_to_slice function to calculate the
|
|
|
|
|
// offset and width of the addressed slice of the member.
|
|
|
|
|
long loff;
|
|
|
|
|
unsigned long lwid;
|
|
|
|
|
prefix_to_slice(member->packed_dims, prefix_indices, tmp, loff, lwid);
|
|
|
|
|
|
|
|
|
|
off += loff;
|
|
|
|
|
use_width = lwid;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-20 02:27:48 +02:00
|
|
|
// The dimenions in the expression must match the packed
|
|
|
|
|
// dimensions that are declared for the variable. For example,
|
|
|
|
|
// if foo is a packed array of struct, then this expression
|
|
|
|
|
// must be "b[n][m]" with the right number of dimensions to
|
|
|
|
|
// match the declaration of "b".
|
|
|
|
|
// Note that one of the packed dimensions is the packed struct
|
|
|
|
|
// itself.
|
|
|
|
|
ivl_assert(*this, name_base.index.size()+1 == reg->packed_dimensions());
|
|
|
|
|
|
|
|
|
|
// Generate an expression that takes the input array of
|
|
|
|
|
// expressions and generates a canonical offset into the
|
|
|
|
|
// packed array.
|
|
|
|
|
NetExpr*packed_base = 0;
|
|
|
|
|
if (reg->packed_dimensions() > 1) {
|
|
|
|
|
list<index_component_t>tmp_index = name_base.index;
|
|
|
|
|
index_component_t member_select;
|
|
|
|
|
member_select.sel = index_component_t::SEL_BIT;
|
|
|
|
|
member_select.msb = new PENumber(new verinum(off));
|
|
|
|
|
tmp_index.push_back(member_select);
|
|
|
|
|
packed_base = collapse_array_indices(des, scope, reg, tmp_index);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-06 01:28:40 +02:00
|
|
|
long tmp;
|
2012-08-20 02:27:48 +02:00
|
|
|
if (packed_base && eval_as_long(tmp, packed_base)) {
|
|
|
|
|
off = tmp;
|
2012-08-06 01:28:40 +02:00
|
|
|
delete packed_base;
|
|
|
|
|
packed_base = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (packed_base == 0) {
|
|
|
|
|
lv->set_part(new NetEConst(verinum(off)), use_width);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-20 02:27:48 +02:00
|
|
|
// Oops, packed_base is not fully evaluated, so I don't know
|
|
|
|
|
// yet what to do with it.
|
|
|
|
|
cerr << get_fileline() << ": internal error: "
|
|
|
|
|
<< "I don't know how to handle this index expression? " << *packed_base << endl;
|
2012-08-06 01:28:40 +02:00
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
return false;
|
2012-01-04 02:38:08 +01:00
|
|
|
}
|
|
|
|
|
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
|
2002-03-09 05:02:26 +01:00
|
|
|
{
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: Constant values not allowed "
|
2002-03-09 05:02:26 +01:00
|
|
|
<< "in l-value expressions." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|