diff --git a/elab_lval.cc b/elab_lval.cc index 2c2308081..fd3058a12 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -468,11 +468,15 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, if ((reg->type()==NetNet::UNRESOLVED_WIRE) && !is_force) { ivl_assert(*this, reg->coerced_to_uwire()); - cerr << get_fileline() << ": error: Cannot perform " - "procedural assignment to word in array '" << reg->name() - << "' because it is also continuously assigned." << endl; - des->errors += 1; - return 0; + NetEConst*canon_const = dynamic_cast(canon_index); + if (!canon_const || reg->test_part_driven(reg->vector_width() - 1, 0, + canon_const->value().as_long())) { + cerr << get_fileline() << ": error: Cannot perform " + "procedural assignment to word in array '" << reg->name() + << "' because it is also continuously assigned." << endl; + des->errors += 1; + return 0; + } } NetAssign_*lv = new NetAssign_(reg); diff --git a/netlist.cc b/netlist.cc index 716044101..0ad54660f 100644 --- a/netlist.cc +++ b/netlist.cc @@ -829,6 +829,30 @@ unsigned NetNet::peek_eref() const return eref_count_; } +/* + * Test each of the bits in the range. If any bits are set then return true. + */ +bool NetNet::test_part_driven(unsigned pmsb, unsigned plsb, int widx) +{ + if (lref_mask_.empty()) + return false; + + // If indexing a word that doesn't exist, then pretend this is + // never driven. + if (widx < 0) + return false; + if (widx >= (int)pin_count()) + return false; + + unsigned word_base = vector_width() * widx; + for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { + if (lref_mask_[idx+word_base]) + return true; + } + + return false; +} + /* * Test each of the bits in the range, and set them. If any bits are * already set then return true. diff --git a/netlist.h b/netlist.h index 06f12fcb5..68a408899 100644 --- a/netlist.h +++ b/netlist.h @@ -793,6 +793,13 @@ class NetNet : public NetObj, public PortType { // only useful for UNRESOLVED_WIRE objects. The msb and lsb // are the part select of the signal, and the widx is the word // index if this is an unpacked array. + bool test_part_driven(unsigned msb, unsigned lsb, int widx =0); + + // Treating this node as a uwire, this function tests whether + // any bits in the canonical part are already driven and sets + // them if not. This is only useful for UNRESOLVED_WIRE objects. + // The msb and lsb are the part select of the signal, and the + // widx is the word index if this is an unpacked array. bool test_and_set_part_driver(unsigned msb, unsigned lsb, int widx =0); unsigned get_refs() const;