Allow l-value part select to be out of bounds.
It is legal (though worthy of a warning, I think) for the part select of an l-value to me out of bounds, so replace the error message with a warning, and generate the appropriate code. In the process, clean up some of the code for signal l-values to divide out the various kinds of processing that can be done. This cleans things up a bit.
This commit is contained in:
parent
ebdf4e478a
commit
30d42e2806
1
PExpr.h
1
PExpr.h
|
|
@ -315,6 +315,7 @@ class PEIdent : public PExpr {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
|
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
|
||||||
|
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
|
||||||
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const;
|
||||||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||||
index_component_t::ctype_t) const;
|
index_component_t::ctype_t) const;
|
||||||
|
|
|
||||||
173
elab_lval.cc
173
elab_lval.cc
|
|
@ -208,101 +208,18 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long msb, lsb;
|
|
||||||
NetExpr*mux;
|
|
||||||
|
|
||||||
if (use_sel == index_component_t::SEL_BIT) {
|
if (use_sel == index_component_t::SEL_BIT) {
|
||||||
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
const index_component_t&index_tail = name_tail.index.back();
|
elaborate_lval_net_bit_(des, scope, lv);
|
||||||
ivl_assert(*this, index_tail.msb != 0);
|
return lv;
|
||||||
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 {
|
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
|
||||||
|
|
||||||
/* No select expressions, so presume a part select the
|
/* No select expressions. */
|
||||||
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);
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
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 "
|
|
||||||
<< 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 "
|
|
||||||
<< 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
|
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
@ -374,10 +291,67 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Bit selects have a single select expression. Evaluate the
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
bool PEIdent::elaborate_lval_net_part_(Design*des,
|
bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
NetScope*scope,
|
NetScope*scope,
|
||||||
NetAssign_*lv) const
|
NetAssign_*lv) const
|
||||||
{
|
{
|
||||||
|
// The range expressions of a part select must be
|
||||||
|
// constant. The calculate_parts_ function calculates the
|
||||||
|
// values into msb and lsb.
|
||||||
long msb, lsb;
|
long msb, lsb;
|
||||||
bool flag = calculate_parts_(des, scope, msb, lsb);
|
bool flag = calculate_parts_(des, scope, msb, lsb);
|
||||||
if (!flag)
|
if (!flag)
|
||||||
|
|
@ -388,17 +362,14 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
|
|
||||||
if (msb == reg->msb() && lsb == reg->lsb()) {
|
if (msb == reg->msb() && lsb == reg->lsb()) {
|
||||||
|
|
||||||
/* No bit select, and part select covers the entire
|
/* Part select covers the entire vector. Simplest case. */
|
||||||
vector. Simplest case. */
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* If the bit/part select is constant, then make the
|
/* Get the canonical offsets into the vector. */
|
||||||
NetAssign_ only as wide as it needs to be and connect
|
long loff = reg->sb_to_idx(lsb);
|
||||||
only to the selected bits of the reg. */
|
long moff = reg->sb_to_idx(msb);
|
||||||
unsigned loff = reg->sb_to_idx(lsb);
|
long wid = moff - loff + 1;
|
||||||
unsigned moff = reg->sb_to_idx(msb);
|
|
||||||
unsigned wid = moff - loff + 1;
|
|
||||||
|
|
||||||
if (moff < loff) {
|
if (moff < loff) {
|
||||||
cerr << get_fileline() << ": error: part select "
|
cerr << get_fileline() << ": error: part select "
|
||||||
|
|
@ -408,17 +379,15 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the part select extends beyond the extreme of the
|
/* If the part select extends beyond the extremes of the
|
||||||
variable, then report an error. Note that loff is
|
variable, then report an error. Note that loff is
|
||||||
converted to normalized form so is relative the
|
converted to normalized form so is relative the
|
||||||
variable pins. */
|
variable pins. */
|
||||||
|
|
||||||
if ((wid + loff) > reg->vector_width()) {
|
if (loff < 0 || moff >= (signed)reg->vector_width()) {
|
||||||
cerr << get_fileline() << ": error: bit/part select "
|
cerr << get_fileline() << ": warning: Part select "
|
||||||
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
|
||||||
<< " is out of range." << endl;
|
<< " is out of range." << endl;
|
||||||
des->errors += 1;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lv->set_part(new NetEConst(verinum(loff)), wid);
|
lv->set_part(new NetEConst(verinum(loff)), wid);
|
||||||
|
|
|
||||||
|
|
@ -3608,17 +3608,26 @@ bool of_SET_X0(vthread_t thr, vvp_code_t cp)
|
||||||
|
|
||||||
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
|
||||||
|
|
||||||
|
// If the entire part is below the beginning of the vector,
|
||||||
|
// then we are done.
|
||||||
if (index < 0 && (wid <= (unsigned)-index))
|
if (index < 0 && (wid <= (unsigned)-index))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If the entire part is above then end of the vector, then we
|
||||||
|
// are done.
|
||||||
if (index >= (long)sig->size())
|
if (index >= (long)sig->size())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If the part starts below the vector, then skip the first
|
||||||
|
// few bits and reduce enough bits to start at the beginning
|
||||||
|
// of the vector.
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
|
if (bit >= 4) bit += (unsigned) -index;
|
||||||
wid -= (unsigned) -index;
|
wid -= (unsigned) -index;
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reduce the width to keep the part inside the vector.
|
||||||
if (index+wid > sig->size())
|
if (index+wid > sig->size())
|
||||||
wid = sig->size() - index;
|
wid = sig->size() - index;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue