From d03780c3f463bb8ac2c5d300ba7a591f1bc90a8f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 5 Mar 2019 17:55:29 -0800 Subject: Fix spelling in pmgen/README.md --- passes/pmgen/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index a1007dc62..223b43059 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -16,7 +16,7 @@ API of Generated Matcher ======================== When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing -a class `foobar_pm`. That class is instanciated with an RTLIL module and a +a class `foobar_pm`. That class is instantiated with an RTLIL module and a list of cells from that module: foobar_pm pm(module, module->selected_cells()); @@ -142,7 +142,7 @@ The `select` lines are evaluated once for each cell when the matcher is initialized. A `match` block will only consider cells for which all `select` expressions evaluated to `true`. Note that the state variable corresponding to the match (in the example `mul`) is the only state variable that may be used -`select` lines. +in `select` lines. Index lines are using the `index expr1 === expr2` syntax. `expr1` is evaluated during matcher initialization and the same restrictions apply as for -- cgit v1.2.3 From 399ab16315468df95fc8a180d384d2ce8eed8049 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 9 Mar 2019 11:52:00 -0800 Subject: Add $dffsr support to async2sync Signed-off-by: Clifford Wolf --- passes/sat/async2sync.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index c92db7118..d045d0dcb 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -39,7 +39,7 @@ struct Async2syncPass : public Pass { log("reset value in the next cycle regardless of the data-in value at the time of\n"); log("the clock edge.\n"); log("\n"); - log("Currently only $adff cells are supported by this pass.\n"); + log("Currently only $adff and $dffsr cells are supported by this pass.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -84,7 +84,7 @@ struct Async2syncPass : public Pass { bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool(); Const arst_val = cell->parameters["\\ARST_VALUE"]; - SigSpec sig_clk = cell->getPort("\\CLK"); + // SigSpec sig_clk = cell->getPort("\\CLK"); SigSpec sig_arst = cell->getPort("\\ARST"); SigSpec sig_d = cell->getPort("\\D"); SigSpec sig_q = cell->getPort("\\Q"); @@ -120,6 +120,55 @@ struct Async2syncPass : public Pass { cell->type = "$dff"; continue; } + + if (cell->type.in("$dffsr")) + { + // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool(); + bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool(); + bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool(); + + // SigSpec sig_clk = cell->getPort("\\CLK"); + SigSpec sig_set = cell->getPort("\\SET"); + SigSpec sig_clr = cell->getPort("\\CLR"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (!set_pol) + sig_set = module->Not(NEW_ID, sig_set); + + if (clr_pol) + sig_clr = module->Not(NEW_ID, sig_clr); + + SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, new_d); + + tmp = module->Or(NEW_ID, new_q, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, sig_q); + + cell->setPort("\\D", new_d); + cell->setPort("\\Q", new_q); + cell->unsetPort("\\SET"); + cell->unsetPort("\\CLR"); + cell->unsetParam("\\SET_POLARITY"); + cell->unsetParam("\\CLR_POLARITY"); + cell->type = "$dff"; + continue; + } } for (auto wire : module->wires()) -- cgit v1.2.3 From f806b95ed6a2f2c1a0e5c8884676fd384e510143 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 20:35:15 +0100 Subject: Improve handling of and-with-1 and or-with-0 in opt_expr, fixes #327 Signed-off-by: Clifford Wolf --- passes/opt/opt_expr.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'passes') diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 26a3ca7bc..a05db2a4f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -155,6 +155,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ new_b.append_bit(it.first.second); } + if (cell->type.in("$and", "$or") && i == GRP_CONST_A) { + log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); + module->connect(new_y, new_b); + module->connect(new_conn); + continue; + } + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); c->setPort("\\A", new_a); -- cgit v1.2.3 From ea8ee2414053101bae26cfc2a537d42daf57f5e0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 12 Mar 2019 17:01:59 +0100 Subject: Add basic "mutate -list N" framework Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/mutate.cc | 229 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 passes/sat/mutate.cc (limited to 'passes') diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 6cb1ea644..e91df1eb0 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -9,4 +9,5 @@ OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o +OBJS += passes/sat/mutate.o diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc new file mode 100644 index 000000000..5fd89b7d0 --- /dev/null +++ b/passes/sat/mutate.cc @@ -0,0 +1,229 @@ +/* + * 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" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct mutate_t { + std::string mode, src; + IdString modname, cellname, celltype, cellport; + SigBit outsigbit; + int portbit = -1; +}; + +struct mutate_opts_t { + std::string mode; + IdString module, cell, port; + int bit = -1; +}; + +void database_add(std::vector &database, const mutate_opts_t &opts, const mutate_t &entry) +{ + if (!opts.module.empty() && opts.module != entry.modname) + return; + + if (!opts.cell.empty() && opts.cell != entry.cellname) + return; + + if (!opts.port.empty() && opts.port != entry.cellport) + return; + + if (opts.bit >= 0 && opts.bit != entry.portbit) + return; + + database.push_back(entry); +} + +void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) +{ +} + +struct MutatePass : public Pass { + MutatePass() : Pass("mutate", "generate or apply design mutations") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" mutate -list N [options] [selection]\n"); + log("\n"); + log("Create a list of N mutations using an even sampling.\n"); + log("\n"); + log(" -o filename\n"); + log(" Write list to this file instead of console output\n"); + log("\n"); + log("\n"); + log(" mutate -mode MODE [options]\n"); + log("\n"); + log("Apply the given mutation.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + mutate_opts_t opts; + string filename; + int N = -1; + + log_header(design, "Executing MUTATE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-list" && argidx+1 < args.size()) { + N = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-o" && argidx+1 < args.size()) { + filename = args[++argidx]; + continue; + } + if (args[argidx] == "-mode" && argidx+1 < args.size()) { + opts.mode = args[++argidx]; + continue; + } + if (args[argidx] == "-module" && argidx+1 < args.size()) { + opts.module = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-cell" && argidx+1 < args.size()) { + opts.cell = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-port" && argidx+1 < args.size()) { + opts.port = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-bit" && argidx+1 < args.size()) { + opts.bit = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (N >= 0) + { + std::vector database; + + for (auto module : design->selected_modules()) + { + if (!opts.module.empty() && module->name != opts.module) + continue; + + SigMap sigmap(module); + + for (auto wire : module->selected_wires()) + { + for (SigBit bit : SigSpec(wire)) + { + SigBit sigbit = sigmap(bit); + + if (bit.wire == nullptr || sigbit.wire == nullptr) + continue; + + if (!bit.wire->port_id != !sigbit.wire->port_id) { + if (bit.wire->port_id) + sigmap.add(bit); + continue; + } + + if (!bit.wire->name[0] != !sigbit.wire->name[0]) { + if (bit.wire->name[0] == '\\') + sigmap.add(bit); + continue; + } + } + } + + for (auto cell : module->selected_cells()) + { + if (!opts.cell.empty() && cell->name != opts.cell) + continue; + + for (auto &conn : cell->connections()) + { + for (int i = 0; i < GetSize(conn.second); i++) { + mutate_t entry; + entry.mode = "inv"; + entry.src = cell->get_src_attribute(); + entry.modname = module->name; + entry.cellname = cell->name; + entry.celltype = cell->type; + entry.cellport = conn.first; + entry.portbit = i; + + if (cell->output(conn.first)) { + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\') + entry.outsigbit = bit; + } + + database_add(database, opts, entry); + } + } + } + } + + log("Raw database size: %d\n", GetSize(database)); + if (N != 0) { + database_reduce(database, opts, N); + log("Reduced database size: %d\n", GetSize(database)); + } + + std::ofstream fout; + + if (!filename.empty()) { + fout.open(filename, std::ios::out | std::ios::trunc); + if (!fout.is_open()) + log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); + } + + for (auto &entry : database) { + string str = stringf("mutate -mode %s", entry.mode.c_str()); + if (!entry.modname.empty()) + str += stringf(" -module %s", log_id(entry.modname)); + if (!entry.cellname.empty()) + str += stringf(" -cell %s", log_id(entry.cellname)); + if (!entry.cellport.empty()) + str += stringf(" -port %s", log_id(entry.cellport)); + if (entry.portbit >= 0) + str += stringf(" -bit %d", entry.portbit); + if (entry.outsigbit.wire || !entry.src.empty()) { + str += " #"; + if (!entry.src.empty()) + str += stringf(" %s", entry.src.c_str()); + if (entry.outsigbit.wire) + str += stringf(" %s", log_signal(entry.outsigbit)); + } + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } + + return; + } + + log_cmd_error("Invalid mode: %s\n", opts.mode.c_str()); + } +} MutatePass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 8e6b69d7bba21dd3fa01064ee698dcd409b5dcc8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 16:09:47 +0100 Subject: Add "mutate -mode inv", various other mutate improvements Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 312 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 213 insertions(+), 99 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 5fd89b7d0..04aebd897 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -34,10 +34,16 @@ struct mutate_opts_t { std::string mode; IdString module, cell, port; int bit = -1; + + IdString ctrl_name; + int ctrl_width, ctrl_value; }; void database_add(std::vector &database, const mutate_opts_t &opts, const mutate_t &entry) { + if (!opts.mode.empty() && opts.mode != entry.mode) + return; + if (!opts.module.empty() && opts.module != entry.modname) return; @@ -57,6 +63,183 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, { } +void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) +{ + std::vector database; + + for (auto module : design->selected_modules()) + { + if (!opts.module.empty() && module->name != opts.module) + continue; + + SigMap sigmap(module); + + for (auto wire : module->selected_wires()) + { + for (SigBit bit : SigSpec(wire)) + { + SigBit sigbit = sigmap(bit); + + if (bit.wire == nullptr || sigbit.wire == nullptr) + continue; + + if (!bit.wire->port_id != !sigbit.wire->port_id) { + if (bit.wire->port_id) + sigmap.add(bit); + continue; + } + + if (!bit.wire->name[0] != !sigbit.wire->name[0]) { + if (bit.wire->name[0] == '\\') + sigmap.add(bit); + continue; + } + } + } + + for (auto cell : module->selected_cells()) + { + if (!opts.cell.empty() && cell->name != opts.cell) + continue; + + for (auto &conn : cell->connections()) + { + for (int i = 0; i < GetSize(conn.second); i++) { + mutate_t entry; + entry.mode = "inv"; + entry.src = cell->get_src_attribute(); + entry.modname = module->name; + entry.cellname = cell->name; + entry.celltype = cell->type; + entry.cellport = conn.first; + entry.portbit = i; + + if (cell->output(conn.first)) { + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\') + entry.outsigbit = bit; + } + + database_add(database, opts, entry); + } + } + } + } + + log("Raw database size: %d\n", GetSize(database)); + if (N != 0) { + database_reduce(database, opts, N); + log("Reduced database size: %d\n", GetSize(database)); + } + + std::ofstream fout; + + if (!filename.empty()) { + fout.open(filename, std::ios::out | std::ios::trunc); + if (!fout.is_open()) + log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); + } + + for (auto &entry : database) { + string str = stringf("mutate -mode %s", entry.mode.c_str()); + if (!entry.modname.empty()) + str += stringf(" -module %s", log_id(entry.modname)); + if (!entry.cellname.empty()) + str += stringf(" -cell %s", log_id(entry.cellname)); + if (!entry.cellport.empty()) + str += stringf(" -port %s", log_id(entry.cellport)); + if (entry.portbit >= 0) + str += stringf(" -bit %d", entry.portbit); + if (entry.outsigbit.wire || !entry.src.empty()) { + str += " #"; + if (!entry.src.empty()) + str += stringf(" %s", entry.src.c_str()); + if (entry.outsigbit.wire) + str += stringf(" %s", log_signal(entry.outsigbit)); + } + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } +} + +SigSpec mutate_ctrl_sig(Module *module, IdString name, int width) +{ + Wire *ctrl_wire = module->wire(name); + + if (ctrl_wire == nullptr) + { + log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module)); + + ctrl_wire = module->addWire(name, width); + ctrl_wire->port_input = true; + module->fixup_ports(); + + for (auto mod : module->design->modules()) + for (auto cell : mod->cells()) + { + if (cell->type != module->name) + continue; + + SigSpec ctrl = mutate_ctrl_sig(mod, name, width); + + log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod)); + cell->setPort(name, ctrl); + } + } + + log_assert(GetSize(ctrl_wire) == width); + return ctrl_wire; +} + +SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts) +{ + if (opts.ctrl_name.empty()) + return State::S1; + + SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width); + return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig))); +} + +SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig) +{ + SigBit ctrl_bit = mutate_ctrl(module, opts); + if (ctrl_bit == State::S0) + return unchanged_sig; + if (ctrl_bit == State::S1) + return changed_sig; + return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit); +} + +void mutate_inv(Design *design, const mutate_opts_t &opts) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.bit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.bit); + SigBit outbit = module->Not(NEW_ID, bit); + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.bit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = module->Not(NEW_ID, inbit); + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.bit] = bit; + cell->setPort(opts.port, s); +} + struct MutatePass : public Pass { MutatePass() : Pass("mutate", "generate or apply design mutations") { } void help() YS_OVERRIDE @@ -70,11 +253,29 @@ struct MutatePass : public Pass { log(" -o filename\n"); log(" Write list to this file instead of console output\n"); log("\n"); + log(" -mode name\n"); + log(" -module name\n"); + log(" -cell name\n"); + log(" -port name\n"); + log(" -bit int\n"); + log(" Filter list of mutation candidates to those matching\n"); + log(" the given parameters.\n"); + log("\n"); log("\n"); log(" mutate -mode MODE [options]\n"); log("\n"); log("Apply the given mutation.\n"); log("\n"); + log(" -ctrl name width value\n"); + log(" Add a control signal with the given name and width. The mutation is\n"); + log(" activated if the control signal equals the given value.\n"); + log("\n"); + log(" -module name\n"); + log(" -cell name\n"); + log(" -port name\n"); + log(" -bit int\n"); + log(" Mutation parameters, as generated by 'mutate -list N'.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -99,6 +300,12 @@ struct MutatePass : public Pass { opts.mode = args[++argidx]; continue; } + if (args[argidx] == "-ctrl" && argidx+3 < args.size()) { + opts.ctrl_name = RTLIL::escape_id(args[++argidx]); + opts.ctrl_width = atoi(args[++argidx].c_str()); + opts.ctrl_value = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-module" && argidx+1 < args.size()) { opts.module = RTLIL::escape_id(args[++argidx]); continue; @@ -119,106 +326,13 @@ struct MutatePass : public Pass { } extra_args(args, argidx, design); - if (N >= 0) - { - std::vector database; - - for (auto module : design->selected_modules()) - { - if (!opts.module.empty() && module->name != opts.module) - continue; - - SigMap sigmap(module); - - for (auto wire : module->selected_wires()) - { - for (SigBit bit : SigSpec(wire)) - { - SigBit sigbit = sigmap(bit); - - if (bit.wire == nullptr || sigbit.wire == nullptr) - continue; - - if (!bit.wire->port_id != !sigbit.wire->port_id) { - if (bit.wire->port_id) - sigmap.add(bit); - continue; - } - - if (!bit.wire->name[0] != !sigbit.wire->name[0]) { - if (bit.wire->name[0] == '\\') - sigmap.add(bit); - continue; - } - } - } - - for (auto cell : module->selected_cells()) - { - if (!opts.cell.empty() && cell->name != opts.cell) - continue; - - for (auto &conn : cell->connections()) - { - for (int i = 0; i < GetSize(conn.second); i++) { - mutate_t entry; - entry.mode = "inv"; - entry.src = cell->get_src_attribute(); - entry.modname = module->name; - entry.cellname = cell->name; - entry.celltype = cell->type; - entry.cellport = conn.first; - entry.portbit = i; - - if (cell->output(conn.first)) { - SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') - entry.outsigbit = bit; - } - - database_add(database, opts, entry); - } - } - } - } - - log("Raw database size: %d\n", GetSize(database)); - if (N != 0) { - database_reduce(database, opts, N); - log("Reduced database size: %d\n", GetSize(database)); - } - - std::ofstream fout; - - if (!filename.empty()) { - fout.open(filename, std::ios::out | std::ios::trunc); - if (!fout.is_open()) - log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); - } - - for (auto &entry : database) { - string str = stringf("mutate -mode %s", entry.mode.c_str()); - if (!entry.modname.empty()) - str += stringf(" -module %s", log_id(entry.modname)); - if (!entry.cellname.empty()) - str += stringf(" -cell %s", log_id(entry.cellname)); - if (!entry.cellport.empty()) - str += stringf(" -port %s", log_id(entry.cellport)); - if (entry.portbit >= 0) - str += stringf(" -bit %d", entry.portbit); - if (entry.outsigbit.wire || !entry.src.empty()) { - str += " #"; - if (!entry.src.empty()) - str += stringf(" %s", entry.src.c_str()); - if (entry.outsigbit.wire) - str += stringf(" %s", log_signal(entry.outsigbit)); - } - if (filename.empty()) - log("%s\n", str.c_str()); - else - fout << str << std::endl; - } + if (N >= 0) { + mutate_list(design, opts, filename, N); + return; + } + if (opts.mode == "inv") { + mutate_inv(design, opts); return; } -- cgit v1.2.3 From 6ad5d036c58766b2bd0a705c7adfcbf9af4a7d16 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 13 Mar 2019 17:36:37 +0100 Subject: Add "mutate" command DB reduce functionality Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 193 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 181 insertions(+), 12 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 04aebd897..3ecb955f0 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -25,16 +25,19 @@ PRIVATE_NAMESPACE_BEGIN struct mutate_t { std::string mode, src; - IdString modname, cellname, celltype, cellport; + Module *module; + Cell *cell; + IdString cellport; SigBit outsigbit; int portbit = -1; + bool used = false; }; struct mutate_opts_t { + int seed = 0; std::string mode; IdString module, cell, port; int bit = -1; - IdString ctrl_name; int ctrl_width, ctrl_value; }; @@ -44,10 +47,10 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co if (!opts.mode.empty() && opts.mode != entry.mode) return; - if (!opts.module.empty() && opts.module != entry.modname) + if (!opts.module.empty() && opts.module != entry.module->name) return; - if (!opts.cell.empty() && opts.cell != entry.cellname) + if (!opts.cell.empty() && opts.cell != entry.cell->name) return; if (!opts.port.empty() && opts.port != entry.cellport) @@ -59,8 +62,159 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co database.push_back(entry); } +struct xs128_t +{ + uint32_t x = 123456789; + uint32_t y = 0, z = 0, w = 0; + + xs128_t(int seed = 0) : w(seed) { + next(); + next(); + next(); + } + + void next() { + uint32_t t = x ^ (x << 11); + x = y, y = z, z = w; + w ^= (w >> 19) ^ t ^ (t >> 8); + } + + int operator()() { + next(); + return w & 0x3fffffff; + } + + int operator()(int n) { + if (n < 2) + return 0; + while (1) { + int k = (*this)(), p = k % n; + if ((k - p + n) <= 0x40000000) + return p; + } + } +}; + +struct mutate_leaf_queue_t +{ + pool db; + + mutate_t *pick(xs128_t &rng) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = *it; + db.erase(it); + if (m->used == false) { + m->used = true; + return m; + } + } + return nullptr; + } + + void add(mutate_t *m) { + db.insert(m); + } +}; + +template +struct mutate_inner_queue_t +{ + dict db; + + mutate_t *pick(xs128_t &rng) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = it->second.pick(rng); + if (m != nullptr) + return m; + db.erase(it); + } + return nullptr; + } + + template + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) { + if (N >= GetSize(database)) + return; + + mutate_inner_queue_t primary_queue_wire; + mutate_inner_queue_t primary_queue_bit; + mutate_inner_queue_t primary_queue_cell; + mutate_inner_queue_t primary_queue_src; + + mutate_inner_queue_t> primary_queue_module_wire; + mutate_inner_queue_t> primary_queue_module_bit; + mutate_inner_queue_t> primary_queue_module_cell; + mutate_inner_queue_t> primary_queue_module_src; + + for (auto &m : database) + { + if (m.outsigbit.wire) { + primary_queue_wire.add(&m, m.outsigbit.wire); + primary_queue_bit.add(&m, m.outsigbit); + primary_queue_module_wire.add(&m, m.module, m.outsigbit.wire); + primary_queue_module_bit.add(&m, m.module, m.outsigbit); + } + + primary_queue_cell.add(&m, m.cell); + primary_queue_module_cell.add(&m, m.module, m.cell); + + if (!m.src.empty()) { + primary_queue_src.add(&m, m.src); + primary_queue_module_src.add(&m, m.module, m.src); + } + } + + int weight_pq_w = 100; + int weight_pq_b = 100; + int weight_pq_c = 100; + int weight_pq_s = 100; + + int weight_pq_mw = 100; + int weight_pq_mb = 100; + int weight_pq_mc = 100; + int weight_pq_ms = 100; + + int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; + total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; + + std::vector new_database; + xs128_t rng(opts.seed); + + while (GetSize(new_database) < N) + { + int k = rng(total_weight); + +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ + } + + X(weight_pq_w, primary_queue_wire) + X(weight_pq_b, primary_queue_bit) + X(weight_pq_c, primary_queue_cell) + X(weight_pq_s, primary_queue_src) + + X(weight_pq_mw, primary_queue_module_wire) + X(weight_pq_mb, primary_queue_module_bit) + X(weight_pq_mc, primary_queue_module_cell) + X(weight_pq_ms, primary_queue_module_src) + } + + std::swap(new_database, database); } void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) @@ -108,9 +262,8 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena mutate_t entry; entry.mode = "inv"; entry.src = cell->get_src_attribute(); - entry.modname = module->name; - entry.cellname = cell->name; - entry.celltype = cell->type; + entry.module = module; + entry.cell = cell; entry.cellport = conn.first; entry.portbit = i; @@ -140,12 +293,17 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); } + int ctrl_value = opts.ctrl_value; + for (auto &entry : database) { - string str = stringf("mutate -mode %s", entry.mode.c_str()); - if (!entry.modname.empty()) - str += stringf(" -module %s", log_id(entry.modname)); - if (!entry.cellname.empty()) - str += stringf(" -cell %s", log_id(entry.cellname)); + string str = "mutate"; + if (!opts.ctrl_name.empty()) + str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++); + str += stringf(" -mode %s", entry.mode.c_str()); + if (entry.module) + str += stringf(" -module %s", log_id(entry.module)); + if (entry.cell) + str += stringf(" -cell %s", log_id(entry.cell)); if (!entry.cellport.empty()) str += stringf(" -port %s", log_id(entry.cellport)); if (entry.portbit >= 0) @@ -253,6 +411,13 @@ struct MutatePass : public Pass { log(" -o filename\n"); log(" Write list to this file instead of console output\n"); log("\n"); + log(" -seed N\n"); + log(" RNG seed for selecting mutations\n"); + log("\n"); + log(" -ctrl name width value\n"); + log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n"); + log(" simply count up from there.\n"); + log("\n"); log(" -mode name\n"); log(" -module name\n"); log(" -cell name\n"); @@ -296,6 +461,10 @@ struct MutatePass : public Pass { filename = args[++argidx]; continue; } + if (args[argidx] == "-seed" && argidx+1 < args.size()) { + opts.seed = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-mode" && argidx+1 < args.size()) { opts.mode = args[++argidx]; continue; -- cgit v1.2.3 From 1b4fdbb0d881040220cdf1591f415cd2176481ad Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 19:52:02 +0100 Subject: Add more mutation types, improve mutation src cover Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 360 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 268 insertions(+), 92 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 3ecb955f0..eac00948a 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -24,20 +24,24 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct mutate_t { - std::string mode, src; - Module *module; - Cell *cell; - IdString cellport; - SigBit outsigbit; + string mode; + pool src; + IdString module, cell; + IdString port, wire; int portbit = -1; + int ctrlbit = -1; + int wirebit = -1; bool used = false; }; struct mutate_opts_t { int seed = 0; std::string mode; - IdString module, cell, port; - int bit = -1; + pool src; + IdString module, cell, port, wire; + int portbit = -1; + int ctrlbit = -1; + int wirebit = -1; IdString ctrl_name; int ctrl_width, ctrl_value; }; @@ -47,16 +51,35 @@ void database_add(std::vector &database, const mutate_opts_t &opts, co if (!opts.mode.empty() && opts.mode != entry.mode) return; - if (!opts.module.empty() && opts.module != entry.module->name) + if (!opts.src.empty()) { + bool found_match = false; + for (auto &s : opts.src) { + if (entry.src.count(s)) + found_match = true; + } + if (!found_match) + return; + } + + if (!opts.module.empty() && opts.module != entry.module) + return; + + if (!opts.cell.empty() && opts.cell != entry.cell) + return; + + if (!opts.port.empty() && opts.port != entry.port) + return; + + if (opts.portbit >= 0 && opts.portbit != entry.portbit) return; - if (!opts.cell.empty() && opts.cell != entry.cell->name) + if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit) return; - if (!opts.port.empty() && opts.port != entry.cellport) + if (!opts.wire.empty() && opts.wire != entry.wire) return; - if (opts.bit >= 0 && opts.bit != entry.portbit) + if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit) return; database.push_back(entry); @@ -99,18 +122,48 @@ struct mutate_leaf_queue_t { pool db; - mutate_t *pick(xs128_t &rng) { - while (!db.empty()) { - int i = rng(GetSize(db)); - auto it = db.element(i); - mutate_t *m = *it; - db.erase(it); - if (m->used == false) { - m->used = true; - return m; + mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *m = nullptr; + if (rng(3)) { + vector candidates; + int best_score = -1; + for (auto p : db) { + if (p->used || p->src.empty()) + continue; + int this_score = -1; + for (auto &s : p->src) { + if (this_score == -1 || this_score > coverdb.at(s)) + this_score = coverdb.at(s); + } + log_assert(this_score != -1); + if (best_score == -1 || this_score < best_score) { + candidates.clear(); + best_score = this_score; + } + if (best_score == this_score) + candidates.push_back(p); } + if (!candidates.empty()) + m = candidates[rng(GetSize(candidates))]; } - return nullptr; + if (m == nullptr) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *p = *it; + db.erase(it); + if (p->used == false) { + m = p; + break; + } + } + } + if (m != nullptr) { + m->used = true; + for (auto &s : m->src) + coverdb[s]++; + } + return m; } void add(mutate_t *m) { @@ -123,11 +176,11 @@ struct mutate_inner_queue_t { dict db; - mutate_t *pick(xs128_t &rng) { + mutate_t *pick(xs128_t &rng, dict &coverdb) { while (!db.empty()) { int i = rng(GetSize(db)); auto it = db.element(i); - mutate_t *m = it->second.pick(rng); + mutate_t *m = it->second.pick(rng, coverdb); if (m != nullptr) return m; db.erase(it); @@ -141,66 +194,67 @@ struct mutate_inner_queue_t } }; -void database_reduce(std::vector &database, const mutate_opts_t &opts, int N) +void database_reduce(std::vector &database, const mutate_opts_t &/* opts */, int N, xs128_t &rng) { + std::vector new_database; + dict coverdb; + + int weight_pq_w = 100; + int weight_pq_b = 100; + int weight_pq_c = 100; + int weight_pq_s = 100; + + int weight_pq_mw = 100; + int weight_pq_mb = 100; + int weight_pq_mc = 100; + int weight_pq_ms = 100; + + int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; + total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; + if (N >= GetSize(database)) return; - mutate_inner_queue_t primary_queue_wire; - mutate_inner_queue_t primary_queue_bit; - mutate_inner_queue_t primary_queue_cell; + mutate_inner_queue_t primary_queue_wire; + mutate_inner_queue_t, mutate_leaf_queue_t> primary_queue_bit; + mutate_inner_queue_t primary_queue_cell; mutate_inner_queue_t primary_queue_src; - mutate_inner_queue_t> primary_queue_module_wire; - mutate_inner_queue_t> primary_queue_module_bit; - mutate_inner_queue_t> primary_queue_module_cell; - mutate_inner_queue_t> primary_queue_module_src; + mutate_inner_queue_t> primary_queue_module_wire; + mutate_inner_queue_t, mutate_leaf_queue_t>> primary_queue_module_bit; + mutate_inner_queue_t> primary_queue_module_cell; + mutate_inner_queue_t> primary_queue_module_src; for (auto &m : database) { - if (m.outsigbit.wire) { - primary_queue_wire.add(&m, m.outsigbit.wire); - primary_queue_bit.add(&m, m.outsigbit); - primary_queue_module_wire.add(&m, m.module, m.outsigbit.wire); - primary_queue_module_bit.add(&m, m.module, m.outsigbit); + if (!m.wire.empty()) { + primary_queue_wire.add(&m, m.wire); + primary_queue_bit.add(&m, pair(m.wire, m.wirebit)); + primary_queue_module_wire.add(&m, m.module, m.wire); + primary_queue_module_bit.add(&m, m.module, pair(m.wire, m.wirebit)); } primary_queue_cell.add(&m, m.cell); primary_queue_module_cell.add(&m, m.module, m.cell); - if (!m.src.empty()) { - primary_queue_src.add(&m, m.src); - primary_queue_module_src.add(&m, m.module, m.src); + for (auto &s : m.src) { + coverdb[s] = 0; + primary_queue_src.add(&m, s); + primary_queue_module_src.add(&m, m.module, s); } } - int weight_pq_w = 100; - int weight_pq_b = 100; - int weight_pq_c = 100; - int weight_pq_s = 100; - - int weight_pq_mw = 100; - int weight_pq_mb = 100; - int weight_pq_mc = 100; - int weight_pq_ms = 100; - - int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; - total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; - - std::vector new_database; - xs128_t rng(opts.seed); - while (GetSize(new_database) < N) { int k = rng(total_weight); -#define X(__wght, __queue) \ - k -= __wght; \ - if (k < 0) { \ - mutate_t *m = __queue.pick(rng); \ - if (m != nullptr) \ - new_database.push_back(*m); \ - continue; \ +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng, coverdb); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ } X(weight_pq_w, primary_queue_wire) @@ -215,11 +269,19 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, } std::swap(new_database, database); + + int covered_cnt = 0; + for (auto &it : coverdb) + if (it.second) + covered_cnt++; + + log("Covered %d/%d src attributes (%.2f%%).\n", covered_cnt, GetSize(coverdb), 100.0 * covered_cnt / GetSize(coverdb)); } void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) { std::vector database; + xs128_t rng(opts.seed); for (auto module : design->selected_modules()) { @@ -260,20 +322,40 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena { for (int i = 0; i < GetSize(conn.second); i++) { mutate_t entry; - entry.mode = "inv"; - entry.src = cell->get_src_attribute(); - entry.module = module; - entry.cell = cell; - entry.cellport = conn.first; + entry.module = module->name; + entry.cell = cell->name; + entry.port = conn.first; entry.portbit = i; - if (cell->output(conn.first)) { - SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') - entry.outsigbit = bit; + for (auto &s : cell->get_strpool_attribute("\\src")) + entry.src.insert(s); + + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\') { + for (auto &s : bit.wire->get_strpool_attribute("\\src")) + entry.src.insert(s); + entry.wire = bit.wire->name; + entry.wirebit = bit.offset; } + entry.mode = "inv"; + database_add(database, opts, entry); + + entry.mode = "const0"; database_add(database, opts, entry); + + entry.mode = "const1"; + database_add(database, opts, entry); + + entry.mode = "cnot0"; + entry.ctrlbit = rng(GetSize(conn.second)); + if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire) + database_add(database, opts, entry); + + entry.mode = "cnot1"; + entry.ctrlbit = rng(GetSize(conn.second)); + if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire) + database_add(database, opts, entry); } } } @@ -281,7 +363,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log("Raw database size: %d\n", GetSize(database)); if (N != 0) { - database_reduce(database, opts, N); + database_reduce(database, opts, N, rng); log("Reduced database size: %d\n", GetSize(database)); } @@ -300,21 +382,22 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena if (!opts.ctrl_name.empty()) str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++); str += stringf(" -mode %s", entry.mode.c_str()); - if (entry.module) + if (!entry.module.empty()) str += stringf(" -module %s", log_id(entry.module)); - if (entry.cell) + if (!entry.cell.empty()) str += stringf(" -cell %s", log_id(entry.cell)); - if (!entry.cellport.empty()) - str += stringf(" -port %s", log_id(entry.cellport)); + if (!entry.port.empty()) + str += stringf(" -port %s", log_id(entry.port)); if (entry.portbit >= 0) - str += stringf(" -bit %d", entry.portbit); - if (entry.outsigbit.wire || !entry.src.empty()) { - str += " #"; - if (!entry.src.empty()) - str += stringf(" %s", entry.src.c_str()); - if (entry.outsigbit.wire) - str += stringf(" %s", log_signal(entry.outsigbit)); - } + str += stringf(" -portbit %d", entry.portbit); + if (entry.ctrlbit >= 0) + str += stringf(" -ctrlbit %d", entry.ctrlbit); + if (!entry.wire.empty()) + str += stringf(" -wire %s", log_id(entry.wire)); + if (entry.wirebit >= 0) + str += stringf(" -wirebit %d", entry.wirebit); + for (auto &s : entry.src) + str += stringf(" -src %s", s.c_str()); if (filename.empty()) log("%s\n", str.c_str()); else @@ -375,18 +458,18 @@ void mutate_inv(Design *design, const mutate_opts_t &opts) Module *module = design->module(opts.module); Cell *cell = module->cell(opts.cell); - SigBit bit = cell->getPort(opts.port)[opts.bit]; + SigBit bit = cell->getPort(opts.port)[opts.portbit]; SigBit inbit, outbit; if (cell->input(opts.port)) { - log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.bit); + log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit); SigBit outbit = module->Not(NEW_ID, bit); bit = mutate_ctrl_mux(module, opts, bit, outbit); } else { - log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.bit); + log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit); SigBit inbit = module->addWire(NEW_ID); SigBit outbit = module->Not(NEW_ID, inbit); module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); @@ -394,7 +477,64 @@ void mutate_inv(Design *design, const mutate_opts_t &opts) } SigSpec s = cell->getPort(opts.port); - s[opts.bit] = bit; + s[opts.portbit] = bit; + cell->setPort(opts.port, s); +} + +void mutate_const(Design *design, const mutate_opts_t &opts, bool one) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.portbit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit outbit = one ? State::S1 : State::S0; + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = one ? State::S1 : State::S0; + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.portbit] = bit; + cell->setPort(opts.port, s); +} + +void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.portbit]; + SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit); + SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl); + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl); + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.portbit] = bit; cell->setPort(opts.port, s); } @@ -422,7 +562,11 @@ struct MutatePass : public Pass { log(" -module name\n"); log(" -cell name\n"); log(" -port name\n"); - log(" -bit int\n"); + log(" -portbit int\n"); + log(" -ctrlbit int\n"); + log(" -wire name\n"); + log(" -wirebit int\n"); + log(" -src string\n"); log(" Filter list of mutation candidates to those matching\n"); log(" the given parameters.\n"); log("\n"); @@ -438,9 +582,15 @@ struct MutatePass : public Pass { log(" -module name\n"); log(" -cell name\n"); log(" -port name\n"); - log(" -bit int\n"); + log(" -portbit int\n"); + log(" -ctrlbit int\n"); log(" Mutation parameters, as generated by 'mutate -list N'.\n"); log("\n"); + log(" -wire name\n"); + log(" -wirebit int\n"); + log(" -src string\n"); + log(" Ignored. (They are generated by -list for documentation purposes.)\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -487,8 +637,24 @@ struct MutatePass : public Pass { opts.port = RTLIL::escape_id(args[++argidx]); continue; } - if (args[argidx] == "-bit" && argidx+1 < args.size()) { - opts.bit = atoi(args[++argidx].c_str()); + if (args[argidx] == "-portbit" && argidx+1 < args.size()) { + opts.portbit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) { + opts.ctrlbit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-wire" && argidx+1 < args.size()) { + opts.wire = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-wirebit" && argidx+1 < args.size()) { + opts.wirebit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-src" && argidx+1 < args.size()) { + opts.src.insert(args[++argidx]); continue; } break; @@ -505,6 +671,16 @@ struct MutatePass : public Pass { return; } + if (opts.mode == "const0" || opts.mode == "const1") { + mutate_const(design, opts, opts.mode == "const1"); + return; + } + + if (opts.mode == "cnot0" || opts.mode == "cnot1") { + mutate_cnot(design, opts, opts.mode == "cnot1"); + return; + } + log_cmd_error("Invalid mode: %s\n", opts.mode.c_str()); } } MutatePass; -- cgit v1.2.3 From 2a4263a75d0bbbc5b8f2de797b572d6f1d64818b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:01:01 +0100 Subject: Improve "mutate" wire coverage metric Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index eac00948a..243a1b48a 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -289,6 +289,21 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena continue; SigMap sigmap(module); + dict bit_user_cnt; + + for (auto wire : module->wires()) { + if (wire->name[0] == '\\' && wire->attributes.count("\\src")) + sigmap.add(wire); + } + + for (auto cell : module->cells()) { + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) + continue; + for (auto bit : sigmap(conn.second)) + bit_user_cnt[bit]++; + } + } for (auto wire : module->selected_wires()) { @@ -331,7 +346,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena entry.src.insert(s); SigBit bit = sigmap(conn.second[i]); - if (bit.wire && bit.wire->name[0] == '\\') { + if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) { for (auto &s : bit.wire->get_strpool_attribute("\\src")) entry.src.insert(s); entry.wire = bit.wire->name; -- cgit v1.2.3 From 4d304e3da77a571d1febfebca1409f522177af38 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:01:55 +0100 Subject: Add a strictly coverage-driven mutation selection strategy Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 243a1b48a..440e8b056 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -199,6 +199,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op std::vector new_database; dict coverdb; + int weight_cover = 500; + int weight_pq_w = 100; int weight_pq_b = 100; int weight_pq_c = 100; @@ -209,7 +211,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op int weight_pq_mc = 100; int weight_pq_ms = 100; - int total_weight = weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; + int total_weight = weight_cover + weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; if (N >= GetSize(database)) @@ -244,10 +246,76 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op } } + vector cover_candidates; + int best_cover_score = -1; + bool skip_cover = false; + while (GetSize(new_database) < N) { int k = rng(total_weight); + k -= weight_cover; + if (k < 0) { + while (!skip_cover) { + if (cover_candidates.empty()) { + best_cover_score = -1; + for (auto &m : database) { + if (m.used || m.src.empty()) + continue; + int this_score = -1; + for (auto &s : m.src) { + if (this_score == -1 || this_score > coverdb.at(s)) + this_score = coverdb.at(s); + } + log_assert(this_score != -1); + if (best_cover_score == -1 || this_score < best_cover_score) { + cover_candidates.clear(); + best_cover_score = this_score; + } + if (best_cover_score == this_score) + cover_candidates.push_back(&m); + } + if (best_cover_score == -1) { + skip_cover = true; + break; + } + } + + mutate_t *m = nullptr; + while (!cover_candidates.empty()) + { + int idx = rng(GetSize(cover_candidates)); + mutate_t *p = cover_candidates[idx]; + cover_candidates[idx] = cover_candidates.back(); + cover_candidates.pop_back(); + + if (p->used) + continue; + + int this_score = -1; + for (auto &s : p->src) { + if (this_score == -1 || this_score > coverdb.at(s)) + this_score = coverdb.at(s); + } + + if (this_score != best_cover_score) + continue; + + m = p; + break; + } + + if (m != nullptr) { + m->used = true; + for (auto &s : m->src) + coverdb[s]++; + new_database.push_back(*m); + break; + } + } + continue; + } + #define X(__wght, __queue) \ k -= __wght; \ if (k < 0) { \ @@ -266,6 +334,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op X(weight_pq_mb, primary_queue_module_bit) X(weight_pq_mc, primary_queue_module_cell) X(weight_pq_ms, primary_queue_module_src) +#undef X } std::swap(new_database, database); -- cgit v1.2.3 From 27a5d9c91e44dd04fa45e1e2aeff8c6d1cd50872 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Mar 2019 23:20:41 +0100 Subject: Add "mutate -cfg", improve pick_cover behavior Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 147 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 46 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 440e8b056..6b9eb3c04 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -42,8 +42,23 @@ struct mutate_opts_t { int portbit = -1; int ctrlbit = -1; int wirebit = -1; + IdString ctrl_name; - int ctrl_width, ctrl_value; + int ctrl_width = -1, ctrl_value = -1; + + int pick_cover_prcnt = 50; + + int weight_cover = 500; + + int weight_pq_w = 100; + int weight_pq_b = 100; + int weight_pq_c = 100; + int weight_pq_s = 100; + + int weight_pq_mw = 100; + int weight_pq_mb = 100; + int weight_pq_mc = 100; + int weight_pq_ms = 100; }; void database_add(std::vector &database, const mutate_opts_t &opts, const mutate_t &entry) @@ -122,25 +137,19 @@ struct mutate_leaf_queue_t { pool db; - mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { mutate_t *m = nullptr; - if (rng(3)) { + if (rng(100) < opts.pick_cover_prcnt) { vector candidates; - int best_score = -1; for (auto p : db) { if (p->used || p->src.empty()) continue; - int this_score = -1; + bool is_covered = false; for (auto &s : p->src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); - } - log_assert(this_score != -1); - if (best_score == -1 || this_score < best_score) { - candidates.clear(); - best_score = this_score; + if (coverdb.at(s)) + is_covered = true; } - if (best_score == this_score) + if (!is_covered) candidates.push_back(p); } if (!candidates.empty()) @@ -176,11 +185,11 @@ struct mutate_inner_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb) { + mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { while (!db.empty()) { int i = rng(GetSize(db)); auto it = db.element(i); - mutate_t *m = it->second.pick(rng, coverdb); + mutate_t *m = it->second.pick(rng, coverdb, opts); if (m != nullptr) return m; db.erase(it); @@ -194,25 +203,13 @@ struct mutate_inner_queue_t } }; -void database_reduce(std::vector &database, const mutate_opts_t &/* opts */, int N, xs128_t &rng) +void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; dict coverdb; - int weight_cover = 500; - - int weight_pq_w = 100; - int weight_pq_b = 100; - int weight_pq_c = 100; - int weight_pq_s = 100; - - int weight_pq_mw = 100; - int weight_pq_mb = 100; - int weight_pq_mc = 100; - int weight_pq_ms = 100; - - int total_weight = weight_cover + weight_pq_w + weight_pq_b + weight_pq_c + weight_pq_s; - total_weight += weight_pq_mw + weight_pq_mb + weight_pq_mc + weight_pq_ms; + int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s; + total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms; if (N >= GetSize(database)) return; @@ -254,7 +251,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op { int k = rng(total_weight); - k -= weight_cover; + k -= opts.weight_cover; if (k < 0) { while (!skip_cover) { if (cover_candidates.empty()) { @@ -316,24 +313,24 @@ void database_reduce(std::vector &database, const mutate_opts_t &/* op continue; } -#define X(__wght, __queue) \ - k -= __wght; \ - if (k < 0) { \ - mutate_t *m = __queue.pick(rng, coverdb); \ - if (m != nullptr) \ - new_database.push_back(*m); \ - continue; \ +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng, coverdb, opts); \ + if (m != nullptr) \ + new_database.push_back(*m); \ + continue; \ } - X(weight_pq_w, primary_queue_wire) - X(weight_pq_b, primary_queue_bit) - X(weight_pq_c, primary_queue_cell) - X(weight_pq_s, primary_queue_src) + X(opts.weight_pq_w, primary_queue_wire) + X(opts.weight_pq_b, primary_queue_bit) + X(opts.weight_pq_c, primary_queue_cell) + X(opts.weight_pq_s, primary_queue_src) - X(weight_pq_mw, primary_queue_module_wire) - X(weight_pq_mb, primary_queue_module_bit) - X(weight_pq_mc, primary_queue_module_cell) - X(weight_pq_ms, primary_queue_module_src) + X(opts.weight_pq_mw, primary_queue_module_wire) + X(opts.weight_pq_mb, primary_queue_module_bit) + X(opts.weight_pq_mc, primary_queue_module_cell) + X(opts.weight_pq_ms, primary_queue_module_src) #undef X } @@ -654,6 +651,12 @@ struct MutatePass : public Pass { log(" Filter list of mutation candidates to those matching\n"); log(" the given parameters.\n"); log("\n"); + log(" -cfg option int\n"); + log(" Set a configuration option. Options available:\n"); + log(" weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n"); + log(" weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n"); + log(" weight_cover pick_cover_prcnt\n"); + log("\n"); log("\n"); log(" mutate -mode MODE [options]\n"); log("\n"); @@ -741,6 +744,58 @@ struct MutatePass : public Pass { opts.src.insert(args[++argidx]); continue; } + if (args[argidx] == "-cfg" && argidx+2 < args.size()) { + if (args[argidx+1] == "pick_cover_prcnt") { + opts.pick_cover_prcnt = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_cover") { + opts.weight_cover = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_w") { + opts.weight_pq_w = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_b") { + opts.weight_pq_b = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_c") { + opts.weight_pq_c = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_s") { + opts.weight_pq_s = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mw") { + opts.weight_pq_mw = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mb") { + opts.weight_pq_mb = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mc") { + opts.weight_pq_mc = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_ms") { + opts.weight_pq_ms = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + } break; } extra_args(args, argidx, design); -- cgit v1.2.3 From d1985f6a223d18e0ae8545a620e4117fd4ca23b3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 00:18:31 +0100 Subject: Improvements in "mutate" list-reduce algorithm Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 6b9eb3c04..4c103dcd5 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -133,7 +133,7 @@ struct xs128_t } }; -struct mutate_leaf_queue_t +struct mutate_queue_t { pool db; @@ -181,7 +181,7 @@ struct mutate_leaf_queue_t }; template -struct mutate_inner_queue_t +struct mutate_chain_queue_t { dict db; @@ -203,6 +203,29 @@ struct mutate_inner_queue_t } }; +template +struct mutate_once_queue_t +{ + dict db; + + mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = it->second.pick(rng, coverdb, opts); + db.erase(it); + if (m != nullptr) + return m; + } + return nullptr; + } + + template + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; @@ -214,26 +237,26 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, if (N >= GetSize(database)) return; - mutate_inner_queue_t primary_queue_wire; - mutate_inner_queue_t, mutate_leaf_queue_t> primary_queue_bit; - mutate_inner_queue_t primary_queue_cell; - mutate_inner_queue_t primary_queue_src; + mutate_once_queue_t, mutate_queue_t> primary_queue_wire; + mutate_once_queue_t, mutate_queue_t> primary_queue_bit; + mutate_once_queue_t, mutate_queue_t> primary_queue_cell; + mutate_once_queue_t primary_queue_src; - mutate_inner_queue_t> primary_queue_module_wire; - mutate_inner_queue_t, mutate_leaf_queue_t>> primary_queue_module_bit; - mutate_inner_queue_t> primary_queue_module_cell; - mutate_inner_queue_t> primary_queue_module_src; + mutate_chain_queue_t> primary_queue_module_wire; + mutate_chain_queue_t, mutate_queue_t>> primary_queue_module_bit; + mutate_chain_queue_t> primary_queue_module_cell; + mutate_chain_queue_t> primary_queue_module_src; for (auto &m : database) { if (!m.wire.empty()) { - primary_queue_wire.add(&m, m.wire); - primary_queue_bit.add(&m, pair(m.wire, m.wirebit)); + primary_queue_wire.add(&m, tuple(m.module, m.wire)); + primary_queue_bit.add(&m, tuple(m.module, m.wire, m.wirebit)); primary_queue_module_wire.add(&m, m.module, m.wire); primary_queue_module_bit.add(&m, m.module, pair(m.wire, m.wirebit)); } - primary_queue_cell.add(&m, m.cell); + primary_queue_cell.add(&m, tuple(m.module, m.cell)); primary_queue_module_cell.add(&m, m.module, m.cell); for (auto &s : m.src) { -- cgit v1.2.3 From 370db33a4c347049cb8f66c181d39fd2f2ce5e3a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 20:18:38 +0100 Subject: Add fmcombine pass Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/fmcombine.cc | 292 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 passes/sat/fmcombine.cc (limited to 'passes') diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index e91df1eb0..4eced2ff1 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -9,5 +9,6 @@ OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o +OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc new file mode 100644 index 000000000..b8a0e94c8 --- /dev/null +++ b/passes/sat/fmcombine.cc @@ -0,0 +1,292 @@ +/* + * 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/celltypes.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct FmcombineWorker +{ + Design *design; + Module *original = nullptr; + Module *module = nullptr; + IdString orig_type, combined_type; + + FmcombineWorker(Design *design, IdString orig_type) : + design(design), original(design->module(orig_type)), + orig_type(orig_type), combined_type("$fmcombine" + orig_type.str()) + { + } + + SigSpec import_sig(SigSpec sig, const string &suffix) + { + SigSpec newsig; + for (auto chunk : sig.chunks()) { + if (chunk.wire != nullptr) + chunk.wire = module->wire(chunk.wire->name.str() + suffix); + newsig.append(chunk); + } + return newsig; + } + + void import_prim_cell(Cell *cell, const string &suffix) + { + Cell *c = module->addCell(cell->name.str() + suffix, cell->type); + c->parameters = cell->parameters; + c->attributes = cell->attributes; + + for (auto &conn : cell->connections()) + c->setPort(conn.first, import_sig(conn.second, suffix)); + } + + void import_hier_cell(Cell *cell) + { + if (!cell->parameters.empty()) + log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell)); + + FmcombineWorker sub_worker(design, cell->type); + sub_worker.generate(); + + Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type); + // c->parameters = cell->parameters; + c->attributes = cell->attributes; + + for (auto &conn : cell->connections()) { + c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold")); + c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate")); + } + } + + void generate() + { + if (design->module(combined_type)) { + // log("Combined module %s already exists.\n", log_id(combined_type)); + return; + } + + log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type)); + module = design->addModule(combined_type); + + for (auto wire : original->wires()) { + module->addWire(wire->name.str() + "_gold", wire); + module->addWire(wire->name.str() + "_gate", wire); + } + module->fixup_ports(); + + for (auto cell : original->cells()) { + if (design->module(cell->type) == nullptr) { + import_prim_cell(cell, "_gold"); + import_prim_cell(cell, "_gate"); + } else { + import_hier_cell(cell); + } + } + + for (auto &conn : original->connections()) { + module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold")); + module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate")); + } + + CellTypes ct; + ct.setup_internals_eval(); + ct.setup_stdcells_eval(); + + SigMap sigmap(module); + + dict data_bit_to_eq_net; + dict cell_to_eq_nets; + dict reduce_db; + dict invert_db; + + for (auto cell : original->cells()) + { + if (!ct.cell_known(cell->type)) + continue; + + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec A = import_sig(conn.second, "_gold"); + SigSpec B = import_sig(conn.second, "_gate"); + SigBit EQ = module->Eq(NEW_ID, A, B); + + for (auto bit : sigmap({A, B})) + data_bit_to_eq_net[bit] = EQ; + + cell_to_eq_nets[cell].append(EQ); + } + } + + for (auto cell : original->cells()) + { + if (!ct.cell_known(cell->type)) + continue; + + bool skip_cell = !cell_to_eq_nets.count(cell); + pool src_eq_bits; + + for (auto &conn : cell->connections()) + { + if (skip_cell) + break; + + if (cell->output(conn.first)) + continue; + + SigSpec A = import_sig(conn.second, "_gold"); + SigSpec B = import_sig(conn.second, "_gate"); + + for (auto bit : sigmap({A, B})) { + if (data_bit_to_eq_net.count(bit)) + src_eq_bits.insert(data_bit_to_eq_net.at(bit)); + else + skip_cell = true; + } + } + + if (!skip_cell) { + SigSpec antecedent = SigSpec(src_eq_bits); + antecedent.sort_and_unify(); + + if (GetSize(antecedent) > 1) { + if (reduce_db.count(antecedent) == 0) + reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent); + antecedent = reduce_db.at(antecedent); + } + + SigSpec consequent = cell_to_eq_nets.at(cell); + consequent.sort_and_unify(); + + if (GetSize(consequent) > 1) { + if (reduce_db.count(consequent) == 0) + reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent); + consequent = reduce_db.at(consequent); + } + + module->addAssume(NEW_ID, consequent, antecedent); + + if (invert_db.count(antecedent) == 0) + invert_db[antecedent] = module->Not(NEW_ID, antecedent); + + if (invert_db.count(consequent) == 0) + invert_db[consequent] = module->Not(NEW_ID, consequent); + + module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent)); + } + } + } +}; + +struct FmcombinePass : public Pass { + FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" fmcombine [options] module_name gold_cell gate_cell\n"); + // log(" fmcombine [options] @gold_cell @gate_cell\n"); + log("\n"); + log("This pass takes two cells, which are instances of the same module, and replaces\n"); + log("them with one instance of a special 'combined' module, that effectively\n"); + log("contains two copies of the original module, plus some formal properties.\n"); + log("\n"); + log("This is useful for formal test benches that check what differences in behavior\n"); + log("a slight difference in input causes in a module.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + Module *module = nullptr; + Cell *gold_cell = nullptr; + Cell *gate_cell = nullptr; + + log_header(design, "Executing FMCOMBINE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-o" && argidx+1 < args.size()) { + // filename = args[++argidx]; + // continue; + // } + break; + } + if (argidx+2 == args.size()) + { + string gold_name = args[argidx++]; + string gate_name = args[argidx++]; + log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet."); + } + else if (argidx+3 == args.size()) + { + IdString module_name = RTLIL::escape_id(args[argidx++]); + IdString gold_name = RTLIL::escape_id(args[argidx++]); + IdString gate_name = RTLIL::escape_id(args[argidx++]); + + module = design->module(module_name); + if (module == nullptr) + log_cmd_error("Module %s not found.\n", log_id(module_name)); + + gold_cell = module->cell(gold_name); + if (gold_cell == nullptr) + log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module)); + + gate_cell = module->cell(gate_name); + if (gate_cell == nullptr) + log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gate_name), log_id(module)); + } + else + { + log_cmd_error("Invalid number of arguments.\n"); + } + // extra_args(args, argidx, design); + + if (gold_cell->type != gate_cell->type) + log_cmd_error("Types of gold and gate cells do not match.\n"); + if (!gold_cell->parameters.empty()) + log_cmd_error("Gold cell has unresolved instance parameters.\n"); + if (!gate_cell->parameters.empty()) + log_cmd_error("Gold cell has unresolved instance parameters.\n"); + + FmcombineWorker worker(design, gold_cell->type); + worker.generate(); + IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell))); + + Cell *cell = module->addCell(combined_cell_name, worker.combined_type); + cell->attributes = gold_cell->attributes; + cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src")); + + log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell)); + + for (auto &conn : gold_cell->connections()) + cell->setPort(conn.first.str() + "_gold", conn.second); + module->remove(gold_cell); + + for (auto &conn : gate_cell->connections()) + cell->setPort(conn.first.str() + "_gate", conn.second); + module->remove(gate_cell); + } +} FmcombinePass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From dacaebae35c81b4f4970af3ef8bfdb73691fa215 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 15 Mar 2019 21:45:37 +0100 Subject: Add "fmcombine -fwd -bwd -nop" Signed-off-by: Clifford Wolf --- passes/sat/fmcombine.cc | 69 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc index b8a0e94c8..cd75ca860 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -24,15 +24,23 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +struct opts_t +{ + bool fwd = false; + bool bwd = false; + bool nop = false; +}; + struct FmcombineWorker { + const opts_t &opts; Design *design; Module *original = nullptr; Module *module = nullptr; IdString orig_type, combined_type; - FmcombineWorker(Design *design, IdString orig_type) : - design(design), original(design->module(orig_type)), + FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) : + opts(opts), design(design), original(design->module(orig_type)), orig_type(orig_type), combined_type("$fmcombine" + orig_type.str()) { } @@ -63,7 +71,7 @@ struct FmcombineWorker if (!cell->parameters.empty()) log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell)); - FmcombineWorker sub_worker(design, cell->type); + FmcombineWorker sub_worker(design, cell->type, opts); sub_worker.generate(); Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type); @@ -106,6 +114,9 @@ struct FmcombineWorker module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate")); } + if (opts.nop) + return; + CellTypes ct; ct.setup_internals_eval(); ct.setup_stdcells_eval(); @@ -184,15 +195,19 @@ struct FmcombineWorker consequent = reduce_db.at(consequent); } - module->addAssume(NEW_ID, consequent, antecedent); + if (opts.fwd) + module->addAssume(NEW_ID, consequent, antecedent); - if (invert_db.count(antecedent) == 0) - invert_db[antecedent] = module->Not(NEW_ID, antecedent); + if (opts.bwd) + { + if (invert_db.count(antecedent) == 0) + invert_db[antecedent] = module->Not(NEW_ID, antecedent); - if (invert_db.count(consequent) == 0) - invert_db[consequent] = module->Not(NEW_ID, consequent); + if (invert_db.count(consequent) == 0) + invert_db[consequent] = module->Not(NEW_ID, consequent); - module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent)); + module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent)); + } } } } @@ -214,9 +229,25 @@ struct FmcombinePass : public Pass { log("This is useful for formal test benches that check what differences in behavior\n"); log("a slight difference in input causes in a module.\n"); log("\n"); + log(" -fwd\n"); + log(" Insert forward hint assumptions into the combined module.\n"); + log("\n"); + log(" -bwd\n"); + log(" Insert backward hint assumptions into the combined module.\n"); + log(" (Backward hints are logically equivalend to fordward hits, but\n"); + log(" some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n"); + log("\n"); + log(" -nop\n"); + log(" Don't insert hint assumptions into the combined module.\n"); + log(" (This should not provide any speedup over the original design, but\n"); + log(" strangely sometimes it does.)\n"); + log("\n"); + log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { + opts_t opts; Module *module = nullptr; Cell *gold_cell = nullptr; Cell *gate_cell = nullptr; @@ -230,6 +261,18 @@ struct FmcombinePass : public Pass { // filename = args[++argidx]; // continue; // } + if (args[argidx] == "-fwd") { + opts.fwd = true; + continue; + } + if (args[argidx] == "-bwd") { + opts.bwd = true; + continue; + } + if (args[argidx] == "-nop") { + opts.nop = true; + continue; + } break; } if (argidx+2 == args.size()) @@ -262,6 +305,12 @@ struct FmcombinePass : public Pass { } // extra_args(args, argidx, design); + if (opts.nop && (opts.fwd || opts.bwd)) + log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n"); + + if (!opts.nop && !opts.fwd && !opts.bwd) + opts.fwd = true; + if (gold_cell->type != gate_cell->type) log_cmd_error("Types of gold and gate cells do not match.\n"); if (!gold_cell->parameters.empty()) @@ -269,7 +318,7 @@ struct FmcombinePass : public Pass { if (!gate_cell->parameters.empty()) log_cmd_error("Gold cell has unresolved instance parameters.\n"); - FmcombineWorker worker(design, gold_cell->type); + FmcombineWorker worker(design, gold_cell->type, opts); worker.generate(); IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell))); -- cgit v1.2.3 From aa65d3fe65bd45994f8cb053daef3a5e52b31cd3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 16 Mar 2019 00:55:46 +0100 Subject: Improve mix of src/wire/wirebit coverage in "mutate -list" Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 113 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 29 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 4c103dcd5..9621d2855 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -46,7 +46,7 @@ struct mutate_opts_t { IdString ctrl_name; int ctrl_width = -1, ctrl_value = -1; - int pick_cover_prcnt = 50; + int pick_cover_prcnt = 80; int weight_cover = 500; @@ -133,25 +133,69 @@ struct xs128_t } }; +struct coverdb_t +{ + dict src_db; + dict, int> wire_db; + dict, int> wirebit_db; + + void insert(const mutate_t &m) { + if (!m.wire.empty()) { + wire_db[tuple(m.module, m.wire)] = 0; + wirebit_db[tuple(m.module, m.wire, m.wirebit)] = 0; + } + for (auto &s : m.src) { + src_db[s] = 0; + } + } + + void update(const mutate_t &m) { + if (!m.wire.empty()) { + wire_db.at(tuple(m.module, m.wire))++; + wirebit_db.at(tuple(m.module, m.wire, m.wirebit))++; + } + for (auto &s : m.src) { + src_db.at(s)++; + } + } + + int score(const mutate_t &m) { + int this_score = m.src.empty() ? 0 : 1; + if (!m.wire.empty()) { + this_score += wire_db.at(tuple(m.module, m.wire)) ? 0 : 5; + this_score += wirebit_db.at(tuple(m.module, m.wire, m.wirebit)) ? 0 : 1; + } + for (auto &s : m.src) { + this_score += src_db.at(s) ? 0 : 5; + } + return this_score; + } +}; + struct mutate_queue_t { pool db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { mutate_t *m = nullptr; if (rng(100) < opts.pick_cover_prcnt) { - vector candidates; + vector candidates, rmqueue; + int best_score = -1; for (auto p : db) { - if (p->used || p->src.empty()) + if (p->used) { + rmqueue.push_back(p); continue; - bool is_covered = false; - for (auto &s : p->src) { - if (coverdb.at(s)) - is_covered = true; } - if (!is_covered) + int this_score = coverdb.score(*p); + if (this_score > best_score) { + best_score = this_score; + candidates.clear(); + } + if (best_score == this_score) candidates.push_back(p); } + for (auto p : rmqueue) + db.erase(p); if (!candidates.empty()) m = candidates[rng(GetSize(candidates))]; } @@ -167,11 +211,6 @@ struct mutate_queue_t } } } - if (m != nullptr) { - m->used = true; - for (auto &s : m->src) - coverdb[s]++; - } return m; } @@ -185,7 +224,7 @@ struct mutate_chain_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { while (!db.empty()) { int i = rng(GetSize(db)); auto it = db.element(i); @@ -208,7 +247,7 @@ struct mutate_once_queue_t { dict db; - mutate_t *pick(xs128_t &rng, dict &coverdb, const mutate_opts_t &opts) { + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { while (!db.empty()) { int i = rng(GetSize(db)); auto it = db.element(i); @@ -229,7 +268,7 @@ struct mutate_once_queue_t void database_reduce(std::vector &database, const mutate_opts_t &opts, int N, xs128_t &rng) { std::vector new_database; - dict coverdb; + coverdb_t coverdb; int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s; total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms; @@ -249,6 +288,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, for (auto &m : database) { + coverdb.insert(m); + if (!m.wire.empty()) { primary_queue_wire.add(&m, tuple(m.module, m.wire)); primary_queue_bit.add(&m, tuple(m.module, m.wire, m.wirebit)); @@ -260,7 +301,6 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, primary_queue_module_cell.add(&m, m.module, m.cell); for (auto &s : m.src) { - coverdb[s] = 0; primary_queue_src.add(&m, s); primary_queue_module_src.add(&m, m.module, s); } @@ -284,8 +324,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, continue; int this_score = -1; for (auto &s : m.src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); + if (this_score == -1 || this_score > coverdb.src_db.at(s)) + this_score = coverdb.src_db.at(s); } log_assert(this_score != -1); if (best_cover_score == -1 || this_score < best_cover_score) { @@ -314,8 +354,8 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, int this_score = -1; for (auto &s : p->src) { - if (this_score == -1 || this_score > coverdb.at(s)) - this_score = coverdb.at(s); + if (this_score == -1 || this_score > coverdb.src_db.at(s)) + this_score = coverdb.src_db.at(s); } if (this_score != best_cover_score) @@ -327,8 +367,7 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, if (m != nullptr) { m->used = true; - for (auto &s : m->src) - coverdb[s]++; + coverdb.update(*m); new_database.push_back(*m); break; } @@ -340,8 +379,11 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, k -= __wght; \ if (k < 0) { \ mutate_t *m = __queue.pick(rng, coverdb, opts); \ - if (m != nullptr) \ + if (m != nullptr) { \ + m->used = true; \ + coverdb.update(*m); \ new_database.push_back(*m); \ + }; \ continue; \ } @@ -359,12 +401,25 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, std::swap(new_database, database); - int covered_cnt = 0; - for (auto &it : coverdb) + int covered_src_cnt = 0; + int covered_wire_cnt = 0; + int covered_wirebit_cnt = 0; + + for (auto &it : coverdb.src_db) + if (it.second) + covered_src_cnt++; + + for (auto &it : coverdb.wire_db) + if (it.second) + covered_wire_cnt++; + + for (auto &it : coverdb.wirebit_db) if (it.second) - covered_cnt++; + covered_wirebit_cnt++; - log("Covered %d/%d src attributes (%.2f%%).\n", covered_cnt, GetSize(coverdb), 100.0 * covered_cnt / GetSize(coverdb)); + log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db)); + log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db)); + log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db)); } void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) -- cgit v1.2.3 From 7cfd83c3415dd3d576539e00b91b6e283997fe52 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 22 Mar 2019 11:42:19 +0100 Subject: Trim init attributes when resizing FFs in "wreduce", fixes #887 Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 1f7222e49..52245ce3e 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -54,6 +54,7 @@ struct WreduceWorker std::set work_queue_bits; pool keep_bits; dict init_bits; + pool remove_init_bits; WreduceWorker(WreduceConfig *config, Module *module) : config(config), module(module), mi(module) { } @@ -164,6 +165,7 @@ struct WreduceWorker { if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) { module->connect(sig_q[i], State::S0); + remove_init_bits.insert(sig_q[i]); sig_d.remove(i); sig_q.remove(i); continue; @@ -171,6 +173,7 @@ struct WreduceWorker if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) { module->connect(sig_q[i], sig_q[i-1]); + remove_init_bits.insert(sig_q[i]); sig_d.remove(i); sig_q.remove(i); continue; @@ -178,6 +181,7 @@ struct WreduceWorker auto info = mi.query(sig_q[i]); if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { + remove_init_bits.insert(sig_q[i]); sig_d.remove(i); sig_q.remove(i); zero_ext = false; @@ -387,13 +391,16 @@ struct WreduceWorker void run() { + // create a copy as mi.sigmap will be updated as we process the module + SigMap init_attr_sigmap = mi.sigmap; + for (auto w : module->wires()) { if (w->get_bool_attribute("\\keep")) for (auto bit : mi.sigmap(w)) keep_bits.insert(bit); if (w->attributes.count("\\init")) { Const initval = w->attributes.at("\\init"); - SigSpec initsig = mi.sigmap(w); + SigSpec initsig = init_attr_sigmap(w); int width = std::min(GetSize(initval), GetSize(initsig)); for (int i = 0; i < width; i++) init_bits[initsig[i]] = initval[i]; @@ -446,6 +453,24 @@ struct WreduceWorker module->connect(nw, SigSpec(w).extract(0, GetSize(nw))); module->swap_names(w, nw); } + + if (!remove_init_bits.empty()) { + for (auto w : module->wires()) { + if (w->attributes.count("\\init")) { + Const initval = w->attributes.at("\\init"); + Const new_initval(State::Sx, GetSize(w)); + SigSpec initsig = init_attr_sigmap(w); + int width = std::min(GetSize(initval), GetSize(initsig)); + for (int i = 0; i < width; i++) { + log_dump(initsig[i], remove_init_bits.count(initsig[i])); + if (!remove_init_bits.count(initsig[i])) + new_initval[i] = initval[i]; + } + w->attributes.at("\\init") = new_initval; + log_dump(w->name, initval, new_initval); + } + } + } } }; -- cgit v1.2.3 From 59c44bb61ab1a69a7ba4cd8d2b6d8d3e3408d9ca Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 17:53:09 +0100 Subject: Add "mutate -s " Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 9621d2855..7025a7aca 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -422,8 +422,9 @@ void database_reduce(std::vector &database, const mutate_opts_t &opts, log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db)); } -void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, int N) +void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N) { + pool sources; std::vector database; xs128_t rng(opts.seed); @@ -497,6 +498,9 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena entry.wirebit = bit.offset; } + if (!srcsfile.empty()) + sources.insert(entry.src.begin(), entry.src.end()); + entry.mode = "inv"; database_add(database, opts, entry); @@ -526,6 +530,16 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log("Reduced database size: %d\n", GetSize(database)); } + if (!srcsfile.empty()) { + std::ofstream sout; + sout.open(srcsfile, std::ios::out | std::ios::trunc); + if (!sout.is_open()) + log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str()); + sources.sort(); + for (auto &s : sources) + sout << s << std::endl; + } + std::ofstream fout; if (!filename.empty()) { @@ -710,6 +724,9 @@ struct MutatePass : public Pass { log(" -o filename\n"); log(" Write list to this file instead of console output\n"); log("\n"); + log(" -s filename\n"); + log(" Write a list of all src tags found in the design to the specified file\n"); + log("\n"); log(" -seed N\n"); log(" RNG seed for selecting mutations\n"); log("\n"); @@ -761,6 +778,7 @@ struct MutatePass : public Pass { { mutate_opts_t opts; string filename; + string srcsfile; int N = -1; log_header(design, "Executing MUTATE pass.\n"); @@ -776,6 +794,10 @@ struct MutatePass : public Pass { filename = args[++argidx]; continue; } + if (args[argidx] == "-s" && argidx+1 < args.size()) { + srcsfile = args[++argidx]; + continue; + } if (args[argidx] == "-seed" && argidx+1 < args.size()) { opts.seed = atoi(args[++argidx].c_str()); continue; @@ -879,7 +901,7 @@ struct MutatePass : public Pass { extra_args(args, argidx, design); if (N >= 0) { - mutate_list(design, opts, filename, N); + mutate_list(design, opts, filename, srcsfile, N); return; } -- cgit v1.2.3 From ccfa2fe01cffcc4d23bc989e558bd33addfea58e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 23 Mar 2019 20:20:32 +0100 Subject: Add "mutate -none -mode", "mutate -mode none" Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index 7025a7aca..c50678c51 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -46,6 +46,8 @@ struct mutate_opts_t { IdString ctrl_name; int ctrl_width = -1, ctrl_value = -1; + bool none = false; + int pick_cover_prcnt = 80; int weight_cover = 500; @@ -526,7 +528,7 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena log("Raw database size: %d\n", GetSize(database)); if (N != 0) { - database_reduce(database, opts, N, rng); + database_reduce(database, opts, opts.none ? N-1 : N, rng); log("Reduced database size: %d\n", GetSize(database)); } @@ -550,6 +552,17 @@ void mutate_list(Design *design, const mutate_opts_t &opts, const string &filena int ctrl_value = opts.ctrl_value; + if (opts.none) { + string str = "mutate"; + if (!opts.ctrl_name.empty()) + str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++); + str += " -mode none"; + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } + for (auto &entry : database) { string str = "mutate"; if (!opts.ctrl_name.empty()) @@ -730,6 +743,9 @@ struct MutatePass : public Pass { log(" -seed N\n"); log(" RNG seed for selecting mutations\n"); log("\n"); + log(" -none\n"); + log(" Include a \"none\" mutation in the output\n"); + log("\n"); log(" -ctrl name width value\n"); log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n"); log(" simply count up from there.\n"); @@ -802,6 +818,10 @@ struct MutatePass : public Pass { opts.seed = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-none") { + opts.none = true; + continue; + } if (args[argidx] == "-mode" && argidx+1 < args.size()) { opts.mode = args[++argidx]; continue; @@ -905,6 +925,15 @@ struct MutatePass : public Pass { return; } + if (opts.mode == "none") { + if (!opts.ctrl_name.empty()) { + Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module); + if (topmod) + mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width); + } + return; + } + if (opts.mode == "inv") { mutate_inv(design, opts); return; -- cgit v1.2.3 From ac6cc88db352938d8dd9f2f9c6d404663674538e Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 24 Mar 2019 16:21:36 +0000 Subject: memory_bram: Fix multiclock make_transp Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'passes') diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index cf4095d06..c38eabaee 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, } // assign write ports - + pair wr_clkdom; for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++) { bool clken = wr_clken[cell_port_i] == State::S1; @@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, pair clkdom(clksig, clkpol); if (!clken) clkdom = pair(State::S1, false); - + wr_clkdom = clkdom; log(" Write port #%d is in clock domain %s%s.\n", cell_port_i, clkdom.second ? "" : "!", clken ? log_signal(clkdom.first) : "~async~"); @@ -718,7 +718,13 @@ grow_read_ports:; if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) { if (match.make_transp && wr_ports <= 1) { pi.make_transp = true; - enable_make_transp = true; + if (pi.clocks != 0) { + if (wr_ports == 1 && wr_clkdom != clkdom) { + log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); + goto skip_bram_rport; + } + enable_make_transp = true; + } } else { log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); goto skip_bram_rport; @@ -913,17 +919,18 @@ grow_read_ports:; } else { SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits); c->setPort(stringf("\\%sDATA", pf), bram_dout); - - if (pi.make_outreg) { + if (pi.make_outreg && pi.make_transp) { + log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); + SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits); + module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol); + c->setPort(stringf("\\%sADDR", pf), sig_addr_q); + } else if (pi.make_outreg) { SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits); if (!pi.sig_en.empty()) bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en); module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol); bram_dout = bram_dout_q; - } - - if (pi.make_transp) - { + } else if (pi.make_transp) { log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits), -- cgit v1.2.3 From 3b3b77291a21ed23a2763c79335501beebb10746 Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Sun, 24 Mar 2019 22:54:18 +0100 Subject: Updated the liberty parser to accept [A:B] ranges (AST has not been updated). Liberty parser now also accepts key : value pair lines that do not end in ';'. --- passes/techmap/libparse.cc | 87 ++++++++++++++++++++++++++++++++++++++++++---- passes/techmap/libparse.h | 10 +++++- 2 files changed, 90 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 3927a657b..878ca3160 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef FILTERLIB #include "kernel/log.h" @@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str) { int c; + // eat whitespace do { c = f.get(); } while (c == ' ' || c == '\t' || c == '\r'); - if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') { + // search for identifiers, numbers, plus or minus. + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { str = c; while (1) { c = f.get(); - if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') str += c; else break; @@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str) } } + // if it wasn't an identifer, number of array range, + // maybe it's a string? if (c == '"') { str = ""; while (1) { @@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str) return 'v'; } + // if it wasn't a string, perhaps it's a comment or a forward slash? if (c == '/') { c = f.get(); - if (c == '*') { + if (c == '*') { // start of '/*' block comment int last_c = 0; while (c > 0 && (last_c != '*' || c != '/')) { last_c = c; @@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str) line++; } return lexer(str); - } else if (c == '/') { + } else if (c == '/') { // start of '//' line comment while (c > 0 && c != '\n') c = f.get(); line++; @@ -144,9 +150,10 @@ int LibertyParser::lexer(std::string &str) } f.unget(); // fprintf(stderr, "LEX: char >>/<<\n"); - return '/'; + return '/'; // a single '/' charater. } + // check for a backslash if (c == '\\') { c = f.get(); if (c == '\r') @@ -157,11 +164,15 @@ int LibertyParser::lexer(std::string &str) return '\\'; } + // check for a new line if (c == '\n') { line++; return 'n'; } + // anything else, such as ';' will get passed + // through as literal items. + // if (c >= 32 && c < 255) // fprintf(stderr, "LEX: char >>%c<<\n", c); // else @@ -210,7 +221,12 @@ LibertyAst *LibertyParser::parse() ast->value += str; tok = lexer(str); } - if (tok == ';') + + // In a liberty file, all key : value pairs should end in ';' + // However, there are some liberty files in the wild that + // just have a newline. We'll be kind and accept a newline + // instead of the ';' too.. + if ((tok == ';') || (tok == 'n')) break; else error(); @@ -225,6 +241,48 @@ LibertyAst *LibertyParser::parse() continue; if (tok == ')') break; + + // FIXME: the AST needs to be extended to store + // these vector ranges. + if (tok == '[') + { + // parse vector range [A] or [A:B] + std::string arg; + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number A + } + tok = lexer(arg); + // optionally check for : in case of [A:B] + // if it isn't we just expect ']' + // as we have [A] + if (tok == ':') + { + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number B + tok = lexer(arg); + } + } + // expect a closing bracket of array range + if (tok != ']') + { + error("Expected ']' on array range."); + } + continue; + } if (tok != 'v') error(); ast->args.push_back(arg); @@ -255,6 +313,14 @@ void LibertyParser::error() log_error("Syntax error in liberty file on line %d.\n", line); } +void LibertyParser::error(const std::string &str) +{ + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + log_error("%s", ss.str().c_str()); +} + #else void LibertyParser::error() @@ -263,6 +329,15 @@ void LibertyParser::error() exit(1); } +void LibertyParser::error(const std::string &str) +{ + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + printf("%s", ss.str().c_str()); + exit(1); +} + /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ #define CHECK_NV(result, check) \ diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index cf6325570..c9ebd06c5 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -46,9 +46,17 @@ namespace Yosys LibertyAst *ast; LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {} ~LibertyParser() { if (ast) delete ast; } + + /* lexer return values: + 'v': identifier, string, array range [...] -> str holds the token string + 'n': newline + anything else is a single character. + */ int lexer(std::string &str); - LibertyAst *parse(); + + LibertyAst *parse(); void error(); + void error(const std::string &str); }; } -- cgit v1.2.3 From 9d9cc8a3140cdbc2d976a5b06b5a057845da739a Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Mon, 25 Mar 2019 12:15:10 +0100 Subject: EOL is now accepted as ';' replacement on lines that look like: feature_xyz(option) --- passes/techmap/libparse.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'passes') diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 878ca3160..9dc3e96ab 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -202,12 +202,11 @@ LibertyAst *LibertyParser::parse() { tok = lexer(str); - if (tok == ';') + // allow both ';' and new lines to + // terminate a statement. + if ((tok == ';') || (tok == 'n')) break; - if (tok == 'n') - continue; - if (tok == ':' && ast->value.empty()) { tok = lexer(ast->value); if (tok != 'v') -- cgit v1.2.3 From 1f7f54e68eb201976ddd42cb906492bf9e611030 Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Mon, 25 Mar 2019 14:12:04 +0100 Subject: spaces -> tabs --- passes/techmap/libparse.cc | 156 ++++++++++++++++++++++----------------------- 1 file changed, 78 insertions(+), 78 deletions(-) (limited to 'passes') diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 9dc3e96ab..8eadd8735 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -87,12 +87,12 @@ int LibertyParser::lexer(std::string &str) { int c; - // eat whitespace + // eat whitespace do { c = f.get(); } while (c == ' ' || c == '\t' || c == '\r'); - // search for identifiers, numbers, plus or minus. + // search for identifiers, numbers, plus or minus. if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { str = c; while (1) { @@ -114,8 +114,8 @@ int LibertyParser::lexer(std::string &str) } } - // if it wasn't an identifer, number of array range, - // maybe it's a string? + // if it wasn't an identifer, number of array range, + // maybe it's a string? if (c == '"') { str = ""; while (1) { @@ -130,7 +130,7 @@ int LibertyParser::lexer(std::string &str) return 'v'; } - // if it wasn't a string, perhaps it's a comment or a forward slash? + // if it wasn't a string, perhaps it's a comment or a forward slash? if (c == '/') { c = f.get(); if (c == '*') { // start of '/*' block comment @@ -153,7 +153,7 @@ int LibertyParser::lexer(std::string &str) return '/'; // a single '/' charater. } - // check for a backslash + // check for a backslash if (c == '\\') { c = f.get(); if (c == '\r') @@ -164,14 +164,14 @@ int LibertyParser::lexer(std::string &str) return '\\'; } - // check for a new line + // check for a new line if (c == '\n') { line++; return 'n'; } - // anything else, such as ';' will get passed - // through as literal items. + // anything else, such as ';' will get passed + // through as literal items. // if (c >= 32 && c < 255) // fprintf(stderr, "LEX: char >>%c<<\n", c); @@ -202,8 +202,8 @@ LibertyAst *LibertyParser::parse() { tok = lexer(str); - // allow both ';' and new lines to - // terminate a statement. + // allow both ';' and new lines to + // terminate a statement. if ((tok == ';') || (tok == 'n')) break; @@ -220,11 +220,11 @@ LibertyAst *LibertyParser::parse() ast->value += str; tok = lexer(str); } - - // In a liberty file, all key : value pairs should end in ';' - // However, there are some liberty files in the wild that - // just have a newline. We'll be kind and accept a newline - // instead of the ';' too.. + + // In a liberty file, all key : value pairs should end in ';' + // However, there are some liberty files in the wild that + // just have a newline. We'll be kind and accept a newline + // instead of the ';' too.. if ((tok == ';') || (tok == 'n')) break; else @@ -240,48 +240,48 @@ LibertyAst *LibertyParser::parse() continue; if (tok == ')') break; - - // FIXME: the AST needs to be extended to store - // these vector ranges. - if (tok == '[') - { - // parse vector range [A] or [A:B] - std::string arg; - tok = lexer(arg); - if (tok != 'v') - { - // expected a vector array index - error("Expected a number."); - } - else - { - // fixme: check for number A - } - tok = lexer(arg); - // optionally check for : in case of [A:B] - // if it isn't we just expect ']' - // as we have [A] - if (tok == ':') - { - tok = lexer(arg); - if (tok != 'v') - { - // expected a vector array index - error("Expected a number."); - } - else - { - // fixme: check for number B - tok = lexer(arg); - } - } - // expect a closing bracket of array range - if (tok != ']') - { - error("Expected ']' on array range."); - } - continue; - } + + // FIXME: the AST needs to be extended to store + // these vector ranges. + if (tok == '[') + { + // parse vector range [A] or [A:B] + std::string arg; + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number A + } + tok = lexer(arg); + // optionally check for : in case of [A:B] + // if it isn't we just expect ']' + // as we have [A] + if (tok == ':') + { + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number B + tok = lexer(arg); + } + } + // expect a closing bracket of array range + if (tok != ']') + { + error("Expected ']' on array range."); + } + continue; + } if (tok != 'v') error(); ast->args.push_back(arg); @@ -314,10 +314,10 @@ void LibertyParser::error() void LibertyParser::error(const std::string &str) { - std::stringstream ss; - ss << "Syntax error in liberty file on line " << line << ".\n"; - ss << " " << str << "\n"; - log_error("%s", ss.str().c_str()); + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + log_error("%s", ss.str().c_str()); } #else @@ -330,32 +330,32 @@ void LibertyParser::error() void LibertyParser::error(const std::string &str) { - std::stringstream ss; - ss << "Syntax error in liberty file on line " << line << ".\n"; - ss << " " << str << "\n"; - printf("%s", ss.str().c_str()); - exit(1); + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + printf("%s", ss.str().c_str()); + exit(1); } /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ #define CHECK_NV(result, check) \ do { \ - auto _R = (result); \ - if (!(_R check)) { \ - fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ - #result, (long int)_R, #check, __FILE__, __LINE__); \ - abort(); \ - } \ + auto _R = (result); \ + if (!(_R check)) { \ + fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ + #result, (long int)_R, #check, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) #define CHECK_COND(result) \ do { \ - if (!(result)) { \ - fprintf(stderr, "Error from '%s' in %s:%d.\n", \ - #result, __FILE__, __LINE__); \ - abort(); \ - } \ + if (!(result)) { \ + fprintf(stderr, "Error from '%s' in %s:%d.\n", \ + #result, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ -- cgit v1.2.3 From ddc1a4488e9fc10f557e4260df0becbc1cf43f72 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 25 Mar 2019 19:49:00 +0100 Subject: Add "cutpoint" pass Signed-off-by: Clifford Wolf --- passes/sat/Makefile.inc | 1 + passes/sat/cutpoint.cc | 164 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 passes/sat/cutpoint.cc (limited to 'passes') diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 4eced2ff1..fc3ac879e 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -11,4 +11,5 @@ OBJS += passes/sat/async2sync.o OBJS += passes/sat/supercover.o OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o +OBJS += passes/sat/cutpoint.o diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc new file mode 100644 index 000000000..3a38ebac0 --- /dev/null +++ b/passes/sat/cutpoint.cc @@ -0,0 +1,164 @@ +/* + * 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" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct CutpointPass : public Pass { + CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" cutpoint [options] [selection]\n"); + log("\n"); + log("This command adds formal cut points to the design.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing CUTPOINT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + if (design->selected_whole_module(module->name)) { + log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); + module->new_connections(std::vector()); + for (auto cell : vector(module->cells())) + module->remove(cell); + vector output_wires; + for (auto wire : module->wires()) + if (wire->port_output) + output_wires.push_back(wire); + for (auto wire : output_wires) + module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire))); + continue; + } + + SigMap sigmap(module); + pool cutpoint_bits; + + for (auto cell : module->selected_cells()) { + if (cell->type == "$anyseq") + continue; + log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell)); + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) + module->connect(conn.second, module->Anyseq(NEW_ID, GetSize(conn.second))); + } + module->remove(cell); + } + + for (auto wire : module->selected_wires()) { + if (wire->port_output) { + log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire)); + Wire *new_wire = module->addWire(NEW_ID, wire); + module->swap_names(wire, new_wire); + module->connect(new_wire, module->Anyseq(NEW_ID, GetSize(new_wire))); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + continue; + } + log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire)); + for (auto bit : sigmap(wire)) + cutpoint_bits.insert(bit); + } + + if (!cutpoint_bits.empty()) + { + for (auto cell : module->cells()) { + for (auto &conn : cell->connections()) { + if (!cell->output(conn.first)) + continue; + SigSpec sig = sigmap(conn.second); + int bit_count = 0; + for (auto &bit : sig) { + if (cutpoint_bits.count(bit)) + bit_count++; + } + if (bit_count == 0) + continue; + SigSpec dummy = module->addWire(NEW_ID, bit_count); + bit_count = 0; + for (auto &bit : sig) { + if (cutpoint_bits.count(bit)) + bit = dummy[bit_count++]; + } + cell->setPort(conn.first, sig); + } + } + + vector rewrite_wires; + for (auto wire : module->wires()) { + if (!wire->port_input) + continue; + int bit_count = 0; + for (auto &bit : sigmap(wire)) + if (cutpoint_bits.count(bit)) + bit_count++; + if (bit_count) + rewrite_wires.push_back(wire); + } + + for (auto wire : rewrite_wires) { + Wire *new_wire = module->addWire(NEW_ID, wire); + SigSpec lhs, rhs, sig = sigmap(wire); + for (int i = 0; i < GetSize(sig); i++) + if (!cutpoint_bits.count(sig[i])) { + lhs.append(SigBit(wire, i)); + rhs.append(SigBit(new_wire, i)); + } + if (GetSize(lhs)) + module->connect(lhs, rhs); + module->swap_names(wire, new_wire); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + } + + SigSpec sig(cutpoint_bits); + sig.sort_and_unify(); + + for (auto chunk : sig.chunks()) { + SigSpec s(chunk); + module->connect(s, module->Anyseq(NEW_ID, GetSize(s))); + } + } + } + } +} CutpointPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From d0b9b1bece9866fd7b0e153c991fc7e9b57a1efc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 26 Mar 2019 14:51:35 +0100 Subject: Add "hdlname" attribute Signed-off-by: Clifford Wolf --- passes/hierarchy/uniquify.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes') diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc index c88ecd82e..e6154e94f 100644 --- a/passes/hierarchy/uniquify.cc +++ b/passes/hierarchy/uniquify.cc @@ -87,6 +87,8 @@ struct UniquifyPass : public Pass { smod->name = newname; cell->type = newname; smod->set_bool_attribute("\\unique"); + if (smod->attributes.count("\\hdlname") == 0) + smod->attributes["\\hdlname"] = string(log_id(tmod->name)); design->add(smod); did_something = true; -- cgit v1.2.3 From 38b3fbd3f0bbdace11a3ab7b3d153b1a05059378 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 26 Mar 2019 16:01:14 +0100 Subject: Add "cutpoint -undef" Signed-off-by: Clifford Wolf --- passes/sat/cutpoint.cc | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'passes') diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 3a38ebac0..048aec7f3 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -33,20 +33,24 @@ struct CutpointPass : public Pass { log("\n"); log("This command adds formal cut points to the design.\n"); log("\n"); + log(" -undef\n"); + log(" set cupoint nets to undef (x). the default behavior is to create a\n"); + log(" $anyseq cell and drive the cutpoint net from that\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - // bool flag_noinit = false; + bool flag_undef = false; log_header(design, "Executing CUTPOINT pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-noinit") { - // flag_noinit = true; - // continue; - // } + if (args[argidx] == "-undef") { + flag_undef = true; + continue; + } break; } extra_args(args, argidx, design); @@ -63,7 +67,7 @@ struct CutpointPass : public Pass { if (wire->port_output) output_wires.push_back(wire); for (auto wire : output_wires) - module->connect(wire, module->Anyseq(NEW_ID, GetSize(wire))); + module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire))); continue; } @@ -76,7 +80,7 @@ struct CutpointPass : public Pass { log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell)); for (auto &conn : cell->connections()) { if (cell->output(conn.first)) - module->connect(conn.second, module->Anyseq(NEW_ID, GetSize(conn.second))); + module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second))); } module->remove(cell); } @@ -86,7 +90,7 @@ struct CutpointPass : public Pass { log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire)); Wire *new_wire = module->addWire(NEW_ID, wire); module->swap_names(wire, new_wire); - module->connect(new_wire, module->Anyseq(NEW_ID, GetSize(new_wire))); + module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire))); wire->port_id = 0; wire->port_input = false; wire->port_output = false; @@ -142,7 +146,7 @@ struct CutpointPass : public Pass { rhs.append(SigBit(new_wire, i)); } if (GetSize(lhs)) - module->connect(lhs, rhs); + module->connect(lhs, rhs); module->swap_names(wire, new_wire); wire->port_id = 0; wire->port_input = false; @@ -154,7 +158,7 @@ struct CutpointPass : public Pass { for (auto chunk : sig.chunks()) { SigSpec s(chunk); - module->connect(s, module->Anyseq(NEW_ID, GetSize(s))); + module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s))); } } } -- cgit v1.2.3 From d351b7cb99efe8c412ef7fa8bc0b99b72bc56726 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Mar 2019 13:33:26 +0100 Subject: Improve "rename" help message Signed-off-by: Clifford Wolf --- passes/cmds/rename.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'passes') diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 698ce7235..466a5da53 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -108,15 +108,19 @@ struct RenamePass : public Pass { log("Rename the specified object. Note that selection patterns are not supported\n"); log("by this command.\n"); log("\n"); + log("\n"); log(" rename -src [selection]\n"); log("\n"); log("Assign names auto-generated from the src attribute to all selected wires and\n"); log("cells with private names.\n"); log("\n"); + log("\n"); log(" rename -wire [selection]\n"); + log("\n"); log("Assign auto-generated names based on the wires they drive to all selected\n"); log("cells with private names. Ignores cells driving privatly named wires.\n"); log("\n"); + log("\n"); log(" rename -enumerate [-pattern ] [selection]\n"); log("\n"); log("Assign short auto-generated names to all selected wires and cells with private\n"); @@ -124,11 +128,13 @@ struct RenamePass : public Pass { log("The character %% in the pattern is replaced with a integer number. The default\n"); log("pattern is '_%%_'.\n"); log("\n"); + log("\n"); log(" rename -hide [selection]\n"); log("\n"); log("Assign private names (the ones with $-prefix) to all selected wires and cells\n"); log("with public names. This ignores all selected ports.\n"); log("\n"); + log("\n"); log(" rename -top new_name\n"); log("\n"); log("Rename top module.\n"); -- cgit v1.2.3 From 2c7fe42ad158a9859895399bdd876f5dbb2c7376 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 27 Mar 2019 13:47:42 +0100 Subject: Add "rename -output" Signed-off-by: Clifford Wolf --- passes/cmds/rename.cc | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'passes') diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 466a5da53..9b1830b7b 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name) +static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output) { from_name = RTLIL::escape_id(from_name); to_name = RTLIL::escape_id(to_name); @@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std:: Wire *w = it.second; log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module)); module->rename(w, to_name); - if (w->port_id) + if (w->port_id || flag_output) { + if (flag_output) + w->port_output = true; module->fixup_ports(); + } return; } for (auto &it : module->cells_) if (it.first == from_name) { + if (flag_output) + log_cmd_error("Called with -output but the specified object is a cell.\n"); log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module)); module->rename(it.second, to_name); return; @@ -109,6 +114,13 @@ struct RenamePass : public Pass { log("by this command.\n"); log("\n"); log("\n"); + log("\n"); + log(" rename -output old_name new_name\n"); + log("\n"); + log("Like above, but also make the wire an output. This will fail if the object is\n"); + log("not a wire.\n"); + log("\n"); + log("\n"); log(" rename -src [selection]\n"); log("\n"); log("Assign names auto-generated from the src attribute to all selected wires and\n"); @@ -148,6 +160,7 @@ struct RenamePass : public Pass { bool flag_enumerate = false; bool flag_hide = false; bool flag_top = false; + bool flag_output = false; bool got_mode = false; size_t argidx; @@ -159,6 +172,11 @@ struct RenamePass : public Pass { got_mode = true; continue; } + if (arg == "-output" && !got_mode) { + flag_output = true; + got_mode = true; + continue; + } if (arg == "-wire" && !got_mode) { flag_wire = true; got_mode = true; @@ -328,10 +346,12 @@ struct RenamePass : public Pass { if (!design->selected_active_module.empty()) { if (design->modules_.count(design->selected_active_module) > 0) - rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name); + rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output); } else { + if (flag_output) + log_cmd_error("Mode -output requires that there is an active module selected.\n"); for (auto &mod : design->modules_) { if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) { to_name = RTLIL::escape_id(to_name); -- cgit v1.2.3 From 487cb45b87ce1cbcc8c2b8127e37d85dd192dceb Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Wed, 27 Mar 2019 15:15:53 +0100 Subject: Liberty file parser now accepts superfluous ; --- passes/techmap/libparse.cc | 61 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) (limited to 'passes') diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 8eadd8735..510a24c24 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -155,11 +155,13 @@ int LibertyParser::lexer(std::string &str) // check for a backslash if (c == '\\') { - c = f.get(); + c = f.get(); if (c == '\r') c = f.get(); - if (c == '\n') + if (c == '\n') { + line++; return lexer(str); + } f.unget(); return '\\'; } @@ -186,14 +188,39 @@ LibertyAst *LibertyParser::parse() int tok = lexer(str); - while (tok == 'n') + // there are liberty files in the while that + // have superfluous ';' at the end of + // a { ... }. We simply ignore a ';' here. + // and get to the next statement. + + while ((tok == 'n') || (tok == ';')) tok = lexer(str); if (tok == '}' || tok < 0) return NULL; - if (tok != 'v') - error(); + if (tok != 'v') { + std::string eReport; + switch(tok) + { + case 'n': + error("Unexpected newline."); + break; + case '[': + case ']': + case '}': + case '{': + case '\"': + case ':': + eReport = "Unexpected '"; + eReport += static_cast(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } LibertyAst *ast = new LibertyAst; ast->id = str; @@ -282,8 +309,28 @@ LibertyAst *LibertyParser::parse() } continue; } - if (tok != 'v') - error(); + if (tok != 'v') { + std::string eReport; + switch(tok) + { + case 'n': + error("Unexpected newline."); + break; + case '[': + case ']': + case '}': + case '{': + case '\"': + case ':': + eReport = "Unexpected '"; + eReport += static_cast(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } ast->args.push_back(arg); } continue; -- cgit v1.2.3 From 263ab60b43f3994e83bfa46b793669147d765bcc Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Wed, 27 Mar 2019 15:17:58 +0100 Subject: Liberty file parser now accepts superfluous ; --- passes/techmap/libparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'passes') diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 510a24c24..991cc4498 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -188,7 +188,7 @@ LibertyAst *LibertyParser::parse() int tok = lexer(str); - // there are liberty files in the while that + // there are liberty files in the wild that // have superfluous ';' at the end of // a { ... }. We simply ignore a ';' here. // and get to the next statement. -- cgit v1.2.3 From 60594ad40cb51f6cf8a5e6ce61377b3405b873a8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 27 Mar 2019 17:19:14 +0000 Subject: memory_bram: Reset make_transp when growing read ports Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes') diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index c38eabaee..85ed1c053 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -641,6 +641,7 @@ grow_read_ports:; pi.sig_data = SigSpec(); pi.sig_en = SigSpec(); pi.make_outreg = false; + pi.make_transp = false; } new_portinfos.push_back(pi); if (pi.dupidx == dup_count-1) { -- cgit v1.2.3