From eec2cd1e7850133302654ae8985d8ede9954a569 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 02:43:31 +0100 Subject: [PATCH 1/6] Added RTLIL::SigSpec::optimized() API --- kernel/rtlil.cc | 7 +++++++ kernel/rtlil.h | 1 + 2 files changed, 8 insertions(+) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1311f31cc..661525735 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1024,6 +1024,13 @@ void RTLIL::SigSpec::optimize() check(); } +RTLIL::SigSpec RTLIL::SigSpec::optimized() const +{ + RTLIL::SigSpec ret = *this; + ret.optimize(); + return ret; +} + bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b) { if (a.wire != b.wire) { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 8e3b78eef..504fdbbdc 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -373,6 +373,7 @@ struct RTLIL::SigSpec { SigSpec(std::vector bits); void expand(); void optimize(); + RTLIL::SigSpec optimized() const; void sort(); void sort_and_unify(); void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with); From 67d155078d15610f8e6b505fe9c4b8552c2e4141 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 02:44:05 +0100 Subject: [PATCH 2/6] More freduce cleanups and bugfixes --- passes/sat/freduce.cc | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index 4b868b3c9..cc3739fe4 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -231,9 +231,7 @@ struct PerformReduction std::vector bucket_sigbits; for (int idx : bucket) bucket_sigbits.push_back(out_bits[idx]); - RTLIL::SigSpec bucket_sig(bucket_sigbits); - bucket_sig.optimize(); - log("%*s Trying to shatter bucket with %d signals: %s\n", 2*level, "", int(bucket.size()), log_signal(bucket_sig)); + log("%*s Trying to shatter bucket with %d signals: %s\n", 2*level, "", int(bucket.size()), log_signal(RTLIL::SigSpec(bucket_sigbits).optimized())); } std::vector sat_list, sat_inv_list; @@ -340,6 +338,34 @@ struct PerformReduction if (r.size() <= 1) continue; + if (verbose_level >= 1) { + std::vector r_sigbits; + for (int idx : r) + r_sigbits.push_back(out_bits[idx]); + log(" Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(RTLIL::SigSpec(r_sigbits).optimized())); + } + + std::vector undef_slaves; + + for (int idx : r) { + std::vector sat_def_list; + for (int idx2 : r) + if (idx != idx2) + sat_def_list.push_back(sat_def[idx2]); + if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list))) + undef_slaves.push_back(idx); + } + + if (undef_slaves.size() == bucket.size()) { + if (verbose_level >= 1) + log(" Complex undef overlap. None of the signals covers the others.\n"); + // FIXME: We could try to further shatter a group with complex undef overlaps + return; + } + + for (int idx : undef_slaves) + out_depth[idx] = std::numeric_limits::max(); + std::vector result; for (int idx : r) { @@ -418,10 +444,8 @@ struct FreduceWorker buckets[std::vector()].push_back(RTLIL::SigBit(RTLIL::State::S1)); for (auto &batch : batches) { - RTLIL::SigSpec batch_sig(std::vector(batch.begin(), batch.end())); - batch_sig.optimize(); - - log(" Finding reduced input cone for signal batch %s%c\n", log_signal(batch_sig), verbose_level ? ':' : '.'); + log(" Finding reduced input cone for signal batch %s%c\n", + log_signal(RTLIL::SigSpec(std::vector(batch.begin(), batch.end())).optimized()), verbose_level ? ':' : '.'); FindReducedInputs infinder(sigmap, drivers); for (auto &bit : batch) { @@ -439,10 +463,7 @@ struct FreduceWorker if (bucket.second.size() == 1) continue; - RTLIL::SigSpec bucket_sig(bucket.second); - bucket_sig.optimize(); - - log(" Trying to shatter bucket %s%c\n", log_signal(bucket_sig), verbose_level ? ':' : '.'); + log(" Trying to shatter bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.'); PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second); worker.analyze(equiv); } From 914e208aa3b6d52d3a4145525d15c4fba237fd87 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 12:33:00 +0100 Subject: [PATCH 3/6] Added "connect" command --- passes/cmds/Makefile.inc | 1 + passes/cmds/connect.cc | 185 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 passes/cmds/connect.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 24d6075b2..9e96ff361 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -4,6 +4,7 @@ OBJS += passes/cmds/design.o OBJS += passes/cmds/select.o OBJS += passes/cmds/show.o OBJS += passes/cmds/rename.o +OBJS += passes/cmds/connect.o OBJS += passes/cmds/scatter.o OBJS += passes/cmds/splitnets.o OBJS += passes/cmds/stat.o diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc new file mode 100644 index 000000000..7a54e8dc6 --- /dev/null +++ b/passes/cmds/connect.cc @@ -0,0 +1,185 @@ +/* + * 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/register.h" +#include "kernel/rtlil.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/log.h" + +static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig) +{ + CellTypes ct(design); + + RTLIL::Wire *dummy_wire = module->new_wire(sig.width, NEW_ID); + + for (auto &it : module->cells) + for (auto &port : it.second->connections) + if (ct.cell_output(it.second->type, port.first)) + sigmap(port.second).replace(sig, dummy_wire, &port.second); + + for (auto &conn : module->connections) + sigmap(conn.first).replace(sig, dummy_wire, &conn.first); +} + +struct ConnectPass : public Pass { + ConnectPass() : Pass("connect", "create or remove connections") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" connect [-nomap] [-nounset] -set \n"); + log("\n"); + log("Create a connection. This is equivialent to adding the statement 'assign\n"); + log(" = ;' to the verilog input. Per default, all existing\n"); + log("drivers for are unconnected. This can be overwritten by using\n"); + log("the -nounset option.\n"); + log("\n"); + log("\n"); + log(" connect [-nomap] -unset \n"); + log("\n"); + log("Unconnect all existing drivers for the specified expression.\n"); + log("\n"); + log("\n"); + log(" connect [-nomap] -port \n"); + log("\n"); + log("Connect the specified cell port to the specified cell port.\n"); + log("\n"); + log("\n"); + log("Per default signal alias names are resolved and all signal names are mapped\n"); + log("the the signal name of the primary driver. Using the -nomap option deactivates\n"); + log("this behavior.\n"); + log("\n"); + log("The connect command operates in one module only. Either only one module must\n"); + log("be selected or an active module must be set using the 'cd' command.\n"); + log("\n"); + log("This command does not operate on module with processes.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + RTLIL::Module *module = NULL; + for (auto &it : design->modules) { + if (!design->selected(it.second)) + continue; + if (module != NULL) + log_cmd_error("Multiple modules selected: %s, %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.first)); + module = it.second; + } + if (module == NULL) + log_cmd_error("No modules selected.\n"); + if (!module->processes.empty()) + log_cmd_error("Found processes in selected module.\n"); + + bool flag_nounset = false, flag_nomap = false; + std::string set_lhs, set_rhs, unset_expr; + std::string port_cell, port_port, port_expr; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-nounset") { + flag_nounset = true; + continue; + } + if (arg == "-nomap") { + flag_nomap = true; + continue; + } + if (arg == "-set" && argidx+2 < args.size()) { + set_lhs = args[++argidx]; + set_rhs = args[++argidx]; + continue; + } + if (arg == "-unset" && argidx+1 < args.size()) { + unset_expr = args[++argidx]; + continue; + } + if (arg == "-port" && argidx+3 < args.size()) { + port_cell = args[++argidx]; + port_port = args[++argidx]; + port_expr = args[++argidx]; + continue; + } + break; + } + + SigMap sigmap; + if (!flag_nomap) + for (auto &it : module->connections) { + std::vector lhs = it.first.to_sigbit_vector(); + std::vector rhs = it.first.to_sigbit_vector(); + for (size_t i = 0; i < lhs.size(); i++) + if (rhs[i].wire != NULL) + sigmap.add(lhs[i], rhs[i]); + } + + if (!set_lhs.empty()) + { + if (!unset_expr.empty() || !port_cell.empty()) + log_cmd_error("Cant use -set together with -unset and/or -port.\n"); + + RTLIL::SigSpec sig_lhs, sig_rhs; + if (!RTLIL::SigSpec::parse(sig_lhs, module, set_lhs)) + log_cmd_error("Failed to parse set lhs expression `%s'.\n", set_lhs.c_str()); + if (!RTLIL::SigSpec::parse_rhs(sig_lhs, sig_rhs, module, set_rhs)) + log_cmd_error("Failed to parse set rhs expression `%s'.\n", set_rhs.c_str()); + + sigmap.apply(sig_lhs); + sigmap.apply(sig_rhs); + + if (!flag_nounset) + unset_drivers(design, module, sigmap, sig_lhs); + + module->connections.push_back(RTLIL::SigSig(sig_lhs, sig_rhs)); + } + else + if (!unset_expr.empty()) + { + if (!port_cell.empty() || flag_nounset) + log_cmd_error("Cant use -unset together with -port and/or -nounset.\n"); + + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, unset_expr)) + log_cmd_error("Failed to parse unset expression `%s'.\n", unset_expr.c_str()); + + sigmap.apply(sig); + unset_drivers(design, module, sigmap, sig); + } + else + if (!port_cell.empty()) + { + if (flag_nounset) + log_cmd_error("Cant use -port together with -nounset.\n"); + + if (module->cells.count(RTLIL::escape_id(port_cell)) == 0) + log_cmd_error("Can't find cell %s.\n", port_cell.c_str()); + + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, port_expr)) + log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str()); + + module->cells.at(RTLIL::escape_id(port_cell))->connections[RTLIL::escape_id(port_port)] = sigmap(sig); + } + else + log_cmd_error("Expected -set, -unset, or -port.\n"); + } +} ConnectPass; + From c3e9f0712fa2a35cf3e4a638164aed7ab8d8ff4a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 12:34:18 +0100 Subject: [PATCH 4/6] Another small freduce cleanup/bugfix --- passes/sat/freduce.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index cc3739fe4..4db11436e 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -482,7 +482,8 @@ struct FreduceWorker RTLIL::Cell *drv = drivers.at(grp[i].bit).first; RTLIL::Wire *dummy_wire = module->new_wire(1, NEW_ID); for (auto &port : drv->connections) - sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second); + if (ct.cell_output(drv->type, port.first)) + sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second); if (grp[i].inverted) { From bf5e5429c19af5ab92c30a0c7ca99408cd1f3dde Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 13:15:11 +0100 Subject: [PATCH 5/6] Use selection in freduce command --- passes/sat/freduce.cc | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index 4db11436e..893fe5167 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -397,13 +397,14 @@ struct PerformReduction struct FreduceWorker { + RTLIL::Design *design; RTLIL::Module *module; SigMap sigmap; drivers_t drivers; std::set> inv_pairs; - FreduceWorker(RTLIL::Module *module) : module(module), sigmap(module) + FreduceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), sigmap(module) { } @@ -444,6 +445,12 @@ struct FreduceWorker buckets[std::vector()].push_back(RTLIL::SigBit(RTLIL::State::S1)); for (auto &batch : batches) { + for (auto &bit : batch) + if (bit.wire != NULL && design->selected(module, bit.wire)) + goto found_selected_wire; + continue; + + found_selected_wire: log(" Finding reduced input cone for signal batch %s%c\n", log_signal(RTLIL::SigSpec(std::vector(batch.begin(), batch.end())).optimized()), verbose_level ? ':' : '.'); @@ -477,6 +484,11 @@ struct FreduceWorker RTLIL::SigSpec inv_sig; for (size_t i = 1; i < grp.size(); i++) { + if (!design->selected(module, grp[i].bit.wire)) { + log(" Skipping not-selected slave: %s\n", log_signal(grp[i].bit)); + continue; + } + log(" Connect slave%s: %s\n", grp[i].inverted ? " using inverter" : "", log_signal(grp[i].bit)); RTLIL::Cell *drv = drivers.at(grp[i].bit).first; @@ -527,15 +539,18 @@ struct FreducePass : public Pass { log("equivialent, they are merged to one node and one of the redundant drivers is\n"); log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\n"); log("\n"); - log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n"); - log("equivialent nodes.\n"); - log("\n"); log(" -v, -vv\n"); log(" enable verbose or very verbose output\n"); log("\n"); log(" -inv\n"); log(" enable explicit handling of inverted signals\n"); log("\n"); + log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n"); + log("equivialent nodes.\n"); + log("\n"); + log("All selected wires are considered for rewiring. The selected cells cover the\n"); + log("circuit that is analyzed.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { @@ -566,7 +581,7 @@ struct FreducePass : public Pass { for (auto &mod_it : design->modules) { RTLIL::Module *module = mod_it.second; if (design->selected(module)) - bitcount += FreduceWorker(module).run(); + bitcount += FreduceWorker(design, module).run(); } log("Rewired a total of %d signal bits.\n", bitcount); From 60fbca9970e1b92d61642b86d2a3170b5b33ad6f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 3 Jan 2014 14:01:06 +0100 Subject: [PATCH 6/6] Added "splitnets -driver" --- passes/cmds/splitnets.cc | 125 ++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 29 deletions(-) diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc index 628e87db4..68e1edd14 100644 --- a/passes/cmds/splitnets.cc +++ b/passes/cmds/splitnets.cc @@ -24,16 +24,48 @@ struct SplitnetsWorker { - std::map> splitmap; + std::map> splitmap; + + void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format) + { + RTLIL::Wire *new_wire = new RTLIL::Wire; + + new_wire->port_id = wire->port_id; + new_wire->port_input = wire->port_input; + new_wire->port_output = wire->port_output; + new_wire->name = wire->name; + new_wire->width = width; + + if (format.size() > 0) + new_wire->name += format.substr(0, 1); + + if (width > 1) { + new_wire->name += stringf("%d", offset+width-1); + if (format.size() > 2) + new_wire->name += format.substr(2, 1); + else + new_wire->name += ":"; + } + + new_wire->name += stringf("%d", offset); + + if (format.size() > 1) + new_wire->name += format.substr(1, 1); + + while (module->count_id(new_wire->name) > 0) + new_wire->name = new_wire->name + "_"; + module->add(new_wire); + + std::vector sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector(); + splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end()); + } void operator()(RTLIL::SigSpec &sig) { sig.expand(); for (auto &c : sig.chunks) - if (splitmap.count(c.wire) > 0) { - c.wire = splitmap.at(c.wire).at(c.offset); - c.offset = 0; - } + if (splitmap.count(c.wire) > 0) + c = splitmap.at(c.wire).at(c.offset); sig.optimize(); } }; @@ -48,19 +80,25 @@ struct SplitnetsPass : public Pass { log("\n"); log("This command splits multi-bit nets into single-bit nets.\n"); log("\n"); - log(" -format char1[char2]\n"); + log(" -format char1[char2[char3]]\n"); log(" the first char is inserted between the net name and the bit index, the\n"); log(" second char is appended to the netname. e.g. -format () creates net\n"); - log(" names like 'mysignal(42)'. the default is '[]'.\n"); + log(" names like 'mysignal(42)'. the 3rd character is the range seperation\n"); + log(" character when creating multi-bit wires. the default is '[]:'.\n"); log("\n"); log(" -ports\n"); log(" also split module ports. per default only internal signals are split.\n"); log("\n"); + log(" -driver\n"); + log(" don't blindly split nets in individual bits. instead look at the driver\n"); + log(" and split nets so that no driver drives only part of a net.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { bool flag_ports = false; - std::string format = "[]"; + bool flag_driver = false; + std::string format = "[]:"; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -73,6 +111,10 @@ struct SplitnetsPass : public Pass { flag_ports = true; continue; } + if (args[argidx] == "-driver") { + flag_driver = true; + continue; + } break; } extra_args(args, argidx, design); @@ -85,30 +127,55 @@ struct SplitnetsPass : public Pass { SplitnetsWorker worker; - for (auto &w : module->wires) { - RTLIL::Wire *wire = w.second; - if (wire->width > 1 && (wire->port_id == 0 || flag_ports)) - worker.splitmap[wire] = std::vector(); - } + if (flag_driver) + { + CellTypes ct(design); - for (auto &it : worker.splitmap) - for (int i = 0; i < it.first->width; i++) { - RTLIL::Wire *wire = new RTLIL::Wire; - wire->port_id = it.first->port_id; - wire->port_input = it.first->port_input; - wire->port_output = it.first->port_output; - wire->name = it.first->name; - if (format.size() > 0) - wire->name += format.substr(0, 1); - wire->name += stringf("%d", i); - if (format.size() > 0) - wire->name += format.substr(1); - while (module->count_id(wire->name) > 0) - wire->name = wire->name + "_"; - module->add(wire); - it.second.push_back(wire); + std::map> split_wires_at; + + for (auto &c : module->cells) + for (auto &p : c.second->connections) + { + if (!ct.cell_known(c.second->type)) + continue; + if (!ct.cell_output(c.second->type, p.first)) + continue; + + RTLIL::SigSpec sig = p.second.optimized(); + for (auto &chunk : sig.chunks) { + if (chunk.wire == NULL) + continue; + if (chunk.wire->port_id == 0 || flag_ports) { + if (chunk.offset != 0) + split_wires_at[chunk.wire].insert(chunk.offset); + if (chunk.offset + chunk.width < chunk.wire->width) + split_wires_at[chunk.wire].insert(chunk.offset + chunk.width); + } + } } + for (auto &it : split_wires_at) { + int cursor = 0; + for (int next_cursor : it.second) { + worker.append_wire(module, it.first, cursor, next_cursor - cursor, format); + cursor = next_cursor; + } + worker.append_wire(module, it.first, cursor, it.first->width - cursor, format); + } + } + else + { + for (auto &w : module->wires) { + RTLIL::Wire *wire = w.second; + if (wire->width > 1 && (wire->port_id == 0 || flag_ports)) + worker.splitmap[wire] = std::vector(); + } + + for (auto &it : worker.splitmap) + for (int i = 0; i < it.first->width; i++) + worker.append_wire(module, it.first, i, 1, format); + } + module->rewrite_sigspecs(worker); for (auto &it : worker.splitmap) {