Move init values across barriers.

This commit is contained in:
nella
2026-09-30 17:41:29 +02:00
parent 5610060fae
commit 5c3c9b2957
3 changed files with 114 additions and 0 deletions
+58
View File
@@ -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<RTLIL::SigBit, RTLIL::SigBit> 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<RTLIL::SigBit> 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<RTLIL::SigBit> input_nets(RTLIL::Module *module) const
{
pool<RTLIL::SigBit> 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<RTLIL::SigBit> &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();
+6
View File
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
#include <algorithm>
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);
}
}
+50
View File
@@ -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 <<EOT
module top(input clk, input d, output reg q = 1'b1);
always @(posedge clk) q <= d;
endmodule
EOT
proc
optbarriers
select -assert-count 1 t:$barrier
select -assert-count 1 t:$dff %co:+[Q] w:* %i a:init %i
select -assert-none w:q a:init %i
design -reset
# init on alias
read_verilog <<EOT
module top(input clk, input d, output reg q = 1'b1, output w);
assign w = q;
always @(posedge clk) q <= d;
endmodule
EOT
proc
setattr -set init 1'b1 w:w
optbarriers -noconns
select -assert-none t:$barrier %co:+[Y] w:* %i a:init %i
design -reset
# Init on input port
read_rtlil <<EOT
module \top
wire input 1 \i
attribute \init 1'1
wire output 2 \y
wire $a
connect $a \i
cell $barrier \b
parameter \WIDTH 1
connect \A $a
connect \Y \y
end
end
EOT
optbarriers
opt_clean
select -assert-none w:i a:init %i