Allow some behavioral assignments to unresolved wires.
If the l-value is an unresolved wire, then elaboration can allow the assignment as long as it is to bits that are not otherwise driven. Handle this in some simple cases.
This commit is contained in:
parent
49cf5556a2
commit
0be577cc44
85
elab_lval.cc
85
elab_lval.cc
|
|
@ -289,7 +289,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
/* Get the signal referenced by the identifier, and make sure
|
||||
it is a register. Wires are not allowed in this context,
|
||||
unless this is the l-value of a force. */
|
||||
if ((reg->type() != NetNet::REG) && !is_force) {
|
||||
if ((reg->type() != NetNet::REG)
|
||||
&& (reg->type() != NetNet::UNRESOLVED_WIRE)
|
||||
&& !is_force) {
|
||||
cerr << get_fileline() << ": error: " << path_ <<
|
||||
" is not a valid l-value in " << scope_path(use_scope) <<
|
||||
"." << endl;
|
||||
|
|
@ -314,7 +316,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
// where the name is a member/method of a struct/class.
|
||||
ivl_assert(*this, method_name.nil());
|
||||
|
||||
bool need_const_idx = is_cassign || is_force;
|
||||
bool need_const_idx = is_cassign || is_force || (reg->type()==NetNet::UNRESOLVED_WIRE);
|
||||
|
||||
if (reg->unpacked_dimensions() > 0)
|
||||
return elaborate_lval_net_word_(des, scope, reg, need_const_idx);
|
||||
|
|
@ -358,6 +360,14 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
|
||||
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< path_ << " Unable assign to unresolved wires."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No select expressions. */
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
|
|
@ -507,6 +517,13 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
|||
canon_index = new NetEConst(verinum(verinum::Vx));
|
||||
canon_index->set_line(*this);
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Unable to assign words of unresolved wire array." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
lv->set_word(canon_index);
|
||||
|
||||
|
|
@ -599,6 +616,19 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate && (reg->type()==NetNet::UNRESOLVED_WIRE)) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_bit_: "
|
||||
<< "Try to assign bits of unresolved wire."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// Notice that we might be assigning to an unresolved wire. This
|
||||
// can happen if we are actually assigning to a variable that
|
||||
// has a partial continuous assignment to it. If that is the
|
||||
// case, then the bit select must be constant.
|
||||
ivl_assert(*this, need_const_idx || (reg->type()!=NetNet::UNRESOLVED_WIRE));
|
||||
|
||||
|
||||
if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
|
||||
// Special case: this is a slice of a multi-dimensional
|
||||
// packed array. For example:
|
||||
|
|
@ -613,8 +643,19 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
||||
ivl_assert(*this, rcl);
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
bool rct = reg->test_and_set_part_driver(loff+lwid-1, loff);
|
||||
if (rct) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "These bits are already driven." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
lv->set_part(new NetEConst(verinum(loff)), lwid);
|
||||
|
||||
} else {
|
||||
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||
unsigned long lwid;
|
||||
mux = normalize_variable_slice_base(prefix_indices, mux,
|
||||
reg, lwid);
|
||||
|
|
@ -622,6 +663,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
}
|
||||
|
||||
} else if (reg->data_type() == IVL_VT_STRING) {
|
||||
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||
// 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
|
||||
|
|
@ -638,6 +680,8 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
lv->set_part(new NetEConst(verinum(lsb)), 8);
|
||||
|
||||
} else if (mux) {
|
||||
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||
|
||||
// Non-constant bit mux. Correct the mux for the range
|
||||
// of the vector, then set the l-value part select
|
||||
// expression.
|
||||
|
|
@ -655,6 +699,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
// Constant bit mux that happens to select the only bit
|
||||
// of the l-value. Don't bother with any select at all.
|
||||
|
||||
// NOTE: Don't know what to do about unresolved wires
|
||||
// here, but they are probably wrong.
|
||||
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||
|
||||
} else {
|
||||
// Constant bit select that does something useful.
|
||||
long loff = reg->sb_to_idx(prefix_indices,lsb);
|
||||
|
|
@ -667,6 +715,15 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
bool rct = reg->test_and_set_part_driver(loff, loff);
|
||||
if (rct) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Bit " << loff << " is already driven." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
lv->set_part(new NetEConst(verinum(loff)), 1);
|
||||
}
|
||||
|
||||
|
|
@ -681,6 +738,14 @@ bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*
|
|||
// For now, only support single-dimension dynamic arrays.
|
||||
ivl_assert(*this, name_tail.index.size() == 1);
|
||||
|
||||
if (lv->sig()->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< path_ << " Unable to darray word select unresolved wires."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
ivl_assert(*this, index_tail.lsb == 0);
|
||||
|
|
@ -723,6 +788,14 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< path_ << " Unable to part select unresolved wires."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const vector<netrange_t>&packed = reg->packed_dims();
|
||||
|
||||
long loff, moff;
|
||||
|
|
@ -1103,6 +1176,14 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
|||
packed_base = 0;
|
||||
}
|
||||
|
||||
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< path_ << " Unable to member-select unresolved wires."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packed_base == 0) {
|
||||
lv->set_part(new NetEConst(verinum(off)), use_width);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -710,7 +710,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
|||
unsigned subnet_wid = midx-lidx+1;
|
||||
|
||||
/* Check if the l-value bits are double-driven. */
|
||||
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) {
|
||||
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx)) {
|
||||
cerr << get_fileline() << ": error: Unresolved net/uwire "
|
||||
<< sig->name() << " cannot have multiple drivers." << endl;
|
||||
des->errors += 1;
|
||||
|
|
|
|||
|
|
@ -868,7 +868,7 @@ unsigned NetNet::peek_eref() const
|
|||
* Test each of the bits in the range, and set them. If any bits are
|
||||
* already set then return true.
|
||||
*/
|
||||
bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb)
|
||||
bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb)
|
||||
{
|
||||
if (lref_mask_.empty())
|
||||
lref_mask_.resize(vector_width());
|
||||
|
|
|
|||
13
netlist.h
13
netlist.h
|
|
@ -726,17 +726,22 @@ class NetNet : public NetObj, public PortType {
|
|||
bool local_flag() const { return local_flag_; }
|
||||
void local_flag(bool f) { local_flag_ = f; }
|
||||
|
||||
/* NetESignal objects may reference this object. Keep a
|
||||
reference count so that I keep track of them. */
|
||||
// NetESignal objects may reference this object. Keep a
|
||||
// reference count so that I keep track of them.
|
||||
void incr_eref();
|
||||
void decr_eref();
|
||||
unsigned peek_eref() const;
|
||||
|
||||
/* Assignment statements count their lrefs here. */
|
||||
// Assignment statements count their lrefs here. And by
|
||||
// asignment statements, we mean BEHAVIORAL assignments.
|
||||
void incr_lref();
|
||||
void decr_lref();
|
||||
unsigned peek_lref() const { return lref_count_; }
|
||||
bool test_part_lref(unsigned msb, unsigned lsb);
|
||||
|
||||
// Treating this node as a uwire, this function tests whether
|
||||
// any bits in the canonical part are already driven. This is
|
||||
// only useful for UNRESOLVED_WIRE objects.
|
||||
bool test_and_set_part_driver(unsigned msb, unsigned lsb);
|
||||
|
||||
unsigned get_refs() const;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue