aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/blackbox.cc26
-rw-r--r--passes/cmds/logger.cc16
-rw-r--r--passes/cmds/printattrs.cc90
-rw-r--r--passes/cmds/stat.cc2
-rw-r--r--passes/hierarchy/hierarchy.cc4
-rw-r--r--passes/memory/memory_share.cc2
-rw-r--r--passes/opt/opt_clean.cc31
-rw-r--r--passes/opt/opt_expr.cc194
-rw-r--r--passes/opt/opt_share.cc4
-rw-r--r--passes/opt/share.cc6
-rw-r--r--passes/opt/wreduce.cc4
-rw-r--r--passes/sat/qbfsat.cc410
-rw-r--r--passes/techmap/.gitignore1
-rw-r--r--passes/techmap/Makefile.inc12
-rw-r--r--passes/techmap/abc9.cc125
-rw-r--r--passes/techmap/abc9_ops.cc1144
-rw-r--r--passes/techmap/simplemap.cc6
-rw-r--r--passes/techmap/simplemap.h2
-rw-r--r--passes/techmap/techmap.cc338
-rw-r--r--passes/tests/test_cell.cc4
21 files changed, 1655 insertions, 767 deletions
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index a88980eaf..53bfd40c6 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -39,3 +39,4 @@ OBJS += passes/cmds/bugpoint.o
endif
OBJS += passes/cmds/scratchpad.o
OBJS += passes/cmds/logger.o
+OBJS += passes/cmds/printattrs.o
diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc
index 5c0405f15..b8297cd77 100644
--- a/passes/cmds/blackbox.cc
+++ b/passes/cmds/blackbox.cc
@@ -48,31 +48,7 @@ struct BlackboxPass : public Pass {
for (auto module : design->selected_whole_modules_warn())
{
- pool<Cell*> remove_cells;
- pool<Wire*> remove_wires;
-
- for (auto cell : module->cells())
- remove_cells.insert(cell);
-
- for (auto wire : module->wires())
- if (wire->port_id == 0)
- remove_wires.insert(wire);
-
- for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
- delete it->second;
- module->memories.clear();
-
- for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
- delete it->second;
- module->processes.clear();
-
- module->new_connections(std::vector<RTLIL::SigSig>());
-
- for (auto cell : remove_cells)
- module->remove(cell);
-
- module->remove(remove_wires);
-
+ module->makeblackbox();
module->set_bool_attribute(ID::blackbox);
}
}
diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc
index 9a27952d4..c9532eced 100644
--- a/passes/cmds/logger.cc
+++ b/passes/cmds/logger.cc
@@ -58,7 +58,8 @@ struct LoggerPass : public Pass {
log(" do not print warnings for the specified experimental feature\n");
log("\n");
log(" -expect <type> <regex> <expected_count>\n");
- log(" expect log,warning or error to appear. In case of error return code is 0.\n");
+ log(" expect log, warning or error to appear. matched errors will terminate\n");
+ log(" with exit code 0.\n");
log("\n");
log(" -expect-no-warnings\n");
log(" gives error in case there is at least one warning that is not expected.\n");
@@ -158,12 +159,13 @@ struct LoggerPass : public Pass {
log_cmd_error("Expected error message occurrences must be 1 !\n");
log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str());
try {
- if (type=="error")
- log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
- else if (type=="warning")
- log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
- else
- log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)));
+ if (type == "error")
+ log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else if (type == "warning")
+ log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else if (type == "log")
+ log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count);
+ else log_abort();
}
catch (const YS_REGEX_NS::regex_error& e) {
log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str());
diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc
new file mode 100644
index 000000000..80dbfa259
--- /dev/null
+++ b/passes/cmds/printattrs.cc
@@ -0,0 +1,90 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2020 Alberto Gonzalez <boqwxp@airmail.cc>
+ *
+ * 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct PrintAttrsPass : public Pass {
+ PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" printattrs [selection]\n");
+ log("\n");
+ log("Print all attributes of the selected objects.\n");
+ log("\n");
+ log("\n");
+ }
+
+ static std::string get_indent_str(const unsigned int indent) {
+ return stringf("%*s", indent, "");
+ }
+
+ static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) {
+ if (x.flags == RTLIL::CONST_FLAG_STRING)
+ log("%s(* %s=\"%s\" *)\n", get_indent_str(indent).c_str(), log_id(s), x.decode_string().c_str());
+ else if (x.flags == RTLIL::CONST_FLAG_NONE)
+ log("%s(* %s=%s *)\n", get_indent_str(indent).c_str(), log_id(s), x.as_string().c_str());
+ else
+ log_assert(x.flags == RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail
+ }
+
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
+
+ unsigned int indent = 0;
+ for (auto mod : design->selected_modules())
+ {
+ if (design->selected_whole_module(mod)) {
+ log("%s%s\n", get_indent_str(indent).c_str(), log_id(mod->name));
+ indent += 2;
+ for (auto &it : mod->attributes)
+ log_const(it.first, it.second, indent);
+ }
+
+ for (auto cell : mod->selected_cells()) {
+ log("%s%s\n", get_indent_str(indent).c_str(), log_id(cell->name));
+ indent += 2;
+ for (auto &it : cell->attributes)
+ log_const(it.first, it.second, indent);
+ indent -= 2;
+ }
+
+ for (auto wire : mod->selected_wires()) {
+ log("%s%s\n", get_indent_str(indent).c_str(), log_id(wire->name));
+ indent += 2;
+ for (auto &it : wire->attributes)
+ log_const(it.first, it.second, indent);
+ indent -= 2;
+ }
+
+ if (design->selected_whole_module(mod))
+ indent -= 2;
+ }
+
+ log("\n");
+ }
+} PrintAttrsPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 6c4bc0e5b..30436d829 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -109,7 +109,7 @@ struct statdata_t
ID($lut), ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
- ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), ID($alu))) {
+ ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) {
int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0;
int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0;
int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0;
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 95d74d1eb..f99d1509d 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -574,9 +574,9 @@ struct HierarchyPass : public Pass {
log("\n");
log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n");
- log("design an re-runs the language frontends for the parametric modules as\n");
+ log("design and re-runs the language frontends for the parametric modules as\n");
log("needed. It also resolves assignments to wired logic data types (wand/wor),\n");
- log("resolves positional module parameters, unroll array instances, and more.\n");
+ log("resolves positional module parameters, unrolls array instances, and more.\n");
log("\n");
log(" -check\n");
log(" also check the design hierarchy. this generates an error when\n");
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 477246687..e11958bd6 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -715,6 +715,8 @@ struct MemoryShareWorker
cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod));
cone_ct.cell_types.erase(ID($div));
+ cone_ct.cell_types.erase(ID($modfloor));
+ cone_ct.cell_types.erase(ID($divfloor));
cone_ct.cell_types.erase(ID($pow));
cone_ct.cell_types.erase(ID($shl));
cone_ct.cell_types.erase(ID($shr));
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6271376f1..f7de02164 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
return !del_wires_queue.empty();
}
-bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
+bool rmunused_module_init(RTLIL::Module *module, bool verbose)
{
bool did_something = false;
CellTypes fftypes;
@@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
for (auto wire : module->wires())
{
- if (!purge_mode && wire->name[0] == '\\')
- continue;
-
if (wire->attributes.count(ID::init) == 0)
continue;
@@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
if (wire_bit == mapped_wire_bit)
goto next_wire;
- if (qbits.count(sigmap(SigBit(wire, i))) == 0)
- goto next_wire;
+ if (mapped_wire_bit.wire) {
+ if (qbits.count(mapped_wire_bit) == 0)
+ goto next_wire;
- if (qbits.at(sigmap(SigBit(wire, i))) != init[i])
- goto next_wire;
+ if (qbits.at(mapped_wire_bit) != init[i])
+ goto next_wire;
+ }
+ else {
+ if (mapped_wire_bit == State::Sx || mapped_wire_bit == State::Sz)
+ goto next_wire;
+
+ if (mapped_wire_bit != init[i]) {
+ log_warning("Initial value conflict for %s resolving to %s but with init %s.\n", log_signal(wire_bit), log_signal(mapped_wire_bit), log_signal(init[i]));
+ goto next_wire;
+ }
+ }
}
if (verbose)
@@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
rmunused_module_cells(module, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { }
- if (rminit && rmunused_module_init(module, purge_mode, verbose))
+ if (rminit && rmunused_module_init(module, verbose))
while (rmunused_module_signals(module, purge_mode, verbose)) { }
}
@@ -611,8 +619,7 @@ struct CleanPass : public Pass {
}
break;
}
- if (argidx < args.size())
- extra_args(args, argidx, design);
+ extra_args(args, argidx, design);
keep_cache.reset(design);
@@ -627,7 +634,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
- rmunused_module(module, purge_mode, ys_debug(), false);
+ rmunused_module(module, purge_mode, ys_debug(), true);
}
log_suppressed();
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 0f5bff680..e5b8bda95 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -132,7 +132,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
did_something = true;
}
-bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
+bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc)
{
IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A;
@@ -156,20 +156,36 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
int group_idx = GRP_DYN;
RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
- if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
- bit_a = bit_b = RTLIL::State::S1;
-
- if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
- bit_a = bit_b = RTLIL::State::S0;
+ if (cell->type == ID($or)) {
+ if (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)
+ bit_a = bit_b = RTLIL::State::S1;
+ }
+ else if (cell->type == ID($and)) {
+ if (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)
+ bit_a = bit_b = RTLIL::State::S0;
+ }
+ else if (!keepdc) {
+ if (cell->type == ID($xor)) {
+ if (bit_a == bit_b)
+ bit_a = bit_b = RTLIL::State::S0;
+ }
+ else if (cell->type == ID($xnor)) {
+ if (bit_a == bit_b)
+ bit_a = bit_b = RTLIL::State::S1; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_
+ }
+ }
- if (bit_a.wire == NULL && bit_b.wire == NULL)
- group_idx = GRP_CONST_AB;
- else if (bit_a.wire == NULL)
- group_idx = GRP_CONST_A;
- else if (bit_b.wire == NULL && commutative)
- group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
- else if (bit_b.wire == NULL)
- group_idx = GRP_CONST_B;
+ bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sz);
+ if (def || !keepdc) {
+ if (bit_a.wire == NULL && bit_b.wire == NULL)
+ group_idx = GRP_CONST_AB;
+ else if (bit_a.wire == NULL)
+ group_idx = GRP_CONST_A;
+ else if (bit_b.wire == NULL && commutative)
+ group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
+ else if (bit_b.wire == NULL)
+ group_idx = GRP_CONST_B;
+ }
grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
}
@@ -186,26 +202,77 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
if (grouped_bits[i].empty())
continue;
- RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
+ RTLIL::SigSpec new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
RTLIL::SigSpec new_a, new_b;
RTLIL::SigSig new_conn;
for (auto &it : grouped_bits[i]) {
for (auto &bit : it.second) {
new_conn.first.append(bit);
- new_conn.second.append(RTLIL::SigBit(new_y, new_a.size()));
+ new_conn.second.append(new_y[new_a.size()]);
}
new_a.append(it.first.first);
new_b.append(it.first.second);
}
if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) {
+ if (!keepdc) {
+ if (cell->type == ID($and))
+ new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b);
+ else if (cell->type == ID($or))
+ new_a.replace(dict<SigBit,SigBit>{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b);
+ else log_abort();
+ }
log_debug(" 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;
}
+ if (cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) {
+ SigSpec undef_a, undef_y, undef_b;
+ SigSpec def_y, def_a, def_b;
+ for (int i = 0; i < GetSize(new_y); i++) {
+ bool undef = new_a[i] == State::Sx || new_a[i] == State::Sz;
+ if (!keepdc && (undef || new_a[i] == new_b[i])) {
+ undef_a.append(new_a[i]);
+ if (cell->type == ID($xor))
+ undef_b.append(State::S0);
+ // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
+ else if (cell->type == ID($xnor))
+ undef_b.append(State::S1);
+ else log_abort();
+ undef_y.append(new_y[i]);
+ }
+ else if (new_a[i] == State::S0 || new_a[i] == State::S1) {
+ undef_a.append(new_a[i]);
+ if (cell->type == ID($xor))
+ undef_b.append(new_a[i] == State::S1 ? module->Not(NEW_ID, new_b[i]).as_bit() : new_b[i]);
+ else if (cell->type == ID($xnor))
+ undef_b.append(new_a[i] == State::S1 ? new_b[i] : module->Not(NEW_ID, new_b[i]).as_bit());
+ else log_abort();
+ undef_y.append(new_y[i]);
+ }
+ else {
+ def_a.append(new_a[i]);
+ def_b.append(new_b[i]);
+ def_y.append(new_y[i]);
+ }
+ }
+ if (!undef_y.empty()) {
+ log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), log_id(cell->type), log_signal(undef_a));
+ module->connect(undef_y, undef_b);
+ if (def_y.empty()) {
+ module->connect(new_conn);
+ continue;
+ }
+ }
+ new_a = std::move(def_a);
+ new_b = std::move(def_b);
+ new_y = std::move(def_y);
+ }
+
+
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
c->setPort(ID::A, new_a);
@@ -219,7 +286,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
}
c->setPort(ID::Y, new_y);
- c->parameters[ID::Y_WIDTH] = new_y->width;
+ c->parameters[ID::Y_WIDTH] = GetSize(new_y);
c->check();
module->connect(new_conn);
@@ -476,13 +543,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- if (detect_const_and && (found_zero || found_inv)) {
+ if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_and");
replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
goto next_cell;
}
- if (detect_const_or && (found_one || found_inv)) {
+ if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_or");
replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
goto next_cell;
@@ -499,6 +566,22 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
SigBit sig_a = assign_map(cell->getPort(ID::A));
SigBit sig_b = assign_map(cell->getPort(ID::B));
+ if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) {
+ if (cell->type.in(ID($xor), ID($_XOR_))) {
+ cover("opt.opt_expr.const_xor");
+ replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0);
+ goto next_cell;
+ }
+ if (cell->type.in(ID($xnor), ID($_XNOR_))) {
+ cover("opt.opt_expr.const_xnor");
+ // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
+ int width = cell->getParam(ID::Y_WIDTH).as_int();
+ replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width));
+ goto next_cell;
+ }
+ log_abort();
+ }
+
if (!sig_a.wire)
std::swap(sig_a, sig_b);
if (sig_b == State::S0 || sig_b == State::S1) {
@@ -550,7 +633,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (do_fine)
{
if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor)))
- if (group_cell_inputs(module, cell, true, assign_map))
+ if (group_cell_inputs(module, cell, true, assign_map, keepdc))
goto next_cell;
if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool)))
@@ -781,7 +864,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
skip_fine_alu:
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
- ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow)))
+ ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
{
RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
@@ -800,7 +883,7 @@ skip_fine_alu:
if (0) {
found_the_x_bit:
cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
- "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
+ "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str());
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else
@@ -904,8 +987,10 @@ skip_fine_alu:
if (input.match("01")) ACTION_DO_Y(1);
if (input.match("10")) ACTION_DO_Y(1);
if (input.match("11")) ACTION_DO_Y(0);
- if (input.match(" *")) ACTION_DO_Y(x);
- if (input.match("* ")) ACTION_DO_Y(x);
+ if (consume_x) {
+ if (input.match(" *")) ACTION_DO_Y(0);
+ if (input.match("* ")) ACTION_DO_Y(0);
+ }
}
if (cell->type == ID($_MUX_)) {
@@ -1088,7 +1173,7 @@ skip_fine_alu:
goto next_cell;
}
- if (!keepdc)
+ if (consume_x)
{
bool identity_wrt_a = false;
bool identity_wrt_b = false;
@@ -1384,6 +1469,8 @@ skip_identity:
FOLD_2ARG_CELL(mul)
FOLD_2ARG_CELL(div)
FOLD_2ARG_CELL(mod)
+ FOLD_2ARG_CELL(divfloor)
+ FOLD_2ARG_CELL(modfloor)
FOLD_2ARG_CELL(pow)
FOLD_1ARG_CELL(pos)
@@ -1498,9 +1585,11 @@ skip_identity:
}
}
- if (!keepdc && cell->type.in(ID($div), ID($mod)))
+ if (!keepdc && cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor)))
{
+ bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
+ SigSpec sig_a = assign_map(cell->getPort(ID::A));
SigSpec sig_b = assign_map(cell->getPort(ID::B));
SigSpec sig_y = assign_map(cell->getPort(ID::Y));
@@ -1525,11 +1614,13 @@ skip_identity:
for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
if (b_val == (1 << i))
{
- if (cell->type == ID($div))
+ if (cell->type.in(ID($div), ID($divfloor)))
{
cover("opt.opt_expr.div_shift");
- log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ bool is_truncating = cell->type == ID($div);
+ log_debug("Replacing %s-divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ is_truncating ? "truncating" : "flooring",
b_val, cell->name.c_str(), module->name.c_str(), i);
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@@ -1537,17 +1628,35 @@ skip_identity:
while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back();
- cell->type = ID($shr);
+ cell->type = ID($sshr);
cell->parameters[ID::B_WIDTH] = GetSize(new_b);
cell->parameters[ID::B_SIGNED] = false;
cell->setPort(ID::B, new_b);
+
+ // Truncating division is the same as flooring division, except when
+ // the result is negative and there is a remainder - then trunc = floor + 1
+ if (is_truncating && a_signed) {
+ Wire *flooring = module->addWire(NEW_ID, sig_y.size());
+ cell->setPort(ID::Y, flooring);
+
+ Wire *result_neg = module->addWire(NEW_ID);
+ module->addXor(NEW_ID, sig_a[sig_a.size()-1], sig_b[sig_b.size()-1], result_neg);
+ Wire *rem_nonzero = module->addWire(NEW_ID);
+ module->addReduceOr(NEW_ID, sig_a.extract(0, i), rem_nonzero);
+ Wire *should_add = module->addWire(NEW_ID);
+ module->addAnd(NEW_ID, result_neg, rem_nonzero, should_add);
+ module->addAdd(NEW_ID, flooring, should_add, sig_y);
+ }
+
cell->check();
}
- else
+ else if (cell->type.in(ID($mod), ID($modfloor)))
{
cover("opt.opt_expr.mod_mask");
- log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
+ bool is_truncating = cell->type == ID($mod);
+ log_debug("Replacing %s-modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
+ is_truncating ? "truncating" : "flooring",
b_val, cell->name.c_str(), module->name.c_str());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@@ -1558,6 +1667,24 @@ skip_identity:
cell->type = ID($and);
cell->parameters[ID::B_WIDTH] = GetSize(new_b);
cell->setPort(ID::B, new_b);
+
+ // truncating modulo has the same masked bits as flooring modulo, but
+ // the sign bits are those of A (except when R=0)
+ if (is_truncating && a_signed) {
+ Wire *flooring = module->addWire(NEW_ID, sig_y.size());
+ cell->setPort(ID::Y, flooring);
+ SigSpec truncating = SigSpec(flooring).extract(0, i);
+
+ Wire *rem_nonzero = module->addWire(NEW_ID);
+ module->addReduceOr(NEW_ID, truncating, rem_nonzero);
+ SigSpec a_sign = sig_a[sig_a.size()-1];
+ Wire *extend_bit = module->addWire(NEW_ID);
+ module->addAnd(NEW_ID, a_sign, rem_nonzero, extend_bit);
+
+ truncating.append(extend_bit);
+ module->addPos(NEW_ID, truncating, sig_y, true);
+ }
+
cell->check();
}
@@ -1980,11 +2107,12 @@ struct OptExprPass : public Pass {
do {
do {
did_something = false;
- replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv);
+ replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
- replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
+ if (!keepdc)
+ replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 1f69c98f4..cbace7bac 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -103,7 +103,7 @@ bool cell_supported(RTLIL::Cell *cell)
if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci)
return true;
- } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) {
+ } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat))) {
return true;
}
@@ -130,7 +130,7 @@ bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b)
RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name)
{
- if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID::B)
+ if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat), SHIFT_OPS) && port_name == ID::B)
return port_name;
return "";
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 2839507b0..988253edf 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -376,7 +376,7 @@ struct ShareWorker
continue;
}
- if (cell->type.in(ID($mul), ID($div), ID($mod))) {
+ if (cell->type.in(ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
if (config.opt_aggressive || cell->parameters.at(ID::Y_WIDTH).as_int() >= 4)
shareable_cells.insert(cell);
continue;
@@ -1133,6 +1133,8 @@ struct ShareWorker
cone_ct.cell_types.erase(ID($mul));
cone_ct.cell_types.erase(ID($mod));
cone_ct.cell_types.erase(ID($div));
+ cone_ct.cell_types.erase(ID($modfloor));
+ cone_ct.cell_types.erase(ID($divfloor));
cone_ct.cell_types.erase(ID($pow));
cone_ct.cell_types.erase(ID($shl));
cone_ct.cell_types.erase(ID($shr));
@@ -1512,6 +1514,8 @@ struct SharePass : public Pass {
config.generic_bin_ops.insert(ID($sub));
config.generic_bin_ops.insert(ID($div));
config.generic_bin_ops.insert(ID($mod));
+ config.generic_bin_ops.insert(ID($divfloor));
+ config.generic_bin_ops.insert(ID($modfloor));
// config.generic_bin_ops.insert(ID($pow));
config.generic_uni_ops.insert(ID($logic_not));
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 195400bf0..f60f2f8a8 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -37,7 +37,7 @@ struct WreduceConfig
ID($and), ID($or), ID($xor), ID($xnor),
ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx),
ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt),
- ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($pow),
+ ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow),
ID($mux), ID($pmux),
ID($dff), ID($adff)
});
@@ -545,7 +545,7 @@ struct WreducePass : public Pass {
}
}
- if (c->type.in(ID($div), ID($mod), ID($pow)))
+ if (c->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
{
SigSpec A = c->getPort(ID::A);
int original_a_width = GetSize(A);
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
index d99ca1b53..d6dbf8ef4 100644
--- a/passes/sat/qbfsat.cc
+++ b/passes/sat/qbfsat.cc
@@ -19,22 +19,12 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
+#include "kernel/consteval.h"
#include "kernel/log.h"
#include "kernel/rtlil.h"
#include "kernel/register.h"
-#include <cstdio>
#include <algorithm>
-#if defined(_WIN32)
-# define WIFEXITED(x) 1
-# define WIFSIGNALED(x) 0
-# define WIFSTOPPED(x) 0
-# define WEXITSTATUS(x) ((x) & 0xff)
-# define WTERMSIG(x) SIGTERM
-#else
-# include <sys/wait.h>
-#endif
-
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -43,26 +33,47 @@ struct QbfSolutionType {
dict<std::string, std::string> hole_to_value;
bool sat;
bool unknown; //true if neither 'sat' nor 'unsat'
- bool success; //true if exit code 0
- QbfSolutionType() : sat(false), unknown(true), success(false) {}
+ QbfSolutionType() : sat(false), unknown(true) {}
};
struct QbfSolveOptions {
bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg;
+ bool nooptimize, nobisection;
bool sat, unsat, show_smtbmc;
+ enum Solver{Z3, Yices, CVC4} solver;
+ int timeout;
std::string specialize_soln_file;
std::string write_soln_soln_file;
std::string dump_final_smt2_file;
size_t argidx;
QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false),
nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false),
- sat(false), unsat(false), show_smtbmc(false), argidx(0) {};
+ nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false),
+ solver(Yices), timeout(0), argidx(0) {};
};
+std::string get_solver_name(const QbfSolveOptions &opt) {
+ if (opt.solver == opt.Solver::Z3)
+ return "z3";
+ else if (opt.solver == opt.Solver::Yices)
+ return "yices";
+ else if (opt.solver == opt.Solver::CVC4)
+ return "cvc4";
+ else
+ log_cmd_error("unknown solver specified.\n");
+ return "";
+}
+
void recover_solution(QbfSolutionType &sol) {
YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED");
YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available");
+ YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED");
+ YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)");
+ YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)");
+ YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)");
+ YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver");
+ YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\"");
YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)");
#ifndef NDEBUG
YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+");
@@ -82,10 +93,40 @@ void recover_solution(QbfSolutionType &sol) {
#endif
sol.hole_to_value[loc] = val;
}
- else if (YS_REGEX_NS::regex_search(x, sat_regex))
+ else if (YS_REGEX_NS::regex_search(x, sat_regex)) {
sat_regex_found = true;
- else if (YS_REGEX_NS::regex_search(x, unsat_regex))
+ sol.sat = true;
+ sol.unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, unsat_regex)) {
+ unsat_regex_found = true;
+ sol.sat = false;
+ sol.unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, memout_regex)) {
+ sol.unknown = true;
+ log_warning("solver ran out of memory\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, timeout_regex)) {
+ sol.unknown = true;
+ log_warning("solver timed out\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) {
+ sol.unknown = true;
+ log_warning("solver timed out\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, unknown_regex)) {
+ sol.unknown = true;
+ log_warning("solver returned \"unknown\"\n");
+ }
+ else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) {
unsat_regex_found = true;
+ sol.sat = false;
+ sol.unknown = false;
+ }
+ else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) {
+ sol.unknown = true;
+ }
}
#ifndef NDEBUG
log_assert(!sol.unknown && sol.sat? sat_regex_found : true);
@@ -107,6 +148,40 @@ dict<std::string, std::string> get_hole_loc_name_map(RTLIL::Module *module, cons
return hole_loc_to_name;
}
+pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
+ bool found_input = false;
+ bool found_hole = false;
+ bool found_1bit_output = false;
+ bool found_assert_assume = false;
+ pool<std::string> input_wires;
+ for (auto wire : module->wires()) {
+ if (wire->port_input) {
+ found_input = true;
+ input_wires.insert(wire->name.str());
+ }
+ if (wire->port_output && wire->width == 1)
+ found_1bit_output = true;
+ }
+ for (auto cell : module->cells()) {
+ if (cell->type == "$allconst")
+ found_input = true;
+ if (cell->type == "$anyconst")
+ found_hole = true;
+ if (cell->type.in("$assert", "$assume"))
+ found_assert_assume = true;
+ }
+ if (!found_input)
+ log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
+ if (!found_hole)
+ log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
+ if (!found_1bit_output && !found_assert_assume)
+ log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
+ if (!found_assert_assume && !opt.assume_outputs)
+ log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
+
+ return input_wires;
+}
+
void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) {
std::ofstream fout(file.c_str());
if (!fout)
@@ -164,7 +239,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) {
}
}
-void specialize(RTLIL::Module *module, const QbfSolutionType &sol) {
+void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = false) {
dict<std::string, std::string> hole_loc_to_name = get_hole_loc_name_map(module, sol);
pool<RTLIL::Cell *> anyconsts_to_remove;
for (auto cell : module->cells())
@@ -189,7 +264,8 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol) {
log_assert(wire->width > 0 && GetSize(hole_value) == wire->width);
#endif
- log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
+ if (!quiet)
+ log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str());
std::vector<RTLIL::SigBit> value_bv;
value_bv.reserve(wire->width);
for (char c : hole_value)
@@ -219,7 +295,6 @@ void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) {
value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0);
std::reverse(value_bv.begin(), value_bv.end());
}
-
}
void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wires) {
@@ -280,84 +355,145 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1);
}
-QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
+QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, const std::string &tempdir_name, const bool quiet = false, const int iter_num = 0) {
+ //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]`
QbfSolutionType ret;
const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc";
+ const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2";
const std::string smtbmc_warning = "z3: WARNING:";
- const bool show_smtbmc = opt.show_smtbmc;
+ const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1";
- const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
- const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem.smt2";
-#ifndef NDEBUG
- log_assert(mod->design != nullptr);
-#endif
Pass::call(mod->design, smt2_command);
+
+ auto process_line = [&ret, &smtbmc_warning, &opt, &quiet](const std::string &line) {
+ ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
+ auto warning_pos = line.find(smtbmc_warning);
+ if (warning_pos != std::string::npos)
+ log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str());
+ else
+ if (opt.show_smtbmc && !quiet)
+ log("smtbmc output: %s", line.c_str());
+ };
log_header(mod->design, "Solving QBF-SAT problem.\n");
+ if (!quiet) log("Launching \"%s\".\n", smtbmc_cmd.c_str());
+ run_command(smtbmc_cmd, process_line);
- //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 <file>]`
- {
- const std::string cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem.smt2 2>&1";
- auto process_line = [&ret, &smtbmc_warning, &show_smtbmc](const std::string &line) {
- ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
- auto warning_pos = line.find(smtbmc_warning);
- if (warning_pos != std::string::npos)
- log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str());
- else
- if (show_smtbmc)
- log("smtbmc output: %s", line.c_str());
- };
-
- log("Launching \"%s\".\n", cmd.c_str());
- int retval = run_command(cmd, process_line);
- if (retval == 0) {
- ret.sat = true;
- ret.unknown = false;
- } else if (retval == 1) {
- ret.sat = false;
- ret.unknown = false;
- }
+ recover_solution(ret);
+ return ret;
+}
+
+QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
+ QbfSolutionType ret, best_soln;
+ const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX");
+ RTLIL::Module *module = mod;
+ RTLIL::Design *design = module->design;
+ std::string module_name = module->name.str();
+ RTLIL::Wire *wire_to_optimize = nullptr;
+ RTLIL::IdString wire_to_optimize_name;
+ bool maximize = false;
+ log_assert(module->design != nullptr);
+
+ Pass::call(design, "design -push-copy");
+
+ //Replace input wires with wires assigned $allconst cells:
+ pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
+ allconstify_inputs(module, input_wires);
+ if (opt.assume_outputs)
+ assume_miter_outputs(module, opt);
+
+ //Find the wire to be optimized, if any:
+ for (auto wire : module->wires())
+ if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize"))
+ wire_to_optimize = wire;
+ if (wire_to_optimize != nullptr) {
+ wire_to_optimize_name = wire_to_optimize->name;
+ maximize = wire_to_optimize->get_bool_attribute("\\maximize");
}
- if(!opt.nocleanup)
- remove_directory(tempdir_name);
+ if (opt.nobisection || opt.nooptimize) {
+ if (wire_to_optimize != nullptr && opt.nooptimize) {
+ wire_to_optimize->set_bool_attribute("\\maximize", false);
+ wire_to_optimize->set_bool_attribute("\\minimize", false);
+ }
+ ret = call_qbf_solver(module, opt, tempdir_name, false, 0);
+ } else {
+ //Do the iterated bisection method:
+ unsigned int iter_num = 1;
+ unsigned int success = 0;
+ unsigned int failure = 0;
+ unsigned int cur_thresh = 0;
+
+ log_assert(wire_to_optimize != nullptr);
+ log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize));
+
+ //If maximizing, grow until we get a failure. Then bisect success and failure.
+ while (failure == 0 || success - failure > 1) {
+ Pass::call(design, "design -push-copy");
+ log_header(design, "Preparing QBF-SAT problem.\n");
- recover_solution(ret);
+ if (cur_thresh != 0) {
+ //Add thresholding logic (but not on the initial run when we don't have a sense of where to start):
+ RTLIL::SigSpec comparator = maximize? module->Ge(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false)
+ : module->Le(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false);
- return ret;
-}
+ module->addAssume(wire_to_optimize_name.str() + "__threshold", comparator, RTLIL::Const(1, 1));
+ log("Trying to solve with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), cur_thresh);
+ }
-pool<std::string> validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) {
- bool found_input = false;
- bool found_hole = false;
- bool found_1bit_output = false;
- bool found_assert_assume = false;
- pool<std::string> input_wires;
- for (auto wire : module->wires()) {
- if (wire->port_input) {
- found_input = true;
- input_wires.insert(wire->name.str());
+ ret = call_qbf_solver(module, opt, tempdir_name, false, iter_num);
+ Pass::call(design, "design -pop");
+ module = design->module(module_name);
+
+ if (!ret.unknown && ret.sat) {
+ Pass::call(design, "design -push-copy");
+ specialize(module, ret, true);
+
+ RTLIL::SigSpec wire, value, undef;
+ RTLIL::SigSpec::parse_sel(wire, design, module, wire_to_optimize_name.str());
+
+ ConstEval ce(module);
+ value = wire;
+ if (!ce.eval(value, undef))
+ log_cmd_error("Failed to evaluate signal %s: Missing value for %s.\n", log_signal(wire), log_signal(undef));
+ log_assert(value.is_fully_const());
+ success = value.as_const().as_int();
+ best_soln = ret;
+ log("Problem is satisfiable with %s = %d.\n", wire_to_optimize_name.c_str(), success);
+ Pass::call(design, "design -pop");
+ module = design->module(module_name);
+
+ //sometimes this happens if we get an 'unknown' or timeout
+ if (!maximize && success < failure)
+ break;
+ else if (maximize && success > failure)
+ break;
+ } else {
+ //Treat 'unknown' as UNSAT
+ failure = cur_thresh;
+ if (failure == 0) {
+ log("Problem is NOT satisfiable.\n");
+ break;
+ }
+ else
+ log("Problem is NOT satisfiable with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), failure);
+ }
+
+ iter_num++;
+ cur_thresh = (maximize && failure == 0)? 2 * success //growth
+ : (success + failure) / 2; //bisection
+ }
+ if (success != 0 || failure != 0) {
+ log("Wire %s is %s at %d.\n", wire_to_optimize_name.c_str(), (maximize? "maximized" : "minimized"), success);
+ ret = best_soln;
}
- if (wire->port_output && wire->width == 1)
- found_1bit_output = true;
- }
- for (auto cell : module->cells()) {
- if (cell->type == "$allconst")
- found_input = true;
- if (cell->type == "$anyconst")
- found_hole = true;
- if (cell->type.in("$assert", "$assume"))
- found_assert_assume = true;
}
- if (!found_input)
- log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n");
- if (!found_hole)
- log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n");
- if (!found_1bit_output && !found_assert_assume)
- log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n");
- if (!found_assert_assume && !opt.assume_outputs)
- log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n");
- return input_wires;
+ if(!opt.nocleanup)
+ remove_directory(tempdir_name);
+
+ Pass::call(design, "design -pop");
+
+ return ret;
}
QbfSolveOptions parse_args(const std::vector<std::string> &args) {
@@ -379,6 +515,43 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) {
opt.assume_neg = true;
continue;
}
+ else if (args[opt.argidx] == "-nooptimize") {
+ opt.nooptimize = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-nobisection") {
+ opt.nobisection = true;
+ continue;
+ }
+ else if (args[opt.argidx] == "-solver") {
+ if (args.size() <= opt.argidx + 1)
+ log_cmd_error("solver not specified.\n");
+ else {
+ if (args[opt.argidx+1] == "z3")
+ opt.solver = opt.Solver::Z3;
+ else if (args[opt.argidx+1] == "yices")
+ opt.solver = opt.Solver::Yices;
+ else if (args[opt.argidx+1] == "cvc4")
+ opt.solver = opt.Solver::CVC4;
+ else
+ log_cmd_error("Unknown solver \"%s\".\n", args[opt.argidx+1].c_str());
+ opt.argidx++;
+ }
+ continue;
+ }
+ else if (args[opt.argidx] == "-timeout") {
+ if (args.size() <= opt.argidx + 1)
+ log_cmd_error("timeout not specified.\n");
+ else {
+ int timeout = atoi(args[opt.argidx+1].c_str());
+ if (timeout > 0)
+ opt.timeout = timeout;
+ else
+ log_cmd_error("timeout must be greater than 0.\n");
+ opt.argidx++;
+ }
+ continue;
+ }
else if (args[opt.argidx] == "-sat") {
opt.sat = true;
continue;
@@ -456,27 +629,43 @@ struct QbfSatPass : public Pass {
log("\n");
log(" qbfsat [options] [selection]\n");
log("\n");
- log("This command solves a 2QBF-SAT problem defined over the currently selected module.\n");
- log("Existentially-quantified variables are declared by assigning a wire \"$anyconst\".\n");
- log("Universally-quantified variables may be explicitly declared by assigning a wire\n");
- log("\"$allconst\", but module inputs will be treated as universally-quantified variables\n");
- log("by default.\n");
+ log("This command solves an \"exists-forall\" 2QBF-SAT problem defined over the currently\n");
+ log("selected module. Existentially-quantified variables are declared by assigning a wire\n");
+ log("\"$anyconst\". Universally-quantified variables may be explicitly declared by assigning\n");
+ log("a wire \"$allconst\", but module inputs will be treated as universally-quantified\n");
+ log("variables by default.\n");
log("\n");
log(" -nocleanup\n");
- log(" Do not delete temporary files and directories. Useful for\n");
- log(" debugging.\n");
+ log(" Do not delete temporary files and directories. Useful for debugging.\n");
log("\n");
log(" -dump-final-smt2 <file>\n");
log(" Pass the --dump-smt2 option to yosys-smtbmc.\n");
log("\n");
log(" -assume-outputs\n");
- log(" Add an $assume cell for the conjunction of all one-bit module output wires.\n");
+ log(" Add an \"$assume\" cell for the conjunction of all one-bit module output wires.\n");
log("\n");
log(" -assume-negative-polarity\n");
log(" When adding $assume cells for one-bit module output wires, assume they are\n");
log(" negative polarity signals and should always be low, for example like the\n");
log(" miters created with the `miter` command.\n");
log("\n");
+ log(" -nooptimize\n");
+ log(" Ignore \"\\minimize\" and \"\\maximize\" attributes, do not emit \"(maximize)\" or\n");
+ log(" \"(minimize)\" in the SMT-LIBv2, and generally make no attempt to optimize anything.\n");
+ log("\n");
+ log(" -nobisection\n");
+ log(" If a wire is marked with the \"\\minimize\" or \"\\maximize\" attribute, do not\n");
+ log(" attempt to optimize that value with the default iterated solving and threshold\n");
+ log(" bisection approach. Instead, have yosys-smtbmc emit a \"(minimize)\" or \"(maximize)\"\n");
+ log(" command in the SMT-LIBv2 output and hope that the solver supports optimizing\n");
+ log(" quantified bitvector problems.\n");
+ log("\n");
+ log(" -solver <solver>\n");
+ log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n");
+ log("\n");
+ log(" -timeout <value>\n");
+ log(" Set the per-iteration timeout in seconds.\n");
+ log("\n");
log(" -sat\n");
log(" Generate an error if the solver does not return \"sat\".\n");
log("\n");
@@ -487,15 +676,16 @@ struct QbfSatPass : public Pass {
log(" Print the output from yosys-smtbmc.\n");
log("\n");
log(" -specialize\n");
- log(" Replace all \"$anyconst\" cells with constant values determined by the solver.\n");
+ log(" If the problem is satisfiable, replace each \"$anyconst\" cell with its\n");
+ log(" corresponding constant value from the model produced by the solver.\n");
log("\n");
log(" -specialize-from-file <solution file>\n");
- log(" Do not run the solver, but instead only attempt to replace all \"$anyconst\"\n");
- log(" cells in the current module with values provided by the specified file.\n");
+ log(" Do not run the solver, but instead only attempt to replace each \"$anyconst\"\n");
+ log(" cell in the current module with a constant value provided by the specified file.\n");
log("\n");
log(" -write-solution <solution file>\n");
- log(" Write the assignments discovered by the solver for all \"$anyconst\" cells\n");
- log(" to the specified file.");
+ log(" If the problem is satisfiable, write the corresponding constant value for each\n");
+ log(" \"$anyconst\" cell from the model produced by the solver to the specified file.");
log("\n");
log("\n");
}
@@ -519,26 +709,15 @@ struct QbfSatPass : public Pass {
if (!opt.specialize_from_file) {
//Save the design to restore after modiyfing the current module.
std::string module_name = module->name.str();
- Pass::call(design, "design -push-copy");
-
- //Replace input wires with wires assigned $allconst cells.
- pool<std::string> input_wires = validate_design_and_get_inputs(module, opt);
- allconstify_inputs(module, input_wires);
- if (opt.assume_outputs)
- assume_miter_outputs(module, opt);
QbfSolutionType ret = qbf_solve(module, opt);
- Pass::call(design, "design -pop");
module = design->module(module_name);
-
- if (ret.unknown)
- log_warning("solver did not give an answer\n");
- else if (ret.sat)
+ if (ret.unknown) {
+ if (opt.sat || opt.unsat)
+ log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
+ }
+ else if (ret.sat) {
print_qed();
- else
- print_proof_failed();
-
- if(!ret.unknown && ret.sat) {
if (opt.write_solution) {
write_solution(module, ret, opt.write_soln_soln_file);
}
@@ -550,10 +729,11 @@ struct QbfSatPass : public Pass {
if (opt.unsat)
log_cmd_error("expected problem to be UNSAT\n");
}
- else if (!ret.unknown && !ret.sat && opt.sat)
- log_cmd_error("expected problem to be SAT\n");
- else if (ret.unknown && (opt.sat || opt.unsat))
- log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT");
+ else {
+ print_proof_failed();
+ if (opt.sat)
+ log_cmd_error("expected problem to be SAT\n");
+ }
} else
specialize_from_file(module, opt.specialize_soln_file);
log_pop();
diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore
deleted file mode 100644
index e6dcc6bc0..000000000
--- a/passes/techmap/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-techmap.inc
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 1802ba0de..873286608 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -45,18 +45,6 @@ OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
endif
-GENFILES += passes/techmap/techmap.inc
-
-passes/techmap/techmap.inc: techlibs/common/techmap.v
- $(Q) mkdir -p $(dir $@)
- $(P) echo "// autogenerated from $<" > $@.new
- $(Q) echo "static char stdcells_code[] = {" >> $@.new
- $(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new
- $(Q) echo "0};" >> $@.new
- $(Q) mv $@.new $@
-
-passes/techmap/techmap.o: passes/techmap/techmap.inc
-
ifeq ($(DISABLE_SPAWN),0)
TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE)
EXTRA_OBJS += passes/techmap/filterlib.o
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
index 1b3d5ff06..06097a6f7 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass
log(" specified).\n");
log("\n");
log(" -dff\n");
- log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n");
- log(" domains are marked as such and automatically partitioned by ABC.\n");
+ log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n");
+ log(" domains are supported and automatically partitioned by ABC.\n");
log("\n");
log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n");
@@ -274,40 +274,106 @@ struct Abc9Pass : public ScriptPass
void script() YS_OVERRIDE
{
+ if (check_label("check")) {
+ if (help_mode)
+ run("abc9_ops -check [-dff]", "(option if -dff)");
+ else
+ run(stringf("abc9_ops -check %s", dff_mode ? "-dff" : ""));
+ }
+
+ if (check_label("map")) {
+ if (help_mode)
+ run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)");
+ else
+ run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : ""));
+ if (dff_mode) {
+ run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)");
+ run("select -unset $abc9_flops", " (only if -dff)");
+ }
+ run("design -stash $abc9");
+ run("design -load $abc9_map");
+ run("proc");
+ run("wbflip");
+ run("techmap");
+ run("opt");
+ if (dff_mode || help_mode) {
+ if (!help_mode)
+ active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something");
+ run("abc9_ops -prep_dff_submod", " (only if -dff)"); // rewrite specify
+ bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something");
+ if (did_something) {
+ // select all $_DFF_[NP]_
+ // then select all its fanins
+ // then select all fanouts of all that
+ // lastly remove $_DFF_[NP]_ cells
+ run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)");
+ run("submod", " (only if -dff)");
+ run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)");
+ if (help_mode) {
+ run("foreach module in design");
+ run(" rename <module-name>_$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)");
+ }
+ else {
+ // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs
+ for (auto module : active_design->selected_modules()) {
+ active_design->selected_active_module = module->name.str();
+ if (module->cell(stringf("%s_$abc9_flop", module->name.c_str())))
+ run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str()));
+ }
+ active_design->selected_active_module.clear();
+ }
+ run("abc9_ops -prep_dff_unmap", " (only if -dff)");
+ run("design -copy-to $abc9 =*_$abc9_flop", " (only if -dff)"); // copy submod out
+ run("delete =*_$abc9_flop", " (only if -dff)");
+ }
+ }
+ run("design -stash $abc9_map");
+ run("design -load $abc9");
+ run("design -delete $abc9");
+ if (help_mode)
+ run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)");
+ else
+ run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : ""));
+ run("design -delete $abc9_map");
+ }
+
if (check_label("pre")) {
- run("abc9_ops -check");
+ run("read_verilog -icells -lib -specify +/abc9_model.v");
run("scc -set_attr abc9_scc_id {}");
if (help_mode)
run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
else
- run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");
+ run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
if (help_mode)
run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
else if (!lut_mode)
run(stringf("abc9_ops -prep_lut %d", maxlut));
if (help_mode)
- run("abc9_ops -prep_box [-dff]", "(skip if -box)");
+ run("abc9_ops -prep_box", "(skip if -box)");
else if (box_file.empty())
- run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : ""));
- run("select -set abc9_holes A:abc9_holes");
- run("flatten -wb @abc9_holes");
- run("techmap @abc9_holes");
- if (dff_mode || help_mode)
- run("abc9_ops -prep_dff", "(only if -dff)");
- run("opt -purge @abc9_holes");
- run("aigmap");
- run("wbflip @abc9_holes");
+ run("abc9_ops -prep_box");
+ if (saved_designs.count("$abc9_holes") || help_mode) {
+ run("design -stash $abc9");
+ run("design -load $abc9_holes");
+ run("techmap -wb -map %$abc9 -map +/techmap.v");
+ run("opt -purge");
+ run("aigmap");
+ run("design -stash $abc9_holes");
+ run("design -load $abc9");
+ run("design -delete $abc9");
+ }
}
- if (check_label("map")) {
+ if (check_label("exe")) {
+ run("aigmap");
if (help_mode) {
run("foreach module in selection");
run(" abc9_ops -write_lut <abc-temp-dir>/input.lut", "(skip if '-lut' or '-luts')");
- run(" abc9_ops -write_box <abc-temp-dir>/input.box");
- run(" write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig");
- run(" abc9_exe [options] -cwd <abc-temp-dir> [-lut <abc-temp-dir>/input.lut] -box <abc-temp-dir>/input.box");
+ run(" abc9_ops -write_box <abc-temp-dir>/input.box", "(skip if '-box')");
+ run(" write_xaiger -map <abc-temp-dir>/input.sym [-dff] <abc-temp-dir>/input.xaig");
+ run(" abc9_exe [options] -cwd <abc-temp-dir> -lut [<abc-temp-dir>/input.lut] -box [<abc-temp-dir>/input.box]");
run(" read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");
- run(" abc9_ops -reintegrate");
+ run(" abc9_ops -reintegrate [-dff]");
}
else {
auto selected_modules = active_design->selected_modules();
@@ -318,7 +384,6 @@ struct Abc9Pass : public ScriptPass
log("Skipping module %s as it contains processes.\n", log_id(mod));
continue;
}
- log_assert(!mod->attributes.count(ID::abc9_box_id));
log_push();
active_design->selection().select(mod);
@@ -333,8 +398,9 @@ struct Abc9Pass : public ScriptPass
if (!lut_mode)
run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str()));
- run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
- run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));
+ if (box_file.empty())
+ run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str()));
+ run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str()));
int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs");
@@ -349,10 +415,13 @@ struct Abc9Pass : public ScriptPass
abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str());
if (!lut_mode)
abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str());
- abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str());
+ if (box_file.empty())
+ abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str());
+ else
+ abc9_exe_cmd += stringf(" -box %s", box_file.c_str());
run_nocheck(abc9_exe_cmd);
run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str()));
- run_nocheck("abc9_ops -reintegrate");
+ run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : ""));
}
else
log("Don't call ABC as there is nothing to map.\n");
@@ -369,6 +438,14 @@ struct Abc9Pass : public ScriptPass
active_design->selection_stack.pop_back();
}
}
+
+ if (check_label("unmap")) {
+ run("techmap -wb -map %$abc9_unmap -map +/abc9_unmap.v"); // techmap user design from submod back to original cell
+ // ($_DFF_[NP]_ already shorted by -reintegrate)
+ run("design -delete $abc9_unmap");
+ if (saved_designs.count("$abc9_holes") || help_mode)
+ run("design -delete $abc9_holes");
+ }
}
} Abc9Pass;
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 1345188a4..8d55b18a0 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -34,13 +34,10 @@ inline std::string remap_name(RTLIL::IdString abc9_name)
return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
}
-void check(RTLIL::Design *design)
+void check(RTLIL::Design *design, bool dff_mode)
{
dict<IdString,IdString> box_lookup;
for (auto m : design->modules()) {
- if (m->name.begins_with("$paramod"))
- continue;
-
auto flop = m->get_bool_attribute(ID::abc9_flop);
auto it = m->attributes.find(ID::abc9_box_id);
if (!flop) {
@@ -88,6 +85,461 @@ void check(RTLIL::Design *design)
log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs);
}
}
+
+ if (dff_mode) {
+ static pool<IdString> unsupported{
+ ID($adff), ID($dlatch), ID($dlatchsr), ID($sr),
+ ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ ID($_DLATCH_N_), ID($_DLATCH_P_),
+ ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_),
+ ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)
+ };
+ pool<IdString> processed;
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ IdString derived_type;
+ Module *derived_module;
+ if (cell->parameters.empty()) {
+ derived_type = cell->type;
+ derived_module = inst_module;
+ }
+ else {
+ derived_type = inst_module->derive(design, cell->parameters);
+ derived_module = design->module(derived_type);
+ log_assert(derived_module);
+ }
+ if (!derived_module->get_bool_attribute(ID::abc9_flop))
+ continue;
+ if (derived_module->get_blackbox_attribute(true /* ignore_wb */))
+ log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type));
+
+ if (derived_module->has_processes())
+ Pass::call_on_module(design, derived_module, "proc");
+
+ bool found = false;
+ for (auto derived_cell : derived_module->cells()) {
+ if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) {
+ if (found)
+ log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module));
+ found = true;
+
+ SigBit Q = derived_cell->getPort(ID::Q);
+ log_assert(GetSize(Q.wire) == 1);
+
+ if (!Q.wire->port_output)
+ log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type));
+
+ Const init = Q.wire->attributes.at(ID::init, State::Sx);
+ log_assert(GetSize(init) == 1);
+ }
+ else if (unsupported.count(derived_cell->type))
+ log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type));
+ }
+ }
+ }
+}
+
+void prep_hier(RTLIL::Design *design, bool dff_mode)
+{
+ auto r = saved_designs.emplace("$abc9_unmap", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *unmap_design = r.first->second;
+
+ static const pool<IdString> seq_types{
+ ID($dff), ID($dffsr), ID($adff),
+ ID($dlatch), ID($dlatchsr), ID($sr),
+ ID($mem),
+ ID($_DFF_N_), ID($_DFF_P_),
+ ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
+ ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),
+ ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
+ ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
+ ID($_DLATCH_N_), ID($_DLATCH_P_),
+ ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
+ ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_),
+ ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)
+ };
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ IdString derived_type;
+ Module *derived_module;
+ if (cell->parameters.empty()) {
+ derived_type = cell->type;
+ derived_module = inst_module;
+ }
+ else {
+ derived_type = inst_module->derive(design, cell->parameters);
+ derived_module = design->module(derived_type);
+ }
+ if (derived_module->get_blackbox_attribute(true /* ignore_wb */))
+ continue;
+
+ if (derived_module->get_bool_attribute(ID::abc9_flop)) {
+ if (!dff_mode)
+ continue;
+ }
+ else {
+ if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+ }
+
+ if (!unmap_design->module(derived_type)) {
+ if (derived_module->has_processes())
+ Pass::call_on_module(design, derived_module, "proc");
+
+ if (derived_module->get_bool_attribute(ID::abc9_flop)) {
+ for (auto derived_cell : derived_module->cells())
+ if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) {
+ SigBit Q = derived_cell->getPort(ID::Q);
+ Const init = Q.wire->attributes.at(ID::init, State::Sx);
+ log_assert(GetSize(init) == 1);
+
+ // Block sequential synthesis on cells with (* init *) != 1'b0
+ // because ABC9 doesn't support them
+ if (init != State::S0) {
+ log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type));
+ derived_module->set_bool_attribute(ID::abc9_flop, false);
+ }
+ break;
+ }
+ }
+ else if (derived_module->get_bool_attribute(ID::abc9_box)) {
+ for (auto derived_cell : derived_module->cells())
+ if (seq_types.count(derived_cell->type)) {
+ derived_module->set_bool_attribute(ID::abc9_box, false);
+ derived_module->set_bool_attribute(ID::abc9_bypass);
+ break;
+ }
+ }
+
+ if (derived_type != cell->type) {
+ auto unmap_module = unmap_design->addModule(derived_type);
+ for (auto port : derived_module->ports) {
+ auto w = unmap_module->addWire(port, derived_module->wire(port));
+ // Do not propagate (* init *) values into the box,
+ // in fact, remove it from outside too
+ if (w->port_output && w->attributes.erase(ID::init)) {
+ auto r = unmap_module->addWire(stringf("\\_TECHMAP_REMOVEINIT_%s_", log_id(port)));
+ unmap_module->connect(r, State::S1);
+ }
+ }
+ unmap_module->ports = derived_module->ports;
+ unmap_module->check();
+
+ auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type);
+ for (const auto &conn : cell->connections()) {
+ auto w = unmap_module->wire(conn.first);
+ log_assert(w);
+ replace_cell->setPort(conn.first, w);
+ }
+ replace_cell->parameters = cell->parameters;
+ }
+ }
+
+ cell->type = derived_type;
+ cell->parameters.clear();
+ }
+}
+
+void prep_bypass(RTLIL::Design *design)
+{
+ auto r = saved_designs.emplace("$abc9_map", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *map_design = r.first->second;
+
+ r = saved_designs.emplace("$abc9_unmap", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ Design *unmap_design = r.first->second;
+
+ pool<IdString> processed;
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ if (!processed.insert(cell->type).second)
+ continue;
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+ log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */));
+ log_assert(cell->parameters.empty());
+
+
+ // The idea is to create two techmap designs, one which maps:
+ //
+ // box u0 (.i(i), .o(o));
+ //
+ // to
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
+ //
+ // the purpose being to move the (* abc9_box *) status from 'box'
+ // (which is stateful) to 'box_$abc9_byp' (which becomes a new
+ // combinatorial black- (not white-) box with all state elements
+ // removed). This has the effect of preserving any combinatorial
+ // paths through an otherwise sequential primitive -- e.g. LUTRAMs.
+ //
+ // The unmap design performs the reverse:
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o));
+ //
+ // to:
+ //
+ // wire $abc9$o;
+ // box u0 (.i(i), .o($abc9_byp$o));
+ // assign o = $abc9_byp$o;
+
+
+ // Copy inst_module into map_design, with the same interface
+ // and duplicate $abc9$* wires for its output ports
+ auto map_module = map_design->addModule(cell->type);
+ for (auto port_name : inst_module->ports) {
+ auto w = map_module->addWire(port_name, inst_module->wire(port_name));
+ if (w->port_output)
+ w->attributes.erase(ID::init);
+ }
+ map_module->ports = inst_module->ports;
+ map_module->check();
+ map_module->set_bool_attribute(ID::whitebox);
+
+ // Create the bypass module in the user design, which has the same
+ // interface as the derived module but with additional input
+ // ports driven by the outputs of the replaced cell
+ auto bypass_module = design->addModule(cell->type.str() + "_$abc9_byp");
+ for (auto port_name : inst_module->ports) {
+ auto port = inst_module->wire(port_name);
+ if (!port->port_output)
+ continue;
+ auto dst = bypass_module->addWire(port_name, port);
+ auto src = bypass_module->addWire("$abc9byp$" + port_name.str(), GetSize(port));
+ src->port_input = true;
+ // For these new input ports driven by the replaced
+ // cell, then create a new simple-path specify entry:
+ // (input => output) = 0
+ auto specify = bypass_module->addCell(NEW_ID, ID($specify2));
+ specify->setPort(ID::EN, State::S1);
+ specify->setPort(ID::SRC, src);
+ specify->setPort(ID::DST, dst);
+ specify->setParam(ID::FULL, 0);
+ specify->setParam(ID::SRC_WIDTH, GetSize(src));
+ specify->setParam(ID::DST_WIDTH, GetSize(dst));
+ specify->setParam(ID::SRC_DST_PEN, 0);
+ specify->setParam(ID::SRC_DST_POL, 0);
+ specify->setParam(ID::T_RISE_MIN, 0);
+ specify->setParam(ID::T_RISE_TYP, 0);
+ specify->setParam(ID::T_RISE_MAX, 0);
+ specify->setParam(ID::T_FALL_MIN, 0);
+ specify->setParam(ID::T_FALL_TYP, 0);
+ specify->setParam(ID::T_FALL_MAX, 0);
+ }
+ bypass_module->set_bool_attribute(ID::blackbox);
+ bypass_module->set_bool_attribute(ID::abc9_box);
+
+ // Copy any 'simple' (combinatorial) specify paths from
+ // the derived module into the bypass module, if EN
+ // is not false and SRC/DST are driven only by
+ // module ports; create new input port if one doesn't
+ // already exist
+ for (auto cell : inst_module->cells()) {
+ if (cell->type != ID($specify2))
+ continue;
+ auto EN = cell->getPort(ID::EN).as_bit();
+ SigBit newEN;
+ if (!EN.wire && EN != State::S1)
+ continue;
+ auto SRC = cell->getPort(ID::SRC);
+ for (const auto &c : SRC.chunks())
+ if (c.wire && !c.wire->port_input) {
+ SRC = SigSpec();
+ break;
+ }
+ if (SRC.empty())
+ continue;
+ auto DST = cell->getPort(ID::DST);
+ for (const auto &c : DST.chunks())
+ if (c.wire && !c.wire->port_output) {
+ DST = SigSpec();
+ break;
+ }
+ if (DST.empty())
+ continue;
+ auto rw = [bypass_module](RTLIL::SigSpec &sig)
+ {
+ SigSpec new_sig;
+ for (auto c : sig.chunks()) {
+ if (c.wire) {
+ auto port = bypass_module->wire(c.wire->name);
+ if (!port)
+ port = bypass_module->addWire(c.wire->name, c.wire);
+ c.wire = port;
+ }
+ new_sig.append(std::move(c));
+ }
+ sig = std::move(new_sig);
+ };
+ auto specify = bypass_module->addCell(NEW_ID, cell);
+ specify->rewrite_sigspecs(rw);
+ }
+ bypass_module->fixup_ports();
+
+ // Create an _TECHMAP_REPLACE_ cell identical to the original cell,
+ // and a bypass cell that has the same inputs/outputs as the
+ // original cell, but with additional inputs taken from the
+ // replaced cell
+ auto replace_cell = map_module->addCell(ID::_TECHMAP_REPLACE_, cell->type);
+ auto bypass_cell = map_module->addCell(NEW_ID, cell->type.str() + "_$abc9_byp");
+ for (const auto &conn : cell->connections()) {
+ auto port = map_module->wire(conn.first);
+ if (cell->input(conn.first)) {
+ replace_cell->setPort(conn.first, port);
+ if (bypass_module->wire(conn.first))
+ bypass_cell->setPort(conn.first, port);
+ }
+ if (cell->output(conn.first)) {
+ bypass_cell->setPort(conn.first, port);
+ auto n = "$abc9byp$" + conn.first.str();
+ auto w = map_module->addWire(n, GetSize(conn.second));
+ replace_cell->setPort(conn.first, w);
+ bypass_cell->setPort(n, w);
+ }
+ }
+
+
+ // Lastly, create a new module in the unmap_design that shorts
+ // out the bypass cell back to leave the replace cell behind
+ // driving the outputs
+ auto unmap_module = unmap_design->addModule(cell->type.str() + "_$abc9_byp");
+ for (auto port_name : inst_module->ports) {
+ auto w = unmap_module->addWire(port_name, inst_module->wire(port_name));
+ if (w->port_output) {
+ w->attributes.erase(ID::init);
+ auto w2 = unmap_module->addWire("$abc9byp$" + port_name.str(), GetSize(w));
+ w2->port_input = true;
+ unmap_module->connect(w, w2);
+ }
+ }
+ unmap_module->fixup_ports();
+ }
+}
+
+void prep_dff(RTLIL::Design *design)
+{
+ auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false)));
+ auto &modules_sel = r.first->second;
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->cells()) {
+ if (modules_sel.selected_whole_module(cell->type))
+ continue;
+ auto inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_bool_attribute(ID::abc9_flop))
+ continue;
+ log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */));
+ log_assert(cell->parameters.empty());
+ modules_sel.select(inst_module);
+ }
+}
+
+void prep_dff_submod(RTLIL::Design *design)
+{
+ for (auto module : design->modules()) {
+ vector<Cell*> specify_cells;
+ SigBit Q;
+ Cell* dff_cell = nullptr;
+
+ if (!module->get_bool_attribute(ID::abc9_flop))
+ continue;
+
+ for (auto cell : module->cells())
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) {
+ log_assert(!dff_cell);
+ dff_cell = cell;
+ Q = cell->getPort(ID::Q);
+ log_assert(GetSize(Q.wire) == 1);
+ }
+ else if (cell->type.in(ID($specify3), ID($specrule)))
+ specify_cells.emplace_back(cell);
+ log_assert(dff_cell);
+
+ // Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that:
+ // (a) flop box will have an output
+ // (b) $_DFF_[NP]_.Q will be present as an input
+ SigBit D = module->addWire(NEW_ID);
+ module->addMuxGate(NEW_ID, dff_cell->getPort(ID::D), Q, State::S0, D);
+ dff_cell->setPort(ID::D, D);
+
+ // Rewrite $specify cells that end with $_DFF_[NP]_.Q
+ // to $_DFF_[NP]_.D since it will be moved into
+ // the submodule
+ for (auto cell : specify_cells) {
+ auto DST = cell->getPort(ID::DST);
+ DST.replace(Q, D);
+ cell->setPort(ID::DST, DST);
+ }
+
+ design->scratchpad_set_bool("abc9_ops.prep_dff_submod.did_something", true);
+ }
+}
+
+void prep_dff_unmap(RTLIL::Design *design)
+{
+ Design *unmap_design = saved_designs.at("$abc9_unmap");
+
+ for (auto module : design->modules()) {
+ if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box))
+ continue;
+
+ // Make sure the box module has all the same ports present on flop cell
+ auto replace_cell = module->cell(ID::_TECHMAP_REPLACE_);
+ log_assert(replace_cell);
+ auto box_module = design->module(module->name.str() + "_$abc9_flop");
+ log_assert(box_module);
+ for (auto port_name : module->ports) {
+ auto port = module->wire(port_name);
+ auto box_port = box_module->wire(port_name);
+ if (box_port) {
+ // Do not propagate init -- already captured by box
+ box_port->attributes.erase(ID::init);
+ continue;
+ }
+ log_assert(port->port_input);
+ box_module->addWire(port_name, port);
+ replace_cell->setPort(port_name, port);
+ }
+ box_module->fixup_ports();
+
+ auto unmap_module = unmap_design->addModule(box_module->name);
+ replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name);
+ for (auto port_name : box_module->ports) {
+ auto w = unmap_module->addWire(port_name, box_module->wire(port_name));
+ if (module->wire(port_name))
+ replace_cell->setPort(port_name, w);
+ }
+ unmap_module->ports = box_module->ports;
+ unmap_module->check();
+ }
}
void mark_scc(RTLIL::Module *module)
@@ -95,7 +547,7 @@ void mark_scc(RTLIL::Module *module)
// For every unique SCC found, (arbitrarily) find the first
// cell in the component, and replace its output connections
// with a new wire driven by the old connection but with a
- // special (* abc9_scc *) attribute set (which is used by
+ // special (* abc9_keep *) attribute set (which is used by
// write_xaiger to break this wire into PI and POs)
pool<RTLIL::Const> ids_seen;
for (auto cell : module->cells()) {
@@ -111,7 +563,7 @@ void mark_scc(RTLIL::Module *module)
if (c.second.is_fully_const()) continue;
if (cell->output(c.first)) {
Wire *w = module->addWire(NEW_ID, GetSize(c.second));
- w->set_bool_attribute(ID::abc9_scc);
+ w->set_bool_attribute(ID::abc9_keep);
module->connect(w, c.second);
c.second = w;
}
@@ -119,80 +571,94 @@ void mark_scc(RTLIL::Module *module)
}
}
-void prep_dff(RTLIL::Module *module)
+void prep_delays(RTLIL::Design *design, bool dff_mode)
{
- auto design = module->design;
- log_assert(design);
+ TimingInfo timing;
- SigMap assign_map(module);
+ // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
+ // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
+ std::vector<Cell*> cells;
+ for (auto module : design->selected_modules()) {
+ if (module->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(module));
+ continue;
+ }
- typedef SigSpec clkdomain_t;
- dict<clkdomain_t, int> clk_to_mergeability;
+ for (auto cell : module->cells()) {
+ if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_)))
+ continue;
+ log_assert(!cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
- for (auto cell : module->cells()) {
- if (cell->type != ID($__ABC9_FF_))
- continue;
+ RTLIL::Module* inst_module = design->module(cell->type);
+ if (!inst_module)
+ continue;
+ if (!inst_module->get_blackbox_attribute())
+ continue;
+ if (!cell->parameters.empty())
+ continue;
- Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str()));
- if (abc9_clock_wire == NULL)
- log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
- SigSpec abc9_clock = assign_map(abc9_clock_wire);
+ if (inst_module->get_bool_attribute(ID::abc9_box))
+ continue;
+ if (inst_module->get_bool_attribute(ID::abc9_bypass))
+ continue;
+
+ if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) {
+ continue; // do not add $__ABC9_DELAY boxes to flops
+ // as delays will be captured in the flop box
+ }
- clkdomain_t key(abc9_clock);
+ if (!timing.count(cell->type))
+ timing.setup_module(inst_module);
- auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
- auto r2 = cell->attributes.insert(ID::abc9_mergeability);
- log_assert(r2.second);
- r2.first->second = r.first->second;
+ cells.emplace_back(cell);
+ }
}
- RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
- if (holes_module) {
- SigMap sigmap(holes_module);
+ // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
+ // (or bypassed white-boxes with required times)
+ dict<int, IdString> box_cache;
+ Module *delay_module = design->module(ID($__ABC9_DELAY));
+ log_assert(delay_module);
+ for (auto cell : cells) {
+ auto module = cell->module;
+ auto inst_module = design->module(cell->type);
+ log_assert(inst_module);
- dict<SigSpec, SigSpec> replace;
- for (auto cell : holes_module->cells().to_vector()) {
- if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
- ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_)))
+ auto &t = timing.at(cell->type).required;
+ for (auto &conn : cell->connections_) {
+ auto port_wire = inst_module->wire(conn.first);
+ if (!port_wire)
+ log_error("Port %s in cell %s (type %s) from module %s does not actually exist",
+ log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module));
+ if (!port_wire->port_input)
continue;
- SigBit D = cell->getPort(ID::D);
- SigBit Q = cell->getPort(ID::Q);
- // Emulate async control embedded inside $_DFF_* cell with mux in front of D
- if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_)))
- D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_)))
- D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_)))
- D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R));
- else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_)))
- D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R));
- // Remove the $_DFF_* cell from what needs to be a combinatorial box
- holes_module->remove(cell);
- Wire *port;
- if (GetSize(Q.wire) == 1)
- port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
- else
- port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
- log_assert(port);
- // Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
- // in order to extract just the combinatorial control logic that feeds the box
- // (i.e. clock enable, synchronous reset, etc.)
- replace.insert(std::make_pair(Q,D));
- // Since `flatten` above would have created wires named "<cell>.Q",
- // extract the pre-techmap cell name
- auto pos = Q.wire->name.str().rfind(".");
- log_assert(pos != std::string::npos);
- IdString driver = Q.wire->name.substr(0, pos);
- // And drive the signal that was previously driven by "DFF.Q" (typically
- // used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
- // wire (which itself is driven an by input port) we inserted above
- Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str()));
- log_assert(currQ);
- holes_module->connect(Q, currQ);
- }
+ if (conn.second.is_fully_const())
+ continue;
+
+ SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
+ for (int i = 0; i < GetSize(conn.second); i++) {
+ auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
+ if (d == 0)
+ continue;
- for (auto &conn : holes_module->connections_)
- conn.second = replace.at(sigmap(conn.second), conn.second);
+#ifndef NDEBUG
+ if (ys_debug(1)) {
+ static std::set<std::tuple<IdString,IdString,int>> seen;
+ if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
+ log_id(cell->type), log_id(conn.first), i, d);
+ }
+#endif
+ auto r = box_cache.insert(d);
+ if (r.second) {
+ r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
+ log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
+ }
+ auto box = module->addCell(NEW_ID, r.first->second);
+ box->setPort(ID::I, conn.second[i]);
+ box->setPort(ID::O, O[i]);
+ conn.second[i] = O[i];
+ }
+ }
}
}
@@ -208,17 +674,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
dict<IdString, std::vector<IdString>> box_ports;
for (auto cell : module->cells()) {
- if (cell->type == ID($__ABC9_FF_))
+ if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
continue;
if (cell->has_keep_attr())
continue;
- auto inst_module = module->design->module(cell->type);
+ auto inst_module = design->module(cell->type);
bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop);
if (abc9_flop && !dff)
continue;
- if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) {
+ if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) {
auto r = box_ports.insert(cell->type);
if (r.second) {
// Make carry in the last PI, and carry out the last PO
@@ -287,9 +753,13 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
log_assert(no_loops);
- RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str()));
+ auto r = saved_designs.emplace("$abc9_holes", nullptr);
+ if (r.second)
+ r.first->second = new Design;
+ RTLIL::Design *holes_design = r.first->second;
+ log_assert(holes_design);
+ RTLIL::Module *holes_module = holes_design->addModule(module->name);
log_assert(holes_module);
- holes_module->set_bool_attribute(ID::abc9_holes);
dict<IdString, Cell*> cell_cache;
TimingInfo timing;
@@ -300,22 +770,20 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
log_assert(cell);
RTLIL::Module* box_module = design->module(cell->type);
- if (!box_module || (!box_module->get_bool_attribute(ID::abc9_box) && !box_module->get_bool_attribute(ID::abc9_flop)))
+ if (!box_module)
+ continue;
+ if (!box_module->get_bool_attribute(ID::abc9_box))
continue;
+ log_assert(cell->parameters.empty());
+ log_assert(box_module->get_blackbox_attribute());
cell->attributes[ID::abc9_box_seq] = box_count++;
- IdString derived_type = box_module->derive(design, cell->parameters);
- box_module = design->module(derived_type);
-
- auto r = cell_cache.insert(derived_type);
+ auto r = cell_cache.insert(cell->type);
auto &holes_cell = r.first->second;
if (r.second) {
- if (box_module->has_processes())
- Pass::call_on_module(design, box_module, "proc");
-
if (box_module->get_bool_attribute(ID::whitebox)) {
- holes_cell = holes_module->addCell(cell->name, derived_type);
+ holes_cell = holes_module->addCell(cell->name, cell->type);
if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc");
@@ -340,22 +808,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
}
}
else if (w->port_output)
- conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w));
- }
-
- // For flops only, create an extra 1-bit input that drives a new wire
- // called "<cell>.abc9_ff.Q" that is used below
- if (box_module->get_bool_attribute(ID::abc9_flop)) {
- box_inputs++;
- Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
- if (!holes_wire) {
- holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
- holes_wire->port_input = true;
- holes_wire->port_id = port_id++;
- holes_module->ports.push_back(holes_wire->name);
- }
- Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str()));
- holes_module->connect(Q, holes_wire);
+ conn = holes_module->addWire(stringf("%s.%s", cell->type.c_str(), log_id(port_name)), GetSize(w));
}
}
else // box_module is a blackbox
@@ -379,90 +832,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
}
}
-void prep_delays(RTLIL::Design *design, bool dff_mode)
-{
- TimingInfo timing;
-
- // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes
- // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations
- pool<Module*> flops;
- std::vector<Cell*> cells;
- for (auto module : design->selected_modules()) {
- if (module->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", log_id(module));
- continue;
- }
-
- for (auto cell : module->cells()) {
- if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY)))
- continue;
-
- RTLIL::Module* inst_module = module->design->module(cell->type);
- if (!inst_module)
- continue;
- if (!inst_module->get_blackbox_attribute())
- continue;
- if (inst_module->attributes.count(ID::abc9_box))
- continue;
- IdString derived_type = inst_module->derive(design, cell->parameters);
- inst_module = design->module(derived_type);
- log_assert(inst_module);
-
- if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) {
- flops.insert(inst_module);
- continue; // do not add $__ABC9_DELAY boxes to flops
- // as delays will be captured in the flop box
- }
-
- if (!timing.count(derived_type))
- timing.setup_module(inst_module);
-
- cells.emplace_back(cell);
- }
- }
-
- // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes
- // with required times
- for (auto cell : cells) {
- auto module = cell->module;
- RTLIL::Module* inst_module = module->design->module(cell->type);
- log_assert(inst_module);
- IdString derived_type = inst_module->derive(design, cell->parameters);
- inst_module = design->module(derived_type);
- log_assert(inst_module);
-
- auto &t = timing.at(derived_type).required;
- for (auto &conn : cell->connections_) {
- auto port_wire = inst_module->wire(conn.first);
- if (!port_wire)
- log_error("Port %s in cell %s (type %s) of module %s does not actually exist",
- log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name));
- if (!port_wire->port_input)
- continue;
-
- SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
- for (int i = 0; i < GetSize(conn.second); i++) {
- auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
- if (d == 0)
- continue;
-
-#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::tuple<IdString,IdString,int>> seen;
- if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
- log_id(cell->type), log_id(conn.first), i, d);
- }
-#endif
- auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY));
- box->setPort(ID::I, conn.second[i]);
- box->setPort(ID::O, O[i]);
- box->setParam(ID::DELAY, d);
- conn.second[i] = O[i];
- }
- }
- }
-}
-
void prep_lut(RTLIL::Design *design, int maxlut)
{
TimingInfo timing;
@@ -540,7 +909,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
-void prep_box(RTLIL::Design *design, bool dff_mode)
+void prep_box(RTLIL::Design *design)
{
TimingInfo timing;
@@ -555,165 +924,162 @@ void prep_box(RTLIL::Design *design, bool dff_mode)
dict<IdString,std::vector<IdString>> box_ports;
for (auto module : design->modules()) {
- auto abc9_flop = module->get_bool_attribute(ID::abc9_flop);
- if (abc9_flop) {
- auto r = module->attributes.insert(ID::abc9_box_id);
- if (!r.second)
- continue;
- r.first->second = abc9_box_id++;
-
- if (dff_mode) {
- int num_inputs = 0, num_outputs = 0;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- log_assert(GetSize(wire) == 1);
- if (wire->port_input) num_inputs++;
- if (wire->port_output) num_outputs++;
- }
- log_assert(num_outputs == 1);
+ auto it = module->attributes.find(ID::abc9_box);
+ if (it == module->attributes.end())
+ continue;
+ bool box = it->second.as_bool();
+ module->attributes.erase(it);
+ if (!box)
+ continue;
- ss << log_id(module) << " " << r.first->second.as_int();
- ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
- ss << " " << num_inputs+1 << " " << num_outputs << std::endl;
+ auto r = module->attributes.insert(ID::abc9_box_id);
+ if (!r.second)
+ continue;
+ r.first->second = abc9_box_id++;
+
+ if (module->get_bool_attribute(ID::abc9_flop)) {
+ int num_inputs = 0, num_outputs = 0;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ log_assert(GetSize(wire) == 1);
+ if (wire->port_input) num_inputs++;
+ if (wire->port_output) num_outputs++;
+ }
+ log_assert(num_outputs == 1);
+
+ ss << log_id(module) << " " << r.first->second.as_int();
+ log_assert(module->get_bool_attribute(ID::whitebox));
+ ss << " " << "1";
+ ss << " " << num_inputs << " " << num_outputs << std::endl;
+
+ ss << "#";
+ bool first = true;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ if (!wire->port_input)
+ continue;
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ ss << log_id(wire);
+ }
+ ss << std::endl;
- ss << "#";
- bool first = true;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- if (!wire->port_input)
- continue;
- if (first)
- first = false;
- else
- ss << " ";
- ss << log_id(wire);
- }
- ss << " abc9_ff.Q" << std::endl;
+ auto &t = timing.setup_module(module).required;
+ if (t.empty())
+ log_error("Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information.\n", log_id(module));
- auto &t = timing.setup_module(module).required;
- first = true;
- for (auto port_name : module->ports) {
- auto wire = module->wire(port_name);
- if (!wire->port_input)
- continue;
- if (first)
- first = false;
- else
- ss << " ";
- log_assert(GetSize(wire) == 1);
- auto it = t.find(TimingInfo::NameBit(port_name,0));
- if (it == t.end())
- // Assume that no setup time means zero
- ss << 0;
- else {
- ss << it->second;
+ first = true;
+ for (auto port_name : module->ports) {
+ auto wire = module->wire(port_name);
+ if (!wire->port_input)
+ continue;
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ log_assert(GetSize(wire) == 1);
+ auto it = t.find(TimingInfo::NameBit(port_name,0));
+ if (it == t.end())
+ // Assume no connectivity if no setup time
+ ss << "-";
+ else {
+ ss << it->second;
#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::pair<IdString,IdString>> seen;
- if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
- log_id(port_name), it->second);
- }
-#endif
+ if (ys_debug(1)) {
+ static std::set<std::pair<IdString,IdString>> seen;
+ if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
+ log_id(port_name), it->second);
}
-
+#endif
}
- // Last input is 'abc9_ff.Q'
- ss << " 0" << std::endl << std::endl;
- continue;
}
+ ss << " # $_DFF_[NP]_.D" << std::endl;
+ ss << std::endl;
}
else {
- if (!module->attributes.erase(ID::abc9_box))
- continue;
-
- auto r = module->attributes.insert(ID::abc9_box_id);
- if (!r.second)
- continue;
- r.first->second = abc9_box_id++;
- }
+ auto r2 = box_ports.insert(module->name);
+ if (r2.second) {
+ // Make carry in the last PI, and carry out the last PO
+ // since ABC requires it this way
+ IdString carry_in, carry_out;
+ for (const auto &port_name : module->ports) {
+ auto w = module->wire(port_name);
+ log_assert(w);
+ if (w->get_bool_attribute(ID::abc9_carry)) {
+ log_assert(w->port_input != w->port_output);
+ if (w->port_input)
+ carry_in = port_name;
+ else if (w->port_output)
+ carry_out = port_name;
+ }
+ else
+ r2.first->second.push_back(port_name);
+ }
- auto r = box_ports.insert(module->name);
- if (r.second) {
- // Make carry in the last PI, and carry out the last PO
- // since ABC requires it this way
- IdString carry_in, carry_out;
- for (const auto &port_name : module->ports) {
- auto w = module->wire(port_name);
- log_assert(w);
- if (w->get_bool_attribute(ID::abc9_carry)) {
- log_assert(w->port_input != w->port_output);
- if (w->port_input)
- carry_in = port_name;
- else if (w->port_output)
- carry_out = port_name;
+ if (carry_in != IdString()) {
+ r2.first->second.push_back(carry_in);
+ r2.first->second.push_back(carry_out);
}
- else
- r.first->second.push_back(port_name);
}
- if (carry_in != IdString()) {
- r.first->second.push_back(carry_in);
- r.first->second.push_back(carry_out);
+ std::vector<SigBit> inputs, outputs;
+ for (auto port_name : r2.first->second) {
+ auto wire = module->wire(port_name);
+ if (wire->port_input)
+ for (int i = 0; i < GetSize(wire); i++)
+ inputs.emplace_back(wire, i);
+ if (wire->port_output)
+ for (int i = 0; i < GetSize(wire); i++)
+ outputs.emplace_back(wire, i);
}
- }
-
- std::vector<SigBit> inputs;
- std::vector<SigBit> outputs;
- for (auto port_name : r.first->second) {
- auto wire = module->wire(port_name);
- if (wire->port_input)
- for (int i = 0; i < GetSize(wire); i++)
- inputs.emplace_back(wire, i);
- if (wire->port_output)
- for (int i = 0; i < GetSize(wire); i++)
- outputs.emplace_back(wire, i);
- }
-
- ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
- ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
- ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
-
- bool first = true;
- ss << "#";
- for (const auto &i : inputs) {
- if (first)
- first = false;
- else
- ss << " ";
- if (GetSize(i.wire) == 1)
- ss << log_id(i.wire);
- else
- ss << log_id(i.wire) << "[" << i.offset << "]";
- }
- ss << std::endl;
- auto &t = timing.setup_module(module).comb;
- if (!abc9_flop && t.empty())
- log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module));
+ ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int();
+ ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0");
+ ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl;
- for (const auto &o : outputs) {
- first = true;
+ bool first = true;
+ ss << "#";
for (const auto &i : inputs) {
if (first)
first = false;
else
ss << " ";
- auto jt = t.find(TimingInfo::BitBit(i,o));
- if (jt == t.end())
- ss << "-";
+ if (GetSize(i.wire) == 1)
+ ss << log_id(i.wire);
else
- ss << jt->second;
+ ss << log_id(i.wire) << "[" << i.offset << "]";
}
- ss << " # ";
- if (GetSize(o.wire) == 1)
- ss << log_id(o.wire);
- else
- ss << log_id(o.wire) << "[" << o.offset << "]";
ss << std::endl;
+ auto &t = timing.setup_module(module);
+ if (t.comb.empty())
+ log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module));
+
+ for (const auto &o : outputs) {
+ first = true;
+ for (const auto &i : inputs) {
+ if (first)
+ first = false;
+ else
+ ss << " ";
+ auto jt = t.comb.find(TimingInfo::BitBit(i,o));
+ if (jt == t.comb.end())
+ ss << "-";
+ else
+ ss << jt->second;
+ }
+ ss << " # ";
+ if (GetSize(o.wire) == 1)
+ ss << log_id(o.wire);
+ else
+ ss << log_id(o.wire) << "[" << o.offset << "]";
+ ss << std::endl;
+ }
+ ss << std::endl;
}
- ss << std::endl;
}
// ABC expects at least one box
@@ -730,7 +1096,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) {
ofs.close();
}
-void reintegrate(RTLIL::Module *module)
+void reintegrate(RTLIL::Module *module, bool dff_mode)
{
auto design = module->design;
log_assert(design);
@@ -744,6 +1110,8 @@ void reintegrate(RTLIL::Module *module)
for (auto w : mapped_mod->wires()) {
auto nw = module->addWire(remap_name(w->name), GetSize(w));
nw->start_offset = w->start_offset;
+ // Remove all (* init *) since they only existon $_DFF_[NP]_
+ w->attributes.erase(ID::init);
}
dict<IdString,std::vector<IdString>> box_ports;
@@ -783,7 +1151,14 @@ void reintegrate(RTLIL::Module *module)
for (auto cell : module->cells().to_vector()) {
if (cell->has_keep_attr())
continue;
- if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))
+
+ // Short out $_DFF_[NP]_ cells since the flop box already has
+ // all the information we need to reconstruct cell
+ if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) {
+ module->connect(cell->getPort(ID::Q), cell->getPort(ID::D));
+ module->remove(cell);
+ }
+ else if (cell->type.in(ID($_AND_), ID($_NOT_)))
module->remove(cell);
else if (cell->attributes.erase(ID::abc9_box_seq))
boxes.emplace_back(cell);
@@ -797,6 +1172,18 @@ void reintegrate(RTLIL::Module *module)
std::map<IdString, int> cell_stats;
for (auto mapped_cell : mapped_mod->cells())
{
+ // Short out $_FF_ cells since the flop box already has
+ // all the information we need to reconstruct cell
+ if (dff_mode && mapped_cell->type == ID($_FF_)) {
+ SigBit D = mapped_cell->getPort(ID::D);
+ SigBit Q = mapped_cell->getPort(ID::Q);
+ if (D.wire)
+ D.wire = module->wires_.at(remap_name(D.wire->name));
+ Q.wire = module->wires_.at(remap_name(Q.wire->name));
+ module->connect(Q, D);
+ continue;
+ }
+
// TODO: Speed up toposort -- we care about NOT ordering only
toposort.node(mapped_cell->name);
@@ -846,7 +1233,7 @@ void reintegrate(RTLIL::Module *module)
continue;
}
- if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
+ if (mapped_cell->type == ID($lut)) {
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
cell->parameters = mapped_cell->parameters;
cell->attributes = mapped_cell->attributes;
@@ -881,7 +1268,7 @@ void reintegrate(RTLIL::Module *module)
if (!existing_cell)
log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell));
- if (existing_cell->type == ID($__ABC9_DELAY)) {
+ if (existing_cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) {
SigBit I = mapped_cell->getPort(ID(i));
SigBit O = mapped_cell->getPort(ID(o));
if (I.wire)
@@ -893,10 +1280,8 @@ void reintegrate(RTLIL::Module *module)
}
RTLIL::Module* box_module = design->module(existing_cell->type);
- IdString derived_type = box_module->derive(design, existing_cell->parameters);
- RTLIL::Module* derived_module = design->module(derived_type);
- log_assert(derived_module);
- log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int()));
+ log_assert(existing_cell->parameters.empty());
+ log_assert(mapped_cell->type == stringf("$__boxid%d", box_module->attributes.at(ID::abc9_box_id).as_int()));
mapped_cell->type = existing_cell->type;
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
@@ -913,7 +1298,7 @@ void reintegrate(RTLIL::Module *module)
SigSpec outputs = std::move(jt->second);
mapped_cell->connections_.erase(jt);
- auto abc9_flop = box_module->attributes.count(ID::abc9_flop);
+ auto abc9_flop = box_module->get_bool_attribute(ID::abc9_flop);
if (!abc9_flop) {
for (const auto &i : inputs)
bit_users[i].insert(mapped_cell->name);
@@ -924,7 +1309,7 @@ void reintegrate(RTLIL::Module *module)
}
int input_count = 0, output_count = 0;
- for (const auto &port_name : box_ports.at(derived_type)) {
+ for (const auto &port_name : box_ports.at(existing_cell->type)) {
RTLIL::Wire *w = box_module->wire(port_name);
log_assert(w);
@@ -988,7 +1373,7 @@ void reintegrate(RTLIL::Module *module)
RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
RTLIL::Wire *wire = module->wire(port);
log_assert(wire);
- wire->attributes.erase(ID::abc9_scc);
+ wire->attributes.erase(ID::abc9_keep);
RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire));
@@ -1116,6 +1501,37 @@ struct Abc9OpsPass : public Pass {
log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n");
log(" (* abc9_carry *) is only given for one input/output port, etc.\n");
log("\n");
+ log(" -prep_hier\n");
+ log(" derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option)\n");
+ log(" whitebox modules. with (* abc9_flop *) modules, only those containing\n");
+ log(" $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation\n");
+ log(" -- will be derived.\n");
+ log("\n");
+ log(" -prep_bypass\n");
+ log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n");
+ log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n");
+ log(" (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g.\n");
+ log(" $dff, $mem, etc.) are discovered inside so that any combinatorial paths\n");
+ log(" will be correctly captured. this bypass box will only contain ports that\n");
+ log(" are referenced by a simple path declaration ($specify2 cell) inside a\n");
+ log(" specify block.\n");
+ log("\n");
+ log(" -prep_dff\n");
+ log(" select all (* abc9_flop *) modules instantiated in the design and store\n");
+ log(" in the named selection '$abc9_flops'.\n");
+ log("\n");
+ log(" -prep_dff_submod\n");
+ log(" within (* abc9_flop *) modules, rewrite all edge-sensitive path\n");
+ log(" declarations and $setup() timing checks ($specify3 and $specrule cells)\n");
+ log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n");
+ log(" the DFF's 'D' port. this is to prepare such specify cells to be moved\n");
+ log(" into the flop box.\n");
+ log("\n");
+ log(" -prep_dff_unmap\n");
+ log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n");
+ log(" cells back into their derived cell types (where the rules created by\n");
+ log(" -prep_hier will then map back to the original cell with parameters).\n");
+ log("\n");
log(" -prep_delays\n");
log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
log(" certain required times.\n");
@@ -1128,18 +1544,13 @@ struct Abc9OpsPass : public Pass {
log("\n");
log(" -prep_xaiger\n");
log(" prepare the design for XAIGER output. this includes computing the\n");
- log(" topological ordering of ABC9 boxes, as well as preparing the\n");
- log(" '<module-name>$holes' module that contains the logic behaviour of ABC9\n");
- log(" whiteboxes.\n");
+ log(" topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes'\n");
+ log(" design that contains the logic behaviour of ABC9 whiteboxes.\n");
log("\n");
log(" -dff\n");
log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n");
log(" during -prep_{delays,xaiger,box}.\n");
log("\n");
- log(" -prep_dff\n");
- log(" compute the clock domain and initial value of each flop in the design.\n");
- log(" process the '$holes' module to support clock-enable functionality.\n");
- log("\n");
log(" -prep_lut <maxlut>\n");
log(" pre-compute the lut library by analysing all modules marked with\n");
log(" (* abc9_lut=<area> *).\n");
@@ -1167,7 +1578,9 @@ struct Abc9OpsPass : public Pass {
bool check_mode = false;
bool prep_delays_mode = false;
bool mark_scc_mode = false;
- bool prep_dff_mode = false;
+ bool prep_hier_mode = false;
+ bool prep_bypass_mode = false;
+ bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false;
bool prep_xaiger_mode = false;
bool prep_lut_mode = false;
bool prep_box_mode = false;
@@ -1177,53 +1590,81 @@ struct Abc9OpsPass : public Pass {
int maxlut = 0;
std::string write_box_dst;
+ bool valid = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-check") {
check_mode = true;
+ valid = true;
continue;
}
if (arg == "-mark_scc") {
mark_scc_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_hier") {
+ prep_hier_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_bypass") {
+ prep_bypass_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_dff") {
prep_dff_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_dff_submod") {
+ prep_dff_submod_mode = true;
+ valid = true;
+ continue;
+ }
+ if (arg == "-prep_dff_unmap") {
+ prep_dff_unmap_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_xaiger") {
prep_xaiger_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_delays") {
prep_delays_mode = true;
+ valid = true;
continue;
}
if (arg == "-prep_lut" && argidx+1 < args.size()) {
prep_lut_mode = true;
maxlut = atoi(args[++argidx].c_str());
- continue;
- }
- if (arg == "-maxlut" && argidx+1 < args.size()) {
+ valid = true;
continue;
}
if (arg == "-write_lut" && argidx+1 < args.size()) {
write_lut_dst = args[++argidx];
rewrite_filename(write_lut_dst);
+ valid = true;
continue;
}
if (arg == "-prep_box") {
prep_box_mode = true;
+ valid = true;
continue;
}
if (arg == "-write_box" && argidx+1 < args.size()) {
write_box_dst = args[++argidx];
rewrite_filename(write_box_dst);
+ valid = true;
continue;
}
if (arg == "-reintegrate") {
reintegrate_mode = true;
+ valid = true;
continue;
}
if (arg == "-dff") {
@@ -1234,25 +1675,32 @@ struct Abc9OpsPass : public Pass {
}
extra_args(args, argidx, design);
- if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode))
- log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
+ if (!valid)
+ log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
- if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode)
- log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n");
+ if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode)
+ log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n");
if (check_mode)
- check(design);
+ check(design, dff_mode);
+ if (prep_hier_mode)
+ prep_hier(design, dff_mode);
+ if (prep_bypass_mode)
+ prep_bypass(design);
+ if (prep_dff_mode)
+ prep_dff(design);
+ if (prep_dff_submod_mode)
+ prep_dff_submod(design);
+ if (prep_dff_unmap_mode)
+ prep_dff_unmap(design);
if (prep_delays_mode)
prep_delays(design, dff_mode);
if (prep_lut_mode)
prep_lut(design, maxlut);
if (prep_box_mode)
- prep_box(design, dff_mode);
+ prep_box(design);
for (auto mod : design->selected_modules()) {
- if (mod->get_bool_attribute(ID::abc9_holes))
- continue;
-
if (mod->processes.size() > 0) {
log("Skipping module %s as it contains processes.\n", log_id(mod));
continue;
@@ -1267,12 +1715,10 @@ struct Abc9OpsPass : public Pass {
write_box(mod, write_box_dst);
if (mark_scc_mode)
mark_scc(mod);
- if (prep_dff_mode)
- prep_dff(mod);
if (prep_xaiger_mode)
prep_xaiger(mod, dff_mode);
if (reintegrate_mode)
- reintegrate(mod);
+ reintegrate(mod, dff_mode);
}
}
} Abc9OpsPass;
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index b65b3e972..214157a64 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -522,7 +522,7 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
+void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
mappers[ID($not)] = simplemap_not;
mappers[ID($pos)] = simplemap_pos;
@@ -559,7 +559,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
{
- static std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ static dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
static bool initialized_mappers = false;
if (!initialized_mappers) {
@@ -595,7 +595,7 @@ struct SimplemapPass : public Pass {
log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
- std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
simplemap_get_mappers(mappers);
for (auto mod : design->modules()) {
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
index c2d73ea79..5091050a1 100644
--- a/passes/techmap/simplemap.h
+++ b/passes/techmap/simplemap.h
@@ -42,7 +42,7 @@ extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+extern void simplemap_get_mappers(dict<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
YOSYS_NAMESPACE_END
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index a554be257..c88f7bd0a 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -27,7 +27,6 @@
#include <string.h>
#include "simplemap.h"
-#include "passes/techmap/techmap.inc"
YOSYS_NAMESPACE_BEGIN
@@ -51,21 +50,21 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
vector<SigChunk> chunks = sig;
for (auto &chunk : chunks)
- if (chunk.wire != NULL) {
+ if (chunk.wire != nullptr) {
IdString wire_name = chunk.wire->name;
apply_prefix(prefix, wire_name);
- log_assert(module->wires_.count(wire_name) > 0);
- chunk.wire = module->wires_[wire_name];
+ log_assert(module->wire(wire_name) != nullptr);
+ chunk.wire = module->wire(wire_name);
}
sig = chunks;
}
struct TechmapWorker
{
- std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
- std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
- std::map<RTLIL::Module*, bool> techmap_do_cache;
- std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
+ dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
+ dict<std::pair<IdString, dict<IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+ dict<RTLIL::Module*, bool> techmap_do_cache;
+ pool<RTLIL::Module*> module_queue;
dict<Module*, SigMap> sigmaps;
pool<IdString> flatten_do_list;
@@ -79,31 +78,21 @@ struct TechmapWorker
RTLIL::SigSpec value;
};
- typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
+ typedef dict<IdString, std::vector<TechmapWireData>> TechmapWires;
- bool extern_mode;
- bool assert_mode;
- bool flatten_mode;
- bool recursive_mode;
- bool autoproc_mode;
- bool ignore_wb;
-
- TechmapWorker()
- {
- extern_mode = false;
- assert_mode = false;
- flatten_mode = false;
- recursive_mode = false;
- autoproc_mode = false;
- ignore_wb = false;
- }
+ bool extern_mode = false;
+ bool assert_mode = false;
+ bool flatten_mode = false;
+ bool recursive_mode = false;
+ bool autoproc_mode = false;
+ bool ignore_wb = false;
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
{
std::string constmap_info;
- std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map;
+ dict<RTLIL::SigBit, std::pair<IdString, int>> connbits_map;
- for (auto conn : cell->connections())
+ for (auto &conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++) {
RTLIL::SigBit bit = sigmap(conn.second[i]);
if (bit.wire == nullptr) {
@@ -117,7 +106,7 @@ struct TechmapWorker
constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
} else {
- connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);
+ connbits_map.emplace(bit, std::make_pair(conn.first, i));
constmap_info += stringf("|%s %d", log_id(conn.first), i);
}
}
@@ -129,24 +118,25 @@ struct TechmapWorker
{
TechmapWires result;
- if (module == NULL)
+ if (module == nullptr)
return result;
- for (auto &it : module->wires_) {
- const char *p = it.first.c_str();
+ for (auto w : module->wires()) {
+ const char *p = w->name.c_str();
if (*p == '$')
continue;
const char *q = strrchr(p+1, '.');
- p = q ? q+1 : p+1;
+ if (q)
+ p = q;
- if (!strncmp(p, "_TECHMAP_", 9)) {
+ if (!strncmp(p, "\\_TECHMAP_", 10)) {
TechmapWireData record;
- record.wire = it.second;
- record.value = it.second;
+ record.wire = w;
+ record.value = w;
result[p].push_back(record);
- it.second->attributes[ID::keep] = RTLIL::Const(1);
- it.second->attributes[ID::_techmap_special_] = RTLIL::Const(1);
+ w->set_bool_attribute(ID::keep);
+ w->set_bool_attribute(ID::_techmap_special_);
}
}
@@ -165,7 +155,7 @@ struct TechmapWorker
if (tpl->processes.size() != 0) {
log("Technology map yielded processes:");
for (auto &it : tpl->processes)
- log(" %s",RTLIL::id2cstr(it.first));
+ log(" %s",log_id(it.first));
log("\n");
if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc");
@@ -179,8 +169,8 @@ struct TechmapWorker
orig_cell_name = cell->name.str();
if (!flatten_mode) {
- for (auto &it : tpl->cells_)
- if (it.first == ID::_TECHMAP_REPLACE_) {
+ for (auto tpl_cell : tpl->cells())
+ if (tpl_cell->name == ID::_TECHMAP_REPLACE_) {
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
}
@@ -204,30 +194,30 @@ struct TechmapWorker
design->select(module, m);
}
- std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
+ dict<IdString, IdString> positional_ports;
dict<Wire*, IdString> temp_renamed_wires;
pool<SigBit> autopurge_tpl_bits;
- for (auto &it : tpl->wires_)
+ for (auto tpl_w : tpl->wires())
{
- if (it.second->port_id > 0)
+ if (tpl_w->port_id > 0)
{
- IdString posportname = stringf("$%d", it.second->port_id);
- positional_ports[posportname] = it.first;
+ IdString posportname = stringf("$%d", tpl_w->port_id);
+ positional_ports.emplace(posportname, tpl_w->name);
- if (!flatten_mode && it.second->get_bool_attribute(ID::techmap_autopurge) &&
- (!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) &&
+ if (!flatten_mode && tpl_w->get_bool_attribute(ID::techmap_autopurge) &&
+ (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) &&
(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname))))
{
if (sigmaps.count(tpl) == 0)
sigmaps[tpl].set(tpl);
- for (auto bit : sigmaps.at(tpl)(it.second))
+ for (auto bit : sigmaps.at(tpl)(tpl_w))
if (bit.wire != nullptr)
autopurge_tpl_bits.insert(bit);
}
}
- IdString w_name = it.second->name;
+ IdString w_name = tpl_w->name;
apply_prefix(cell->name, w_name);
RTLIL::Wire *w = module->wire(w_name);
if (w != nullptr) {
@@ -237,30 +227,30 @@ struct TechmapWorker
w = nullptr;
} else {
w->attributes.erase(ID::hierconn);
- if (GetSize(w) < GetSize(it.second)) {
+ if (GetSize(w) < GetSize(tpl_w)) {
log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w),
- log_id(tpl), log_id(it.second), log_id(module), log_id(cell));
- w->width = GetSize(it.second);
+ log_id(tpl), log_id(tpl_w), log_id(module), log_id(cell));
+ w->width = GetSize(tpl_w);
}
}
}
if (w == nullptr) {
- w = module->addWire(w_name, it.second);
+ w = module->addWire(w_name, tpl_w);
w->port_input = false;
w->port_output = false;
w->port_id = 0;
if (!flatten_mode)
w->attributes.erase(ID::techmap_autopurge);
- if (it.second->get_bool_attribute(ID::_techmap_special_))
+ if (tpl_w->get_bool_attribute(ID::_techmap_special_))
w->attributes.clear();
if (w->attributes.count(ID::src))
w->add_strpool_attribute(ID::src, extra_src_attrs);
}
design->select(module, w);
- if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) {
- IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), it.second->name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
- Wire *replace_w = module->addWire(replace_name, it.second);
+ if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) {
+ IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
+ Wire *replace_w = module->addWire(replace_name, tpl_w);
module->connect(replace_w, w);
}
}
@@ -268,24 +258,23 @@ struct TechmapWorker
SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_written_bits;
- for (auto &it1 : tpl->cells_)
- for (auto &it2 : it1.second->connections_)
- if (it1.second->output(it2.first))
- for (auto bit : tpl_sigmap(it2.second))
+ for (auto tpl_cell : tpl->cells())
+ for (auto &conn : tpl_cell->connections())
+ if (tpl_cell->output(conn.first))
+ for (auto bit : tpl_sigmap(conn.second))
tpl_written_bits.insert(bit);
- for (auto &it1 : tpl->connections_)
- for (auto bit : tpl_sigmap(it1.first))
+ for (auto &conn : tpl->connections())
+ for (auto bit : tpl_sigmap(conn.first))
tpl_written_bits.insert(bit);
SigMap port_signal_map;
- SigSig port_signal_assign;
for (auto &it : cell->connections())
{
- RTLIL::IdString portname = it.first;
+ IdString portname = it.first;
if (positional_ports.count(portname) > 0)
portname = positional_ports.at(portname);
- if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) {
+ if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) {
if (portname.begins_with("$"))
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
continue;
@@ -294,7 +283,7 @@ struct TechmapWorker
if (GetSize(it.second) == 0)
continue;
- RTLIL::Wire *w = tpl->wires_.at(portname);
+ RTLIL::Wire *w = tpl->wire(portname);
RTLIL::SigSig c, extra_connect;
if (w->port_output && !w->port_input) {
@@ -377,19 +366,19 @@ struct TechmapWorker
}
}
- for (auto &it : tpl->cells_)
+ for (auto tpl_cell : tpl->cells())
{
- IdString c_name = it.second->name.str();
+ IdString c_name = tpl_cell->name;
bool techmap_replace_cell = (!flatten_mode) && (c_name == ID::_TECHMAP_REPLACE_);
if (techmap_replace_cell)
c_name = orig_cell_name;
- else if (it.second->name.begins_with("\\_TECHMAP_REPLACE_."))
+ else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_."))
c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
else
apply_prefix(cell->name, c_name);
- RTLIL::Cell *c = module->addCell(c_name, it.second);
+ RTLIL::Cell *c = module->addCell(c_name, tpl_cell);
design->select(module, c);
if (!flatten_mode && c->type.begins_with("\\$"))
@@ -397,12 +386,12 @@ struct TechmapWorker
vector<IdString> autopurge_ports;
- for (auto &it2 : c->connections_)
+ for (auto &conn : c->connections())
{
bool autopurge = false;
if (!autopurge_tpl_bits.empty()) {
- autopurge = GetSize(it2.second) != 0;
- for (auto &bit : sigmaps.at(tpl)(it2.second))
+ autopurge = GetSize(conn.second) != 0;
+ for (auto &bit : sigmaps.at(tpl)(conn.second))
if (!autopurge_tpl_bits.count(bit)) {
autopurge = false;
break;
@@ -410,10 +399,12 @@ struct TechmapWorker
}
if (autopurge) {
- autopurge_ports.push_back(it2.first);
+ autopurge_ports.push_back(conn.first);
} else {
- apply_prefix(cell->name, it2.second, module);
- port_signal_map.apply(it2.second);
+ RTLIL::SigSpec new_conn = conn.second;
+ apply_prefix(cell->name, new_conn, module);
+ port_signal_map.apply(new_conn);
+ c->setPort(conn.first, std::move(new_conn));
}
}
@@ -463,8 +454,8 @@ struct TechmapWorker
}
}
- bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
- const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion)
+ bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool<RTLIL::Cell*> &handled_cells,
+ const dict<IdString, pool<IdString>> &celltypeMap, bool in_recursion)
{
std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
@@ -489,13 +480,13 @@ struct TechmapWorker
}
}
- TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
+ TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit;
+ dict<RTLIL::SigBit, pool<RTLIL::Cell*>> outbit_to_cell;
- for (auto cell : module->cells())
+ for (auto cell : module->selected_cells())
{
- if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
+ if (handled_cells.count(cell) > 0)
continue;
std::string cell_type = cell->type.str();
@@ -511,7 +502,7 @@ struct TechmapWorker
if (flatten_mode) {
bool keepit = cell->get_bool_attribute(ID::keep_hierarchy);
for (auto &tpl_name : celltypeMap.at(cell_type))
- if (map->modules_[tpl_name]->get_bool_attribute(ID::keep_hierarchy))
+ if (map->module(tpl_name)->get_bool_attribute(ID::keep_hierarchy))
keepit = true;
if (keepit) {
if (!flatten_keep_list[cell]) {
@@ -533,7 +524,7 @@ struct TechmapWorker
continue;
for (auto &tpl_name : celltypeMap.at(cell_type)) {
- RTLIL::Module *tpl = map->modules_[tpl_name];
+ RTLIL::Module *tpl = map->module(tpl_name);
RTLIL::Wire *port = tpl->wire(conn.first);
if (port && port->port_input)
cell_to_inbit[cell].insert(sig.begin(), sig.end());
@@ -566,9 +557,9 @@ struct TechmapWorker
for (auto &tpl_name : celltypeMap.at(cell_type))
{
- RTLIL::IdString derived_name = tpl_name;
- RTLIL::Module *tpl = map->modules_[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
+ IdString derived_name = tpl_name;
+ RTLIL::Module *tpl = map->module(tpl_name);
+ dict<IdString, RTLIL::Const> parameters(cell->parameters);
if (tpl->get_blackbox_attribute(ignore_wb))
continue;
@@ -675,7 +666,7 @@ struct TechmapWorker
if (extmapper_name == "simplemap") {
if (simplemap_mappers.count(cell->type) == 0)
- log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
+ log_error("No simplemap mapper for cell type %s found!\n", log_id(cell->type));
simplemap_mappers.at(cell->type)(module, cell);
}
@@ -686,7 +677,7 @@ struct TechmapWorker
}
module->remove(cell);
- cell = NULL;
+ cell = nullptr;
}
did_something = true;
@@ -694,10 +685,10 @@ struct TechmapWorker
break;
}
- for (auto conn : cell->connections()) {
+ for (auto &conn : cell->connections()) {
if (conn.first.begins_with("$"))
continue;
- if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0)
+ if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0)
continue;
if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
goto next_tpl;
@@ -710,23 +701,23 @@ struct TechmapWorker
}
if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0)
- parameters[ID::_TECHMAP_CELLTYPE_] = RTLIL::unescape_id(cell->type);
+ parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type));
- for (auto conn : cell->connections()) {
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &conn : cell->connections()) {
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) {
std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
for (auto &bit : v)
- bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
- parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0);
+ parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const());
}
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) {
std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
for (auto &bit : v)
- if (bit.wire != NULL)
+ if (bit.wire != nullptr)
bit = RTLIL::SigBit(RTLIL::State::Sx);
- parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const());
}
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) {
auto sig = sigmap(conn.second);
RTLIL::Const value(State::Sx, sig.size());
for (int i = 0; i < sig.size(); i++) {
@@ -735,20 +726,20 @@ struct TechmapWorker
value[i] = it->second;
}
}
- parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value;
+ parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value);
}
}
int unique_bit_id_counter = 0;
- std::map<RTLIL::SigBit, int> unique_bit_id;
+ dict<RTLIL::SigBit, int> unique_bit_id;
unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
- for (auto conn : cell->connections())
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
- for (auto &bit : sigmap(conn.second).to_sigbit_vector())
+ for (auto &conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
+ for (auto &bit : sigmap(conn.second))
if (unique_bit_id.count(bit) == 0)
unique_bit_id[bit] = unique_bit_id_counter++;
}
@@ -763,14 +754,17 @@ struct TechmapWorker
if (tpl->avail_parameters.count(ID::_TECHMAP_BITS_CONNMAP_))
parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits;
- for (auto conn : cell->connections())
- if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) {
RTLIL::Const value;
- for (auto &bit : sigmap(conn.second).to_sigbit_vector()) {
- RTLIL::Const chunk(unique_bit_id.at(bit), bits);
- value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end());
+ for (auto &bit : sigmap(conn.second)) {
+ int val = unique_bit_id.at(bit);
+ for (int i = 0; i < bits; i++) {
+ value.bits.push_back((val & 1) != 0 ? State::S1 : State::S0);
+ val = val >> 1;
+ }
}
- parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value;
+ parameters.emplace(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first)), value);
}
}
@@ -778,17 +772,18 @@ struct TechmapWorker
use_wrapper_tpl:;
// do not register techmap_wrap modules with techmap_cache
} else {
- std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
- if (techmap_cache.count(key) > 0) {
- tpl = techmap_cache[key];
+ std::pair<IdString, dict<IdString, RTLIL::Const>> key(tpl_name, parameters);
+ auto it = techmap_cache.find(key);
+ if (it != techmap_cache.end()) {
+ tpl = it->second;
} else {
if (parameters.size() != 0) {
mkdebug.on();
- derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
+ derived_name = tpl->derive(map, parameters);
tpl = map->module(derived_name);
log_continue = true;
}
- techmap_cache[key] = tpl;
+ techmap_cache.emplace(std::move(key), tpl);
}
}
@@ -805,7 +800,7 @@ struct TechmapWorker
bool keep_running = true;
techmap_do_cache[tpl] = true;
- std::set<std::string> techmap_wire_names;
+ pool<IdString> techmap_wire_names;
while (keep_running)
{
@@ -815,11 +810,11 @@ struct TechmapWorker
for (auto &it : twd)
techmap_wire_names.insert(it.first);
- for (auto &it : twd["_TECHMAP_FAIL_"]) {
+ for (auto &it : twd[ID::_TECHMAP_FAIL_]) {
RTLIL::SigSpec value = it.value;
if (value.is_fully_const() && value.as_bool()) {
log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
- derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
+ derived_name.c_str(), log_id(it.wire->name), log_signal(value));
techmap_do_cache[tpl] = false;
}
}
@@ -829,13 +824,13 @@ struct TechmapWorker
for (auto &it : twd)
{
- if (it.first.compare(0, 12, "_TECHMAP_DO_") != 0 || it.second.empty())
+ if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty())
continue;
auto &data = it.second.front();
if (!data.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value));
techmap_wire_names.erase(it.first);
@@ -851,7 +846,7 @@ struct TechmapWorker
cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
log("Analyzing pattern of constant bits for this cell:\n");
- RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
+ IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
log_assert(map->module(new_tpl_name) == nullptr);
@@ -862,16 +857,16 @@ struct TechmapWorker
techmap_do_cache[new_tpl] = true;
tpl = new_tpl;
- std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
- std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
- std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
+ dict<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
+ dict<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
+ dict<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
for (auto wire : tpl->wires().to_vector())
{
if (!wire->port_input || wire->port_output)
continue;
- RTLIL::IdString port_name = wire->name;
+ IdString port_name = wire->name;
tpl->rename(wire, NEW_ID);
RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
@@ -879,12 +874,12 @@ struct TechmapWorker
wire->port_id = 0;
for (int i = 0; i < wire->width; i++) {
- port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
- port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
+ port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i));
+ port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i));
}
}
- for (auto conn : cell->connections())
+ for (auto &conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
@@ -926,7 +921,7 @@ struct TechmapWorker
log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
- while (tpl->wires_.count(new_name))
+ while (tpl->wire(new_name) != nullptr)
new_name += "_";
tpl->rename(data.wire->name, new_name);
@@ -937,17 +932,17 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) {
- if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
- log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
+ if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_"))
+ log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first));
if (techmap_do_cache[tpl])
for (auto &it2 : it.second)
if (!it2.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value));
techmap_wire_names.erase(it.first);
}
for (auto &it : techmap_wire_names)
- log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it));
+ log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", log_id(it));
if (recursive_mode) {
if (log_continue) {
@@ -970,10 +965,10 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) {
- if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") {
+ if (it.first.begins_with("\\_TECHMAP_REMOVEINIT_")) {
for (auto &it2 : it.second) {
auto val = it2.value.as_const();
- auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1));
+ auto wirename = RTLIL::escape_id(it.first.substr(21, it.first.size() - 21 - 1));
auto it = cell->connections().find(wirename);
if (it != cell->connections().end()) {
auto sig = sigmap(it->second);
@@ -1015,7 +1010,7 @@ struct TechmapWorker
}
log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
techmap_module_worker(design, module, cell, tpl);
- cell = NULL;
+ cell = nullptr;
}
did_something = true;
mapped_cell = true;
@@ -1275,8 +1270,7 @@ struct TechmapPass : public Pass {
RTLIL::Design *map = new RTLIL::Design;
if (map_files.empty()) {
- std::istringstream f(stdcells_code);
- Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
+ Frontend::frontend_call(map, nullptr, "+/techmap.v", verilog_frontend);
} else {
for (auto &fn : map_files)
if (fn.compare(0, 1, "%") == 0) {
@@ -1285,35 +1279,30 @@ struct TechmapPass : public Pass {
log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1);
}
for (auto mod : saved_designs.at(fn.substr(1))->modules())
- if (!map->has(mod->name))
+ if (!map->module(mod->name))
map->add(mod->clone());
} else {
- std::ifstream f;
- rewrite_filename(fn);
- f.open(fn.c_str());
- yosys_input_files.insert(fn);
- if (f.fail())
- log_cmd_error("Can't open map file `%s'\n", fn.c_str());
- Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
+ Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
}
}
log_header(design, "Continuing TECHMAP pass.\n");
- std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
- for (auto &it : map->modules_) {
- if (it.second->attributes.count(ID::techmap_celltype) && !it.second->attributes.at(ID::techmap_celltype).bits.empty()) {
- char *p = strdup(it.second->attributes.at(ID::techmap_celltype).decode_string().c_str());
- for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
- celltypeMap[RTLIL::escape_id(q)].insert(it.first);
+ dict<IdString, pool<IdString>> celltypeMap;
+ for (auto module : map->modules()) {
+ if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) {
+ char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str());
+ for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n"))
+ celltypeMap[RTLIL::escape_id(q)].insert(module->name);
free(p);
} else {
- string module_name = it.first.str();
- if (it.first.begins_with("\\$"))
- module_name = module_name.substr(1);
- celltypeMap[module_name].insert(it.first);
+ IdString module_name = module->name.begins_with("\\$") ?
+ module->name.substr(1) : module->name.str();
+ celltypeMap[module_name].insert(module->name);
}
}
+ for (auto &i : celltypeMap)
+ i.second.sort(RTLIL::sort_by_id_str());
for (auto module : design->modules())
worker.module_queue.insert(module);
@@ -1325,7 +1314,7 @@ struct TechmapPass : public Pass {
int module_max_iter = max_iter;
bool did_something = true;
- std::set<RTLIL::Cell*> handled_cells;
+ pool<RTLIL::Cell*> handled_cells;
while (did_something) {
did_something = false;
if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
@@ -1382,18 +1371,20 @@ struct FlattenPass : public Pass {
extra_args(args, argidx, design);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
+ dict<IdString, pool<IdString>> celltypeMap;
for (auto module : design->modules())
celltypeMap[module->name].insert(module->name);
+ for (auto &i : celltypeMap)
+ i.second.sort(RTLIL::sort_by_id_str());
- RTLIL::Module *top_mod = NULL;
+ RTLIL::Module *top_mod = nullptr;
if (design->full_selection())
for (auto mod : design->modules())
if (mod->get_bool_attribute(ID::top))
top_mod = mod;
- std::set<RTLIL::Cell*> handled_cells;
- if (top_mod != NULL) {
+ pool<RTLIL::Cell*> handled_cells;
+ if (top_mod != nullptr) {
worker.flatten_do_list.insert(top_mod->name);
while (!worker.flatten_do_list.empty()) {
auto mod = design->module(*worker.flatten_do_list.begin());
@@ -1402,20 +1393,19 @@ struct FlattenPass : public Pass {
worker.flatten_do_list.erase(mod->name);
}
} else {
- for (auto mod : vector<Module*>(design->modules())) {
+ for (auto mod : design->modules().to_vector())
while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
- }
}
log_suppressed();
log("No more expansions possible.\n");
- if (top_mod != NULL)
+ if (top_mod != nullptr)
{
- pool<RTLIL::IdString> used_modules, new_used_modules;
+ pool<IdString> used_modules, new_used_modules;
new_used_modules.insert(top_mod->name);
while (!new_used_modules.empty()) {
- pool<RTLIL::IdString> queue;
+ pool<IdString> queue;
queue.swap(new_used_modules);
for (auto modname : queue)
used_modules.insert(modname);
@@ -1425,15 +1415,11 @@ struct FlattenPass : public Pass {
new_used_modules.insert(cell->type);
}
- dict<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto mod : vector<Module*>(design->modules()))
- if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
- new_modules[mod->name] = mod;
- } else {
+ for (auto mod : design->modules().to_vector())
+ if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) {
log("Deleting now unused module %s.\n", log_id(mod));
- delete mod;
+ design->remove(mod);
}
- design->modules_.swap(new_modules);
}
log_pop();
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index cdbe922b2..c6801007d 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort(ID::Y, wire);
}
- if (muxdiv && cell_type.in(ID($div), ID($mod))) {
+ if (muxdiv && cell_type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) {
auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B));
auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y)));
module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort(ID::Y));
@@ -839,6 +839,8 @@ struct TestCellPass : public Pass {
cell_types[ID($mul)] = "ABSY";
cell_types[ID($div)] = "ABSY";
cell_types[ID($mod)] = "ABSY";
+ cell_types[ID($divfloor)] = "ABSY";
+ cell_types[ID($modfloor)] = "ABSY";
// cell_types[ID($pow)] = "ABsY";
cell_types[ID($logic_not)] = "ASY";