From: Andrew Zonenberg Date: Tue, 12 Sep 2017 00:18:26 +0000 (-0700) Subject: Initial version of opt_demorgan is functioning for AND/OR gates. Not the prettiest... X-Git-Tag: yosys-0.8~321^2~1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6da5d36968b2792e27291adb1c89f0b1db5c5cd0;p=yosys.git Initial version of opt_demorgan is functioning for AND/OR gates. Not the prettiest results for bus inputs, but this can be improved --- diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index a145cf946..639dc6590 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -6,6 +6,7 @@ OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_rmdff.o OBJS += passes/opt/opt_clean.o OBJS += passes/opt/opt_expr.o +OBJS += passes/opt/opt_demorgan.o OBJS += passes/opt/rmports.o ifneq ($(SMALL),1) diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc new file mode 100644 index 000000000..62d65dea7 --- /dev/null +++ b/passes/opt/opt_demorgan.cc @@ -0,0 +1,202 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2017 Clifford Wolf + * + * 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" +#include "kernel/modtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void demorgan_worker( + ModIndex& index, + Cell *cell, + unsigned int& cells_changed) +{ + SigMap& sigmap = index.sigmap; + auto m = cell->module; + + //TODO: Add support for reduce_xor + //DeMorgan of XOR is either XOR (if even number of inputs) or XNOR (if odd number) + + if( (cell->type != "$reduce_and") && (cell->type != "$reduce_or") ) + return; + + auto insig = sigmap(cell->getPort("\\A")); + log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), insig.size()); + int num_inverted = 0; + for(int i=0; i ports = index.query_ports(b); + bool inverted = false; + for(auto x : ports) + { + if(x.port == "\\Y" && x.cell->type == "$_NOT_") + { + inverted = true; + break; + } + } + + if(inverted) + num_inverted ++; + } + + //Stop if less than half of the inputs are inverted + if(num_inverted*2 < insig.size()) + { + log(" %d / %d inputs are inverted, not pushing\n", num_inverted, insig.size()); + return; + } + + //More than half of the inputs are inverted! Push through + cells_changed ++; + log(" %d / %d inputs are inverted, pushing inverter through reduction\n", num_inverted, insig.size()); + + //For each input, either add or remove the inverter as needed + //TODO: this duplicates the loop up above, can we refactor it? + for(int i=0; i ports = index.query_ports(b); + RTLIL::Cell* srcinv = NULL; + for(auto x : ports) + { + if(x.port == "\\Y" && x.cell->type == "$_NOT_") + { + srcinv = x.cell; + break; + } + } + + //We are NOT inverted! Add an inverter + if(!srcinv) + { + auto inverted_b = m->addWire(NEW_ID); + m->addNot(NEW_ID, RTLIL::SigSpec(b), RTLIL::SigSpec(inverted_b)); + insig[i] = inverted_b; + } + + //We ARE inverted - bypass it + //Don't automatically delete the inverter since other stuff might still use it + else + insig[i] = srcinv->getPort("\\A"); + } + + //Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it + //Reductions are all commutative, so there's no point in having them in a weird order + bool same_signal = true; + RTLIL::Wire* srcwire = insig[0].wire; + std::map seen_bits; + for(int i=0; iwidth) ) + { + log("Rearranging bits\n"); + RTLIL::SigSpec newsig; + for(int i=0; isetPort("\\A", insig); + + //Change the cell type + if(cell->type == "$reduce_and") + cell->type = "$reduce_or"; + else if(cell->type == "$reduce_or") + cell->type = "$reduce_and"; + //don't change XOR + + //Add an inverter to the output + auto inverted_output = cell->getPort("\\Y"); + auto uninverted_output = m->addWire(NEW_ID); + m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output); + cell->setPort("\\Y", uninverted_output); +} + +struct OptDemorganPass : public Pass { + OptDemorganPass() : Pass("opt_demorgan", "Optimize reductions with DeMorgan equivalents") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_demorgan [selection]\n"); + log("\n"); + log("This pass pushes inverters through $reduce_* cells if this will reduce the\n"); + log("overall gate count of the circuit\n"); + log("\n"); + } + virtual void execute(std::vector /*args*/, RTLIL::Design *design) + { + log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n"); + + //int argidx = 0; + //extra_args(args, argidx, design); + + unsigned int cells_changed = 0; + for (auto module : design->selected_modules()) + { + ModIndex index(module); + for (auto cell : module->selected_cells()) + demorgan_worker(index, cell, cells_changed); + } + + if(cells_changed) + log("Pushed inverters through %u reductions\n", cells_changed); + } +} OptDemorganPass; + +PRIVATE_NAMESPACE_END