3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-25 00:22:34 +00:00

Add muxmode pass and tests

This commit is contained in:
Akash Levy 2025-03-30 17:54:18 -07:00
parent dacd882383
commit 161ff0fa3f
7 changed files with 653 additions and 2 deletions

View file

@ -21,3 +21,14 @@ PEEPOPT_PATTERN = passes/silimate/peepopt_expand.pmg
passes/silimate/peepopt_expand.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
OBJS += passes/silimate/muxmode.o
GENFILES += passes/silimate/peepopt_muxmode.h
passes/silimate/muxmode.o: passes/silimate/peepopt_muxmode.h
$(eval $(call add_extra_objs,passes/silimate/peepopt_muxmode.h))
PEEPOPT_PATTERN = passes/silimate/peepopt_muxmode.pmg
PEEPOPT_PATTERN += passes/silimate/peepopt_muxinvprop.pmg
passes/silimate/peepopt_muxmode.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p $(dir $@) && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)

View file

@ -0,0 +1,64 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* Akash Levy <akash@silimate.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/silimate/peepopt_muxmode.h"
struct MuxmodePass : public Pass {
MuxmodePass() : Pass("muxmode", "convert primitives to muxes") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" muxmode [selection]\n");
log("\n");
log("This pass makes muxes of 1-bit primitives having an input coming from a mux.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing MUXMODE pass (make muxes from 1-bit primitives).\n");
size_t argidx = 1;
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
did_something = true;
for (int i = 0; did_something; i++)
{
log("ITERATION %d OF MUXMODE\n", i);
did_something = false;
peepopt_pm pm(module);
pm.setup(module->selected_cells());
pm.run_muxmode();
pm.run_muxinvprop();
}
}
}
} PeepoptPass;
PRIVATE_NAMESPACE_END

View file

@ -0,0 +1,60 @@
pattern muxinvprop
//
// Authored by Akash Levy of Silimate, Inc. under ISC license.
//
// Propagate inverters from mux outputs to inputs
//
// ~ (S ? A : B) ==> S ? ~A : ~B
//
state <SigSpec> mux_a mux_b mux_y inv_a inv_y
match mux_gate
// Select mux
select mux_gate->type.in($mux)
set mux_a port(mux_gate, \A)
set mux_b port(mux_gate, \B)
set mux_y port(mux_gate, \Y)
endmatch
code
// Fanout of each MUX gate Y bit should be 1 (no bit-split)
if (nusers(mux_y) != 2)
reject;
endcode
match inv_gate
// Select inverter
select inv_gate->type.in($not)
set inv_a port(inv_gate, \A)
set inv_y port(inv_gate, \Y)
// Connection
index <SigSpec> port(inv_gate, \A) === mux_y
endmatch
code mux_a mux_b mux_y inv_a inv_y
// Disconnect all ports
mux_gate->unsetPort(\A);
mux_gate->unsetPort(\B);
mux_gate->unsetPort(\Y);
inv_gate->unsetPort(\A);
inv_gate->unsetPort(\Y);
// Set cell to mux_gate for naming
Cell *cell = mux_gate;
// Set new ports
mux_gate->setPort(\A, module->Not(NEW_ID2_SUFFIX("not_a"), mux_a, false, mux_gate->get_src_attribute()));
mux_gate->setPort(\B, module->Not(NEW_ID2_SUFFIX("not_b"), mux_b, false, mux_gate->get_src_attribute()));
mux_gate->setPort(\Y, inv_y);
// Rename MUX gate for formal
module->rename(mux_gate, NEW_ID2_SUFFIX("not"));
// Log, fixup, accept
log("muxinvprop pattern in %s: mux=%s, not=%s\n", log_id(module), log_id(mux_gate), log_id(inv_gate));
autoremove(inv_gate);
did_something = true;
accept;
endcode

View file

@ -0,0 +1,77 @@
pattern muxmode
//
// Authored by Akash Levy of Silimate, Inc. under ISC license.
//
// Make muxes of 1-bit primitives having an input coming from a mux
//
// A & B ==> A ? B : 0
// A | B ==> A ? 1 : B
// A ^ B ==> A ? ~B : B
// A ^~ B ==> A ? B : ~B
//
state <SigSpec> mux_y prim_a prim_b
match mux_gate
// Select MUX that connects to one of the primitives' inputs
select mux_gate->type.in($mux)
filter param(mux_gate, \WIDTH) == 1
set mux_y port(mux_gate, \Y)
endmatch
match prim_gate
// Select AND/OR (not XOR/XNOR for now)
select prim_gate->type.in($and, $or)
filter param(prim_gate, \A_WIDTH) == 1
filter param(prim_gate, \B_WIDTH) == 1
// Set ports, allowing A and B to be swapped
choice <IdString> A {\A, \B}
define <IdString> B (A == \A ? \B : \A)
set prim_a port(prim_gate, A)
set prim_b port(prim_gate, B)
// Connection
index <SigSpec> port(prim_gate, B) === mux_y
endmatch
code mux_y prim_a prim_b
// Unset ports/params of primitive
prim_gate->unsetPort(\A);
prim_gate->unsetPort(\B);
prim_gate->unsetParam(\A_WIDTH);
prim_gate->unsetParam(\A_SIGNED);
prim_gate->unsetParam(\B_WIDTH);
prim_gate->unsetParam(\B_SIGNED);
prim_gate->unsetParam(\Y_WIDTH);
// Set mux's S port to primitive's A port
prim_gate->setPort(\S, prim_a);
// Set cell to be prim_gate for naming
Cell *cell = prim_gate;
// Set mux inputs
if (prim_gate->type == $and) {
prim_gate->setPort(\A, State::S0);
prim_gate->setPort(\B, prim_b);
} else if (prim_gate->type == $or) {
prim_gate->setPort(\A, prim_b);
prim_gate->setPort(\B, State::S1);
} else if (prim_gate->type == $xor) {
prim_gate->setPort(\A, prim_b);
prim_gate->setPort(\B, module->Not(NEW_ID2, prim_b, false, cell->get_src_attribute()));
} else if (prim_gate->type == $xnor) {
prim_gate->setPort(\A, module->Not(NEW_ID2, prim_b, false, cell->get_src_attribute()));
prim_gate->setPort(\B, prim_b);
} else {
log_abort();
}
// Log, fixup type and parameters, accept
log("muxmode pattern in %s: mux=%s, prim=%s, primtype=%s\n", log_id(module), log_id(mux_gate), log_id(prim_gate), log_id(prim_gate->type));
prim_gate->type = $mux;
prim_gate->fixup_parameters();
did_something = true;
accept;
endcode