From: Clifford Wolf Date: Sun, 3 Aug 2014 13:02:05 +0000 (+0200) Subject: Added "wreduce" command (work in progress) X-Git-Tag: yosys-0.4~313 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b02f6ca30a7bb5c3c8c34908aab8b8aa821c113;p=yosys.git Added "wreduce" command (work in progress) --- diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index b55af9958..d6e45f2d1 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -20,4 +20,5 @@ OBJS += passes/cmds/write_file.o OBJS += passes/cmds/connwrappers.o OBJS += passes/cmds/cover.o OBJS += passes/cmds/trace.o +OBJS += passes/cmds/wreduce.o diff --git a/passes/cmds/wreduce.cc b/passes/cmds/wreduce.cc new file mode 100644 index 000000000..39881a831 --- /dev/null +++ b/passes/cmds/wreduce.cc @@ -0,0 +1,252 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 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" + +#include + +USING_YOSYS_NAMESPACE +using namespace RTLIL; + +PRIVATE_NAMESPACE_BEGIN + +struct WreduceConfig +{ + std::set supported_cell_types; + + WreduceConfig() + { + supported_cell_types.insert("$not"); + supported_cell_types.insert("$pos"); + supported_cell_types.insert("$bu0"); + supported_cell_types.insert("$neg"); + + supported_cell_types.insert("$and"); + supported_cell_types.insert("$or"); + supported_cell_types.insert("$xor"); + supported_cell_types.insert("$xnor"); + + supported_cell_types.insert("$shl"); + supported_cell_types.insert("$shr"); + supported_cell_types.insert("$sshl"); + supported_cell_types.insert("$sshr"); + supported_cell_types.insert("$shift"); + supported_cell_types.insert("$shiftx"); + + supported_cell_types.insert("$lt"); + supported_cell_types.insert("$le"); + supported_cell_types.insert("$eq"); + supported_cell_types.insert("$ne"); + supported_cell_types.insert("$eqx"); + supported_cell_types.insert("$nex"); + supported_cell_types.insert("$ge"); + supported_cell_types.insert("$gt"); + + supported_cell_types.insert("$add"); + supported_cell_types.insert("$sub"); + // supported_cell_types.insert("$mul"); + // supported_cell_types.insert("$div"); + // supported_cell_types.insert("$mod"); + // supported_cell_types.insert("$pow"); + + // supported_cell_types.insert("$mux"); + // supported_cell_types.insert("$pmux"); + // supported_cell_types.insert("$safe_pmux"); + } +}; + +struct WreduceWorker +{ + WreduceConfig *config; + Module *module; + ModIndex mi; + + std::set> work_queue_cells; + std::set work_queue_bits; + SigMap constmap; + + WreduceWorker(WreduceConfig *config, Module *module) : + config(config), module(module), mi(module) { } + + void run_reduce_inport(Cell *cell, char port) + { + bool is_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool(); + SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port))); + + int bits_removed = 0; + if (is_signed) { + while (SIZE(sig) > 1 && constmap(sig[SIZE(sig)-1]) == constmap(sig[SIZE(sig)-2])) + work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++; + } else { + while (SIZE(sig) > 1 && constmap(sig[SIZE(sig)-1]) == S0) + work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++; + } + + if (bits_removed) { + log("Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n", + bits_removed, SIZE(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type)); + cell->setPort(stringf("\\%c", port), sig); + } + } + + void run_cell(Cell *cell) + { + if (config->supported_cell_types.count(cell->type) == 0) + return; + + if (cell->type == ID("$shl") || cell->type == ID("$shr") || cell->type == ID("$sshl") || cell->type == ID("$sshr")) + cell->setParam("\\B_SIGNED", false); + + if (cell->hasParam("\\A_SIGNED")) + run_reduce_inport(cell, 'A'); + + if (cell->hasParam("\\B_SIGNED")) + run_reduce_inport(cell, 'B'); + + SigSpec sig = mi.sigmap(cell->getPort("\\Y")); + + int bits_removed = 0; + while (SIZE(sig) > 0) { + auto info = mi.query(sig[SIZE(sig)-1]); + if (info->is_output || SIZE(info->ports) > 1) + break; + sig.remove(SIZE(sig)-1); + bits_removed++; + } + + if (cell->type == ID("$not") || cell->type == ID("$pos") || cell->type == ID("$bu0") || cell->type == ID("$neg") || + cell->type == ID("$and") || cell->type == ID("$or") || cell->type == ID("$xor") || cell->type == ID("$xnor") || + cell->type == ID("$add") || cell->type == ID("$sub") || cell->type == ID("$mul")) + { + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + + int a_size = 0, b_size = 0; + if (cell->hasPort("\\A")) a_size = SIZE(cell->getPort("\\A")); + if (cell->hasPort("\\B")) b_size = SIZE(cell->getPort("\\B")); + + while (SIZE(sig) > 1 && SIZE(sig) > std::max(a_size, b_size)) { + module->connect(sig[SIZE(sig)-1], is_signed ? sig[SIZE(sig)-2] : S0); + sig.remove(SIZE(sig)-1); + bits_removed++; + } + } + + if (bits_removed) { + log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n", + bits_removed, SIZE(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type)); + cell->setPort("\\Y", sig); + } + + cell->fixup_parameters(); + } + + void run() + { + for (auto c : module->selected_cells()) + work_queue_cells.insert(c); + + while (!work_queue_cells.empty()) + { + work_queue_bits.clear(); + for (auto c : work_queue_cells) + run_cell(c); + + work_queue_cells.clear(); + for (auto bit : work_queue_bits) + for (auto port : mi.query_ports(bit)) + work_queue_cells.insert(port.cell); + } + + std::set removed_wire_bits; + + for (auto w : module->selected_wires()) + { + int bits_removed = 0; + while (w->width > 0) { + SigBit bit(w, w->width-1); + auto info = mi.query(bit); + if (info == nullptr || (!info->is_output && !info->is_input && !SIZE(info->ports))) { + removed_wire_bits.insert(bit); + bits_removed++; + w->width--; + continue; + } + break; + } + if (bits_removed) + log("Removed top %d bits (of %d) from wire %s.%s.\n", + bits_removed, SIZE(w) + bits_removed, log_id(module), log_id(w)); + } + + if (!removed_wire_bits.empty()) { + std::vector new_conn = module->connections(); + for (auto &ss : new_conn) { + SigSig new_ss; + for (int i = 0; i < SIZE(ss.first); i++) + if (!removed_wire_bits.count(ss.first[i]) && !removed_wire_bits.count(ss.second[i])) { + new_ss.first.append_bit(ss.first[i]); + new_ss.second.append_bit(ss.second[i]); + } + ss = std::move(new_ss); + } + module->new_connections(new_conn); + } + } +}; + +struct WreducePass : public Pass { + WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" wreduce [options] [selection]\n"); + log("\n"); + log("This command reduces the word size of operations.\n"); + log("\n"); + } + virtual void execute(std::vector args, Design *design) + { + WreduceConfig config; + + log_header("Executing WREDCUE pass (reducing word size of cells).\n"); + + log_error("FIXME: This command is under construction.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + if (module->has_processes_warn()) + continue; + + WreduceWorker worker(&config, module); + worker.run(); + } + } +} WreducePass; + +PRIVATE_NAMESPACE_END +