From 5ff5eeb9f8d4758bc6c959fa332e184e4875d8f9 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 26 Aug 2026 14:13:22 +0200 Subject: [PATCH 1/3] Fix bufnorm edge cases. --- kernel/rtlil.h | 2 ++ kernel/rtlil_bufnorm.cc | 56 +++++++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 79466ac3b..fffd09400 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2115,6 +2115,8 @@ public: pool buf_norm_wire_queue; pool pending_deleted_cells; dict> buf_norm_connect_index; + bool buf_norm_initialized = false; + void bufNormalizeInit(); void bufNormalize(); template void rewrite_sigspecs(T &functor); diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index 19474b565..ecdef8bc4 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -44,40 +44,39 @@ void RTLIL::Design::bufNormalize(bool enable) wire->driverPort_ = IdString(); } module->buf_norm_connect_index.clear(); + module->buf_norm_initialized = false; } flagBufferedNormalized = false; return; } - if (!flagBufferedNormalized) - { - for (auto module : modules()) - { - // When entering buf normalized mode, we need the first module-level bufNormalize - // call to know about all drivers, about all module ports (whether represented by - // a cell or not) and about all used but undriven wires (whether represented by a - // cell or not). We ensure this by enqueing all cell output ports and all wires. - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) { - if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT)) - continue; - module->buf_norm_cell_queue.insert(cell); - module->buf_norm_cell_port_queue.emplace(cell, conn.first); - } - for (auto wire : module->wires()) - module->buf_norm_wire_queue.insert(wire); - - } - - flagBufferedNormalized = true; - } + flagBufferedNormalized = true; for (auto module : modules()) module->bufNormalize(); } +void RTLIL::Module::bufNormalizeInit() +{ + // When entering buf normalized mode, we need the first module-level bufNormalize + // call to know about all drivers, about all module ports (whether represented by + // a cell or not) and about all used but undriven wires (whether represented by a + // cell or not). We ensure this by enqueing all cell output ports and all wires. + + for (auto cell : cells()) + for (auto &conn : cell->connections()) { + if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT)) + continue; + buf_norm_cell_queue.insert(cell); + buf_norm_cell_port_queue.emplace(cell, conn.first); + } + for (auto wire : wires()) + buf_norm_wire_queue.insert(wire); + + buf_norm_initialized = true; +} + struct bit_drive_data_t { int drivers = 0; int inout = 0; @@ -95,11 +94,16 @@ void RTLIL::Module::bufNormalize() if (!design->flagBufferedNormalized) return; + // A module added after the design entered buf normalized mode has to be + // enqueued before its first pass + if (!buf_norm_initialized) + bufNormalizeInit(); + if (!buf_norm_cell_queue.empty() || !buf_norm_wire_queue.empty() || !connections_.empty()) { // Ensure that every enqueued input port is represented by a cell for (auto wire : buf_norm_wire_queue) { - if (wire->port_input && !wire->port_output) { + if (wire->port_input && !wire->port_output && GetSize(wire) != 0) { if (wire->driverCell_ != nullptr && wire->driverCell_->type != ID($input_port)) { wire->driverCell_ = nullptr; wire->driverPort_.clear(); @@ -425,6 +429,10 @@ void RTLIL::Module::bufNormalize() // connected via `$connect` cells but every wire of the net has the // corresponding bit still driven by a buffered `Sz`. for (auto wire : wire_queue_entries) { + // A zero-width wire carries no bits and needs no driver + if (GetSize(wire) == 0) + continue; + SigSpec wire_drivers; for (int i = 0; i < GetSize(wire); ++i) { SigBit bit(wire, i); From f0236d8d200022bbddf46962850649f9a393e201 Mon Sep 17 00:00:00 2001 From: nella Date: Thu, 27 Aug 2026 14:34:10 +0200 Subject: [PATCH 2/3] Move module seeding into Design::add. --- kernel/rtlil.cc | 16 ---------- kernel/rtlil.h | 2 -- kernel/rtlil_bufnorm.cc | 68 +++++++++++++++++++++++++---------------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index eb477c5d3..622e16d7c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1226,22 +1226,6 @@ RTLIL::Module *RTLIL::Design::top_module() const return module_count == 1 ? module : nullptr; } -void RTLIL::Design::add(RTLIL::Module *module) -{ - log_assert(modules_.count(module->name) == 0); - log_assert(refcount_modules_ == 0); - modules_[module->name] = module; - module->design = this; - - for (auto mon : monitors) - mon->notify_module_add(module); - - if (yosys_xtrace) { - log("#X# New Module: %s\n", module); - log_backtrace("-X- ", yosys_xtrace-1); - } -} - void RTLIL::Design::add(RTLIL::Binding *binding) { log_assert(binding != nullptr); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index fffd09400..79466ac3b 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2115,8 +2115,6 @@ public: pool buf_norm_wire_queue; pool pending_deleted_cells; dict> buf_norm_connect_index; - bool buf_norm_initialized = false; - void bufNormalizeInit(); void bufNormalize(); template void rewrite_sigspecs(T &functor); diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index ecdef8bc4..96705a4e9 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -28,6 +28,19 @@ YOSYS_NAMESPACE_BEGIN +static void buf_norm_seed_queues(RTLIL::Module *module) +{ + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) { + if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT)) + continue; + module->buf_norm_cell_queue.insert(cell); + module->buf_norm_cell_port_queue.emplace(cell, conn.first); + } + for (auto wire : module->wires()) + module->buf_norm_wire_queue.insert(wire); +} + void RTLIL::Design::bufNormalize(bool enable) { if (!enable) @@ -44,39 +57,24 @@ void RTLIL::Design::bufNormalize(bool enable) wire->driverPort_ = IdString(); } module->buf_norm_connect_index.clear(); - module->buf_norm_initialized = false; } flagBufferedNormalized = false; return; } - flagBufferedNormalized = true; + if (!flagBufferedNormalized) + { + for (auto module : modules()) + buf_norm_seed_queues(module); + + flagBufferedNormalized = true; + } for (auto module : modules()) module->bufNormalize(); } -void RTLIL::Module::bufNormalizeInit() -{ - // When entering buf normalized mode, we need the first module-level bufNormalize - // call to know about all drivers, about all module ports (whether represented by - // a cell or not) and about all used but undriven wires (whether represented by a - // cell or not). We ensure this by enqueing all cell output ports and all wires. - - for (auto cell : cells()) - for (auto &conn : cell->connections()) { - if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT)) - continue; - buf_norm_cell_queue.insert(cell); - buf_norm_cell_port_queue.emplace(cell, conn.first); - } - for (auto wire : wires()) - buf_norm_wire_queue.insert(wire); - - buf_norm_initialized = true; -} - struct bit_drive_data_t { int drivers = 0; int inout = 0; @@ -94,11 +92,6 @@ void RTLIL::Module::bufNormalize() if (!design->flagBufferedNormalized) return; - // A module added after the design entered buf normalized mode has to be - // enqueued before its first pass - if (!buf_norm_initialized) - bufNormalizeInit(); - if (!buf_norm_cell_queue.empty() || !buf_norm_wire_queue.empty() || !connections_.empty()) { // Ensure that every enqueued input port is represented by a cell @@ -678,4 +671,25 @@ void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal) } +void RTLIL::Design::add(RTLIL::Module *module) +{ + log_assert(modules_.count(module->name) == 0); + log_assert(refcount_modules_ == 0); + modules_[module->name] = module; + module->design = this; + + for (auto mon : monitors) + mon->notify_module_add(module); + + if (yosys_xtrace) { + log("#X# New Module: %s\n", module); + log_backtrace("-X- ", yosys_xtrace-1); + } + + if (flagBufferedNormalized) { + buf_norm_seed_queues(module); + module->bufNormalize(); + } +} + YOSYS_NAMESPACE_END From 2c40c4ea13144fb5f81f77edc2a5473f1a6c8cbc Mon Sep 17 00:00:00 2001 From: nella Date: Thu, 27 Aug 2026 15:16:48 +0200 Subject: [PATCH 3/3] Readd seeding comment. --- kernel/rtlil_bufnorm.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index 96705a4e9..aad4f5199 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -30,6 +30,11 @@ YOSYS_NAMESPACE_BEGIN static void buf_norm_seed_queues(RTLIL::Module *module) { + // When entering buf normalized mode, we need the first module-level bufNormalize + // call to know about all drivers, about all module ports (whether represented by + // a cell or not) and about all used but undriven wires (whether represented by a + // cell or not). We ensure this by enqueing all cell output ports and all wires. + for (auto cell : module->cells()) for (auto &conn : cell->connections()) { if (GetSize(conn.second) == 0 || (cell->port_dir(conn.first) != RTLIL::PD_OUTPUT && cell->port_dir(conn.first) != RTLIL::PD_INOUT))