From 46f9f887f7d0736eda64d61cef56f082bd5936e7 Mon Sep 17 00:00:00 2001 From: junyao Date: Sun, 31 May 2026 00:18:49 +0800 Subject: [PATCH] setundef: strip init attributes from undriven wires (fixes #5835) When `setundef -undriven` connects an undriven wire to a replacement value, the wire's \\init attribute (if present) is now removed. Previously, the init attribute was left intact, causing downstream passes like opt_merge to report "Conflicting init values" errors because the init value contradicted the newly assigned constant. For wires that are entirely undriven, the init attribute is removed completely. For partially undriven wires (where only some bits are undriven), only the corresponding init bits are cleared to x. Wires driven by flip-flops or other cells are not affected, as they are excluded from the undriven signal set before this code runs. --- passes/cmds/setundef.cc | 22 ++++++++++++ tests/various/setundef_init.ys | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/various/setundef_init.ys diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 99a223bdc..2cd845bdf 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -355,6 +355,28 @@ struct SetundefPass : public Pass { bits.append(worker.next_bit()); module->connect(RTLIL::SigSig(c, bits)); } + // Remove init attributes from undriven wires to prevent + // conflicts with the values we just assigned (issue #5835). + for (auto &c : sig.chunks()) { + if (c.wire && c.wire->attributes.count(ID::init)) { + if (c.wire->width == c.width && c.offset == 0) { + c.wire->attributes.erase(ID::init); + log("Removing init attribute from undriven wire %s.\n", log_id(c.wire)); + } else { + Const &initval = c.wire->attributes[ID::init]; + initval.resize(GetSize(c.wire), State::Sx); + for (int i = c.offset; i < c.offset + c.width; i++) + initval.set(i, State::Sx); + if (initval.is_fully_undef()) { + c.wire->attributes.erase(ID::init); + log("Removing init attribute from undriven wire %s.\n", log_id(c.wire)); + } else { + log("Clearing init attribute bits [%d:%d] from partially undriven wire %s.\n", + c.offset + c.width - 1, c.offset, log_id(c.wire)); + } + } + } + } } } diff --git a/tests/various/setundef_init.ys b/tests/various/setundef_init.ys new file mode 100644 index 000000000..db5b80783 --- /dev/null +++ b/tests/various/setundef_init.ys @@ -0,0 +1,61 @@ +# Test for issue #5835: setundef -undriven should not cause conflicts +# with init attributes on undriven wires. + +# Test 1: Basic case from the bug report - undriven wire with init attribute +read_rtlil << EOT +module \top + attribute \init 3 + wire width 4 \i +end +EOT +setundef -undriven -undef +# Verify that the init attribute was removed from the undriven wire +select -assert-count 0 w:* a:init %i +# Verify that opt doesn't crash with "Conflicting init values" error +opt +design -reset + +# Test 2: setundef -undriven -zero with init attribute +read_rtlil << EOT +module \top + attribute \init 3 + wire width 4 \i +end +EOT +setundef -undriven -zero +select -assert-count 0 w:* a:init %i +opt +design -reset + +# Test 3: setundef -undriven -one with init attribute +read_rtlil << EOT +module \top + attribute \init 3 + wire width 4 \i +end +EOT +setundef -undriven -one +select -assert-count 0 w:* a:init %i +opt +design -reset + +# Test 4: Wire driven by a cell should keep its init attribute +read_rtlil << EOT +module \top + wire width 1 input 1 \clk + wire width 1 input 2 \d + attribute \init 1'0 + wire width 1 output 3 \q + cell $dff \myff + parameter \CLK_POLARITY 1'1 + parameter \WIDTH 1 + connect \CLK \clk + connect \D \d + connect \Q \q + end +end +EOT +setundef -undriven -zero +# The init attribute should still be present since the wire is driven by a FF +select -assert-count 1 w:* a:init %i +design -reset