2000-09-09 17:21:26 +02:00
|
|
|
/*
|
2009-01-09 02:59:39 +01:00
|
|
|
* Copyright (c) 2000-2009 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
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
# include "PExpr.h"
|
|
|
|
|
# include "netlist.h"
|
2003-09-19 05:30:04 +02:00
|
|
|
# include "netmisc.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;
|
2003-01-27 06:09:17 +01:00
|
|
|
* rather then 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.
|
|
|
|
|
*/
|
2004-12-30 00:55:43 +01:00
|
|
|
NetAssign_* PExpr::elaborate_lval(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
bool is_force) 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
|
|
|
|
2000-09-10 04:18:16 +02:00
|
|
|
for (unsigned idx = 0 ; idx < parms_.count() ; 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
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2000-09-10 04:18:16 +02:00
|
|
|
assert(tmp);
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2000-09-10 05:59:59 +02:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
/* Link the new l-value to the previous one. */
|
2000-09-10 05:59:59 +02:00
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
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;
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
symbol_search(this, des, scope, path_, reg, par, eve);
|
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);
|
|
|
|
|
|
|
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-03-14 06:06:49 +01:00
|
|
|
// This is the special case that the l-value is an entire
|
|
|
|
|
// memory. This is, in fact, an error.
|
2007-05-24 06:07:11 +02:00
|
|
|
if (reg->array_dimensions() > 0 && name_tail.index.empty()) {
|
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
|
|
|
|
|
it is a register. Wires are not allows in this context,
|
|
|
|
|
unless this is the l-value of a force. */
|
|
|
|
|
if ((reg->type() != NetNet::REG) && !is_force) {
|
|
|
|
|
cerr << get_fileline() << ": error: " << path_ <<
|
|
|
|
|
" is not a valid l-value in " << scope_path(scope) <<
|
|
|
|
|
"." << endl;
|
|
|
|
|
cerr << reg->get_fileline() << ": : " << path_ <<
|
|
|
|
|
" is declared here as " << reg->type() << "." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
if (reg->array_dimensions() > 0)
|
|
|
|
|
return elaborate_lval_net_word_(des, scope, reg);
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2009-04-02 03:31:29 +02:00
|
|
|
// This must be after the array word elaboration above!
|
|
|
|
|
if (reg->data_type() == IVL_VT_REAL &&
|
|
|
|
|
use_sel != index_component_t::SEL_NONE) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
2009-04-02 20:05:09 +02:00
|
|
|
<< "can not select part of real: " << 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) {
|
2008-06-15 06:22:55 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
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-05-24 06:07:11 +02:00
|
|
|
ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
|
|
|
|
|
ivl_assert(*this, index_head.msb != 0);
|
|
|
|
|
ivl_assert(*this, index_head.lsb == 0);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2009-01-02 13:43:59 +01:00
|
|
|
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
|
2009-01-08 04:01:09 +01:00
|
|
|
// This not used, but it needs to have a default value.
|
|
|
|
|
bool unsized_flag_tmp = false;
|
2009-01-02 13:43:59 +01:00
|
|
|
index_head.msb->test_width(des, scope,
|
|
|
|
|
reg->vector_width(), reg->vector_width(),
|
|
|
|
|
expr_type_tmp,
|
|
|
|
|
unsized_flag_tmp);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
NetExpr*word = elab_and_eval(des, scope, index_head.msb, -1);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
|
|
|
|
// If there is a non-zero base to the memory, then build an
|
|
|
|
|
// expression to calculate the canonical address.
|
|
|
|
|
if (long base = reg->array_first()) {
|
|
|
|
|
|
|
|
|
|
word = make_add_expr(word, 0-base);
|
2008-03-08 03:51:50 +01:00
|
|
|
eval_expr(word);
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
lv->set_word(word);
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate)
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": debug: Set array word=" << *word << endl;
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2007-02-27 06:14:38 +01:00
|
|
|
// Test for the case that the index is a constant, and is out
|
|
|
|
|
// of bounds. The "word" expression is the word index already
|
|
|
|
|
// converted to canonical address, so this just needs to check
|
|
|
|
|
// that the address is not too big.
|
|
|
|
|
if (NetEConst*word_const = dynamic_cast<NetEConst*>(word)) {
|
|
|
|
|
verinum word_val = word_const->value();
|
|
|
|
|
long index = word_val.as_long();
|
2009-02-19 18:32:53 +01:00
|
|
|
|
2008-01-07 22:10:18 +01:00
|
|
|
if (index < 0 || index >= (long) reg->array_count()) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": warning: Constant array index "
|
2007-02-27 06:14:38 +01:00
|
|
|
<< (index + reg->array_first())
|
|
|
|
|
<< " is out of range for array "
|
|
|
|
|
<< reg->name() << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
if (name_tail.index.size() > 1)
|
|
|
|
|
use_sel = name_tail.index.back().sel;
|
|
|
|
|
|
2009-04-02 03:31:29 +02:00
|
|
|
if (reg->data_type() == IVL_VT_REAL &&
|
|
|
|
|
use_sel != index_component_t::SEL_NONE) {
|
2009-04-02 20:05:09 +02:00
|
|
|
perm_string name = peek_tail_name(path_);
|
2009-04-02 03:31:29 +02:00
|
|
|
cerr << get_fileline() << ": error: "
|
2009-04-02 20:05:09 +02:00
|
|
|
<< "can not select part of real array word: "
|
|
|
|
|
<< reg->name() << "[" << *word << "]" << 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
|
|
|
|
|
{
|
|
|
|
|
const name_component_t&name_tail = path_.back();
|
|
|
|
|
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();
|
|
|
|
|
|
2009-01-02 13:43:59 +01:00
|
|
|
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
|
2009-01-08 04:01:09 +01:00
|
|
|
// This not used, but it needs to have a default value.
|
|
|
|
|
bool unsized_flag_tmp = false;
|
2009-01-02 13:43:59 +01:00
|
|
|
index_tail.msb->test_width(des, scope,
|
|
|
|
|
lv->lwidth(), lv->lwidth(),
|
|
|
|
|
expr_type_tmp,
|
|
|
|
|
unsized_flag_tmp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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)) {
|
|
|
|
|
lsb = index_con->value().as_long();
|
|
|
|
|
mux = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mux) {
|
|
|
|
|
// Non-constant bit mux. Correct the mux for the range
|
|
|
|
|
// of the vector, then set the l-value part select expression.
|
|
|
|
|
if (reg->msb() < reg->lsb())
|
|
|
|
|
mux = make_sub_expr(reg->lsb(), mux);
|
|
|
|
|
else if (reg->lsb() != 0)
|
|
|
|
|
mux = make_add_expr(mux, - reg->lsb());
|
|
|
|
|
|
|
|
|
|
lv->set_part(mux, 1);
|
|
|
|
|
|
|
|
|
|
} else if (lsb == reg->msb() && lsb == reg->lsb()) {
|
|
|
|
|
// 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.
|
|
|
|
|
long loff = reg->sb_to_idx(lsb);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
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);
|
2006-11-04 07:19:24 +01:00
|
|
|
if (!flag)
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2006-04-16 02:54:04 +02:00
|
|
|
|
2009-01-02 01:20:41 +01:00
|
|
|
ivl_assert(*this, parts_defined_flag);
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
NetNet*reg = lv->sig();
|
|
|
|
|
assert(reg);
|
2006-04-16 02:54:04 +02:00
|
|
|
|
|
|
|
|
if (msb == reg->msb() && lsb == reg->lsb()) {
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
/* Part select covers the entire vector. Simplest case. */
|
2006-04-16 02:54:04 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
/* Get the canonical offsets into the vector. */
|
|
|
|
|
long loff = reg->sb_to_idx(lsb);
|
|
|
|
|
long moff = reg->sb_to_idx(msb);
|
|
|
|
|
long wid = moff - loff + 1;
|
2006-04-16 02:54:04 +02:00
|
|
|
|
|
|
|
|
if (moff < loff) {
|
2007-12-20 18:31:01 +01:00
|
|
|
cerr << get_fileline() << ": error: part select "
|
2006-04-16 02:54:04 +02:00
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is reversed." << endl;
|
|
|
|
|
des->errors += 1;
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2006-04-16 02:54:04 +02:00
|
|
|
}
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
/* If the part select extends beyond the extremes of the
|
2006-04-16 02:54:04 +02:00
|
|
|
variable, then report an error. Note that loff is
|
|
|
|
|
converted to normalized form so is relative the
|
|
|
|
|
variable pins. */
|
|
|
|
|
|
2008-06-15 06:22:55 +02:00
|
|
|
if (loff < 0 || moff >= (signed)reg->vector_width()) {
|
|
|
|
|
cerr << get_fileline() << ": warning: Part select "
|
2006-04-16 02:54:04 +02:00
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is out of range." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
{
|
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
|
|
|
|
2009-01-02 13:43:59 +01:00
|
|
|
ivl_variable_type_t expr_type_tmp = IVL_VT_NO_TYPE;
|
2009-01-08 04:01:09 +01:00
|
|
|
// This not used, but it needs to have a default value.
|
|
|
|
|
bool unsized_flag_tmp = false;
|
2009-01-02 13:43:59 +01:00
|
|
|
index_tail.msb->test_width(des, scope,
|
|
|
|
|
wid, wid,
|
|
|
|
|
expr_type_tmp,
|
|
|
|
|
unsized_flag_tmp);
|
|
|
|
|
|
2007-05-24 06:07:11 +02:00
|
|
|
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
2006-04-16 02:15:43 +02:00
|
|
|
|
|
|
|
|
/* Correct the mux for the range of the vector. */
|
|
|
|
|
if (reg->msb() < reg->lsb())
|
|
|
|
|
base = make_sub_expr(reg->lsb(), base);
|
|
|
|
|
else if (reg->lsb() != 0)
|
|
|
|
|
base = make_add_expr(base, - reg->lsb());
|
|
|
|
|
|
2007-11-07 20:26:56 +01:00
|
|
|
if (use_sel == index_component_t::SEL_IDX_DO && wid > 1 ) {
|
|
|
|
|
base = make_add_expr(base, 1-(long)wid);
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
2006-04-16 02:15:43 +02:00
|
|
|
lv->set_part(base, wid);
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
return true;
|
2006-04-16 02:15:43 +02: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;
|
|
|
|
|
}
|