iverilog/elab_lval.cc

487 lines
15 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com)
*
* 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
*/
# include "config.h"
# include "PExpr.h"
# include "netlist.h"
2003-09-19 05:30:04 +02:00
# include "netmisc.h"
# include "compiler.h"
# include <cstdlib>
# include <iostream>
# include "ivl_assert.h"
/*
* 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.
*
* 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_
* 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_
* 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
* special case of the part select.
*
2003-01-27 06:09:17 +01:00
* If the bit-select is non-constant (i.e., foo[<expr>] = <value>) the
* 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
* 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,
* 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.
*/
NetAssign_* PExpr::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
NetNet*ll = 0;
if (ll == 0) {
cerr << get_fileline() << ": Assignment l-value too complex."
<< endl;
return 0;
}
NetAssign_*lv = new NetAssign_(ll);
return lv;
}
/*
* Concatenation expressions can appear as l-values. Handle them here.
*
* 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.
*/
NetAssign_* PEConcat::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
2000-09-10 17:43:59 +02:00
if (repeat_) {
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 04:18:16 +02:00
NetAssign_*res = 0;
2000-09-10 04:18:16 +02:00
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
if (parms_[idx] == 0) {
cerr << get_fileline() << ": error: Empty expressions "
<< "not allowed in concatenations." << endl;
des->errors += 1;
continue;
}
NetAssign_*tmp = parms_[idx]->elaborate_lval(des, scope, is_force);
/* 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);
/* Link the new l-value to the previous one. */
NetAssign_*last = tmp;
while (last->more)
last = last->more;
last->more = res;
res = tmp;
2000-09-10 04:18:16 +02:00
}
return res;
}
/*
* Handle the ident as an l-value. This includes bit and part selects
* of that ident.
*/
NetAssign_* PEIdent::elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const
{
2003-09-19 05:30:04 +02:00
NetNet* reg = 0;
const NetExpr*par = 0;
NetEvent* eve = 0;
symbol_search(des, scope, path_, reg, par, eve);
2003-09-19 05:30:04 +02:00
if (reg == 0) {
cerr << get_fileline() << ": error: Could not find variable ``"
<< path_ << "'' in ``" << scope_path(scope) <<
"''" << endl;
des->errors += 1;
return 0;
}
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;
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.
if (reg->array_dimensions() > 0 && name_tail.index.empty()) {
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;
}
if (reg->array_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg);
2006-04-16 02:54:04 +02:00
if (use_sel == index_component_t::SEL_PART) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_part_(des, scope, lv);
return lv;
}
2006-04-16 02:15:43 +02:00
if (use_sel == index_component_t::SEL_IDX_UP ||
use_sel == index_component_t::SEL_IDX_DO) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_idx_(des, scope, lv, use_sel);
return lv;
}
2006-04-16 02:15:43 +02: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) <<
2000-10-31 18:49:02 +01:00
"." << endl;
cerr << reg->get_fileline() << ": : " << path_ <<
" is declared here as " << reg->type() << "." << endl;
des->errors += 1;
return 0;
}
long msb, lsb;
NetExpr*mux;
if (use_sel == index_component_t::SEL_BIT) {
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
/* 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. */
NetExpr*index_expr = elab_and_eval(des, scope, index_tail.msb, -1);
if (NetEConst*index_con = dynamic_cast<NetEConst*> (index_expr)) {
msb = index_con->value().as_long();
lsb = index_con->value().as_long();
mux = 0;
} else {
msb = 0;
lsb = 0;
mux = index_expr;
}
} 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
NetAssign_ to the target reg and attach a
bmux to select the target bit. */
lv = new NetAssign_(reg);
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);
} else if (msb == reg->msb() && lsb == reg->lsb()) {
/* No bit select, and part select covers the entire
vector. Simplest case. */
lv = new NetAssign_(reg);
} 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-12-01 03:55:37 +01:00
if (moff < loff) {
cerr << get_fileline() << ": error: part select "
2000-12-01 03:55:37 +01:00
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return 0;
}
/* 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_fileline() << ": 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;
}
lv = new NetAssign_(reg);
lv->set_part(new NetEConst(verinum(loff)), wid);
}
return lv;
}
NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
2006-04-16 02:54:04 +02:00
NetScope*scope,
NetNet*reg) const
{
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();
if (index_head.sel == index_component_t::SEL_PART) {
cerr << get_fileline() << ": error: cannot perform a part "
<< "select on array " << reg->name() << "." << endl;
des->errors += 1;
return 0;
}
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);
NetExpr*word = elab_and_eval(des, scope, index_head.msb, -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_fileline() << ": debug: Set array word=" << *word << endl;
// 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();
if (index < 0 || index >= reg->array_count()) {
cerr << get_fileline() << ": warning: Constant array index "
<< (index + reg->array_first())
<< " is out of range for array "
<< reg->name() << "." << endl;
}
}
/* An array word may also have part selects applied to them. */
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;
if (use_sel == index_component_t::SEL_PART)
elaborate_lval_net_part_(des, scope, lv);
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);
return lv;
}
bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
2006-04-16 02:54:04 +02:00
{
long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb);
if (!flag)
return false;
2006-04-16 02:54:04 +02: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_fileline() << ": error: part select "
2006-04-16 02:54:04 +02:00
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
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_fileline() << ": error: bit/part select "
2006-04-16 02:54:04 +02:00
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return false;
2006-04-16 02:54:04 +02:00
}
lv->set_part(new NetEConst(verinum(loff)), wid);
}
return true;
2006-04-16 02:54:04 +02: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
{
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
NetNet*reg = lv->sig();
assert(reg);
2006-04-16 02:15:43 +02:00
if (reg->type() != NetNet::REG) {
cerr << get_fileline() << ": error: " << path_ <<
" is not a reg/integer/time in " << scope_path(scope) <<
2006-04-16 02:15:43 +02:00
"." << endl;
cerr << reg->get_fileline() << ": : " << path_ <<
2006-04-16 02:15:43 +02:00
" is declared here as " << reg->type() << "." << endl;
des->errors += 1;
return false;
2006-04-16 02:15:43 +02:00
}
unsigned long wid;
calculate_up_do_width_(des, scope, wid);
2006-04-16 02:15:43 +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());
if (use_sel == index_component_t::SEL_IDX_DO && wid > 1 ) {
base = make_add_expr(base, 1-(long)wid);
}
if (debug_elaborate)
cerr << get_fileline() << ": debug: Set part select width="
<< wid << ", base=" << *base << endl;
2006-04-16 02:15:43 +02:00
lv->set_part(base, wid);
return true;
2006-04-16 02:15:43 +02:00
}
NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const
{
cerr << get_fileline() << ": error: Constant values not allowed "
<< "in l-value expressions." << endl;
des->errors += 1;
return 0;
}