aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG2
-rw-r--r--Makefile3
-rw-r--r--backends/cxxrtl/cxxrtl.cc822
-rw-r--r--backends/cxxrtl/cxxrtl.h60
-rw-r--r--backends/firrtl/firrtl.cc93
-rw-r--r--frontends/ast/ast.cc5
-rw-r--r--frontends/ast/simplify.cc53
-rw-r--r--frontends/rpc/rpc_frontend.cc2
-rw-r--r--frontends/verilog/verilog_parser.y6
-rw-r--r--kernel/hashlib.h72
-rw-r--r--kernel/register.cc7
-rw-r--r--kernel/rtlil.cc40
-rw-r--r--kernel/rtlil.h13
-rw-r--r--libs/sha1/sha1.h6
-rw-r--r--libs/subcircuit/subcircuit.cc3
-rw-r--r--passes/cmds/design.cc24
-rw-r--r--passes/cmds/rename.cc222
-rw-r--r--passes/cmds/scatter.cc28
-rw-r--r--passes/cmds/select.cc25
-rw-r--r--passes/opt/opt_expr.cc19
-rw-r--r--passes/sat/qbfsat.cc6
-rw-r--r--passes/techmap/abc.cc179
-rw-r--r--passes/techmap/abc9_ops.cc49
-rw-r--r--techlibs/ecp5/dsp_map.v2
-rw-r--r--tests/arch/ecp5/memories.ys2
-rw-r--r--tests/arch/ice40/memories.ys1
-rw-r--r--tests/opt/opt_expr_alu.ys74
-rw-r--r--tests/select/unset.ys10
-rw-r--r--tests/select/unset2.ys10
-rw-r--r--tests/various/abc9.ys19
-rw-r--r--tests/various/design.ys9
-rw-r--r--tests/various/design2.ys9
-rw-r--r--tests/various/global_scope.ys18
33 files changed, 1331 insertions, 562 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5fd82fccf..df8e14b26 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -64,6 +64,8 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "opt_lut_ins" pass
- Added "logger" pass
- Removed "dffsr2dff" (use opt_rmdff instead)
+ - Added "design -delete"
+ - Added "select -unset"
Yosys 0.8 .. Yosys 0.9
----------------------
diff --git a/Makefile b/Makefile
index fc417ab9d..b3cfd71f9 100644
--- a/Makefile
+++ b/Makefile
@@ -148,7 +148,10 @@ define newline
endef
ifneq ($(wildcard Makefile.conf),)
+# don't echo Makefile.conf contents when invoked to print source versions
+ifeq ($(findstring echo-,$(MAKECMDGOALS)),)
$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,')))
+endif
include Makefile.conf
endif
diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc
index d1a855bf0..ef8335e50 100644
--- a/backends/cxxrtl/cxxrtl.cc
+++ b/backends/cxxrtl/cxxrtl.cc
@@ -171,14 +171,14 @@ struct Scheduler {
}
};
-static bool is_unary_cell(RTLIL::IdString type)
+bool is_unary_cell(RTLIL::IdString type)
{
return type.in(
ID($not), ID($logic_not), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool),
ID($pos), ID($neg));
}
-static bool is_binary_cell(RTLIL::IdString type)
+bool is_binary_cell(RTLIL::IdString type)
{
return type.in(
ID($and), ID($or), ID($xor), ID($xnor), ID($logic_and), ID($logic_or),
@@ -187,25 +187,25 @@ static bool is_binary_cell(RTLIL::IdString type)
ID($add), ID($sub), ID($mul), ID($div), ID($mod));
}
-static bool is_elidable_cell(RTLIL::IdString type)
+bool is_elidable_cell(RTLIL::IdString type)
{
return is_unary_cell(type) || is_binary_cell(type) || type.in(
ID($mux), ID($concat), ID($slice));
}
-static bool is_sync_ff_cell(RTLIL::IdString type)
+bool is_sync_ff_cell(RTLIL::IdString type)
{
return type.in(
ID($dff), ID($dffe));
}
-static bool is_ff_cell(RTLIL::IdString type)
+bool is_ff_cell(RTLIL::IdString type)
{
return is_sync_ff_cell(type) || type.in(
ID($adff), ID($dffsr), ID($dlatch), ID($dlatchsr), ID($sr));
}
-static bool is_internal_cell(RTLIL::IdString type)
+bool is_internal_cell(RTLIL::IdString type)
{
return type[0] == '$' && !type.begins_with("$paramod\\");
}
@@ -288,7 +288,7 @@ struct FlowGraph {
log_assert(cell->known());
for (auto conn : cell->connections()) {
if (cell->output(conn.first)) {
- if (is_sync_ff_cell(cell->type) || (cell->type == ID($memrd) && cell->getParam(ID(CLK_ENABLE)).as_bool()))
+ if (is_sync_ff_cell(cell->type) || (cell->type == ID($memrd) && cell->getParam(ID::CLK_ENABLE).as_bool()))
/* non-combinatorial outputs do not introduce defs */;
else if (is_elidable_cell(cell->type))
add_defs(node, conn.second, /*elidable=*/true);
@@ -356,6 +356,53 @@ struct FlowGraph {
}
};
+bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell)
+{
+ RTLIL::Module *cell_module = cell->module->design->module(cell->type);
+ log_assert(cell_module != nullptr);
+ return cell_module->get_bool_attribute(ID(cxxrtl.blackbox));
+}
+
+std::vector<std::string> split_by(const std::string &str, const std::string &sep)
+{
+ std::vector<std::string> result;
+ size_t prev = 0;
+ while (true) {
+ size_t curr = str.find_first_of(sep, prev + 1);
+ if (curr > str.size())
+ curr = str.size();
+ if (curr > prev + 1)
+ result.push_back(str.substr(prev, curr - prev));
+ if (curr == str.size())
+ break;
+ prev = curr;
+ }
+ return result;
+}
+
+std::string escape_cxx_string(const std::string &input)
+{
+ std::string output = "\"";
+ for (auto c : input) {
+ if (::isprint(c)) {
+ if (c == '\\')
+ output.push_back('\\');
+ output.push_back(c);
+ } else {
+ char l = c & 0xf, h = (c >> 4) & 0xf;
+ output.append("\\x");
+ output.push_back((h < 10 ? '0' + h : 'a' + h - 10));
+ output.push_back((l < 10 ? '0' + l : 'a' + l - 10));
+ }
+ }
+ output.push_back('"');
+ if (output.find('\0') != std::string::npos) {
+ output.insert(0, "std::string {");
+ output.append(stringf(", %zu}", input.size()));
+ }
+ return output;
+}
+
struct CxxrtlWorker {
bool split_intf = false;
std::string intf_filename;
@@ -382,6 +429,7 @@ struct CxxrtlWorker {
dict<const RTLIL::Wire*, FlowGraph::Node> elided_wires;
dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule;
pool<const RTLIL::Wire*> localized_wires;
+ dict<const RTLIL::Module*, pool<std::string>> blackbox_specializations;
void inc_indent() {
indent += "\t";
@@ -429,9 +477,11 @@ struct CxxrtlWorker {
return mangled;
}
- std::string mangle_module_name(const RTLIL::IdString &name)
+ std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false)
{
// Class namespace.
+ if (is_blackbox)
+ return "bb_" + mangle_name(name);
return mangle_name(name);
}
@@ -455,7 +505,7 @@ struct CxxrtlWorker {
std::string mangle(const RTLIL::Module *module)
{
- return mangle_module_name(module->name);
+ return mangle_module_name(module->name, /*is_blackbox=*/module->get_bool_attribute(ID(cxxrtl.blackbox)));
}
std::string mangle(const RTLIL::Memory *memory)
@@ -481,6 +531,80 @@ struct CxxrtlWorker {
return mangle(sigbit.wire) + "_" + std::to_string(sigbit.offset);
}
+ std::vector<std::string> template_param_names(const RTLIL::Module *module)
+ {
+ if (!module->has_attribute(ID(cxxrtl.template)))
+ return {};
+
+ if (module->attributes.at(ID(cxxrtl.template)).flags != RTLIL::CONST_FLAG_STRING)
+ log_cmd_error("Attribute `cxxrtl.template' of module `%s' is not a string.\n", log_id(module));
+
+ std::vector<std::string> param_names = split_by(module->get_string_attribute(ID(cxxrtl.template)), " \t");
+ for (const auto &param_name : param_names) {
+ // Various lowercase prefixes (p_, i_, cell_, ...) are used for member variables, so require
+ // parameters to start with an uppercase letter to avoid name conflicts. (This is the convention
+ // in both Verilog and C++, anyway.)
+ if (!isupper(param_name[0]))
+ log_cmd_error("Attribute `cxxrtl.template' of module `%s' includes a parameter `%s', "
+ "which does not start with an uppercase letter.\n",
+ log_id(module), param_name.c_str());
+ }
+ return param_names;
+ }
+
+ std::string template_params(const RTLIL::Module *module, bool is_decl)
+ {
+ std::vector<std::string> param_names = template_param_names(module);
+ if (param_names.empty())
+ return "";
+
+ std::string params = "<";
+ bool first = true;
+ for (const auto &param_name : param_names) {
+ if (!first)
+ params += ", ";
+ first = false;
+ if (is_decl)
+ params += "size_t ";
+ params += param_name;
+ }
+ params += ">";
+ return params;
+ }
+
+ std::string template_args(const RTLIL::Cell *cell)
+ {
+ RTLIL::Module *cell_module = cell->module->design->module(cell->type);
+ log_assert(cell_module != nullptr);
+ if (!cell_module->get_bool_attribute(ID(cxxrtl.blackbox)))
+ return "";
+
+ std::vector<std::string> param_names = template_param_names(cell_module);
+ if (param_names.empty())
+ return "";
+
+ std::string params = "<";
+ bool first = true;
+ for (const auto &param_name : param_names) {
+ if (!first)
+ params += ", ";
+ first = false;
+ params += "/*" + param_name + "=*/";
+ RTLIL::IdString id_param_name = '\\' + param_name;
+ if (!cell->hasParam(id_param_name))
+ log_cmd_error("Cell `%s.%s' does not have a parameter `%s', which is required by the templated module `%s'.\n",
+ log_id(cell->module), log_id(cell), param_name.c_str(), log_id(cell_module));
+ RTLIL::Const param_value = cell->getParam(id_param_name);
+ if (((param_value.flags & ~RTLIL::CONST_FLAG_SIGNED) != 0) || param_value.as_int() < 0)
+ log_cmd_error("Parameter `%s' of cell `%s.%s', which is required by the templated module `%s', "
+ "is not a positive integer.\n",
+ param_name.c_str(), log_id(cell->module), log_id(cell), log_id(cell_module));
+ params += std::to_string(cell->getParam(id_param_name).as_int());
+ }
+ params += ">";
+ return params;
+ }
+
std::string fresh_temporary()
{
return stringf("tmp_%d", temporary++);
@@ -549,7 +673,8 @@ struct CxxrtlWorker {
if (is_elidable_cell(node.cell->type)) {
dump_cell_elided(node.cell);
} else {
- f << mangle(node.cell) << "." << mangle_wire_name(cell_wire_defs[node.cell][chunk.wire]) << ".curr";
+ const char *access = is_cxxrtl_blackbox_cell(node.cell) ? "->" : ".";
+ f << mangle(node.cell) << access << mangle_wire_name(cell_wire_defs[node.cell][chunk.wire]) << ".curr";
}
break;
default:
@@ -660,42 +785,42 @@ struct CxxrtlWorker {
// Unary cells
if (is_unary_cell(cell->type)) {
f << cell->type.substr(1) << '_' <<
- (cell->getParam(ID(A_SIGNED)).as_bool() ? 's' : 'u') <<
- "<" << cell->getParam(ID(Y_WIDTH)).as_int() << ">(";
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') <<
+ "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ")";
// Binary cells
} else if (is_binary_cell(cell->type)) {
f << cell->type.substr(1) << '_' <<
- (cell->getParam(ID(A_SIGNED)).as_bool() ? 's' : 'u') <<
- (cell->getParam(ID(B_SIGNED)).as_bool() ? 's' : 'u') <<
- "<" << cell->getParam(ID(Y_WIDTH)).as_int() << ">(";
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ (cell->getParam(ID::A_SIGNED).as_bool() ? 's' : 'u') <<
+ (cell->getParam(ID::B_SIGNED).as_bool() ? 's' : 'u') <<
+ "<" << cell->getParam(ID::Y_WIDTH).as_int() << ">(";
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ", ";
- dump_sigspec_rhs(cell->getPort(ID(B)));
+ dump_sigspec_rhs(cell->getPort(ID::B));
f << ")";
// Muxes
} else if (cell->type == ID($mux)) {
f << "(";
- dump_sigspec_rhs(cell->getPort(ID(S)));
+ dump_sigspec_rhs(cell->getPort(ID::S));
f << " ? ";
- dump_sigspec_rhs(cell->getPort(ID(B)));
+ dump_sigspec_rhs(cell->getPort(ID::B));
f << " : ";
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ")";
// Concats
} else if (cell->type == ID($concat)) {
- dump_sigspec_rhs(cell->getPort(ID(B)));
+ dump_sigspec_rhs(cell->getPort(ID::B));
f << ".concat(";
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ").val()";
// Slices
} else if (cell->type == ID($slice)) {
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ".slice<";
- f << cell->getParam(ID(OFFSET)).as_int() + cell->getParam(ID(Y_WIDTH)).as_int() - 1;
+ f << cell->getParam(ID::OFFSET).as_int() + cell->getParam(ID::Y_WIDTH).as_int() - 1;
f << ",";
- f << cell->getParam(ID(OFFSET)).as_int();
+ f << cell->getParam(ID::OFFSET).as_int();
f << ">().val()";
} else {
log_assert(false);
@@ -704,8 +829,8 @@ struct CxxrtlWorker {
bool is_cell_elided(const RTLIL::Cell *cell)
{
- return is_elidable_cell(cell->type) && cell->hasPort(ID(Y)) && cell->getPort(ID(Y)).is_wire() &&
- elided_wires.count(cell->getPort(ID(Y)).as_wire());
+ return is_elidable_cell(cell->type) && cell->hasPort(ID::Y) && cell->getPort(ID::Y).is_wire() &&
+ elided_wires.count(cell->getPort(ID::Y).as_wire());
}
void collect_cell(const RTLIL::Cell *cell, std::vector<RTLIL::IdString> &cells)
@@ -715,7 +840,7 @@ struct CxxrtlWorker {
cells.push_back(cell->name);
for (auto port : cell->connections())
- if (port.first != ID(Y))
+ if (port.first != ID::Y)
collect_sigspec_rhs(port.second, cells);
}
@@ -729,7 +854,7 @@ struct CxxrtlWorker {
std::vector<RTLIL::IdString> elided_cells;
if (is_elidable_cell(cell->type)) {
for (auto port : cell->connections())
- if (port.first != ID(Y))
+ if (port.first != ID::Y)
collect_sigspec_rhs(port.second, elided_cells);
}
if (elided_cells.empty()) {
@@ -745,26 +870,26 @@ struct CxxrtlWorker {
// Elidable cells
if (is_elidable_cell(cell->type)) {
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Y)));
+ dump_sigspec_lhs(cell->getPort(ID::Y));
f << " = ";
dump_cell_elided(cell);
f << ";\n";
// Parallel (one-hot) muxes
} else if (cell->type == ID($pmux)) {
- int width = cell->getParam(ID(WIDTH)).as_int();
- int s_width = cell->getParam(ID(S_WIDTH)).as_int();
+ int width = cell->getParam(ID::WIDTH).as_int();
+ int s_width = cell->getParam(ID::S_WIDTH).as_int();
bool first = true;
for (int part = 0; part < s_width; part++) {
f << (first ? indent : " else ");
first = false;
f << "if (";
- dump_sigspec_rhs(cell->getPort(ID(S)).extract(part));
+ dump_sigspec_rhs(cell->getPort(ID::S).extract(part));
f << ") {\n";
inc_indent();
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Y)));
+ dump_sigspec_lhs(cell->getPort(ID::Y));
f << " = ";
- dump_sigspec_rhs(cell->getPort(ID(B)).extract(part * width, width));
+ dump_sigspec_rhs(cell->getPort(ID::B).extract(part * width, width));
f << ";\n";
dec_indent();
f << indent << "}";
@@ -772,31 +897,31 @@ struct CxxrtlWorker {
f << " else {\n";
inc_indent();
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Y)));
+ dump_sigspec_lhs(cell->getPort(ID::Y));
f << " = ";
- dump_sigspec_rhs(cell->getPort(ID(A)));
+ dump_sigspec_rhs(cell->getPort(ID::A));
f << ";\n";
dec_indent();
f << indent << "}\n";
// Flip-flops
} else if (is_ff_cell(cell->type)) {
- if (cell->hasPort(ID(CLK)) && cell->getPort(ID(CLK)).is_wire()) {
+ if (cell->hasPort(ID::CLK) && cell->getPort(ID::CLK).is_wire()) {
// Edge-sensitive logic
- RTLIL::SigBit clk_bit = cell->getPort(ID(CLK))[0];
+ RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0];
clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
- f << indent << "if (" << (cell->getParam(ID(CLK_POLARITY)).as_bool() ? "posedge_" : "negedge_")
+ f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_")
<< mangle(clk_bit) << ") {\n";
inc_indent();
if (cell->type == ID($dffe)) {
f << indent << "if (";
- dump_sigspec_rhs(cell->getPort(ID(EN)));
- f << " == value<1> {" << cell->getParam(ID(EN_POLARITY)).as_bool() << "u}) {\n";
+ dump_sigspec_rhs(cell->getPort(ID::EN));
+ f << " == value<1> {" << cell->getParam(ID::EN_POLARITY).as_bool() << "u}) {\n";
inc_indent();
}
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << " = ";
- dump_sigspec_rhs(cell->getPort(ID(D)));
+ dump_sigspec_rhs(cell->getPort(ID::D));
f << ";\n";
if (cell->type == ID($dffe)) {
dec_indent();
@@ -804,77 +929,77 @@ struct CxxrtlWorker {
}
dec_indent();
f << indent << "}\n";
- } else if (cell->hasPort(ID(EN))) {
+ } else if (cell->hasPort(ID::EN)) {
// Level-sensitive logic
f << indent << "if (";
- dump_sigspec_rhs(cell->getPort(ID(EN)));
- f << " == value<1> {" << cell->getParam(ID(EN_POLARITY)).as_bool() << "u}) {\n";
+ dump_sigspec_rhs(cell->getPort(ID::EN));
+ f << " == value<1> {" << cell->getParam(ID::EN_POLARITY).as_bool() << "u}) {\n";
inc_indent();
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << " = ";
- dump_sigspec_rhs(cell->getPort(ID(D)));
+ dump_sigspec_rhs(cell->getPort(ID::D));
f << ";\n";
dec_indent();
f << indent << "}\n";
}
- if (cell->hasPort(ID(ARST))) {
+ if (cell->hasPort(ID::ARST)) {
// Asynchronous reset (entire coarse cell at once)
f << indent << "if (";
- dump_sigspec_rhs(cell->getPort(ID(ARST)));
- f << " == value<1> {" << cell->getParam(ID(ARST_POLARITY)).as_bool() << "u}) {\n";
+ dump_sigspec_rhs(cell->getPort(ID::ARST));
+ f << " == value<1> {" << cell->getParam(ID::ARST_POLARITY).as_bool() << "u}) {\n";
inc_indent();
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << " = ";
- dump_const(cell->getParam(ID(ARST_VALUE)));
+ dump_const(cell->getParam(ID::ARST_VALUE));
f << ";\n";
dec_indent();
f << indent << "}\n";
}
- if (cell->hasPort(ID(SET))) {
+ if (cell->hasPort(ID::SET)) {
// Asynchronous set (for individual bits)
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << " = ";
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << ".update(";
- dump_const(RTLIL::Const(RTLIL::S1, cell->getParam(ID(WIDTH)).as_int()));
+ dump_const(RTLIL::Const(RTLIL::S1, cell->getParam(ID::WIDTH).as_int()));
f << ", ";
- dump_sigspec_rhs(cell->getPort(ID(SET)));
- f << (cell->getParam(ID(SET_POLARITY)).as_bool() ? "" : ".bit_not()") << ");\n";
+ dump_sigspec_rhs(cell->getPort(ID::SET));
+ f << (cell->getParam(ID::SET_POLARITY).as_bool() ? "" : ".bit_not()") << ");\n";
}
- if (cell->hasPort(ID(CLR))) {
+ if (cell->hasPort(ID::CLR)) {
// Asynchronous clear (for individual bits; priority over set)
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << " = ";
- dump_sigspec_lhs(cell->getPort(ID(Q)));
+ dump_sigspec_lhs(cell->getPort(ID::Q));
f << ".update(";
- dump_const(RTLIL::Const(RTLIL::S0, cell->getParam(ID(WIDTH)).as_int()));
+ dump_const(RTLIL::Const(RTLIL::S0, cell->getParam(ID::WIDTH).as_int()));
f << ", ";
- dump_sigspec_rhs(cell->getPort(ID(CLR)));
- f << (cell->getParam(ID(CLR_POLARITY)).as_bool() ? "" : ".bit_not()") << ");\n";
+ dump_sigspec_rhs(cell->getPort(ID::CLR));
+ f << (cell->getParam(ID::CLR_POLARITY).as_bool() ? "" : ".bit_not()") << ");\n";
}
// Memory ports
} else if (cell->type.in(ID($memrd), ID($memwr))) {
- if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
- RTLIL::SigBit clk_bit = cell->getPort(ID(CLK))[0];
+ if (cell->getParam(ID::CLK_ENABLE).as_bool()) {
+ RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0];
clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
- f << indent << "if (" << (cell->getParam(ID(CLK_POLARITY)).as_bool() ? "posedge_" : "negedge_")
+ f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_")
<< mangle(clk_bit) << ") {\n";
inc_indent();
}
- RTLIL::Memory *memory = cell->module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ RTLIL::Memory *memory = cell->module->memories[cell->getParam(ID::MEMID).decode_string()];
std::string valid_index_temp = fresh_temporary();
f << indent << "auto " << valid_index_temp << " = memory_index(";
- dump_sigspec_rhs(cell->getPort(ID(ADDR)));
+ dump_sigspec_rhs(cell->getPort(ID::ADDR));
f << ", " << memory->start_offset << ", " << memory->size << ");\n";
if (cell->type == ID($memrd)) {
- bool has_enable = cell->getParam(ID(CLK_ENABLE)).as_bool() && !cell->getPort(ID(EN)).is_fully_ones();
+ bool has_enable = cell->getParam(ID::CLK_ENABLE).as_bool() && !cell->getPort(ID::EN).is_fully_ones();
if (has_enable) {
f << indent << "if (";
- dump_sigspec_rhs(cell->getPort(ID(EN)));
+ dump_sigspec_rhs(cell->getPort(ID::EN));
f << ") {\n";
inc_indent();
}
@@ -890,8 +1015,8 @@ struct CxxrtlWorker {
inc_indent();
if (writable_memories[memory]) {
std::string addr_temp = fresh_temporary();
- f << indent << "const value<" << cell->getPort(ID(ADDR)).size() << "> &" << addr_temp << " = ";
- dump_sigspec_rhs(cell->getPort(ID(ADDR)));
+ f << indent << "const value<" << cell->getPort(ID::ADDR).size() << "> &" << addr_temp << " = ";
+ dump_sigspec_rhs(cell->getPort(ID::ADDR));
f << ";\n";
std::string lhs_temp = fresh_temporary();
f << indent << "value<" << memory->width << "> " << lhs_temp << " = "
@@ -899,35 +1024,35 @@ struct CxxrtlWorker {
std::vector<const RTLIL::Cell*> memwr_cells(transparent_for[cell].begin(), transparent_for[cell].end());
std::sort(memwr_cells.begin(), memwr_cells.end(),
[](const RTLIL::Cell *a, const RTLIL::Cell *b) {
- return a->getParam(ID(PRIORITY)).as_int() < b->getParam(ID(PRIORITY)).as_int();
+ return a->getParam(ID::PRIORITY).as_int() < b->getParam(ID::PRIORITY).as_int();
});
for (auto memwr_cell : memwr_cells) {
f << indent << "if (" << addr_temp << " == ";
- dump_sigspec_rhs(memwr_cell->getPort(ID(ADDR)));
+ dump_sigspec_rhs(memwr_cell->getPort(ID::ADDR));
f << ") {\n";
inc_indent();
f << indent << lhs_temp << " = " << lhs_temp;
f << ".update(";
- dump_sigspec_rhs(memwr_cell->getPort(ID(DATA)));
+ dump_sigspec_rhs(memwr_cell->getPort(ID::DATA));
f << ", ";
- dump_sigspec_rhs(memwr_cell->getPort(ID(EN)));
+ dump_sigspec_rhs(memwr_cell->getPort(ID::EN));
f << ");\n";
dec_indent();
f << indent << "}\n";
}
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ dump_sigspec_lhs(cell->getPort(ID::DATA));
f << " = " << lhs_temp << ";\n";
} else {
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ dump_sigspec_lhs(cell->getPort(ID::DATA));
f << " = " << mangle(memory) << "[" << valid_index_temp << ".index];\n";
}
dec_indent();
f << indent << "} else {\n";
inc_indent();
f << indent;
- dump_sigspec_lhs(cell->getPort(ID(DATA)));
+ dump_sigspec_lhs(cell->getPort(ID::DATA));
f << " = value<" << memory->width << "> {};\n";
dec_indent();
f << indent << "}\n";
@@ -944,14 +1069,14 @@ struct CxxrtlWorker {
f << indent << "if (" << valid_index_temp << ".valid) {\n";
inc_indent();
f << indent << mangle(memory) << ".update(" << valid_index_temp << ".index, ";
- dump_sigspec_rhs(cell->getPort(ID(DATA)));
+ dump_sigspec_rhs(cell->getPort(ID::DATA));
f << ", ";
- dump_sigspec_rhs(cell->getPort(ID(EN)));
- f << ", " << cell->getParam(ID(PRIORITY)).as_int() << ");\n";
+ dump_sigspec_rhs(cell->getPort(ID::EN));
+ f << ", " << cell->getParam(ID::PRIORITY).as_int() << ");\n";
dec_indent();
f << indent << "}\n";
}
- if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
+ if (cell->getParam(ID::CLK_ENABLE).as_bool()) {
dec_indent();
f << indent << "}\n";
}
@@ -961,13 +1086,14 @@ struct CxxrtlWorker {
// User cells
} else {
log_assert(cell->known());
+ const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
for (auto conn : cell->connections())
if (cell->input(conn.first)) {
- f << indent << mangle(cell) << "." << mangle_wire_name(conn.first) << ".next = ";
+ f << indent << mangle(cell) << access << mangle_wire_name(conn.first) << ".next = ";
dump_sigspec_rhs(conn.second);
f << ";\n";
}
- f << indent << mangle(cell) << ".eval();\n";
+ f << indent << mangle(cell) << access << "eval();\n";
for (auto conn : cell->connections()) {
if (conn.second.is_wire()) {
RTLIL::Wire *wire = conn.second.as_wire();
@@ -979,7 +1105,7 @@ struct CxxrtlWorker {
continue; // ignore disconnected ports
f << indent;
dump_sigspec_lhs(conn.second);
- f << " = " << mangle(cell) << "." << mangle_wire_name(conn.first) << ".curr;\n";
+ f << " = " << mangle(cell) << access << mangle_wire_name(conn.first) << ".curr;\n";
}
}
}
@@ -1076,24 +1202,34 @@ struct CxxrtlWorker {
log_assert(proc->root_case.attributes.empty());
dump_case_rule(&proc->root_case);
for (auto sync : proc->syncs) {
- RTLIL::SigBit sync_bit = sync->signal[0];
- sync_bit = sigmaps[sync_bit.wire->module](sync_bit);
+ RTLIL::SigBit sync_bit;
+ if (!sync->signal.empty()) {
+ sync_bit = sync->signal[0];
+ sync_bit = sigmaps[sync_bit.wire->module](sync_bit);
+ }
pool<std::string> events;
switch (sync->type) {
case RTLIL::STp:
+ log_assert(sync_bit.wire != nullptr);
events.insert("posedge_" + mangle(sync_bit));
break;
case RTLIL::STn:
+ log_assert(sync_bit.wire != nullptr);
events.insert("negedge_" + mangle(sync_bit));
+ break;
case RTLIL::STe:
+ log_assert(sync_bit.wire != nullptr);
events.insert("posedge_" + mangle(sync_bit));
events.insert("negedge_" + mangle(sync_bit));
break;
+ case RTLIL::STa:
+ events.insert("true");
+ break;
+
case RTLIL::ST0:
case RTLIL::ST1:
- case RTLIL::STa:
case RTLIL::STg:
case RTLIL::STi:
log_assert(false);
@@ -1132,11 +1268,18 @@ struct CxxrtlWorker {
if (localized_wires.count(wire))
return;
+ std::string width;
+ if (wire->module->has_attribute(ID(cxxrtl.blackbox)) && wire->has_attribute(ID(cxxrtl.width))) {
+ width = wire->get_string_attribute(ID(cxxrtl.width));
+ } else {
+ width = std::to_string(wire->width);
+ }
+
dump_attrs(wire);
- f << indent << "wire<" << wire->width << "> " << mangle(wire);
- if (wire->attributes.count(ID(init))) {
+ f << indent << "wire<" << width << "> " << mangle(wire);
+ if (wire->has_attribute(ID::init)) {
f << " ";
- dump_const_init(wire->attributes.at(ID(init)));
+ dump_const_init(wire->attributes.at(ID::init));
}
f << ";\n";
if (sync_wires[wire]) {
@@ -1156,18 +1299,17 @@ struct CxxrtlWorker {
{
vector<const RTLIL::Cell*> init_cells;
for (auto cell : module->cells())
- if (cell->type == ID($meminit) && cell->getParam(ID(MEMID)).decode_string() == memory->name.str())
+ if (cell->type == ID($meminit) && cell->getParam(ID::MEMID).decode_string() == memory->name.str())
init_cells.push_back(cell);
std::sort(init_cells.begin(), init_cells.end(), [](const RTLIL::Cell *a, const RTLIL::Cell *b) {
- int a_addr = a->getPort(ID(ADDR)).as_int(), b_addr = b->getPort(ID(ADDR)).as_int();
- int a_prio = a->getParam(ID(PRIORITY)).as_int(), b_prio = b->getParam(ID(PRIORITY)).as_int();
+ int a_addr = a->getPort(ID::ADDR).as_int(), b_addr = b->getPort(ID::ADDR).as_int();
+ int a_prio = a->getParam(ID::PRIORITY).as_int(), b_prio = b->getParam(ID::PRIORITY).as_int();
return a_prio > b_prio || (a_prio == b_prio && a_addr < b_addr);
});
dump_attrs(memory);
- f << indent << (writable_memories[memory] ? "" : "const ")
- << "memory<" << memory->width << "> " << mangle(memory)
+ f << indent << "memory<" << memory->width << "> " << mangle(memory)
<< " { " << memory->size << "u";
if (init_cells.empty()) {
f << " };\n";
@@ -1176,11 +1318,11 @@ struct CxxrtlWorker {
inc_indent();
for (auto cell : init_cells) {
dump_attrs(cell);
- RTLIL::Const data = cell->getPort(ID(DATA)).as_const();
- size_t width = cell->getParam(ID(WIDTH)).as_int();
- size_t words = cell->getParam(ID(WORDS)).as_int();
+ RTLIL::Const data = cell->getPort(ID::DATA).as_const();
+ size_t width = cell->getParam(ID::WIDTH).as_int();
+ size_t words = cell->getParam(ID::WORDS).as_int();
f << indent << "memory<" << memory->width << ">::init<" << words << "> { "
- << stringf("%#x", cell->getPort(ID(ADDR)).as_int()) << ", {";
+ << stringf("%#x", cell->getPort(ID::ADDR).as_int()) << ", {";
inc_indent();
for (size_t n = 0; n < words; n++) {
if (n % 4 == 0)
@@ -1198,54 +1340,24 @@ struct CxxrtlWorker {
}
}
- void dump_module_intf(RTLIL::Module *module)
+ void dump_eval_method(RTLIL::Module *module)
{
- dump_attrs(module);
- f << "struct " << mangle(module) << " : public module {\n";
inc_indent();
- for (auto wire : module->wires())
- dump_wire(wire, /*is_local=*/false);
- f << "\n";
- bool has_memories = false;
- for (auto memory : module->memories) {
- dump_memory(module, memory.second);
- has_memories = true;
- }
- if (has_memories)
- f << "\n";
- bool has_cells = false;
- for (auto cell : module->cells()) {
- if (is_internal_cell(cell->type))
- continue;
- f << indent << mangle_module_name(cell->type) << " " << mangle(cell) << ";\n";
- has_cells = true;
- }
- if (has_cells)
- f << "\n";
- f << indent << "void eval() override;\n";
- f << indent << "bool commit() override;\n";
- dec_indent();
- f << "}; // struct " << mangle(module) << "\n";
- f << "\n";
- }
-
- void dump_module_impl(RTLIL::Module *module)
- {
- f << "void " << mangle(module) << "::eval() {\n";
- inc_indent();
- for (auto wire : module->wires())
- dump_wire(wire, /*is_local=*/true);
- for (auto node : schedule[module]) {
- switch (node.type) {
- case FlowGraph::Node::Type::CONNECT:
- dump_connect(node.connect);
- break;
- case FlowGraph::Node::Type::CELL:
- dump_cell(node.cell);
- break;
- case FlowGraph::Node::Type::PROCESS:
- dump_process(node.process);
- break;
+ if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) {
+ for (auto wire : module->wires())
+ dump_wire(wire, /*is_local=*/true);
+ for (auto node : schedule[module]) {
+ switch (node.type) {
+ case FlowGraph::Node::Type::CONNECT:
+ dump_connect(node.connect);
+ break;
+ case FlowGraph::Node::Type::CELL:
+ dump_cell(node.cell);
+ break;
+ case FlowGraph::Node::Type::PROCESS:
+ dump_process(node.process);
+ break;
+ }
}
}
for (auto sync_type : sync_types) {
@@ -1257,10 +1369,10 @@ struct CxxrtlWorker {
}
}
dec_indent();
- f << "}\n";
- f << "\n";
+ }
- f << "bool " << mangle(module) << "::commit() {\n";
+ void dump_commit_method(RTLIL::Module *module)
+ {
inc_indent();
f << indent << "bool changed = false;\n";
for (auto wire : module->wires()) {
@@ -1296,42 +1408,180 @@ struct CxxrtlWorker {
}
dec_indent();
f << indent << "}\n";
- } else {
+ } else if (!module->get_bool_attribute(ID(cxxrtl.blackbox)) || wire->port_id != 0) {
f << indent << "changed |= " << mangle(wire) << ".commit();\n";
}
}
- for (auto memory : module->memories) {
- if (!writable_memories[memory.second])
- continue;
- f << indent << "changed |= " << mangle(memory.second) << ".commit();\n";
+ if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) {
+ for (auto memory : module->memories) {
+ if (!writable_memories[memory.second])
+ continue;
+ f << indent << "changed |= " << mangle(memory.second) << ".commit();\n";
+ }
+ for (auto cell : module->cells()) {
+ if (is_internal_cell(cell->type))
+ continue;
+ const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
+ f << indent << "changed |= " << mangle(cell) << access << "commit();\n";
+ }
}
- for (auto cell : module->cells()) {
- if (is_internal_cell(cell->type))
+ f << indent << "return changed;\n";
+ dec_indent();
+ }
+
+ void dump_metadata_map(const dict<RTLIL::IdString, RTLIL::Const> &metadata_map)
+ {
+ if (metadata_map.empty()) {
+ f << "metadata_map()";
+ return;
+ }
+ f << "metadata_map({\n";
+ inc_indent();
+ for (auto metadata_item : metadata_map) {
+ if (!metadata_item.first.begins_with("\\"))
continue;
- f << indent << "changed |= " << mangle(cell) << ".commit();\n";
+ f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", ";
+ if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) {
+ f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint;
+ } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) {
+ f << escape_cxx_string(metadata_item.second.decode_string());
+ } else {
+ f << metadata_item.second.as_int(/*is_signed=*/metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED);
+ if (!(metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED))
+ f << "u";
+ }
+ f << " },\n";
}
- f << indent << "return changed;\n";
dec_indent();
- f << "}\n";
+ f << indent << "})";
+ }
+
+ void dump_module_intf(RTLIL::Module *module)
+ {
+ dump_attrs(module);
+ if (module->get_bool_attribute(ID(cxxrtl.blackbox))) {
+ if (module->has_attribute(ID(cxxrtl.template)))
+ f << indent << "template" << template_params(module, /*is_decl=*/true) << "\n";
+ f << indent << "struct " << mangle(module) << " : public module {\n";
+ inc_indent();
+ for (auto wire : module->wires()) {
+ if (wire->port_id != 0)
+ dump_wire(wire, /*is_local=*/false);
+ }
+ f << "\n";
+ f << indent << "void eval() override {\n";
+ dump_eval_method(module);
+ f << indent << "}\n";
+ f << "\n";
+ f << indent << "bool commit() override {\n";
+ dump_commit_method(module);
+ f << indent << "}\n";
+ f << "\n";
+ f << indent << "static std::unique_ptr<" << mangle(module);
+ f << template_params(module, /*is_decl=*/false) << "> ";
+ f << "create(std::string name, metadata_map parameters, metadata_map attributes);\n";
+ dec_indent();
+ f << indent << "}; // struct " << mangle(module) << "\n";
+ f << "\n";
+ if (blackbox_specializations.count(module)) {
+ // If templated black boxes are used, the constructor of any module which includes the black box cell
+ // (which calls the declared but not defined in the generated code `create` function) may only be used
+ // if (a) the create function is defined in the same translation unit, or (b) the create function has
+ // a forward-declared explicit specialization.
+ //
+ // Option (b) makes it possible to have the generated code and the black box implementation in different
+ // translation units, which is convenient. Of course, its downside is that black boxes must predefine
+ // a specialization for every combination of parameters the generated code may use; but since the main
+ // purpose of templated black boxes is abstracting over datapath width, it is expected that there would
+ // be very few such combinations anyway.
+ for (auto specialization : blackbox_specializations[module]) {
+ f << indent << "template<>\n";
+ f << indent << "std::unique_ptr<" << mangle(module) << specialization << "> ";
+ f << mangle(module) << specialization << "::";
+ f << "create(std::string name, metadata_map parameters, metadata_map attributes);\n";
+ f << "\n";
+ }
+ }
+ } else {
+ f << indent << "struct " << mangle(module) << " : public module {\n";
+ inc_indent();
+ for (auto wire : module->wires())
+ dump_wire(wire, /*is_local=*/false);
+ f << "\n";
+ bool has_memories = false;
+ for (auto memory : module->memories) {
+ dump_memory(module, memory.second);
+ has_memories = true;
+ }
+ if (has_memories)
+ f << "\n";
+ bool has_cells = false;
+ for (auto cell : module->cells()) {
+ if (is_internal_cell(cell->type))
+ continue;
+ dump_attrs(cell);
+ RTLIL::Module *cell_module = module->design->module(cell->type);
+ log_assert(cell_module != nullptr);
+ if (cell_module->get_bool_attribute(ID(cxxrtl.blackbox))) {
+ f << indent << "std::unique_ptr<" << mangle(cell_module) << template_args(cell) << "> ";
+ f << mangle(cell) << " = " << mangle(cell_module) << template_args(cell);
+ f << "::create(" << escape_cxx_string(cell->name.str()) << ", ";
+ dump_metadata_map(cell->parameters);
+ f << ", ";
+ dump_metadata_map(cell->attributes);
+ f << ");\n";
+ } else {
+ f << indent << mangle(cell_module) << " " << mangle(cell) << ";\n";
+ }
+ has_cells = true;
+ }
+ if (has_cells)
+ f << "\n";
+ f << indent << "void eval() override;\n";
+ f << indent << "bool commit() override;\n";
+ dec_indent();
+ f << indent << "}; // struct " << mangle(module) << "\n";
+ f << "\n";
+ }
+ }
+
+ void dump_module_impl(RTLIL::Module *module)
+ {
+ if (module->get_bool_attribute(ID(cxxrtl.blackbox)))
+ return;
+ f << indent << "void " << mangle(module) << "::eval() {\n";
+ dump_eval_method(module);
+ f << indent << "}\n";
+ f << "\n";
+ f << indent << "bool " << mangle(module) << "::commit() {\n";
+ dump_commit_method(module);
+ f << indent << "}\n";
f << "\n";
}
void dump_design(RTLIL::Design *design)
{
+ std::vector<RTLIL::Module*> modules;
TopoSort<RTLIL::Module*> topo_design;
for (auto module : design->modules()) {
- if (module->get_blackbox_attribute() || !design->selected_module(module))
+ if (!design->selected_module(module))
+ continue;
+ if (module->get_bool_attribute(ID(cxxrtl.blackbox)))
+ modules.push_back(module); // cxxrtl blackboxes first
+ if (module->get_blackbox_attribute() || module->get_bool_attribute(ID(cxxrtl.blackbox)))
continue;
- topo_design.node(module);
+ topo_design.node(module);
for (auto cell : module->cells()) {
- if (is_internal_cell(cell->type))
+ if (is_internal_cell(cell->type) || is_cxxrtl_blackbox_cell(cell))
continue;
- log_assert(design->has(cell->type));
- topo_design.edge(design->module(cell->type), module);
+ RTLIL::Module *cell_module = design->module(cell->type);
+ log_assert(cell_module != nullptr);
+ topo_design.edge(cell_module, module);
}
}
log_assert(topo_design.sort());
+ modules.insert(modules.end(), topo_design.sorted.begin(), topo_design.sorted.end());
if (split_intf) {
// The only thing more depraved than include guards, is mangling filenames to turn them into include guards.
@@ -1347,11 +1597,8 @@ struct CxxrtlWorker {
f << "\n";
f << "namespace " << design_ns << " {\n";
f << "\n";
- for (auto module : topo_design.sorted) {
- if (!design->selected_module(module))
- continue;
+ for (auto module : modules)
dump_module_intf(module);
- }
f << "} // namespace " << design_ns << "\n";
f << "\n";
f << "#endif\n";
@@ -1367,9 +1614,7 @@ struct CxxrtlWorker {
f << "\n";
f << "namespace " << design_ns << " {\n";
f << "\n";
- for (auto module : topo_design.sorted) {
- if (!design->selected_module(module))
- continue;
+ for (auto module : modules) {
if (!split_intf)
dump_module_intf(module);
dump_module_impl(module);
@@ -1407,10 +1652,39 @@ struct CxxrtlWorker {
if (!design->selected_module(module))
continue;
- FlowGraph flow;
SigMap &sigmap = sigmaps[module];
sigmap.set(module);
+ if (module->get_bool_attribute(ID(cxxrtl.blackbox))) {
+ for (auto port : module->ports) {
+ RTLIL::Wire *wire = module->wire(port);
+ if (wire->has_attribute(ID(cxxrtl.edge))) {
+ RTLIL::Const edge_attr = wire->attributes[ID(cxxrtl.edge)];
+ if (!(edge_attr.flags & RTLIL::CONST_FLAG_STRING) || (int)edge_attr.decode_string().size() != GetSize(wire))
+ log_cmd_error("Attribute `cxxrtl.edge' of port `%s.%s' is not a string with one character per bit.\n",
+ log_id(module), log_signal(wire));
+
+ std::string edges = wire->get_string_attribute(ID(cxxrtl.edge));
+ for (int i = 0; i < GetSize(wire); i++) {
+ RTLIL::SigSpec wire_sig = wire;
+ switch (edges[i]) {
+ case '-': break;
+ case 'p': register_edge_signal(sigmap, wire_sig[i], RTLIL::STp); break;
+ case 'n': register_edge_signal(sigmap, wire_sig[i], RTLIL::STn); break;
+ case 'a': register_edge_signal(sigmap, wire_sig[i], RTLIL::STe); break;
+ default:
+ log_cmd_error("Attribute `cxxrtl.edge' of port `%s.%s' contains specifiers "
+ "other than '-', 'p', 'n', or 'a'.\n",
+ log_id(module), log_signal(wire));
+ }
+ }
+ }
+ }
+ continue;
+ }
+
+ FlowGraph flow;
+
for (auto conn : module->connections())
flow.add_node(conn);
@@ -1418,32 +1692,44 @@ struct CxxrtlWorker {
dict<std::pair<RTLIL::SigBit, const RTLIL::Memory*>,
pool<const RTLIL::Cell*>> memwr_per_domain;
for (auto cell : module->cells()) {
+ if (!cell->known())
+ log_cmd_error("Unknown cell `%s'.\n", log_id(cell->type));
+
+ RTLIL::Module *cell_module = design->module(cell->type);
+ if (cell_module &&
+ cell_module->get_blackbox_attribute() &&
+ !cell_module->get_bool_attribute(ID(cxxrtl.blackbox)))
+ log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", log_id(cell->type));
+
+ if (cell_module &&
+ cell_module->get_bool_attribute(ID(cxxrtl.blackbox)) &&
+ cell_module->get_bool_attribute(ID(cxxrtl.template)))
+ blackbox_specializations[cell_module].insert(template_args(cell));
+
FlowGraph::Node *node = flow.add_node(cell);
// Various DFF cells are treated like posedge/negedge processes, see above for details.
if (cell->type.in(ID($dff), ID($dffe), ID($adff), ID($dffsr))) {
- if (cell->getPort(ID(CLK)).is_wire())
- register_edge_signal(sigmap, cell->getPort(ID(CLK)),
- cell->parameters[ID(CLK_POLARITY)].as_bool() ? RTLIL::STp : RTLIL::STn);
- // The $adff and $dffsr cells are level-sensitive, not edge-sensitive (in spite of the fact that they
- // are inferred from an edge-sensitive Verilog process) and do not correspond to an edge-type sync rule.
+ if (cell->getPort(ID::CLK).is_wire())
+ register_edge_signal(sigmap, cell->getPort(ID::CLK),
+ cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn);
}
// Similar for memory port cells.
if (cell->type.in(ID($memrd), ID($memwr))) {
- if (cell->getParam(ID(CLK_ENABLE)).as_bool()) {
- if (cell->getPort(ID(CLK)).is_wire())
- register_edge_signal(sigmap, cell->getPort(ID(CLK)),
- cell->parameters[ID(CLK_POLARITY)].as_bool() ? RTLIL::STp : RTLIL::STn);
+ if (cell->getParam(ID::CLK_ENABLE).as_bool()) {
+ if (cell->getPort(ID::CLK).is_wire())
+ register_edge_signal(sigmap, cell->getPort(ID::CLK),
+ cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn);
}
memrw_cell_nodes[cell] = node;
}
// Optimize access to read-only memories.
if (cell->type == ID($memwr))
- writable_memories.insert(module->memories[cell->getParam(ID(MEMID)).decode_string()]);
+ writable_memories.insert(module->memories[cell->getParam(ID::MEMID).decode_string()]);
// Collect groups of memory write ports in the same domain.
- if (cell->type == ID($memwr) && cell->getParam(ID(CLK_ENABLE)).as_bool() && cell->getPort(ID(CLK)).is_wire()) {
- RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID(CLK)))[0];
- const RTLIL::Memory *memory = module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ if (cell->type == ID($memwr) && cell->getParam(ID::CLK_ENABLE).as_bool() && cell->getPort(ID::CLK).is_wire()) {
+ RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID::CLK))[0];
+ const RTLIL::Memory *memory = module->memories[cell->getParam(ID::MEMID).decode_string()];
memwr_per_domain[{clk_bit, memory}].insert(cell);
}
// Handling of packed memories is delegated to the `memory_unpack` pass, so we can rely on the presence
@@ -1453,17 +1739,17 @@ struct CxxrtlWorker {
}
for (auto cell : module->cells()) {
// Collect groups of memory write ports read by every transparent read port.
- if (cell->type == ID($memrd) && cell->getParam(ID(CLK_ENABLE)).as_bool() && cell->getPort(ID(CLK)).is_wire() &&
- cell->getParam(ID(TRANSPARENT)).as_bool()) {
- RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID(CLK)))[0];
- const RTLIL::Memory *memory = module->memories[cell->getParam(ID(MEMID)).decode_string()];
+ if (cell->type == ID($memrd) && cell->getParam(ID::CLK_ENABLE).as_bool() && cell->getPort(ID::CLK).is_wire() &&
+ cell->getParam(ID::TRANSPARENT).as_bool()) {
+ RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID::CLK))[0];
+ const RTLIL::Memory *memory = module->memories[cell->getParam(ID::MEMID).decode_string()];
for (auto memwr_cell : memwr_per_domain[{clk_bit, memory}]) {
transparent_for[cell].insert(memwr_cell);
// Our implementation of transparent $memrd cells reads \EN, \ADDR and \DATA from every $memwr cell
// in the same domain, which isn't directly visible in the netlist. Add these uses explicitly.
- flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(EN)));
- flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(ADDR)));
- flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID(DATA)));
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID::EN));
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID::ADDR));
+ flow.add_uses(memrw_cell_nodes[cell], memwr_cell->getPort(ID::DATA));
}
}
}
@@ -1499,7 +1785,7 @@ struct CxxrtlWorker {
for (auto wire : module->wires()) {
if (!flow.is_elidable(wire)) continue;
if (wire->port_id != 0) continue;
- if (wire->get_bool_attribute(ID(keep))) continue;
+ if (wire->get_bool_attribute(ID::keep)) continue;
if (wire->name.begins_with("$") && !elide_internal) continue;
if (wire->name.begins_with("\\") && !elide_public) continue;
if (sync_wires[wire]) continue;
@@ -1557,7 +1843,7 @@ struct CxxrtlWorker {
if (!feedback_wires.empty()) {
has_feedback_arcs = true;
- log("Module `%s` contains feedback arcs through wires:\n", module->name.c_str());
+ log("Module `%s' contains feedback arcs through wires:\n", module->name.c_str());
for (auto wire : feedback_wires) {
log(" %s\n", wire->name.c_str());
}
@@ -1566,7 +1852,7 @@ struct CxxrtlWorker {
for (auto wire : module->wires()) {
if (feedback_wires[wire]) continue;
if (wire->port_id != 0) continue;
- if (wire->get_bool_attribute(ID(keep))) continue;
+ if (wire->get_bool_attribute(ID::keep)) continue;
if (wire->name.begins_with("$") && !localize_internal) continue;
if (wire->name.begins_with("\\") && !localize_public) continue;
if (sync_wires[wire]) continue;
@@ -1585,12 +1871,12 @@ struct CxxrtlWorker {
has_sync_init = has_packed_mem = false;
for (auto module : design->modules()) {
- if (module->get_blackbox_attribute())
+ if (module->get_blackbox_attribute() && !module->has_attribute(ID(cxxrtl.blackbox)))
continue;
if (!design->selected_whole_module(module))
if (design->selected_module(module))
- log_cmd_error("Can't handle partially selected module `%s`!\n", id2cstr(module->name));
+ log_cmd_error("Can't handle partially selected module `%s'!\n", id2cstr(module->name));
if (!design->selected_module(module))
continue;
@@ -1642,21 +1928,145 @@ struct CxxrtlBackend : public Backend {
log("\n");
log(" write_cxxrtl [options] [filename]\n");
log("\n");
- log("Write C++ code for simulating the design. The generated code requires a driver;\n");
- log("the following simple driver is provided as an example:\n");
+ log("Write C++ code that simulates the design. The generated code requires a driver\n");
+ log("that instantiates the design, toggles its clock, and interacts with its ports.\n");
+ log("\n");
+ log("The following driver may be used as an example for a design with a single clock\n");
+ log("driving rising edge triggered flip-flops:\n");
log("\n");
log(" #include \"top.cc\"\n");
log("\n");
log(" int main() {\n");
log(" cxxrtl_design::p_top top;\n");
+ log(" top.step();\n");
log(" while (1) {\n");
- log(" top.p_clk.next = value<1> {1u};\n");
- log(" top.step();\n");
+ log(" /* user logic */\n");
log(" top.p_clk.next = value<1> {0u};\n");
log(" top.step();\n");
+ log(" top.p_clk.next = value<1> {1u};\n");
+ log(" top.step();\n");
+ log(" }\n");
+ log(" }\n");
+ log("\n");
+ log("Note that CXXRTL simulations, just like the hardware they are simulating, are\n");
+ log("subject to race conditions. If, in the example above, the user logic would run\n");
+ log("simultaneously with the rising edge of the clock, the design would malfunction.\n");
+ log("\n");
+ log("This backend supports replacing parts of the design with black boxes implemented\n");
+ log("in C++. If a module marked as a CXXRTL black box, its implementation is ignored,\n");
+ log("and the generated code consists only of an interface and a factory function.\n");
+ log("The driver must implement the factory function that creates an implementation of\n");
+ log("the black box, taking into account the parameters it is instantiated with.\n");
+ log("\n");
+ log("For example, the following Verilog code defines a CXXRTL black box interface for\n");
+ log("a synchronous debug sink:\n");
+ log("\n");
+ log(" (* cxxrtl.blackbox *)\n");
+ log(" module debug(...);\n");
+ log(" (* cxxrtl.edge = \"p\" *) input clk;\n");
+ log(" input en;\n");
+ log(" input [7:0] data;\n");
+ log(" endmodule\n");
+ log("\n");
+ log("For this HDL interface, this backend will generate the following C++ interface:\n");
+ log("\n");
+ log(" struct bb_p_debug : public module {\n");
+ log(" wire<1> p_clk;\n");
+ log(" bool posedge_p_clk = false;\n");
+ log(" wire<1> p_en;\n");
+ log(" wire<8> p_data;\n");
+ log("\n");
+ log(" void eval() override;\n");
+ log(" bool commit() override;\n");
+ log("\n");
+ log(" static std::unique_ptr<bb_p_debug>\n");
+ log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n");
+ log(" };\n");
+ log("\n");
+ log("The `create' function must be implemented by the driver. For example, it could\n");
+ log("always provide an implementation logging the values to standard error stream:\n");
+ log("\n");
+ log(" namespace cxxrtl_design {\n");
+ log("\n");
+ log(" struct stderr_debug : public bb_p_debug {\n");
+ log(" void eval() override {\n");
+ log(" if (posedge_p_clk && p_en.curr)\n");
+ log(" fprintf(stderr, \"debug: %%02x\\n\", p_data.curr.data[0]);\n");
+ log(" bb_p_debug::eval();\n");
log(" }\n");
+ log(" };\n");
+ log("\n");
+ log(" std::unique_ptr<bb_p_debug>\n");
+ log(" bb_p_debug::create(std::string name, cxxrtl::metadata_map parameters,\n");
+ log(" cxxrtl::metadata_map attributes) {\n");
+ log(" return std::make_unique<stderr_debug>();\n");
+ log(" }\n");
+ log("\n");
log(" }\n");
log("\n");
+ log("For complex applications of black boxes, it is possible to parameterize their\n");
+ log("port widths. For example, the following Verilog code defines a CXXRTL black box\n");
+ log("interface for a configurable width debug sink:\n");
+ log("\n");
+ log(" (* cxxrtl.blackbox, cxxrtl.template = \"WIDTH\" *)\n");
+ log(" module debug(...);\n");
+ log(" parameter WIDTH = 8;\n");
+ log(" (* cxxrtl.edge = \"p\" *) input clk;\n");
+ log(" input en;\n");
+ log(" (* cxxrtl.width = \"WIDTH\" *) input [WIDTH - 1:0] data;\n");
+ log(" endmodule\n");
+ log("\n");
+ log("For this parametric HDL interface, this backend will generate the following C++\n");
+ log("interface (only the differences are shown):\n");
+ log("\n");
+ log(" template<size_t WIDTH>\n");
+ log(" struct bb_p_debug : public module {\n");
+ log(" // ...\n");
+ log(" wire<WIDTH> p_data;\n");
+ log(" // ...\n");
+ log(" static std::unique_ptr<bb_p_debug<WIDTH>>\n");
+ log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n");
+ log(" };\n");
+ log("\n");
+ log("The `create' function must be implemented by the driver, specialized for every\n");
+ log("possible combination of template parameters. (Specialization is necessary to\n");
+ log("enable separate compilation of generated code and black box implementations.)\n");
+ log("\n");
+ log(" template<size_t SIZE>\n");
+ log(" struct stderr_debug : public bb_p_debug<SIZE> {\n");
+ log(" // ...\n");
+ log(" };\n");
+ log("\n");
+ log(" template<>\n");
+ log(" std::unique_ptr<bb_p_debug<8>>\n");
+ log(" bb_p_debug<8>::create(std::string name, cxxrtl::metadata_map parameters,\n");
+ log(" cxxrtl::metadata_map attributes) {\n");
+ log(" return std::make_unique<stderr_debug<8>>();\n");
+ log(" }\n");
+ log("\n");
+ log("The following attributes are recognized by this backend:\n");
+ log("\n");
+ log(" cxxrtl.blackbox\n");
+ log(" only valid on modules. if specified, the module contents are ignored,\n");
+ log(" and the generated code includes only the module interface and a factory\n");
+ log(" function, which will be called to instantiate the module.\n");
+ log("\n");
+ log(" cxxrtl.edge\n");
+ log(" only valid on inputs of black boxes. must be one of \"p\", \"n\", \"a\".\n");
+ log(" if specified on signal `clk`, the generated code includes boolean fields\n");
+ log(" `posedge_p_clk` (if \"p\"), `negedge_p_clk` (if \"n\"), or both (if \"a\"),\n");
+ log(" as well as edge detection logic, simplifying implementation of clocked\n");
+ log(" black boxes.\n");
+ log("\n");
+ log(" cxxrtl.template\n");
+ log(" only valid on black boxes. must contain a space separated sequence of\n");
+ log(" identifiers that have a corresponding black box parameters. for each\n");
+ log(" of them, the generated code includes a `size_t` template parameter.\n");
+ log("\n");
+ log(" cxxrtl.width\n");
+ log(" only valid on ports of black boxes. must be a constant expression, which\n");
+ log(" is directly inserted into generated code.\n");
+ log("\n");
log("The following options are supported by this backend:\n");
log("\n");
log(" -header\n");
diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h
index 593c31c28..41e6290d1 100644
--- a/backends/cxxrtl/cxxrtl.h
+++ b/backends/cxxrtl/cxxrtl.h
@@ -28,7 +28,9 @@
#include <type_traits>
#include <tuple>
#include <vector>
+#include <map>
#include <algorithm>
+#include <memory>
#include <sstream>
// The cxxrtl support library implements compile time specialized arbitrary width arithmetics, as well as provides
@@ -604,12 +606,15 @@ struct memory {
auto _ = {std::move(std::begin(init.data), std::end(init.data), data.begin() + init.offset)...};
}
- value<Width> &operator [](size_t index) {
+ // An operator for direct memory reads. May be used at any time during the simulation.
+ const value<Width> &operator [](size_t index) const {
assert(index < data.size());
return data[index];
}
- const value<Width> &operator [](size_t index) const {
+ // An operator for direct memory writes. May only be used before the simulation is started. If used
+ // after the simulation is started, the design may malfunction.
+ value<Width> &operator [](size_t index) {
assert(index < data.size());
return data[index];
}
@@ -654,6 +659,57 @@ struct memory {
}
};
+struct metadata {
+ const enum {
+ MISSING = 0,
+ UINT = 1,
+ SINT = 2,
+ STRING = 3,
+ DOUBLE = 4,
+ } value_type;
+
+ // In debug mode, using the wrong .as_*() function will assert.
+ // In release mode, using the wrong .as_*() function will safely return a default value.
+ union {
+ const unsigned uint_value = 0;
+ const signed sint_value;
+ };
+ const std::string string_value = "";
+ const double double_value = 0.0;
+
+ metadata() : value_type(MISSING) {}
+ metadata(unsigned value) : value_type(UINT), uint_value(value) {}
+ metadata(signed value) : value_type(SINT), sint_value(value) {}
+ metadata(const std::string &value) : value_type(STRING), string_value(value) {}
+ metadata(const char *value) : value_type(STRING), string_value(value) {}
+ metadata(double value) : value_type(DOUBLE), double_value(value) {}
+
+ metadata(const metadata &) = default;
+ metadata &operator=(const metadata &) = delete;
+
+ unsigned as_uint() const {
+ assert(value_type == UINT);
+ return uint_value;
+ }
+
+ signed as_sint() const {
+ assert(value_type == SINT);
+ return sint_value;
+ }
+
+ const std::string &as_string() const {
+ assert(value_type == STRING);
+ return string_value;
+ }
+
+ double as_double() const {
+ assert(value_type == DOUBLE);
+ return double_value;
+ }
+};
+
+typedef std::map<std::string, metadata> metadata_map;
+
struct module {
module() {}
virtual ~module() {}
diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 1f750b359..40d05a036 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -42,6 +42,13 @@ static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3;
static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
+std::string getFileinfo(const RTLIL::AttrObject *design_entity)
+{
+ std::string src(design_entity->get_src_attribute());
+ std::string fileinfo_str = src.empty() ? "" : "@[" + src + "]";
+ return fileinfo_str;
+}
+
// Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module)
{
@@ -192,9 +199,10 @@ struct FirrtlWorker
if (this->width == 0) {
log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
}
- }
+ }
+
// We need a default constructor for the dict insert.
- memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
+ memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
const char *atLine() {
if (srcLine == "") {
@@ -298,17 +306,8 @@ struct FirrtlWorker
// If this is a parameterized module, its parent module is encoded in the cell type
if (cell->type.begins_with("$paramod"))
{
- std::string::iterator it;
- for (it = cell_type.begin(); it < cell_type.end(); it++)
- {
- switch (*it) {
- case '\\': /* FALL_THROUGH */
- case '=': /* FALL_THROUGH */
- case '\'': /* FALL_THROUGH */
- case '$': instanceOf.append("_"); break;
- default: instanceOf.append(1, *it); break;
- }
- }
+ log_assert(cell->has_attribute(ID::hdlname));
+ instanceOf = cell->get_string_attribute(ID::hdlname);
}
else
{
@@ -329,7 +328,8 @@ struct FirrtlWorker
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
return;
}
- wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
+ std::string cellFileinfo = getFileinfo(cell);
+ wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str(), cellFileinfo.c_str()));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
@@ -370,7 +370,7 @@ struct FirrtlWorker
// as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig);
} else {
- wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
+ wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str()));
}
}
}
@@ -394,12 +394,15 @@ struct FirrtlWorker
void run()
{
- f << stringf(" module %s:\n", make_id(module->name));
+ std::string moduleFileinfo = getFileinfo(module);
+ f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
+ std::string wireFileinfo = getFileinfo(wire);
+
// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
if (wire->attributes.count(ID::init)) {
log_warning("Initial value (%s) for (%s.%s) not supported\n",
@@ -410,12 +413,12 @@ struct FirrtlWorker
{
if (wire->port_input && wire->port_output)
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
- port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output",
- wireName, wire->width));
+ port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
+ wireName, wire->width, wireFileinfo.c_str()));
}
else
{
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", wireName, wire->width, wireFileinfo.c_str()));
}
}
@@ -423,7 +426,7 @@ struct FirrtlWorker
{
static Const ndef(0, 0);
- // Is this cell is a module instance?
+ // Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
@@ -441,11 +444,12 @@ struct FirrtlWorker
string primop;
bool always_uint = false;
string y_id = make_id(cell->name);
+ std::string cellFileinfo = getFileinfo(cell);
if (cell->type.in(ID($not), ID($logic_not), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor)))
{
string a_expr = make_expr(cell->getPort(ID::A));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
@@ -464,16 +468,16 @@ struct FirrtlWorker
firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
firrtl_width = a_width;
} else if (cell->type == ID($logic_not)) {
- primop = "eq";
- a_expr = stringf("%s, UInt(0)", a_expr.c_str());
- }
+ primop = "eq";
+ a_expr = stringf("%s, UInt(0)", a_expr.c_str());
+ }
else if (cell->type == ID($reduce_and)) primop = "andr";
else if (cell->type == ID($reduce_or)) primop = "orr";
else if (cell->type == ID($reduce_xor)) primop = "xorr";
else if (cell->type == ID($reduce_xnor)) {
- primop = "not";
- a_expr = stringf("xorr(%s)", a_expr.c_str());
- }
+ primop = "not";
+ a_expr = stringf("xorr(%s)", a_expr.c_str());
+ }
else if (cell->type == ID($reduce_bool)) {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
@@ -485,18 +489,19 @@ struct FirrtlWorker
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
}
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx),
- ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
- ID($logic_and), ID($logic_or), ID($pow)))
+ ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
+ ID($logic_and), ID($logic_or), ID($pow)))
{
string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+ std::string cellFileinfo = getFileinfo(cell);
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
if (a_signed) {
a_expr = "asSInt(" + a_expr + ")";
@@ -579,7 +584,7 @@ struct FirrtlWorker
primop = "eq";
always_uint = true;
firrtl_width = 1;
- }
+ }
else if ((cell->type == ID($ne)) | (cell->type == ID($nex))) {
primop = "neq";
always_uint = true;
@@ -712,7 +717,7 @@ struct FirrtlWorker
if ((firrtl_is_signed && !always_uint))
expr = stringf("asUInt(%s)", expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@@ -724,11 +729,11 @@ struct FirrtlWorker
string a_expr = make_expr(cell->getPort(ID::A));
string b_expr = make_expr(cell->getPort(ID::B));
string s_expr = make_expr(cell->getPort(ID::S));
- wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width));
+ wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), width, cellFileinfo.c_str()));
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
continue;
@@ -867,9 +872,9 @@ struct FirrtlWorker
string expr = make_expr(cell->getPort(ID::D));
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
- wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str()));
+ wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s %s\n", y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str()));
- cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
+ cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
continue;
@@ -959,6 +964,7 @@ struct FirrtlWorker
for (auto wire : module->wires())
{
string expr;
+ std::string wireFileinfo = getFileinfo(wire);
if (wire->port_input)
continue;
@@ -1017,14 +1023,20 @@ struct FirrtlWorker
if (is_valid) {
if (make_unconn_id) {
- wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str()));
+ wire_decls.push_back(stringf(" wire %s: UInt<1> %s\n", unconn_id.c_str(), wireFileinfo.c_str()));
+ // `invalid` is a firrtl construction for simulation so we will not
+ // tag it with a @[fileinfo] tag as it doesn't directly correspond to
+ // a specific line of verilog code.
wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
}
- wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str()));
+ wire_exprs.push_back(stringf(" %s <= %s %s\n", make_id(wire->name), expr.c_str(), wireFileinfo.c_str()));
} else {
if (make_unconn_id) {
unconn_id.clear();
}
+ // `invalid` is a firrtl construction for simulation so we will not
+ // tag it with a @[fileinfo] tag as it doesn't directly correspond to
+ // a specific line of verilog code.
wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
}
}
@@ -1123,7 +1135,8 @@ struct FirrtlBackend : public Backend {
if (top == nullptr)
top = last;
- *f << stringf("circuit %s:\n", make_id(top->name));
+ std::string circuitFileinfo = getFileinfo(top);
+ *f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str());
for (auto module : design->modules())
{
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 4cf329f75..9ddd538b5 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1158,6 +1158,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
+ current_ast_mod = nullptr;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr;
@@ -1224,6 +1225,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
}
design->add(process_module(*it, defer));
+ current_ast_mod = nullptr;
}
else if ((*it)->type == AST_PACKAGE) {
// process enum/other declarations
@@ -1568,6 +1570,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
rewritten.reserve(GetSize(parameters));
AstNode *new_ast = ast->clone();
+ if (!new_ast->attributes.count(ID::hdlname))
+ new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name);
+
para_counter = 0;
for (auto child : new_ast->children) {
if (child->type != AST_PARAMETER)
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 2ebe2edbc..837c14ad7 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -64,6 +64,21 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg
continue;
}
+ bool got_len = false;
+ bool got_zlen = false;
+ int len_value = 0;
+
+ while ('0' <= cformat && cformat <= '9')
+ {
+ if (!got_len && cformat == '0')
+ got_zlen = true;
+
+ got_len = true;
+ len_value = 10*len_value + (cformat - '0');
+
+ cformat = sformat[++i];
+ }
+
// Simplify the argument
AstNode *node_arg = nullptr;
@@ -74,6 +89,9 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg
case 'S':
case 'd':
case 'D':
+ if (got_len)
+ goto unsupported_format;
+ /* fall through */
case 'x':
case 'X':
if (next_arg >= GetSize(children))
@@ -88,9 +106,12 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg
case 'm':
case 'M':
+ if (got_len)
+ goto unsupported_format;
break;
default:
+ unsupported_format:
log_file_error(filename, location.first_line, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
break;
}
@@ -104,19 +125,28 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg
case 'd':
case 'D':
- {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int());
- sout += tmp;
- }
+ sout += stringf("%d", node_arg->bitsAsConst().as_int());
break;
case 'x':
case 'X':
{
- char tmp[128];
- snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int());
- sout += tmp;
+ Const val = node_arg->bitsAsConst();
+
+ while (GetSize(val) % 4 != 0)
+ val.bits.push_back(State::S0);
+
+ int len = GetSize(val) / 4;
+ for (int i = len; i < len_value; i++)
+ sout += got_zlen ? '0' : ' ';
+
+ for (int i = len-1; i >= 0; i--) {
+ Const digit = val.extract(4*i, 4);
+ if (digit.is_fully_def())
+ sout += stringf(cformat == 'x' ? "%x" : "%X", digit.as_int());
+ else
+ sout += cformat == 'x' ? "x" : "X";
+ }
}
break;
@@ -1169,7 +1199,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// annotate identifiers using scope resolution and create auto-wires as needed
if (type == AST_IDENTIFIER) {
if (current_scope.count(str) == 0) {
- for (auto node : current_ast_mod->children) {
+ AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod;
+ for (auto node : current_scope_ast->children) {
//log("looking at mod scope child %s\n", type2str(node->type).c_str());
switch (node->type) {
case AST_PARAMETER:
@@ -1203,7 +1234,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
- if (flag_autowire || str == "\\$global_clock") {
+ if (current_ast_mod == nullptr) {
+ log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared outside of a module.\n", str.c_str());
+ } else if (flag_autowire || str == "\\$global_clock") {
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
diff --git a/frontends/rpc/rpc_frontend.cc b/frontends/rpc/rpc_frontend.cc
index a23f7548e..46ee6a733 100644
--- a/frontends/rpc/rpc_frontend.cc
+++ b/frontends/rpc/rpc_frontend.cc
@@ -217,6 +217,8 @@ struct RpcModule : RTLIL::Module {
module.second->name = mangled_name;
module.second->design = design;
module.second->attributes.erase(ID::top);
+ if (!module.second->has_attribute(ID::hdlname))
+ module.second->set_string_attribute(ID::hdlname, module.first.str());
design->modules_[mangled_name] = module.second;
derived_design->modules_.erase(module.first);
}
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 76373c2e4..4a5aba79e 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -1924,11 +1924,13 @@ always_events:
always_event:
TOK_POSEDGE expr {
AstNode *node = new AstNode(AST_POSEDGE);
+ SET_AST_NODE_LOC(node, @1, @1);
ast_stack.back()->children.push_back(node);
node->children.push_back($2);
} |
TOK_NEGEDGE expr {
AstNode *node = new AstNode(AST_NEGEDGE);
+ SET_AST_NODE_LOC(node, @1, @1);
ast_stack.back()->children.push_back(node);
node->children.push_back($2);
} |
@@ -2244,6 +2246,7 @@ behavioral_stmt:
exitTypeScope();
if ($4 != NULL && $8 != NULL && *$4 != *$8)
frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1);
+ SET_AST_NODE_LOC(ast_stack.back(), @2, @8);
delete $4;
delete $8;
ast_stack.pop_back();
@@ -2618,6 +2621,7 @@ basic_expr:
bits->str = *$1;
SET_AST_NODE_LOC(bits, @1, @1);
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+ SET_AST_NODE_LOC(val, @2, @2);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -2626,6 +2630,7 @@ basic_expr:
} |
integral_number {
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
+ SET_AST_NODE_LOC($$, @1, @1);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
@@ -2644,6 +2649,7 @@ basic_expr:
} |
TOK_STRING {
$$ = AstNode::mkconst_str(*$1);
+ SET_AST_NODE_LOC($$, @1, @1);
delete $1;
} |
hierarchical_id attr {
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index e7cb312ed..996bda38e 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -314,11 +314,11 @@ class dict
int do_insert(const K &key, int &hash)
{
if (hashtable.empty()) {
- entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
+ entries.emplace_back(std::pair<K, T>(key, T()), -1);
do_rehash();
hash = do_hash(key);
} else {
- entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
+ entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]);
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
@@ -327,11 +327,25 @@ class dict
int do_insert(const std::pair<K, T> &value, int &hash)
{
if (hashtable.empty()) {
- entries.push_back(entry_t(value, -1));
+ entries.emplace_back(value, -1);
do_rehash();
hash = do_hash(value.first);
} else {
- entries.push_back(entry_t(value, hashtable[hash]));
+ entries.emplace_back(value, hashtable[hash]);
+ hashtable[hash] = entries.size() - 1;
+ }
+ return entries.size() - 1;
+ }
+
+ int do_insert(std::pair<K, T> &&rvalue, int &hash)
+ {
+ if (hashtable.empty()) {
+ auto key = rvalue.first;
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1);
+ do_rehash();
+ hash = do_hash(key);
+ } else {
+ entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]);
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
@@ -441,6 +455,56 @@ public:
return std::pair<iterator, bool>(iterator(this, i), true);
}
+ std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue)
+ {
+ int hash = do_hash(rvalue.first);
+ int i = do_lookup(rvalue.first, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T const &value)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K const &key, T &&rvalue)
+ {
+ int hash = do_hash(key);
+ int i = do_lookup(key, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T const &value)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
+ std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue)
+ {
+ int hash = do_hash(rkey);
+ int i = do_lookup(rkey, hash);
+ if (i >= 0)
+ return std::pair<iterator, bool>(iterator(this, i), false);
+ i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash);
+ return std::pair<iterator, bool>(iterator(this, i), true);
+ }
+
int erase(const K &key)
{
int hash = do_hash(key);
diff --git a/kernel/register.cc b/kernel/register.cc
index af8c1b8e8..925d0d776 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -485,20 +485,21 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
filename = arg;
+ //Accommodate heredocs with EOT marker spaced out from "<<", e.g. "<< EOT" vs. "<<EOT"
if (filename == "<<" && argidx+1 < args.size())
filename += args[++argidx];
if (filename.compare(0, 2, "<<") == 0) {
- if (Frontend::current_script_file == NULL)
- log_error("Unexpected here document '%s' outside of script!\n", filename.c_str());
if (filename.size() <= 2)
log_error("Missing EOT marker in here document!\n");
std::string eot_marker = filename.substr(2);
+ if (Frontend::current_script_file == nullptr)
+ filename = "<stdin>";
last_here_document.clear();
while (1) {
std::string buffer;
char block[4096];
while (1) {
- if (fgets(block, 4096, Frontend::current_script_file) == NULL)
+ if (fgets(block, 4096, Frontend::current_script_file == nullptr? stdin : Frontend::current_script_file) == nullptr)
log_error("Unexpected end of file in here document '%s'!\n", filename.c_str());
buffer += block;
if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index dc368ead5..8af941c85 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -273,6 +273,11 @@ bool RTLIL::Const::is_fully_undef() const
return true;
}
+bool RTLIL::AttrObject::has_attribute(RTLIL::IdString id) const
+{
+ return attributes.count(id);
+}
+
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{
if (value)
@@ -289,6 +294,23 @@ bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
return it->second.as_bool();
}
+void RTLIL::AttrObject::set_string_attribute(RTLIL::IdString id, string value)
+{
+ if (value.empty())
+ attributes.erase(id);
+ else
+ attributes[id] = value;
+}
+
+string RTLIL::AttrObject::get_string_attribute(RTLIL::IdString id) const
+{
+ std::string value;
+ const auto it = attributes.find(id);
+ if (it != attributes.end())
+ value = it->second.decode_string();
+ return value;
+}
+
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
{
string attrval;
@@ -317,23 +339,6 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const
return data;
}
-void RTLIL::AttrObject::set_src_attribute(const std::string &src)
-{
- if (src.empty())
- attributes.erase(ID::src);
- else
- attributes[ID::src] = src;
-}
-
-std::string RTLIL::AttrObject::get_src_attribute() const
-{
- std::string src;
- const auto it = attributes.find(ID::src);
- if (it != attributes.end())
- src = it->second.decode_string();
- return src;
-}
-
bool RTLIL::Selection::selected_module(RTLIL::IdString mod_name) const
{
if (full_selection)
@@ -597,6 +602,7 @@ void RTLIL::Design::remove(RTLIL::Module *module)
}
log_assert(modules_.at(module->name) == module);
+ log_assert(refcount_modules_ == 0);
modules_.erase(module->name);
delete module;
}
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 17f038e36..f3b1c9ae7 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -656,6 +656,8 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
+ bool has_attribute(RTLIL::IdString id) const;
+
void set_bool_attribute(RTLIL::IdString id, bool value=true);
bool get_bool_attribute(RTLIL::IdString id) const;
@@ -663,12 +665,19 @@ struct RTLIL::AttrObject
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
}
+ void set_string_attribute(RTLIL::IdString id, string value);
+ string get_string_attribute(RTLIL::IdString id) const;
+
void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
pool<string> get_strpool_attribute(RTLIL::IdString id) const;
- void set_src_attribute(const std::string &src);
- std::string get_src_attribute() const;
+ void set_src_attribute(const std::string &src) {
+ set_string_attribute(ID::src, src);
+ }
+ std::string get_src_attribute() const {
+ return get_string_attribute(ID::src);
+ }
};
struct RTLIL::SigChunk
diff --git a/libs/sha1/sha1.h b/libs/sha1/sha1.h
index 9f526376e..b1346b548 100644
--- a/libs/sha1/sha1.h
+++ b/libs/sha1/sha1.h
@@ -35,9 +35,9 @@ public:
static std::string from_file(const std::string &filename);
private:
- static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
- static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
- static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
+ static constexpr unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
+ static constexpr unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
+ static constexpr unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
uint32_t digest[DIGEST_INTS];
std::string buffer;
diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc
index e8361a67e..4068dc09a 100644
--- a/libs/subcircuit/subcircuit.cc
+++ b/libs/subcircuit/subcircuit.cc
@@ -316,7 +316,7 @@ class SubCircuit::SolverWorker
// helper functions for handling permutations
- static const int maxPermutationsLimit = 1000000;
+ static constexpr int maxPermutationsLimit = 1000000;
static int numberOfPermutations(const std::vector<std::string> &list)
{
@@ -1689,4 +1689,3 @@ void SubCircuit::Solver::clearConfig()
{
worker->clearConfig();
}
-
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 4612760cc..cfe97067d 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -99,6 +99,11 @@ struct DesignPass : public Pass {
log("The Verilog front-end remembers defined macros and top-level declarations\n");
log("between calls to 'read_verilog'. This command resets this memory.\n");
log("\n");
+ log(" design -delete <name>\n");
+ log("\n");
+ log("Delete the design previously saved under the given name.\n");
+ log("\n");
+
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@@ -110,7 +115,7 @@ struct DesignPass : public Pass {
bool pop_mode = false;
bool import_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
- std::string save_name, load_name, as_name;
+ std::string save_name, load_name, as_name, delete_name;
std::vector<RTLIL::Module*> copy_src_modules;
size_t argidx;
@@ -190,6 +195,13 @@ struct DesignPass : public Pass {
as_name = args[++argidx];
continue;
}
+ if (!got_mode && args[argidx] == "-delete" && argidx+1 < args.size()) {
+ got_mode = true;
+ delete_name = args[++argidx];
+ if (saved_designs.count(delete_name) == 0)
+ log_cmd_error("No saved design '%s' found!\n", delete_name.c_str());
+ continue;
+ }
break;
}
@@ -340,7 +352,7 @@ struct DesignPass : public Pass {
if (reset_mode || !load_name.empty() || push_mode || pop_mode)
{
- for (auto mod : design->modules())
+ for (auto mod : design->modules().to_vector())
design->remove(mod);
design->selection_stack.clear();
@@ -379,6 +391,14 @@ struct DesignPass : public Pass {
pushed_designs.pop_back();
}
}
+
+ if (!delete_name.empty())
+ {
+ auto it = saved_designs.find(delete_name);
+ log_assert(it != saved_designs.end());
+ delete it->second;
+ saved_designs.erase(it);
+ }
}
} DesignPass;
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 9b1830b7b..7d6d84d42 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -32,27 +32,27 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
if (module->count_id(to_name))
log_cmd_error("There is already an object `%s' in module `%s'.\n", to_name.c_str(), module->name.c_str());
- for (auto &it : module->wires_)
- if (it.first == from_name) {
- Wire *w = it.second;
- log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
- module->rename(w, to_name);
- if (w->port_id || flag_output) {
- if (flag_output)
- w->port_output = true;
- module->fixup_ports();
- }
- return;
- }
+ RTLIL::Wire *wire_to_rename = module->wire(from_name);
+ RTLIL::Cell *cell_to_rename = module->cell(from_name);
- for (auto &it : module->cells_)
- if (it.first == from_name) {
+ if (wire_to_rename != nullptr) {
+ log("Renaming wire %s to %s in module %s.\n", log_id(wire_to_rename), log_id(to_name), log_id(module));
+ module->rename(wire_to_rename, to_name);
+ if (wire_to_rename->port_id || flag_output) {
if (flag_output)
- log_cmd_error("Called with -output but the specified object is a cell.\n");
- log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
- module->rename(it.second, to_name);
- return;
+ wire_to_rename->port_output = true;
+ module->fixup_ports();
}
+ return;
+ }
+
+ if (cell_to_rename != nullptr) {
+ if (flag_output)
+ log_cmd_error("Called with -output but the specified object is a cell.\n");
+ log("Renaming cell %s to %s in module %s.\n", log_id(cell_to_rename), log_id(to_name), log_id(module));
+ module->rename(cell_to_rename, to_name);
+ return;
+ }
log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
@@ -66,26 +66,26 @@ static std::string derive_name_from_src(const std::string &src, int counter)
return stringf("\\%s$%d", src_base.c_str(), counter);
}
-static IdString derive_name_from_wire(const RTLIL::Cell &cell)
+static IdString derive_name_from_cell_output_wire(const RTLIL::Cell *cell)
{
// Find output
const SigSpec *output = nullptr;
int num_outputs = 0;
- for (auto &connection : cell.connections()) {
- if (cell.output(connection.first)) {
+ for (auto &connection : cell->connections()) {
+ if (cell->output(connection.first)) {
output = &connection.second;
num_outputs++;
}
}
if (num_outputs != 1) // Skip cells thad drive multiple outputs
- return cell.name;
+ return cell->name;
std::string name = "";
for (auto &chunk : output->chunks()) {
// Skip cells that drive privately named wires
if (!chunk.wire || chunk.wire->name.str()[0] == '$')
- return cell.name;
+ return cell->name;
if (name != "")
name += "$";
@@ -99,7 +99,7 @@ static IdString derive_name_from_wire(const RTLIL::Cell &cell)
}
}
- return name + cell.type.str();
+ return name + cell->type.str();
}
struct RenamePass : public Pass {
@@ -210,30 +210,25 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
int counter = 0;
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '$')
+ new_wire_names.emplace(wire, derive_name_from_src(wire->get_src_attribute(), counter++));
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$')
+ new_cell_names.emplace(cell, derive_name_from_src(cell->get_src_attribute(), counter++));
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -241,19 +236,13 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
- {
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- it.second->name = derive_name_from_wire(*it.second);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto module : design->selected_modules()) {
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$')
+ new_cell_names[cell] = derive_name_from_cell_output_wire(cell);
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -261,32 +250,33 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
int counter = 0;
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '$') {
+ RTLIL::IdString buf;
+ do buf = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
+ while (module->wire(buf) != nullptr);
+ new_wire_names[wire] = buf;
+ }
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '$') {
+ RTLIL::IdString buf;
+ do buf = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
+ while (module->cell(buf) != nullptr);
+ new_cell_names[cell] = buf;
+ }
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
- while (module->count_id(it.second->name) > 0);
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
- while (module->count_id(it.second->name) > 0);
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -294,30 +284,24 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = mod.second;
- if (!design->selected(module))
- continue;
-
- dict<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires_) {
- if (design->selected(module, it.second))
- if (it.first[0] == '\\' && it.second->port_id == 0)
- it.second->name = NEW_ID;
- new_wires[it.second->name] = it.second;
- }
- module->wires_.swap(new_wires);
- module->fixup_ports();
-
- dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells_) {
- if (design->selected(module, it.second))
- if (it.first[0] == '\\')
- it.second->name = NEW_ID;
- new_cells[it.second->name] = it.second;
- }
- module->cells_.swap(new_cells);
+ dict<RTLIL::Wire *, IdString> new_wire_names;
+ dict<RTLIL::Cell *, IdString> new_cell_names;
+
+ for (auto wire : module->selected_wires())
+ if (wire->name[0] == '\\' && wire->port_id == 0)
+ new_wire_names[wire] = NEW_ID;
+
+ for (auto cell : module->selected_cells())
+ if (cell->name[0] == '\\')
+ new_cell_names[cell] = NEW_ID;
+
+ for (auto &it : new_wire_names)
+ module->rename(it.first, it.second);
+
+ for (auto &it : new_cell_names)
+ module->rename(it.first, it.second);
}
}
else
@@ -329,7 +313,7 @@ struct RenamePass : public Pass {
IdString new_name = RTLIL::escape_id(args[argidx]);
RTLIL::Module *module = design->top_module();
- if (module == NULL)
+ if (module == nullptr)
log_cmd_error("No top module found!\n");
log("Renaming module %s to %s.\n", log_id(module), log_id(new_name));
@@ -345,27 +329,27 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
- if (design->modules_.count(design->selected_active_module) > 0)
- rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
+ if (design->module(design->selected_active_module) != nullptr)
+ rename_in_module(design->module(design->selected_active_module), from_name, to_name, flag_output);
}
else
{
if (flag_output)
log_cmd_error("Mode -output requires that there is an active module selected.\n");
- for (auto &mod : design->modules_) {
- if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
- to_name = RTLIL::escape_id(to_name);
- log("Renaming module %s to %s.\n", mod.first.c_str(), to_name.c_str());
- RTLIL::Module *module = mod.second;
- design->modules_.erase(module->name);
- module->name = to_name;
- design->modules_[module->name] = module;
- goto rename_ok;
+
+ RTLIL::Module *module_to_rename = nullptr;
+ for (auto module : design->modules())
+ if (module->name == from_name || RTLIL::unescape_id(module->name) == from_name) {
+ module_to_rename = module;
+ break;
}
- }
- log_cmd_error("Object `%s' not found!\n", from_name.c_str());
- rename_ok:;
+ if (module_to_rename != nullptr) {
+ to_name = RTLIL::escape_id(to_name);
+ log("Renaming module %s to %s.\n", module_to_rename->name.c_str(), to_name.c_str());
+ design->rename(module_to_rename, to_name);
+ } else
+ log_cmd_error("Object `%s' not found!\n", from_name.c_str());
}
}
}
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index 7123ba9fb..a5ef95f02 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -46,25 +46,19 @@ struct ScatterPass : public Pass {
CellTypes ct(design);
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- if (!design->selected(mod_it.second))
- continue;
-
- for (auto &c : mod_it.second->cells_)
- for (auto &p : c.second->connections_)
- {
- RTLIL::Wire *wire = mod_it.second->addWire(NEW_ID, p.second.size());
-
- if (ct.cell_output(c.second->type, p.first)) {
- RTLIL::SigSig sigsig(p.second, wire);
- mod_it.second->connect(sigsig);
- } else {
- RTLIL::SigSig sigsig(wire, p.second);
- mod_it.second->connect(sigsig);
+ for (auto cell : module->cells()) {
+ dict<RTLIL::IdString, RTLIL::SigSig> new_connections;
+ for (auto conn : cell->connections())
+ new_connections.emplace(conn.first, RTLIL::SigSig(conn.second, module->addWire(NEW_ID, GetSize(conn.second))));
+ for (auto &it : new_connections) {
+ if (ct.cell_output(cell->type, it.first))
+ module->connect(RTLIL::SigSig(it.second.first, it.second.second));
+ else
+ module->connect(RTLIL::SigSig(it.second.second, it.second.first));
+ cell->setPort(it.first, it.second.second);
}
-
- p.second = wire;
}
}
}
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index b64b077e4..c04ff438a 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -1007,6 +1007,7 @@ struct SelectPass : public Pass {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
+ log(" select [ -unset <name> ]\n");
log(" select [ <assert_option> ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
@@ -1029,6 +1030,10 @@ struct SelectPass : public Pass {
log(" under the given name (see @<name> below). to save the current selection,\n");
log(" use \"select -set <name> %%\"\n");
log("\n");
+ log(" -unset <name>\n");
+ log(" do not modify the current selection. instead remove a previously saved\n");
+ log(" selection under the given name (see @<name> below).");
+ log("\n");
log(" -assert-none\n");
log(" do not modify the current selection. instead assert that the given\n");
log(" selection is empty. i.e. produce an error if any object matching the\n");
@@ -1238,7 +1243,7 @@ struct SelectPass : public Pass {
int assert_max = -1;
int assert_min = -1;
std::string write_file, read_file;
- std::string set_name, sel_str;
+ std::string set_name, unset_name, sel_str;
work_stack.clear();
@@ -1310,6 +1315,10 @@ struct SelectPass : public Pass {
set_name = RTLIL::escape_id(args[++argidx]);
continue;
}
+ if (arg == "-unset" && argidx+1 < args.size()) {
+ unset_name = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
if (arg.size() > 0 && arg[0] == '-')
log_cmd_error("Unknown option %s.\n", arg.c_str());
bool disable_empty_warning = count_mode || assert_none || assert_any || (assert_count != -1) || (assert_max != -1) || (assert_min != -1);
@@ -1358,8 +1367,11 @@ struct SelectPass : public Pass {
if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any, assert-count, -assert-max, or -assert-min.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || !unset_name.empty() || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -unset, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
+
+ if (!unset_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || !set_name.empty() || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -unset can not be combined with -list, -write, -count, -add, -del, -set, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1527,6 +1539,13 @@ struct SelectPass : public Pass {
return;
}
+ if (!unset_name.empty())
+ {
+ if (!design->selection_vars.erase(unset_name))
+ log_error("Selection '%s' does not exist!\n", unset_name.c_str());
+ return;
+ }
+
if (work_stack.size() == 0) {
RTLIL::Selection &sel = design->selection_stack.back();
if (sel.full_selection)
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 3229dd1b2..2b35ace5e 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -1135,9 +1135,24 @@ skip_fine_alu:
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (cell->type == ID($alu)) {
+ bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
+ bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
+ bool is_signed = a_signed && b_signed;
+ RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID::CI));
int y_width = GetSize(cell->getPort(ID::Y));
- module->connect(cell->getPort(ID::X), RTLIL::Const(State::S0, y_width));
- module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S0, y_width));
+ if (sig_ci == State::S1) {
+ /* sub, b is 0 */
+ RTLIL::SigSpec a = cell->getPort(ID::A);
+ a.extend_u0(y_width, is_signed);
+ module->connect(cell->getPort(ID::X), module->Not(NEW_ID, a));
+ module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S1, y_width));
+ } else {
+ /* add */
+ RTLIL::SigSpec ab = cell->getPort(identity_wrt_a ? ID::A : ID::B);
+ ab.extend_u0(y_width, is_signed);
+ module->connect(cell->getPort(ID::X), ab);
+ module->connect(cell->getPort(ID::CO), RTLIL::Const(State::S0, y_width));
+ }
cell->unsetPort(ID::BI);
cell->unsetPort(ID::CI);
cell->unsetPort(ID::X);
diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc
index 44691425f..981271770 100644
--- a/passes/sat/qbfsat.cc
+++ b/passes/sat/qbfsat.cc
@@ -39,7 +39,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct QbfSolutionType {
- std::vector<std::string> stdout;
+ std::vector<std::string> stdout_lines;
dict<std::string, std::string> hole_to_value;
bool sat;
bool unknown; //true if neither 'sat' nor 'unsat'
@@ -72,7 +72,7 @@ void recover_solution(QbfSolutionType &sol) {
bool sat_regex_found = false;
bool unsat_regex_found = false;
dict<std::string, bool> hole_value_recovered;
- for (const std::string &x : sol.stdout) {
+ for (const std::string &x : sol.stdout_lines) {
if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) {
std::string loc = m[1].str();
std::string val = m[2].str();
@@ -294,7 +294,7 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) {
{
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.push_back(line.substr(0, line.size()-1)); //don't include trailing newline
+ 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());
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 0ee495abd..aff0baa44 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -160,7 +160,7 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1,
void mark_port(RTLIL::SigSpec sig)
{
for (auto &bit : assign_map(sig))
- if (bit.wire != NULL && signal_map.count(bit) > 0)
+ if (bit.wire != nullptr && signal_map.count(bit) > 0)
signal_list[signal_map[bit]].is_port = true;
}
@@ -197,7 +197,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
if (keepff)
for (auto &c : sig_q.chunks())
- if (c.wire != NULL)
+ if (c.wire != nullptr)
c.wire->attributes[ID::keep] = 1;
assign_map.apply(sig_d);
@@ -370,7 +370,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
{
- if (f == NULL)
+ if (f == nullptr)
return;
log("Dumping loop state graph to slide %d.\n", ++nr);
@@ -406,7 +406,7 @@ void handle_loops()
std::vector<int> in_edges_count(signal_list.size());
std::set<int> workpool;
- FILE *dot_f = NULL;
+ FILE *dot_f = nullptr;
int dot_nr = 0;
// uncomment for troubleshooting the loop detection code
@@ -464,9 +464,9 @@ void handle_loops()
int id2 = edge_it.first;
RTLIL::Wire *w1 = signal_list[id1].bit.wire;
RTLIL::Wire *w2 = signal_list[id2].bit.wire;
- if (w1 == NULL)
+ if (w1 == nullptr)
id1 = id2;
- else if (w2 == NULL)
+ else if (w2 == nullptr)
continue;
else if (w1->name[0] == '$' && w2->name[0] == '\\')
id1 = id2;
@@ -485,7 +485,7 @@ void handle_loops()
continue;
}
- log_assert(signal_list[id1].bit.wire != NULL);
+ log_assert(signal_list[id1].bit.wire != nullptr);
std::stringstream sstr;
sstr << "$abcloop$" << (autoidx++);
@@ -526,7 +526,7 @@ void handle_loops()
}
}
- if (dot_f != NULL)
+ if (dot_f != nullptr)
fclose(dot_f);
}
@@ -688,15 +688,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
en_polarity = false;
en_str = en_str.substr(1);
}
- if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
- en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+ if (module->wire(RTLIL::escape_id(en_str)) != nullptr)
+ en_sig = assign_map(module->wire(RTLIL::escape_id(en_str)));
}
if (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
}
- if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
+ if (module->wire(RTLIL::escape_id(clk_str)) != nullptr)
+ clk_sig = assign_map(module->wire(RTLIL::escape_id(clk_str)));
}
if (dff_mode && clk_sig.empty())
@@ -790,13 +790,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto c : cells)
extract_cell(c, keepff);
- for (auto &wire_it : module->wires_) {
- if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute(ID::keep))
- mark_port(RTLIL::SigSpec(wire_it.second));
+ for (auto wire : module->wires()) {
+ if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep))
+ mark_port(wire);
}
- for (auto &cell_it : module->cells_)
- for (auto &port_it : cell_it.second->connections())
+ for (auto cell : module->cells())
+ for (auto &port_it : cell->connections())
mark_port(port_it.second);
if (clk_sig.size() != 0)
@@ -809,7 +809,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
std::string buffer = stringf("%s/input.blif", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
- if (f == NULL)
+ if (f == nullptr)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, ".model netlist\n");
@@ -840,7 +840,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit));
for (auto &si : signal_list) {
- if (si.bit.wire == NULL) {
+ if (si.bit.wire == nullptr) {
fprintf(f, ".names ys__n%d\n", si.id);
if (si.bit == RTLIL::State::S1)
fprintf(f, "1\n");
@@ -936,7 +936,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
- if (f == NULL)
+ if (f == nullptr)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
fprintf(f, "GATE ONE 1 Y=CONST1;\n");
@@ -981,7 +981,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!lut_costs.empty()) {
buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
- if (f == NULL)
+ if (f == nullptr)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
for (int i = 0; i < GetSize(lut_costs); i++)
fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i));
@@ -1025,11 +1025,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
ifs.close();
log_header(design, "Re-integrating ABC results.\n");
- RTLIL::Module *mapped_mod = mapped_design->modules_[ID(netlist)];
- if (mapped_mod == NULL)
+ RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist));
+ if (mapped_mod == nullptr)
log_error("ABC output file does not contain a module `netlist'.\n");
- for (auto &it : mapped_mod->wires_) {
- RTLIL::Wire *w = it.second;
+ for (auto w : mapped_mod->wires()) {
RTLIL::Wire *orig_wire = nullptr;
RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire));
if (orig_wire != nullptr && orig_wire->attributes.count(ID::src))
@@ -1046,121 +1045,99 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type.in(ID(ZERO), ID(ONE))) {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
+ RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name);
+ conn.first = module->wire(name_y);
conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1);
module->connect(conn);
continue;
}
if (c->type == ID(BUF)) {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]);
- conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]);
+ RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name);
+ RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name);
+ conn.first = module->wire(name_y);
+ conn.second = module->wire(name_a);
module->connect(conn);
continue;
}
if (c->type == ID(NOT)) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type.in(ID(MUX), ID(NMUX))) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::S, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::S).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::S, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type == ID(MUX4)) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::C, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::C).as_wire()->name)]));
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::S, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::S).as_wire()->name)]));
- cell->setPort(ID::T, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::T).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type == ID(MUX8)) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::C, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::C).as_wire()->name)]));
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::E, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::E).as_wire()->name)]));
- cell->setPort(ID::F, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::F).as_wire()->name)]));
- cell->setPort(ID::G, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::G).as_wire()->name)]));
- cell->setPort(ID::H, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::H).as_wire()->name)]));
- cell->setPort(ID::S, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::S).as_wire()->name)]));
- cell->setPort(ID::T, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::T).as_wire()->name)]));
- cell->setPort(ID::U, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::U).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type == ID(MUX16)) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::C, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::C).as_wire()->name)]));
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::E, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::E).as_wire()->name)]));
- cell->setPort(ID::F, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::F).as_wire()->name)]));
- cell->setPort(ID::G, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::G).as_wire()->name)]));
- cell->setPort(ID::H, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::H).as_wire()->name)]));
- cell->setPort(ID::I, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::I).as_wire()->name)]));
- cell->setPort(ID::J, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::J).as_wire()->name)]));
- cell->setPort(ID::K, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::K).as_wire()->name)]));
- cell->setPort(ID::L, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::L).as_wire()->name)]));
- cell->setPort(ID::M, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::M).as_wire()->name)]));
- cell->setPort(ID::N, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::N).as_wire()->name)]));
- cell->setPort(ID::O, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::O).as_wire()->name)]));
- cell->setPort(ID::P, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::P).as_wire()->name)]));
- cell->setPort(ID::S, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::S).as_wire()->name)]));
- cell->setPort(ID::T, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::T).as_wire()->name)]));
- cell->setPort(ID::U, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::U).as_wire()->name)]));
- cell->setPort(ID::V, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::V).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K,
+ ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type.in(ID(AOI3), ID(OAI3))) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::C, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::C).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::C, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
if (c->type.in(ID(AOI4), ID(OAI4))) {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1));
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]));
- cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)]));
- cell->setPort(ID::C, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::C).as_wire()->name)]));
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]));
+ for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
design->select(module, cell);
continue;
}
@@ -1175,8 +1152,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
cell->setPort(ID::E, en_sig);
}
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::Q, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Q).as_wire()->name)]));
+ for (auto name : {ID::D, ID::Q}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
cell->setPort(ID::C, clk_sig);
design->select(module, cell);
continue;
@@ -1187,7 +1166,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (c->type.in(ID(_const0_), ID(_const1_))) {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
+ conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name));
conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1);
module->connect(conn);
continue;
@@ -1204,16 +1183,18 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
cell->setPort(ID::E, en_sig);
}
if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx;
- cell->setPort(ID::D, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::D).as_wire()->name)]));
- cell->setPort(ID::Q, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Q).as_wire()->name)]));
+ for (auto name : {ID::D, ID::Q}) {
+ RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name);
+ cell->setPort(name, module->wire(remapped_name));
+ }
cell->setPort(ID::C, clk_sig);
design->select(module, cell);
continue;
}
if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) {
- SigSpec my_a = module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)];
- SigSpec my_y = module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)];
+ SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name));
+ SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name));
module->connect(my_y, my_a);
continue;
}
@@ -1227,7 +1208,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (c.width == 0)
continue;
log_assert(c.width == 1);
- newsig.append(module->wires_[remap_name(c.wire->name)]);
+ newsig.append(module->wire(remap_name(c.wire->name)));
}
cell->setPort(conn.first, newsig);
}
@@ -1236,16 +1217,16 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
for (auto conn : mapped_mod->connections()) {
if (!conn.first.is_fully_const())
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(conn.first.as_wire()->name)]);
+ conn.first = module->wire(remap_name(conn.first.as_wire()->name));
if (!conn.second.is_fully_const())
- conn.second = RTLIL::SigSpec(module->wires_[remap_name(conn.second.as_wire()->name)]);
+ conn.second = module->wire(remap_name(conn.second.as_wire()->name));
module->connect(conn);
}
if (recover_init)
for (auto wire : mapped_mod->wires()) {
if (wire->attributes.count(ID::init)) {
- Wire *w = module->wires_[remap_name(wire->name)];
+ Wire *w = module->wire(remap_name(wire->name));
log_assert(w->attributes.count(ID::init) == 0);
w->attributes[ID::init] = wire->attributes.at(ID::init);
}
@@ -1261,10 +1242,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
RTLIL::SigSig conn;
if (si.type != G(NONE)) {
conn.first = si.bit;
- conn.second = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
+ conn.second = module->wire(remap_name(buffer));
out_wires++;
} else {
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
+ conn.first = module->wire(remap_name(buffer));
conn.second = si.bit;
in_wires++;
}
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 8ae1b51ff..78c902866 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -467,7 +467,12 @@ void prep_lut(RTLIL::Design *design, int maxlut)
{
TimingInfo timing;
- std::vector<std::tuple<int, IdString, int, std::vector<int>>> table;
+ struct t_lut {
+ IdString name;
+ int area;
+ std::vector<int> delays;
+ };
+ std::map<int,t_lut> table;
for (auto module : design->modules()) {
auto it = module->attributes.find(ID::abc9_lut);
if (it == module->attributes.end())
@@ -476,40 +481,52 @@ void prep_lut(RTLIL::Design *design, int maxlut)
auto &t = timing.setup_module(module);
TimingInfo::NameBit o;
- std::vector<int> specify;
+ std::vector<int> delays;
for (const auto &i : t.comb) {
auto &d = i.first.second;
if (o == TimingInfo::NameBit())
o = d;
else if (o != d)
- log_error("(* abc9_lut *) module '%s' with has more than one output.\n", log_id(module));
- specify.push_back(i.second);
+ log_error("Module '%s' with (* abc9_lut *) has more than one output.\n", log_id(module));
+ delays.push_back(i.second);
}
- if (maxlut && GetSize(specify) > maxlut)
+ if (GetSize(delays) == 0)
+ log_error("Module '%s' with (* abc9_lut *) has no specify entries.\n", log_id(module));
+ if (maxlut && GetSize(delays) > maxlut)
continue;
// ABC requires non-decreasing LUT input delays
- std::sort(specify.begin(), specify.end());
- table.emplace_back(GetSize(specify), module->name, it->second.as_int(), std::move(specify));
+ std::sort(delays.begin(), delays.end());
+
+ int K = GetSize(delays);
+ auto entry = t_lut{module->name, it->second.as_int(), std::move(delays)};
+ auto r = table.emplace(K, entry);
+ if (!r.second) {
+ if (r.first->second.area != entry.area)
+ log_error("Modules '%s' and '%s' have conflicting (* abc9_lut *) values.\n", log_id(module), log_id(r.first->second.name));
+ if (r.first->second.delays != entry.delays)
+ log_error("Modules '%s' and '%s' have conflicting specify entries.\n", log_id(module), log_id(r.first->second.name));
+ }
}
- // ABC requires ascending size
- std::sort(table.begin(), table.end());
+
+ if (table.empty())
+ log_error("Design does not contain any modules with (* abc9_lut *).\n");
std::stringstream ss;
- const auto &first = table.front();
+ const auto &front = *table.begin();
// If the first entry does not start from a 1-input LUT,
// (as ABC requires) crop the first entry to do so
- for (int i = 1; i < std::get<0>(first); i++) {
+ for (int i = 1; i < front.first; i++) {
ss << "# $__ABC9_LUT" << i << std::endl;
- ss << i << " " << std::get<2>(first);
+ ss << i << " " << front.second.area;
for (int j = 0; j < i; j++)
- ss << " " << std::get<3>(first)[j];
+ ss << " " << front.second.delays[j];
ss << std::endl;
}
for (const auto &i : table) {
- ss << "# " << log_id(std::get<1>(i)) << std::endl;
- ss << std::get<0>(i) << " " << std::get<2>(i);
- for (const auto &j : std::get<3>(i))
+ ss << "# " << log_id(i.second.name) << std::endl;
+ ss << i.first << " " << i.second.area;
+ for (const auto &j : i.second.delays)
ss << " " << j;
ss << std::endl;
}
diff --git a/techlibs/ecp5/dsp_map.v b/techlibs/ecp5/dsp_map.v
index cb95ddb1c..df54d1d9f 100644
--- a/techlibs/ecp5/dsp_map.v
+++ b/techlibs/ecp5/dsp_map.v
@@ -10,7 +10,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]),
.B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]),
.C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0),
- .SIGNEDA(A_SIGNED), .SIGNEDB(B_SIGNED), .SOURCEA(1'b0), .SOURCEB(1'b0),
+ .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0),
.P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35])
);
diff --git a/tests/arch/ecp5/memories.ys b/tests/arch/ecp5/memories.ys
index e1f748e26..f55bf01d2 100644
--- a/tests/arch/ecp5/memories.ys
+++ b/tests/arch/ecp5/memories.ys
@@ -208,7 +208,6 @@ select -assert-count 1 t:PDPW16KD
design -reset; read_verilog ../common/blockrom.v
chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
-write_ilang
synth_ecp5 -top sync_rom; cd sync_rom
select -assert-count 0 t:PDPW16KD # too inefficient
select -assert-min 18 t:LUT4
@@ -274,7 +273,6 @@ select -assert-count 1 t:DP16KD
design -reset; read_verilog ../common/blockrom.v
chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 18 sync_rom
-write_ilang
synth_ecp5 -top sync_rom; cd sync_rom
select -assert-count 0 t:DP16KD # too inefficient
select -assert-min 9 t:LUT4
diff --git a/tests/arch/ice40/memories.ys b/tests/arch/ice40/memories.ys
index 571edec1d..c32f12315 100644
--- a/tests/arch/ice40/memories.ys
+++ b/tests/arch/ice40/memories.ys
@@ -112,7 +112,6 @@ select -assert-count 1 t:SB_RAM40_4K
design -reset; read_verilog ../common/blockrom.v
chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
-write_ilang
synth_ice40 -top sync_rom; cd sync_rom
select -assert-count 0 t:SB_RAM40_4K # too inefficient
select -assert-min 1 t:SB_LUT4
diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys
index e288bcea6..9121c0096 100644
--- a/tests/opt/opt_expr_alu.ys
+++ b/tests/opt/opt_expr_alu.ys
@@ -8,7 +8,7 @@ alumacc
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -20,7 +20,7 @@ EOT
alumacc
select -assert-count 1 t:$alu
-select -assert-count none t:$alu t:* %D
+select -assert-none t:$alu t:* %D
design -reset
@@ -33,7 +33,7 @@ EOT
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -46,7 +46,7 @@ EOT
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-none t:$pos t:* %D
design -reset
@@ -60,7 +60,8 @@ alumacc
equiv_opt -assert opt_expr -fine
design -load postopt
select -assert-count 1 t:$pos
-select -assert-count none t:$pos t:* %D
+select -assert-count 1 t:$not
+select -assert-none t:$pos t:$not %% t:* %D
design -reset
@@ -76,7 +77,7 @@ design -load postopt
select -assert-count 1 t:$alu
select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
select -assert-count 1 t:$not
-select -assert-count none t:$alu t:$not t:* %D %D
+select -assert-none t:$alu t:$not t:* %D %D
design -reset
@@ -93,7 +94,7 @@ dump
select -assert-count 2 t:$alu
select -assert-count 1 t:$alu r:Y_WIDTH=2 %i
select -assert-count 1 t:$alu r:Y_WIDTH=3 %i
-select -assert-count none t:$alu t:* %D
+select -assert-none t:$alu t:* %D
design -reset
@@ -108,4 +109,61 @@ equiv_opt -assert opt -fine
design -load postopt
select -assert-count 2 t:$alu
select -assert-count 2 t:$alu r:Y_WIDTH=3 %i
-select -assert-count none t:$alu t:* %D
+select -assert-none t:$alu t:* %D
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(a), .B(4'h0),
+ .BI(1'b0), .CI(1'b0),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(a), .B(4'h0),
+ .BI(1'b1), .CI(1'b1),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
+
+
+design -reset
+read_verilog -icells <<EOT
+module test(input [3:0] a, output [3:0] y, output [3:0] x, output [3:0] co);
+$alu #(
+ .A_WIDTH(4), .B_WIDTH(4), .Y_WIDTH(4),
+ .A_SIGNED(0), .B_SIGNED(0),
+) alu (
+ .A(4'h0), .B(a),
+ .BI(1'b0), .CI(1'b0),
+ .Y(y), .X(x), .CO(co),
+);
+endmodule
+EOT
+
+equiv_opt -assert opt
+design -load postopt
+select -assert-none t:$alu
diff --git a/tests/select/unset.ys b/tests/select/unset.ys
new file mode 100644
index 000000000..4f60781c2
--- /dev/null
+++ b/tests/select/unset.ys
@@ -0,0 +1,10 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+select -set foo w:*
+select -assert-any @foo
+select -unset foo
+logger -expect error "Selection '\\foo' does not exist!" 1
+select -unset foo
diff --git a/tests/select/unset2.ys b/tests/select/unset2.ys
new file mode 100644
index 000000000..456b84c22
--- /dev/null
+++ b/tests/select/unset2.ys
@@ -0,0 +1,10 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+select -set foo w:*
+select -assert-any @foo
+select -unset foo
+logger -expect error "Selection @foo is not defined!" 1
+select -list @foo
diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys
index 0c7695089..6e2415ad7 100644
--- a/tests/various/abc9.ys
+++ b/tests/various/abc9.ys
@@ -53,3 +53,22 @@ assign q = w;
endmodule
EOT
abc9 -lut 4 -dff
+
+
+design -reset
+read_verilog -icells -specify <<EOT
+(* abc9_lut=1, blackbox *)
+module LUT2(input [1:0] i, output o);
+parameter [3:0] mask = 0;
+assign o = i[0] ? (i[1] ? mask[3] : mask[2])
+ : (i[1] ? mask[1] : mask[0]);
+specify
+ (i *> o) = 1;
+endspecify
+endmodule
+
+module top(input [1:0] i, output o);
+LUT2 #(.mask(4'b0)) lut (.i(i), .o(o));
+endmodule
+EOT
+abc9
diff --git a/tests/various/design.ys b/tests/various/design.ys
new file mode 100644
index 000000000..f13ad8171
--- /dev/null
+++ b/tests/various/design.ys
@@ -0,0 +1,9 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+design -stash foo
+design -delete foo
+logger -expect error "No saved design 'foo' found!" 1
+design -delete foo
diff --git a/tests/various/design2.ys b/tests/various/design2.ys
new file mode 100644
index 000000000..399999020
--- /dev/null
+++ b/tests/various/design2.ys
@@ -0,0 +1,9 @@
+read_verilog <<EOT
+module top(input i, output o);
+assign o = i;
+endmodule
+EOT
+design -stash foo
+design -delete foo
+logger -expect error "No saved design 'foo' found!" 1
+design -load foo
diff --git a/tests/various/global_scope.ys b/tests/various/global_scope.ys
new file mode 100644
index 000000000..8c8618e10
--- /dev/null
+++ b/tests/various/global_scope.ys
@@ -0,0 +1,18 @@
+read_verilog -sv <<EOT
+parameter A = 10;
+parameter B = A;
+
+typedef enum {
+ CONST_A = A,
+ CONST_B = A+1
+} enum_t;
+
+module top(output [3:0] q, output [3:0] r);
+assign q = 10;
+assign r = CONST_B;
+endmodule
+EOT
+
+hierarchy -top top
+sat -verify -prove q 10 top
+sat -verify -prove r 11 top