diff --git a/elab_lval.cc b/elab_lval.cc index 70802ac9f..e4de5d80b 100644 --- a/elab_lval.cc +++ b/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&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; diff --git a/elab_net.cc b/elab_net.cc index c81f0646f..1cad8de9c 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -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; diff --git a/netlist.cc b/netlist.cc index 6e0a3db5a..e66c9c7c9 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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()); diff --git a/netlist.h b/netlist.h index 513409ec5..577036428 100644 --- a/netlist.h +++ b/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;