From 5c3c9b29574063d75bec085886106c447d1a90e2 Mon Sep 17 00:00:00 2001 From: nella Date: Wed, 30 Sep 2026 17:41:29 +0200 Subject: [PATCH] Move init values across barriers. --- kernel/ffinit.h | 58 ++++++++++++++++++++++++++++++++++++ passes/cmds/optbarriers.cc | 6 ++++ tests/various/optbarriers.ys | 50 +++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/kernel/ffinit.h b/kernel/ffinit.h index 8b4758f60..4f34b0cfd 100644 --- a/kernel/ffinit.h +++ b/kernel/ffinit.h @@ -143,6 +143,64 @@ struct FfInitVals remove_init(bit); } + // Move $barrier output init value to it's input + void move_barrier_inits(RTLIL::Module *module) + { + dict next; + for (auto cell : module->cells()) { + if (cell->type != ID($barrier)) + continue; + RTLIL::SigSpec sig_y = (*sigmap)(cell->getPort(ID::Y)), sig_a = cell->getPort(ID::A); + for (int i = 0; i < GetSize(sig_y); i++) + next[sig_y[i]] = sig_a[i]; + } + pool inputs = input_nets(module), moved; + for (auto [from, to] : next) { + RTLIL::State val = (*this)(from); + if (val == State::Sx) + continue; + moved.insert(from); + for (int i = 0; i < GetSize(next) && next.count((*sigmap)(to)); i++) + to = next.at((*sigmap)(to)); + RTLIL::SigBit to_net = (*sigmap)(to); + if (to_net.wire == nullptr || inputs.count(to_net)) + continue; + RTLIL::State to_val = (*this)(to); + if (to_val == State::Sx) + set_init(to, val); + else if (to_val != val) + log_error("Conflicting init values for signal %s (%s = %s != %s).\n", + log_signal(to), log_signal(from), log_signal(val), log_signal(to_val)); + } + remove_net_inits(module, moved); + } + + pool input_nets(RTLIL::Module *module) const + { + pool nets; + for (auto wire : module->wires()) + if (wire->port_input) + for (auto bit : (*sigmap)(wire)) + nets.insert(bit); + return nets; + } + + void remove_net_inits(RTLIL::Module *module, const pool &nets) + { + for (auto bit : nets) + initbits.erase(bit); + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID::init); + if (it == wire->attributes.end()) + continue; + for (int i = 0; i < GetSize(wire) && i < GetSize(it->second); i++) + if (nets.count((*sigmap)(RTLIL::SigBit(wire, i)))) + it->second.set(i, State::Sx); + if (it->second.is_fully_undef()) + wire->attributes.erase(it); + } + } + void clear() { initbits.clear(); diff --git a/passes/cmds/optbarriers.cc b/passes/cmds/optbarriers.cc index b76a635e7..17db61e6d 100644 --- a/passes/cmds/optbarriers.cc +++ b/passes/cmds/optbarriers.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include USING_YOSYS_NAMESPACE @@ -455,6 +456,11 @@ struct OptBarriersPass : public Pass { } module->new_connections(new_connections); } + + // Init values belong to the driver side of the barriers + SigMap init_sigmap(module); + FfInitVals initvals(&init_sigmap, module); + initvals.move_barrier_inits(module); } } diff --git a/tests/various/optbarriers.ys b/tests/various/optbarriers.ys index 3c1ce8db2..4e0ba61f9 100644 --- a/tests/various/optbarriers.ys +++ b/tests/various/optbarriers.ys @@ -166,3 +166,53 @@ design -pop # With barriers they aren't prep -barriers select -assert-none w:c %ci1 w:d %ci1 %i + +design -reset + +# init on FF output +read_verilog <