2000-09-09 17:21:26 +02:00
|
|
|
/*
|
2007-01-16 06:44:14 +01:00
|
|
|
* Copyright (c) 2000-2006 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
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2007-02-01 06:25:26 +01:00
|
|
|
#ident "$Id: elab_lval.cc,v 1.39 2007/02/01 05:25:26 steve Exp $"
|
2000-09-09 17:21:26 +02:00
|
|
|
#endif
|
|
|
|
|
|
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"
|
2001-07-25 05:10:48 +02:00
|
|
|
# include <iostream>
|
|
|
|
|
|
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
|
2003-01-27 06:09:17 +01:00
|
|
|
* l-value is a simple name (i.e., foo <= <value>) the 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) {
|
|
|
|
|
cerr << get_line() << ": Assignment l-value too complex."
|
|
|
|
|
<< 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_) {
|
|
|
|
|
cerr << get_line() << ": error: Repeat concatenations make "
|
|
|
|
|
"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) {
|
|
|
|
|
cerr << get_line() << ": error: Empty expressions "
|
|
|
|
|
<< "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
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
symbol_search(des, scope, path_, reg, par, eve);
|
2003-09-19 05:30:04 +02:00
|
|
|
if (reg == 0) {
|
2002-06-04 07:38:43 +02:00
|
|
|
cerr << get_line() << ": error: Could not find variable ``"
|
|
|
|
|
<< path_ << "'' in ``" << scope->name() <<
|
|
|
|
|
"''" << endl;
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
assert(reg);
|
|
|
|
|
|
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
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
if (sel_ == SEL_PART) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_net_part_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
if (sel_ == SEL_IDX_UP) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_net_idx_up_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sel_ == SEL_IDX_DO) {
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
elaborate_lval_net_idx_do_(des, scope, lv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
2006-04-16 02:15:43 +02:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
/* Get the signal referenced by the identifier, and make sure
|
2004-12-30 00:55:43 +01:00
|
|
|
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) {
|
2001-12-03 05:47:14 +01:00
|
|
|
cerr << get_line() << ": error: " << path_ <<
|
2007-02-01 06:25:26 +01:00
|
|
|
" is not a valid l-value in " << scope->name() <<
|
2000-10-31 18:49:02 +01:00
|
|
|
"." << endl;
|
2004-08-28 16:59:44 +02:00
|
|
|
cerr << reg->get_line() << ": : " << path_ <<
|
|
|
|
|
" is declared here as " << reg->type() << "." << endl;
|
2000-09-09 17:21:26 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-16 02:54:04 +02:00
|
|
|
assert(msb_ == 0);
|
|
|
|
|
assert(lsb_ == 0);
|
2000-09-09 17:21:26 +02:00
|
|
|
long msb, lsb;
|
|
|
|
|
NetExpr*mux;
|
|
|
|
|
|
2006-04-16 02:54:04 +02:00
|
|
|
if (! idx_.empty()) {
|
2000-09-09 17:21:26 +02:00
|
|
|
|
|
|
|
|
/* If there is only a single select expression, it is a
|
|
|
|
|
bit select. Evaluate the constant value and treat it
|
|
|
|
|
as a part select with a bit width of 1. If the
|
|
|
|
|
expression it not constant, then return the
|
|
|
|
|
expression as a mux. */
|
2006-02-02 03:43:57 +01:00
|
|
|
assert(idx_.size() == 1);
|
|
|
|
|
verinum*v = idx_[0]->eval_const(des, scope);
|
2000-09-09 17:21:26 +02:00
|
|
|
if (v == 0) {
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*m = idx_[0]->elaborate_expr(des, scope, -1, false);
|
2000-09-09 17:21:26 +02:00
|
|
|
assert(m);
|
|
|
|
|
msb = 0;
|
|
|
|
|
lsb = 0;
|
|
|
|
|
mux = m;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
msb = v->as_long();
|
|
|
|
|
lsb = v->as_long();
|
|
|
|
|
mux = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* No select expressions, so presume a part select the
|
|
|
|
|
width of the register. */
|
|
|
|
|
|
|
|
|
|
msb = reg->msb();
|
|
|
|
|
lsb = reg->lsb();
|
|
|
|
|
mux = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NetAssign_*lv;
|
|
|
|
|
if (mux) {
|
|
|
|
|
|
|
|
|
|
/* If there is a non-constant bit select, make a
|
2001-08-26 01:50:02 +02:00
|
|
|
NetAssign_ to the target reg and attach a
|
2000-09-09 17:21:26 +02:00
|
|
|
bmux to select the target bit. */
|
2001-08-26 01:50:02 +02:00
|
|
|
lv = new NetAssign_(reg);
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2006-04-16 02:15:43 +02:00
|
|
|
/* Correct the mux for the range of the vector. */
|
|
|
|
|
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);
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2006-02-02 03:43:57 +01:00
|
|
|
} else if (msb == reg->msb() && lsb == reg->lsb()) {
|
|
|
|
|
|
|
|
|
|
/* No bit select, and part select covers the entire
|
|
|
|
|
vector. Simplest case. */
|
|
|
|
|
lv = new NetAssign_(reg);
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* If the bit/part select is constant, then make the
|
|
|
|
|
NetAssign_ only as wide as it needs to be and connect
|
|
|
|
|
only to the selected bits of the reg. */
|
2000-12-01 03:55:37 +01:00
|
|
|
unsigned loff = reg->sb_to_idx(lsb);
|
|
|
|
|
unsigned moff = reg->sb_to_idx(msb);
|
|
|
|
|
unsigned wid = moff - loff + 1;
|
2000-09-09 17:21:26 +02:00
|
|
|
|
2000-12-01 03:55:37 +01:00
|
|
|
if (moff < loff) {
|
|
|
|
|
cerr << get_line() << ": error: part select "
|
|
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is reversed." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-09 04:16:48 +01:00
|
|
|
/* If the part select extends beyond the extreme of the
|
|
|
|
|
variable, then report an error. Note that loff is
|
|
|
|
|
converted to normalized form so is relative the
|
|
|
|
|
variable pins. */
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
if ((wid + loff) > reg->vector_width()) {
|
2001-02-09 04:16:48 +01:00
|
|
|
cerr << get_line() << ": error: bit/part select "
|
2000-12-01 03:55:37 +01:00
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-08-26 01:50:02 +02:00
|
|
|
lv = new NetAssign_(reg);
|
2006-02-02 03:43:57 +01:00
|
|
|
lv->set_part(new NetEConst(verinum(loff)), wid);
|
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
|
|
|
{
|
|
|
|
|
assert(idx_.size() == 1);
|
|
|
|
|
|
|
|
|
|
NetExpr*word = elab_and_eval(des, scope, idx_[0], -1);
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
if (NetExpr*tmp = word->eval_tree()) {
|
|
|
|
|
word = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetAssign_*lv = new NetAssign_(reg);
|
|
|
|
|
lv->set_word(word);
|
|
|
|
|
|
|
|
|
|
if (debug_elaborate)
|
|
|
|
|
cerr << get_line() << ": debug: Set array word=" << *word << endl;
|
|
|
|
|
|
|
|
|
|
/* An array word may also have part selects applied to them. */
|
|
|
|
|
|
|
|
|
|
if (sel_ == SEL_PART)
|
|
|
|
|
elaborate_lval_net_part_(des, scope, lv);
|
|
|
|
|
|
|
|
|
|
if (sel_ == SEL_IDX_UP)
|
|
|
|
|
elaborate_lval_net_idx_up_(des, scope, lv);
|
|
|
|
|
|
|
|
|
|
if (sel_ == SEL_IDX_DO)
|
|
|
|
|
elaborate_lval_net_idx_do_(des, scope, lv);
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PEIdent::elaborate_lval_net_part_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv) const
|
2006-04-16 02:54:04 +02:00
|
|
|
{
|
2006-11-04 07:19:24 +01:00
|
|
|
long msb, lsb;
|
|
|
|
|
bool flag = calculate_parts_(des, scope, msb, lsb);
|
|
|
|
|
if (!flag)
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2006-04-16 02:54:04 +02:00
|
|
|
|
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()) {
|
|
|
|
|
|
|
|
|
|
/* No bit select, and part select covers the entire
|
|
|
|
|
vector. Simplest case. */
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* If the bit/part select is constant, then make the
|
|
|
|
|
NetAssign_ only as wide as it needs to be and connect
|
|
|
|
|
only to the selected bits of the reg. */
|
|
|
|
|
unsigned loff = reg->sb_to_idx(lsb);
|
|
|
|
|
unsigned moff = reg->sb_to_idx(msb);
|
|
|
|
|
unsigned wid = moff - loff + 1;
|
|
|
|
|
|
|
|
|
|
if (moff < loff) {
|
|
|
|
|
cerr << get_line() << ": error: part select "
|
|
|
|
|
<< 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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the part select extends beyond the extreme of the
|
|
|
|
|
variable, then report an error. Note that loff is
|
|
|
|
|
converted to normalized form so is relative the
|
|
|
|
|
variable pins. */
|
|
|
|
|
|
|
|
|
|
if ((wid + loff) > reg->vector_width()) {
|
|
|
|
|
cerr << get_line() << ": error: bit/part select "
|
|
|
|
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
|
|
|
|
<< " is out of range." << endl;
|
|
|
|
|
des->errors += 1;
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2006-04-16 02:54:04 +02: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-01-16 06:44:14 +01:00
|
|
|
bool PEIdent::elaborate_lval_net_idx_up_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv) const
|
2006-04-16 02:15:43 +02:00
|
|
|
{
|
|
|
|
|
assert(lsb_);
|
|
|
|
|
assert(msb_);
|
|
|
|
|
|
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) {
|
|
|
|
|
cerr << get_line() << ": error: " << path_ <<
|
|
|
|
|
" is not a reg/integer/time in " << scope->name() <<
|
|
|
|
|
"." << endl;
|
|
|
|
|
cerr << reg->get_line() << ": : " << path_ <<
|
|
|
|
|
" 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
|
|
|
|
2006-06-02 06:48:49 +02:00
|
|
|
NetExpr*base = elab_and_eval(des, scope, 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-01-16 06:44:14 +01:00
|
|
|
if (debug_elaborate)
|
|
|
|
|
cerr << get_line() << ": debug: Set part select width="
|
|
|
|
|
<< 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
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
bool PEIdent::elaborate_lval_net_idx_do_(Design*des,
|
|
|
|
|
NetScope*scope,
|
|
|
|
|
NetAssign_*lv) const
|
2006-04-16 02:15:43 +02:00
|
|
|
{
|
|
|
|
|
assert(lsb_);
|
|
|
|
|
assert(msb_);
|
|
|
|
|
cerr << get_line() << ": internal error: don't know how to "
|
|
|
|
|
"deal with SEL_IDX_DO in lval?" << endl;
|
|
|
|
|
des->errors += 1;
|
2007-01-16 06:44:14 +01:00
|
|
|
return false;
|
2002-06-04 07:38: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
|
|
|
{
|
|
|
|
|
cerr << get_line() << ": error: Constant values not allowed "
|
|
|
|
|
<< "in l-value expressions." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-09 17:21:26 +02:00
|
|
|
/*
|
|
|
|
|
* $Log: elab_lval.cc,v $
|
2007-02-01 06:25:26 +01:00
|
|
|
* Revision 1.39 2007/02/01 05:25:26 steve
|
|
|
|
|
* Error message better reflects more general reality.
|
|
|
|
|
*
|
2007-01-16 06:44:14 +01:00
|
|
|
* Revision 1.38 2007/01/16 05:44:15 steve
|
|
|
|
|
* Major rework of array handling. Memories are replaced with the
|
|
|
|
|
* more general concept of arrays. The NetMemory and NetEMemory
|
|
|
|
|
* classes are removed from the ivl core program, and the IVL_LPM_RAM
|
|
|
|
|
* lpm type is removed from the ivl_target API.
|
|
|
|
|
*
|
2006-11-04 07:19:24 +01:00
|
|
|
* Revision 1.37 2006/11/04 06:19:25 steve
|
|
|
|
|
* Remove last bits of relax_width methods, and use test_width
|
|
|
|
|
* to calculate the width of an r-value expression that may
|
|
|
|
|
* contain unsized numbers.
|
|
|
|
|
*
|
2006-06-02 06:48:49 +02:00
|
|
|
* Revision 1.36 2006/06/02 04:48:50 steve
|
|
|
|
|
* Make elaborate_expr methods aware of the width that the context
|
|
|
|
|
* requires of it. In the process, fix sizing of the width of unary
|
|
|
|
|
* minus is context determined sizes.
|
|
|
|
|
*
|
2006-04-16 02:54:04 +02:00
|
|
|
* Revision 1.35 2006/04/16 00:54:04 steve
|
|
|
|
|
* Cleanup lval part select handling.
|
|
|
|
|
*
|
2006-04-16 02:15:43 +02:00
|
|
|
* Revision 1.34 2006/04/16 00:15:43 steve
|
|
|
|
|
* Fix part selects in l-values.
|
|
|
|
|
*
|
2006-02-02 03:43:57 +01:00
|
|
|
* Revision 1.33 2006/02/02 02:43:57 steve
|
|
|
|
|
* Allow part selects of memory words in l-values.
|
|
|
|
|
*
|
2005-07-11 18:56:50 +02:00
|
|
|
* Revision 1.32 2005/07/11 16:56:50 steve
|
|
|
|
|
* Remove NetVariable and ivl_variable_t structures.
|
|
|
|
|
*
|
2004-12-30 00:55:43 +01:00
|
|
|
* Revision 1.31 2004/12/29 23:55:43 steve
|
|
|
|
|
* Unify elaboration of l-values for all proceedural assignments,
|
|
|
|
|
* including assing, cassign and force.
|
|
|
|
|
*
|
|
|
|
|
* Generate NetConcat devices for gate outputs that feed into a
|
|
|
|
|
* vector results. Use this to hande gate arrays. Also let gate
|
|
|
|
|
* arrays handle vectors of gates when the outputs allow for it.
|
|
|
|
|
*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Revision 1.30 2004/12/11 02:31:25 steve
|
|
|
|
|
* Rework of internals to carry vectors through nexus instead
|
|
|
|
|
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
|
|
|
|
* down this path.
|
|
|
|
|
*
|
2004-10-04 03:10:51 +02:00
|
|
|
* Revision 1.29 2004/10/04 01:10:52 steve
|
|
|
|
|
* Clean up spurious trailing white space.
|
|
|
|
|
*
|
2004-08-28 16:59:44 +02:00
|
|
|
* Revision 1.28 2004/08/28 14:59:44 steve
|
|
|
|
|
* More detailed error message about bad variable.
|
|
|
|
|
*
|
2003-09-19 05:30:04 +02:00
|
|
|
* Revision 1.27 2003/09/19 03:30:05 steve
|
|
|
|
|
* Fix name search in elab_lval.
|
2000-09-09 17:21:26 +02:00
|
|
|
*/
|
|
|
|
|
|