3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-25 16:42:35 +00:00
yosys/passes/silimate/peepopt_muxneg.pmg
2026-03-30 16:30:46 -07:00

74 lines
2.1 KiB
Text

pattern muxneg
//
// Authored by Abhinav Tondapu of Silimate, Inc. under ISC license.
//
// Factor negation out of mux
//
// s ? (-a) : (-b) ===> -(s ? a : b)
//
state <SigSpec> mux_a mux_b mux_s mux_y neg_a_in neg_a_y neg_b_in neg_b_y
state <bool> neg_a_signed neg_b_signed
match mux
select mux->type == $mux
set mux_a port(mux, \A)
set mux_b port(mux, \B)
set mux_s port(mux, \S)
set mux_y port(mux, \Y)
endmatch
match neg_a
select neg_a->type == $neg
filter nusers(port(neg_a, \Y)) == 2
index <SigSpec> port(neg_a, \Y) === mux_a
set neg_a_in port(neg_a, \A)
set neg_a_y port(neg_a, \Y)
set neg_a_signed neg_a->getParam(\A_SIGNED).as_bool()
endmatch
match neg_b
select neg_b->type == $neg
filter nusers(port(neg_b, \Y)) == 2
index <SigSpec> port(neg_b, \Y) === mux_b
set neg_b_in port(neg_b, \A)
set neg_b_y port(neg_b, \Y)
set neg_b_signed neg_b->getParam(\A_SIGNED).as_bool()
endmatch
code mux_a mux_b mux_s mux_y neg_a_in neg_a_y neg_b_in neg_b_y neg_a_signed neg_b_signed
if (neg_a_signed != neg_b_signed)
reject;
{
// Anchor to the narrower negation width to preserve wrap behavior
int width = std::min(GetSize(neg_a_y), GetSize(neg_b_y));
Cell *cell = mux;
SigSpec neg_a_rs = neg_a_in;
SigSpec neg_b_rs = neg_b_in;
neg_a_rs.extend_u0(width, neg_a_signed);
neg_b_rs.extend_u0(width, neg_b_signed);
SigSpec mux_out = module->addWire(NEW_ID2_SUFFIX("y"), width);
Cell *new_mux = module->addMux(NEW_ID2_SUFFIX("mux"), neg_a_rs, neg_b_rs, mux_s, mux_out);
SigSpec neg_out = module->addWire(NEW_ID2_SUFFIX("neg_y"), width);
Cell *new_neg = module->addNeg(NEW_ID2_SUFFIX("neg"), mux_out, neg_out, neg_a_signed);
// Extend back to mux output width when needed
SigSpec neg_out_rs = neg_out;
neg_out_rs.extend_u0(GetSize(mux_y), neg_a_signed);
module->connect(mux_y, neg_out_rs);
log(" mux=%s, neg_a=%s, neg_b=%s\n",
log_id(mux), log_id(neg_a), log_id(neg_b));
new_mux->fixup_parameters();
new_neg->fixup_parameters();
autoremove(mux);
autoremove(neg_a);
autoremove(neg_b);
did_something = true;
}
accept;
endcode