summaryrefslogtreecommitdiff
path: root/passes
diff options
context:
space:
mode:
authorAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
committerAhmed Irfan <irfan@levert.(none)>2015-04-03 16:38:07 +0200
commitbdf6b2b19ab2206f5957ad5b2ec582c2730d45ee (patch)
tree1d02541701054a1c3b1cdb66478d0cbc31c2d38f /passes
parent8acdd90bc918b780ad45cdac42b3baf84d2cc476 (diff)
parent4b4490761949e738dee54bdfc52e080e0a5c9067 (diff)
Merge branch 'master' of https://github.com/cliffordwolf/yosys
Diffstat (limited to 'passes')
-rw-r--r--passes/abc/abc.cc720
-rw-r--r--passes/abc/blifparse.cc10
-rw-r--r--passes/abc/blifparse.h7
-rw-r--r--passes/cmds/Makefile.inc3
-rw-r--r--passes/cmds/add.cc8
-rw-r--r--passes/cmds/check.cc154
-rw-r--r--passes/cmds/connect.cc4
-rw-r--r--passes/cmds/connwrappers.cc4
-rw-r--r--passes/cmds/copy.cc4
-rw-r--r--passes/cmds/cover.cc25
-rw-r--r--passes/cmds/delete.cc16
-rw-r--r--passes/cmds/logcmd.cc (renamed from passes/cmds/log.cc)4
-rw-r--r--passes/cmds/plugin.cc9
-rw-r--r--passes/cmds/rename.cc21
-rw-r--r--passes/cmds/scatter.cc4
-rw-r--r--passes/cmds/scc.cc59
-rw-r--r--passes/cmds/select.cc223
-rw-r--r--passes/cmds/setattr.cc6
-rw-r--r--passes/cmds/setundef.cc4
-rw-r--r--passes/cmds/show.cc94
-rw-r--r--passes/cmds/splice.cc33
-rw-r--r--passes/cmds/splitnets.cc6
-rw-r--r--passes/cmds/stat.cc242
-rw-r--r--passes/cmds/tee.cc8
-rw-r--r--passes/cmds/trace.cc17
-rw-r--r--passes/cmds/write_file.cc8
-rw-r--r--passes/equiv/Makefile.inc9
-rw-r--r--passes/equiv/equiv_add.cc89
-rw-r--r--passes/equiv/equiv_induct.cc241
-rw-r--r--passes/equiv/equiv_make.cc474
-rw-r--r--passes/equiv/equiv_miter.cc343
-rw-r--r--passes/equiv/equiv_remove.cc83
-rw-r--r--passes/equiv/equiv_simple.cc358
-rw-r--r--passes/equiv/equiv_status.cc94
-rw-r--r--passes/fsm/fsm.cc14
-rw-r--r--passes/fsm/fsm_detect.cc6
-rw-r--r--passes/fsm/fsm_expand.cc6
-rw-r--r--passes/fsm/fsm_export.cc9
-rw-r--r--passes/fsm/fsm_extract.cc22
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc15
-rw-r--r--passes/fsm/fsm_opt.cc18
-rw-r--r--passes/fsm/fsm_recode.cc55
-rw-r--r--passes/fsm/fsmdata.h15
-rw-r--r--passes/hierarchy/hierarchy.cc183
-rw-r--r--passes/hierarchy/submod.cc8
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc17
-rw-r--r--passes/memory/memory_bram.cc1174
-rw-r--r--passes/memory/memory_collect.cc130
-rw-r--r--passes/memory/memory_dff.cc16
-rw-r--r--passes/memory/memory_map.cc32
-rw-r--r--passes/memory/memory_share.cc33
-rw-r--r--passes/memory/memory_unpack.cc8
-rw-r--r--passes/opt/Makefile.inc3
-rw-r--r--passes/opt/opt.cc23
-rw-r--r--passes/opt/opt_clean.cc149
-rw-r--r--passes/opt/opt_const.cc103
-rw-r--r--passes/opt/opt_muxtree.cc349
-rw-r--r--passes/opt/opt_reduce.cc32
-rw-r--r--passes/opt/opt_rmdff.cc12
-rw-r--r--passes/opt/opt_share.cc31
-rw-r--r--passes/opt/share.cc489
-rw-r--r--passes/opt/wreduce.cc105
-rw-r--r--passes/proc/Makefile.inc1
-rw-r--r--passes/proc/proc.cc9
-rw-r--r--passes/proc/proc_arst.cc19
-rw-r--r--passes/proc/proc_clean.cc15
-rw-r--r--passes/proc/proc_dff.cc18
-rw-r--r--passes/proc/proc_dlatch.cc308
-rw-r--r--passes/proc/proc_init.cc8
-rw-r--r--passes/proc/proc_mux.cc18
-rw-r--r--passes/proc/proc_rmdead.cc8
-rw-r--r--passes/sat/eval.cc32
-rw-r--r--passes/sat/expose.cc20
-rw-r--r--passes/sat/freduce.cc60
-rw-r--r--passes/sat/miter.cc6
-rw-r--r--passes/sat/sat.cc417
-rw-r--r--passes/techmap/Makefile.inc13
-rw-r--r--passes/techmap/alumacc.cc92
-rw-r--r--passes/techmap/dff2dffe.cc337
-rw-r--r--passes/techmap/dfflibmap.cc113
-rw-r--r--passes/techmap/extract.cc534
-rw-r--r--passes/techmap/hilomap.cc10
-rw-r--r--passes/techmap/iopadmap.cc23
-rw-r--r--passes/techmap/libparse.cc45
-rw-r--r--passes/techmap/libparse.h2
-rw-r--r--passes/techmap/maccmap.cc84
-rw-r--r--passes/techmap/simplemap.cc121
-rw-r--r--passes/techmap/simplemap.h48
-rw-r--r--passes/techmap/techmap.cc140
-rw-r--r--passes/tests/test_abcloop.cc44
-rw-r--r--passes/tests/test_autotb.cc31
-rw-r--r--passes/tests/test_cell.cc165
94 files changed, 7274 insertions, 1913 deletions
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc
index f1d56b23..8cd0211c 100644
--- a/passes/abc/abc.cc
+++ b/passes/abc/abc.cc
@@ -29,33 +29,42 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558–562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}"
-#define ABC_COMMAND_CTR "strash; scorr -v; ifraig -v; retime -v {D}; strash; dch -vf; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; if -v"
-#define ABC_COMMAND_DFL "strash; scorr -v; ifraig -v; retime -v; strash; dch -vf; map -v"
+#define ABC_COMMAND_LIB "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}"
+#define ABC_COMMAND_CTR "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; scorr; ifraig; retime; strash; dch -f; if"
+#define ABC_COMMAND_DFL "strash; scorr; ifraig; retime; strash; dch -f; map"
-#define ABC_FAST_COMMAND_LIB "retime -v {D}; map -v {D}"
-#define ABC_FAST_COMMAND_CTR "retime -v {D}; map -v {D}; buffer -v; upsize -v {D}; dnsize -v {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime -v; if -v"
-#define ABC_FAST_COMMAND_DFL "retime -v; map -v"
+#define ABC_FAST_COMMAND_LIB "retime {D}; map {D}"
+#define ABC_FAST_COMMAND_CTR "retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "retime; if"
+#define ABC_FAST_COMMAND_DFL "retime; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cost.h"
#include "kernel/log.h"
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dirent.h>
#include <cerrno>
#include <sstream>
#include <climits>
+#ifndef _WIN32
+# include <unistd.h>
+# include <dirent.h>
+#endif
+
#include "blifparse.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
enum class gate_type_t {
G_NONE,
G_FF,
+ G_BUF,
G_NOT,
G_AND,
G_NAND,
@@ -81,16 +90,17 @@ struct gate_t
RTLIL::SigBit bit;
};
-static int map_autoidx;
-static SigMap assign_map;
-static RTLIL::Module *module;
-static std::vector<gate_t> signal_list;
-static std::map<RTLIL::SigBit, int> signal_map;
+bool markgroups;
+int map_autoidx;
+SigMap assign_map;
+RTLIL::Module *module;
+std::vector<gate_t> signal_list;
+std::map<RTLIL::SigBit, int> signal_map;
-static bool clk_polarity;
-static RTLIL::SigSpec clk_sig;
+bool clk_polarity, en_polarity;
+RTLIL::SigSpec clk_sig, en_sig;
-static int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
+int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1)
{
assign_map.apply(bit);
@@ -124,14 +134,14 @@ static int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in
return gate.id;
}
-static void mark_port(RTLIL::SigSpec sig)
+void mark_port(RTLIL::SigSpec sig)
{
for (auto &bit : assign_map(sig))
if (bit.wire != NULL && signal_map.count(bit) > 0)
signal_list[signal_map[bit]].is_port = true;
}
-static void extract_cell(RTLIL::Cell *cell, bool keepff)
+void extract_cell(RTLIL::Cell *cell, bool keepff)
{
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
@@ -139,7 +149,26 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
if (clk_sig != assign_map(cell->getPort("\\C")))
return;
+ if (GetSize(en_sig) != 0)
+ return;
+ goto matching_dff;
+ }
+
+ if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ {
+ if (clk_polarity != (cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_"))
+ return;
+ if (en_polarity != (cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_"))
+ return;
+ if (clk_sig != assign_map(cell->getPort("\\C")))
+ return;
+ if (en_sig != assign_map(cell->getPort("\\E")))
+ return;
+ goto matching_dff;
+ }
+ if (0) {
+ matching_dff:
RTLIL::SigSpec sig_d = cell->getPort("\\D");
RTLIL::SigSpec sig_q = cell->getPort("\\Q");
@@ -157,7 +186,7 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
return;
}
- if (cell->type == "$_NOT_")
+ if (cell->type.in("$_BUF_", "$_NOT_"))
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
@@ -165,7 +194,7 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
assign_map.apply(sig_a);
assign_map.apply(sig_y);
- map_signal(sig_y, G(NOT), map_signal(sig_a));
+ map_signal(sig_y, cell->type == "$_BUF_" ? G(BUF) : G(NOT), map_signal(sig_a));
module->remove(cell);
return;
@@ -273,14 +302,14 @@ static void extract_cell(RTLIL::Cell *cell, bool keepff)
}
}
-static std::string remap_name(RTLIL::IdString abc_name)
+std::string remap_name(RTLIL::IdString abc_name)
{
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
return sstr.str();
}
-static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts)
+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)
return;
@@ -309,7 +338,7 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
fprintf(f, "}\n");
}
-static void handle_loops()
+void handle_loops()
{
// http://en.wikipedia.org/wiki/Topological_sorting
// (Kahn, Arthur B. (1962), "Topological sorting of large networks")
@@ -442,7 +471,7 @@ static void handle_loops()
fclose(dot_f);
}
-static std::string add_echos_to_abc_cmd(std::string str)
+std::string add_echos_to_abc_cmd(std::string str)
{
std::string new_str, token;
for (size_t i = 0; i < str.size(); i++) {
@@ -450,8 +479,6 @@ static std::string add_echos_to_abc_cmd(std::string str)
if (str[i] == ';') {
while (i+1 < str.size() && str[i+1] == ' ')
i++;
- if (!new_str.empty())
- new_str += "echo; ";
new_str += "echo + " + token + " " + token + " ";
token.clear();
}
@@ -459,14 +486,14 @@ static std::string add_echos_to_abc_cmd(std::string str)
if (!token.empty()) {
if (!new_str.empty())
- new_str += "echo; echo + " + token + "; ";
+ new_str += "echo + " + token + "; ";
new_str += token;
}
return new_str;
}
-static std::string fold_abc_cmd(std::string str)
+std::string fold_abc_cmd(std::string str)
{
std::string token, new_str = " ";
int char_counter = 10;
@@ -485,63 +512,165 @@ static std::string fold_abc_cmd(std::string str)
return new_str;
}
-static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, bool fast_mode)
+std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
+{
+ if (show_tempdir)
+ return text;
+
+ while (1) {
+ size_t pos = text.find(tempdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
+ }
+
+ std::string selfdir_name = proc_self_dirname();
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
+
+ return text;
+}
+
+struct abc_output_filter
+{
+ bool got_cr;
+ int escape_seq_state;
+ std::string linebuf;
+ std::string tempdir_name;
+ bool show_tempdir;
+
+ abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
+ {
+ got_cr = false;
+ escape_seq_state = 0;
+ }
+
+ void next_char(char ch)
+ {
+ if (escape_seq_state == 0 && ch == '\033') {
+ escape_seq_state = 1;
+ return;
+ }
+ if (escape_seq_state == 1) {
+ escape_seq_state = ch == '[' ? 2 : 0;
+ return;
+ }
+ if (escape_seq_state == 2) {
+ if ((ch < '0' || '9' < ch) && ch != ';')
+ escape_seq_state = 0;
+ return;
+ }
+ escape_seq_state = 0;
+ if (ch == '\r') {
+ got_cr = true;
+ return;
+ }
+ if (ch == '\n') {
+ log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str());
+ got_cr = false, linebuf.clear();
+ return;
+ }
+ if (got_cr)
+ got_cr = false, linebuf.clear();
+ linebuf += ch;
+ }
+
+ void next_line(const std::string &line)
+ {
+ for (char ch : line)
+ next_char(ch);
+ }
+};
+
+void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
+ std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, int lut_mode2, bool dff_mode, std::string clk_str,
+ bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir)
{
module = current_module;
map_autoidx = autoidx++;
signal_map.clear();
signal_list.clear();
- assign_map.set(module);
- clk_polarity = true;
- clk_sig = RTLIL::SigSpec();
+ if (clk_str != "$")
+ {
+ assign_map.set(module);
+
+ clk_polarity = true;
+ clk_sig = RTLIL::SigSpec();
- char tempdir_name[] = "/tmp/yosys-abc-XXXXXX";
+ en_polarity = true;
+ en_sig = RTLIL::SigSpec();
+ }
+
+ std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
- char *p = mkdtemp(tempdir_name);
- log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n", module->name.c_str(), tempdir_name);
- if (p == NULL)
- log_error("For some reason mkdtemp() failed!\n");
+ tempdir_name = make_temp_dir(tempdir_name);
+ log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
+ module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
+
+ std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
+
+ if (!liberty_file.empty()) {
+ abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ if (!constr_file.empty())
+ abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
+ } else
+ if (lut_mode)
+ abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
+ else
+ abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
- std::string abc_command;
if (!script_file.empty()) {
if (script_file[0] == '+') {
for (size_t i = 1; i < script_file.size(); i++)
if (script_file[i] == '\'')
- abc_command += "'\\''";
+ abc_script += "'\\''";
else if (script_file[i] == ',')
- abc_command += " ";
+ abc_script += " ";
else
- abc_command += script_file[i];
+ abc_script += script_file[i];
} else
- abc_command = stringf("source %s", script_file.c_str());
+ abc_script += stringf("source %s", script_file.c_str());
} else if (lut_mode)
- abc_command = fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
+ abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
else if (!liberty_file.empty())
- abc_command = constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
+ abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else
- abc_command = fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+ abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
- for (size_t pos = abc_command.find("{D}"); pos != std::string::npos; pos = abc_command.find("{D}", pos))
- abc_command = abc_command.substr(0, pos) + delay_target + abc_command.substr(pos+3);
+ for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
- abc_command = add_echos_to_abc_cmd(abc_command);
+ abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
+ abc_script = add_echos_to_abc_cmd(abc_script);
- if (abc_command.size() > 128) {
- for (size_t i = 0; i+1 < abc_command.size(); i++)
- if (abc_command[i] == ';' && abc_command[i+1] == ' ')
- abc_command[i+1] = '\n';
- FILE *f = fopen(stringf("%s/abc.script", tempdir_name).c_str(), "wt");
- fprintf(f, "%s\n", abc_command.c_str());
- fclose(f);
- abc_command = stringf("source %s/abc.script", tempdir_name);
- }
+ for (size_t i = 0; i+1 < abc_script.size(); i++)
+ if (abc_script[i] == ';' && abc_script[i+1] == ' ')
+ abc_script[i+1] = '\n';
+
+ FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
+ fprintf(f, "%s\n", abc_script.c_str());
+ fclose(f);
- if (clk_str.empty()) {
+ if (!clk_str.empty() && clk_str != "$")
+ {
+ if (clk_str.find(',') != std::string::npos) {
+ int pos = clk_str.find(',');
+ std::string en_str = clk_str.substr(pos+1);
+ clk_str = clk_str.substr(0, pos);
+ if (en_str[0] == '!') {
+ 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 (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
@@ -550,41 +679,21 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
}
- if (dff_mode && clk_sig.size() == 0)
- {
- int best_dff_counter = 0;
- std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters;
+ if (dff_mode && clk_sig.empty())
+ log_error("Clock domain %s not found.\n", clk_str.c_str());
- for (auto &it : module->cells_)
- {
- RTLIL::Cell *cell = it.second;
- if (cell->type != "$_DFF_N_" && cell->type != "$_DFF_P_")
- continue;
-
- std::pair<bool, RTLIL::SigSpec> key(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")));
- if (++dff_counters[key] > best_dff_counter) {
- best_dff_counter = dff_counters[key];
- clk_polarity = key.first;
- clk_sig = key.second;
- }
- }
- }
-
- if (dff_mode || !clk_str.empty()) {
+ if (dff_mode || !clk_str.empty())
+ {
if (clk_sig.size() == 0)
- log("No (matching) clock domain found. Not extracting any FF cells.\n");
- else
- log("Found (matching) %s clock domain: %s\n", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+ log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
+ else {
+ log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+ if (en_sig.size() != 0)
+ log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+ log("\n");
+ }
}
- if (clk_sig.size() != 0)
- mark_port(clk_sig);
-
- std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells_.size());
- for (auto &it : module->cells_)
- if (design->selected(current_module, it.second))
- cells.push_back(it.second);
for (auto c : cells)
extract_cell(c, keepff);
@@ -596,14 +705,19 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
for (auto &cell_it : module->cells_)
for (auto &port_it : cell_it.second->connections())
mark_port(port_it.second);
-
+
+ if (clk_sig.size() != 0)
+ mark_port(clk_sig);
+
+ if (en_sig.size() != 0)
+ mark_port(en_sig);
+
handle_loops();
- if (asprintf(&p, "%s/input.blif", tempdir_name) < 0) log_abort();
- FILE *f = fopen(p, "wt");
+ std::string buffer = stringf("%s/input.blif", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
- free(p);
+ log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
fprintf(f, ".model netlist\n");
@@ -642,7 +756,10 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
int count_gates = 0;
for (auto &si : signal_list) {
- if (si.type == G(NOT)) {
+ if (si.type == G(BUF)) {
+ fprintf(f, ".names n%d n%d\n", si.in1, si.id);
+ fprintf(f, "1 1\n");
+ } else if (si.type == G(NOT)) {
fprintf(f, ".names n%d n%d\n", si.in1, si.id);
fprintf(f, "0 1\n");
} else if (si.type == G(AND)) {
@@ -700,132 +817,64 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
fprintf(f, ".end\n");
fclose(f);
- log("Extracted %d gates and %zd wires to a netlist network with %d inputs and %d outputs.\n",
- count_gates, signal_list.size(), count_input, count_output);
+ log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+ count_gates, GetSize(signal_list), count_input, count_output);
log_push();
-
+
if (count_output > 0)
{
log_header("Executing ABC.\n");
- if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) log_abort();
- f = fopen(p, "wt");
+ buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
- fprintf(f, "GATE ZERO 1 Y=CONST0;\n");
- fprintf(f, "GATE ONE 1 Y=CONST1;\n");
- fprintf(f, "GATE BUF 1 Y=A; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NOT 1 Y=!A; PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE AND 1 Y=A*B; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NAND 1 Y=!(A*B); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OR 1 Y=A+B; PIN * NONINV 1 999 1 0 1 0\n");
- fprintf(f, "GATE NOR 1 Y=!(A+B); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE XOR 1 Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE XNOR 1 Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE MUX 1 Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n");
- fprintf(f, "GATE AOI3 1 Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OAI3 1 Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE AOI4 1 Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n");
- fprintf(f, "GATE OAI4 1 Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n");
+ 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");
+ fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
+ fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
+ fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+ fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+ fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+ fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+ fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+ fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+ fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+ fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+ fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+ fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+ fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
fclose(f);
- free(p);
if (lut_mode) {
- if (asprintf(&p, "%s/lutdefs.txt", tempdir_name) < 0) log_abort();
- f = fopen(p, "wt");
+ buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
+ f = fopen(buffer.c_str(), "wt");
if (f == NULL)
- log_error("Opening %s for writing failed: %s\n", p, strerror(errno));
+ log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
for (int i = 0; i < lut_mode; i++)
fprintf(f, "%d 1.00 1.00\n", i+1);
+ for (int i = lut_mode; i < lut_mode2; i++)
+ fprintf(f, "%d %d.00 1.00\n", i+1, 2 << (i - lut_mode));
fclose(f);
- free(p);
}
- std::string buffer;
- if (!liberty_file.empty()) {
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lib -w %s; ",
- exe_file.c_str(), tempdir_name, liberty_file.c_str());
- if (!constr_file.empty())
- buffer += stringf("read_constr -v %s; ", constr_file.c_str());
- buffer += abc_command + "; ";
- } else
- if (lut_mode)
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lut %s/lutdefs.txt; %s; ",
- exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
- else
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_library %s/stdcells.genlib; %s; ",
- exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
- buffer += stringf("write_blif %s/output.blif' 2>&1", tempdir_name);
+ buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+ log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
- log("%s\n", buffer.c_str());
+ abc_output_filter filt(tempdir_name, show_tempdir);
+ int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+ if (ret != 0)
+ log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
- errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
- f = popen(buffer.c_str(), "r");
+ buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif");
+ f = fopen(buffer.c_str(), "rt");
if (f == NULL)
- log_error("Opening pipe to `%s' for reading failed: %s\n", buffer.c_str(), strerror(errno));
-#if 0
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- log("ABC: %s", logbuf);
-#else
- bool got_cr = false;
- int escape_seq_state = 0;
- std::string linebuf;
- char logbuf[1024];
- while (fgets(logbuf, 1024, f) != NULL)
- for (char *p = logbuf; *p; p++) {
- if (escape_seq_state == 0 && *p == '\033') {
- escape_seq_state = 1;
- continue;
- }
- if (escape_seq_state == 1) {
- escape_seq_state = *p == '[' ? 2 : 0;
- continue;
- }
- if (escape_seq_state == 2) {
- if ((*p < '0' || '9' < *p) && *p != ';')
- escape_seq_state = 0;
- continue;
- }
- escape_seq_state = 0;
- if (*p == '\r') {
- got_cr = true;
- continue;
- }
- if (*p == '\n') {
- log("ABC: %s\n", linebuf.c_str());
- got_cr = false, linebuf.clear();
- continue;
- }
- if (got_cr)
- got_cr = false, linebuf.clear();
- linebuf += *p;
- }
- if (!linebuf.empty())
- log("ABC: %s\n", linebuf.c_str());
-#endif
- errno = 0;
- int ret = pclose(f);
- if (ret < 0)
- log_error("Closing pipe to `%s' failed: %s\n", buffer.c_str(), strerror(errno));
- if (WEXITSTATUS(ret) != 0) {
- switch (WEXITSTATUS(ret)) {
- case 127: log_error("ABC: execution of command \"%s\" failed: Command not found\n", exe_file.c_str()); break;
- case 126: log_error("ABC: execution of command \"%s\" failed: Command not executable\n", exe_file.c_str()); break;
- default: log_error("ABC: execution of command \"%s\" failed: the shell returned %d\n", exe_file.c_str(), WEXITSTATUS(ret)); break;
- }
- }
-
- if (asprintf(&p, "%s/%s", tempdir_name, "output.blif") < 0) log_abort();
- f = fopen(p, "rt");
- if (f == NULL)
- log_error("Can't open ABC output file `%s'.\n", p);
+ log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
bool builtin_lib = liberty_file.empty() && script_file.empty() && !lut_mode;
RTLIL::Design *mapped_design = abc_parse_blif(f, builtin_lib ? "\\DFF" : "\\_dff_");
fclose(f);
- free(p);
log_header("Re-integrating ABC results.\n");
RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
@@ -834,6 +883,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second;
RTLIL::Wire *wire = module->addWire(remap_name(w->name));
+ if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx;
design->select(module, wire);
}
@@ -859,6 +909,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\NOT") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
@@ -866,6 +917,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
@@ -874,6 +926,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\MUX") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
@@ -883,6 +936,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AOI3" || c->type == "\\OAI3") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
@@ -892,6 +946,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\AOI4" || c->type == "\\OAI4") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
@@ -902,7 +957,15 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\DFF") {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
+ }
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
cell->setPort("\\C", clk_sig);
@@ -927,7 +990,15 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (c->type == "\\_dff_") {
log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
+ }
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
cell->setPort("\\C", clk_sig);
@@ -935,6 +1006,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
continue;
}
RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->parameters = c->parameters;
for (auto &conn : c->connections()) {
RTLIL::SigSpec newsig;
@@ -990,23 +1062,8 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
if (cleanup)
{
- log_header("Removing temp directory `%s':\n", tempdir_name);
-
- struct dirent **namelist;
- int n = scandir(tempdir_name, &namelist, 0, alphasort);
- log_assert(n >= 0);
- for (int i = 0; i < n; i++) {
- if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
- if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) log_abort();
- log("Removing `%s'.\n", p);
- remove(p);
- free(p);
- }
- free(namelist[i]);
- }
- free(namelist);
- log("Removing `%s'.\n", tempdir_name);
- rmdir(tempdir_name);
+ log("Removing temp directory.\n");
+ remove_directory(tempdir_name);
}
log_pop();
@@ -1087,15 +1144,20 @@ struct AbcPass : public Pass {
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
+ log(" -lut <w1>:<w2>\n");
+ log(" generate netlist using luts of (max) the specified width <w2>. All\n");
+ log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
+ log(" the area cost doubles with each additional input bit. the delay cost\n");
+ log(" is still constant for all lut widths.\n");
+ log("\n");
log(" -dff\n");
- log(" also pass $_DFF_?_ cells through ABC (only one clock domain, if many\n");
- log(" clock domains are present in a module, the one with the largest number\n");
- log(" of $_DFF_?_ cells in it is used)\n");
+ log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
+ log(" clock domains are automatically partitioned in clock domains and each\n");
+ log(" domain is passed through ABC independently.\n");
log("\n");
- log(" -clk [!]<signal-name>\n");
- log(" use the specified clock domain. (when this option is used in combination\n");
- log(" with -dff, then it falls back to the automatic dection of clock domain\n");
- log(" if the specified clock is not found in a module.)\n");
+ log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
+ log(" use only the specified clock domain. this is like -dff, but only FF\n");
+ log(" cells that belong to the specified clock domain are used.\n");
log("\n");
log(" -keepff\n");
log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
@@ -1105,6 +1167,15 @@ struct AbcPass : public Pass {
log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n");
log("\n");
+ log(" -showtmp\n");
+ log(" print the temp dir name in log. usually this is suppressed so that the\n");
+ log(" command output is identical across runs.\n");
+ log("\n");
+ log(" -markgroups\n");
+ log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n");
+ log(" this attribute is a unique integer for each ABC process started. This\n");
+ log(" is useful for debugging the partitioning of clock domains.\n");
+ log("\n");
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
@@ -1122,7 +1193,14 @@ struct AbcPass : public Pass {
std::string exe_file = proc_self_dirname() + "yosys-abc";
std::string script_file, liberty_file, constr_file, clk_str, delay_target;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
- int lut_mode = 0;
+ bool show_tempdir = false;
+ int lut_mode = 0, lut_mode2 = 0;
+ markgroups = false;
+
+#ifdef _WIN32
+ if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
+ exe_file = proc_self_dirname() + "..\\yosys-abc";
+#endif
size_t argidx;
char pwd [PATH_MAX];
@@ -1138,19 +1216,19 @@ struct AbcPass : public Pass {
}
if (arg == "-script" && argidx+1 < args.size()) {
script_file = args[++argidx];
- if (!script_file.empty() && script_file[0] != '/' && script_file[0] != '+')
+ if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
script_file = std::string(pwd) + "/" + script_file;
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
liberty_file = args[++argidx];
- if (!liberty_file.empty() && liberty_file[0] != '/')
+ if (!liberty_file.empty() && !is_absolute_path(liberty_file))
liberty_file = std::string(pwd) + "/" + liberty_file;
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
constr_file = args[++argidx];
- if (!constr_file.empty() && constr_file[0] != '/')
+ if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
@@ -1159,7 +1237,15 @@ struct AbcPass : public Pass {
continue;
}
if (arg == "-lut" && argidx+1 < args.size()) {
- lut_mode = atoi(args[++argidx].c_str());
+ string arg = args[++argidx];
+ size_t pos = arg.find_first_of(':');
+ if (pos != string::npos) {
+ lut_mode = atoi(arg.substr(0, pos).c_str());
+ lut_mode2 = atoi(arg.substr(pos+1).c_str());
+ } else {
+ lut_mode = atoi(arg.c_str());
+ lut_mode2 = lut_mode;
+ }
continue;
}
if (arg == "-fast") {
@@ -1172,6 +1258,7 @@ struct AbcPass : public Pass {
}
if (arg == "-clk" && argidx+1 < args.size()) {
clk_str = args[++argidx];
+ dff_mode = true;
continue;
}
if (arg == "-keepff") {
@@ -1182,6 +1269,14 @@ struct AbcPass : public Pass {
cleanup = false;
continue;
}
+ if (arg == "-showtmp") {
+ show_tempdir = true;
+ continue;
+ }
+ if (arg == "-markgroups") {
+ markgroups = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -1191,12 +1286,158 @@ struct AbcPass : public Pass {
if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n");
- for (auto &mod_it : design->modules_)
- if (design->selected(mod_it.second)) {
- if (mod_it.second->processes.size() > 0)
- log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
- else
- abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str, keepff, delay_target, fast_mode);
+ for (auto mod : design->selected_modules())
+ if (mod->processes.size() > 0)
+ log("Skipping module %s as it contains processes.\n", log_id(mod));
+ else if (!dff_mode || !clk_str.empty())
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
+ else
+ {
+ assign_map.set(mod);
+ CellTypes ct(design);
+
+ std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+ std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+
+ std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
+ std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+ std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+
+ typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+ std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+ std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+
+ for (auto cell : all_cells)
+ {
+ clkdomain_t key;
+
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second) {
+ bit = assign_map(bit);
+ if (bit.wire != nullptr) {
+ cell_to_bit[cell].insert(bit);
+ bit_to_cell[bit].insert(cell);
+ if (ct.cell_input(cell->type, conn.first)) {
+ cell_to_bit_up[cell].insert(bit);
+ bit_to_cell_down[bit].insert(cell);
+ }
+ if (ct.cell_output(cell->type, conn.first)) {
+ cell_to_bit_down[cell].insert(bit);
+ bit_to_cell_up[bit].insert(cell);
+ }
+ }
+ }
+
+ if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ {
+ key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+ }
+ else
+ if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+ {
+ bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
+ bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
+ key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+ }
+ else
+ continue;
+
+ unassigned_cells.erase(cell);
+ expand_queue.insert(cell);
+ expand_queue_up.insert(cell);
+ expand_queue_down.insert(cell);
+
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ while (!expand_queue_up.empty() || !expand_queue_down.empty())
+ {
+ if (!expand_queue_up.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_up.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_up.erase(cell);
+
+ for (auto bit : cell_to_bit_up[cell])
+ for (auto c : bit_to_cell_up[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (!expand_queue_down.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue_down.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue_down.erase(cell);
+
+ for (auto bit : cell_to_bit_down[cell])
+ for (auto c : bit_to_cell_down[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue_up.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ expand_queue.insert(c);
+ }
+ }
+
+ if (expand_queue_up.empty() && expand_queue_down.empty()) {
+ expand_queue_up.swap(next_expand_queue_up);
+ expand_queue_down.swap(next_expand_queue_down);
+ }
+ }
+
+ while (!expand_queue.empty())
+ {
+ RTLIL::Cell *cell = *expand_queue.begin();
+ clkdomain_t key = assigned_cells_reverse.at(cell);
+ expand_queue.erase(cell);
+
+ for (auto bit : cell_to_bit.at(cell)) {
+ for (auto c : bit_to_cell[bit])
+ if (unassigned_cells.count(c)) {
+ unassigned_cells.erase(c);
+ next_expand_queue.insert(c);
+ assigned_cells[key].push_back(c);
+ assigned_cells_reverse[c] = key;
+ }
+ bit_to_cell[bit].clear();
+ }
+
+ if (expand_queue.empty())
+ expand_queue.swap(next_expand_queue);
+ }
+
+ clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+ for (auto cell : unassigned_cells) {
+ assigned_cells[key].push_back(cell);
+ assigned_cells_reverse[cell] = key;
+ }
+
+ log_header("Summary of detected clock domains:\n");
+ for (auto &it : assigned_cells)
+ log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+ std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+ std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+ for (auto &it : assigned_cells) {
+ clk_polarity = std::get<0>(it.first);
+ clk_sig = assign_map(std::get<1>(it.first));
+ en_polarity = std::get<2>(it.first);
+ en_sig = assign_map(std::get<3>(it.first));
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, lut_mode2,
+ !clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir);
+ assign_map.set(mod);
+ }
}
assign_map.clear();
@@ -1207,3 +1448,4 @@ struct AbcPass : public Pass {
}
} AbcPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/abc/blifparse.cc b/passes/abc/blifparse.cc
index 1fbb5720..db87eec4 100644
--- a/passes/abc/blifparse.cc
+++ b/passes/abc/blifparse.cc
@@ -18,9 +18,8 @@
*/
#include "blifparse.h"
-#include "kernel/log.h"
-#include <stdio.h>
-#include <string.h>
+
+YOSYS_NAMESPACE_BEGIN
static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, FILE *f)
{
@@ -130,7 +129,8 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
if (p == NULL)
goto error;
- RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(p));
+ IdString celltype = RTLIL::escape_id(p);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
@@ -240,3 +240,5 @@ error:
// return NULL;
}
+YOSYS_NAMESPACE_END
+
diff --git a/passes/abc/blifparse.h b/passes/abc/blifparse.h
index 272e4e64..31f5b2e5 100644
--- a/passes/abc/blifparse.h
+++ b/passes/abc/blifparse.h
@@ -20,9 +20,12 @@
#ifndef ABC_BLIFPARSE
#define ABC_BLIFPARSE
-#include "kernel/rtlil.h"
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
extern RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name);
-#endif
+YOSYS_NAMESPACE_END
+#endif
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index eba61d1d..e4b40c41 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -14,11 +14,12 @@ OBJS += passes/cmds/setattr.o
OBJS += passes/cmds/copy.o
OBJS += passes/cmds/splice.o
OBJS += passes/cmds/scc.o
-OBJS += passes/cmds/log.o
+OBJS += passes/cmds/logcmd.o
OBJS += passes/cmds/tee.o
OBJS += passes/cmds/write_file.o
OBJS += passes/cmds/connwrappers.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/trace.o
OBJS += passes/cmds/plugin.o
+OBJS += passes/cmds/check.o
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index e3fde855..054cfc1c 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -17,9 +17,10 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output, bool flag_global)
{
@@ -150,3 +151,4 @@ struct AddPass : public Pass {
}
} AddPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
new file mode 100644
index 00000000..bb8fe78e
--- /dev/null
+++ b/passes/cmds/check.cc
@@ -0,0 +1,154 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/utils.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct CheckPass : public Pass {
+ CheckPass() : Pass("check", "check for obvious problems in the design") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" check [options] [selection]\n");
+ log("\n");
+ log("This pass identifies the following problems in the current design:\n");
+ log("\n");
+ log(" - combinatorical loops\n");
+ log("\n");
+ log(" - two or more conflicting drivers for one wire\n");
+ log("\n");
+ log(" - used wires that do not have a driver\n");
+ log("\n");
+ log("When called with -noinit then this command also checks for wires which have\n");
+ log("the 'init' attribute set.\n");
+ log("\n");
+ log("When called with -assert then the command will produce an error if any\n");
+ log("problems are found in the current design.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ int counter = 0;
+ bool noinit = false;
+ bool assert_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-noinit") {
+ noinit = true;
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ assert_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log_header("Executing CHECK pass (checking for obvious problems).\n");
+
+ for (auto module : design->selected_whole_modules_warn())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ log("checking module %s..\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, vector<string>> wire_drivers;
+ pool<SigBit> used_wires;
+ TopoSort<string> topo;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ SigSpec sig = sigmap(conn.second);
+ bool logic_cell = yosys_celltypes.cell_evaluable(cell->type);
+ if (cell->input(conn.first))
+ for (auto bit : sig)
+ if (bit.wire) {
+ if (logic_cell)
+ topo.edge(stringf("wire %s", log_signal(bit)),
+ stringf("cell %s (%s)", log_id(cell), log_id(cell->type)));
+ used_wires.insert(bit);
+ }
+ if (cell->output(conn.first))
+ for (int i = 0; i < GetSize(sig); i++) {
+ if (logic_cell)
+ topo.edge(stringf("cell %s (%s)", log_id(cell), log_id(cell->type)),
+ stringf("wire %s", log_signal(sig[i])));
+ wire_drivers[sig[i]].push_back(stringf("port %s[%d] of cell %s (%s)",
+ log_id(conn.first), i, log_id(cell), log_id(cell->type)));
+ }
+ }
+
+ for (auto wire : module->wires()) {
+ if (wire->port_input) {
+ SigSpec sig = sigmap(wire);
+ for (int i = 0; i < GetSize(sig); i++)
+ wire_drivers[sig[i]].push_back(stringf("module input %s[%d]", log_id(wire), i));
+ }
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ if (bit.wire) used_wires.insert(bit);
+ if (noinit && wire->attributes.count("\\init")) {
+ log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
+ counter++;
+ }
+ }
+
+ for (auto it : wire_drivers)
+ if (GetSize(it.second) > 1) {
+ string message = stringf("multiple conflicting drivers for %s.%s:\n", log_id(module), log_signal(it.first));
+ for (auto str : it.second)
+ message += stringf(" %s\n", str.c_str());
+ log_warning("%s", message.c_str());
+ counter++;
+ }
+
+ for (auto bit : used_wires)
+ if (!wire_drivers.count(bit)) {
+ log_warning("Wire %s.%s is used but has no driver.\n", log_id(module), log_signal(bit));
+ counter++;
+ }
+
+ topo.sort();
+ for (auto &loop : topo.loops) {
+ string message = stringf("found logic loop in module %s:\n", log_id(module));
+ for (auto &str : loop)
+ message += stringf(" %s\n", str.c_str());
+ log_warning("%s", message.c_str());
+ counter++;
+ }
+ }
+
+ log("found and reported %d problems.\n", counter);
+
+ if (assert_mode && counter > 0)
+ log_error("Found %d problems in 'check -assert'.\n", counter);
+ }
+} CheckPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 30c80f73..e17c1b1c 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -23,6 +23,9 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig)
{
CellTypes ct(design);
@@ -183,3 +186,4 @@ struct ConnectPass : public Pass {
}
} ConnectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index aac11716..a65a6364 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ConnwrappersWorker
{
struct portdecl_t {
@@ -203,3 +206,4 @@ struct ConnwrappersPass : public Pass {
}
} ConnwrappersPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index be775820..459e5b0e 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct CopyPass : public Pass {
CopyPass() : Pass("copy", "copy modules in the design") { }
virtual void help()
@@ -53,3 +56,4 @@ struct CopyPass : public Pass {
}
} CopyPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index ac72ba53..5644066a 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -17,14 +17,22 @@
*
*/
+#include "kernel/yosys.h"
#include <sys/types.h>
-#include <unistd.h>
-#include <fnmatch.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") { }
virtual void help()
@@ -72,7 +80,7 @@ struct CoverPass : public Pass {
log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n");
log("\n");
log("\n");
- log("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+ log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -92,9 +100,13 @@ struct CoverPass : public Pass {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx];
if (args[argidx-1] == "-d") {
+ #ifdef _WIN32
+ log_cmd_error("The 'cover -d' option is not supported on win32.\n");
+ #else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4);
+ #endif
}
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
@@ -116,11 +128,11 @@ struct CoverPass : public Pass {
log("\n");
}
-#ifdef COVER_ACTIVE
+#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
- if (!fnmatch(p.c_str(), it.first.c_str(), 0))
+ if (patmatch(p.c_str(), it.first.c_str()))
goto pattern_match;
continue;
}
@@ -134,7 +146,7 @@ struct CoverPass : public Pass {
for (auto f : out_files)
fclose(f);
- log_cmd_error("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+ log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n");
#endif
for (auto f : out_files)
@@ -142,3 +154,4 @@ struct CoverPass : public Pass {
}
} CoverPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 2a91bc9e..b4362887 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -17,9 +17,10 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
@@ -90,10 +91,10 @@ struct DeletePass : public Pass {
continue;
}
- std::set<RTLIL::Wire*> delete_wires;
- std::set<RTLIL::Cell*> delete_cells;
- std::set<RTLIL::IdString> delete_procs;
- std::set<RTLIL::IdString> delete_mems;
+ pool<RTLIL::Wire*> delete_wires;
+ pool<RTLIL::Cell*> delete_cells;
+ pool<RTLIL::IdString> delete_procs;
+ pool<RTLIL::IdString> delete_mems;
for (auto &it : module->wires_)
if (design->selected(module, it.second))
@@ -140,3 +141,4 @@ struct DeletePass : public Pass {
}
} DeletePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/log.cc b/passes/cmds/logcmd.cc
index 34db0eed..85386f3d 100644
--- a/passes/cmds/log.cc
+++ b/passes/cmds/logcmd.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct LogPass : public Pass {
LogPass() : Pass("log", "print text and log files") { }
virtual void help()
@@ -76,3 +79,4 @@ struct LogPass : public Pass {
}
} LogPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index 4e8234d1..f7c65bbd 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -28,9 +28,9 @@ YOSYS_NAMESPACE_BEGIN
std::map<std::string, void*> loaded_plugins;
std::map<std::string, std::string> loaded_plugin_aliases;
+#ifdef YOSYS_ENABLE_PLUGINS
void load_plugin(std::string filename, std::vector<std::string> aliases)
{
-#ifdef YOSYS_ENABLE_PLUGINS
if (filename.find('/') == std::string::npos)
filename = "./" + filename;
@@ -44,10 +44,13 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
for (auto &alias : aliases)
loaded_plugin_aliases[alias] = filename;
+}
#else
+void load_plugin(std::string, std::vector<std::string>)
+{
log_error("This version of yosys is built without plugin support.\n");
-#endif
}
+#endif
struct PluginPass : public Pass {
PluginPass() : Pass("plugin", "load and list loaded plugins") { }
@@ -112,7 +115,7 @@ struct PluginPass : public Pass {
log("\n");
int max_alias_len = 1;
for (auto &it : loaded_plugin_aliases)
- max_alias_len = std::max(max_alias_len, SIZE(it.first));
+ max_alias_len = std::max(max_alias_len, GetSize(it.first));
for (auto &it : loaded_plugin_aliases)
log("Alias: %-*s %s\n", max_alias_len, it.first.c_str(), it.second.c_str());
}
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 91de364f..17d803e9 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
{
from_name = RTLIL::escape_id(from_name);
@@ -31,8 +34,11 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
for (auto &it : module->wires_)
if (it.first == from_name) {
- log("Renaming wire %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
- module->rename(it.second, to_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)
+ module->fixup_ports();
return;
}
@@ -113,7 +119,7 @@ struct RenamePass : public Pass {
if (!design->selected(module))
continue;
- std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ 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());
@@ -121,8 +127,9 @@ struct RenamePass : public Pass {
new_wires[it.second->name] = it.second;
}
module->wires_.swap(new_wires);
+ module->fixup_ports();
- std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ 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());
@@ -143,7 +150,7 @@ struct RenamePass : public Pass {
if (!design->selected(module))
continue;
- std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
+ 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)
@@ -151,8 +158,9 @@ struct RenamePass : public Pass {
new_wires[it.second->name] = it.second;
}
module->wires_.swap(new_wires);
+ module->fixup_ports();
- std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
+ dict<RTLIL::IdString, RTLIL::Cell*> new_cells;
for (auto &it : module->cells_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\')
@@ -196,3 +204,4 @@ struct RenamePass : public Pass {
}
} RenamePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index e09c0012..1cd55ecb 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ScatterPass : public Pass {
ScatterPass() : Pass("scatter", "add additional intermediate nets") { }
virtual void help()
@@ -67,3 +70,4 @@ struct ScatterPass : public Pass {
}
} ScatterPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index 5224f5bc..f4eeac07 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -29,6 +29,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SccWorker
{
RTLIL::Design *design;
@@ -97,7 +100,8 @@ struct SccWorker
}
}
- SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool allCellTypes, int maxDepth) : design(design), module(module), sigmap(module)
+ SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
+ design(design), module(module), sigmap(module)
{
if (module->processes.size() > 0) {
log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
@@ -164,11 +168,23 @@ struct SccWorker
labelCounter = 0;
cellLabels.clear();
- while (workQueue.size() > 0) {
+ while (workQueue.size() > 0)
+ {
RTLIL::Cell *cell = *workQueue.begin();
log_assert(cellStack.size() == 0);
cellDepth.clear();
- run(cell, 0, maxDepth);
+
+ if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
+ log("Found an SCC:");
+ std::set<RTLIL::Cell*> scc;
+ log(" %s", RTLIL::id2cstr(cell->name));
+ cell2scc[cell] = sccList.size();
+ scc.insert(cell);
+ sccList.push_back(scc);
+ workQueue.erase(cell);
+ log("\n");
+ } else
+ run(cell, 0, maxDepth);
}
log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
@@ -209,10 +225,18 @@ struct SccPass : public Pass {
log("This command identifies strongly connected components (aka logic loops) in the\n");
log("design.\n");
log("\n");
+ log(" -expect <num>\n");
+ log(" expect to find exactly <num> SSCs. A different number of SSCs will\n");
+ log(" produce an error.\n");
+ log("\n");
log(" -max_depth <num>\n");
- log(" limit to loops not longer than the specified number of cells. This can\n");
- log(" e.g. be useful in identifying local loops in a module that turns out\n");
- log(" to be one gigantic SCC.\n");
+ log(" limit to loops not longer than the specified number of cells. This\n");
+ log(" can e.g. be useful in identifying small local loops in a module that\n");
+ log(" implements one large SCC.\n");
+ log("\n");
+ log(" -nofeedback\n");
+ log(" do not count cells that have their output fed back into one of their\n");
+ log(" inputs as single-cell scc.\n");
log("\n");
log(" -all_cell_types\n");
log(" Usually this command only considers internal non-memory cells. With\n");
@@ -236,7 +260,9 @@ struct SccPass : public Pass {
std::map<std::string, std::string> setCellAttr, setWireAttr;
bool allCellTypes = false;
bool selectMode = false;
+ bool nofeedbackMode = false;
int maxDepth = -1;
+ int expect = -1;
log_header("Executing SCC pass (detecting logic loops).\n");
@@ -246,6 +272,14 @@ struct SccPass : public Pass {
maxDepth = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-expect" && argidx+1 < args.size()) {
+ expect = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-nofeedback") {
+ nofeedbackMode = true;
+ continue;
+ }
if (args[argidx] == "-all_cell_types") {
allCellTypes = true;
continue;
@@ -279,16 +313,26 @@ struct SccPass : public Pass {
log_cmd_error("The -set*_attr options are not implemented at the moment!\n");
RTLIL::Selection newSelection(false);
+ int scc_counter = 0;
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
{
- SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
+ SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);
+ scc_counter += GetSize(worker.sccList);
if (selectMode)
worker.select(newSelection);
}
+ if (expect >= 0) {
+ if (scc_counter == expect)
+ log("Found and expected %d SCCs.\n", scc_counter);
+ else
+ log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
+ } else
+ log("Found %d SCCs.\n", scc_counter);
+
if (selectMode) {
log_assert(origSelectPos >= 0);
design->selection_stack[origSelectPos] = newSelection;
@@ -297,3 +341,4 @@ struct SccPass : public Pass {
}
} SccPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 4c540ca6..53ff4d47 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -17,14 +17,15 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
#include <string.h>
-#include <fnmatch.h>
#include <errno.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
static std::vector<RTLIL::Selection> work_stack;
@@ -35,9 +36,9 @@ static bool match_ids(RTLIL::IdString id, std::string pattern)
return true;
if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern)
return true;
- if (!fnmatch(pattern.c_str(), id.c_str(), 0))
+ if (patmatch(pattern.c_str(), id.c_str()))
return true;
- if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), 0))
+ if (id.size() > 0 && id[0] == '\\' && patmatch(pattern.c_str(), id.substr(1).c_str()))
return true;
if (id.size() > 0 && id[0] == '$' && pattern.size() > 0 && pattern[0] == '$') {
const char *p = id.c_str();
@@ -80,7 +81,7 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
std::string value_str = value.decode_string();
if (match_op == '=')
- if (!fnmatch(pattern.c_str(), value.decode_string().c_str(), FNM_NOESCAPE))
+ if (patmatch(pattern.c_str(), value.decode_string().c_str()))
return true;
if (match_op == '=')
@@ -100,13 +101,13 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
log_abort();
}
-static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op)
+static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, char match_op)
{
if (name_pat.find('*') != std::string::npos || name_pat.find('?') != std::string::npos || name_pat.find('[') != std::string::npos) {
for (auto &it : attributes) {
- if (!fnmatch(name_pat.c_str(), it.first.c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op))
+ if (patmatch(name_pat.c_str(), it.first.c_str()) && match_attr_val(it.second, value_pat, match_op))
return true;
- if (it.first.size() > 0 && it.first[0] == '\\' && !fnmatch(name_pat.c_str(), it.first.substr(1).c_str(), FNM_NOESCAPE) && match_attr_val(it.second, value_pat, match_op))
+ if (it.first.size() > 0 && it.first[0] == '\\' && patmatch(name_pat.c_str(), it.first.substr(1).c_str()) && match_attr_val(it.second, value_pat, match_op))
return true;
}
} else {
@@ -118,7 +119,7 @@ static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes
return false;
}
-static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
+static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
{
size_t pos = match_expr.find_first_of("<!=>");
@@ -364,7 +365,7 @@ static int parse_comma_list(std::set<RTLIL::IdString> &tokens, std::string str,
}
}
-static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct)
+static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct, bool eval_only)
{
int sel_objects = 0;
bool is_input, is_output;
@@ -375,6 +376,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
RTLIL::Module *mod = mod_it.second;
std::set<RTLIL::Wire*> selected_wires;
+ auto selected_members = lhs.selected_members[mod->name];
for (auto &it : mod->wires_)
if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0)
@@ -388,9 +390,9 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
for (size_t i = 0; i < conn_lhs.size(); i++) {
if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL)
continue;
- if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && lhs.selected_members[mod->name].count(conn_lhs[i].wire->name) == 0)
+ if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && selected_members.count(conn_lhs[i].wire->name) == 0)
lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--;
- if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && lhs.selected_members[mod->name].count(conn_rhs[i].wire->name) == 0)
+ if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && selected_members.count(conn_rhs[i].wire->name) == 0)
lhs.selected_members[mod->name].insert(conn_rhs[i].wire->name), sel_objects++, max_objects--;
}
}
@@ -399,6 +401,8 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
for (auto &conn : cell.second->connections())
{
char last_mode = '-';
+ if (eval_only && !yosys_celltypes.cell_evaluable(cell.second->type))
+ goto exclude_match;
for (auto &rule : rules) {
last_mode = rule.mode;
if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type) == 0)
@@ -417,10 +421,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first);
for (auto &chunk : conn.second.chunks())
if (chunk.wire != NULL) {
- if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && lhs.selected_members[mod->name].count(cell.first) == 0)
+ if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && selected_members.count(cell.first) == 0)
if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input))
lhs.selected_members[mod->name].insert(cell.first), sel_objects++, max_objects--;
- if (max_objects != 0 && lhs.selected_members[mod->name].count(cell.first) > 0 && limits.count(cell.first) == 0 && lhs.selected_members[mod->name].count(chunk.wire->name) == 0)
+ if (max_objects != 0 && selected_members.count(cell.first) > 0 && limits.count(cell.first) == 0 && selected_members.count(chunk.wire->name) == 0)
if (mode == 'x' || (mode == 'i' && is_input) || (mode == 'o' && is_output))
lhs.selected_members[mod->name].insert(chunk.wire->name), sel_objects++, max_objects--;
}
@@ -431,9 +435,10 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
return sel_objects;
}
-static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
+static void select_op_expand(RTLIL::Design *design, std::string arg, char mode, bool eval_only)
{
- int pos = mode == 'x' ? 2 : 3, levels = 1, rem_objects = -1;
+ int pos = (mode == 'x' ? 2 : 3) + (eval_only ? 1 : 0);
+ int levels = 1, rem_objects = -1;
std::vector<expand_rule_t> rules;
std::set<RTLIL::IdString> limits;
@@ -524,14 +529,14 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
#endif
while (levels-- > 0 && rem_objects != 0) {
- int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct);
+ int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct, eval_only);
if (num_objects == 0)
break;
rem_objects -= num_objects;
}
if (rem_objects == 0)
- log("Warning: reached configured limit at `%s'.\n", arg.c_str());
+ log_warning("reached configured limit at `%s'.\n", arg.c_str());
}
static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
@@ -631,17 +636,32 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%x.\n");
- select_op_expand(design, arg, 'x');
+ select_op_expand(design, arg, 'x', false);
} else
if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%ci.\n");
- select_op_expand(design, arg, 'i');
+ select_op_expand(design, arg, 'i', false);
} else
if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
if (work_stack.size() < 1)
log_cmd_error("Must have at least one element on the stack for operator %%co.\n");
- select_op_expand(design, arg, 'o');
+ select_op_expand(design, arg, 'o', false);
+ } else
+ if (arg == "%xe" || (arg.size() > 3 && arg.substr(0, 3) == "%x" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%xe.\n");
+ select_op_expand(design, arg, 'x', true);
+ } else
+ if (arg == "%cie" || (arg.size() > 4 && arg.substr(0, 4) == "%cie" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%cie.\n");
+ select_op_expand(design, arg, 'i', true);
+ } else
+ if (arg == "%coe" || (arg.size() > 4 && arg.substr(0, 4) == "%coe" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%coe.\n");
+ select_op_expand(design, arg, 'o', true);
} else
log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
if (work_stack.size() >= 1)
@@ -795,8 +815,11 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_filter_active_mod(design, work_stack.back());
}
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
// used in kernel/register.cc and maybe other locations, extern decl. in register.h
-void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
+void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
{
work_stack.clear();
for (; argidx < args_size; argidx++) {
@@ -812,20 +835,46 @@ void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t
select_op_union(design, work_stack.front(), work_stack.back());
work_stack.pop_back();
}
- if (work_stack.size() > 0)
- design->selection_stack.push_back(work_stack.back());
- else
+ if (work_stack.empty())
design->selection_stack.push_back(RTLIL::Selection(false));
+ else
+ design->selection_stack.push_back(work_stack.back());
}
+// extern decl. in register.h
+RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design)
+{
+ work_stack.clear();
+ for (auto &arg : args)
+ select_stmt(design, arg);
+ while (work_stack.size() > 1) {
+ select_op_union(design, work_stack.front(), work_stack.back());
+ work_stack.pop_back();
+ }
+ if (work_stack.empty())
+ return RTLIL::Selection(false);
+ return work_stack.back();
+}
+
+// extern decl. in register.h
+void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design)
+{
+ work_stack.swap(work);
+ select_stmt(design, op);
+ work_stack.swap(work);
+}
+
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct SelectPass : public Pass {
SelectPass() : Pass("select", "modify and view the list of selected objects") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" select [ -add | -del | -set <name> ] <selection>\n");
- log(" select [ -assert-none | -assert-any ] <selection>\n");
+ log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
+ log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
log("\n");
@@ -867,6 +916,9 @@ struct SelectPass : public Pass {
log(" -write <filename>\n");
log(" like -list but write the output to the specified file\n");
log("\n");
+ log(" -read <filename>\n");
+ log(" read the specified file (written by -write)\n");
+ log("\n");
log(" -count\n");
log(" count all objects in the current selection\n");
log("\n");
@@ -997,6 +1049,9 @@ struct SelectPass : public Pass {
log(" %%co[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
log(" simmilar to %%x, but only select input (%%ci) or output cones (%%co)\n");
log("\n");
+ log(" %%xe[...] %%cie[...] %%coe\n");
+ log(" like %%x, %%ci, and %%co but only consider combinatorial cells\n");
+ log("\n");
log(" %%a\n");
log(" expand top set by selecting all wires that are (at least in part)\n");
log(" aliases for selected wires.\n");
@@ -1026,9 +1081,8 @@ struct SelectPass : public Pass {
bool assert_none = false;
bool assert_any = false;
int assert_count = -1;
- std::string write_file;
- std::string set_name;
- std::string sel_str;
+ std::string write_file, read_file;
+ std::string set_name, sel_str;
work_stack.clear();
@@ -1072,6 +1126,10 @@ struct SelectPass : public Pass {
write_file = args[++argidx];
continue;
}
+ if (arg == "-read" && argidx+1 < args.size()) {
+ read_file = args[++argidx];
+ continue;
+ }
if (arg == "-count") {
count_mode = true;
continue;
@@ -1094,6 +1152,34 @@ struct SelectPass : public Pass {
sel_str += " " + arg;
}
+ if (!read_file.empty())
+ {
+ if (!sel_str.empty())
+ log_cmd_error("Option -read can not be combined with a selection expression.\n");
+
+ std::ifstream f(read_file);
+ if (f.fail())
+ log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno));
+
+ RTLIL::Selection sel(false);
+ string line;
+
+ while (std::getline(f, line)) {
+ size_t slash_pos = line.find('/');
+ if (slash_pos == string::npos) {
+ log_warning("Ignoring line without slash in 'select -read': %s\n", line.c_str());
+ continue;
+ }
+ IdString mod_name = RTLIL::escape_id(line.substr(0, slash_pos));
+ IdString obj_name = RTLIL::escape_id(line.substr(slash_pos+1));
+ sel.selected_members[mod_name].insert(obj_name);
+ }
+
+ select_filter_active_mod(design, sel);
+ sel.optimize(design);
+ work_stack.push_back(sel);
+ }
+
if (clear_mode && args.size() != 2)
log_cmd_error("Option -clear can not be combined with any other options.\n");
@@ -1135,7 +1221,7 @@ struct SelectPass : public Pass {
if (list_mode || count_mode || !write_file.empty())
{
- #define LOG_OBJECT(...) do { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } while (0)
+ #define LOG_OBJECT(...) { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; }
int total_count = 0;
FILE *f = NULL;
if (!write_file.empty()) {
@@ -1154,16 +1240,16 @@ struct SelectPass : public Pass {
if (sel->selected_module(mod_it.first)) {
for (auto &it : mod_it.second->wires_)
if (sel->selected_member(mod_it.first, it.first))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first))
for (auto &it : mod_it.second->memories)
if (sel->selected_member(mod_it.first, it.first))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first))
for (auto &it : mod_it.second->cells_)
if (sel->selected_member(mod_it.first, it.first))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first))
for (auto &it : mod_it.second->processes)
if (sel->selected_member(mod_it.first, it.first))
- LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
+ LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first))
}
}
if (count_mode)
@@ -1320,21 +1406,20 @@ struct CdPass : public Pass {
} CdPass;
template<typename T>
-static int log_matches(const char *title, std::string pattern, T list)
+static void log_matches(const char *title, Module *module, T list)
{
- std::vector<RTLIL::IdString> matches;
+ std::vector<IdString> matches;
for (auto &it : list)
- if (pattern.empty() || match_ids(it.first, pattern))
+ if (module->selected(it.second))
matches.push_back(it.first);
- if (matches.empty())
- return 0;
-
- log("\n%d %s:\n", int(matches.size()), title);
- for (auto &id : matches)
- log(" %s\n", RTLIL::id2cstr(id));
- return matches.size();
+ if (!matches.empty()) {
+ log("\n%d %s:\n", int(matches.size()), title);
+ std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str());
+ for (auto id : matches)
+ log(" %s\n", RTLIL::id2cstr(id));
+ }
}
struct LsPass : public Pass {
@@ -1343,44 +1428,42 @@ struct LsPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" ls [pattern]\n");
+ log(" ls [selection]\n");
log("\n");
- log("When no active module is selected, this prints a list of all modules.\n");
+ log("When no active module is selected, this prints a list of modules.\n");
log("\n");
log("When an active module is selected, this prints a list of objects in the module.\n");
log("\n");
- log("If a pattern is given, the objects matching the pattern are printed\n");
- log("\n");
- log("Note that this command does not use the selection mechanism and always operates\n");
- log("on the whole design or whole active module. Use 'select -list' to show a list\n");
- log("of currently selected objects.\n");
- log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::string pattern;
- int counter = 0;
-
- if (args.size() != 1 && args.size() != 2)
- log_cmd_error("Invalid number of arguments.\n");
- if (args.size() == 2)
- pattern = args.at(1);
+ size_t argidx = 1;
+ extra_args(args, argidx, design);
if (design->selected_active_module.empty())
{
- counter += log_matches("modules", pattern, design->modules_);
+ std::vector<IdString> matches;
+
+ for (auto mod : design->selected_modules())
+ matches.push_back(mod->name);
+
+ if (!matches.empty()) {
+ log("\n%d %s:\n", int(matches.size()), "modules");
+ std::sort(matches.begin(), matches.end(), RTLIL::sort_by_id_str());
+ for (auto id : matches)
+ log(" %s%s\n", log_id(id), design->selected_whole_module(design->module(id)) ? "" : "*");
+ }
}
else
- if (design->modules_.count(design->selected_active_module) > 0)
+ if (design->module(design->selected_active_module) != nullptr)
{
- RTLIL::Module *module = design->modules_.at(design->selected_active_module);
- counter += log_matches("wires", pattern, module->wires_);
- counter += log_matches("memories", pattern, module->memories);
- counter += log_matches("cells", pattern, module->cells_);
- counter += log_matches("processes", pattern, module->processes);
+ RTLIL::Module *module = design->module(design->selected_active_module);
+ log_matches("wires", module, module->wires_);
+ log_matches("memories", module, module->memories);
+ log_matches("cells", module, module->cells_);
+ log_matches("processes", module, module->processes);
}
-
- // log("\nfound %d item%s.\n", counter, counter == 1 ? "" : "s");
}
} LsPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 029c0ec7..9a6d8a03 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct setunset_t
{
RTLIL::IdString name;
@@ -47,7 +50,7 @@ struct setunset_t
}
};
-static void do_setunset(std::map<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
+static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
{
for (auto &item : list)
if (item.unset)
@@ -178,3 +181,4 @@ struct SetparamPass : public Pass {
}
} SetparamPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index c72e64b8..b9a29b7d 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,6 +23,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SetundefWorker
{
int next_bit_mode;
@@ -153,3 +156,4 @@ struct SetundefPass : public Pass {
}
} SetundefPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 2218eded..81321665 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -21,12 +21,18 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string.h>
-#include <dirent.h>
+
+#ifndef _WIN32
+# include <dirent.h>
+#endif
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
#endif
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
#undef CLUSTER_CELLS_AND_PORTBOXES
@@ -58,6 +64,10 @@ struct ShowWorker
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections;
const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections;
+ std::map<RTLIL::Const, int> colorattr_cache;
+ RTLIL::IdString colorattr;
+
+
static uint32_t xorshift32(uint32_t x) {
x ^= x << 13;
x ^= x >> 17;
@@ -69,7 +79,7 @@ struct ShowWorker
{
if (currentColor == 0)
return "color=\"black\"";
- return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor%8+1);
+ return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor%8+1, currentColor%8+1);
}
std::string nextColor(std::string presetColor)
@@ -122,7 +132,25 @@ struct ShowWorker
dot_escape_store.push_back(stringf(", color=\"%s\"", s.first.c_str()));
return dot_escape_store.back().c_str();
}
- return "";
+
+ RTLIL::Const colorattr_value;
+ RTLIL::Cell *cell = module->cell(member_name);
+ RTLIL::Wire *wire = module->wire(member_name);
+
+ if (cell && cell->attributes.count(colorattr))
+ colorattr_value = cell->attributes.at(colorattr);
+ else if (wire && wire->attributes.count(colorattr))
+ colorattr_value = wire->attributes.at(colorattr);
+ else
+ return "";
+
+ if (colorattr_cache.count(colorattr_value) == 0) {
+ int next_id = GetSize(colorattr_cache);
+ colorattr_cache[colorattr_value] = (next_id % 8) + 1;
+ }
+
+ dot_escape_store.push_back(stringf(", colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", colorattr_cache.at(colorattr_value), colorattr_cache.at(colorattr_value)));
+ return dot_escape_store.back().c_str();
}
const char *findLabel(std::string member_name)
@@ -175,7 +203,7 @@ struct ShowWorker
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
{
- if (SIZE(sig) == 0) {
+ if (GetSize(sig) == 0) {
fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
return stringf("v%d", single_idx_count++);
}
@@ -203,22 +231,24 @@ struct ShowWorker
std::string label_string;
int pos = sig.size()-1;
int idx = single_idx_count++;
- for (int i = int(sig.chunks().size())-1; i >= 0; i--) {
+ for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false);
log_assert(!net.empty());
+ for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {}
+ std::string repinfo = rep > 1 ? stringf("%dx ", rep) : "";
if (driver) {
- label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
+ label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
- net_conn_map[net].bits = c.width;
+ net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
} else {
- label_string += stringf("<s%d> %d:%d - %d:%d |", i, c.offset+c.width-1, c.offset, pos, pos-c.width+1);
+ label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1);
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
- net_conn_map[net].bits = c.width;
+ net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
}
- pos -= c.width;
+ pos -= rep * c.width;
}
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
@@ -452,8 +482,8 @@ struct ShowWorker
if (left_node[0] == 'x' && right_node[0] == 'x') {
currentColor = xorshift32(currentColor);
- fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.size()).c_str());
- } else {
+ fprintf(f, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node.c_str(), right_node.c_str(), nextColor(conn).c_str(), widthLabel(conn.first.size()).c_str());
+ } else {
net_conn_map[right_node].bits = conn.first.size();
net_conn_map[right_node].color = nextColor(conn, net_conn_map[right_node].color);
net_conn_map[left_node].bits = conn.first.size();
@@ -499,10 +529,10 @@ struct ShowWorker
ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed, bool genWidthLabels,
bool genSignedLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle,
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections,
- const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections) :
+ const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections, RTLIL::IdString colorattr) :
f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels),
genSignedLabels(genSignedLabels), stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
- notitle(notitle), color_selections(color_selections), label_selections(label_selections)
+ notitle(notitle), color_selections(color_selections), label_selections(label_selections), colorattr(colorattr)
{
ct.setup_internals();
ct.setup_internals_mem();
@@ -560,6 +590,10 @@ struct ShowPass : public Pass {
log(" inputs or outputs. This option can be used multiple times to specify\n");
log(" more than one library.\n");
log("\n");
+ log(" note: in most cases it is better to load the library before calling\n");
+ log(" show with 'read_verilog -lib <filename>'. it is also possible to\n");
+ log(" load liberty files with 'read_liberty -lib <filename>'.\n");
+ log("\n");
log(" -prefix <prefix>\n");
log(" generate <prefix>.* instead of ~/.yosys_show.*\n");
log("\n");
@@ -578,6 +612,10 @@ struct ShowPass : public Pass {
log(" for the random number generator. Change the seed value if the colored\n");
log(" graph still is ambigous. A seed of zero deactivates the coloring.\n");
log("\n");
+ log(" -colorattr <attribute_name>\n");
+ log(" Use the specified attribute to assign colors. A unique color is\n");
+ log(" assigned to each unique value of this attribute.\n");
+ log("\n");
log(" -width\n");
log(" annotate busses with a label indicating the width of the bus.\n");
log("\n");
@@ -607,6 +645,9 @@ struct ShowPass : public Pass {
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
log("\n");
+ log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
+ log("to 'show.dot' in the current directory and new viewer is launched.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -616,9 +657,14 @@ struct ShowPass : public Pass {
std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
std::vector<std::pair<std::string, RTLIL::Selection>> label_selections;
+#if defined(EMSCRIPTEN) || defined(_WIN32)
+ std::string format = "dot";
+ std::string prefix = "show";
+#else
std::string format;
- std::string viewer_exe;
std::string prefix = stringf("%s/.yosys_show", getenv("HOME") ? getenv("HOME") : ".");
+#endif
+ std::string viewer_exe;
std::vector<std::string> libfiles;
std::vector<RTLIL::Design*> libs;
uint32_t colorSeed = 0;
@@ -629,6 +675,7 @@ struct ShowPass : public Pass {
bool flag_enum = false;
bool flag_abbeviate = true;
bool flag_notitle = false;
+ RTLIL::IdString colorattr;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -670,6 +717,10 @@ struct ShowPass : public Pass {
colorSeed = ShowWorker::xorshift32(colorSeed);
continue;
}
+ if (arg == "-colorattr" && argidx+1 < args.size()) {
+ colorattr = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
if (arg == "-format" && argidx+1 < args.size()) {
format = args[++argidx];
continue;
@@ -745,7 +796,7 @@ struct ShowPass : public Pass {
delete lib;
log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file.c_str());
}
- ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections);
+ ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections, colorattr);
fclose(f);
for (auto lib : libs)
@@ -755,22 +806,22 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("dot -T%s -o '%s.new' '%s' && mv '%s.new' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
}
if (!viewer_exe.empty()) {
std::string cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
} else
if (format.empty()) {
- std::string cmd = stringf("fuser -s '%s' || xdot '%s' < '%s' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
log("Exec: %s\n", cmd.c_str());
- if (system(cmd.c_str()) != 0)
+ if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
}
@@ -795,3 +846,4 @@ struct ShowPass : public Pass {
}
} ShowPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index d03aaf3b..3e0158c5 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -24,6 +24,9 @@
#include "kernel/log.h"
#include <tuple>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SpliceWorker
{
RTLIL::Design *design;
@@ -179,11 +182,13 @@ struct SpliceWorker
if (design->selected(module, it.second))
selected_bits.add(sigmap(it.second));
- for (auto &it : module->cells_) {
- if (!sel_by_wire && !design->selected(module, it.second))
+ std::vector<Cell*> mod_cells = module->cells();
+
+ for (auto cell : mod_cells) {
+ if (!sel_by_wire && !design->selected(module, cell))
continue;
- for (auto &conn : it.second->connections_)
- if (ct.cell_input(it.second->type, conn.first)) {
+ for (auto &conn : cell->connections_)
+ if (ct.cell_input(cell->type, conn.first)) {
if (ports.size() > 0 && !ports.count(conn.first))
continue;
if (no_ports.size() > 0 && no_ports.count(conn.first))
@@ -202,24 +207,25 @@ struct SpliceWorker
}
std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
+ std::vector<Wire*> mod_wires = module->wires();
- for (auto &it : module->wires_)
- if (!no_outputs && it.second->port_output) {
- if (!design->selected(module, it.second))
+ for (auto mod : mod_wires)
+ if (!no_outputs && mod->port_output) {
+ if (!design->selected(module, mod))
continue;
- RTLIL::SigSpec sig = sigmap(it.second);
+ RTLIL::SigSpec sig = sigmap(mod);
if (driven_chunks.count(sig) > 0)
continue;
RTLIL::SigSpec new_sig = get_spliced_signal(sig);
if (new_sig != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, new_sig));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, new_sig));
} else
- if (!it.second->port_input) {
- RTLIL::SigSpec sig = sigmap(it.second);
+ if (!mod->port_input) {
+ RTLIL::SigSpec sig = sigmap(mod);
if (spliced_signals_cache.count(sig) && spliced_signals_cache.at(sig) != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, spliced_signals_cache.at(sig)));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, spliced_signals_cache.at(sig)));
else if (sliced_signals_cache.count(sig) && sliced_signals_cache.at(sig) != sig)
- rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, sliced_signals_cache.at(sig)));
+ rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(mod, sliced_signals_cache.at(sig)));
}
for (auto &it : rework_wires)
@@ -349,3 +355,4 @@ struct SplicePass : public Pass {
}
} SplicePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 344b03fc..d4e721a5 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SplitnetsWorker
{
std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap;
@@ -173,7 +176,7 @@ struct SplitnetsPass : public Pass {
module->rewrite_sigspecs(worker);
- std::set<RTLIL::Wire*> delete_wires;
+ pool<RTLIL::Wire*> delete_wires;
for (auto &it : worker.splitmap)
delete_wires.insert(it.first);
module->remove(delete_wires);
@@ -183,3 +186,4 @@ struct SplitnetsPass : public Pass {
}
} SplitnetsPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 19cdaa62..bd3a43ac 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -21,145 +21,145 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
-namespace
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct statdata_t
{
- struct statdata_t
+ #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
+ X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
+
+ #define X(_name) int _name;
+ STAT_INT_MEMBERS
+ #undef X
+
+ std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+
+ statdata_t operator+(const statdata_t &other) const
{
- #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
- X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
+ statdata_t sum = other;
+ #define X(_name) sum._name += _name;
+ STAT_INT_MEMBERS
+ #undef X
+ for (auto &it : num_cells_by_type)
+ sum.num_cells_by_type[it.first] += it.second;
+ return sum;
+ }
+
+ statdata_t operator*(int other) const
+ {
+ statdata_t sum = *this;
+ #define X(_name) sum._name *= other;
+ STAT_INT_MEMBERS
+ #undef X
+ for (auto &it : sum.num_cells_by_type)
+ it.second *= other;
+ return sum;
+ }
- #define X(_name) int _name;
+ statdata_t()
+ {
+ #define X(_name) _name = 0;
STAT_INT_MEMBERS
- #undef X
+ #undef X
+ }
- std::map<RTLIL::IdString, int> num_cells_by_type;
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
+ {
+ #define X(_name) _name = 0;
+ STAT_INT_MEMBERS
+ #undef X
- statdata_t operator+(const statdata_t &other) const
+ for (auto &it : mod->wires_)
{
- statdata_t sum = other;
- #define X(_name) sum._name += _name;
- STAT_INT_MEMBERS
- #undef X
- for (auto &it : num_cells_by_type)
- sum.num_cells_by_type[it.first] += it.second;
- return sum;
- }
+ if (!design->selected(mod, it.second))
+ continue;
- statdata_t operator*(int other) const
- {
- statdata_t sum = *this;
- #define X(_name) sum._name *= other;
- STAT_INT_MEMBERS
- #undef X
- for (auto &it : sum.num_cells_by_type)
- it.second *= other;
- return sum;
+ if (it.first[0] == '\\') {
+ num_pub_wires++;
+ num_pub_wire_bits += it.second->width;
+ }
+
+ num_wires++;
+ num_wire_bits += it.second->width;
}
- statdata_t()
- {
- #define X(_name) _name = 0;
- STAT_INT_MEMBERS
- #undef X
+ for (auto &it : mod->memories) {
+ if (!design->selected(mod, it.second))
+ continue;
+ num_memories++;
+ num_memory_bits += it.second->width * it.second->size;
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
+ for (auto &it : mod->cells_)
{
- #define X(_name) _name = 0;
- STAT_INT_MEMBERS
- #undef X
-
- for (auto &it : mod->wires_)
- {
- if (!design->selected(mod, it.second))
- continue;
-
- if (it.first[0] == '\\') {
- num_pub_wires++;
- num_pub_wire_bits += it.second->width;
- }
-
- num_wires++;
- num_wire_bits += it.second->width;
- }
+ if (!design->selected(mod, it.second))
+ continue;
- for (auto &it : mod->memories) {
- if (!design->selected(mod, it.second))
- continue;
- num_memories++;
- num_memory_bits += it.second->width * it.second->size;
- }
+ RTLIL::IdString cell_type = it.second->type;
- for (auto &it : mod->cells_)
+ if (width_mode)
{
- if (!design->selected(mod, it.second))
- continue;
-
- RTLIL::IdString cell_type = it.second->type;
-
- if (width_mode)
- {
- if (cell_type.in("$not", "$pos", "$neg",
- "$logic_not", "$logic_and", "$logic_or",
- "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
- "$lut", "$and", "$or", "$xor", "$xnor",
- "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
- "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
- "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
- int width_a = it.second->hasPort("\\A") ? SIZE(it.second->getPort("\\A")) : 0;
- int width_b = it.second->hasPort("\\B") ? SIZE(it.second->getPort("\\B")) : 0;
- int width_y = it.second->hasPort("\\Y") ? SIZE(it.second->getPort("\\Y")) : 0;
- cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
- }
- else if (cell_type.in("$mux", "$pmux"))
- cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Y")));
- else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
- cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Q")));
+ if (cell_type.in("$not", "$pos", "$neg",
+ "$logic_not", "$logic_and", "$logic_or",
+ "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
+ "$lut", "$and", "$or", "$xor", "$xnor",
+ "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
+ "$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
+ int width_a = it.second->hasPort("\\A") ? GetSize(it.second->getPort("\\A")) : 0;
+ int width_b = it.second->hasPort("\\B") ? GetSize(it.second->getPort("\\B")) : 0;
+ int width_y = it.second->hasPort("\\Y") ? GetSize(it.second->getPort("\\Y")) : 0;
+ cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
}
-
- num_cells++;
- num_cells_by_type[cell_type]++;
+ else if (cell_type.in("$mux", "$pmux"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Y")));
+ else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
+ cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Q")));
}
- for (auto &it : mod->processes) {
- if (!design->selected(mod, it.second))
- continue;
- num_processes++;
- }
+ num_cells++;
+ num_cells_by_type[cell_type]++;
}
- void log_data()
- {
- log(" Number of wires: %6d\n", num_wires);
- log(" Number of wire bits: %6d\n", num_wire_bits);
- log(" Number of public wires: %6d\n", num_pub_wires);
- log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
- log(" Number of memories: %6d\n", num_memories);
- log(" Number of memory bits: %6d\n", num_memory_bits);
- log(" Number of processes: %6d\n", num_processes);
- log(" Number of cells: %6d\n", num_cells);
- for (auto &it : num_cells_by_type)
- log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
+ for (auto &it : mod->processes) {
+ if (!design->selected(mod, it.second))
+ continue;
+ num_processes++;
}
- };
+ }
- statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
+ void log_data()
{
- statdata_t mod_data = mod_stat.at(mod);
- std::map<RTLIL::IdString, int> num_cells_by_type;
- num_cells_by_type.swap(mod_data.num_cells_by_type);
-
+ log(" Number of wires: %6d\n", num_wires);
+ log(" Number of wire bits: %6d\n", num_wire_bits);
+ log(" Number of public wires: %6d\n", num_pub_wires);
+ log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
+ log(" Number of memories: %6d\n", num_memories);
+ log(" Number of memory bits: %6d\n", num_memory_bits);
+ log(" Number of processes: %6d\n", num_processes);
+ log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
- if (mod_stat.count(it.first) > 0) {
- log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
- mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
- mod_data.num_cells -= it.second;
- } else {
- mod_data.num_cells_by_type[it.first] += it.second;
- }
-
- return mod_data;
+ log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
}
+};
+
+statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
+{
+ statdata_t mod_data = mod_stat.at(mod);
+ std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
+ num_cells_by_type.swap(mod_data.num_cells_by_type);
+
+ for (auto &it : num_cells_by_type)
+ if (mod_stat.count(it.first) > 0) {
+ log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
+ mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
+ mod_data.num_cells -= it.second;
+ } else {
+ mod_data.num_cells_by_type[it.first] += it.second;
+ }
+
+ return mod_data;
}
struct StatPass : public Pass {
@@ -208,20 +208,17 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules_)
+ for (auto mod : design->selected_modules())
{
- if (!design->selected_module(it.first))
- continue;
-
if (!top_mod && design->full_selection())
- if (it.second->get_bool_attribute("\\top"))
- top_mod = it.second;
+ if (mod->get_bool_attribute("\\top"))
+ top_mod = mod;
- statdata_t data(design, it.second, width_mode);
- mod_stat[it.first] = data;
+ statdata_t data(design, mod, width_mode);
+ mod_stat[mod->name] = data;
log("\n");
- log("=== %s%s ===\n", RTLIL::id2cstr(it.first), design->selected_whole_module(it.first) ? "" : " (partially selected)");
+ log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
data.log_data();
}
@@ -243,3 +240,4 @@ struct StatPass : public Pass {
}
} StatPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index 6f80ef72..a0484090 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -22,6 +22,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct TeePass : public Pass {
TeePass() : Pass("tee", "redirect command output to file") { }
virtual void help()
@@ -73,11 +76,11 @@ struct TeePass : public Pass {
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
- } catch (log_cmd_error_expection) {
+ } catch (...) {
for (auto cf : files_to_close)
fclose(cf);
log_files = backup_log_files;
- throw log_cmd_error_expection();
+ throw;
}
for (auto cf : files_to_close)
@@ -86,3 +89,4 @@ struct TeePass : public Pass {
}
} TeePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
index 09293a86..1a5f873f 100644
--- a/passes/cmds/trace.cc
+++ b/passes/cmds/trace.cc
@@ -20,38 +20,39 @@
#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TraceMonitor : public RTLIL::Monitor
{
- virtual void notify_module_add(RTLIL::Module *module) OVERRIDE
+ virtual void notify_module_add(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module add: %s\n", log_id(module));
}
- virtual void notify_module_del(RTLIL::Module *module) OVERRIDE
+ virtual void notify_module_del(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Module delete: %s\n", log_id(module));
}
- virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
+ virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
{
log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
}
- virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) OVERRIDE
+ virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) OVERRIDE
+ virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE
{
log("#TRACE# New connections in module %s:\n", log_id(module));
for (auto &sigsig : sigsig_vec)
log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second));
}
- virtual void notify_blackout(RTLIL::Module *module) OVERRIDE
+ virtual void notify_blackout(RTLIL::Module *module) YS_OVERRIDE
{
log("#TRACE# Blackout in module %s:\n", log_id(module));
}
@@ -84,9 +85,9 @@ struct TracePass : public Pass {
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
- } catch (log_cmd_error_expection) {
+ } catch (...) {
design->monitors.erase(&monitor);
- throw log_cmd_error_expection();
+ throw;
}
design->monitors.erase(&monitor);
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
index 813e215b..25ec4acc 100644
--- a/passes/cmds/write_file.cc
+++ b/passes/cmds/write_file.cc
@@ -20,6 +20,9 @@
#include "kernel/yosys.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct WriteFileFrontend : public Frontend {
WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
virtual void help()
@@ -65,12 +68,13 @@ struct WriteFileFrontend : public Frontend {
FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
char buffer[64 * 1024];
- size_t bytes;
+ int bytes;
- while (0 < (bytes = f->readsome(buffer, sizeof(buffer))))
+ while (0 < (bytes = readsome(*f, buffer, sizeof(buffer))))
fwrite(buffer, bytes, 1, of);
fclose(of);
}
} WriteFileFrontend;
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc
new file mode 100644
index 00000000..548eaca3
--- /dev/null
+++ b/passes/equiv/Makefile.inc
@@ -0,0 +1,9 @@
+
+OBJS += passes/equiv/equiv_make.o
+OBJS += passes/equiv/equiv_miter.o
+OBJS += passes/equiv/equiv_simple.o
+OBJS += passes/equiv/equiv_status.o
+OBJS += passes/equiv/equiv_add.o
+OBJS += passes/equiv/equiv_remove.o
+OBJS += passes/equiv/equiv_induct.o
+
diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc
new file mode 100644
index 00000000..a6e2f01b
--- /dev/null
+++ b/passes/equiv/equiv_add.cc
@@ -0,0 +1,89 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivAddPass : public Pass {
+ EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_add gold_sig gate_sig\n");
+ log("\n");
+ log("This command adds an $equiv cell for the specified signals.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ if (GetSize(args) != 3)
+ cmd_error(args, GetSize(args)-1, "Invalid number of arguments.");
+
+ if (design->selected_active_module.empty())
+ log_cmd_error("This command must be executed in module context!\n");
+
+ Module *module = design->module(design->selected_active_module);
+ log_assert(module != nullptr);
+
+ SigSpec gold_signal, gate_signal;
+
+ if (!SigSpec::parse(gate_signal, module, args[2]))
+ log_cmd_error("Error in gate signal: %s\n", args[2].c_str());
+
+ if (!SigSpec::parse_rhs(gate_signal, gold_signal, module, args[1]))
+ log_cmd_error("Error in gold signal: %s\n", args[1].c_str());
+
+ log_assert(GetSize(gold_signal) == GetSize(gate_signal));
+ SigSpec equiv_signal = module->addWire(NEW_ID, GetSize(gold_signal));
+
+ SigMap sigmap(module);
+ sigmap.apply(gold_signal);
+ sigmap.apply(gate_signal);
+
+ dict<SigBit, SigBit> to_equiv_bits;
+ pool<Cell*> added_equiv_cells;
+
+ for (int i = 0; i < GetSize(gold_signal); i++) {
+ Cell *equiv_cell = module->addEquiv(NEW_ID, gold_signal[i], gate_signal[i], equiv_signal[i]);
+ equiv_cell->set_bool_attribute("\\keep");
+ to_equiv_bits[gold_signal[i]] = equiv_signal[i];
+ to_equiv_bits[gate_signal[i]] = equiv_signal[i];
+ added_equiv_cells.insert(equiv_cell);
+ }
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ if (!added_equiv_cells.count(cell) && cell->input(conn.first)) {
+ SigSpec new_sig;
+ for (auto bit : conn.second)
+ if (to_equiv_bits.count(sigmap(bit)))
+ new_sig.append(to_equiv_bits.at(sigmap(bit)));
+ else
+ new_sig.append(bit);
+ if (conn.second != new_sig)
+ cell->setPort(conn.first, new_sig);
+ }
+ }
+} EquivAddPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
new file mode 100644
index 00000000..a56730d4
--- /dev/null
+++ b/passes/equiv/equiv_induct.cc
@@ -0,0 +1,241 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivInductWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ vector<Cell*> cells;
+ pool<Cell*> workset;
+
+ ezSatPtr ez;
+ SatGen satgen;
+
+ int max_seq;
+ int success_counter;
+
+ dict<int, int> ez_step_is_consistent;
+ pool<Cell*> cell_warn_cache;
+ SigPool undriven_signals;
+
+ EquivInductWorker(Module *module, const pool<Cell*> &unproven_equiv_cells, bool model_undef, int max_seq) : module(module), sigmap(module),
+ cells(module->selected_cells()), workset(unproven_equiv_cells),
+ satgen(ez.get(), &sigmap), max_seq(max_seq), success_counter(0)
+ {
+ satgen.model_undef = model_undef;
+ }
+
+ void create_timestep(int step)
+ {
+ vector<int> ez_equal_terms;
+
+ for (auto cell : cells) {
+ if (!satgen.importCell(cell, step) && !cell_warn_cache.count(cell)) {
+ log_warning("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
+ cell_warn_cache.insert(cell);
+ }
+ if (cell->type == "$equiv") {
+ SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+ if (bit_a != bit_b) {
+ int ez_a = satgen.importSigBit(bit_a, step);
+ int ez_b = satgen.importSigBit(bit_b, step);
+ int cond = ez->IFF(ez_a, ez_b);
+ if (satgen.model_undef)
+ cond = ez->OR(cond, satgen.importUndefSigBit(bit_a, step));
+ ez_equal_terms.push_back(cond);
+ }
+ }
+ }
+
+ if (satgen.model_undef) {
+ for (auto bit : undriven_signals.export_all())
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step)));
+ }
+
+ log_assert(!ez_step_is_consistent.count(step));
+ ez_step_is_consistent[step] = ez->expression(ez->OpAnd, ez_equal_terms);
+ }
+
+ void run()
+ {
+ log("Found %d unproven $equiv cells in module %s:\n", GetSize(workset), log_id(module));
+
+ if (satgen.model_undef) {
+ for (auto cell : cells)
+ if (yosys_celltypes.cell_known(cell->type))
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_input(cell->type, conn.first))
+ undriven_signals.add(sigmap(conn.second));
+ for (auto cell : cells)
+ if (yosys_celltypes.cell_known(cell->type))
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_output(cell->type, conn.first))
+ undriven_signals.del(sigmap(conn.second));
+ }
+
+ create_timestep(1);
+
+ if (satgen.model_undef) {
+ for (auto bit : satgen.initial_state.export_all())
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, 1)));
+ log(" Undef modelling: force def on %d initial reg values and %d inputs.\n",
+ GetSize(satgen.initial_state), GetSize(undriven_signals));
+ }
+
+ for (int step = 1; step <= max_seq; step++)
+ {
+ ez->assume(ez_step_is_consistent[step]);
+
+ log(" Proving existence of base case for step %d. (%d clauses over %d variables)\n", step, ez->numCnfClauses(), ez->numCnfVariables());
+ if (!ez->solve()) {
+ log(" Proof for base case failed. Circuit inherently diverges!\n");
+ return;
+ }
+
+ create_timestep(step+1);
+ int new_step_not_consistent = ez->NOT(ez_step_is_consistent[step+1]);
+ ez->bind(new_step_not_consistent);
+
+ log(" Proving induction step %d. (%d clauses over %d variables)\n", step, ez->numCnfClauses(), ez->numCnfVariables());
+ if (!ez->solve(new_step_not_consistent)) {
+ log(" Proof for induction step holds. Entire workset of %d cells proven!\n", GetSize(workset));
+ for (auto cell : workset)
+ cell->setPort("\\B", cell->getPort("\\A"));
+ success_counter += GetSize(workset);
+ return;
+ }
+
+ log(" Proof for induction step failed. %s\n", step != max_seq ? "Extending to next time step." : "Trying to prove individual $equiv from workset.");
+ }
+
+ workset.sort();
+
+ for (auto cell : workset)
+ {
+ SigBit bit_a = sigmap(cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(cell->getPort("\\B")).to_single_sigbit();
+
+ log(" Trying to prove $equiv for %s:", log_signal(sigmap(cell->getPort("\\Y"))));
+
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importSigBit(bit_b, max_seq+1);
+ int cond = ez->XOR(ez_a, ez_b);
+
+ if (satgen.model_undef)
+ cond = ez->AND(cond, ez->NOT(satgen.importUndefSigBit(bit_a, max_seq+1)));
+
+ if (!ez->solve(cond)) {
+ log(" success!\n");
+ cell->setPort("\\B", cell->getPort("\\A"));
+ success_counter++;
+ } else {
+ log(" failed.\n");
+ }
+ }
+ }
+};
+
+struct EquivInductPass : public Pass {
+ EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_induct [options] [selection]\n");
+ log("\n");
+ log("Uses a version of temporal induction to prove $equiv cells.\n");
+ log("\n");
+ log("Only selected $equiv cells are proven and only selected cells are used to\n");
+ log("perform the proof.\n");
+ log("\n");
+ log(" -undef\n");
+ log(" enable modelling of undef states\n");
+ log("\n");
+ log(" -seq <N>\n");
+ log(" the max. number of time steps to be considered (default = 4)\n");
+ log("\n");
+ log("This command is very effective in proving complex sequential circuits, when\n");
+ log("the internal state of the circuit quickly propagates to $equiv cells.\n");
+ log("\n");
+ log("However, this command uses a weak definition of 'equivalence': This command\n");
+ log("proves that the two circuits will not diverge after they produce equal\n");
+ log("outputs (observable points via $equiv) for at least <N> cycles (the <N>\n");
+ log("specified via -seq).\n");
+ log("\n");
+ log("Combined with simulation this is very powerful because simulation can give\n");
+ log("you confidence that the circuits start out synced for at least <N> cycles\n");
+ log("after reset.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ int success_counter = 0;
+ bool model_undef = false;
+ int max_seq = 4;
+
+ log_header("Executing EQUIV_INDUCT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-undef") {
+ model_undef = true;
+ continue;
+ }
+ if (args[argidx] == "-seq" && argidx+1 < args.size()) {
+ max_seq = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ pool<Cell*> unproven_equiv_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ if (cell->getPort("\\A") != cell->getPort("\\B"))
+ unproven_equiv_cells.insert(cell);
+ }
+
+ if (unproven_equiv_cells.empty()) {
+ log("No selected unproven $equiv cells found in %s.\n", log_id(module));
+ continue;
+ }
+
+ EquivInductWorker worker(module, unproven_equiv_cells, model_undef, max_seq);
+ worker.run();
+ success_counter += worker.success_counter;
+ }
+
+ log("Proved %d previously unproven $equiv cells.\n", success_counter);
+ }
+} EquivInductPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
new file mode 100644
index 00000000..5635e7a7
--- /dev/null
+++ b/passes/equiv/equiv_make.cc
@@ -0,0 +1,474 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivMakeWorker
+{
+ Module *gold_mod, *gate_mod, *equiv_mod;
+ pool<IdString> wire_names, cell_names;
+ CellTypes ct;
+
+ bool inames;
+ vector<string> blacklists;
+ vector<string> encfiles;
+
+ pool<IdString> blacklist_names;
+ dict<IdString, dict<Const, Const>> encdata;
+
+ pool<SigBit> undriven_bits;
+ SigMap assign_map;
+
+ void read_blacklists()
+ {
+ for (auto fn : blacklists)
+ {
+ std::ifstream f(fn);
+ if (f.fail())
+ log_cmd_error("Can't open blacklist file '%s'!\n", fn.c_str());
+
+ string line, token;
+ while (std::getline(f, line)) {
+ while (1) {
+ token = next_token(line);
+ if (token.empty())
+ break;
+ blacklist_names.insert(RTLIL::escape_id(token));
+ }
+ }
+ }
+ }
+
+ void read_encfiles()
+ {
+ for (auto fn : encfiles)
+ {
+ std::ifstream f(fn);
+ if (f.fail())
+ log_cmd_error("Can't open encfile '%s'!\n", fn.c_str());
+
+ dict<Const, Const> *ed = nullptr;
+ string line, token;
+ while (std::getline(f, line))
+ {
+ token = next_token(line);
+ if (token.empty() || token[0] == '#')
+ continue;
+
+ if (token == ".fsm") {
+ IdString modname = RTLIL::escape_id(next_token(line));
+ IdString signame = RTLIL::escape_id(next_token(line));
+ if (encdata.count(signame))
+ log_cmd_error("Re-definition of signal '%s' in encfile '%s'!\n", signame.c_str(), fn.c_str());
+ encdata[signame] = dict<Const, Const>();
+ ed = &encdata[signame];
+ continue;
+ }
+
+ if (token == ".map") {
+ Const gold_bits = Const::from_string(next_token(line));
+ Const gate_bits = Const::from_string(next_token(line));
+ (*ed)[gold_bits] = gate_bits;
+ continue;
+ }
+
+ log_cmd_error("Syntax error in encfile '%s'!\n", fn.c_str());
+ }
+ }
+ }
+
+ void copy_to_equiv()
+ {
+ Module *gold_clone = gold_mod->clone();
+ Module *gate_clone = gate_mod->clone();
+
+ for (auto it : gold_clone->wires().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ wire_names.insert(it->name);
+ gold_clone->rename(it, it->name.str() + "_gold");
+ }
+
+ for (auto it : gold_clone->cells().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ cell_names.insert(it->name);
+ gold_clone->rename(it, it->name.str() + "_gold");
+ }
+
+ for (auto it : gate_clone->wires().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ wire_names.insert(it->name);
+ gate_clone->rename(it, it->name.str() + "_gate");
+ }
+
+ for (auto it : gate_clone->cells().to_vector()) {
+ if ((it->name[0] == '\\' || inames) && blacklist_names.count(it->name) == 0)
+ cell_names.insert(it->name);
+ gate_clone->rename(it, it->name.str() + "_gate");
+ }
+
+ gold_clone->cloneInto(equiv_mod);
+ gate_clone->cloneInto(equiv_mod);
+ delete gold_clone;
+ delete gate_clone;
+ }
+
+ void find_same_wires()
+ {
+ SigMap assign_map(equiv_mod);
+ SigMap rd_signal_map;
+
+ // list of cells without added $equiv cells
+ auto cells_list = equiv_mod->cells().to_vector();
+
+ for (auto id : wire_names)
+ {
+ IdString gold_id = id.str() + "_gold";
+ IdString gate_id = id.str() + "_gate";
+
+ Wire *gold_wire = equiv_mod->wire(gold_id);
+ Wire *gate_wire = equiv_mod->wire(gate_id);
+
+ if (encdata.count(id))
+ {
+ log("Creating encoder/decoder for signal %s.\n", log_id(id));
+
+ Wire *dec_wire = equiv_mod->addWire(id.str() + "_decoded", gold_wire->width);
+ Wire *enc_wire = equiv_mod->addWire(id.str() + "_encoded", gate_wire->width);
+
+ SigSpec dec_a, dec_b, dec_s;
+ SigSpec enc_a, enc_b, enc_s;
+
+ dec_a = SigSpec(State::Sx, dec_wire->width);
+ enc_a = SigSpec(State::Sx, enc_wire->width);
+
+ for (auto &it : encdata.at(id))
+ {
+ SigSpec dec_sig = gate_wire, dec_pat = it.second;
+ SigSpec enc_sig = dec_wire, enc_pat = it.first;
+
+ if (GetSize(dec_sig) != GetSize(dec_pat))
+ log_error("Invalid pattern %s for signal %s of size %d!\n",
+ log_signal(dec_pat), log_signal(dec_sig), GetSize(dec_sig));
+
+ if (GetSize(enc_sig) != GetSize(enc_pat))
+ log_error("Invalid pattern %s for signal %s of size %d!\n",
+ log_signal(enc_pat), log_signal(enc_sig), GetSize(enc_sig));
+
+ SigSpec reduced_dec_sig, reduced_dec_pat;
+ for (int i = 0; i < GetSize(dec_sig); i++)
+ if (dec_pat[i] == State::S0 || dec_pat[i] == State::S1) {
+ reduced_dec_sig.append(dec_sig[i]);
+ reduced_dec_pat.append(dec_pat[i]);
+ }
+
+ SigSpec reduced_enc_sig, reduced_enc_pat;
+ for (int i = 0; i < GetSize(enc_sig); i++)
+ if (enc_pat[i] == State::S0 || enc_pat[i] == State::S1) {
+ reduced_enc_sig.append(enc_sig[i]);
+ reduced_enc_pat.append(enc_pat[i]);
+ }
+
+ SigSpec dec_result = it.first;
+ for (auto &bit : dec_result)
+ if (bit != State::S1) bit = State::S0;
+
+ SigSpec enc_result = it.second;
+ for (auto &bit : enc_result)
+ if (bit != State::S1) bit = State::S0;
+
+ SigSpec dec_eq = equiv_mod->addWire(NEW_ID);
+ SigSpec enc_eq = equiv_mod->addWire(NEW_ID);
+
+ equiv_mod->addEq(NEW_ID, reduced_dec_sig, reduced_dec_pat, dec_eq);
+ cells_list.push_back(equiv_mod->addEq(NEW_ID, reduced_enc_sig, reduced_enc_pat, enc_eq));
+
+ dec_s.append(dec_eq);
+ enc_s.append(enc_eq);
+ dec_b.append(dec_result);
+ enc_b.append(enc_result);
+ }
+
+ equiv_mod->addPmux(NEW_ID, dec_a, dec_b, dec_s, dec_wire);
+ equiv_mod->addPmux(NEW_ID, enc_a, enc_b, enc_s, enc_wire);
+
+ rd_signal_map.add(assign_map(gate_wire), enc_wire);
+ gate_wire = dec_wire;
+ }
+
+ if (gold_wire == nullptr || gate_wire == nullptr || gold_wire->width != gate_wire->width) {
+ if (gold_wire && gold_wire->port_id)
+ log_error("Can't match gold port `%s' to a gate port.\n", log_id(gold_wire));
+ if (gate_wire && gate_wire->port_id)
+ log_error("Can't match gate port `%s' to a gold port.\n", log_id(gate_wire));
+ continue;
+ }
+
+ log("Presumably equivalent wires: %s (%s), %s (%s) -> %s\n",
+ log_id(gold_wire), log_signal(assign_map(gold_wire)),
+ log_id(gate_wire), log_signal(assign_map(gate_wire)), log_id(id));
+
+ if (gold_wire->port_output || gate_wire->port_output)
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ wire->port_output = true;
+ gold_wire->port_input = false;
+ gate_wire->port_input = false;
+ gold_wire->port_output = false;
+ gate_wire->port_output = false;
+
+ for (int i = 0; i < wire->width; i++)
+ equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
+
+ rd_signal_map.add(assign_map(gold_wire), wire);
+ rd_signal_map.add(assign_map(gate_wire), wire);
+ }
+ else
+ if (gold_wire->port_input || gate_wire->port_input)
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ wire->port_input = true;
+ gold_wire->port_input = false;
+ gate_wire->port_input = false;
+ equiv_mod->connect(gold_wire, wire);
+ equiv_mod->connect(gate_wire, wire);
+ }
+ else
+ {
+ Wire *wire = equiv_mod->addWire(id, gold_wire->width);
+ SigSpec rdmap_gold, rdmap_gate, rdmap_equiv;
+
+ for (int i = 0; i < wire->width; i++) {
+ if (undriven_bits.count(assign_map(SigBit(gold_wire, i)))) {
+ log(" Skipping signal bit %d: undriven on gold side.\n", i);
+ continue;
+ }
+ if (undriven_bits.count(assign_map(SigBit(gate_wire, i)))) {
+ log(" Skipping signal bit %d: undriven on gate side.\n", i);
+ continue;
+ }
+ equiv_mod->addEquiv(NEW_ID, SigSpec(gold_wire, i), SigSpec(gate_wire, i), SigSpec(wire, i));
+ rdmap_gold.append(SigBit(gold_wire, i));
+ rdmap_gate.append(SigBit(gate_wire, i));
+ rdmap_equiv.append(SigBit(wire, i));
+ }
+
+ rd_signal_map.add(rdmap_gold, rdmap_equiv);
+ rd_signal_map.add(rdmap_gate, rdmap_equiv);
+ }
+ }
+
+ for (auto c : cells_list)
+ for (auto &conn : c->connections())
+ if (ct.cell_input(c->type, conn.first)) {
+ SigSpec old_sig = assign_map(conn.second);
+ SigSpec new_sig = rd_signal_map(old_sig);
+ if (old_sig != new_sig) {
+ log("Changing input %s of cell %s (%s): %s -> %s\n",
+ log_id(conn.first), log_id(c), log_id(c->type),
+ log_signal(old_sig), log_signal(new_sig));
+ c->setPort(conn.first, new_sig);
+ }
+ }
+
+ equiv_mod->fixup_ports();
+ }
+
+ void find_same_cells()
+ {
+ SigMap assign_map(equiv_mod);
+
+ for (auto id : cell_names)
+ {
+ IdString gold_id = id.str() + "_gold";
+ IdString gate_id = id.str() + "_gate";
+
+ Cell *gold_cell = equiv_mod->cell(gold_id);
+ Cell *gate_cell = equiv_mod->cell(gate_id);
+
+ if (gold_cell == nullptr || gate_cell == nullptr || gold_cell->type != gate_cell->type || !ct.cell_known(gold_cell->type) ||
+ gold_cell->parameters != gate_cell->parameters || GetSize(gold_cell->connections()) != GetSize(gate_cell->connections()))
+ try_next_cell_name:
+ continue;
+
+ for (auto gold_conn : gold_cell->connections())
+ if (!gate_cell->connections().count(gold_conn.first))
+ goto try_next_cell_name;
+
+ log("Presumably equivalent cells: %s %s (%s) -> %s\n",
+ log_id(gold_cell), log_id(gate_cell), log_id(gold_cell->type), log_id(id));
+
+ for (auto gold_conn : gold_cell->connections())
+ {
+ SigSpec gold_sig = assign_map(gold_conn.second);
+ SigSpec gate_sig = assign_map(gate_cell->getPort(gold_conn.first));
+
+ if (ct.cell_output(gold_cell->type, gold_conn.first)) {
+ equiv_mod->connect(gate_sig, gold_sig);
+ continue;
+ }
+
+ for (int i = 0; i < GetSize(gold_sig); i++)
+ if (gold_sig[i] != gate_sig[i]) {
+ Wire *w = equiv_mod->addWire(NEW_ID);
+ equiv_mod->addEquiv(NEW_ID, gold_sig[i], gate_sig[i], w);
+ gold_sig[i] = w;
+ }
+
+ gold_cell->setPort(gold_conn.first, gold_sig);
+ }
+
+ equiv_mod->remove(gate_cell);
+ equiv_mod->rename(gold_cell, id);
+ }
+ }
+
+ void find_undriven_nets(bool mark)
+ {
+ undriven_bits.clear();
+ assign_map.set(equiv_mod);
+
+ for (auto wire : equiv_mod->wires()) {
+ for (auto bit : assign_map(wire))
+ if (bit.wire)
+ undriven_bits.insert(bit);
+ }
+
+ for (auto wire : equiv_mod->wires()) {
+ if (wire->port_input)
+ for (auto bit : assign_map(wire))
+ undriven_bits.erase(bit);
+ }
+
+ for (auto cell : equiv_mod->cells()) {
+ for (auto &conn : cell->connections())
+ if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
+ for (auto bit : assign_map(conn.second))
+ undriven_bits.erase(bit);
+ }
+
+ if (mark) {
+ SigSpec undriven_sig(undriven_bits);
+ undriven_sig.sort_and_unify();
+
+ for (auto chunk : undriven_sig.chunks()) {
+ log("Setting undriven nets to undef: %s\n", log_signal(chunk));
+ equiv_mod->connect(chunk, SigSpec(State::Sx, chunk.width));
+ }
+ }
+ }
+
+ void run()
+ {
+ copy_to_equiv();
+ find_undriven_nets(false);
+ find_same_wires();
+ find_same_cells();
+ find_undriven_nets(true);
+ }
+};
+
+struct EquivMakePass : public Pass {
+ EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_make [options] gold_module gate_module equiv_module\n");
+ log("\n");
+ log("This creates a module annotated with $equiv cells from two presumably\n");
+ log("equivalent modules. Use commands such as 'equiv_simple' and 'equiv_status'\n");
+ log("to work with the created equivalent checking module.\n");
+ log("\n");
+ log(" -inames\n");
+ log(" Also match cells and wires with $... names.\n");
+ log("\n");
+ log(" -blacklist <file>\n");
+ log(" Do not match cells or signals that match the names in the file.\n");
+ log("\n");
+ log(" -encfile <file>\n");
+ log(" Match FSM encodings using the desiption from the file.\n");
+ log(" See 'help fsm_recode' for details.\n");
+ log("\n");
+ log("Note: The circuit created by this command is not a miter (with something like\n");
+ log("a trigger output), but instead uses $equiv cells to encode the equivalence\n");
+ log("checking problem. Use 'miter -equiv' if you want to create a miter circuit.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ EquivMakeWorker worker;
+ worker.ct.setup(design);
+ worker.inames = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-inames") {
+ worker.inames = true;
+ continue;
+ }
+ if (args[argidx] == "-blacklist" && argidx+1 < args.size()) {
+ worker.blacklists.push_back(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-encfile" && argidx+1 < args.size()) {
+ worker.encfiles.push_back(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+
+ if (argidx+3 != args.size())
+ log_cmd_error("Invalid number of arguments.\n");
+
+ worker.gold_mod = design->module(RTLIL::escape_id(args[argidx]));
+ worker.gate_mod = design->module(RTLIL::escape_id(args[argidx+1]));
+ worker.equiv_mod = design->module(RTLIL::escape_id(args[argidx+2]));
+
+ if (worker.gold_mod == nullptr)
+ log_cmd_error("Can't find gold module %s.\n", args[argidx].c_str());
+
+ if (worker.gate_mod == nullptr)
+ log_cmd_error("Can't find gate module %s.\n", args[argidx+1].c_str());
+
+ if (worker.equiv_mod != nullptr)
+ log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str());
+
+ if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes())
+ log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+
+ if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes())
+ log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n");
+
+ worker.read_blacklists();
+ worker.read_encfiles();
+
+ log_header("Executing EQUIV_MAKE pass (creating equiv checking module).\n");
+
+ worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2]));
+ worker.run();
+ }
+} EquivMakePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
new file mode 100644
index 00000000..23b34818
--- /dev/null
+++ b/passes/equiv/equiv_miter.cc
@@ -0,0 +1,343 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivMiterWorker
+{
+ CellTypes ct;
+ SigMap sigmap;
+
+ bool mode_trigger;
+ bool mode_cmp;
+ bool mode_assert;
+ bool mode_undef;
+
+ IdString miter_name;
+ Module *miter_module;
+ Module *source_module;
+
+ dict<SigBit, Cell*> bit_to_driver;
+ pool<Cell*> seed_cells, miter_cells;
+ pool<Wire*> miter_wires;
+
+ void follow_cone(pool<Cell*> &cone, pool<Cell*> &leaves, Cell *c, bool gold_mode)
+ {
+ if (cone.count(c))
+ return;
+
+ if (c->type == "$equiv" && !seed_cells.count(c)) {
+ leaves.insert(c);
+ return;
+ }
+
+ cone.insert(c);
+
+ for (auto &conn : c->connections()) {
+ if (!ct.cell_input(c->type, conn.first))
+ continue;
+ if (c->type == "$equiv" && (conn.first == "\\A") != gold_mode)
+ continue;
+ for (auto bit : sigmap(conn.second))
+ if (bit_to_driver.count(bit))
+ follow_cone(cone, leaves, bit_to_driver.at(bit), gold_mode);
+ }
+ }
+
+ void find_miter_cells_wires()
+ {
+ sigmap.set(source_module);
+
+ // initialize bit_to_driver
+
+ for (auto c : source_module->cells())
+ for (auto &conn : c->connections())
+ if (ct.cell_output(c->type, conn.first))
+ for (auto bit : sigmap(conn.second))
+ if (bit.wire)
+ bit_to_driver[bit] = c;
+
+ // find seed cells
+
+ for (auto c : source_module->selected_cells())
+ if (c->type == "$equiv") {
+ log("Seed $equiv cell: %s\n", log_id(c));
+ seed_cells.insert(c);
+ }
+
+ // follow cone from seed cells to next $equiv
+
+ while (1)
+ {
+ pool<Cell*> gold_cone, gold_leaves;
+ pool<Cell*> gate_cone, gate_leaves;
+
+ for (auto c : seed_cells) {
+ follow_cone(gold_cone, gold_leaves, c, true);
+ follow_cone(gate_cone, gate_leaves, c, false);
+ }
+
+ log("Gold cone: %d cells (%d leaves).\n", GetSize(gold_cone), GetSize(gold_leaves));
+ log("Gate cone: %d cells (%d leaves).\n", GetSize(gate_cone), GetSize(gate_leaves));
+
+ // done if all leaves are shared leaves
+
+ if (gold_leaves == gate_leaves) {
+ miter_cells = gold_cone;
+ miter_cells.insert(gate_cone.begin(), gate_cone.end());
+ log("Selected %d miter cells.\n", GetSize(miter_cells));
+ break;
+ }
+
+ // remove shared leaves
+
+ for (auto it = gold_leaves.begin(); it != gold_leaves.end(); ) {
+ auto it2 = gate_leaves.find(*it);
+ if (it2 != gate_leaves.end()) {
+ it = gold_leaves.erase(it);
+ gate_leaves.erase(it2);
+ } else
+ ++it;
+ }
+
+ // add remaining leaves to seeds and re-run
+
+ log("Adding %d gold and %d gate seed cells.\n", GetSize(gold_leaves), GetSize(gate_leaves));
+ seed_cells.insert(gold_leaves.begin(), gold_leaves.end());
+ seed_cells.insert(gate_leaves.begin(), gate_leaves.end());
+ }
+
+ for (auto c : miter_cells)
+ for (auto &conn : c->connections())
+ for (auto bit : sigmap(conn.second))
+ if (bit.wire)
+ miter_wires.insert(bit.wire);
+ log("Selected %d miter wires.\n", GetSize(miter_wires));
+ }
+
+ void copy_to_miter()
+ {
+ // copy wires and cells
+
+ for (auto w : miter_wires)
+ miter_module->addWire(w->name, w->width);
+ for (auto c : miter_cells) {
+ miter_module->addCell(c->name, c);
+ auto mc = miter_module->cell(c->name);
+ for (auto &conn : mc->connections())
+ mc->setPort(conn.first, sigmap(conn.second));
+ }
+
+ // fixup wire references in cells
+
+ sigmap.clear();
+
+ struct RewriteSigSpecWorker {
+ RTLIL::Module * mod;
+ void operator()(SigSpec &sig) {
+ vector<RTLIL::SigChunk> chunks = sig.chunks();
+ for (auto &c : chunks)
+ if (c.wire != NULL)
+ c.wire = mod->wires_.at(c.wire->name);
+ sig = chunks;
+ }
+ };
+
+ RewriteSigSpecWorker rewriteSigSpecWorker;
+ rewriteSigSpecWorker.mod = miter_module;
+ miter_module->rewrite_sigspecs(rewriteSigSpecWorker);
+
+ // find undriven or unused wires
+
+ pool<SigBit> driven_bits, used_bits;
+
+ for (auto c : miter_module->cells())
+ for (auto &conn : c->connections()) {
+ if (ct.cell_input(c->type, conn.first))
+ for (auto bit : conn.second)
+ if (bit.wire)
+ used_bits.insert(bit);
+ if (ct.cell_output(c->type, conn.first))
+ for (auto bit : conn.second)
+ if (bit.wire)
+ driven_bits.insert(bit);
+ }
+
+ // create ports
+
+ for (auto w : miter_module->wires()) {
+ for (auto bit : SigSpec(w)) {
+ if (driven_bits.count(bit) && !used_bits.count(bit))
+ w->port_output = true;
+ if (!driven_bits.count(bit) && used_bits.count(bit))
+ w->port_input = true;
+ }
+ if (w->port_output && w->port_input)
+ log("Created miter inout port %s.\n", log_id(w));
+ else if (w->port_output)
+ log("Created miter output port %s.\n", log_id(w));
+ else if (w->port_input)
+ log("Created miter input port %s.\n", log_id(w));
+ }
+
+ miter_module->fixup_ports();
+ }
+
+ void make_stuff()
+ {
+ if (!mode_trigger && !mode_cmp && !mode_assert)
+ return;
+
+ SigSpec trigger_signals;
+ vector<Cell*> equiv_cells;
+
+ for (auto c : miter_module->cells())
+ if (c->type == "$equiv" && c->getPort("\\A") != c->getPort("\\B"))
+ equiv_cells.push_back(c);
+
+ for (auto c : equiv_cells)
+ {
+ SigSpec cmp = mode_undef ?
+ miter_module->LogicOr(NEW_ID, miter_module->Eqx(NEW_ID, c->getPort("\\A"), State::Sx),
+ miter_module->Eqx(NEW_ID, c->getPort("\\A"), c->getPort("\\B"))) :
+ miter_module->Eq(NEW_ID, c->getPort("\\A"), c->getPort("\\B"));
+
+ if (mode_cmp) {
+ string cmp_name = string("\\cmp") + log_signal(c->getPort("\\Y"));
+ for (int i = 1; i < GetSize(cmp_name); i++)
+ if (cmp_name[i] == '\\')
+ cmp_name[i] = '_';
+ else if (cmp_name[i] == ' ')
+ cmp_name = cmp_name.substr(0, i) + cmp_name.substr(i+1);
+ auto w = miter_module->addWire(cmp_name);
+ w->port_output = true;
+ miter_module->connect(w, cmp);
+ }
+
+ if (mode_assert)
+ miter_module->addAssert(NEW_ID, cmp, State::S1);
+
+ trigger_signals.append(miter_module->Not(NEW_ID, cmp));
+ }
+
+ if (mode_trigger) {
+ auto w = miter_module->addWire("\\trigger");
+ w->port_output = true;
+ miter_module->addReduceOr(NEW_ID, trigger_signals, w);
+ }
+
+ miter_module->fixup_ports();
+ }
+
+ void run()
+ {
+ log("Creating miter %s from module %s.\n", log_id(miter_module), log_id(source_module));
+ find_miter_cells_wires();
+ copy_to_miter();
+ make_stuff();
+ }
+};
+
+struct EquivMiterPass : public Pass {
+ EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_miter [options] miter_module [selection]\n");
+ log("\n");
+ log("This creates a miter module for further analysis of the selected $equiv cells.\n");
+ log("\n");
+ log(" -trigger\n");
+ log(" Create a trigger output\n");
+ log("\n");
+ log(" -cmp\n");
+ log(" Create cmp_* outputs for individual unproven $equiv cells\n");
+ log("\n");
+ log(" -assert\n");
+ log(" Create a $assert cell for each unproven $equiv cell\n");
+ log("\n");
+ log(" -undef\n");
+ log(" Create compare logic that handles undefs correctly\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ EquivMiterWorker worker;
+ worker.ct.setup(design);
+ worker.mode_trigger = false;
+ worker.mode_cmp = false;
+ worker.mode_assert = false;
+ worker.mode_undef = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-trigger") {
+ worker.mode_trigger = true;
+ continue;
+ }
+ if (args[argidx] == "-cmp") {
+ worker.mode_cmp = true;
+ continue;
+ }
+ if (args[argidx] == "-assert") {
+ worker.mode_assert = true;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ worker.mode_undef = true;
+ continue;
+ }
+ break;
+ }
+
+ if (argidx >= args.size())
+ log_cmd_error("Invalid number of arguments.\n");
+
+ worker.miter_name = RTLIL::escape_id(args[argidx++]);
+ extra_args(args, argidx, design);
+
+ if (design->module(worker.miter_name))
+ log_cmd_error("Miter module %s already exists.\n", log_id(worker.miter_name));
+
+ worker.source_module = nullptr;
+ for (auto m : design->selected_modules()) {
+ if (worker.source_module != nullptr)
+ goto found_two_modules;
+ worker.source_module = m;
+ }
+
+ if (worker.source_module == nullptr)
+ found_two_modules:
+ log_cmd_error("Exactly one module must be selected for 'equiv_miter'!\n");
+
+ log_header("Executing EQUIV_MITER pass.\n");
+
+ worker.miter_module = design->addModule(worker.miter_name);
+ worker.run();
+ }
+} EquivMiterPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
new file mode 100644
index 00000000..b6e232f9
--- /dev/null
+++ b/passes/equiv/equiv_remove.cc
@@ -0,0 +1,83 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivRemovePass : public Pass {
+ EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_remove [options] [selection]\n");
+ log("\n");
+ log("This command removes the selected $equiv cells. If neither -gold nor -gate is\n");
+ log("used then only proven cells are removed.\n");
+ log("\n");
+ log(" -gold\n");
+ log(" keep gold circuit\n");
+ log("\n");
+ log(" -gate\n");
+ log(" keep gate circuit\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool mode_gold = false;
+ bool mode_gate = false;
+ int remove_count = 0;
+
+ log_header("Executing EQUIV_REMOVE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-gold") {
+ mode_gold = true;
+ continue;
+ }
+ if (args[argidx] == "-gate") {
+ mode_gate = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (mode_gold && mode_gate)
+ log_cmd_error("Options -gold and -gate are exclusive.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv" && (mode_gold || mode_gate || cell->getPort("\\A") == cell->getPort("\\B"))) {
+ log("Removing $equiv cell %s.%s (%s).\n", log_id(module), log_id(cell), log_signal(cell->getPort("\\Y")));
+ module->connect(cell->getPort("\\Y"), mode_gate ? cell->getPort("\\B") : cell->getPort("\\A"));
+ module->remove(cell);
+ remove_count++;
+ }
+ }
+
+ log("Removed a total of %d $equiv cells.\n", remove_count);
+ }
+} EquivRemovePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
new file mode 100644
index 00000000..f1b66432
--- /dev/null
+++ b/passes/equiv/equiv_simple.cc
@@ -0,0 +1,358 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivSimpleWorker
+{
+ Module *module;
+ const vector<Cell*> &equiv_cells;
+ Cell *equiv_cell;
+
+ SigMap &sigmap;
+ dict<SigBit, Cell*> &bit2driver;
+
+ ezSatPtr ez;
+ SatGen satgen;
+ int max_seq;
+ bool verbose;
+
+ pool<pair<Cell*, int>> imported_cells_cache;
+
+ EquivSimpleWorker(const vector<Cell*> &equiv_cells, SigMap &sigmap, dict<SigBit, Cell*> &bit2driver, int max_seq, bool verbose, bool model_undef) :
+ module(equiv_cells.front()->module), equiv_cells(equiv_cells), equiv_cell(nullptr),
+ sigmap(sigmap), bit2driver(bit2driver), satgen(ez.get(), &sigmap), max_seq(max_seq), verbose(verbose)
+ {
+ satgen.model_undef = model_undef;
+ }
+
+ bool find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, Cell *cell)
+ {
+ if (cells_cone.count(cell))
+ return false;
+
+ cells_cone.insert(cell);
+
+ if (cells_stop.count(cell))
+ return true;
+
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_input(cell->type, conn.first))
+ for (auto bit : sigmap(conn.second)) {
+ if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_")) {
+ if (!conn.first.in("\\CLK", "\\C"))
+ next_seed.insert(bit);
+ } else
+ find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit);
+ }
+ return false;
+ }
+
+ void find_input_cone(pool<SigBit> &next_seed, pool<Cell*> &cells_cone, pool<SigBit> &bits_cone, const pool<Cell*> &cells_stop, const pool<SigBit> &bits_stop, pool<SigBit> *input_bits, SigBit bit)
+ {
+ if (bits_cone.count(bit))
+ return;
+
+ bits_cone.insert(bit);
+
+ if (bits_stop.count(bit)) {
+ if (input_bits != nullptr) input_bits->insert(bit);
+ return;
+ }
+
+ if (!bit2driver.count(bit))
+ return;
+
+ if (find_input_cone(next_seed, cells_cone, bits_cone, cells_stop, bits_stop, input_bits, bit2driver.at(bit)))
+ if (input_bits != nullptr) input_bits->insert(bit);
+ }
+
+ bool run_cell()
+ {
+ SigBit bit_a = sigmap(equiv_cell->getPort("\\A")).to_single_sigbit();
+ SigBit bit_b = sigmap(equiv_cell->getPort("\\B")).to_single_sigbit();
+ int ez_context = ez->frozen_literal();
+
+ if (satgen.model_undef)
+ {
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importDefSigBit(bit_b, max_seq+1);
+ int ez_undef_a = satgen.importUndefSigBit(bit_a, max_seq+1);
+
+ ez->assume(ez->XOR(ez_a, ez_b), ez_context);
+ ez->assume(ez->NOT(ez_undef_a), ez_context);
+ }
+ else
+ {
+ int ez_a = satgen.importSigBit(bit_a, max_seq+1);
+ int ez_b = satgen.importSigBit(bit_b, max_seq+1);
+ ez->assume(ez->XOR(ez_a, ez_b), ez_context);
+ }
+
+ pool<SigBit> seed_a = { bit_a };
+ pool<SigBit> seed_b = { bit_b };
+
+ if (verbose) {
+ log(" Trying to prove $equiv cell %s:\n", log_id(equiv_cell));
+ log(" A = %s, B = %s, Y = %s\n", log_signal(bit_a), log_signal(bit_b), log_signal(equiv_cell->getPort("\\Y")));
+ } else {
+ log(" Trying to prove $equiv for %s:", log_signal(equiv_cell->getPort("\\Y")));
+ }
+
+ int step = max_seq;
+ while (1)
+ {
+ pool<Cell*> no_stop_cells;
+ pool<SigBit> no_stop_bits;
+
+ pool<Cell*> full_cells_cone_a, full_cells_cone_b;
+ pool<SigBit> full_bits_cone_a, full_bits_cone_b;
+
+ pool<SigBit> next_seed_a, next_seed_b;
+
+ for (auto bit_a : seed_a)
+ find_input_cone(next_seed_a, full_cells_cone_a, full_bits_cone_a, no_stop_cells, no_stop_bits, nullptr, bit_a);
+ next_seed_a.clear();
+
+ for (auto bit_b : seed_b)
+ find_input_cone(next_seed_b, full_cells_cone_b, full_bits_cone_b, no_stop_cells, no_stop_bits, nullptr, bit_b);
+ next_seed_b.clear();
+
+ pool<Cell*> short_cells_cone_a, short_cells_cone_b;
+ pool<SigBit> short_bits_cone_a, short_bits_cone_b;
+ pool<SigBit> input_bits;
+
+ for (auto bit_a : seed_a)
+ find_input_cone(next_seed_a, short_cells_cone_a, short_bits_cone_a, full_cells_cone_b, full_bits_cone_b, &input_bits, bit_a);
+ next_seed_a.swap(seed_a);
+
+ for (auto bit_b : seed_b)
+ find_input_cone(next_seed_b, short_cells_cone_b, short_bits_cone_b, full_cells_cone_a, full_bits_cone_a, &input_bits, bit_b);
+ next_seed_b.swap(seed_b);
+
+ pool<Cell*> problem_cells;
+ problem_cells.insert(short_cells_cone_a.begin(), short_cells_cone_a.end());
+ problem_cells.insert(short_cells_cone_b.begin(), short_cells_cone_b.end());
+
+ if (verbose)
+ log(" Adding %d new cells to the problem (%d A, %d B, %d shared).\n",
+ GetSize(problem_cells), GetSize(short_cells_cone_a), GetSize(short_cells_cone_b),
+ (GetSize(short_cells_cone_a) + GetSize(short_cells_cone_b)) - GetSize(problem_cells));
+
+ for (auto cell : problem_cells) {
+ auto key = pair<Cell*, int>(cell, step+1);
+ if (!imported_cells_cache.count(key) && !satgen.importCell(cell, step+1))
+ log_cmd_error("No SAT model available for cell %s (%s).\n", log_id(cell), log_id(cell->type));
+ imported_cells_cache.insert(key);
+ }
+
+ if (satgen.model_undef) {
+ for (auto bit : input_bits)
+ ez->assume(ez->NOT(satgen.importUndefSigBit(bit, step+1)));
+ }
+
+ if (verbose)
+ log(" Problem size at t=%d: %d literals, %d clauses\n", step, ez->numCnfVariables(), ez->numCnfClauses());
+
+ if (!ez->solve(ez_context)) {
+ log(verbose ? " Proved equivalence! Marking $equiv cell as proven.\n" : " success!\n");
+ equiv_cell->setPort("\\B", equiv_cell->getPort("\\A"));
+ ez->assume(ez->NOT(ez_context));
+ return true;
+ }
+
+ if (verbose)
+ log(" Failed to prove equivalence with sequence length %d.\n", max_seq - step);
+
+ if (--step < 0) {
+ if (verbose)
+ log(" Reached sequence limit.\n");
+ break;
+ }
+
+ if (seed_a.empty() && seed_b.empty()) {
+ if (verbose)
+ log(" No nets to continue in previous time step.\n");
+ break;
+ }
+
+ if (seed_a.empty()) {
+ if (verbose)
+ log(" No nets on A-side to continue in previous time step.\n");
+ break;
+ }
+
+ if (seed_b.empty()) {
+ if (verbose)
+ log(" No nets on B-side to continue in previous time step.\n");
+ break;
+ }
+
+ if (verbose) {
+ #if 0
+ log(" Continuing analysis in previous time step with the following nets:\n");
+ for (auto bit : seed_a)
+ log(" A: %s\n", log_signal(bit));
+ for (auto bit : seed_b)
+ log(" B: %s\n", log_signal(bit));
+ #else
+ log(" Continuing analysis in previous time step with %d A- and %d B-nets.\n", GetSize(seed_a), GetSize(seed_b));
+ #endif
+ }
+ }
+
+ if (!verbose)
+ log(" failed.\n");
+
+ ez->assume(ez->NOT(ez_context));
+ return false;
+ }
+
+ int run()
+ {
+ if (GetSize(equiv_cells) > 1) {
+ SigSpec sig;
+ for (auto c : equiv_cells)
+ sig.append(sigmap(c->getPort("\\Y")));
+ log(" Grouping SAT models for %s:\n", log_signal(sig));
+ }
+
+ int counter = 0;
+ for (auto c : equiv_cells) {
+ equiv_cell = c;
+ if (run_cell())
+ counter++;
+ }
+ return counter;
+ }
+
+};
+
+struct EquivSimplePass : public Pass {
+ EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_simple [options] [selection]\n");
+ log("\n");
+ log("This command tries to prove $equiv cells using a simple direct SAT approach.\n");
+ log("\n");
+ log(" -v\n");
+ log(" verbose output\n");
+ log("\n");
+ log(" -undef\n");
+ log(" enable modelling of undef states\n");
+ log("\n");
+ log(" -nogroup\n");
+ log(" disabling grouping of $equiv cells by output wire\n");
+ log("\n");
+ log(" -seq <N>\n");
+ log(" the max. number of time steps to be considered (default = 1)\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool verbose = false, model_undef = false, nogroup = false;
+ int success_counter = 0;
+ int max_seq = 1;
+
+ log_header("Executing EQUIV_SIMPLE pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-v") {
+ verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ model_undef = true;
+ continue;
+ }
+ if (args[argidx] == "-nogroup") {
+ nogroup = true;
+ continue;
+ }
+ if (args[argidx] == "-seq" && argidx+1 < args.size()) {
+ max_seq = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> bit2driver;
+ dict<SigBit, dict<SigBit, Cell*>> unproven_equiv_cells;
+ int unproven_cells_counter = 0;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv" && cell->getPort("\\A") != cell->getPort("\\B")) {
+ auto bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
+ auto bit_group = bit;
+ if (!nogroup && bit_group.wire)
+ bit_group.offset = 0;
+ unproven_equiv_cells[bit_group][bit] = cell;
+ unproven_cells_counter++;
+ }
+
+ if (unproven_equiv_cells.empty())
+ continue;
+
+ log("Found %d unproven $equiv cells (%d groups) in %s:\n",
+ unproven_cells_counter, GetSize(unproven_equiv_cells), log_id(module));
+
+ for (auto cell : module->cells()) {
+ if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_"))
+ continue;
+ for (auto &conn : cell->connections())
+ if (yosys_celltypes.cell_output(cell->type, conn.first))
+ for (auto bit : sigmap(conn.second))
+ bit2driver[bit] = cell;
+ }
+
+ unproven_equiv_cells.sort();
+ for (auto it : unproven_equiv_cells)
+ {
+ it.second.sort();
+
+ vector<Cell*> cells;
+ for (auto it2 : it.second)
+ cells.push_back(it2.second);
+
+ EquivSimpleWorker worker(cells, sigmap, bit2driver, max_seq, verbose, model_undef);
+ success_counter += worker.run();
+ }
+ }
+
+ log("Proved %d previously unproven $equiv cells.\n", success_counter);
+ }
+} EquivSimplePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
new file mode 100644
index 00000000..8ca1aacd
--- /dev/null
+++ b/passes/equiv/equiv_status.cc
@@ -0,0 +1,94 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EquivStatusPass : public Pass {
+ EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" equiv_status [options] [selection]\n");
+ log("\n");
+ log("This command prints status information for all selected $equiv cells.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" produce an error if any unproven $equiv cell is found\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ bool assert_mode = false;
+ int unproven_count = 0;
+
+ log_header("Executing EQUIV_STATUS pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-assert") {
+ assert_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> unproven_equiv_cells;
+ int proven_equiv_cells = 0;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$equiv") {
+ if (cell->getPort("\\A") != cell->getPort("\\B"))
+ unproven_equiv_cells.push_back(cell);
+ else
+ proven_equiv_cells++;
+ }
+
+ if (unproven_equiv_cells.empty() && !proven_equiv_cells) {
+ log("No $equiv cells found in %s.\n", log_id(module));
+ continue;
+ }
+
+ log("Found %d $equiv cells in %s:\n", GetSize(unproven_equiv_cells) + proven_equiv_cells, log_id(module));
+ log(" Of those cells %d are proven and %d are unproven.\n", proven_equiv_cells, GetSize(unproven_equiv_cells));
+ if (unproven_equiv_cells.empty()) {
+ log(" Equivalence successfully proven!\n");
+ } else {
+ for (auto cell : unproven_equiv_cells)
+ log(" Unproven $equiv %s: %s %s\n", log_id(cell), log_signal(cell->getPort("\\A")), log_signal(cell->getPort("\\B")));
+ }
+
+ unproven_count += GetSize(unproven_equiv_cells);
+ }
+
+ if (unproven_count != 0) {
+ log("Found a total of %d unproven $equiv cells.\n", unproven_count);
+ if (assert_mode && unproven_count != 0)
+ log_error("Found %d unproven $equiv cells in 'equiv_status -assert'.\n", unproven_count);
+ }
+ }
+} EquivStatusPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 2fae7609..e76be40c 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmPass : public Pass {
FsmPass() : Pass("fsm", "extract and optimize finite state machines") { }
virtual void help()
@@ -58,6 +61,7 @@ struct FsmPass : public Pass {
log("\n");
log(" -encoding tye\n");
log(" -fm_set_fsm_file file\n");
+ log(" -encfile file\n");
log(" passed through to fsm_recode pass\n");
log("\n");
}
@@ -69,6 +73,7 @@ struct FsmPass : public Pass {
bool flag_expand = false;
bool flag_export = false;
std::string fm_set_fsm_file_opt;
+ std::string encfile_opt;
std::string encoding_opt;
log_header("Executing FSM pass (extract and optimize FSM).\n");
@@ -81,7 +86,11 @@ struct FsmPass : public Pass {
fm_set_fsm_file_opt = " -fm_set_fsm_file " + args[++argidx];
continue;
}
- if (arg == "-encoding" && argidx+1 < args.size() && fm_set_fsm_file_opt.empty()) {
+ if (arg == "-encfile" && argidx+1 < args.size() && encfile_opt.empty()) {
+ encfile_opt = " -encfile " + args[++argidx];
+ continue;
+ }
+ if (arg == "-encoding" && argidx+1 < args.size() && encoding_opt.empty()) {
encoding_opt = " -encoding " + args[++argidx];
continue;
}
@@ -124,7 +133,7 @@ struct FsmPass : public Pass {
}
if (!flag_norecode)
- Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encoding_opt);
+ Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encfile_opt + encoding_opt);
Pass::call(design, "fsm_info");
if (flag_export)
@@ -137,3 +146,4 @@ struct FsmPass : public Pass {
}
} FsmPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 2c846a4c..c89553c6 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -24,6 +24,9 @@
#include "kernel/celltypes.h"
#include "fsmdata.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static RTLIL::Module *module;
static SigMap assign_map;
typedef std::pair<RTLIL::Cell*, RTLIL::IdString> sig2driver_entry_t;
@@ -40,7 +43,7 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, Sig
return true;
if (recursion_monitor.check_any(sig)) {
- log("Warning: logic loop in mux tree at signal %s in module %s.\n",
+ log_warning("logic loop in mux tree at signal %s in module %s.\n",
log_signal(sig), RTLIL::id2cstr(module->name));
return false;
}
@@ -189,3 +192,4 @@ struct FsmDetectPass : public Pass {
}
} FsmDetectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index d1364391..a261eb22 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmExpand
{
RTLIL::Module *module;
@@ -236,7 +239,7 @@ struct FsmExpand
if (merged_set.size() > 0 && !already_optimized)
FsmData::optimize_fsm(fsm_cell, module);
- log(" merged %zd cells into FSM.\n", merged_set.size());
+ log(" merged %d cells into FSM.\n", GetSize(merged_set));
}
};
@@ -273,3 +276,4 @@ struct FsmExpandPass : public Pass {
}
} FsmExpandPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index b4a6b3f7..ad927033 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -28,6 +28,9 @@
#include <iostream>
#include <fstream>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
/**
* Convert a signal into a KISS-compatible textual representation.
*/
@@ -47,7 +50,7 @@ std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
* @param cell pointer to the FSM cell which should be exported.
*/
void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::string filename, bool origenc) {
- std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
+ dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
FsmData fsm_data;
FsmData::transition_t tr;
std::ofstream kiss_file;
@@ -142,7 +145,7 @@ struct FsmExportPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- std::map<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
+ dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it;
std::string arg;
bool flag_noauto = false;
std::string filename;
@@ -182,3 +185,5 @@ struct FsmExportPass : public Pass {
}
}
} FsmExportPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 451f00fc..68667ef0 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -29,6 +29,9 @@
#include "kernel/celltypes.h"
#include "fsmdata.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static RTLIL::Module *module;
static SigMap assign_map;
typedef std::pair<RTLIL::IdString, RTLIL::IdString> sig2driver_entry_t;
@@ -37,7 +40,7 @@ static std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> exclusive_ctrls;
static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL::SigSpec &ctrl, std::map<RTLIL::Const, int> &states, RTLIL::Const *reset_state = NULL)
{
- sig.extend(dff_out.size(), false);
+ sig.extend_u0(dff_out.size(), false);
if (sig == dff_out)
return true;
@@ -70,9 +73,9 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
sig_aa.replace(sig_y, sig_a);
RTLIL::SigSpec sig_bb;
- for (int i = 0; i < SIZE(sig_b)/SIZE(sig_a); i++) {
+ for (int i = 0; i < GetSize(sig_b)/GetSize(sig_a); i++) {
RTLIL::SigSpec s = sig;
- s.replace(sig_y, sig_b.extract(i*SIZE(sig_a), SIZE(sig_a)));
+ s.replace(sig_y, sig_b.extract(i*GetSize(sig_a), GetSize(sig_a)));
sig_bb.append(s);
}
@@ -95,8 +98,8 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
if (!find_states(sig_aa, dff_out, ctrl, states))
return false;
- for (int i = 0; i < SIZE(sig_bb)/SIZE(sig_aa); i++) {
- if (!find_states(sig_bb.extract(i*SIZE(sig_aa), SIZE(sig_aa)), dff_out, ctrl, states))
+ for (int i = 0; i < GetSize(sig_bb)/GetSize(sig_aa); i++) {
+ if (!find_states(sig_bb.extract(i*GetSize(sig_aa), GetSize(sig_aa)), dff_out, ctrl, states))
return false;
}
}
@@ -107,7 +110,7 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State noconst_state, RTLIL::SigSpec dont_care = RTLIL::SigSpec())
{
if (dont_care.size() > 0) {
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (dont_care.extract(sig[i]).size() > 0)
sig[i] = noconst_state;
}
@@ -115,7 +118,7 @@ static RTLIL::Const sig2const(ConstEval &ce, RTLIL::SigSpec sig, RTLIL::State no
ce.assign_map.apply(sig);
ce.values_map.apply(sig);
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (sig[i].wire != NULL)
sig[i] = noconst_state;
@@ -145,7 +148,7 @@ undef_bit_in_next_state:
tr.ctrl_out = sig2const(ce, ctrl_out, RTLIL::State::Sx);
std::map<RTLIL::SigBit, int> ctrl_in_bit_indices;
- for (int i = 0; i < SIZE(ctrl_in); i++)
+ for (int i = 0; i < GetSize(ctrl_in); i++)
ctrl_in_bit_indices[ctrl_in[i]] = i;
for (auto &it : ctrl_in_bit_indices)
@@ -287,7 +290,7 @@ static void extract_fsm(RTLIL::Wire *wire)
log(" fsm extraction failed: state selection tree is not closed.\n");
return;
}
- if (SIZE(states) <= 1) {
+ if (GetSize(states) <= 1) {
log(" fsm extraction failed: at least two states are required.\n");
return;
}
@@ -456,3 +459,4 @@ struct FsmExtractPass : public Pass {
}
} FsmExtractPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 45d68a90..4a1f1d9a 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmInfoPass : public Pass {
FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { }
virtual void help()
@@ -56,3 +59,4 @@ struct FsmInfoPass : public Pass {
}
} FsmInfoPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index ab6d5671..155801a3 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -25,10 +25,13 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static bool pattern_is_subset(const RTLIL::Const &super_pattern, const RTLIL::Const &sub_pattern)
{
- log_assert(SIZE(super_pattern.bits) == SIZE(sub_pattern.bits));
- for (int i = 0; i < SIZE(super_pattern.bits); i++)
+ log_assert(GetSize(super_pattern.bits) == GetSize(sub_pattern.bits));
+ for (int i = 0; i < GetSize(super_pattern.bits); i++)
if (sub_pattern.bits[i] == RTLIL::State::S0 || sub_pattern.bits[i] == RTLIL::State::S1) {
if (super_pattern.bits[i] == RTLIL::State::S0 || super_pattern.bits[i] == RTLIL::State::S1) {
if (super_pattern.bits[i] != sub_pattern.bits[i])
@@ -88,7 +91,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
if (pattern_is_subset(pattern, it2.first))
complete_in_state_cache.insert(it2.second.begin(), it2.second.end());
- if (SIZE(complete_in_state_cache) < num_states)
+ if (GetSize(complete_in_state_cache) < num_states)
{
if (or_sig.size() == 1)
{
@@ -221,9 +224,12 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
}
}
+ if (encoding_is_onehot)
+ state_wire->set_bool_attribute("\\onehot");
+
// generate next_state signal
- if (SIZE(fsm_data.state_table) == 1)
+ if (GetSize(fsm_data.state_table) == 1)
{
module->connect(next_state_wire, fsm_data.state_table.front());
}
@@ -345,3 +351,4 @@ struct FsmMapPass : public Pass {
}
} FsmMapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index a0e1885e..4b93d79f 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -25,6 +25,9 @@
#include "fsmdata.h"
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmOpt
{
FsmData fsm_data;
@@ -40,7 +43,7 @@ struct FsmOpt
std::vector<RTLIL::Const> new_state_table;
std::map<int, int> old_to_new_state;
- for (int i = 0; i < SIZE(fsm_data.state_table); i++)
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++)
if (i != fsm_data.reset_state)
unreachable_states.insert(i);
@@ -50,12 +53,12 @@ struct FsmOpt
if (unreachable_states.empty())
break;
- for (int i = 0; i < SIZE(fsm_data.state_table); i++) {
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++) {
if (unreachable_states.count(i)) {
log(" Removing unreachable state %s.\n", log_signal(fsm_data.state_table[i]));
continue;
}
- old_to_new_state[i] = SIZE(new_state_table);
+ old_to_new_state[i] = GetSize(new_state_table);
new_state_table.push_back(fsm_data.state_table[i]);
}
@@ -309,11 +312,15 @@ struct FsmOpt
}
};
-void FsmData::optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module)
+PRIVATE_NAMESPACE_END
+
+void YOSYS_NAMESPACE_PREFIX FsmData::optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module)
{
FsmOpt fsmopt(cell, module);
}
+PRIVATE_NAMESPACE_BEGIN
+
struct FsmOptPass : public Pass {
FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { }
virtual void help()
@@ -335,9 +342,10 @@ struct FsmOptPass : public Pass {
for (auto &mod_it : design->modules_) {
if (design->selected(mod_it.second))
for (auto &cell_it : mod_it.second->cells_)
- if (cell_it.second->type == "$fsm" and design->selected(mod_it.second, cell_it.second))
+ if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
FsmData::optimize_fsm(cell_it.second, mod_it.second);
}
}
} FsmOptPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 873ee7a1..16996810 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -27,6 +27,9 @@
#include <string.h>
#include <errno.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &fsm_data, const char *prefix, FILE *f)
{
std::string name = cell->parameters["\\NAME"].decode_string();
@@ -38,9 +41,9 @@ static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &
prefix, RTLIL::unescape_id(module->name).c_str());
fprintf(f, "set_fsm_encoding {");
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- fprintf(f, " s%zd=2#", i);
- for (int j = int(fsm_data.state_table[i].bits.size())-1; j >= 0; j--)
+ for (int i = 0; i < GetSize(fsm_data.state_table); i++) {
+ fprintf(f, " s%d=2#", i);
+ for (int j = GetSize(fsm_data.state_table[i].bits)-1; j >= 0; j--)
fprintf(f, "%c", fsm_data.state_table[i].bits[j] == RTLIL::State::S1 ? '1' : '0');
}
fprintf(f, " } -name {%s_%s} {%s:/WORK/%s}\n",
@@ -48,7 +51,7 @@ static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &
prefix, RTLIL::unescape_id(module->name).c_str());
}
-static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fsm_file, std::string default_encoding)
+static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fsm_file, FILE *encfile, std::string default_encoding)
{
std::string encoding = cell->attributes.count("\\fsm_encoding") ? cell->attributes.at("\\fsm_encoding").decode_string() : "auto";
@@ -74,7 +77,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
if (!default_encoding.empty())
encoding = default_encoding;
else
- encoding = SIZE(fsm_data.state_table) < 32 ? "one-hot" : "binary";
+ encoding = GetSize(fsm_data.state_table) < 32 ? "one-hot" : "binary";
log(" mapping auto encoding to `%s` for this FSM.\n", encoding.c_str());
}
@@ -91,6 +94,9 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
} else
log_error("FSM encoding `%s' is not supported!\n", encoding.c_str());
+ if (encfile)
+ fprintf(encfile, ".fsm %s %s\n", log_id(module), RTLIL::unescape_id(cell->parameters["\\NAME"].decode_string()).c_str());
+
int state_idx_counter = fsm_data.reset_state >= 0 ? 1 : 0;
for (int i = 0; i < int(fsm_data.state_table.size()); i++)
{
@@ -107,6 +113,8 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
log_abort();
log(" %s -> %s\n", fsm_data.state_table[i].as_string().c_str(), new_code.as_string().c_str());
+ if (encfile)
+ fprintf(encfile, ".map %s %s\n", fsm_data.state_table[i].as_string().c_str(), new_code.as_string().c_str());
fsm_data.state_table[i] = new_code;
}
@@ -122,21 +130,31 @@ struct FsmRecodePass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" fsm_recode [-encoding type] [-fm_set_fsm_file file] [selection]\n");
+ log(" fsm_recode [options] [selection]\n");
log("\n");
log("This pass reassign the state encodings for FSM cells. At the moment only\n");
- log("one-hot encoding and binary encoding is supported. The option -encoding\n");
- log("can be used to specify the encoding scheme used for FSMs without the\n");
- log("`fsm_encoding' attribute (or with the attribute set to `auto'.\n");
+ log("one-hot encoding and binary encoding is supported.\n");
+
+ log(" -encoding <type>\n");
+ log(" specify the encoding scheme used for FSMs without the\n");
+ log(" 'fsm_encoding' attribute or with the attribute set to `auto'.\n");
+ log("\n");
+ log(" -fm_set_fsm_file <file>\n");
+ log(" generate a file containing the mapping from old to new FSM encoding\n");
+ log(" in form of Synopsys Formality set_fsm_* commands.\n");
log("\n");
- log("The option -fm_set_fsm_file can be used to generate a file containing the\n");
- log("mapping from old to new FSM encoding in form of Synopsys Formality set_fsm_*\n");
- log("commands.\n");
+ log(" -encfile <file>\n");
+ log(" write the mappings from old to new FSM encoding to a file in the\n");
+ log(" following format:\n");
+ log("\n");
+ log(" .fsm <module_name> <state_signal>\n");
+ log(" .map <old_bitpattern> <new_bitpattern>\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
FILE *fm_set_fsm_file = NULL;
+ FILE *encfile = NULL;
std::string default_encoding;
log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
@@ -149,7 +167,13 @@ struct FsmRecodePass : public Pass {
log_error("Can't open fm_set_fsm_file `%s' for writing: %s\n", args[argidx].c_str(), strerror(errno));
continue;
}
- if (arg == "-encoding" && argidx+1 < args.size() && fm_set_fsm_file == NULL) {
+ if (arg == "-encfile" && argidx+1 < args.size() && encfile == NULL) {
+ encfile = fopen(args[++argidx].c_str(), "w");
+ if (encfile == NULL)
+ log_error("Can't open encfile `%s' for writing: %s\n", args[argidx].c_str(), strerror(errno));
+ continue;
+ }
+ if (arg == "-encoding" && argidx+1 < args.size() && default_encoding.empty()) {
default_encoding = args[++argidx];
continue;
}
@@ -161,10 +185,13 @@ struct FsmRecodePass : public Pass {
if (design->selected(mod_it.second))
for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
- fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file, default_encoding);
+ fsm_recode(cell_it.second, mod_it.second, fm_set_fsm_file, encfile, default_encoding);
if (fm_set_fsm_file != NULL)
fclose(fm_set_fsm_file);
+ if (encfile != NULL)
+ fclose(encfile);
}
} FsmRecodePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
index 7a44dd45..5671d000 100644
--- a/passes/fsm/fsmdata.h
+++ b/passes/fsm/fsmdata.h
@@ -20,8 +20,9 @@
#ifndef FSMDATA_H
#define FSMDATA_H
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
struct FsmData
{
@@ -142,24 +143,24 @@ struct FsmData
log("\n");
log(" Input signals:\n");
RTLIL::SigSpec sig_in = cell->getPort("\\CTRL_IN");
- for (int i = 0; i < SIZE(sig_in); i++)
+ for (int i = 0; i < GetSize(sig_in); i++)
log(" %3d: %s\n", i, log_signal(sig_in[i]));
log("\n");
log(" Output signals:\n");
RTLIL::SigSpec sig_out = cell->getPort("\\CTRL_OUT");
- for (int i = 0; i < SIZE(sig_out); i++)
+ for (int i = 0; i < GetSize(sig_out); i++)
log(" %3d: %s\n", i, log_signal(sig_out[i]));
log("\n");
log(" State encoding:\n");
- for (int i = 0; i < SIZE(state_table); i++)
+ for (int i = 0; i < GetSize(state_table); i++)
log(" %3d: %10s%s\n", i, log_signal(state_table[i], false),
int(i) == reset_state ? " <RESET STATE>" : "");
log("\n");
log(" Transition Table (state_in, ctrl_in, state_out, ctrl_out):\n");
- for (int i = 0; i < SIZE(transition_table); i++) {
+ for (int i = 0; i < GetSize(transition_table); i++) {
transition_t &tr = transition_table[i];
log(" %5d: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
}
@@ -172,4 +173,6 @@ struct FsmData
static void optimize_fsm(RTLIL::Cell *cell, RTLIL::Module *module);
};
+YOSYS_NAMESPACE_END
+
#endif
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 14bf8d1b..a393343d 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -17,23 +17,26 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
#include <stdlib.h>
#include <stdio.h>
-#include <fnmatch.h>
#include <set>
-#include <unistd.h>
-
-namespace {
- struct generate_port_decl_t {
- bool input, output;
- RTLIL::IdString portname;
- int index;
- };
-}
-static void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct generate_port_decl_t {
+ bool input, output;
+ string portname;
+ int index;
+};
+
+void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, const std::vector<generate_port_decl_t> &portdecls)
{
std::set<RTLIL::IdString> found_celltypes;
@@ -46,7 +49,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__")
continue;
for (auto &pattern : celltypes)
- if (!fnmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str(), FNM_NOESCAPE))
+ if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str()))
found_celltypes.insert(cell->type);
}
@@ -96,9 +99,9 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
while (portnames.size() > 0) {
RTLIL::IdString portname = *portnames.begin();
for (auto &decl : portdecls)
- if (decl.index == 0 && !fnmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str(), FNM_NOESCAPE)) {
+ if (decl.index == 0 && patmatch(decl.portname.c_str(), RTLIL::unescape_id(portname).c_str())) {
generate_port_decl_t d = decl;
- d.portname = portname;
+ d.portname = portname.str();
d.index = *indices.begin();
log_assert(!indices.empty());
indices.erase(d.index);
@@ -135,7 +138,7 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
}
}
-static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -171,7 +174,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
for (auto &dir : libdirs)
{
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "verilog");
@@ -179,7 +182,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
}
filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (access(filename.c_str(), F_OK) == 0) {
+ if (check_file_exists(filename)) {
std::vector<std::string> args;
args.push_back(filename);
Frontend::frontend_call(design, NULL, filename, "ilang");
@@ -196,6 +199,19 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
if (design->modules_.count(cell->type) == 0)
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
+ } else
+ if (flag_check)
+ {
+ RTLIL::Module *mod = design->module(cell->type);
+ for (auto &conn : cell->connections())
+ if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
+ int id = atoi(conn.first.c_str()+1);
+ if (id <= 0 || id > GetSize(mod->ports))
+ log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d ports, requested port %d.\n",
+ log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->ports), id);
+ } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0)
+ log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n",
+ log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first));
}
if (cell->parameters.size() == 0)
@@ -245,24 +261,31 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
return did_something;
}
-static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
+void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
{
if (used.count(mod) > 0)
return;
if (indent == 0)
log("Top module: %s\n", mod->name.c_str());
- else
+ else if (!mod->get_bool_attribute("\\blackbox"))
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
- for (auto &it : mod->cells_) {
- if (design->modules_.count(it.second->type) > 0)
- hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
+ for (auto cell : mod->cells()) {
+ std::string celltype = cell->type.str();
+ if (celltype.substr(0, 7) == "$array:") {
+ int pos_idx = celltype.find_first_of(':');
+ int pos_num = celltype.find_first_of(':', pos_idx + 1);
+ int pos_type = celltype.find_first_of(':', pos_num + 1);
+ celltype = celltype.substr(pos_type + 1);
+ }
+ if (design->module(celltype))
+ hierarchy_worker(design, used, design->module(celltype), indent+4);
}
}
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
+void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
{
std::set<RTLIL::Module*> used;
hierarchy_worker(design, used, top, 0);
@@ -272,17 +295,41 @@ static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib,
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
+ int del_counter = 0;
for (auto mod : del_modules) {
- if (first_pass && mod->name.substr(0, 9) == "$abstract")
+ if (mod->name.substr(0, 9) == "$abstract")
continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name);
+ del_counter++;
delete mod;
}
- log("Removed %zd unused modules.\n", del_modules.size());
+ log("Removed %d unused modules.\n", del_counter);
+}
+
+bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
+{
+ if (cache.count(mod) == 0)
+ for (auto c : mod->cells()) {
+ RTLIL::Module *m = mod->design->module(c->type);
+ if ((m != nullptr && set_keep_assert(cache, m)) || c->type == "$assert")
+ return cache[mod] = true;
+ }
+ return cache[mod];
+}
+
+int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
+{
+ if (db.count(module) == 0) {
+ db[module] = 0;
+ for (auto cell : module->cells())
+ if (design->module(cell->type))
+ db[module] = std::max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ }
+ return db.at(module);
}
struct HierarchyPass : public Pass {
@@ -305,7 +352,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
- log(" module. use this options to also remove unused blackbox modules.\n");
+ log(" modules. use this option to also remove unused blackbox modules.\n");
log("\n");
log(" -libdir <directory>\n");
log(" search for files named <module_name>.v in the specified directory\n");
@@ -316,6 +363,11 @@ struct HierarchyPass : public Pass {
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log("\n");
+ log(" -nokeep_asserts\n");
+ log(" per default this pass sets the \"keep\" attribute on all modules\n");
+ log(" that directly or indirectly contain one or more $assert cells. this\n");
+ log(" option disables this behavior.\n");
+ log("\n");
log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n");
log(" outside this tree (unused modules) are removed.\n");
@@ -324,6 +376,9 @@ struct HierarchyPass : public Pass {
log(" specified top module. otherwise a module with the 'top' attribute set\n");
log(" will implicitly be used as top module, if such a module exists.\n");
log("\n");
+ log(" -auto-top\n");
+ log(" automatically determine the top of the design hierarchy and mark it.\n");
+ log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@@ -350,8 +405,10 @@ struct HierarchyPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::vector<std::string> libdirs;
+ bool auto_top_mode = false;
bool generate_mode = false;
bool keep_positionals = false;
+ bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
@@ -409,6 +466,10 @@ struct HierarchyPass : public Pass {
keep_positionals = true;
continue;
}
+ if (args[argidx] == "-nokeep_asserts") {
+ nokeep_asserts = true;
+ continue;
+ }
if (args[argidx] == "-libdir" && argidx+1 < args.size()) {
libdirs.push_back(args[++argidx]);
continue;
@@ -418,7 +479,7 @@ struct HierarchyPass : public Pass {
log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
- std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
+ dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
@@ -426,6 +487,10 @@ struct HierarchyPass : public Pass {
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
continue;
}
+ if (args[argidx] == "-auto-top") {
+ auto_top_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design, false);
@@ -437,35 +502,47 @@ struct HierarchyPass : public Pass {
log_push();
- if (top_mod == NULL)
+ if (top_mod == nullptr)
for (auto &mod_it : design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_mod = mod_it.second;
- if (top_mod != NULL)
- hierarchy(design, top_mod, purge_lib, true);
+ if (top_mod == nullptr && auto_top_mode) {
+ log_header("Finding top of design hierarchy..\n");
+ dict<Module*, int> db;
+ for (Module *mod : design->modules()) {
+ int score = find_top_mod_score(design, mod, db);
+ log("root of %3d design levels: %-20s\n", score, log_id(mod));
+ if (!top_mod || score > db[top_mod])
+ top_mod = mod;
+ }
+ if (top_mod != nullptr)
+ log("Automatically selected %s as design top module.\n", log_id(top_mod));
+ }
bool did_something = true;
- bool did_something_once = false;
- while (did_something) {
+ while (did_something)
+ {
did_something = false;
- std::vector<RTLIL::IdString> modnames;
- modnames.reserve(design->modules_.size());
- for (auto &mod_it : design->modules_)
- modnames.push_back(mod_it.first);
- for (auto &modname : modnames) {
- if (design->modules_.count(modname) == 0)
- continue;
- if (expand_module(design, design->modules_[modname], flag_check, libdirs))
+
+ std::set<RTLIL::Module*> used_modules;
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_worker(design, used_modules, top_mod, 0);
+ } else {
+ for (auto mod : design->modules())
+ used_modules.insert(mod);
+ }
+
+ for (auto module : used_modules) {
+ if (expand_module(design, module, flag_check, libdirs))
did_something = true;
}
- if (did_something)
- did_something_once = true;
}
- if (top_mod != NULL && did_something_once) {
- log_header("Re-running hierarchy analysis..\n");
- hierarchy(design, top_mod, purge_lib, false);
+ if (top_mod != NULL) {
+ log_header("Analyzing design hierarchy..\n");
+ hierarchy_clean(design, top_mod, purge_lib);
}
if (top_mod != NULL) {
@@ -476,6 +553,15 @@ struct HierarchyPass : public Pass {
mod_it.second->attributes.erase("\\top");
}
+ if (!nokeep_asserts) {
+ std::map<RTLIL::Module*, bool> cache;
+ for (auto mod : design->modules())
+ if (set_keep_assert(cache, mod)) {
+ log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
+ mod->set_bool_attribute("\\keep");
+ }
+ }
+
if (!keep_positionals)
{
std::set<RTLIL::Module*> pos_mods;
@@ -507,7 +593,7 @@ struct HierarchyPass : public Pass {
RTLIL::Cell *cell = work.second;
log("Mapping positional arguments of cell %s.%s (%s).\n",
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- std::map<RTLIL::IdString, RTLIL::SigSpec> new_connections;
+ dict<RTLIL::IdString, RTLIL::SigSpec> new_connections;
for (auto &conn : cell->connections())
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
int id = atoi(conn.first.c_str()+1);
@@ -528,3 +614,4 @@ struct HierarchyPass : public Pass {
}
} HierarchyPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 1b03ab55..8d4012c5 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -24,6 +24,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct SubmodWorker
{
CellTypes ct;
@@ -82,7 +85,7 @@ struct SubmodWorker
for (auto &conn : cell->connections())
flag_signal(conn.second, true, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first), false, false);
} else {
- log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+ log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
for (auto &conn : cell->connections())
flag_signal(conn.second, true, true, true, false, false);
}
@@ -99,7 +102,7 @@ struct SubmodWorker
for (auto &conn : cell->connections())
flag_signal(conn.second, false, false, false, true, true);
if (flag_found_something)
- log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
+ log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell->name.c_str(), cell->type.c_str());
}
}
@@ -347,3 +350,4 @@ struct SubmodPass : public Pass {
}
} SubmodPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index 026c5ff8..aeff225d 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -4,5 +4,6 @@ OBJS += passes/memory/memory_dff.o
OBJS += passes/memory/memory_share.o
OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o
+OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index fc309553..866efae7 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -22,13 +22,16 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct MemoryPass : public Pass {
MemoryPass() : Pass("memory", "translate memories to basic cells") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory [-nomap] [selection]\n");
+ log(" memory [-nomap] [-bram <bram_rules>] [selection]\n");
log("\n");
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
@@ -37,7 +40,8 @@ struct MemoryPass : public Pass {
log(" memory_share\n");
log(" opt_clean\n");
log(" memory_collect\n");
- log(" memory_map (skipped if called with -nomap)\n");
+ log(" memory_bram -rules <bram_rules> (when called with -bram)\n");
+ log(" memory_map (skipped if called with -nomap)\n");
log("\n");
log("This converts memories to word-wide DFFs and address decoders\n");
log("or multiport memory blocks if called with the -nomap option.\n");
@@ -46,6 +50,7 @@ struct MemoryPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_nomap = false;
+ string memory_bram_opts;
log_header("Executing MEMORY pass.\n");
log_push();
@@ -56,6 +61,10 @@ struct MemoryPass : public Pass {
flag_nomap = true;
continue;
}
+ if (argidx+1 < args.size() && args[argidx] == "-bram") {
+ memory_bram_opts += " -rules " + args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -66,6 +75,9 @@ struct MemoryPass : public Pass {
Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
+ if (!memory_bram_opts.empty())
+ Pass::call(design, "memory_bram" + memory_bram_opts);
+
if (!flag_nomap)
Pass::call(design, "memory_map");
@@ -73,3 +85,4 @@ struct MemoryPass : public Pass {
}
} MemoryPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
new file mode 100644
index 00000000..958cc88b
--- /dev/null
+++ b/passes/memory/memory_bram.cc
@@ -0,0 +1,1174 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct rules_t
+{
+ struct portinfo_t {
+ int group, index, dupidx;
+ int wrmode, enable, transp, clocks, clkpol;
+
+ SigBit sig_clock;
+ SigSpec sig_addr, sig_data, sig_en;
+ bool effective_clkpol;
+ bool make_transp;
+ int mapped_port;
+ };
+
+ struct bram_t {
+ IdString name;
+ int variant;
+
+ int groups, abits, dbits, init;
+ vector<int> ports, wrmode, enable, transp, clocks, clkpol;
+
+ void dump_config() const
+ {
+ log(" bram %s # variant %d\n", log_id(name), variant);
+ log(" init %d\n", init);
+ log(" abits %d\n", abits);
+ log(" dbits %d\n", dbits);
+ log(" groups %d\n", groups);
+
+ log(" ports "); for (int v : ports) log("%4d", v); log("\n");
+ log(" wrmode"); for (int v : wrmode) log("%4d", v); log("\n");
+ log(" enable"); for (int v : enable) log("%4d", v); log("\n");
+ log(" transp"); for (int v : transp) log("%4d", v); log("\n");
+ log(" clocks"); for (int v : clocks) log("%4d", v); log("\n");
+ log(" clkpol"); for (int v : clkpol) log("%4d", v); log("\n");
+ log(" endbram\n");
+ }
+
+ void check_vectors() const
+ {
+ if (groups != GetSize(ports)) log_error("Bram %s variant %d has %d groups but only %d entries in 'ports'.\n", log_id(name), variant, groups, GetSize(ports));
+ if (groups != GetSize(wrmode)) log_error("Bram %s variant %d has %d groups but only %d entries in 'wrmode'.\n", log_id(name), variant, groups, GetSize(wrmode));
+ if (groups != GetSize(enable)) log_error("Bram %s variant %d has %d groups but only %d entries in 'enable'.\n", log_id(name), variant, groups, GetSize(enable));
+ if (groups != GetSize(transp)) log_error("Bram %s variant %d has %d groups but only %d entries in 'transp'.\n", log_id(name), variant, groups, GetSize(transp));
+ if (groups != GetSize(clocks)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clocks'.\n", log_id(name), variant, groups, GetSize(clocks));
+ if (groups != GetSize(clkpol)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clkpol'.\n", log_id(name), variant, groups, GetSize(clkpol));
+ }
+
+ vector<portinfo_t> make_portinfos() const
+ {
+ vector<portinfo_t> portinfos;
+ for (int i = 0; i < groups; i++)
+ for (int j = 0; j < ports[i]; j++) {
+ portinfo_t pi;
+ pi.group = i;
+ pi.index = j;
+ pi.dupidx = 0;
+ pi.wrmode = wrmode[i];
+ pi.enable = enable[i];
+ pi.transp = transp[i];
+ pi.clocks = clocks[i];
+ pi.clkpol = clkpol[i];
+ pi.mapped_port = -1;
+ pi.make_transp = false;
+ pi.effective_clkpol = false;
+ portinfos.push_back(pi);
+ }
+ return portinfos;
+ }
+
+ void find_variant_params(dict<IdString, Const> &variant_params, const bram_t &other) const
+ {
+ log_assert(name == other.name);
+
+ if (groups != other.groups)
+ log_error("Bram %s variants %d and %d have different values for 'groups'.\n", log_id(name), variant, other.variant);
+
+ if (abits != other.abits)
+ variant_params["\\CFG_ABITS"] = abits;
+ if (dbits != other.dbits)
+ variant_params["\\CFG_DBITS"] = dbits;
+ if (init != other.init)
+ variant_params["\\CFG_INIT"] = init;
+
+ for (int i = 0; i < groups; i++)
+ {
+ if (ports[i] != other.ports[i])
+ log_error("Bram %s variants %d and %d have different number of %c-ports.\n", log_id(name), variant, other.variant, 'A'+i);
+ if (wrmode[i] != other.wrmode[i])
+ variant_params[stringf("\\CFG_WRMODE_%c", 'A' + i)] = wrmode[1];
+ if (enable[i] != other.enable[i])
+ variant_params[stringf("\\CFG_ENABLE_%c", 'A' + i)] = enable[1];
+ if (transp[i] != other.transp[i])
+ variant_params[stringf("\\CFG_TRANSP_%c", 'A' + i)] = transp[1];
+ if (clocks[i] != other.clocks[i])
+ variant_params[stringf("\\CFG_CLOCKS_%c", 'A' + i)] = clocks[1];
+ if (clkpol[i] != other.clkpol[i])
+ variant_params[stringf("\\CFG_CLKPOL_%c", 'A' + i)] = clkpol[1];
+ }
+ }
+ };
+
+ struct match_t {
+ IdString name;
+ dict<string, int> min_limits, max_limits;
+ bool or_next_if_better, make_transp;
+ char shuffle_enable;
+ };
+
+ dict<IdString, vector<bram_t>> brams;
+ vector<match_t> matches;
+
+ std::ifstream infile;
+ vector<string> tokens;
+ vector<string> labels;
+ int linecount;
+
+ void syntax_error()
+ {
+ if (tokens.empty())
+ log_error("Unexpected end of rules file in line %d.\n", linecount);
+ log_error("Syntax error in rules file line %d.\n", linecount);
+ }
+
+ bool next_line()
+ {
+ string line;
+ while (std::getline(infile, line)) {
+ tokens.clear();
+ labels.clear();
+ linecount++;
+ for (string tok = next_token(line); !tok.empty(); tok = next_token(line)) {
+ if (tok[0] == '@') {
+ labels.push_back(tok.substr(1));
+ continue;
+ }
+ if (tok[0] == '#')
+ break;
+ tokens.push_back(tok);
+ }
+ if (!tokens.empty())
+ return true;
+ }
+ return false;
+ }
+
+ bool parse_single_int(const char *stmt, int &value)
+ {
+ if (GetSize(tokens) == 2 && tokens[0] == stmt) {
+ value = atoi(tokens[1].c_str());
+ return true;
+ }
+ return false;
+ }
+
+ bool parse_int_vect(const char *stmt, vector<int> &value)
+ {
+ if (GetSize(tokens) >= 2 && tokens[0] == stmt) {
+ value.resize(GetSize(tokens)-1);
+ for (int i = 1; i < GetSize(tokens); i++)
+ value[i-1] = atoi(tokens[i].c_str());
+ return true;
+ }
+ return false;
+ }
+
+ void parse_bram()
+ {
+ IdString bram_name = RTLIL::escape_id(tokens[1]);
+
+ if (GetSize(tokens) != 2)
+ syntax_error();
+
+ vector<vector<string>> lines_nolabels;
+ std::map<string, vector<vector<string>>> lines_labels;
+
+ while (next_line())
+ {
+ if (GetSize(tokens) == 1 && tokens[0] == "endbram")
+ break;
+ if (labels.empty())
+ lines_nolabels.push_back(tokens);
+ for (auto lab : labels)
+ lines_labels[lab].push_back(tokens);
+ }
+
+ std::map<string, vector<vector<string>>> variant_lines;
+
+ if (lines_labels.empty())
+ variant_lines[""] = lines_nolabels;
+ for (auto &it : lines_labels) {
+ variant_lines[it.first] = lines_nolabels;
+ variant_lines[it.first].insert(variant_lines[it.first].end(), it.second.begin(), it.second.end());
+ }
+
+ for (auto &it : variant_lines)
+ {
+ bram_t data;
+ data.name = bram_name;
+ data.variant = GetSize(brams[data.name]) + 1;
+ data.groups = 0;
+ data.abits = 0;
+ data.dbits = 0;
+ data.init = 0;
+
+ for (auto &line_tokens : it.second)
+ {
+ tokens = line_tokens;
+
+ if (parse_single_int("groups", data.groups))
+ continue;
+
+ if (parse_single_int("abits", data.abits))
+ continue;
+
+ if (parse_single_int("dbits", data.dbits))
+ continue;
+
+ if (parse_single_int("init", data.init))
+ continue;
+
+ if (parse_int_vect("ports", data.ports))
+ continue;
+
+ if (parse_int_vect("wrmode", data.wrmode))
+ continue;
+
+ if (parse_int_vect("enable", data.enable))
+ continue;
+
+ if (parse_int_vect("transp", data.transp))
+ continue;
+
+ if (parse_int_vect("clocks", data.clocks))
+ continue;
+
+ if (parse_int_vect("clkpol", data.clkpol))
+ continue;
+
+ syntax_error();
+ }
+
+ data.check_vectors();
+ brams[data.name].push_back(data);
+ }
+ }
+
+ void parse_match()
+ {
+ if (GetSize(tokens) != 2)
+ syntax_error();
+
+ match_t data;
+ data.name = RTLIL::escape_id(tokens[1]);
+ data.or_next_if_better = false;
+ data.make_transp = false;
+ data.shuffle_enable = 0;
+
+ while (next_line())
+ {
+ if (!labels.empty())
+ syntax_error();
+
+ if (GetSize(tokens) == 1 && tokens[0] == "endmatch") {
+ matches.push_back(data);
+ break;
+ }
+
+ if (GetSize(tokens) == 3 && tokens[0] == "min") {
+ data.min_limits[tokens[1]] = atoi(tokens[2].c_str());
+ continue;
+ }
+
+ if (GetSize(tokens) == 3 && tokens[0] == "max") {
+ data.max_limits[tokens[1]] = atoi(tokens[2].c_str());
+ continue;
+ }
+
+ if (GetSize(tokens) == 2 && tokens[0] == "shuffle_enable" && GetSize(tokens[1]) == 1 && 'A' <= tokens[1][0] && tokens[1][0] <= 'Z') {
+ data.shuffle_enable = tokens[1][0];
+ continue;
+ }
+
+ if (GetSize(tokens) == 1 && tokens[0] == "make_transp") {
+ data.make_transp = true;
+ continue;
+ }
+
+ if (GetSize(tokens) == 1 && tokens[0] == "or_next_if_better") {
+ data.or_next_if_better = true;
+ continue;
+ }
+
+ syntax_error();
+ }
+ }
+
+ void parse(string filename)
+ {
+ if (filename.substr(0, 2) == "+/")
+ filename = proc_share_dirname() + filename.substr(1);
+
+ infile.open(filename);
+ linecount = 0;
+
+ if (infile.fail())
+ log_error("Can't open rules file `%s'.\n", filename.c_str());
+
+ while (next_line())
+ {
+ if (!labels.empty())
+ syntax_error();
+
+ if (tokens[0] == "bram") {
+ parse_bram();
+ continue;
+ }
+
+ if (tokens[0] == "match") {
+ parse_match();
+ continue;
+ }
+
+ syntax_error();
+ }
+
+ infile.close();
+ }
+};
+
+bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, const rules_t::match_t &match, dict<string, int> &match_properties, int mode)
+{
+ Module *module = cell->module;
+
+ auto portinfos = bram.make_portinfos();
+ int dup_count = 1;
+
+ pair<SigBit, bool> make_transp_clk;
+ bool enable_make_transp = false;
+ int make_transp_enbits = 0;
+
+ dict<int, pair<SigBit, bool>> clock_domains;
+ dict<int, bool> clock_polarities;
+ dict<int, bool> read_transp;
+ pool<int> clocks_wr_ports;
+ pool<int> clkpol_wr_ports;
+ int clocks_max = 0;
+ int clkpol_max = 0;
+ int transp_max = 0;
+
+ clock_polarities[0] = false;
+ clock_polarities[1] = true;
+
+ for (auto &pi : portinfos) {
+ if (pi.wrmode) {
+ clocks_wr_ports.insert(pi.clocks);
+ if (pi.clkpol > 1)
+ clkpol_wr_ports.insert(pi.clkpol);
+ }
+ clocks_max = std::max(clocks_max, pi.clocks);
+ clkpol_max = std::max(clkpol_max, pi.clkpol);
+ transp_max = std::max(transp_max, pi.transp);
+ }
+
+ log(" Mapping to bram type %s (variant %d):\n", log_id(bram.name), bram.variant);
+ // bram.dump_config();
+
+ int mem_size = cell->getParam("\\SIZE").as_int();
+ int mem_abits = cell->getParam("\\ABITS").as_int();
+ int mem_width = cell->getParam("\\WIDTH").as_int();
+ // int mem_offset = cell->getParam("\\OFFSET").as_int();
+
+ int wr_ports = cell->getParam("\\WR_PORTS").as_int();
+ auto wr_clken = SigSpec(cell->getParam("\\WR_CLK_ENABLE"));
+ auto wr_clkpol = SigSpec(cell->getParam("\\WR_CLK_POLARITY"));
+ wr_clken.extend_u0(wr_ports);
+ wr_clkpol.extend_u0(wr_ports);
+
+ SigSpec wr_en = cell->getPort("\\WR_EN");
+ SigSpec wr_clk = cell->getPort("\\WR_CLK");
+ SigSpec wr_data = cell->getPort("\\WR_DATA");
+ SigSpec wr_addr = cell->getPort("\\WR_ADDR");
+
+ int rd_ports = cell->getParam("\\RD_PORTS").as_int();
+ auto rd_clken = SigSpec(cell->getParam("\\RD_CLK_ENABLE"));
+ auto rd_clkpol = SigSpec(cell->getParam("\\RD_CLK_POLARITY"));
+ auto rd_transp = SigSpec(cell->getParam("\\RD_TRANSPARENT"));
+ rd_clken.extend_u0(rd_ports);
+ rd_clkpol.extend_u0(rd_ports);
+ rd_transp.extend_u0(rd_ports);
+
+ SigSpec rd_clk = cell->getPort("\\RD_CLK");
+ SigSpec rd_data = cell->getPort("\\RD_DATA");
+ SigSpec rd_addr = cell->getPort("\\RD_ADDR");
+
+ if (match.shuffle_enable && bram.dbits >= portinfos.at(match.shuffle_enable - 'A').enable*2 && portinfos.at(match.shuffle_enable - 'A').enable > 0)
+ {
+ int bucket_size = bram.dbits / portinfos.at(match.shuffle_enable - 'A').enable;
+ log(" Shuffle bit order to accommodate enable buckets of size %d..\n", bucket_size);
+
+ // extract unshuffled data/enable bits
+
+ std::vector<SigSpec> old_wr_en;
+ std::vector<SigSpec> old_wr_data;
+ std::vector<SigSpec> old_rd_data;
+
+ for (int i = 0; i < wr_ports; i++) {
+ old_wr_en.push_back(wr_en.extract(i*mem_width, mem_width));
+ old_wr_data.push_back(wr_data.extract(i*mem_width, mem_width));
+ }
+
+ for (int i = 0; i < rd_ports; i++)
+ old_rd_data.push_back(rd_data.extract(i*mem_width, mem_width));
+
+ // analyze enable structure
+
+ std::vector<SigSpec> en_order;
+ dict<SigSpec, vector<int>> bits_wr_en;
+
+ for (int i = 0; i < mem_width; i++) {
+ SigSpec sig;
+ for (int j = 0; j < wr_ports; j++)
+ sig.append(old_wr_en[j][i]);
+ if (bits_wr_en.count(sig) == 0)
+ en_order.push_back(sig);
+ bits_wr_en[sig].push_back(i);
+ }
+
+ // re-create memory ports
+
+ std::vector<SigSpec> new_wr_en(GetSize(old_wr_en));
+ std::vector<SigSpec> new_wr_data(GetSize(old_wr_data));
+ std::vector<SigSpec> new_rd_data(GetSize(old_rd_data));
+ std::vector<int> shuffle_map;
+
+ for (auto &it : en_order)
+ {
+ auto &bits = bits_wr_en.at(it);
+ int buckets = (GetSize(bits) + bucket_size - 1) / bucket_size;
+ int fillbits = buckets*bucket_size - GetSize(bits);
+ SigBit fillbit;
+
+ for (int i = 0; i < GetSize(bits); i++) {
+ for (int j = 0; j < wr_ports; j++) {
+ new_wr_en[j].append(old_wr_en[j][bits[i]]);
+ new_wr_data[j].append(old_wr_data[j][bits[i]]);
+ fillbit = old_wr_en[j][bits[i]];
+ }
+ for (int j = 0; j < rd_ports; j++)
+ new_rd_data[j].append(old_rd_data[j][bits[i]]);
+ shuffle_map.push_back(bits[i]);
+ }
+
+ for (int i = 0; i < fillbits; i++) {
+ for (int j = 0; j < wr_ports; j++) {
+ new_wr_en[j].append(fillbit);
+ new_wr_data[j].append(State::S0);
+ }
+ for (int j = 0; j < rd_ports; j++)
+ new_rd_data[j].append(State::Sx);
+ shuffle_map.push_back(-1);
+ }
+ }
+
+ log(" Results of bit order shuffling:");
+ for (int v : shuffle_map)
+ log(" %d", v);
+ log("\n");
+
+ // update mem_*, wr_*, and rd_* variables
+
+ mem_width = GetSize(new_wr_en.front());
+ wr_en = SigSpec(0, wr_ports * mem_width);
+ wr_data = SigSpec(0, wr_ports * mem_width);
+ rd_data = SigSpec(0, rd_ports * mem_width);
+
+ for (int i = 0; i < wr_ports; i++) {
+ wr_en.replace(i*mem_width, new_wr_en[i]);
+ wr_data.replace(i*mem_width, new_wr_data[i]);
+ }
+
+ for (int i = 0; i < rd_ports; i++)
+ rd_data.replace(i*mem_width, new_rd_data[i]);
+ }
+
+ // assign write ports
+
+ for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
+ {
+ bool clken = wr_clken[cell_port_i] == State::S1;
+ bool clkpol = wr_clkpol[cell_port_i] == State::S1;
+ SigBit clksig = wr_clk[cell_port_i];
+
+ pair<SigBit, bool> clkdom(clksig, clkpol);
+ if (!clken)
+ clkdom = pair<SigBit, bool>(State::S1, false);
+
+ log(" Write port #%d is in clock domain %s%s.\n",
+ cell_port_i, clkdom.second ? "" : "!",
+ clken ? log_signal(clkdom.first) : "~async~");
+
+ for (; bram_port_i < GetSize(portinfos); bram_port_i++)
+ {
+ auto &pi = portinfos[bram_port_i];
+ make_transp_enbits = pi.enable;
+ make_transp_clk = clkdom;
+
+ if (pi.wrmode != 1)
+ skip_bram_wport:
+ continue;
+
+ if (clken) {
+ if (pi.clocks == 0) {
+ log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ if (clock_domains.count(pi.clocks) && clock_domains.at(pi.clocks) != clkdom) {
+ log(" Bram port %c%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ log(" Bram port %c%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ } else {
+ if (pi.clocks != 0) {
+ log(" Bram port %c%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ }
+
+ SigSpec sig_en;
+ SigBit last_en_bit = State::S1;
+ for (int i = 0; i < mem_width; i++) {
+ if (pi.enable && i % (bram.dbits / pi.enable) == 0) {
+ last_en_bit = wr_en[i + cell_port_i*mem_width];
+ sig_en.append(last_en_bit);
+ }
+ if (last_en_bit != wr_en[i + cell_port_i*mem_width]) {
+ log(" Bram port %c%d has incompatible enable structure.\n", pi.group + 'A', pi.index + 1);
+ goto skip_bram_wport;
+ }
+ }
+
+ log(" Mapped to bram port %c%d.\n", pi.group + 'A', pi.index + 1);
+ pi.mapped_port = cell_port_i;
+
+ if (clken) {
+ clock_domains[pi.clocks] = clkdom;
+ clock_polarities[pi.clkpol] = clkdom.second;
+ pi.sig_clock = clkdom.first;
+ pi.effective_clkpol = clkdom.second;
+ }
+
+ pi.sig_en = sig_en;
+ pi.sig_addr = wr_addr.extract(cell_port_i*mem_abits, mem_abits);
+ pi.sig_data = wr_data.extract(cell_port_i*mem_width, mem_width);
+
+ bram_port_i++;
+ goto mapped_wr_port;
+ }
+
+ log(" Failed to map write port #%d.\n", cell_port_i);
+ return false;
+ mapped_wr_port:;
+ }
+
+ // houskeeping stuff for growing more read ports and restarting read port assignments
+
+ int grow_read_ports_cursor = -1;
+ bool try_growing_more_read_ports = false;
+ auto backup_clock_domains = clock_domains;
+ auto backup_clock_polarities = clock_polarities;
+
+ if (0) {
+grow_read_ports:;
+ vector<rules_t::portinfo_t> new_portinfos;
+ for (auto &pi : portinfos) {
+ if (pi.wrmode == 0) {
+ pi.mapped_port = -1;
+ pi.sig_clock = SigBit();
+ pi.sig_addr = SigSpec();
+ pi.sig_data = SigSpec();
+ pi.sig_en = SigSpec();
+ }
+ new_portinfos.push_back(pi);
+ if (pi.dupidx == dup_count-1) {
+ if (pi.clocks && !clocks_wr_ports[pi.clocks])
+ pi.clocks += clocks_max;
+ if (pi.clkpol > 1 && !clkpol_wr_ports[pi.clkpol])
+ pi.clkpol += clkpol_max;
+ if (pi.transp > 1)
+ pi.transp += transp_max;
+ pi.dupidx++;
+ new_portinfos.push_back(pi);
+ }
+ }
+ try_growing_more_read_ports = false;
+ portinfos.swap(new_portinfos);
+ clock_domains = backup_clock_domains;
+ clock_polarities = backup_clock_polarities;
+ dup_count++;
+ }
+
+ read_transp.clear();
+ read_transp[0] = false;
+ read_transp[1] = true;
+
+ // assign read ports
+
+ for (int cell_port_i = 0; cell_port_i < rd_ports; cell_port_i++)
+ {
+ bool clken = rd_clken[cell_port_i] == State::S1;
+ bool clkpol = rd_clkpol[cell_port_i] == State::S1;
+ bool transp = rd_transp[cell_port_i] == State::S1;
+ SigBit clksig = rd_clk[cell_port_i];
+
+ pair<SigBit, bool> clkdom(clksig, clkpol);
+ if (!clken)
+ clkdom = pair<SigBit, bool>(State::S1, false);
+
+ log(" Read port #%d is in clock domain %s%s.\n",
+ cell_port_i, clkdom.second ? "" : "!",
+ clken ? log_signal(clkdom.first) : "~async~");
+
+ for (int bram_port_i = 0; bram_port_i < GetSize(portinfos); bram_port_i++)
+ {
+ auto &pi = portinfos[bram_port_i];
+
+ if (pi.wrmode != 0 || pi.mapped_port >= 0)
+ skip_bram_rport:
+ continue;
+
+ if (clken) {
+ if (pi.clocks == 0) {
+ log(" Bram port %c%d.%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ if (clock_domains.count(pi.clocks) && clock_domains.at(pi.clocks) != clkdom) {
+ log(" Bram port %c%d.%d is in a different clock domain.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ if (clock_polarities.count(pi.clkpol) && clock_polarities.at(pi.clkpol) != clkpol) {
+ log(" Bram port %c%d.%d has incompatible clock polarity.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
+ if (match.make_transp && wr_ports <= 1) {
+ pi.make_transp = true;
+ enable_make_transp = true;
+ } else {
+ log(" Bram port %c%d.%d has incompatible read transparancy.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ }
+ } else {
+ if (pi.clocks != 0) {
+ log(" Bram port %c%d.%d has incompatible clock type.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ }
+
+ log(" Mapped to bram port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ pi.mapped_port = cell_port_i;
+
+ if (clken) {
+ clock_domains[pi.clocks] = clkdom;
+ clock_polarities[pi.clkpol] = clkdom.second;
+ read_transp[pi.transp] = transp;
+ pi.sig_clock = clkdom.first;
+ pi.effective_clkpol = clkdom.second;
+ }
+
+ pi.sig_addr = rd_addr.extract(cell_port_i*mem_abits, mem_abits);
+ pi.sig_data = rd_data.extract(cell_port_i*mem_width, mem_width);
+
+ if (grow_read_ports_cursor < cell_port_i) {
+ grow_read_ports_cursor = cell_port_i;
+ try_growing_more_read_ports = true;
+ }
+
+ goto mapped_rd_port;
+ }
+
+ log(" Failed to map read port #%d.\n", cell_port_i);
+ if (try_growing_more_read_ports) {
+ log(" Growing more read ports by duplicating bram cells.\n");
+ goto grow_read_ports;
+ }
+ return false;
+ mapped_rd_port:;
+ }
+
+ // update properties and re-check conditions
+
+ if (mode <= 1)
+ {
+ match_properties["dups"] = dup_count;
+ match_properties["waste"] = match_properties["dups"] * match_properties["bwaste"];
+
+ int cells = ((mem_width + bram.dbits - 1) / bram.dbits) * ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ match_properties["efficiency"] = (100 * match_properties["bits"]) / (dup_count * cells * bram.dbits * (1 << bram.abits));
+
+ match_properties["dcells"] = ((mem_width + bram.dbits - 1) / bram.dbits);
+ match_properties["acells"] = ((mem_size + (1 << bram.abits) - 1) / (1 << bram.abits));
+ match_properties["cells"] = match_properties["dcells"] * match_properties["acells"] * match_properties["dups"];
+
+ log(" Updated properties: dups=%d waste=%d efficiency=%d\n",
+ match_properties["dups"], match_properties["waste"], match_properties["efficiency"]);
+
+ for (auto it : match.min_limits) {
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] >= it.second)
+ continue;
+ log(" Rule for bram type %s rejected: requirement 'min %s %d' not met.\n",
+ log_id(match.name), it.first.c_str(), it.second);
+ return false;
+ }
+ for (auto it : match.max_limits) {
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] <= it.second)
+ continue;
+ log(" Rule for bram type %s rejected: requirement 'max %s %d' not met.\n",
+ log_id(match.name), it.first.c_str(), it.second);
+ return false;
+ }
+
+ if (mode == 1)
+ return true;
+ }
+
+ // prepare variant parameters
+
+ dict<IdString, Const> variant_params;
+ for (auto &other_bram : rules.brams.at(bram.name))
+ bram.find_variant_params(variant_params, other_bram);
+
+ // actually replace that memory cell
+
+ dict<SigSpec, pair<SigSpec, SigSpec>> dout_cache;
+
+ for (int grid_d = 0; grid_d*bram.dbits < mem_width; grid_d++)
+ {
+ SigSpec mktr_wraddr, mktr_wrdata, mktr_wrdata_q;
+ vector<SigSpec> mktr_wren;
+
+ if (enable_make_transp) {
+ mktr_wraddr = module->addWire(NEW_ID, bram.abits);
+ mktr_wrdata = module->addWire(NEW_ID, bram.dbits);
+ mktr_wrdata_q = module->addWire(NEW_ID, bram.dbits);
+ module->addDff(NEW_ID, make_transp_clk.first, mktr_wrdata, mktr_wrdata_q, make_transp_clk.second);
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ mktr_wren.push_back(module->addWire(NEW_ID, make_transp_enbits));
+ }
+
+ for (int grid_a = 0; grid_a*(1 << bram.abits) < mem_size; grid_a++)
+ for (int dupidx = 0; dupidx < dup_count; dupidx++)
+ {
+ Cell *c = module->addCell(module->uniquify(stringf("%s.%d.%d.%d", cell->name.c_str(), grid_d, grid_a, dupidx)), bram.name);
+ log(" Creating %s cell at grid position <%d %d %d>: %s\n", log_id(bram.name), grid_d, grid_a, dupidx, log_id(c));
+
+ for (auto &vp : variant_params)
+ c->setParam(vp.first, vp.second);
+
+ for (auto &pi : portinfos)
+ {
+ if (pi.dupidx != dupidx)
+ continue;
+
+ string prefix = stringf("%c%d", pi.group + 'A', pi.index + 1);
+ const char *pf = prefix.c_str();
+
+ if (pi.clocks && (!c->hasPort(stringf("\\CLK%d", (pi.clocks-1) % clocks_max + 1)) || pi.sig_clock.wire)) {
+ c->setPort(stringf("\\CLK%d", (pi.clocks-1) % clocks_max + 1), pi.sig_clock);
+ if (pi.clkpol > 1 && pi.sig_clock.wire)
+ c->setParam(stringf("\\CLKPOL%d", (pi.clkpol-1) % clkpol_max + 1), clock_polarities.at(pi.clkpol));
+ if (pi.transp > 1 && pi.sig_clock.wire)
+ c->setParam(stringf("\\TRANSP%d", (pi.transp-1) % transp_max + 1), read_transp.at(pi.transp));
+ }
+
+ SigSpec addr_ok;
+ if (GetSize(pi.sig_addr) > bram.abits) {
+ SigSpec extra_addr = pi.sig_addr.extract(bram.abits, GetSize(pi.sig_addr) - bram.abits);
+ SigSpec extra_addr_sel = SigSpec(grid_a, GetSize(extra_addr));
+ addr_ok = module->Eq(NEW_ID, extra_addr, extra_addr_sel);
+ }
+
+ if (pi.enable)
+ {
+ SigSpec sig_en = pi.sig_en;
+ sig_en.extend_u0((grid_d+1) * pi.enable);
+ sig_en = sig_en.extract(grid_d * pi.enable, pi.enable);
+
+ if (!addr_ok.empty())
+ sig_en = module->Mux(NEW_ID, SigSpec(0, GetSize(sig_en)), sig_en, addr_ok);
+
+ c->setPort(stringf("\\%sEN", pf), sig_en);
+
+ if (pi.wrmode == 1 && enable_make_transp)
+ module->connect(mktr_wren[grid_a], sig_en);
+ }
+
+ SigSpec sig_addr = pi.sig_addr;
+ sig_addr.extend_u0(bram.abits);
+ c->setPort(stringf("\\%sADDR", pf), sig_addr);
+
+ if (pi.wrmode == 1 && enable_make_transp && grid_a == 0)
+ module->connect(mktr_wraddr, sig_addr);
+
+ SigSpec sig_data = pi.sig_data;
+ sig_data.extend_u0((grid_d+1) * bram.dbits);
+ sig_data = sig_data.extract(grid_d * bram.dbits, bram.dbits);
+
+ if (pi.wrmode == 1) {
+ c->setPort(stringf("\\%sDATA", pf), sig_data);
+ if (enable_make_transp && grid_a == 0)
+ module->connect(mktr_wrdata, sig_data);
+ } else {
+ SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
+ c->setPort(stringf("\\%sDATA", pf), bram_dout);
+
+ if (pi.make_transp)
+ {
+ log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+
+ SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
+ mktr_wren[grid_a], module->Eq(NEW_ID, mktr_wraddr, sig_addr));
+
+ SigSpec transp_en_q = module->addWire(NEW_ID, make_transp_enbits);
+ module->addDff(NEW_ID, make_transp_clk.first, transp_en_d, transp_en_q, make_transp_clk.second);
+
+ for (int i = 0; i < make_transp_enbits; i++) {
+ int en_width = bram.dbits / make_transp_enbits;
+ SigSpec orig_bram_dout = bram_dout.extract(i * en_width, en_width);
+ SigSpec bypass_dout = mktr_wrdata_q.extract(i * en_width, en_width);
+ bram_dout.replace(i * en_width, module->Mux(NEW_ID, orig_bram_dout, bypass_dout, transp_en_q[i]));
+ }
+ }
+
+ for (int i = bram.dbits-1; i >= 0; i--)
+ if (sig_data[i].wire == nullptr) {
+ sig_data.remove(i);
+ bram_dout.remove(i);
+ }
+
+ SigSpec addr_ok_q = addr_ok;
+ if (pi.clocks && !addr_ok.empty()) {
+ addr_ok_q = module->addWire(NEW_ID);
+ module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol);
+ }
+
+ dout_cache[sig_data].first.append(addr_ok_q);
+ dout_cache[sig_data].second.append(bram_dout);
+ }
+ }
+ }
+ }
+
+ for (auto &it : dout_cache)
+ {
+ if (it.second.first.empty())
+ {
+ log_assert(GetSize(it.first) == GetSize(it.second.second));
+ module->connect(it.first, it.second.second);
+ }
+ else
+ {
+ log_assert(GetSize(it.first)*GetSize(it.second.first) == GetSize(it.second.second));
+ module->addPmux(NEW_ID, SigSpec(State::Sx, GetSize(it.first)), it.second.second, it.second.first, it.first);
+ }
+ }
+
+ module->remove(cell);
+ return true;
+}
+
+void handle_cell(Cell *cell, const rules_t &rules)
+{
+ log("Processing %s.%s:\n", log_id(cell->module), log_id(cell));
+
+ if (!SigSpec(cell->getParam("\\INIT")).is_fully_undef()) {
+ log(" initialized memories are not supported yet.");
+ return;
+ }
+
+ dict<string, int> match_properties;
+ match_properties["words"] = cell->getParam("\\SIZE").as_int();
+ match_properties["abits"] = cell->getParam("\\ABITS").as_int();
+ match_properties["dbits"] = cell->getParam("\\WIDTH").as_int();
+ match_properties["wports"] = cell->getParam("\\WR_PORTS").as_int();
+ match_properties["rports"] = cell->getParam("\\RD_PORTS").as_int();
+ match_properties["bits"] = match_properties["words"] * match_properties["dbits"];
+ match_properties["ports"] = match_properties["wports"] + match_properties["rports"];
+
+ log(" Properties:");
+ for (auto &it : match_properties)
+ log(" %s=%d", it.first.c_str(), it.second);
+ log("\n");
+
+ pool<pair<IdString, int>> failed_brams;
+ dict<pair<int, int>, std::tuple<int, int, int>> best_rule_cache;
+
+ for (int i = 0; i < GetSize(rules.matches); i++)
+ {
+ auto &match = rules.matches.at(i);
+
+ if (!rules.brams.count(rules.matches[i].name))
+ log_error("No bram description for resource %s found!\n", log_id(rules.matches[i].name));
+
+ for (int vi = 0; vi < GetSize(rules.brams.at(match.name)); vi++)
+ {
+ auto &bram = rules.brams.at(match.name).at(vi);
+ bool or_next_if_better = match.or_next_if_better || vi+1 < GetSize(rules.brams.at(match.name));
+
+ if (failed_brams.count(pair<IdString, int>(bram.name, bram.variant)))
+ continue;
+
+ int avail_rd_ports = 0;
+ int avail_wr_ports = 0;
+ for (int j = 0; j < bram.groups; j++) {
+ if (GetSize(bram.wrmode) < j || bram.wrmode.at(j) == 0)
+ avail_rd_ports += GetSize(bram.ports) < j ? bram.ports.at(j) : 0;
+ if (GetSize(bram.wrmode) < j || bram.wrmode.at(j) != 0)
+ avail_wr_ports += GetSize(bram.ports) < j ? bram.ports.at(j) : 0;
+ }
+
+ log(" Checking rule #%d for bram type %s (variant %d):\n", i+1, log_id(bram.name), bram.variant);
+ log(" Bram geometry: abits=%d dbits=%d wports=%d rports=%d\n", bram.abits, bram.dbits, avail_wr_ports, avail_rd_ports);
+
+ int dups = avail_rd_ports ? (match_properties["rports"] + avail_rd_ports - 1) / avail_rd_ports : 1;
+ match_properties["dups"] = dups;
+
+ log(" Estimated number of duplicates for more read ports: dups=%d\n", match_properties["dups"]);
+
+ int aover = match_properties["words"] % (1 << bram.abits);
+ int awaste = aover ? (1 << bram.abits) - aover : 0;
+ match_properties["awaste"] = awaste;
+
+ int dover = match_properties["dbits"] % bram.dbits;
+ int dwaste = dover ? bram.dbits - dover : 0;
+ match_properties["dwaste"] = dwaste;
+
+ int bwaste = awaste * bram.dbits + dwaste * (1 << bram.abits) - awaste * dwaste;
+ match_properties["bwaste"] = bwaste;
+
+ int waste = match_properties["dups"] * bwaste;
+ match_properties["waste"] = waste;
+
+ int cells = ((match_properties["dbits"] + bram.dbits - 1) / bram.dbits) * ((match_properties["words"] + (1 << bram.abits) - 1) / (1 << bram.abits));
+ int efficiency = (100 * match_properties["bits"]) / (dups * cells * bram.dbits * (1 << bram.abits));
+ match_properties["efficiency"] = efficiency;
+
+ log(" Metrics for %s: awaste=%d dwaste=%d bwaste=%d waste=%d efficiency=%d\n",
+ log_id(match.name), awaste, dwaste, bwaste, waste, efficiency);
+
+ for (auto it : match.min_limits) {
+ if (it.first == "waste" || it.first == "dups" || it.first == "acells" || it.first == "dcells" || it.first == "cells")
+ continue;
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] >= it.second)
+ continue;
+ log(" Rule #%d for bram type %s (variant %d) rejected: requirement 'min %s %d' not met.\n",
+ i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
+ goto next_match_rule;
+ }
+ for (auto it : match.max_limits) {
+ if (it.first == "acells" || it.first == "dcells" || it.first == "cells")
+ continue;
+ if (!match_properties.count(it.first))
+ log_error("Unknown property '%s' in match rule for bram type %s.\n",
+ it.first.c_str(), log_id(match.name));
+ if (match_properties[it.first] <= it.second)
+ continue;
+ log(" Rule #%d for bram type %s (variant %d) rejected: requirement 'max %s %d' not met.\n",
+ i+1, log_id(bram.name), bram.variant, it.first.c_str(), it.second);
+ goto next_match_rule;
+ }
+
+ log(" Rule #%d for bram type %s (variant %d) accepted.\n", i+1, log_id(bram.name), bram.variant);
+
+ if (or_next_if_better || !best_rule_cache.empty())
+ {
+ if (or_next_if_better && i+1 == GetSize(rules.matches) && vi+1 == GetSize(rules.brams.at(match.name)))
+ log_error("Found 'or_next_if_better' in last match rule.\n");
+
+ if (!replace_cell(cell, rules, bram, match, match_properties, 1)) {
+ log(" Mapping to bram type %s failed.\n", log_id(match.name));
+ failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
+ goto next_match_rule;
+ }
+
+ log(" Storing for later selection.\n");
+ best_rule_cache[pair<int, int>(i, vi)] = std::tuple<int, int, int>(match_properties["efficiency"], -match_properties["cells"], -match_properties["acells"]);
+
+ if (or_next_if_better)
+ goto next_match_rule;
+
+ next_match_rule:
+ if (or_next_if_better || best_rule_cache.empty())
+ continue;
+
+ log(" Selecting best of %d rules:\n", GetSize(best_rule_cache));
+ pair<int, int> best_rule = best_rule_cache.begin()->first;
+
+ for (auto &it : best_rule_cache) {
+ if (it.second > best_rule_cache[best_rule])
+ best_rule = it.first;
+ log(" Efficiency for rule %d.%d: efficiency=%d, cells=%d, acells=%d\n", it.first.first+1, it.first.second+1,
+ std::get<0>(it.second), -std::get<1>(it.second), -std::get<2>(it.second));
+ }
+
+ log(" Selected rule %d.%d with efficiency %d.\n", best_rule.first+1, best_rule.second+1, std::get<0>(best_rule_cache[best_rule]));
+ best_rule_cache.clear();
+
+ auto &best_bram = rules.brams.at(rules.matches.at(best_rule.first).name).at(best_rule.second);
+ if (!replace_cell(cell, rules, best_bram, rules.matches.at(best_rule.first), match_properties, 2))
+ log_error("Mapping to bram type %s (variant %d) after pre-selection failed.\n", log_id(best_bram.name), best_bram.variant);
+ return;
+ }
+
+ if (!replace_cell(cell, rules, bram, match, match_properties, 0)) {
+ log(" Mapping to bram type %s failed.\n", log_id(match.name));
+ failed_brams.insert(pair<IdString, int>(bram.name, bram.variant));
+ goto next_match_rule;
+ }
+ return;
+ }
+ }
+
+ log(" No acceptable bram resources found.\n");
+}
+
+struct MemoryBramPass : public Pass {
+ MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_bram -rules <rule_file> [selection]\n");
+ log("\n");
+ log("This pass converts the multi-port $mem memory cells into block ram instances.\n");
+ log("The given rules file describes the available resources and how they should be\n");
+ log("used.\n");
+ log("\n");
+ log("The rules file contains a set of block ram description and a sequence of match\n");
+ log("rules. A block ram description looks like this:\n");
+ log("\n");
+ log(" bram RAMB1024X32 # name of BRAM cell\n");
+ // log(" init 1 # set to '1' if BRAM can be initialized\n");
+ log(" abits 10 # number of address bits\n");
+ log(" dbits 32 # number of data bits\n");
+ log(" groups 2 # number of port groups\n");
+ log(" ports 1 1 # number of ports in each group\n");
+ log(" wrmode 1 0 # set to '1' if this groups is write ports\n");
+ log(" enable 4 0 # number of enable bits (for write ports)\n");
+ log(" transp 0 2 # transparatent (for read ports)\n");
+ log(" clocks 1 2 # clock configuration\n");
+ log(" clkpol 2 2 # clock polarity configuration\n");
+ log(" endbram\n");
+ log("\n");
+ log("For the option 'transp' the value 0 means non-transparent, 1 means transparent\n");
+ log("and a value greater than 1 means configurable. All groups with the same\n");
+ log("value greater than 1 share the same configuration bit.\n");
+ log("\n");
+ log("For the option 'clocks' the value 0 means non-clocked, and a value greater\n");
+ log("than 0 means clocked. All groups with the same value share the same clock\n");
+ log("signal.\n");
+ log("\n");
+ log("For the option 'clkpol' the value 0 means negative edge, 1 means positive edge\n");
+ log("and a value greater than 1 means configurable. All groups with the same value\n");
+ log("greater than 1 share the same configuration bit.\n");
+ log("\n");
+ log("Using the same bram name in different bram blocks will create different variants\n");
+ log("of the bram. Verilog configration parameters for the bram are created as needed.\n");
+ log("\n");
+ log("It is also possible to create variants by repeating statements in the bram block\n");
+ log("and appending '@<label>' to the individual statements.\n");
+ log("\n");
+ log("A match rule looks like this:\n");
+ log("\n");
+ log(" match RAMB1024X32\n");
+ log(" max waste 16384 # only use this bram if <= 16k ram bits are unused\n");
+ log(" min efficiency 80 # only use this bram if efficiency is at least 80%%\n");
+ log(" endmatch\n");
+ log("\n");
+ log("It is possible to match against the following values with min/max rules:\n");
+ log("\n");
+ log(" words ........ number of words in memory in design\n");
+ log(" abits ........ number of address bits on memory in design\n");
+ log(" dbits ........ number of data bits on memory in design\n");
+ log(" wports ....... number of write ports on memory in design\n");
+ log(" rports ....... number of read ports on memory in design\n");
+ log(" ports ........ number of ports on memory in design\n");
+ log(" bits ......... number of bits in memory in design\n");
+ log(" dups .......... number of duplications for more read ports\n");
+ log("\n");
+ log(" awaste ....... number of unused address slots for this match\n");
+ log(" dwaste ....... number of unused data bits for this match\n");
+ log(" bwaste ....... number of unused bram bits for this match\n");
+ log(" waste ........ total number of unused bram bits (bwaste*dups)\n");
+ log(" efficiency ... total percentage of used and non-duplicated bits\n");
+ log("\n");
+ log(" acells ....... number of cells in 'address-direction'\n");
+ log(" dcells ....... number of cells in 'data-direction'\n");
+ log(" cells ........ total number of cells (acells*dcells*dups)\n");
+ log("\n");
+ log("The interface for the created bram instances is dervived from the bram\n");
+ log("description. Use 'techmap' to convert the created bram instances into\n");
+ log("instances of the actual bram cells of your target architecture.\n");
+ log("\n");
+ log("A match containing the command 'or_next_if_better' is only used if it\n");
+ log("has a higher efficiency than the next match (and the one after that if\n");
+ log("the next also has 'or_next_if_better' set, and so forth).\n");
+ log("\n");
+ log("A match containing the command 'make_transp' will add external circuitry\n");
+ log("to simulate 'transparent read', if necessary.\n");
+ log("\n");
+ log("A match containing the command 'shuffle_enable A' will re-organize\n");
+ log("the data bits to accommodate the enable pattern of port A.\n");
+ log("\n");
+ }
+ virtual void execute(vector<string> args, Design *design)
+ {
+ rules_t rules;
+
+ log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-rules" && argidx+1 < args.size()) {
+ rules.parse(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ for (auto cell : mod->selected_cells())
+ if (cell->type == "$mem")
+ handle_cell(cell, rules);
+ }
+} MemoryBramPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 9c670f00..96d0ada0 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -17,13 +17,13 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/log.h"
-#include <sstream>
-#include <algorithm>
-#include <stdlib.h>
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
-static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
if (a->type == "$memrd" && b->type == "$memrd")
return a->name < b->name;
@@ -32,14 +32,15 @@ static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
return a->parameters.at("\\PRIORITY").as_int() < b->parameters.at("\\PRIORITY").as_int();
}
-static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
+void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
{
- log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n",
+ log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
int addr_bits = 0;
- while ((1 << addr_bits) < memory->size)
- addr_bits++;
+
+ Const init_data(State::Sx, memory->size * memory->width);
+ SigMap sigmap(module);
int wr_ports = 0;
RTLIL::SigSpec sig_wr_clk;
@@ -57,37 +58,64 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
RTLIL::SigSpec sig_rd_addr;
RTLIL::SigSpec sig_rd_data;
- std::vector<RTLIL::Cell*> del_cells;
std::vector<RTLIL::Cell*> memcells;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string())
+ if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) {
+ addr_bits = std::max(addr_bits, cell->getParam("\\ABITS").as_int());
memcells.push_back(cell);
+ }
+ }
+
+ if (memcells.empty()) {
+ log(" no cells found. removing memory.\n");
+ return;
}
std::sort(memcells.begin(), memcells.end(), memcells_cmp);
for (auto cell : memcells)
{
- if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string())
+ log(" %s (%s)\n", log_id(cell), log_id(cell->type));
+
+ if (cell->type == "$meminit")
{
- wr_ports++;
- del_cells.push_back(cell);
-
- RTLIL::SigSpec clk = cell->getPort("\\CLK");
- RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
- RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
- RTLIL::SigSpec addr = cell->getPort("\\ADDR");
- RTLIL::SigSpec data = cell->getPort("\\DATA");
- RTLIL::SigSpec en = cell->getPort("\\EN");
-
- clk.extend(1, false);
- clk_enable.extend(1, false);
- clk_polarity.extend(1, false);
- addr.extend(addr_bits, false);
- data.extend(memory->width, false);
- en.extend(memory->width, false);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+
+ if (!addr.is_fully_const())
+ log_error("Non-constant address %s in memory initialization %s.\n", log_signal(addr), log_id(cell));
+ if (!data.is_fully_const())
+ log_error("Non-constant data %s in memory initialization %s.\n", log_signal(data), log_id(cell));
+
+ int offset = (addr.as_int() - memory->start_offset) * memory->width;
+
+ if (offset < 0 || offset + GetSize(data) > GetSize(init_data))
+ log_warning("Address %s in memory initialization %s is out-of-bounds.\n", log_signal(addr), log_id(cell));
+
+ for (int i = 0; i < GetSize(data); i++)
+ if (0 <= i+offset && i+offset < GetSize(init_data))
+ init_data.bits[i+offset] = data[i].data;
+
+ continue;
+ }
+
+ if (cell->type == "$memwr")
+ {
+ SigSpec clk = sigmap(cell->getPort("\\CLK"));
+ SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+ SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+ SigSpec en = sigmap(cell->getPort("\\EN"));
+
+ clk.extend_u0(1, false);
+ clk_enable.extend_u0(1, false);
+ clk_polarity.extend_u0(1, false);
+ addr.extend_u0(addr_bits, false);
+ data.extend_u0(memory->width, false);
+ en.extend_u0(memory->width, false);
sig_wr_clk.append(clk);
sig_wr_clk_enable.append(clk_enable);
@@ -95,26 +123,26 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_wr_addr.append(addr);
sig_wr_data.append(data);
sig_wr_en.append(en);
+
+ wr_ports++;
+ continue;
}
- if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string())
+ if (cell->type == "$memrd")
{
- rd_ports++;
- del_cells.push_back(cell);
-
- RTLIL::SigSpec clk = cell->getPort("\\CLK");
- RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
- RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
- RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]);
- RTLIL::SigSpec addr = cell->getPort("\\ADDR");
- RTLIL::SigSpec data = cell->getPort("\\DATA");
-
- clk.extend(1, false);
- clk_enable.extend(1, false);
- clk_polarity.extend(1, false);
- transparent.extend(1, false);
- addr.extend(addr_bits, false);
- data.extend(memory->width, false);
+ SigSpec clk = sigmap(cell->getPort("\\CLK"));
+ SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]);
+ SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]);
+ SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]);
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ SigSpec data = sigmap(cell->getPort("\\DATA"));
+
+ clk.extend_u0(1, false);
+ clk_enable.extend_u0(1, false);
+ clk_polarity.extend_u0(1, false);
+ transparent.extend_u0(1, false);
+ addr.extend_u0(addr_bits, false);
+ data.extend_u0(memory->width, false);
sig_rd_clk.append(clk);
sig_rd_clk_enable.append(clk_enable);
@@ -122,6 +150,9 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_rd_transparent.append(transparent);
sig_rd_addr.append(addr);
sig_rd_data.append(data);
+
+ rd_ports++;
+ continue;
}
}
@@ -135,6 +166,10 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
mem->parameters["\\SIZE"] = RTLIL::Const(memory->size);
mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+ while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx)
+ init_data.bits.pop_back();
+ mem->parameters["\\INIT"] = init_data;
+
log_assert(sig_wr_clk.size() == wr_ports);
log_assert(sig_wr_clk_enable.size() == wr_ports && sig_wr_clk_enable.is_fully_const());
log_assert(sig_wr_clk_polarity.size() == wr_ports && sig_wr_clk_polarity.is_fully_const());
@@ -166,7 +201,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
mem->setPort("\\RD_ADDR", sig_rd_addr);
mem->setPort("\\RD_DATA", sig_rd_data);
- for (auto c : del_cells)
+ for (auto c : memcells)
module->remove(c);
}
@@ -205,3 +240,4 @@ struct MemoryCollectPass : public Pass {
}
} MemoryCollectPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 302ab3ab..d3cc681a 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -22,13 +22,16 @@
#include <stdlib.h>
#include <sstream>
-static void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
for (auto &conn : module->connections())
sig.replace(conn.first, conn.second);
}
-static bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
normalize_sig(module, sig);
@@ -66,7 +69,7 @@ static bool find_sig_before_dff(RTLIL::Module *module, std::vector<RTLIL::Cell*>
return true;
}
-static void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
+void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
@@ -105,7 +108,7 @@ static void handle_wr_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff
log("no (compatible) $dff found.\n");
}
-static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
+void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
{
normalize_sig(module, sig);
sig.sort_and_unify();
@@ -123,7 +126,7 @@ static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
}
}
-static void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
+void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff_cells, RTLIL::Cell *cell)
{
log("Checking cell `%s' in module `%s': ", cell->name.c_str(), module->name.c_str());
@@ -161,7 +164,7 @@ static void handle_rd_cell(RTLIL::Module *module, std::vector<RTLIL::Cell*> &dff
log("no (compatible) $dff found.\n");
}
-static void handle_module(RTLIL::Module *module, bool flag_wr_only)
+void handle_module(RTLIL::Module *module, bool flag_wr_only)
{
std::vector<RTLIL::Cell*> dff_cells;
@@ -216,3 +219,4 @@ struct MemoryDffPass : public Pass {
}
} MemoryDffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index eecb6f35..41c4a7b1 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -23,6 +23,9 @@
#include <set>
#include <stdlib.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct MemoryMapWorker
{
RTLIL::Design *design;
@@ -55,21 +58,21 @@ struct MemoryMapWorker
RTLIL::Wire *addr_decode(RTLIL::SigSpec addr_sig, RTLIL::SigSpec addr_val)
{
std::pair<RTLIL::SigSpec, RTLIL::SigSpec> key(addr_sig, addr_val);
- log_assert(SIZE(addr_sig) == SIZE(addr_val));
+ log_assert(GetSize(addr_sig) == GetSize(addr_val));
if (decoder_cache.count(key) == 0) {
- if (SIZE(addr_sig) < 2) {
+ if (GetSize(addr_sig) < 2) {
decoder_cache[key] = module->Eq(NEW_ID, addr_sig, addr_val);
} else {
- int split_at = SIZE(addr_sig) / 2;
+ int split_at = GetSize(addr_sig) / 2;
RTLIL::SigBit left_eq = addr_decode(addr_sig.extract(0, split_at), addr_val.extract(0, split_at));
- RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, SIZE(addr_sig) - split_at), addr_val.extract(split_at, SIZE(addr_val) - split_at));
+ RTLIL::SigBit right_eq = addr_decode(addr_sig.extract(split_at, GetSize(addr_sig) - split_at), addr_val.extract(split_at, GetSize(addr_val) - split_at));
decoder_cache[key] = module->And(NEW_ID, left_eq, right_eq);
}
}
RTLIL::SigBit bit = decoder_cache.at(key);
- log_assert(bit.wire != nullptr && SIZE(bit.wire) == 1);
+ log_assert(bit.wire != nullptr && GetSize(bit.wire) == 1);
return bit.wire;
}
@@ -77,11 +80,15 @@ struct MemoryMapWorker
{
std::set<int> static_ports;
std::map<int, RTLIL::SigSpec> static_cells_map;
+
int mem_size = cell->parameters["\\SIZE"].as_int();
int mem_width = cell->parameters["\\WIDTH"].as_int();
int mem_offset = cell->parameters["\\OFFSET"].as_int();
int mem_abits = cell->parameters["\\ABITS"].as_int();
+ SigSpec init_data = cell->getParam("\\INIT");
+ init_data.extend_u0(mem_size*mem_width, true);
+
// delete unused memory cell
if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
module->remove(cell);
@@ -107,7 +114,7 @@ struct MemoryMapWorker
// FIXME: Actually we should check for wr_en.is_fully_const() also and
// create a $adff cell with this ports wr_en input as reset pin when wr_en
// is not a simple static 1.
- static_cells_map[wr_addr.as_int()] = wr_data;
+ static_cells_map[wr_addr.as_int() - mem_offset] = wr_data;
static_ports.insert(i);
continue;
}
@@ -162,7 +169,10 @@ struct MemoryMapWorker
w_out_name = genid(cell->name, "", i, "$q");
RTLIL::Wire *w_out = module->addWire(w_out_name, mem_width);
- w_out->start_offset = mem_offset;
+ SigSpec w_init = init_data.extract(i*mem_width, mem_width);
+
+ if (!w_init.is_fully_undef())
+ w_out->attributes["\\init"] = w_init.as_const();
data_reg_out.push_back(RTLIL::SigSpec(w_out));
c->setPort("\\Q", data_reg_out.back());
@@ -177,6 +187,9 @@ struct MemoryMapWorker
{
RTLIL::SigSpec rd_addr = cell->getPort("\\RD_ADDR").extract(i*mem_abits, mem_abits);
+ if (mem_offset)
+ rd_addr = module->Sub(NEW_ID, rd_addr, SigSpec(mem_offset, GetSize(rd_addr)));
+
std::vector<RTLIL::SigSpec> rd_signals;
rd_signals.push_back(cell->getPort("\\RD_DATA").extract(i*mem_width, mem_width));
@@ -253,6 +266,10 @@ struct MemoryMapWorker
RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(j*mem_abits, mem_abits);
RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(j*mem_width, mem_width);
RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(j*mem_width, mem_width);
+
+ if (mem_offset)
+ wr_addr = module->Sub(NEW_ID, wr_addr, SigSpec(mem_offset, GetSize(wr_addr)));
+
RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
int wr_offset = 0;
@@ -339,3 +356,4 @@ struct MemoryMapPass : public Pass {
}
} MemoryMapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 3ae0cd2c..3d241433 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -22,9 +22,10 @@
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
if (a->type == "$memrd" && b->type == "$memrd")
return a->name < b->name;
@@ -488,8 +489,8 @@ struct MemoryShareWorker
if (wr_ports.size() <= 1)
return;
- ezDefaultSAT ez;
- SatGen satgen(&ez, &modwalker.sigmap);
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &modwalker.sigmap);
// find list of considered ports and port pairs
@@ -543,6 +544,7 @@ struct MemoryShareWorker
// create SAT representation of common input cone of all considered EN signals
+ pool<Wire*> one_hot_wires;
std::set<RTLIL::Cell*> sat_cells;
std::set<RTLIL::SigBit> bits_queue;
std::map<int, int> port_to_sat_variable;
@@ -551,7 +553,7 @@ struct MemoryShareWorker
if (considered_port_pairs.count(i) || considered_port_pairs.count(i+1))
{
RTLIL::SigSpec sig = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
- port_to_sat_variable[i] = ez.expression(ez.OpOr, satgen.importSigSpec(sig));
+ port_to_sat_variable[i] = ez->expression(ez->OpOr, satgen.importSigSpec(sig));
std::vector<RTLIL::SigBit> bits = sig;
bits_queue.insert(bits.begin(), bits.end());
@@ -559,24 +561,36 @@ struct MemoryShareWorker
while (!bits_queue.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ for (auto bit : bits_queue)
+ if (bit.wire && bit.wire->get_bool_attribute("\\onehot"))
+ one_hot_wires.insert(bit.wire);
+
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, bits_queue);
bits_queue.clear();
for (auto &pbit : portbits)
if (sat_cells.count(pbit.cell) == 0 && cone_ct.cell_known(pbit.cell->type)) {
- std::set<RTLIL::SigBit> &cell_inputs = modwalker.cell_inputs[pbit.cell];
+ pool<RTLIL::SigBit> &cell_inputs = modwalker.cell_inputs[pbit.cell];
bits_queue.insert(cell_inputs.begin(), cell_inputs.end());
sat_cells.insert(pbit.cell);
}
}
+ for (auto wire : one_hot_wires) {
+ log(" Adding one-hot constraint for wire %s.\n", log_id(wire));
+ vector<int> ez_wire_bits = satgen.importSigSpec(wire);
+ for (int i : ez_wire_bits)
+ for (int j : ez_wire_bits)
+ if (i != j) ez->assume(ez->NOT(i), j);
+ }
+
log(" Common input cone for all EN signals: %d cells.\n", int(sat_cells.size()));
for (auto cell : sat_cells)
satgen.importCell(cell);
- log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez.numCnfVariables(), ez.numCnfClauses());
+ log(" Size of unconstrained SAT problem: %d variables, %d clauses\n", ez->numCnfVariables(), ez->numCnfClauses());
// merge subsequent ports if possible
@@ -585,13 +599,13 @@ struct MemoryShareWorker
if (!considered_port_pairs.count(i))
continue;
- if (ez.solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
+ if (ez->solve(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i))) {
log(" According to SAT solver sharing of port %d with port %d is not possible.\n", i-1, i);
continue;
}
log(" Merging port %d into port %d.\n", i-1, i);
- port_to_sat_variable.at(i) = ez.OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
+ port_to_sat_variable.at(i) = ez->OR(port_to_sat_variable.at(i-1), port_to_sat_variable.at(i));
RTLIL::SigSpec last_addr = wr_ports[i-1]->getPort("\\ADDR");
RTLIL::SigSpec last_data = wr_ports[i-1]->getPort("\\DATA");
@@ -741,4 +755,3 @@ struct MemorySharePass : public Pass {
} MemorySharePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 5a4c4eac..e650facb 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -23,7 +23,10 @@
#include <algorithm>
#include <stdlib.h>
-static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
{
log("Creating $memrd and $memwr for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
@@ -76,7 +79,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
module->remove(memory);
}
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
+void handle_module(RTLIL::Design *design, RTLIL::Module *module)
{
std::vector<RTLIL::IdString> memcells;
for (auto &cell_it : module->cells_)
@@ -107,3 +110,4 @@ struct MemoryUnpackPass : public Pass {
}
} MemoryUnpackPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 3a8d27f9..6b075cd9 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -6,6 +6,9 @@ OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_const.o
+
+ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
OBJS += passes/opt/wreduce.o
+endif
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index b20521d1..5ca57a14 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
virtual void help()
@@ -34,22 +37,22 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" opt_share -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
- log(" opt_reduce [-fine]\n");
+ log(" opt_reduce [-fine] [-full]\n");
log(" opt_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
log("\n");
log("When called with -fast the following script is used instead:\n");
log("\n");
log(" do\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-full] [-keepdc]\n");
log(" opt_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
@@ -93,6 +96,11 @@ struct OptPass : public Pass {
opt_reduce_args += " -fine";
continue;
}
+ if (args[argidx] == "-full") {
+ opt_const_args += " -full";
+ opt_reduce_args += " -full";
+ continue;
+ }
if (args[argidx] == "-keepdc") {
opt_const_args += " -keepdc";
continue;
@@ -137,8 +145,13 @@ struct OptPass : public Pass {
}
}
- log_header(fast_mode ? "Finished fast OPT passes." : "Finished OPT passes. (There is nothing left to do.)\n");
+ design->optimize();
+ design->sort();
+ design->check();
+
+ log_header(fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 5046752f..9d2a262a 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -25,65 +25,61 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
-static CellTypes ct, ct_reg, ct_all;
-static int count_rm_cells, count_rm_wires;
+CellTypes ct, ct_reg, ct_all;
+int count_rm_cells, count_rm_wires;
-static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
+void rmunused_module_cells(Module *module, bool verbose)
{
- SigMap assign_map(module);
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
+ SigMap sigmap(module);
+ pool<Cell*> queue, unused;
+ dict<SigBit, pool<Cell*>> wire2driver;
- SigSet<RTLIL::Cell*> wire2driver;
for (auto &it : module->cells_) {
- RTLIL::Cell *cell = it.second;
+ Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
- if (!ct.cell_input(cell->type, it2.first)) {
- RTLIL::SigSpec sig = it2.second;
- assign_map.apply(sig);
- wire2driver.insert(sig, cell);
- }
+ if (!ct.cell_input(cell->type, it2.first))
+ for (auto bit : sigmap(it2.second))
+ if (bit.wire != nullptr)
+ wire2driver[bit].insert(cell);
}
- if (cell->type == "$memwr" || cell->type == "$assert" || cell->get_bool_attribute("\\keep"))
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume") || cell->has_keep_attr())
queue.insert(cell);
- unused.insert(cell);
+ else
+ unused.insert(cell);
}
for (auto &it : module->wires_) {
- RTLIL::Wire *wire = it.second;
+ Wire *wire = it.second;
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
- std::set<RTLIL::Cell*> cell_list;
- RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
- assign_map.apply(sig);
- wire2driver.find(sig, cell_list);
- for (auto cell : cell_list)
- queue.insert(cell);
+ for (auto bit : sigmap(wire))
+ for (auto c : wire2driver[bit])
+ queue.insert(c), unused.erase(c);
}
}
- while (queue.size() > 0)
+ while (!queue.empty())
{
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
+ pool<SigBit> bits;
for (auto cell : queue)
- unused.erase(cell);
- for (auto cell : queue) {
- for (auto &it : cell->connections()) {
- if (!ct.cell_output(cell->type, it.first)) {
- std::set<RTLIL::Cell*> cell_list;
- RTLIL::SigSpec sig = it.second;
- assign_map.apply(sig);
- wire2driver.find(sig, cell_list);
- for (auto cell : cell_list) {
- if (unused.count(cell) > 0)
- new_queue.insert(cell);
- }
- }
- }
- }
- queue.swap(new_queue);
+ for (auto &it : cell->connections())
+ if (!ct.cell_output(cell->type, it.first))
+ for (auto bit : sigmap(it.second))
+ bits.insert(bit);
+
+ queue.clear();
+ for (auto bit : bits)
+ for (auto c : wire2driver[bit])
+ if (unused.count(c))
+ queue.insert(c), unused.erase(c);
}
+ unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>());
+
for (auto cell : unused) {
if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
@@ -93,7 +89,7 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
}
}
-static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
+int count_nontrivial_wire_attrs(RTLIL::Wire *w)
{
int count = w->attributes.size();
count -= w->attributes.count("\\src");
@@ -101,7 +97,7 @@ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
return count;
}
-static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
+bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, pool<RTLIL::Wire*> &direct_wires)
{
RTLIL::Wire *w1 = s1.wire;
RTLIL::Wire *w2 = s2.wire;
@@ -116,7 +112,7 @@ static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs,
if (regs.check_any(s1) != regs.check_any(s2))
return regs.check_any(s2);
if (direct_wires.count(w1) != direct_wires.count(w2))
- return direct_wires.count(w2);
+ return direct_wires.count(w2) != 0;
if (conns.check_any(s1) != conns.check_any(s2))
return conns.check_any(s2);
}
@@ -136,7 +132,7 @@ static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs,
return w2->name < w1->name;
}
-static bool check_public_name(RTLIL::IdString id)
+bool check_public_name(RTLIL::IdString id)
{
const std::string &id_str = id.str();
if (id_str[0] == '$')
@@ -148,7 +144,7 @@ static bool check_public_name(RTLIL::IdString id)
return true;
}
-static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
+void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@@ -165,8 +161,8 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
SigMap assign_map(module);
- std::set<RTLIL::SigSpec> direct_sigs;
- std::set<RTLIL::Wire*> direct_wires;
+ pool<RTLIL::SigSpec> direct_sigs;
+ pool<RTLIL::Wire*> direct_wires;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_all.cell_known(cell->type))
@@ -226,9 +222,9 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
maybe_del_wires.push_back(wire);
} else {
- log_assert(SIZE(s1) == SIZE(s2));
+ log_assert(GetSize(s1) == GetSize(s2));
RTLIL::SigSig new_conn;
- for (int i = 0; i < SIZE(s1); i++)
+ for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
@@ -247,7 +243,7 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
- for (int i = 0; i < SIZE(sig); i++) {
+ for (int i = 0; i < GetSize(sig); i++) {
if (sig[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(sig[i])) {
@@ -266,7 +262,7 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
- std::set<RTLIL::Wire*> del_wires;
+ pool<RTLIL::Wire*> del_wires;
int del_wires_count = 0;
for (auto wire : maybe_del_wires)
@@ -285,11 +281,30 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
log(" removed %d unused temporary wires.\n", del_wires_count);
}
-static void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
+void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
{
if (verbose)
log("Finding unused cells or wires in module %s..\n", module->name.c_str());
+ std::vector<RTLIL::Cell*> delcells;
+ for (auto cell : module->cells())
+ if (cell->type.in("$pos", "$_BUF_")) {
+ bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec y = cell->getPort("\\Y");
+ a.extend_u0(GetSize(y), is_signed);
+ module->connect(y, a);
+ delcells.push_back(cell);
+ }
+ for (auto cell : delcells) {
+ if (verbose)
+ log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
+ log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
+ module->remove(cell);
+ }
+ if (!delcells.empty())
+ module->design->scratchpad_set_bool("opt.did_something", true);
+
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
}
@@ -338,19 +353,16 @@ struct OptCleanPass : public Pass {
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
- for (auto &mod_it : design->modules_) {
- if (!design->selected_whole_module(mod_it.first)) {
- if (design->selected(mod_it.second))
- log("Skipping module %s as it is only partially selected.\n", id2cstr(mod_it.second->name));
+ for (auto module : design->selected_whole_modules_warn()) {
+ if (module->has_processes_warn())
continue;
- }
- if (mod_it.second->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
- } else {
- rmunused_module(mod_it.second, purge_mode, true);
- }
+ rmunused_module(module, purge_mode, true);
}
+ design->optimize();
+ design->sort();
+ design->check();
+
ct.clear();
ct_reg.clear();
log_pop();
@@ -402,20 +414,23 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
- for (auto &mod_it : design->modules_) {
- if (design->selected_whole_module(mod_it.first) && mod_it.second->processes.size() == 0)
- do {
- design->scratchpad_unset("opt.did_something");
- rmunused_module(mod_it.second, purge_mode, false);
- } while (design->scratchpad_get_bool("opt.did_something"));
+ for (auto module : design->selected_whole_modules()) {
+ if (module->has_processes())
+ continue;
+ rmunused_module(module, purge_mode, false);
}
if (count_rm_cells > 0 || count_rm_wires > 0)
log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
+ design->optimize();
+ design->sort();
+ design->check();
+
ct.clear();
ct_reg.clear();
ct_all.clear();
}
} CleanPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index f9b78c05..1758a34f 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -26,9 +26,12 @@
#include <stdio.h>
#include <algorithm>
-static bool did_something;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
-static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
+bool did_something;
+
+void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
{
CellTypes ct(design);
SigMap sigmap(module);
@@ -70,7 +73,7 @@ static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
}
-static void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
{
RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false);
@@ -85,7 +88,7 @@ static void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell
did_something = true;
}
-static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
+bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
{
std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
@@ -104,7 +107,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N };
std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::set<RTLIL::SigBit>> grouped_bits[GRP_N];
- for (int i = 0; i < SIZE(bits_y); i++)
+ for (int i = 0; i < GetSize(bits_y); i++)
{
int group_idx = GRP_DYN;
RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
@@ -128,7 +131,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
}
for (int i = 0; i < GRP_N; i++)
- if (SIZE(grouped_bits[i]) == SIZE(bits_y))
+ if (GetSize(grouped_bits[i]) == GetSize(bits_y))
return false;
log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
@@ -139,7 +142,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
if (grouped_bits[i].empty())
continue;
- RTLIL::Wire *new_y = module->addWire(NEW_ID, SIZE(grouped_bits[i]));
+ RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i]));
RTLIL::SigSpec new_a, new_b;
RTLIL::SigSig new_conn;
@@ -183,7 +186,7 @@ static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool com
return true;
}
-static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
+void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc)
{
if (!design->selected(module))
return;
@@ -193,11 +196,11 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
ct_combinational.setup_stdcells();
SigMap assign_map(module);
- std::map<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
+ dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
- TopoSort<RTLIL::Cell*> cells;
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
+ TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
+ dict<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
+ dict<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
for (auto cell : module->cells())
if (design->selected(module, cell) && cell->type[0] == '$') {
@@ -483,12 +486,12 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec new_a, new_b;
- log_assert(SIZE(a) == SIZE(b));
- for (int i = 0; i < SIZE(a); i++) {
+ log_assert(GetSize(a) == GetSize(b));
+ for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
- new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
+ new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
goto next_cell;
}
@@ -501,7 +504,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (new_a.size() == 0) {
cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
- new_y.extend(cell->parameters["\\Y_WIDTH"].as_int(), false);
+ new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
goto next_cell;
}
@@ -521,11 +524,11 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
- if (a.is_fully_const()) {
+ if (a.is_fully_const() && !b.is_fully_const()) {
cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str());
- RTLIL::SigSpec tmp = cell->getPort("\\A");
- cell->setPort("\\A", cell->getPort("\\B"));
- cell->setPort("\\B", tmp);
+ cell->setPort("\\A", b);
+ cell->setPort("\\B", a);
+ std::swap(a, b);
}
if (b.is_fully_const()) {
@@ -556,15 +559,15 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int());
- if (SIZE(sig_a) < SIZE(sig_y))
- sig_a.extend(SIZE(sig_y), cell->getParam("\\A_SIGNED").as_bool());
+ if (GetSize(sig_a) < GetSize(sig_y))
+ sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
int idx = i + shift_bits;
- if (0 <= idx && idx < SIZE(sig_a))
+ if (0 <= idx && idx < GetSize(sig_a))
sig_y[i] = sig_a[idx];
- else if (SIZE(sig_a) <= idx && sign_ext)
- sig_y[i] = sig_a[SIZE(sig_a)-1];
+ else if (GetSize(sig_a) <= idx && sign_ext)
+ sig_y[i] = sig_a[GetSize(sig_a)-1];
}
cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
@@ -666,8 +669,9 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->unsetPort("\\B");
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
cell->type = "$not";
@@ -683,9 +687,10 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\B_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters["\\B_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
@@ -702,9 +707,10 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\B_WIDTH"] = cell->parameters["\\WIDTH"];
- cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
+ Const width = cell->parameters["\\WIDTH"];
+ cell->parameters["\\A_WIDTH"] = width;
+ cell->parameters["\\B_WIDTH"] = width;
+ cell->parameters["\\Y_WIDTH"] = width;
cell->parameters["\\A_SIGNED"] = 0;
cell->parameters["\\B_SIGNED"] = 0;
cell->parameters.erase("\\WIDTH");
@@ -751,7 +757,7 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
- SIZE(cell->getPort("\\S")) - SIZE(new_s), log_id(cell->type), log_id(cell), log_id(module));
+ GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b);
cell->setPort("\\S", new_s);
@@ -891,17 +897,17 @@ static void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bo
if (!swapped_ab) {
cell->setPort("\\A", cell->getPort("\\B"));
- cell->parameters["\\A_WIDTH"] = cell->parameters["\\B_WIDTH"];
- cell->parameters["\\A_SIGNED"] = cell->parameters["\\B_SIGNED"];
+ cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
+ cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
}
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
- while (SIZE(new_b) > 1 && new_b.back() == RTLIL::State::S0)
+ while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
new_b.pop_back();
cell->type = "$shl";
- cell->parameters["\\B_WIDTH"] = SIZE(new_b);
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
cell->parameters["\\B_SIGNED"] = false;
cell->setPort("\\B", new_b);
cell->check();
@@ -939,15 +945,18 @@ struct OptConstPass : public Pass {
log(" -undriven\n");
log(" replace undriven nets with undef (x) constants\n");
log("\n");
+ log(" -fine\n");
+ log(" perform fine-grain optimizations\n");
+ log("\n");
+ log(" -full\n");
+ log(" alias for -mux_undef -mux_bool -undriven -fine\n");
+ log("\n");
log(" -keepdc\n");
log(" some optimizations change the behavior of the circuit with respect to\n");
log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n");
log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
- log(" -fine\n");
- log(" perform fine-grain optimizations\n");
- log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -978,6 +987,13 @@ struct OptConstPass : public Pass {
do_fine = true;
continue;
}
+ if (args[argidx] == "-full") {
+ mux_undef = true;
+ mux_bool = true;
+ undriven = true;
+ do_fine = true;
+ continue;
+ }
if (args[argidx] == "-keepdc") {
keepdc = true;
continue;
@@ -986,7 +1002,7 @@ struct OptConstPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto module : design->modules())
+ for (auto module : design->selected_modules())
{
if (undriven)
replace_undriven(design, module);
@@ -1006,3 +1022,4 @@ struct OptConstPass : public Pass {
}
} OptConstPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 2c5dcf66..98287074 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
struct OptMuxtreeWorker
@@ -34,37 +37,33 @@ struct OptMuxtreeWorker
SigMap assign_map;
int removed_count;
- struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
- bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
- bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
- };
-
-
struct bitinfo_t {
- int num;
- bitDef_t bit;
bool seen_non_mux;
- std::vector<int> mux_users;
- std::vector<int> mux_drivers;
+ pool<int> mux_users;
+ pool<int> mux_drivers;
};
- std::map<bitDef_t, int> bit2num;
- std::vector<bitinfo_t> bit2info;
+ idict<SigBit> bit2num;
+ vector<bitinfo_t> bit2info;
struct portinfo_t {
- std::vector<int> ctrl_sigs;
- std::vector<int> input_sigs;
- std::vector<int> input_muxes;
+ int ctrl_sig;
+ pool<int> input_sigs;
+ pool<int> input_muxes;
bool const_activated;
+ bool const_deactivated;
bool enabled;
};
struct muxinfo_t {
RTLIL::Cell *cell;
- std::vector<portinfo_t> ports;
+ vector<portinfo_t> ports;
};
- std::vector<muxinfo_t> mux2info;
+ vector<muxinfo_t> mux2info;
+ vector<bool> root_muxes;
+ vector<bool> root_enable_muxes;
+ pool<int> root_mux_rerun;
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
@@ -78,9 +77,10 @@ struct OptMuxtreeWorker
// .mux_users
// .mux_drivers
// Populate mux2info[].ports[]:
- // .ctrl_sigs
+ // .ctrl_sig
// .input_sigs
// .const_activated
+ // .const_deactivated
for (auto cell : module->cells())
{
if (cell->type == "$mux" || cell->type == "$pmux")
@@ -93,32 +93,34 @@ struct OptMuxtreeWorker
muxinfo_t muxinfo;
muxinfo.cell = cell;
- for (int i = 0; i < sig_s.size(); i++) {
- RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size());
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ RTLIL::SigSpec sig = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo;
+ portinfo.ctrl_sig = sig2bits(ctrl_sig, false).front();
for (int idx : sig2bits(sig)) {
- add_to_list(bit2info[idx].mux_users, mux2info.size());
- add_to_list(portinfo.input_sigs, idx);
+ bit2info[idx].mux_users.insert(GetSize(mux2info));
+ portinfo.input_sigs.insert(idx);
}
- for (int idx : sig2bits(ctrl_sig))
- add_to_list(portinfo.ctrl_sigs, idx);
portinfo.const_activated = ctrl_sig.is_fully_const() && ctrl_sig.as_bool();
+ portinfo.const_deactivated = ctrl_sig.is_fully_const() && !ctrl_sig.as_bool();
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
}
portinfo_t portinfo;
for (int idx : sig2bits(sig_a)) {
- add_to_list(bit2info[idx].mux_users, mux2info.size());
- add_to_list(portinfo.input_sigs, idx);
+ bit2info[idx].mux_users.insert(GetSize(mux2info));
+ portinfo.input_sigs.insert(idx);
}
+ portinfo.ctrl_sig = -1;
portinfo.const_activated = false;
+ portinfo.const_deactivated = false;
portinfo.enabled = false;
muxinfo.ports.push_back(portinfo);
for (int idx : sig2bits(sig_y))
- add_to_list(bit2info[idx].mux_drivers, mux2info.size());
+ bit2info[idx].mux_drivers.insert(GetSize(mux2info));
for (int idx : sig2bits(sig_s))
bit2info[idx].seen_non_mux = true;
@@ -139,53 +141,78 @@ struct OptMuxtreeWorker
bit2info[idx].seen_non_mux = true;
}
- if (mux2info.size() == 0) {
+ if (mux2info.empty()) {
log(" No muxes found in this module.\n");
return;
}
// Populate mux2info[].ports[]:
// .input_muxes
- for (size_t i = 0; i < bit2info.size(); i++)
+ for (int i = 0; i < GetSize(bit2info); i++)
for (int j : bit2info[i].mux_users)
for (auto &p : mux2info[j].ports) {
- if (is_in_list(p.input_sigs, i))
+ if (p.input_sigs.count(i))
for (int k : bit2info[i].mux_drivers)
- add_to_list(p.input_muxes, k);
+ p.input_muxes.insert(k);
}
log(" Evaluating internal representation of mux trees.\n");
- std::set<int> root_muxes;
+ dict<int, pool<int>> mux_to_users;
+ root_muxes.resize(GetSize(mux2info));
+ root_enable_muxes.resize(GetSize(mux2info));
+
for (auto &bi : bit2info) {
+ for (int i : bi.mux_drivers)
+ for (int j : bi.mux_users)
+ mux_to_users[i].insert(j);
if (!bi.seen_non_mux)
continue;
- for (int mux_idx : bi.mux_drivers)
- root_muxes.insert(mux_idx);
+ for (int mux_idx : bi.mux_drivers) {
+ root_muxes.at(mux_idx) = true;
+ root_enable_muxes.at(mux_idx) = true;
+ }
}
- for (int mux_idx : root_muxes)
+
+ for (auto &it : mux_to_users)
+ if (GetSize(it.second) > 1)
+ root_muxes.at(it.first) = true;
+
+ for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
+ if (root_muxes.at(mux_idx)) {
+ log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
+ root_mux_rerun.erase(mux_idx);
+ eval_root_mux(mux_idx);
+ }
+
+ while (!root_mux_rerun.empty()) {
+ int mux_idx = *root_mux_rerun.begin();
+ log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
+ log_assert(root_enable_muxes.at(mux_idx));
+ root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
+ }
log(" Analyzing evaluation results.\n");
for (auto &mi : mux2info)
{
- std::vector<int> live_ports;
- for (size_t port_idx = 0; port_idx < mi.ports.size(); port_idx++) {
+ vector<int> live_ports;
+ for (int port_idx = 0; port_idx < GetSize(mi.ports); port_idx++) {
portinfo_t &pi = mi.ports[port_idx];
if (pi.enabled) {
live_ports.push_back(port_idx);
} else {
- log(" dead port %zd/%zd on %s %s.\n", port_idx+1, mi.ports.size(),
+ log(" dead port %d/%d on %s %s.\n", port_idx+1, GetSize(mi.ports),
mi.cell->type.c_str(), mi.cell->name.c_str());
removed_count++;
}
}
- if (live_ports.size() == mi.ports.size())
+ if (GetSize(live_ports) == GetSize(mi.ports))
continue;
- if (live_ports.size() == 0) {
+ if (live_ports.empty()) {
module->remove(mi.cell);
continue;
}
@@ -198,9 +225,9 @@ struct OptMuxtreeWorker
RTLIL::SigSpec sig_ports = sig_b;
sig_ports.append(sig_a);
- if (live_ports.size() == 1)
+ if (GetSize(live_ports) == 1)
{
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.size(), sig_a.size());
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*GetSize(sig_a), GetSize(sig_a));
module->connect(RTLIL::SigSig(sig_y, sig_in));
module->remove(mi.cell);
}
@@ -208,9 +235,9 @@ struct OptMuxtreeWorker
{
RTLIL::SigSpec new_sig_a, new_sig_b, new_sig_s;
- for (size_t i = 0; i < live_ports.size(); i++) {
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.size(), sig_a.size());
- if (i == live_ports.size()-1) {
+ for (int i = 0; i < GetSize(live_ports); i++) {
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*GetSize(sig_a), GetSize(sig_a));
+ if (i == GetSize(live_ports)-1) {
new_sig_a = sig_in;
} else {
new_sig_b.append(sig_in);
@@ -221,123 +248,162 @@ struct OptMuxtreeWorker
mi.cell->setPort("\\A", new_sig_a);
mi.cell->setPort("\\B", new_sig_b);
mi.cell->setPort("\\S", new_sig_s);
- if (new_sig_s.size() == 1) {
+ if (GetSize(new_sig_s) == 1) {
mi.cell->type = "$mux";
mi.cell->parameters.erase("\\S_WIDTH");
} else {
- mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
+ mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(GetSize(new_sig_s));
}
}
}
}
- bool list_is_subset(const std::vector<int> &sub, const std::vector<int> &super)
+ vector<int> sig2bits(RTLIL::SigSpec sig, bool skip_non_wires = true)
{
- for (int v : sub)
- if (!is_in_list(super, v))
- return false;
- return true;
- }
-
- bool is_in_list(const std::vector<int> &list, int value)
- {
- for (int v : list)
- if (v == value)
- return true;
- return false;
- }
-
- void add_to_list(std::vector<int> &list, int value)
- {
- if (!is_in_list(list, value))
- list.push_back(value);
- }
-
- std::vector<int> sig2bits(RTLIL::SigSpec sig)
- {
- std::vector<int> results;
+ vector<int> results;
assign_map.apply(sig);
for (auto &bit : sig)
if (bit.wire != NULL) {
if (bit2num.count(bit) == 0) {
bitinfo_t info;
- info.num = bit2info.size();
- info.bit = bit;
info.seen_non_mux = false;
+ bit2num.expect(bit, GetSize(bit2info));
bit2info.push_back(info);
- bit2num[info.bit] = info.num;
}
- results.push_back(bit2num[bit]);
- }
+ results.push_back(bit2num.at(bit));
+ } else if (!skip_non_wires)
+ results.push_back(-1);
return results;
}
struct knowledge_t
{
// database of known inactive signals
- // the 2nd integer is a reference counter used to manage the
+ // the payload is a reference counter used to manage the
// list. when it is non-zero the signal in known to be inactive
- std::map<int, int> known_inactive;
+ vector<int> known_inactive;
// database of known active signals
- // the 2nd dimension is the list of or-ed signals. so we know that
- // for each i there is a j so that known_active[i][j] points to an
- // inactive control signal.
- std::vector<std::vector<int>> known_active;
+ vector<int> known_active;
// this is just used to keep track of visited muxes in order to prohibit
// endless recursion in mux loops
- std::set<int> visited_muxes;
+ vector<bool> visited_muxes;
};
- void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx)
+ void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
muxinfo_t &muxinfo = mux2info[mux_idx];
- muxinfo.ports[port_idx].enabled = true;
- for (size_t i = 0; i < muxinfo.ports.size(); i++) {
- if (int(i) == port_idx)
+ if (do_enable_ports)
+ muxinfo.ports[port_idx].enabled = true;
+
+ for (int i = 0; i < GetSize(muxinfo.ports); i++) {
+ if (i == port_idx)
continue;
- for (int b : muxinfo.ports[i].ctrl_sigs)
- knowledge.known_inactive[b]++;
+ if (muxinfo.ports[i].ctrl_sig >= 0)
+ knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++;
}
- if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
- knowledge.known_active.push_back(muxinfo.ports[port_idx].ctrl_sigs);
+ if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
+ knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++;
- std::vector<int> parent_muxes;
+ vector<int> parent_muxes;
for (int m : muxinfo.ports[port_idx].input_muxes) {
- if (knowledge.visited_muxes.count(m) > 0)
+ if (knowledge.visited_muxes[m])
continue;
- knowledge.visited_muxes.insert(m);
+ knowledge.visited_muxes[m] = true;
parent_muxes.push_back(m);
}
for (int m : parent_muxes)
- eval_mux(knowledge, m);
+ if (root_enable_muxes.at(m))
+ continue;
+ else if (root_muxes.at(m)) {
+ if (abort_count == 0) {
+ root_mux_rerun.insert(m);
+ root_enable_muxes.at(m) = true;
+ log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
+ } else
+ eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
+ } else
+ eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count);
for (int m : parent_muxes)
- knowledge.visited_muxes.erase(m);
+ knowledge.visited_muxes[m] = false;
+
+ if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated)
+ knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--;
- if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
- knowledge.known_active.pop_back();
+ for (int i = 0; i < GetSize(muxinfo.ports); i++) {
+ if (i == port_idx)
+ continue;
+ if (muxinfo.ports[i].ctrl_sig >= 0)
+ knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--;
+ }
+ }
- for (size_t i = 0; i < muxinfo.ports.size(); i++) {
- if (int(i) == port_idx)
+ void replace_known(knowledge_t &knowledge, muxinfo_t &muxinfo, IdString portname)
+ {
+ SigSpec sig = muxinfo.cell->getPort(portname);
+ bool did_something = false;
+
+ int width = 0;
+ idict<int> ctrl_bits;
+ if (portname == "\\B")
+ width = GetSize(muxinfo.cell->getPort("\\A"));
+ for (int bit : sig2bits(muxinfo.cell->getPort("\\S"), false))
+ ctrl_bits(bit);
+
+ int port_idx = 0, port_off = 0;
+ vector<int> bits = sig2bits(sig, false);
+ for (int i = 0; i < GetSize(bits); i++) {
+ if (bits[i] < 0)
continue;
- for (int b : muxinfo.ports[i].ctrl_sigs)
- knowledge.known_inactive[b]--;
+ if (knowledge.known_inactive.at(bits[i])) {
+ sig[i] = State::S0;
+ did_something = true;
+ } else
+ if (knowledge.known_active.at(bits[i])) {
+ sig[i] = State::S1;
+ did_something = true;
+ }
+ if (width) {
+ if (ctrl_bits.count(bits[i])) {
+ sig[i] = ctrl_bits.at(bits[i]) == port_idx ? State::S1 : State::S0;
+ did_something = true;
+ }
+ if (++port_off == width)
+ port_idx++, port_off=0;
+ } else {
+ if (ctrl_bits.count(bits[i])) {
+ sig[i] = State::S0;
+ did_something = true;
+ }
+ }
+ }
+
+ if (did_something) {
+ log(" Replacing known input bits on port %s of cell %s: %s -> %s\n", log_id(portname),
+ log_id(muxinfo.cell), log_signal(muxinfo.cell->getPort(portname)), log_signal(sig));
+ muxinfo.cell->setPort(portname, sig);
}
}
- void eval_mux(knowledge_t &knowledge, int mux_idx)
+ void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
muxinfo_t &muxinfo = mux2info[mux_idx];
+ // set input ports to constants if we find known active or inactive signals
+ if (do_replace_known) {
+ replace_known(knowledge, muxinfo, "\\A");
+ replace_known(knowledge, muxinfo, "\\B");
+ }
+
// if there is a constant activated port we just use it
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports); port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
if (portinfo.const_activated) {
- eval_mux_port(knowledge, mux_idx, port_idx);
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
return;
}
}
@@ -345,56 +411,39 @@ struct OptMuxtreeWorker
// compare ports with known_active signals. if we find a match, only this
// port can be active. do not include the last port (its the default port
// that has no control signals).
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size()-1; port_idx++)
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports)-1; port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
- for (size_t i = 0; i < knowledge.known_active.size(); i++) {
- if (list_is_subset(knowledge.known_active[i], portinfo.ctrl_sigs)) {
- eval_mux_port(knowledge, mux_idx, port_idx);
- return;
- }
+ if (portinfo.const_deactivated)
+ continue;
+ if (knowledge.known_active.at(portinfo.ctrl_sig)) {
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
+ return;
}
}
- // compare ports with known_inactive and known_active signals. If all control
- // signals of the port are know_inactive or if the control signals of all other
- // ports are known_active this port can't be activated. this loop includes the
- // default port but no known_inactive match is performed on the default port.
- for (size_t port_idx = 0; port_idx < muxinfo.ports.size(); port_idx++)
+ // eval all ports that could be activated (control signal is not in
+ // known_inactive or const_deactivated).
+ for (int port_idx = 0; port_idx < GetSize(muxinfo.ports); port_idx++)
{
portinfo_t &portinfo = muxinfo.ports[port_idx];
-
- if (port_idx < muxinfo.ports.size()-1) {
- bool found_non_known_inactive = false;
- for (int i : portinfo.ctrl_sigs)
- if (knowledge.known_inactive[i] == 0)
- found_non_known_inactive = true;
- if (!found_non_known_inactive)
- continue;
- }
-
- bool port_active = true;
- std::vector<int> other_ctrl_sig;
- for (size_t i = 0; i < muxinfo.ports.size()-1; i++) {
- if (i == port_idx)
+ if (portinfo.const_deactivated)
+ continue;
+ if (port_idx < GetSize(muxinfo.ports)-1)
+ if (knowledge.known_inactive.at(portinfo.ctrl_sig))
continue;
- other_ctrl_sig.insert(other_ctrl_sig.end(),
- muxinfo.ports[i].ctrl_sigs.begin(), muxinfo.ports[i].ctrl_sigs.end());
- }
- for (size_t i = 0; i < knowledge.known_active.size(); i++) {
- if (list_is_subset(knowledge.known_active[i], other_ctrl_sig))
- port_active = false;
- }
- if (port_active)
- eval_mux_port(knowledge, mux_idx, port_idx);
+ eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count);
}
}
void eval_root_mux(int mux_idx)
{
knowledge_t knowledge;
- knowledge.visited_muxes.insert(mux_idx);
- eval_mux(knowledge, mux_idx);
+ knowledge.known_inactive.resize(GetSize(bit2info));
+ knowledge.known_active.resize(GetSize(bit2info));
+ knowledge.visited_muxes.resize(GetSize(mux2info));
+ knowledge.visited_muxes[mux_idx] = true;
+ eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3);
}
};
@@ -413,24 +462,17 @@ struct OptMuxtreePass : public Pass {
log("This pass only operates on completely selected modules without processes.\n");
log("\n");
}
- virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ virtual void execute(vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
int total_count = 0;
- for (auto mod : design->modules()) {
- if (!design->selected_whole_module(mod)) {
- if (design->selected(mod))
- log("Skipping module %s as it is only partially selected.\n", log_id(mod));
+ for (auto module : design->selected_whole_modules_warn()) {
+ if (module->has_processes_warn())
continue;
- }
- if (mod->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", log_id(mod));
- } else {
- OptMuxtreeWorker worker(design, mod);
- total_count += worker.removed_count;
- }
+ OptMuxtreeWorker worker(design, module);
+ total_count += worker.removed_count;
}
if (total_count)
design->scratchpad_set_bool("opt.did_something", true);
@@ -438,3 +480,4 @@ struct OptMuxtreePass : public Pass {
}
} OptMuxtreePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index e9e2bb39..5c36eb26 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <set>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptReduceWorker
{
RTLIL::Design *design;
@@ -34,14 +37,14 @@ struct OptReduceWorker
int total_count;
bool did_something;
- void opt_reduce(std::set<RTLIL::Cell*> &cells, SigSet<RTLIL::Cell*> &drivers, RTLIL::Cell *cell)
+ void opt_reduce(pool<RTLIL::Cell*> &cells, SigSet<RTLIL::Cell*> &drivers, RTLIL::Cell *cell)
{
if (cells.count(cell) == 0)
return;
cells.erase(cell);
RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
- std::set<RTLIL::SigBit> new_sig_a_bits;
+ pool<RTLIL::SigBit> new_sig_a_bits;
for (auto &bit : sig_a.to_sigbit_set())
{
@@ -71,7 +74,7 @@ struct OptReduceWorker
if (child_cell->type == cell->type) {
opt_reduce(cells, drivers, child_cell);
if (child_cell->getPort("\\Y")[0] == bit) {
- std::set<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_set();
+ pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_pool();
new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
} else
new_sig_a_bits.insert(RTLIL::State::S0);
@@ -102,7 +105,7 @@ struct OptReduceWorker
RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
RTLIL::SigSpec new_sig_b, new_sig_s;
- std::set<RTLIL::SigSpec> handled_sig;
+ pool<RTLIL::SigSpec> handled_sig;
handled_sig.insert(sig_a);
for (int i = 0; i < sig_s.size(); i++)
@@ -287,7 +290,7 @@ struct OptReduceWorker
for (auto type : type_list)
{
SigSet<RTLIL::Cell*> drivers;
- std::set<RTLIL::Cell*> cells;
+ pool<RTLIL::Cell*> cells;
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
@@ -343,6 +346,9 @@ struct OptReducePass : public Pass {
log(" -fine\n");
log(" perform fine-grain optimizations\n");
log("\n");
+ log(" -full\n");
+ log(" alias for -fine\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -356,21 +362,22 @@ struct OptReducePass : public Pass {
do_fine = true;
continue;
}
+ if (args[argidx] == "-full") {
+ do_fine = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules_) {
- if (!design->selected(mod_it.second))
- continue;
- do {
- OptReduceWorker worker(design, mod_it.second, do_fine);
+ for (auto module : design->selected_modules())
+ while (1) {
+ OptReduceWorker worker(design, module, do_fine);
total_count += worker.total_count;
if (worker.total_count == 0)
break;
- } while (1);
- }
+ }
if (total_count)
design->scratchpad_set_bool("opt.did_something", true);
@@ -378,3 +385,4 @@ struct OptReducePass : public Pass {
}
} OptReducePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 48f406f6..5f52bb8d 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -23,10 +23,13 @@
#include <stdlib.h>
#include <stdio.h>
-static SigMap assign_map, dff_init_map;
-static SigSet<RTLIL::Cell*> mux_drivers;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
-static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
+SigMap assign_map, dff_init_map;
+SigSet<RTLIL::Cell*> mux_drivers;
+
+bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
{
RTLIL::SigSpec sig_d, sig_q, sig_c, sig_r;
RTLIL::Const val_cp, val_rp, val_rv;
@@ -80,7 +83,7 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx);
}
- if (dff->type == "$dff" && mux_drivers.has(sig_d)) {
+ if (dff->type == "$dff" && mux_drivers.has(sig_d) && !has_init) {
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
@@ -215,3 +218,4 @@ struct OptRmdffPass : public Pass {
}
} OptRmdffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index 4b76a5a2..cce97d65 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -28,6 +28,9 @@
#define USE_CELL_HASH_CACHE
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct OptShareWorker
{
RTLIL::Design *design;
@@ -38,7 +41,7 @@ struct OptShareWorker
CellTypes ct;
int total_count;
#ifdef USE_CELL_HASH_CACHE
- std::map<const RTLIL::Cell*, std::string> cell_hash_cache;
+ dict<const RTLIL::Cell*, std::string> cell_hash_cache;
#endif
#ifdef USE_CELL_HASH_CACHE
@@ -64,8 +67,8 @@ struct OptShareWorker
for (auto &it : cell->parameters)
hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n";
- const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
- std::map<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
+ const dict<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> alt_conn;
if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" ||
cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
@@ -124,12 +127,14 @@ struct OptShareWorker
#endif
if (cell1->parameters != cell2->parameters) {
- lt = cell1->parameters < cell2->parameters;
+ std::map<RTLIL::IdString, RTLIL::Const> p1(cell1->parameters.begin(), cell1->parameters.end());
+ std::map<RTLIL::IdString, RTLIL::Const> p2(cell2->parameters.begin(), cell2->parameters.end());
+ lt = p1 < p2;
return true;
}
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
+ dict<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
for (auto &it : conn1) {
if (ct.cell_output(cell1->type, it.first))
@@ -168,7 +173,9 @@ struct OptShareWorker
}
if (conn1 != conn2) {
- lt = conn1 < conn2;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> c1(conn1.begin(), conn1.end());
+ std::map<RTLIL::IdString, RTLIL::SigSpec> c2(conn2.begin(), conn2.end());
+ lt = c1 < c2;
return true;
}
@@ -193,7 +200,7 @@ struct OptShareWorker
if (!ct.cell_known(cell1->type))
return cell1 < cell2;
- if (cell1->get_bool_attribute("\\keep") || cell2->get_bool_attribute("\\keep"))
+ if (cell1->has_keep_attr() || cell2->has_keep_attr())
return cell1 < cell2;
bool lt;
@@ -263,6 +270,7 @@ struct OptShareWorker
}
}
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+ cell_hash_cache.erase(cell);
module->remove(cell);
total_count++;
} else {
@@ -306,10 +314,8 @@ struct OptSharePass : public Pass {
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules_) {
- if (!design->selected(mod_it.second))
- continue;
- OptShareWorker worker(design, mod_it.second, mode_nomux);
+ for (auto module : design->selected_modules()) {
+ OptShareWorker worker(design, module, mode_nomux);
total_count += worker.total_count;
}
@@ -319,3 +325,4 @@ struct OptSharePass : public Pass {
}
} OptSharePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 74b049bb..bf406bcd 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -22,22 +22,27 @@
#include "kernel/sigtools.h"
#include "kernel/modtools.h"
#include "kernel/utils.h"
+#include "kernel/macc.h"
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+typedef RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell> cell_ptr_cmp;
+typedef std::pair<RTLIL::SigSpec, RTLIL::Const> ssc_pair_t;
+
struct ShareWorkerConfig
{
int limit;
bool opt_force;
bool opt_aggressive;
bool opt_fast;
- std::set<RTLIL::IdString> generic_uni_ops, generic_bin_ops, generic_cbin_ops;
+ pool<RTLIL::IdString> generic_uni_ops, generic_bin_ops, generic_cbin_ops, generic_other_ops;
};
struct ShareWorker
{
ShareWorkerConfig config;
- std::set<RTLIL::IdString> generic_ops;
+ pool<RTLIL::IdString> generic_ops;
RTLIL::Design *design;
RTLIL::Module *module;
@@ -46,30 +51,32 @@ struct ShareWorker
ModWalker modwalker;
ModIndex mi;
- std::set<RTLIL::Cell*> cells_to_remove;
- std::set<RTLIL::Cell*> recursion_state;
+ pool<RTLIL::Cell*> cells_to_remove;
+ pool<RTLIL::Cell*> recursion_state;
SigMap topo_sigmap;
- std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> topo_cell_drivers;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> topo_bit_drivers;
+ std::map<RTLIL::Cell*, std::set<RTLIL::Cell*, cell_ptr_cmp>, cell_ptr_cmp> topo_cell_drivers;
+ std::map<RTLIL::SigBit, std::set<RTLIL::Cell*, cell_ptr_cmp>> topo_bit_drivers;
+
+ std::vector<std::pair<RTLIL::SigBit, RTLIL::SigBit>> exclusive_ctrls;
// ------------------------------------------------------------------------------
// Find terminal bits -- i.e. bits that do not (exclusively) feed into a mux tree
// ------------------------------------------------------------------------------
- std::set<RTLIL::SigBit> terminal_bits;
+ pool<RTLIL::SigBit> terminal_bits;
void find_terminal_bits()
{
- std::set<RTLIL::SigBit> queue_bits;
- std::set<RTLIL::Cell*> visited_cells;
+ pool<RTLIL::SigBit> queue_bits;
+ pool<RTLIL::Cell*> visited_cells;
queue_bits.insert(modwalker.signal_outputs.begin(), modwalker.signal_outputs.end());
for (auto &it : module->cells_)
if (!fwd_ct.cell_known(it.second->type)) {
- std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
+ pool<RTLIL::SigBit> &bits = modwalker.cell_inputs[it.second];
queue_bits.insert(bits.begin(), bits.end());
}
@@ -77,19 +84,19 @@ struct ShareWorker
while (!queue_bits.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, queue_bits);
queue_bits.clear();
for (auto &pbit : portbits) {
if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") {
- std::set<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_set();
+ pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_pool();
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
}
if (fwd_ct.cell_known(pbit.cell->type) && visited_cells.count(pbit.cell) == 0) {
- std::set<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
+ pool<RTLIL::SigBit> &bits = modwalker.cell_inputs[pbit.cell];
terminal_bits.insert(bits.begin(), bits.end());
queue_bits.insert(bits.begin(), bits.end());
visited_cells.insert(pbit.cell);
@@ -100,17 +107,251 @@ struct ShareWorker
// ---------------------------------------------------
+ // Code for sharing and comparing MACC cells
+ // ---------------------------------------------------
+
+ static int bits_macc_port(const Macc::port_t &p, int width)
+ {
+ if (GetSize(p.in_a) == 0 || GetSize(p.in_b) == 0)
+ return std::min(std::max(GetSize(p.in_a), GetSize(p.in_b)), width);
+ return std::min(GetSize(p.in_a), width) * std::min(GetSize(p.in_b), width) / 2;
+ }
+
+ static int bits_macc(const Macc &m, int width)
+ {
+ int bits = GetSize(m.bit_ports);
+ for (auto &p : m.ports)
+ bits += bits_macc_port(p, width);
+ return bits;
+ }
+
+ static int bits_macc(RTLIL::Cell *c)
+ {
+ Macc m(c);
+ int width = GetSize(c->getPort("\\Y"));
+ return bits_macc(m, width);
+ }
+
+ static bool cmp_macc_ports(const Macc::port_t &p1, const Macc::port_t &p2)
+ {
+ bool mul1 = GetSize(p1.in_a) && GetSize(p1.in_b);
+ bool mul2 = GetSize(p2.in_a) && GetSize(p2.in_b);
+
+ int w1 = mul1 ? GetSize(p1.in_a) * GetSize(p1.in_b) : GetSize(p1.in_a) + GetSize(p1.in_b);
+ int w2 = mul2 ? GetSize(p2.in_a) * GetSize(p2.in_b) : GetSize(p2.in_a) + GetSize(p2.in_b);
+
+ if (mul1 != mul2)
+ return mul1;
+
+ if (w1 != w2)
+ return w1 > w2;
+
+ if (p1.is_signed != p2.is_signed)
+ return p1.is_signed < p2.is_signed;
+
+ if (p1.do_subtract != p2.do_subtract)
+ return p1.do_subtract < p2.do_subtract;
+
+ if (p1.in_a != p2.in_a)
+ return p1.in_a < p2.in_a;
+
+ if (p1.in_b != p2.in_b)
+ return p1.in_b < p2.in_b;
+
+ return false;
+ }
+
+ int share_macc_ports(Macc::port_t &p1, Macc::port_t &p2, int w1, int w2,
+ RTLIL::SigSpec act = RTLIL::SigSpec(), Macc *supermacc = nullptr, pool<RTLIL::Cell*> *supercell_aux = nullptr)
+ {
+ if (p1.do_subtract != p2.do_subtract)
+ return -1;
+
+ bool mul1 = GetSize(p1.in_a) && GetSize(p1.in_b);
+ bool mul2 = GetSize(p2.in_a) && GetSize(p2.in_b);
+
+ if (mul1 != mul2)
+ return -1;
+
+ bool force_signed = false, force_not_signed = false;
+
+ if ((GetSize(p1.in_a) && GetSize(p1.in_a) < w1) || (GetSize(p1.in_b) && GetSize(p1.in_b) < w1)) {
+ if (p1.is_signed)
+ force_signed = true;
+ else
+ force_not_signed = true;
+ }
+
+ if ((GetSize(p2.in_a) && GetSize(p2.in_a) < w2) || (GetSize(p2.in_b) && GetSize(p2.in_b) < w2)) {
+ if (p2.is_signed)
+ force_signed = true;
+ else
+ force_not_signed = true;
+ }
+
+ if (force_signed && force_not_signed)
+ return -1;
+
+ if (supermacc)
+ {
+ RTLIL::SigSpec sig_a1 = p1.in_a, sig_b1 = p1.in_b;
+ RTLIL::SigSpec sig_a2 = p2.in_a, sig_b2 = p2.in_b;
+
+ RTLIL::SigSpec sig_a = GetSize(sig_a1) > GetSize(sig_a2) ? sig_a1 : sig_a2;
+ RTLIL::SigSpec sig_b = GetSize(sig_b1) > GetSize(sig_b2) ? sig_b1 : sig_b2;
+
+ sig_a1.extend_u0(GetSize(sig_a), p1.is_signed);
+ sig_b1.extend_u0(GetSize(sig_b), p1.is_signed);
+
+ sig_a2.extend_u0(GetSize(sig_a), p2.is_signed);
+ sig_b2.extend_u0(GetSize(sig_b), p2.is_signed);
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, sig_a2, sig_a1, act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, sig_b2, sig_b1, act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = force_signed;
+ p.do_subtract = p1.do_subtract;
+ supermacc->ports.push_back(p);
+ }
+
+ int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * std::max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
+
+ for (int i = 0; i < std::min(GetSize(p1.in_a), GetSize(p2.in_a)); i++)
+ if (p1.in_a[i] == p2.in_a[i] && score > 0)
+ score--;
+
+ for (int i = 0; i < std::min(GetSize(p1.in_b), GetSize(p2.in_b)); i++)
+ if (p1.in_b[i] == p2.in_b[i] && score > 0)
+ score--;
+
+ return score;
+ }
+
+ int share_macc(RTLIL::Cell *c1, RTLIL::Cell *c2,
+ RTLIL::SigSpec act = RTLIL::SigSpec(), RTLIL::Cell *supercell = nullptr, pool<RTLIL::Cell*> *supercell_aux = nullptr)
+ {
+ Macc m1(c1), m2(c2), supermacc;
+
+ int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y"));
+ int width = std::max(w1, w2);
+
+ m1.optimize(w1);
+ m2.optimize(w2);
+
+ std::sort(m1.ports.begin(), m1.ports.end(), cmp_macc_ports);
+ std::sort(m2.ports.begin(), m2.ports.end(), cmp_macc_ports);
+
+ std::set<int> m1_unmapped, m2_unmapped;
+
+ for (int i = 0; i < GetSize(m1.ports); i++)
+ m1_unmapped.insert(i);
+
+ for (int i = 0; i < GetSize(m2.ports); i++)
+ m2_unmapped.insert(i);
+
+ while (1)
+ {
+ int best_i = -1, best_j = -1, best_score = 0;
+
+ for (int i : m1_unmapped)
+ for (int j : m2_unmapped) {
+ int score = share_macc_ports(m1.ports[i], m2.ports[j], w1, w2);
+ if (score >= 0 && (best_i < 0 || best_score > score))
+ best_i = i, best_j = j, best_score = score;
+ }
+
+ if (best_i >= 0) {
+ m1_unmapped.erase(best_i);
+ m2_unmapped.erase(best_j);
+ share_macc_ports(m1.ports[best_i], m2.ports[best_j], w1, w2, act, &supermacc, supercell_aux);
+ } else
+ break;
+ }
+
+ for (int i : m1_unmapped)
+ {
+ RTLIL::SigSpec sig_a = m1.ports[i].in_a;
+ RTLIL::SigSpec sig_b = m1.ports[i].in_b;
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_a)), m1.ports[i].in_a, act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_b)), m1.ports[i].in_b, act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = m1.ports[i].is_signed;
+ p.do_subtract = m1.ports[i].do_subtract;
+ supermacc.ports.push_back(p);
+ }
+
+ for (int i : m2_unmapped)
+ {
+ RTLIL::SigSpec sig_a = m2.ports[i].in_a;
+ RTLIL::SigSpec sig_b = m2.ports[i].in_b;
+
+ if (supercell_aux && GetSize(sig_a)) {
+ sig_a = module->addWire(NEW_ID, GetSize(sig_a));
+ supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_a, RTLIL::SigSpec(0, GetSize(sig_a)), act, sig_a));
+ }
+
+ if (supercell_aux && GetSize(sig_b)) {
+ sig_b = module->addWire(NEW_ID, GetSize(sig_b));
+ supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_b, RTLIL::SigSpec(0, GetSize(sig_b)), act, sig_b));
+ }
+
+ Macc::port_t p;
+ p.in_a = sig_a;
+ p.in_b = sig_b;
+ p.is_signed = m2.ports[i].is_signed;
+ p.do_subtract = m2.ports[i].do_subtract;
+ supermacc.ports.push_back(p);
+ }
+
+ if (supercell)
+ {
+ RTLIL::SigSpec sig_y = module->addWire(NEW_ID, width);
+
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort("\\Y")));
+ supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort("\\Y")));
+
+ supercell->setParam("\\Y_WIDTH", width);
+ supercell->setPort("\\Y", sig_y);
+
+ supermacc.optimize(width);
+ supermacc.to_cell(supercell);
+ }
+
+ return bits_macc(supermacc, width);
+ }
+
+
+ // ---------------------------------------------------
// Find shareable cells and compatible groups of cells
// ---------------------------------------------------
- std::set<RTLIL::Cell*, RTLIL::sort_by_name_str<RTLIL::Cell>> shareable_cells;
+ pool<RTLIL::Cell*> shareable_cells;
void find_shareable_cells()
{
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
-
if (!design->selected(module, cell) || !modwalker.ct.cell_known(cell->type))
continue;
@@ -128,7 +369,9 @@ struct ShareWorker
}
if (cell->type == "$memrd") {
- if (!cell->parameters.at("\\CLK_ENABLE").as_bool())
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ continue;
+ if (config.opt_aggressive || !modwalker.sigmap(cell->getPort("\\ADDR")).is_fully_const())
shareable_cells.insert(cell);
continue;
}
@@ -146,7 +389,7 @@ struct ShareWorker
}
if (generic_ops.count(cell->type)) {
- if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 10)
+ if (config.opt_aggressive)
shareable_cells.insert(cell);
continue;
}
@@ -183,7 +426,7 @@ struct ShareWorker
return true;
}
- if (config.generic_bin_ops.count(c1->type))
+ if (config.generic_bin_ops.count(c1->type) || c1->type == "$alu")
{
if (!config.opt_aggressive)
{
@@ -229,6 +472,14 @@ struct ShareWorker
return true;
}
+ if (c1->type == "$macc")
+ {
+ if (!config.opt_aggressive)
+ if (share_macc(c1, c2) > 2 * std::min(bits_macc(c1), bits_macc(c2))) return false;
+
+ return true;
+ }
+
for (auto &it : c1->parameters)
if (c2->parameters.count(it.first) == 0 || c2->parameters.at(it.first) != it.second)
return false;
@@ -253,7 +504,7 @@ struct ShareWorker
// Create replacement cell
// -----------------------
- RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, std::set<RTLIL::Cell*> &supercell_aux)
+ RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, pool<RTLIL::Cell*> &supercell_aux)
{
log_assert(c1->type == c2->type);
@@ -306,7 +557,7 @@ struct ShareWorker
return supercell;
}
- if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type))
+ if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == "$alu")
{
bool modified_src_cells = false;
@@ -409,6 +660,8 @@ struct ShareWorker
supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b));
RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+ RTLIL::Wire *x = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
+ RTLIL::Wire *co = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr;
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
supercell->parameters["\\A_SIGNED"] = a_signed;
@@ -419,15 +672,39 @@ struct ShareWorker
supercell->setPort("\\A", a);
supercell->setPort("\\B", b);
supercell->setPort("\\Y", y);
+ if (c1->type == "$alu") {
+ RTLIL::Wire *ci = module->addWire(NEW_ID), *bi = module->addWire(NEW_ID);
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\CI"), c1->getPort("\\CI"), act, ci));
+ supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\BI"), c1->getPort("\\BI"), act, bi));
+ supercell->setPort("\\CI", ci);
+ supercell->setPort("\\BI", bi);
+ supercell->setPort("\\CO", co);
+ supercell->setPort("\\X", x);
+ }
supercell->check();
supercell_aux.insert(module->addPos(NEW_ID, y, y1));
supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+ if (c1->type == "$alu") {
+ supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort("\\CO")));
+ supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort("\\CO")));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort("\\X")));
+ supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort("\\X")));
+ }
supercell_aux.insert(supercell);
return supercell;
}
+ if (c1->type == "$macc")
+ {
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell_aux.insert(supercell);
+ share_macc(c1, c2, act, supercell, &supercell_aux);
+ supercell->check();
+ return supercell;
+ }
+
if (c1->type == "$memrd")
{
RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
@@ -444,20 +721,20 @@ struct ShareWorker
// Finding forbidden control inputs for a cell
// -------------------------------------------
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> forbidden_controls_cache;
+ std::map<RTLIL::Cell*, pool<RTLIL::SigBit>, cell_ptr_cmp> forbidden_controls_cache;
- const std::set<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
+ const pool<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
{
if (recursion_state.count(cell)) {
- static std::set<RTLIL::SigBit> empty_controls_set;
+ static pool<RTLIL::SigBit> empty_controls_set;
return empty_controls_set;
}
if (forbidden_controls_cache.count(cell))
return forbidden_controls_cache.at(cell);
- std::set<ModWalker::PortBit> pbits;
- std::set<RTLIL::Cell*> consumer_cells;
+ pool<ModWalker::PortBit> pbits;
+ pool<RTLIL::Cell*> consumer_cells;
modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
@@ -471,11 +748,11 @@ struct ShareWorker
for (auto c : consumer_cells)
if (fwd_ct.cell_known(c->type)) {
- const std::set<RTLIL::SigBit> &bits = find_forbidden_controls(c);
+ const pool<RTLIL::SigBit> &bits = find_forbidden_controls(c);
forbidden_controls_cache[cell].insert(bits.begin(), bits.end());
}
- log_assert(recursion_state.count(cell));
+ log_assert(recursion_state.count(cell) != 0);
recursion_state.erase(cell);
return forbidden_controls_cache[cell];
@@ -486,14 +763,14 @@ struct ShareWorker
// Finding control inputs and activation pattern for a cell
// --------------------------------------------------------
- std::map<RTLIL::Cell*, std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>>> activation_patterns_cache;
+ std::map<RTLIL::Cell*, pool<ssc_pair_t>, cell_ptr_cmp> activation_patterns_cache;
- bool sort_check_activation_pattern(std::pair<RTLIL::SigSpec, RTLIL::Const> &p)
+ bool sort_check_activation_pattern(ssc_pair_t &p)
{
std::map<RTLIL::SigBit, RTLIL::State> p_bits;
std::vector<RTLIL::SigBit> p_first_bits = p.first;
- for (int i = 0; i < SIZE(p_first_bits); i++) {
+ for (int i = 0; i < GetSize(p_first_bits); i++) {
RTLIL::SigBit b = p_first_bits[i];
RTLIL::State v = p.second.bits[i];
if (p_bits.count(b) && p_bits.at(b) != v)
@@ -512,30 +789,30 @@ struct ShareWorker
return true;
}
- void optimize_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> & /* patterns */)
+ void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */)
{
// TODO: Remove patterns that are contained in other patterns
// TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
}
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
+ const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
{
if (recursion_state.count(cell)) {
- static std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> empty_patterns_set;
+ static pool<ssc_pair_t> empty_patterns_set;
return empty_patterns_set;
}
if (activation_patterns_cache.count(cell))
return activation_patterns_cache.at(cell);
- const std::set<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
- std::set<RTLIL::Cell*> driven_cells, driven_data_muxes;
+ const pool<RTLIL::SigBit> &cell_out_bits = modwalker.cell_outputs[cell];
+ pool<RTLIL::Cell*> driven_cells, driven_data_muxes;
for (auto &bit : cell_out_bits)
{
if (terminal_bits.count(bit)) {
// Terminal cells are always active: unconditional activation pattern
- activation_patterns_cache[cell].insert(std::pair<RTLIL::SigSpec, RTLIL::Const>());
+ activation_patterns_cache[cell].insert(ssc_pair_t());
return activation_patterns_cache.at(cell);
}
for (auto &pbit : modwalker.signal_consumers[bit]) {
@@ -551,7 +828,7 @@ struct ShareWorker
for (auto c : driven_data_muxes)
{
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+ const pool<ssc_pair_t> &c_patterns = find_cell_activation_patterns(c, indent);
bool used_in_a = false;
std::set<int> used_in_b_parts;
@@ -565,13 +842,13 @@ struct ShareWorker
if (cell_out_bits.count(bit))
used_in_a = true;
- for (int i = 0; i < SIZE(sig_b); i++)
+ for (int i = 0; i < GetSize(sig_b); i++)
if (cell_out_bits.count(sig_b[i]))
used_in_b_parts.insert(i / width);
if (used_in_a)
for (auto p : c_patterns) {
- for (int i = 0; i < SIZE(sig_s); i++)
+ for (int i = 0; i < GetSize(sig_s); i++)
p.first.append_bit(sig_s[i]), p.second.bits.push_back(RTLIL::State::S0);
if (sort_check_activation_pattern(p))
activation_patterns_cache[cell].insert(p);
@@ -586,11 +863,11 @@ struct ShareWorker
}
for (auto c : driven_cells) {
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+ const pool<ssc_pair_t> &c_patterns = find_cell_activation_patterns(c, indent);
activation_patterns_cache[cell].insert(c_patterns.begin(), c_patterns.end());
}
- log_assert(recursion_state.count(cell));
+ log_assert(recursion_state.count(cell) != 0);
recursion_state.erase(cell);
optimize_activation_patterns(activation_patterns_cache[cell]);
@@ -604,7 +881,7 @@ struct ShareWorker
return activation_patterns_cache[cell];
}
- RTLIL::SigSpec bits_from_activation_patterns(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns)
+ RTLIL::SigSpec bits_from_activation_patterns(const pool<ssc_pair_t> &activation_patterns)
{
std::set<RTLIL::SigBit> all_bits;
for (auto &it : activation_patterns) {
@@ -619,15 +896,15 @@ struct ShareWorker
return signal;
}
- void filter_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &out,
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &in, const std::set<RTLIL::SigBit> &filter_bits)
+ void filter_activation_patterns(pool<ssc_pair_t> &out,
+ const pool<ssc_pair_t> &in, const std::set<RTLIL::SigBit> &filter_bits)
{
for (auto &p : in)
{
std::vector<RTLIL::SigBit> p_first = p.first;
- std::pair<RTLIL::SigSpec, RTLIL::Const> new_p;
+ ssc_pair_t new_p;
- for (int i = 0; i < SIZE(p_first); i++)
+ for (int i = 0; i < GetSize(p_first); i++)
if (filter_bits.count(p_first[i]) == 0) {
new_p.first.append_bit(p_first[i]);
new_p.second.bits.push_back(p.second.bits.at(i));
@@ -637,7 +914,7 @@ struct ShareWorker
}
}
- RTLIL::SigSpec make_cell_activation_logic(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns, std::set<RTLIL::Cell*> &supercell_aux)
+ RTLIL::SigSpec make_cell_activation_logic(const pool<ssc_pair_t> &activation_patterns, pool<RTLIL::Cell*> &supercell_aux)
{
RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0);
@@ -665,14 +942,14 @@ struct ShareWorker
ct.setup_internals();
ct.setup_stdcells();
- TopoSort<RTLIL::Cell*> toposort;
+ TopoSort<RTLIL::Cell*, cell_ptr_cmp> toposort;
toposort.analyze_loops = false;
topo_sigmap.set(module);
topo_bit_drivers.clear();
- std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bits;
- std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cells;
+ dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_bits;
+ dict<RTLIL::SigBit, pool<RTLIL::Cell*>> bit_to_cells;
for (auto cell : module->cells())
if (ct.cell_known(cell->type))
@@ -709,7 +986,7 @@ struct ShareWorker
return found_scc;
}
- bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, std::set<RTLIL::Cell*> &stop)
+ bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, pool<RTLIL::Cell*> &stop)
{
if (root == needle)
return true;
@@ -727,7 +1004,7 @@ struct ShareWorker
bool find_in_input_cone(RTLIL::Cell *root, RTLIL::Cell *needle)
{
- std::set<RTLIL::Cell*> stop;
+ pool<RTLIL::Cell*> stop;
return find_in_input_cone_worker(root, needle, stop);
}
@@ -737,12 +1014,12 @@ struct ShareWorker
ct.setup_internals();
ct.setup_stdcells();
- std::set<RTLIL::Cell*> queue, covered;
+ pool<RTLIL::Cell*> queue, covered;
queue.insert(cell);
while (!queue.empty())
{
- std::set<RTLIL::Cell*> new_queue;
+ pool<RTLIL::Cell*> new_queue;
for (auto c : queue) {
if (!ct.cell_known(c->type))
@@ -775,14 +1052,25 @@ struct ShareWorker
// Setup and run
// -------------
+ void remove_cell(Cell *cell)
+ {
+ shareable_cells.erase(cell);
+ forbidden_controls_cache.erase(cell);
+ activation_patterns_cache.erase(cell);
+ module->remove(cell);
+ }
+
ShareWorker(ShareWorkerConfig config, RTLIL::Design *design, RTLIL::Module *module) :
config(config), design(design), module(module), mi(module)
{
+ #ifndef NDEBUG
bool before_scc = module_has_scc();
+ #endif
generic_ops.insert(config.generic_uni_ops.begin(), config.generic_uni_ops.end());
generic_ops.insert(config.generic_bin_ops.begin(), config.generic_bin_ops.end());
generic_ops.insert(config.generic_cbin_ops.begin(), config.generic_cbin_ops.end());
+ generic_ops.insert(config.generic_other_ops.begin(), config.generic_other_ops.end());
fwd_ct.setup_internals();
@@ -805,16 +1093,23 @@ struct ShareWorker
return;
log("Found %d cells in module %s that may be considered for resource sharing.\n",
- SIZE(shareable_cells), log_id(module));
+ GetSize(shareable_cells), log_id(module));
+
+ for (auto cell : module->cells())
+ if (cell->type == "$pmux")
+ for (auto bit : cell->getPort("\\S"))
+ for (auto other_bit : cell->getPort("\\S"))
+ if (bit < other_bit)
+ exclusive_ctrls.push_back(std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit, other_bit));
while (!shareable_cells.empty() && config.limit != 0)
{
RTLIL::Cell *cell = *shareable_cells.begin();
shareable_cells.erase(cell);
- log(" Analyzing resource sharing options for %s:\n", log_id(cell));
+ log(" Analyzing resource sharing options for %s (%s):\n", log_id(cell), log_id(cell->type));
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
+ const pool<ssc_pair_t> &cell_activation_patterns = find_cell_activation_patterns(cell, " ");
RTLIL::SigSpec cell_activation_signals = bits_from_activation_patterns(cell_activation_patterns);
if (cell_activation_patterns.empty()) {
@@ -823,12 +1118,12 @@ struct ShareWorker
continue;
}
- if (cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ if (cell_activation_patterns.count(ssc_pair_t())) {
log(" Cell is always active. Therefore no sharing is possible.\n");
continue;
}
- log(" Found %d activation_patterns using ctrl signal %s.\n", SIZE(cell_activation_patterns), log_signal(cell_activation_signals));
+ log(" Found %d activation_patterns using ctrl signal %s.\n", GetSize(cell_activation_patterns), log_signal(cell_activation_signals));
std::vector<RTLIL::Cell*> candidates;
find_shareable_partners(candidates, cell);
@@ -838,16 +1133,16 @@ struct ShareWorker
continue;
}
- log(" Found %d candidates:", SIZE(candidates));
+ log(" Found %d candidates:", GetSize(candidates));
for (auto c : candidates)
log(" %s", log_id(c));
log("\n");
for (auto other_cell : candidates)
{
- log(" Analyzing resource sharing with %s:\n", log_id(other_cell));
+ log(" Analyzing resource sharing with %s (%s):\n", log_id(other_cell), log_id(other_cell->type));
- const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
+ const pool<ssc_pair_t> &other_cell_activation_patterns = find_cell_activation_patterns(other_cell, " ");
RTLIL::SigSpec other_cell_activation_signals = bits_from_activation_patterns(other_cell_activation_patterns);
if (other_cell_activation_patterns.empty()) {
@@ -857,17 +1152,17 @@ struct ShareWorker
continue;
}
- if (other_cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ if (other_cell_activation_patterns.count(ssc_pair_t())) {
log(" Cell is always active. Therefore no sharing is possible.\n");
shareable_cells.erase(other_cell);
continue;
}
log(" Found %d activation_patterns using ctrl signal %s.\n",
- SIZE(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
+ GetSize(other_cell_activation_patterns), log_signal(other_cell_activation_signals));
- const std::set<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
- const std::set<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
+ const pool<RTLIL::SigBit> &cell_forbidden_controls = find_forbidden_controls(cell);
+ const pool<RTLIL::SigBit> &other_cell_forbidden_controls = find_forbidden_controls(other_cell);
std::set<RTLIL::SigBit> union_forbidden_controls;
union_forbidden_controls.insert(cell_forbidden_controls.begin(), cell_forbidden_controls.end());
@@ -876,8 +1171,8 @@ struct ShareWorker
if (!union_forbidden_controls.empty())
log(" Forbidden control signals for this pair of cells: %s\n", log_signal(union_forbidden_controls));
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_cell_activation_patterns;
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> filtered_other_cell_activation_patterns;
+ pool<ssc_pair_t> filtered_cell_activation_patterns;
+ pool<ssc_pair_t> filtered_other_cell_activation_patterns;
filter_activation_patterns(filtered_cell_activation_patterns, cell_activation_patterns, union_forbidden_controls);
filter_activation_patterns(filtered_other_cell_activation_patterns, other_cell_activation_patterns, union_forbidden_controls);
@@ -885,10 +1180,10 @@ struct ShareWorker
optimize_activation_patterns(filtered_cell_activation_patterns);
optimize_activation_patterns(filtered_other_cell_activation_patterns);
- ezDefaultSAT ez;
- SatGen satgen(&ez, &modwalker.sigmap);
+ ezSatPtr ez;
+ SatGen satgen(ez.get(), &modwalker.sigmap);
- std::set<RTLIL::Cell*> sat_cells;
+ pool<RTLIL::Cell*> sat_cells;
std::set<RTLIL::SigBit> bits_queue;
std::vector<int> cell_active, other_cell_active;
@@ -896,13 +1191,13 @@ struct ShareWorker
for (auto &p : filtered_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
- cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
for (auto &p : filtered_other_cell_activation_patterns) {
log(" Activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
- other_cell_active.push_back(ez.vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
+ other_cell_active.push_back(ez->vec_eq(satgen.importSigSpec(p.first), satgen.importSigSpec(p.second)));
all_ctrl_signals.append(p.first);
}
@@ -914,7 +1209,7 @@ struct ShareWorker
while (!bits_queue.empty())
{
- std::set<ModWalker::PortBit> portbits;
+ pool<ModWalker::PortBit> portbits;
modwalker.get_drivers(portbits, bits_queue);
bits_queue.clear();
@@ -932,34 +1227,44 @@ struct ShareWorker
break;
}
- if (!ez.solve(ez.expression(ez.OpOr, cell_active))) {
+ for (auto it : exclusive_ctrls)
+ if (satgen.importedSigBit(it.first) && satgen.importedSigBit(it.second)) {
+ log(" Adding exclusive control bits: %s vs. %s\n", log_signal(it.first), log_signal(it.second));
+ int sub1 = satgen.importSigBit(it.first);
+ int sub2 = satgen.importSigBit(it.second);
+ ez->assume(ez->NOT(ez->AND(sub1, sub2)));
+ }
+
+ if (!ez->solve(ez->expression(ez->OpOr, cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(cell));
cells_to_remove.insert(cell);
break;
}
- if (!ez.solve(ez.expression(ez.OpOr, other_cell_active))) {
+ if (!ez->solve(ez->expression(ez->OpOr, other_cell_active))) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(other_cell));
cells_to_remove.insert(other_cell);
shareable_cells.erase(other_cell);
continue;
}
- ez.non_incremental();
+ ez->non_incremental();
all_ctrl_signals.sort_and_unify();
std::vector<int> sat_model = satgen.importSigSpec(all_ctrl_signals);
std::vector<bool> sat_model_values;
- ez.assume(ez.AND(ez.expression(ez.OpOr, cell_active), ez.expression(ez.OpOr, other_cell_active)));
+ int sub1 = ez->expression(ez->OpOr, cell_active);
+ int sub2 = ez->expression(ez->OpOr, other_cell_active);
+ ez->assume(ez->AND(sub1, sub2));
log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
- SIZE(sat_cells), ez.numCnfVariables(), ez.numCnfClauses());
+ GetSize(sat_cells), ez->numCnfVariables(), ez->numCnfClauses());
- if (ez.solve(sat_model, sat_model_values)) {
+ if (ez->solve(sat_model, sat_model_values)) {
log(" According to the SAT solver this pair of cells can not be shared.\n");
- log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), SIZE(sat_model_values));
- for (int i = SIZE(sat_model_values)-1; i >= 0; i--)
+ log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), GetSize(sat_model_values));
+ for (int i = GetSize(sat_model_values)-1; i >= 0; i--)
log("%c", sat_model_values[i] ? '1' : '0');
log("\n");
continue;
@@ -989,7 +1294,7 @@ struct ShareWorker
other_cell_select_score += p.first.size();
RTLIL::Cell *supercell;
- std::set<RTLIL::Cell*> supercell_aux;
+ pool<RTLIL::Cell*> supercell_aux;
if (cell_select_score <= other_cell_select_score) {
RTLIL::SigSpec act = make_cell_activation_logic(filtered_cell_activation_patterns, supercell_aux);
supercell = make_supercell(cell, other_cell, act, supercell_aux);
@@ -1016,11 +1321,11 @@ struct ShareWorker
cells_to_remove.erase(other_cell);
shareable_cells.insert(other_cell);
for (auto cc : supercell_aux)
- module->remove(cc);
+ remove_cell(cc);
continue;
}
- std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> supercell_activation_patterns;
+ pool<ssc_pair_t> supercell_activation_patterns;
supercell_activation_patterns.insert(filtered_cell_activation_patterns.begin(), filtered_cell_activation_patterns.end());
supercell_activation_patterns.insert(filtered_other_cell_activation_patterns.begin(), filtered_other_cell_activation_patterns.end());
optimize_activation_patterns(supercell_activation_patterns);
@@ -1045,17 +1350,19 @@ struct ShareWorker
}
if (!cells_to_remove.empty()) {
- log("Removing %d cells in module %s:\n", SIZE(cells_to_remove), log_id(module));
+ log("Removing %d cells in module %s:\n", GetSize(cells_to_remove), log_id(module));
for (auto c : cells_to_remove) {
log(" Removing cell %s (%s).\n", log_id(c), log_id(c->type));
- module->remove(c);
+ remove_cell(c);
}
}
log_assert(recursion_state.empty());
+ #ifndef NDEBUG
bool after_scc = before_scc || module_has_scc();
log_assert(before_scc == after_scc);
+ #endif
}
};
@@ -1137,6 +1444,9 @@ struct SharePass : public Pass {
config.generic_cbin_ops.insert("$logic_and");
config.generic_cbin_ops.insert("$logic_or");
+ config.generic_other_ops.insert("$alu");
+ config.generic_other_ops.insert("$macc");
+
log_header("Executing SHARE pass (SAT-based resource sharing).\n");
size_t argidx;
@@ -1168,4 +1478,3 @@ struct SharePass : public Pass {
} SharePass;
PRIVATE_NAMESPACE_END
-
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 58a6d1b0..fc91f368 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -28,18 +28,18 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig
{
- std::set<IdString> supported_cell_types;
+ pool<IdString> supported_cell_types;
WreduceConfig()
{
- supported_cell_types = {
+ supported_cell_types = pool<IdString>({
"$not", "$pos", "$neg",
"$and", "$or", "$xor", "$xnor",
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$add", "$sub", // "$mul", "$div", "$mod", "$pow",
"$mux", "$pmux"
- };
+ });
}
};
@@ -65,20 +65,20 @@ struct WreduceWorker
SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
std::vector<SigBit> bits_removed;
- for (int i = SIZE(sig_y)-1; i >= 0; i--)
+ for (int i = GetSize(sig_y)-1; i >= 0; i--)
{
auto info = mi.query(sig_y[i]);
- if (!info->is_output && SIZE(info->ports) <= 1) {
+ if (!info->is_output && GetSize(info->ports) <= 1) {
bits_removed.push_back(Sx);
continue;
}
SigBit ref = sig_a[i];
- for (int k = 0; k < SIZE(sig_s); k++) {
- if (ref != Sx && sig_b[k*SIZE(sig_a) + i] != Sx && ref != sig_b[k*SIZE(sig_a) + i])
+ for (int k = 0; k < GetSize(sig_s); k++) {
+ if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
- if (sig_b[k*SIZE(sig_a) + i] != Sx)
- ref = sig_b[k*SIZE(sig_a) + i];
+ if (sig_b[k*GetSize(sig_a) + i] != Sx)
+ ref = sig_b[k*GetSize(sig_a) + i];
}
if (0)
no_match_ab:
@@ -90,10 +90,10 @@ struct WreduceWorker
return;
SigSpec sig_removed;
- for (int i = SIZE(bits_removed)-1; i >= 0; i--)
+ for (int i = GetSize(bits_removed)-1; i >= 0; i--)
sig_removed.append_bit(bits_removed[i]);
- if (SIZE(bits_removed) == SIZE(sig_y)) {
+ if (GetSize(bits_removed) == GetSize(sig_y)) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->connect(sig_y, sig_removed);
module->remove(cell);
@@ -101,10 +101,10 @@ struct WreduceWorker
}
log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n",
- SIZE(sig_removed), SIZE(sig_y), log_id(module), log_id(cell), log_id(cell->type));
+ GetSize(sig_removed), GetSize(sig_y), log_id(module), log_id(cell), log_id(cell->type));
- int n_removed = SIZE(sig_removed);
- int n_kept = SIZE(sig_y) - SIZE(sig_removed);
+ int n_removed = GetSize(sig_removed);
+ int n_kept = GetSize(sig_y) - GetSize(sig_removed);
SigSpec new_work_queue_bits;
new_work_queue_bits.append(sig_a.extract(n_kept, n_removed));
@@ -114,9 +114,9 @@ struct WreduceWorker
SigSpec new_sig_y = sig_y.extract(0, n_kept);
SigSpec new_sig_b;
- for (int k = 0; k < SIZE(sig_s); k++) {
- new_sig_b.append(sig_b.extract(k*SIZE(sig_a), n_kept));
- new_work_queue_bits.append(sig_b.extract(k*SIZE(sig_a) + n_kept, n_removed));
+ for (int k = 0; k < GetSize(sig_s); k++) {
+ new_sig_b.append(sig_b.extract(k*GetSize(sig_a), n_kept));
+ new_work_queue_bits.append(sig_b.extract(k*GetSize(sig_a) + n_kept, n_removed));
}
for (auto bit : new_work_queue_bits)
@@ -139,24 +139,24 @@ struct WreduceWorker
port_signed = false;
int bits_removed = 0;
- if (SIZE(sig) > max_port_size) {
- bits_removed = SIZE(sig) - max_port_size;
+ if (GetSize(sig) > max_port_size) {
+ bits_removed = GetSize(sig) - max_port_size;
for (auto bit : sig.extract(max_port_size, bits_removed))
work_queue_bits.insert(bit);
sig = sig.extract(0, max_port_size);
}
if (port_signed) {
- while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == sig[SIZE(sig)-2])
- work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2])
+ work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
} else {
- while (SIZE(sig) > 1 && sig[SIZE(sig)-1] == S0)
- work_queue_bits.insert(sig[SIZE(sig)-1]), sig.remove(SIZE(sig)-1), bits_removed++;
+ while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0)
+ work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
}
if (bits_removed) {
log("Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n",
- bits_removed, SIZE(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
+ bits_removed, GetSize(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
cell->setPort(stringf("\\%c", port), sig);
did_something = true;
}
@@ -175,12 +175,12 @@ struct WreduceWorker
// Reduce size of ports A and B based on constant input bits and size of output port
- int max_port_a_size = cell->hasPort("\\A") ? SIZE(cell->getPort("\\A")) : -1;
- int max_port_b_size = cell->hasPort("\\B") ? SIZE(cell->getPort("\\B")) : -1;
+ int max_port_a_size = cell->hasPort("\\A") ? GetSize(cell->getPort("\\A")) : -1;
+ int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1;
if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
- max_port_a_size = std::min(max_port_a_size, SIZE(cell->getPort("\\Y")));
- max_port_b_size = std::min(max_port_b_size, SIZE(cell->getPort("\\Y")));
+ max_port_a_size = std::min(max_port_a_size, GetSize(cell->getPort("\\Y")));
+ max_port_b_size = std::min(max_port_b_size, GetSize(cell->getPort("\\Y")));
}
bool port_a_signed = false;
@@ -201,14 +201,14 @@ struct WreduceWorker
if (port_a_signed && cell->type == "$shr") {
// do not reduce size of output on $shr cells with signed A inputs
} else {
- while (SIZE(sig) > 0)
+ while (GetSize(sig) > 0)
{
- auto info = mi.query(sig[SIZE(sig)-1]);
+ auto info = mi.query(sig[GetSize(sig)-1]);
- if (info->is_output || SIZE(info->ports) > 1)
+ if (info->is_output || GetSize(info->ports) > 1)
break;
- sig.remove(SIZE(sig)-1);
+ sig.remove(GetSize(sig)-1);
bits_removed++;
}
}
@@ -218,8 +218,8 @@ struct WreduceWorker
bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
int a_size = 0, b_size = 0;
- if (cell->hasPort("\\A")) a_size = SIZE(cell->getPort("\\A"));
- if (cell->hasPort("\\B")) b_size = SIZE(cell->getPort("\\B"));
+ if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
+ if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B"));
int max_y_size = std::max(a_size, b_size);
@@ -229,14 +229,14 @@ struct WreduceWorker
if (cell->type == "$mul")
max_y_size = a_size + b_size;
- while (SIZE(sig) > 1 && SIZE(sig) > max_y_size) {
- module->connect(sig[SIZE(sig)-1], is_signed ? sig[SIZE(sig)-2] : S0);
- sig.remove(SIZE(sig)-1);
+ while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) {
+ module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0);
+ sig.remove(GetSize(sig)-1);
bits_removed++;
}
}
- if (SIZE(sig) == 0) {
+ if (GetSize(sig) == 0) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->remove(cell);
return;
@@ -244,7 +244,7 @@ struct WreduceWorker
if (bits_removed) {
log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
- bits_removed, SIZE(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
+ bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
cell->setPort("\\Y", sig);
did_something = true;
}
@@ -281,6 +281,10 @@ struct WreduceWorker
work_queue_cells.insert(port.cell);
}
+ pool<SigSpec> complete_wires;
+ for (auto w : module->wires())
+ complete_wires.insert(mi.sigmap(w));
+
for (auto w : module->selected_wires())
{
int unused_top_bits = 0;
@@ -288,27 +292,30 @@ struct WreduceWorker
if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
continue;
- for (int i = SIZE(w)-1; i >= 0; i--) {
+ for (int i = GetSize(w)-1; i >= 0; i--) {
SigBit bit(w, i);
auto info = mi.query(bit);
- if (info && (info->is_input || info->is_output || SIZE(info->ports) > 0))
+ if (info && (info->is_input || info->is_output || GetSize(info->ports) > 0))
break;
unused_top_bits++;
}
- if (0 < unused_top_bits && unused_top_bits < SIZE(w)) {
- log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, SIZE(w), log_id(module), log_id(w));
- Wire *nw = module->addWire(NEW_ID, w);
- nw->width = SIZE(w) - unused_top_bits;
- module->connect(nw, SigSpec(w).extract(0, SIZE(nw)));
- module->swap_names(w, nw);
- }
+ if (unused_top_bits == 0 || unused_top_bits == GetSize(w))
+ continue;
+
+ if (complete_wires[mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits)])
+ continue;
+
+ log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w));
+ Wire *nw = module->addWire(NEW_ID, GetSize(w) - unused_top_bits);
+ module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
+ module->swap_names(w, nw);
}
}
};
struct WreducePass : public Pass {
- WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { }
+ WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc
index dfbc78ea..397fe46a 100644
--- a/passes/proc/Makefile.inc
+++ b/passes/proc/Makefile.inc
@@ -5,5 +5,6 @@ OBJS += passes/proc/proc_rmdead.o
OBJS += passes/proc/proc_init.o
OBJS += passes/proc/proc_arst.o
OBJS += passes/proc/proc_mux.o
+OBJS += passes/proc/proc_dlatch.o
OBJS += passes/proc/proc_dff.o
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index 36d4141b..40b2b30f 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <stdio.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct ProcPass : public Pass {
ProcPass() : Pass("proc", "translate processes to netlists") { }
virtual void help()
@@ -37,10 +40,12 @@ struct ProcPass : public Pass {
log(" proc_init\n");
log(" proc_arst\n");
log(" proc_mux\n");
+ log(" proc_dlatch\n");
log(" proc_dff\n");
log(" proc_clean\n");
log("\n");
- log("This replaces the processes in the design with multiplexers and flip-flops.\n");
+ log("This replaces the processes in the design with multiplexers,\n");
+ log("flip-flops and latches.\n");
log("\n");
log("The following options are supported:\n");
log("\n");
@@ -74,6 +79,7 @@ struct ProcPass : public Pass {
else
Pass::call(design, "proc_arst -global_arst " + global_arst);
Pass::call(design, "proc_mux");
+ Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
Pass::call(design, "proc_clean");
@@ -81,3 +87,4 @@ struct ProcPass : public Pass {
}
} ProcPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index f11b328f..27c6b3bc 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -23,10 +23,14 @@
#include <stdlib.h>
#include <stdio.h>
-// defined in proc_clean.cc
+YOSYS_NAMESPACE_BEGIN
extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_END
-static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
{
if (signal.size() != 1)
return false;
@@ -81,7 +85,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp
return false;
}
-static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
+void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::SigSpec &rval, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity, bool unknown)
{
for (auto &action : cs->actions) {
if (unknown)
@@ -114,7 +118,7 @@ static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::S
}
}
-static void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
+void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigSpec const_sig, bool polarity)
{
for (auto sw : cs->switches) {
bool this_polarity = polarity;
@@ -149,7 +153,7 @@ static void eliminate_const(RTLIL::Module *mod, RTLIL::CaseRule *cs, RTLIL::SigS
}
}
-static void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
+void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_map)
{
restart_proc_arst:
if (proc->root_case.switches.size() != 1)
@@ -170,7 +174,7 @@ restart_proc_arst:
for (auto &action : sync->actions) {
RTLIL::SigSpec rspec = action.second;
RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
- for (int i = 0; i < SIZE(rspec); i++)
+ for (int i = 0; i < GetSize(rspec); i++)
if (rspec[i].wire == NULL)
rval[i] = rspec[i];
RTLIL::SigSpec last_rval;
@@ -258,7 +262,7 @@ struct ProcArstPass : public Pass {
for (auto &chunk : act.first.chunks())
if (chunk.wire && chunk.wire->attributes.count("\\init")) {
RTLIL::SigSpec value = chunk.wire->attributes.at("\\init");
- value.extend(chunk.wire->width, false);
+ value.extend_u0(chunk.wire->width, false);
arst_sig.append(chunk);
arst_val.append(value.extract(chunk.offset, chunk.width));
}
@@ -280,3 +284,4 @@ struct ProcArstPass : public Pass {
}
} ProcArstPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 1e3dd9ce..82716cd0 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -22,8 +22,12 @@
#include <stdlib.h>
#include <stdio.h>
-extern void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_BEGIN
extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth);
+YOSYS_NAMESPACE_END
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth)
{
@@ -89,6 +93,9 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
}
}
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int max_depth)
{
for (size_t i = 0; i < cs->actions.size(); i++) {
@@ -109,7 +116,10 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m
}
}
-static void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count)
{
int count = 0;
bool did_something = true;
@@ -174,3 +184,4 @@ struct ProcCleanPass : public Pass {
}
} ProcCleanPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index e69e8023..76842da6 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -25,7 +25,10 @@
#include <stdlib.h>
#include <stdio.h>
-static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
{
RTLIL::SigSpec lvalue;
@@ -50,7 +53,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
return lvalue;
}
-static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
+void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> &async_rules, RTLIL::Process *proc)
{
RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.size());
@@ -140,7 +143,7 @@ static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::S
cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
}
-static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
+void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
{
std::stringstream sstr;
@@ -187,7 +190,7 @@ static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec
clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
}
-static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
+void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
{
std::stringstream sstr;
@@ -215,7 +218,7 @@ static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_
log(".\n");
}
-static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
+void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
{
while (1)
{
@@ -330,12 +333,12 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
if (many_async_rules.size() > 0)
{
- log("WARNING: Complex async reset for dff `%s'.\n", log_signal(sig));
+ log_warning("Complex async reset for dff `%s'.\n", log_signal(sig));
gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, many_async_rules, proc);
}
else if (!rstval.is_fully_const() && !ce.eval(rstval))
{
- log("WARNING: Async reset value `%s' is not constant!\n", log_signal(rstval));
+ log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval));
gen_dffsr(mod, insig, rstval, sig,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
@@ -380,3 +383,4 @@ struct ProcDffPass : public Pass {
}
} ProcDffPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
new file mode 100644
index 00000000..e1bbab54
--- /dev/null
+++ b/passes/proc/proc_dlatch.cc
@@ -0,0 +1,308 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/consteval.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct proc_dlatch_db_t
+{
+ Module *module;
+ SigMap sigmap;
+
+ dict<SigBit, pair<Cell*, int>> mux_drivers;
+ dict<SigBit, int> sigusers;
+
+ proc_dlatch_db_t(Module *module) : module(module), sigmap(module)
+ {
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in("$mux", "$pmux")) {
+ auto sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < GetSize(sig_y); i++)
+ mux_drivers[sig_y[i]] = pair<Cell*, int>(cell, i);
+ }
+
+ for (auto &conn : cell->connections())
+ if (!cell->known() || cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigusers[bit]++;
+ }
+
+ for (auto wire : module->wires())
+ if (wire->port_input)
+ for (auto bit : sigmap(wire))
+ sigusers[bit]++;
+ }
+
+ struct rule_node_t
+ {
+ // a node is true if "signal" equals "match" and [any
+ // of the child nodes is true or "children" is empty]
+ SigBit signal, match;
+ vector<int> children;
+
+ bool operator==(const rule_node_t &other) const {
+ return signal == other.signal && match == other.match && children == other.children;
+ }
+
+ unsigned int hash() const {
+ unsigned int h = mkhash_init;
+ mkhash(h, signal.hash());
+ mkhash(h, match.hash());
+ for (auto i : children) mkhash(h, i);
+ return h;
+ }
+ };
+
+ enum tf_node_types_t : int {
+ true_node = 1,
+ false_node = 2
+ };
+
+ idict<rule_node_t, 3> rules_db;
+ dict<int, SigBit> rules_sig;
+
+ int make_leaf(SigBit signal, SigBit match)
+ {
+ rule_node_t node;
+ node.signal = signal;
+ node.match = match;
+ return rules_db(node);
+ }
+
+ int make_inner(SigBit signal, SigBit match, int child)
+ {
+ rule_node_t node;
+ node.signal = signal;
+ node.match = match;
+ node.children.push_back(child);
+ return rules_db(node);
+ }
+
+ int make_inner(const pool<int> &children)
+ {
+ rule_node_t node;
+ node.signal = State::S0;
+ node.match = State::S0;
+ node.children = vector<int>(children.begin(), children.end());
+ std::sort(node.children.begin(), node.children.end());
+ return rules_db(node);
+ }
+
+ int find_mux_feedback(SigBit haystack, SigBit needle, bool set_undef)
+ {
+ if (sigusers[haystack] > 1)
+ set_undef = false;
+
+ if (haystack == needle)
+ return true_node;
+
+ auto it = mux_drivers.find(haystack);
+ if (it == mux_drivers.end())
+ return false_node;
+
+ Cell *cell = it->second.first;
+ int index = it->second.second;
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+ int width = GetSize(sig_a);
+
+ pool<int> children;
+
+ int n = find_mux_feedback(sig_a[index], needle, set_undef);
+ if (n != false_node) {
+ if (set_undef && sig_a[index] == needle) {
+ SigSpec sig = cell->getPort("\\A");
+ sig[index] = State::Sx;
+ cell->setPort("\\A", sig);
+ }
+ for (int i = 0; i < GetSize(sig_s); i++)
+ n = make_inner(sig_s[i], State::S0, n);
+ children.insert(n);
+ }
+
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ n = find_mux_feedback(sig_b[i*width + index], needle, set_undef);
+ if (n != false_node) {
+ if (set_undef && sig_b[i*width + index] == needle) {
+ SigSpec sig = cell->getPort("\\B");
+ sig[i*width + index] = State::Sx;
+ cell->setPort("\\B", sig);
+ }
+ children.insert(make_inner(sig_s[i], State::S1, n));
+ }
+ }
+
+ if (children.empty())
+ return false_node;
+
+ return make_inner(children);
+ }
+
+ SigBit make_hold(int n)
+ {
+ if (n == true_node)
+ return State::S1;
+
+ if (n == false_node)
+ return State::S0;
+
+ if (rules_sig.count(n))
+ return rules_sig.at(n);
+
+ const rule_node_t &rule = rules_db[n];
+ SigSpec and_bits;
+
+ if (rule.signal != rule.match) {
+ if (rule.match == State::S1)
+ and_bits.append(rule.signal);
+ else if (rule.match == State::S0)
+ and_bits.append(module->Not(NEW_ID, rule.signal));
+ else
+ and_bits.append(module->Eq(NEW_ID, rule.signal, rule.match));
+ }
+
+ if (!rule.children.empty()) {
+ SigSpec or_bits;
+ for (int k : rule.children)
+ or_bits.append(make_hold(k));
+ and_bits.append(module->ReduceOr(NEW_ID, or_bits));
+ }
+
+ if (GetSize(and_bits) == 2)
+ and_bits = module->And(NEW_ID, and_bits[0], and_bits[1]);
+ log_assert(GetSize(and_bits) == 1);
+
+ rules_sig[n] = and_bits[0];
+ return and_bits[0];
+ }
+};
+
+void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
+{
+ std::vector<RTLIL::SyncRule*> new_syncs;
+ RTLIL::SigSig latches_bits, nolatches_bits;
+ dict<SigBit, SigBit> latches_out_in;
+ dict<SigBit, int> latches_hold;
+
+ for (auto sr : proc->syncs)
+ {
+ if (sr->type != RTLIL::SyncType::STa) {
+ new_syncs.push_back(sr);
+ continue;
+ }
+
+ for (auto ss : sr->actions) {
+ db.sigmap.apply(ss.first);
+ db.sigmap.apply(ss.second);
+ for (int i = 0; i < GetSize(ss.first); i++)
+ latches_out_in[ss.first[i]] = ss.second[i];
+ }
+
+ delete sr;
+ }
+
+ latches_out_in.sort();
+ for (auto &it : latches_out_in) {
+ int n = db.find_mux_feedback(it.second, it.first, true);
+ if (n == db.false_node) {
+ nolatches_bits.first.append(it.first);
+ nolatches_bits.second.append(it.second);
+ } else {
+ latches_bits.first.append(it.first);
+ latches_bits.second.append(it.second);
+ latches_hold[it.first] = n;
+ }
+ }
+
+ int offset = 0;
+ for (auto chunk : nolatches_bits.first.chunks()) {
+ SigSpec lhs = chunk, rhs = nolatches_bits.second.extract(offset, chunk.width);
+ log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n",
+ db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str());
+ db.module->connect(lhs, rhs);
+ offset += chunk.width;
+ }
+
+ offset = 0;
+ while (offset < GetSize(latches_bits.first))
+ {
+ int width = 1;
+ int n = latches_hold[latches_bits.first[offset]];
+ Wire *w = latches_bits.first[offset].wire;
+
+ if (w != nullptr)
+ {
+ while (offset+width < GetSize(latches_bits.first) &&
+ n == latches_hold[latches_bits.first[offset+width]] &&
+ w == latches_bits.first[offset+width].wire)
+ width++;
+
+ SigSpec lhs = latches_bits.first.extract(offset, width);
+ SigSpec rhs = latches_bits.second.extract(offset, width);
+
+ Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
+ db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
+ }
+
+ offset += width;
+ }
+
+ new_syncs.swap(proc->syncs);
+}
+
+struct ProcDlatchPass : public Pass {
+ ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" proc_dlatch [selection]\n");
+ log("\n");
+ log("This pass identifies latches in the processes and converts them to\n");
+ log("d-type latches.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing PROC_DLATCH pass (convert process syncs to latches).\n");
+
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules()) {
+ proc_dlatch_db_t db(module);
+ for (auto &proc_it : module->processes)
+ if (design->selected(module, proc_it.second))
+ proc_dlatch(db, proc_it.second);
+ }
+ }
+} ProcDlatchPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index c72840c0..dff68159 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -23,7 +23,10 @@
#include <stdlib.h>
#include <stdio.h>
-static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
{
log_assert(rule.compare.size() == 0);
@@ -37,7 +40,7 @@ static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
}
}
-static void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
{
bool found_init = false;
@@ -109,3 +112,4 @@ struct ProcInitPass : public Pass {
}
} ProcInitPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index c00b00a2..4aa1aab5 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -24,7 +24,10 @@
#include <stdlib.h>
#include <stdio.h>
-static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
{
for (auto &action : cs->actions) {
if (action.first.size())
@@ -41,7 +44,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
return RTLIL::SigSpec();
}
-static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
+void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
{
for (auto &action : cs->actions) {
RTLIL::SigSpec lvalue = action.first.extract(sig);
@@ -54,7 +57,7 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
extract_core_signal(cs2, sig);
}
-static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
{
std::stringstream sstr;
sstr << "$procmux$" << (autoidx++);
@@ -122,7 +125,7 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
return RTLIL::SigSpec(ctrl_wire);
}
-static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
{
log_assert(when_signal.size() == else_signal.size());
@@ -156,7 +159,7 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
return RTLIL::SigSpec(result_wire);
}
-static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
+void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
{
log_assert(last_mux_cell != NULL);
log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
@@ -176,7 +179,7 @@ static void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
-static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
{
RTLIL::SigSpec result = defval;
@@ -233,7 +236,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
return result;
}
-static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
{
bool first = true;
while (1)
@@ -283,3 +286,4 @@ struct ProcMuxPass : public Pass {
}
} ProcMuxPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index fe3532da..427e0d56 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -25,13 +25,16 @@
#include <stdio.h>
#include <set>
-static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
{
BitPatternPool pool(sw->signal);
for (size_t i = 0; i < sw->cases.size(); i++)
{
- bool is_default = SIZE(sw->cases[i]->compare) == 0 && (!pool.empty() || SIZE(sw->signal) == 0);
+ bool is_default = GetSize(sw->cases[i]->compare) == 0 && (!pool.empty() || GetSize(sw->signal) == 0);
for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) {
RTLIL::SigSpec sig = sw->cases[i]->compare[j];
@@ -98,3 +101,4 @@ struct ProcRmdeadPass : public Pass {
}
} ProcRmdeadPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index f07ad943..01d0e031 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -31,7 +31,8 @@
#include <string.h>
#include <algorithm>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
/* this should only be used for regression testing of ConstEval -- see vloghammer */
struct BruteForceEquivChecker
@@ -68,7 +69,7 @@ struct BruteForceEquivChecker
log_signal(undef2), log_signal(mod1_inputs), log_signal(inputs));
if (ignore_x_mod1) {
- for (int i = 0; i < SIZE(sig1); i++)
+ for (int i = 0; i < GetSize(sig1); i++)
if (sig1[i] == RTLIL::State::Sx)
sig2[i] = RTLIL::State::Sx;
}
@@ -142,16 +143,16 @@ struct VlogHammerReporter
{
log("Verifying SAT model (%s)..\n", model_undef ? "with undef" : "without undef");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
satgen.model_undef = model_undef;
for (auto &c : module->cells_)
if (!satgen.importCell(c.second))
log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
- ez.assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals));
+ ez->assume(satgen.signals_eq(recorded_set_vars, recorded_set_vals));
std::vector<int> y_vec = satgen.importDefSigSpec(module->wires_.at("\\y"));
std::vector<bool> y_values;
@@ -162,9 +163,9 @@ struct VlogHammerReporter
}
log(" Created SAT problem with %d variables and %d clauses.\n",
- ez.numCnfVariables(), ez.numCnfClauses());
+ ez->numCnfVariables(), ez->numCnfClauses());
- if (!ez.solve(y_vec, y_values))
+ if (!ez->solve(y_vec, y_values))
log_error("Failed to find solution to SAT problem.\n");
for (int i = 0; i < expected_y.size(); i++) {
@@ -203,7 +204,7 @@ struct VlogHammerReporter
if (y_undef.at(i))
{
log(" Toggling undef bit %d to test undef gating.\n", i);
- if (!ez.solve(y_vec, y_values, ez.IFF(y_vec.at(i), y_values.at(i) ? ez.FALSE : ez.TRUE)))
+ if (!ez->solve(y_vec, y_values, ez->IFF(y_vec.at(i), y_values.at(i) ? ez->CONST_FALSE : ez->CONST_TRUE)))
log_error("Failed to find solution with toggled bit!\n");
cmp_vars.push_back(y_vec.at(expected_y.size() + i));
@@ -219,15 +220,15 @@ struct VlogHammerReporter
}
log(" Testing if SAT solution is unique.\n");
- ez.assume(ez.vec_ne(cmp_vars, ez.vec_const(cmp_vals)));
- if (ez.solve(y_vec, y_values))
+ ez->assume(ez->vec_ne(cmp_vars, ez->vec_const(cmp_vals)));
+ if (ez->solve(y_vec, y_values))
log_error("Found two distinct solutions to SAT problem.\n");
}
else
{
log(" Testing if SAT solution is unique.\n");
- ez.assume(ez.vec_ne(y_vec, ez.vec_const(y_values)));
- if (ez.solve(y_vec, y_values))
+ ez->assume(ez->vec_ne(y_vec, ez->vec_const(y_values)));
+ if (ez->solve(y_vec, y_values))
log_error("Found two distinct solutions to SAT problem.\n");
}
@@ -276,7 +277,7 @@ struct VlogHammerReporter
while (!ce.eval(sig, undef)) {
// log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(undef));
- log("Warning: Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name));
+ log_warning("Setting signal %s in module %s to undef.\n", log_signal(undef), RTLIL::id2cstr(module->name));
ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
}
@@ -289,7 +290,7 @@ struct VlogHammerReporter
} else if (rtl_sig.size() > 0) {
if (rtl_sig.size() != sig.size())
log_error("Output (y) has a different width in module %s compared to rtl!\n", RTLIL::id2cstr(module->name));
- for (int i = 0; i < SIZE(sig); i++)
+ for (int i = 0; i < GetSize(sig); i++)
if (rtl_sig[i] == RTLIL::State::Sx)
sig[i] = RTLIL::State::Sx;
}
@@ -357,8 +358,6 @@ struct VlogHammerReporter
}
};
-} /* namespace */
-
struct EvalPass : public Pass {
EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
virtual void help()
@@ -601,3 +600,4 @@ struct EvalPass : public Pass {
}
} EvalPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index e856fdf7..b012bc6a 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -23,6 +23,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct dff_map_info_t {
RTLIL::SigSpec sig_d, sig_clk, sig_arst;
bool clk_polarity, arst_polarity;
@@ -37,7 +40,7 @@ struct dff_map_bit_info_t {
RTLIL::Cell *cell;
};
-static bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
+bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_info_t> &dff_dq_map)
{
if (wire->name[0] == '$' || dff_dq_map.count(wire->name))
return false;
@@ -46,7 +49,7 @@ static bool consider_wire(RTLIL::Wire *wire, std::map<RTLIL::IdString, dff_map_i
return true;
}
-static bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
+bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_cells, RTLIL::Cell *cell)
{
if (cell->name[0] == '$' || dff_cells.count(cell->name))
return false;
@@ -55,7 +58,7 @@ static bool consider_cell(RTLIL::Design *design, std::set<RTLIL::IdString> &dff_
return true;
}
-static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
+bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
{
log_assert(wire1->name == wire2->name);
if (wire1->width != wire2->width)
@@ -63,7 +66,7 @@ static bool compare_wires(RTLIL::Wire *wire1, RTLIL::Wire *wire2)
return true;
}
-static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
+bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
{
log_assert(cell1->name == cell2->name);
if (cell1->type != cell2->type)
@@ -73,7 +76,7 @@ static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
return true;
}
-static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
+void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
{
CellTypes ct;
ct.setup_internals_mem();
@@ -93,7 +96,7 @@ static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *
}
}
-static void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
+void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
{
std::map<RTLIL::SigBit, dff_map_bit_info_t> bit_info;
SigMap sigmap(module);
@@ -208,7 +211,7 @@ static void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RT
}
}
-static RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
+RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
{
if (module->count_id(name))
log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", log_id(name));
@@ -604,7 +607,7 @@ struct ExposePass : public Pass {
RTLIL::SigSpec sig;
if (cell->hasPort(p->name))
sig = cell->getPort(p->name);
- sig.extend(w->width);
+ sig.extend_u0(w->width);
if (w->port_input)
module->connect(RTLIL::SigSig(sig, w));
else
@@ -644,3 +647,4 @@ struct ExposePass : public Pass {
}
} ExposePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index bfed0005..8a5301ec 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -28,7 +28,8 @@
#include <string.h>
#include <algorithm>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
bool inv_mode;
int verbose_level, reduce_counter, reduce_stop_at;
@@ -72,7 +73,7 @@ struct FindReducedInputs
SigMap &sigmap;
drivers_t &drivers;
- ezDefaultSAT ez;
+ ezSatPtr ez;
std::set<RTLIL::Cell*> ez_cells;
SatGen satgen;
@@ -80,7 +81,7 @@ struct FindReducedInputs
std::vector<int> sat_pi_uniq_bitvec;
FindReducedInputs(SigMap &sigmap, drivers_t &drivers) :
- sigmap(sigmap), drivers(drivers), satgen(&ez, &sigmap)
+ sigmap(sigmap), drivers(drivers), satgen(ez.get(), &sigmap)
{
satgen.model_undef = true;
}
@@ -103,30 +104,30 @@ struct FindReducedInputs
satgen.setContext(&sigmap, "A");
int sat_a = satgen.importSigSpec(bit).front();
- ez.assume(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(bit).front()));
satgen.setContext(&sigmap, "B");
int sat_b = satgen.importSigSpec(bit).front();
- ez.assume(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(bit).front()));
int idx = sat_pi.size();
size_t idx_bits = get_bits(idx);
if (sat_pi_uniq_bitvec.size() != idx_bits) {
- sat_pi_uniq_bitvec.push_back(ez.frozen_literal(stringf("uniq_%d", int(idx_bits)-1)));
+ sat_pi_uniq_bitvec.push_back(ez->frozen_literal(stringf("uniq_%d", int(idx_bits)-1)));
for (auto &it : sat_pi)
- ez.assume(ez.OR(ez.NOT(it.second), ez.NOT(sat_pi_uniq_bitvec.back())));
+ ez->assume(ez->OR(ez->NOT(it.second), ez->NOT(sat_pi_uniq_bitvec.back())));
}
log_assert(sat_pi_uniq_bitvec.size() == idx_bits);
- sat_pi[bit] = ez.frozen_literal(stringf("p, falsei_%s", log_signal(bit)));
- ez.assume(ez.IFF(ez.XOR(sat_a, sat_b), sat_pi[bit]));
+ sat_pi[bit] = ez->frozen_literal(stringf("p, falsei_%s", log_signal(bit)));
+ ez->assume(ez->IFF(ez->XOR(sat_a, sat_b), sat_pi[bit]));
for (size_t i = 0; i < idx_bits; i++)
if ((idx & (1 << i)) == 0)
- ez.assume(ez.OR(ez.NOT(sat_pi[bit]), ez.NOT(sat_pi_uniq_bitvec[i])));
+ ez->assume(ez->OR(ez->NOT(sat_pi[bit]), ez->NOT(sat_pi_uniq_bitvec[i])));
else
- ez.assume(ez.OR(ez.NOT(sat_pi[bit]), sat_pi_uniq_bitvec[i]));
+ ez->assume(ez->OR(ez->NOT(sat_pi[bit]), sat_pi_uniq_bitvec[i]));
}
void register_cone_worker(std::set<RTLIL::SigBit> &pi, std::set<RTLIL::SigBit> &sigdone, RTLIL::SigBit out)
@@ -200,7 +201,7 @@ struct FindReducedInputs
model_expr.push_back(sat_pi.at(pi[i]));
}
- if (!ez.solve(model_expr, model, ez.expression(ezSAT::OpOr, model_expr), ez.XOR(output_a, output_b), ez.NOT(output_undef_a), ez.NOT(output_undef_b)))
+ if (!ez->solve(model_expr, model, ez->expression(ezSAT::OpOr, model_expr), ez->XOR(output_a, output_b), ez->NOT(output_undef_a), ez->NOT(output_undef_b)))
break;
int found_count = 0;
@@ -229,7 +230,7 @@ struct PerformReduction
drivers_t &drivers;
std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs;
- ezDefaultSAT ez;
+ ezSatPtr ez;
SatGen satgen;
std::vector<int> sat_pi, sat_out, sat_def;
@@ -259,7 +260,7 @@ struct PerformReduction
} else {
pi_bits.push_back(out);
sat_pi.push_back(satgen.importSigSpec(out).front());
- ez.assume(ez.NOT(satgen.importUndefSigSpec(out).front()));
+ ez->assume(ez->NOT(satgen.importUndefSigSpec(out).front()));
sigdepth[out] = 0;
}
@@ -267,7 +268,7 @@ struct PerformReduction
}
PerformReduction(SigMap &sigmap, drivers_t &drivers, std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs, std::vector<RTLIL::SigBit> &bits, int cone_size) :
- sigmap(sigmap), drivers(drivers), inv_pairs(inv_pairs), satgen(&ez, &sigmap), out_bits(bits), cone_size(cone_size)
+ sigmap(sigmap), drivers(drivers), inv_pairs(inv_pairs), satgen(ez.get(), &sigmap), out_bits(bits), cone_size(cone_size)
{
satgen.model_undef = true;
@@ -277,15 +278,15 @@ struct PerformReduction
for (auto &bit : bits) {
out_depth.push_back(register_cone_worker(celldone, sigdepth, bit));
sat_out.push_back(satgen.importSigSpec(bit).front());
- sat_def.push_back(ez.NOT(satgen.importUndefSigSpec(bit).front()));
+ sat_def.push_back(ez->NOT(satgen.importUndefSigSpec(bit).front()));
}
if (inv_mode && cone_size > 0) {
- if (!ez.solve(sat_out, out_inverted, ez.expression(ezSAT::OpAnd, sat_def)))
+ if (!ez->solve(sat_out, out_inverted, ez->expression(ezSAT::OpAnd, sat_def)))
log_error("Solving for initial model failed!\n");
for (size_t i = 0; i < sat_out.size(); i++)
if (out_inverted.at(i))
- sat_out[i] = ez.NOT(sat_out[i]);
+ sat_out[i] = ez->NOT(sat_out[i]);
} else
out_inverted = std::vector<bool>(sat_out.size(), false);
}
@@ -295,8 +296,8 @@ struct PerformReduction
if (verbose_level == 1)
log(" Finding const value for %s.\n", log_signal(out_bits[idx]));
- bool can_be_set = ez.solve(ez.AND(sat_out[idx], sat_def[idx]));
- bool can_be_clr = ez.solve(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ bool can_be_set = ez->solve(ez->AND(sat_out[idx], sat_def[idx]));
+ bool can_be_clr = ez->solve(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
log_assert(!can_be_set || !can_be_clr);
RTLIL::SigBit value(RTLIL::State::Sx);
@@ -354,8 +355,8 @@ struct PerformReduction
std::vector<int> sat_set_list, sat_clr_list;
for (int idx : bucket) {
- sat_set_list.push_back(ez.AND(sat_out[idx], sat_def[idx]));
- sat_clr_list.push_back(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ sat_set_list.push_back(ez->AND(sat_out[idx], sat_def[idx]));
+ sat_clr_list.push_back(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
}
std::vector<int> modelVars = sat_out;
@@ -365,7 +366,7 @@ struct PerformReduction
if (verbose_level >= 2)
modelVars.insert(modelVars.end(), sat_pi.begin(), sat_pi.end());
- if (ez.solve(modelVars, model, ez.expression(ezSAT::OpOr, sat_set_list), ez.expression(ezSAT::OpOr, sat_clr_list)))
+ if (ez->solve(modelVars, model, ez->expression(ezSAT::OpOr, sat_set_list), ez->expression(ezSAT::OpOr, sat_clr_list)))
{
int iter_count = 1;
@@ -378,13 +379,13 @@ struct PerformReduction
for (int idx : bucket)
if (!model[sat_out.size() + idx]) {
- sat_set_list.push_back(ez.AND(sat_out[idx], sat_def[idx]));
- sat_clr_list.push_back(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx]));
+ sat_set_list.push_back(ez->AND(sat_out[idx], sat_def[idx]));
+ sat_clr_list.push_back(ez->AND(ez->NOT(sat_out[idx]), sat_def[idx]));
} else {
sat_def_list.push_back(sat_def[idx]);
}
- if (!ez.solve(modelVars, model, ez.expression(ezSAT::OpOr, sat_set_list), ez.expression(ezSAT::OpOr, sat_clr_list), ez.expression(ezSAT::OpAnd, sat_def_list)))
+ if (!ez->solve(modelVars, model, ez->expression(ezSAT::OpOr, sat_set_list), ez->expression(ezSAT::OpOr, sat_clr_list), ez->expression(ezSAT::OpAnd, sat_def_list)))
break;
iter_count++;
}
@@ -430,7 +431,7 @@ struct PerformReduction
for (int idx2 : bucket)
if (idx != idx2)
sat_def_list.push_back(sat_def[idx2]);
- if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list)))
+ if (ez->solve(ez->NOT(sat_def[idx]), ez->expression(ezSAT::OpOr, sat_def_list)))
undef_slaves.push_back(idx);
}
@@ -504,7 +505,7 @@ struct PerformReduction
for (int idx2 : r)
if (idx != idx2)
sat_def_list.push_back(sat_def[idx2]);
- if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list)))
+ if (ez->solve(ez->NOT(sat_def[idx]), ez->expression(ezSAT::OpOr, sat_def_list)))
undef_slaves.push_back(idx);
}
@@ -745,8 +746,6 @@ struct FreduceWorker
}
};
-} /* namespace */
-
struct FreducePass : public Pass {
FreducePass() : Pass("freduce", "perform functional reduction") { }
virtual void help()
@@ -827,3 +826,4 @@ struct FreducePass : public Pass {
}
} FreducePass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index b3adefb9..9853cd0c 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -21,7 +21,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL::Design *design)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_ignore_gold_x = false;
bool flag_make_outputs = false;
@@ -299,3 +302,4 @@ struct MiterPass : public Pass {
}
} MiterPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index fd0abf4a..9e5cc9e9 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -33,23 +33,25 @@
#include <errno.h>
#include <string.h>
-namespace {
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct SatHelper
{
RTLIL::Design *design;
RTLIL::Module *module;
- ezDefaultSAT ez;
SigMap sigmap;
CellTypes ct;
+
+ ezSatPtr ez;
SatGen satgen;
// additional constraints
std::vector<std::pair<std::string, std::string>> sets, prove, prove_x, sets_init;
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
std::map<int, std::vector<std::string>> unsets_at;
- bool prove_asserts;
+ bool prove_asserts, set_assumes;
// undef constraints
bool enable_undef, set_init_def, set_init_undef, set_init_zero, ignore_unknown_cells;
@@ -64,7 +66,7 @@ struct SatHelper
bool gotTimeout;
SatHelper(RTLIL::Design *design, RTLIL::Module *module, bool enable_undef) :
- design(design), module(module), sigmap(module), ct(design), satgen(&ez, &sigmap)
+ design(design), module(module), sigmap(module), ct(design), satgen(ez.get(), &sigmap)
{
this->enable_undef = enable_undef;
satgen.model_undef = enable_undef;
@@ -115,7 +117,7 @@ struct SatHelper
}
if (removed_bits.size())
- log("Warning: ignoring initial value on non-register: %s\n", log_signal(removed_bits));
+ log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
if (lhs.size()) {
log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
@@ -154,7 +156,7 @@ struct SatHelper
if (set_init_def) {
RTLIL::SigSpec rem = satgen.initial_state.export_all();
std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
- ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_rem)));
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
}
if (set_init_undef) {
@@ -178,7 +180,7 @@ struct SatHelper
log("Final constraint equation: %s = %s\n\n", log_signal(big_lhs), log_signal(big_rhs));
check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez.assume(satgen.signals_eq(big_lhs, big_rhs, 1));
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, 1));
}
void setup(int timestep = -1)
@@ -249,7 +251,7 @@ struct SatHelper
log("Final constraint equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs));
check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez.assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
// 0 = sets_def
// 1 = sets_any_undef
@@ -309,28 +311,36 @@ struct SatHelper
log("Import %s constraint for this timestep: %s\n", t == 0 ? "def" : t == 1 ? "any_undef" : "all_undef", log_signal(sig));
std::vector<int> undef_sig = satgen.importUndefSigSpec(sig, timestep);
if (t == 0)
- ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_sig)));
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_sig)));
if (t == 1)
- ez.assume(ez.expression(ezSAT::OpOr, undef_sig));
+ ez->assume(ez->expression(ezSAT::OpOr, undef_sig));
if (t == 2)
- ez.assume(ez.expression(ezSAT::OpAnd, undef_sig));
+ ez->assume(ez->expression(ezSAT::OpAnd, undef_sig));
}
int import_cell_counter = 0;
- for (auto &c : module->cells_)
- if (design->selected(module, c.second)) {
- // log("Import cell: %s\n", RTLIL::id2cstr(c.first));
- if (satgen.importCell(c.second, timestep)) {
- for (auto &p : c.second->connections())
- if (ct.cell_output(c.second->type, p.first))
- show_drivers.insert(sigmap(p.second), c.second);
+ for (auto cell : module->cells())
+ if (design->selected(module, cell)) {
+ // log("Import cell: %s\n", RTLIL::id2cstr(cell->name));
+ if (satgen.importCell(cell, timestep)) {
+ for (auto &p : cell->connections())
+ if (ct.cell_output(cell->type, p.first))
+ show_drivers.insert(sigmap(p.second), cell);
import_cell_counter++;
} else if (ignore_unknown_cells)
- log("Warning: Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
+ log_warning("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
else
- log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c.first), RTLIL::id2cstr(c.second->type));
+ log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
}
log("Imported %d cells to SAT database.\n", import_cell_counter);
+
+ if (set_assumes) {
+ RTLIL::SigSpec assumes_a, assumes_en;
+ satgen.getAssumes(assumes_a, assumes_en, timestep);
+ for (int i = 0; i < GetSize(assumes_a); i++)
+ log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
+ ez->assume(satgen.importAssumes(timestep));
+ }
}
int setup_proof(int timestep = -1)
@@ -400,33 +410,33 @@ struct SatHelper
std::vector<int> undef_rhs = satgen.importUndefSigSpec(big_rhs, timestep);
for (size_t i = 0; i < value_lhs.size(); i++)
- prove_bits.push_back(ez.OR(undef_lhs.at(i), ez.AND(ez.NOT(undef_rhs.at(i)), ez.NOT(ez.XOR(value_lhs.at(i), value_rhs.at(i))))));
+ prove_bits.push_back(ez->OR(undef_lhs.at(i), ez->AND(ez->NOT(undef_rhs.at(i)), ez->NOT(ez->XOR(value_lhs.at(i), value_rhs.at(i))))));
}
if (prove_asserts) {
RTLIL::SigSpec asserts_a, asserts_en;
satgen.getAsserts(asserts_a, asserts_en, timestep);
- for (int i = 0; i < SIZE(asserts_a); i++)
+ for (int i = 0; i < GetSize(asserts_a); i++)
log("Import proof for assert: %s when %s.\n", log_signal(asserts_a[i]), log_signal(asserts_en[i]));
prove_bits.push_back(satgen.importAsserts(timestep));
}
- return ez.expression(ezSAT::OpAnd, prove_bits);
+ return ez->expression(ezSAT::OpAnd, prove_bits);
}
void force_unique_state(int timestep_from, int timestep_to)
{
RTLIL::SigSpec state_signals = satgen.initial_state.export_all();
for (int i = timestep_from; i < timestep_to; i++)
- ez.assume(ez.NOT(satgen.signals_eq(state_signals, state_signals, i, timestep_to)));
+ ez->assume(ez->NOT(satgen.signals_eq(state_signals, state_signals, i, timestep_to)));
}
bool solve(const std::vector<int> &assumptions)
{
log_assert(gotTimeout == false);
- ez.setSolverTimeout(timeout);
- bool success = ez.solve(modelExpressions, modelValues, assumptions);
- if (ez.getSolverTimoutStatus())
+ ez->setSolverTimeout(timeout);
+ bool success = ez->solve(modelExpressions, modelValues, assumptions);
+ if (ez->getSolverTimoutStatus())
gotTimeout = true;
return success;
}
@@ -434,9 +444,9 @@ struct SatHelper
bool solve(int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0)
{
log_assert(gotTimeout == false);
- ez.setSolverTimeout(timeout);
- bool success = ez.solve(modelExpressions, modelValues, a, b, c, d, e, f);
- if (ez.getSolverTimoutStatus())
+ ez->setSolverTimeout(timeout);
+ bool success = ez->solve(modelExpressions, modelValues, a, b, c, d, e, f);
+ if (ez->getSolverTimoutStatus())
gotTimeout = true;
return success;
}
@@ -477,7 +487,7 @@ struct SatHelper
maybe_undef.push_back(modelExpressions.at(modelExpressions.size()/2 + i));
backupValues.swap(modelValues);
- if (!solve(ez.expression(ezSAT::OpAnd, must_undef), ez.expression(ezSAT::OpOr, maybe_undef)))
+ if (!solve(ez->expression(ezSAT::OpAnd, must_undef), ez->expression(ezSAT::OpOr, maybe_undef)))
break;
}
@@ -670,7 +680,7 @@ struct SatHelper
fprintf(f, " %s\n", stime);
fprintf(f, "$end\n");
fprintf(f, "$version\n");
- fprintf(f, " Generated by %s\n", yosys_version_str);
+ fprintf(f, " Generated by %s\n", yosys_version_str);
fprintf(f, "$end\n");
fprintf(f, "$comment\n");
fprintf(f, " Generated from SAT problem in module %s (declared at %s)\n",
@@ -749,6 +759,80 @@ struct SatHelper
fclose(f);
}
+ void dump_model_to_json(std::string json_file_name)
+ {
+ FILE *f = fopen(json_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno));
+
+ log("Dumping SAT model to WaveJSON file '%s'.\n", json_file_name.c_str());
+
+ int mintime = 1, maxtime = 0, maxwidth = 0;;
+ dict<string, pair<int, dict<int, Const>>> wavedata;
+
+ for (auto &info : modelInfo)
+ {
+ Const value;
+ for (int i = 0; i < info.width; i++) {
+ value.bits.push_back(modelValues.at(info.offset+i) ? RTLIL::State::S1 : RTLIL::State::S0);
+ if (enable_undef && modelValues.at(modelExpressions.size()/2 + info.offset + i))
+ value.bits.back() = RTLIL::State::Sx;
+ }
+
+ wavedata[info.description].first = info.width;
+ wavedata[info.description].second[info.timestep] = value;
+ mintime = std::min(mintime, info.timestep);
+ maxtime = std::max(maxtime, info.timestep);
+ maxwidth = std::max(maxwidth, info.width);
+ }
+
+ fprintf(f, "{ \"signal\": [");
+ bool fist_wavedata = true;
+ for (auto &wd : wavedata)
+ {
+ fprintf(f, "%s", fist_wavedata ? "\n" : ",\n");
+ fist_wavedata = false;
+
+ vector<string> data;
+ string name = wd.first.c_str();
+ while (name.substr(0, 1) == "\\")
+ name = name.substr(1);
+
+ fprintf(f, " { \"name\": \"%s\", \"wave\": \"", name.c_str());
+ for (int i = mintime; i <= maxtime; i++) {
+ if (wd.second.second.count(i)) {
+ string this_data = wd.second.second[i].as_string();
+ char ch = '=';
+ if (wd.second.first == 1)
+ ch = this_data[0];
+ if (!data.empty() && data.back() == this_data) {
+ fprintf(f, ".");
+ } else {
+ data.push_back(this_data);
+ fprintf(f, "%c", ch);
+ }
+ } else {
+ data.push_back("");
+ fprintf(f, "4");
+ }
+ }
+ if (wd.second.first != 1) {
+ fprintf(f, "\", \"data\": [");
+ for (int i = 0; i < GetSize(data); i++)
+ fprintf(f, "%s\"%s\"", i ? ", " : "", data[i].c_str());
+ fprintf(f, "] }");
+ } else {
+ fprintf(f, "\" }");
+ }
+ }
+ fprintf(f, "\n ],\n");
+ fprintf(f, " \"config\": {\n");
+ fprintf(f, " \"hscale\": %.2f\n", maxwidth / 4.0);
+ fprintf(f, " }\n");
+ fprintf(f, "}\n");
+ fclose(f);
+ }
+
void invalidate_model(bool max_undef)
{
std::vector<int> clause;
@@ -757,18 +841,16 @@ struct SatHelper
int bit = modelExpressions.at(i), bit_undef = modelExpressions.at(modelExpressions.size()/2 + i);
bool val = modelValues.at(i), val_undef = modelValues.at(modelExpressions.size()/2 + i);
if (!max_undef || !val_undef)
- clause.push_back(val_undef ? ez.NOT(bit_undef) : val ? ez.NOT(bit) : bit);
+ clause.push_back(val_undef ? ez->NOT(bit_undef) : val ? ez->NOT(bit) : bit);
}
} else
for (size_t i = 0; i < modelExpressions.size(); i++)
- clause.push_back(modelValues.at(i) ? ez.NOT(modelExpressions.at(i)) : modelExpressions.at(i));
- ez.assume(ez.expression(ezSAT::OpOr, clause));
+ clause.push_back(modelValues.at(i) ? ez->NOT(modelExpressions.at(i)) : modelExpressions.at(i));
+ ez->assume(ez->expression(ezSAT::OpOr, clause));
}
};
-} /* namespace */
-
-static void print_proof_failed()
+void print_proof_failed()
{
log("\n");
log(" ______ ___ ___ _ _ _ _ \n");
@@ -780,7 +862,7 @@ static void print_proof_failed()
log("\n");
}
-static void print_timeout()
+void print_timeout()
{
log("\n");
log(" _____ _ _ _____ ____ _ _____\n");
@@ -791,7 +873,7 @@ static void print_timeout()
log("\n");
}
-static void print_qed()
+void print_qed()
{
log("\n");
log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n");
@@ -851,8 +933,8 @@ struct SatPass : public Pass {
log(" show the model for the specified signal. if no -show option is\n");
log(" passed then a set of signals to be shown is automatically selected.\n");
log("\n");
- log(" -show-inputs, -show-outputs\n");
- log(" add all module input (output) ports to the list of shown signals\n");
+ log(" -show-inputs, -show-outputs, -show-ports\n");
+ log(" add all module (input/output) ports to the list of shown signals\n");
log("\n");
log(" -ignore_div_by_zero\n");
log(" ignore all solutions that involve a division by zero\n");
@@ -866,11 +948,17 @@ struct SatPass : public Pass {
log(" set up a sequential problem with <N> time steps. The steps will\n");
log(" be numbered from 1 to N.\n");
log("\n");
+ log(" note: for large <N> it can be significantly faster to use\n");
+ log(" -tempinduct-baseonly -maxsteps <N> instead of -seq <N>.\n");
+ log("\n");
log(" -set-at <N> <signal> <value>\n");
log(" -unset-at <N> <signal>\n");
log(" set or unset the specified signal to the specified value in the\n");
log(" given timestep. this has priority over a -set for the same signal.\n");
log("\n");
+ log(" -set-assumes\n");
+ log(" set all assumptions provided via $assume cells\n");
+ log("\n");
log(" -set-def-at <N> <signal>\n");
log(" -set-any-undef-at <N> <signal>\n");
log(" -set-all-undef-at <N> <signal>\n");
@@ -891,6 +979,9 @@ struct SatPass : public Pass {
log(" -dump_vcd <vcd-file-name>\n");
log(" dump SAT model (counter example in proof) to VCD file\n");
log("\n");
+ log(" -dump_json <json-file-name>\n");
+ log(" dump SAT model (counter example in proof) to a WaveJSON file.\n");
+ log("\n");
log(" -dump_cnf <cnf-file-name>\n");
log(" dump CNF of SAT problem (in DIMACS format). in temporal induction\n");
log(" proofs this is the CNF of the first induction step.\n");
@@ -907,6 +998,20 @@ struct SatPass : public Pass {
log(" Perform a temporal induction proof. Assume an initial state with all\n");
log(" registers set to defined values for the induction step.\n");
log("\n");
+ log(" -tempinduct-baseonly\n");
+ log(" Run only the basecase half of temporal induction (requires -maxsteps)\n");
+ log("\n");
+ log(" -tempinduct-inductonly\n");
+ log(" Run only the induction half of temporal induction\n");
+ log("\n");
+ log(" -tempinduct-skip <N>\n");
+ log(" Skip the first <N> steps of the induction proof.\n");
+ log("\n");
+ log(" note: this will assume that the base case holds for <N> steps.\n");
+ log(" this must be proven independently with \"-tempinduct-baseonly\n");
+ log(" -maxsteps <N>\". Use -initsteps if you just want to set a\n");
+ log(" minimal induction length.\n");
+ log("\n");
log(" -prove <signal> <value>\n");
log(" Attempt to proof that <signal> is always <value>.\n");
log("\n");
@@ -925,6 +1030,13 @@ struct SatPass : public Pass {
log("\n");
log(" -initsteps <N>\n");
log(" Set initial length for the induction.\n");
+ log(" This will speed up the search of the right induction length\n");
+ log(" for deep induction proofs.\n");
+ log("\n");
+ log(" -stepsize <N>\n");
+ log(" Increase the size of the induction proof in steps of <N>.\n");
+ log(" This will speed up the search of the right induction length\n");
+ log(" for deep induction proofs.\n");
log("\n");
log(" -timeout <N>\n");
log(" Maximum number of seconds a single SAT instance may take.\n");
@@ -953,7 +1065,9 @@ struct SatPass : public Pass {
bool ignore_div_by_zero = false, set_init_undef = false, set_init_zero = false, max_undef = false;
bool tempinduct = false, prove_asserts = false, show_inputs = false, show_outputs = false;
bool ignore_unknown_cells = false, falsify = false, tempinduct_def = false, set_init_def = false;
- std::string vcd_file_name, cnf_file_name;
+ bool tempinduct_baseonly = false, tempinduct_inductonly = false, set_assumes = false;
+ int tempinduct_skip = 0, stepsize = 1;
+ std::string vcd_file_name, json_file_name, cnf_file_name;
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
@@ -997,6 +1111,10 @@ struct SatPass : public Pass {
initsteps = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-stepsize" && argidx+1 < args.size()) {
+ stepsize = std::max(1, atoi(args[++argidx].c_str()));
+ continue;
+ }
if (args[argidx] == "-ignore_div_by_zero") {
ignore_div_by_zero = true;
continue;
@@ -1036,6 +1154,10 @@ struct SatPass : public Pass {
enable_undef = true;
continue;
}
+ if (args[argidx] == "-set-assumes") {
+ set_assumes = true;
+ continue;
+ }
if (args[argidx] == "-tempinduct") {
tempinduct = true;
continue;
@@ -1045,6 +1167,20 @@ struct SatPass : public Pass {
tempinduct_def = true;
continue;
}
+ if (args[argidx] == "-tempinduct-baseonly") {
+ tempinduct = true;
+ tempinduct_baseonly = true;
+ continue;
+ }
+ if (args[argidx] == "-tempinduct-inductonly") {
+ tempinduct = true;
+ tempinduct_inductonly = true;
+ continue;
+ }
+ if (args[argidx] == "-tempinduct-skip" && argidx+1 < args.size()) {
+ tempinduct_skip = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-prove" && argidx+2 < args.size()) {
std::string lhs = args[++argidx];
std::string rhs = args[++argidx];
@@ -1131,6 +1267,11 @@ struct SatPass : public Pass {
show_outputs = true;
continue;
}
+ if (args[argidx] == "-show-ports") {
+ show_inputs = true;
+ show_outputs = true;
+ continue;
+ }
if (args[argidx] == "-ignore_unknown_cells") {
ignore_unknown_cells = true;
continue;
@@ -1139,6 +1280,10 @@ struct SatPass : public Pass {
vcd_file_name = args[++argidx];
continue;
}
+ if (args[argidx] == "-dump_json" && argidx+1 < args.size()) {
+ json_file_name = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-dump_cnf" && argidx+1 < args.size()) {
cnf_file_name = args[++argidx];
continue;
@@ -1155,14 +1300,14 @@ struct SatPass : public Pass {
RTLIL::id2cstr(module->name), RTLIL::id2cstr(mod_it.first));
module = mod_it.second;
}
- if (module == NULL)
+ if (module == NULL)
log_cmd_error("Can't perform SAT on an empty selection!\n");
if (!prove.size() && !prove_x.size() && !prove_asserts && tempinduct)
log_cmd_error("Got -tempinduct but nothing to prove!\n");
if (prove_skip && tempinduct)
- log_cmd_error("Options -prove-skip and -tempinduct don't work with each other.\n");
+ log_cmd_error("Options -prove-skip and -tempinduct don't work with each other. Use -seq instead of -prove-skip.\n");
if (prove_skip >= seq_len && prove_skip > 0)
log_cmd_error("The value of -prove-skip must be smaller than the one of -seq.\n");
@@ -1195,8 +1340,10 @@ struct SatPass : public Pass {
SatHelper basecase(design, module, enable_undef);
SatHelper inductstep(design, module, enable_undef);
+ bool basecase_setup_init = true;
basecase.sets = sets;
+ basecase.set_assumes = set_assumes;
basecase.prove = prove;
basecase.prove_x = prove_x;
basecase.prove_asserts = prove_asserts;
@@ -1218,10 +1365,11 @@ struct SatPass : public Pass {
basecase.ignore_unknown_cells = ignore_unknown_cells;
for (int timestep = 1; timestep <= seq_len; timestep++)
- basecase.setup(timestep);
- basecase.setup_init();
+ if (!tempinduct_inductonly)
+ basecase.setup(timestep);
inductstep.sets = sets;
+ inductstep.set_assumes = set_assumes;
inductstep.prove = prove;
inductstep.prove_x = prove_x;
inductstep.prove_asserts = prove_asserts;
@@ -1233,12 +1381,14 @@ struct SatPass : public Pass {
inductstep.satgen.ignore_div_by_zero = ignore_div_by_zero;
inductstep.ignore_unknown_cells = ignore_unknown_cells;
- inductstep.setup(1);
- inductstep.ez.assume(inductstep.setup_proof(1));
+ if (!tempinduct_baseonly) {
+ inductstep.setup(1);
+ inductstep.ez->assume(inductstep.setup_proof(1));
+ }
if (tempinduct_def) {
std::vector<int> undef_state = inductstep.satgen.importUndefSigSpec(inductstep.satgen.initial_state.export_all(), 1);
- inductstep.ez.assume(inductstep.ez.NOT(inductstep.ez.expression(ezSAT::OpOr, undef_state)));
+ inductstep.ez->assume(inductstep.ez->NOT(inductstep.ez->expression(ezSAT::OpOr, undef_state)));
}
for (int inductlen = 1; inductlen <= maxsteps || maxsteps == 0; inductlen++)
@@ -1247,81 +1397,120 @@ struct SatPass : public Pass {
// phase 1: proving base case
- basecase.setup(seq_len + inductlen);
- int property = basecase.setup_proof(seq_len + inductlen);
- basecase.generate_model();
-
- if (inductlen > 1)
- basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
+ if (!tempinduct_inductonly)
+ {
+ basecase.setup(seq_len + inductlen);
+ int property = basecase.setup_proof(seq_len + inductlen);
+ basecase.generate_model();
- log("\n[base case] Solving problem with %d variables and %d clauses..\n",
- basecase.ez.numCnfVariables(), basecase.ez.numCnfClauses());
+ if (basecase_setup_init) {
+ basecase.setup_init();
+ basecase_setup_init = false;
+ }
- if (basecase.solve(basecase.ez.NOT(property))) {
- log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
- print_proof_failed();
- basecase.print_model();
- if(!vcd_file_name.empty())
- basecase.dump_model_to_vcd(vcd_file_name);
- goto tip_failed;
- }
+ if (inductlen > 1)
+ basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
- if (basecase.gotTimeout)
- goto timeout;
+ if (tempinduct_skip < inductlen)
+ {
+ log("\n[base case %d] Solving problem with %d variables and %d clauses..\n",
+ inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+
+ if (basecase.solve(basecase.ez->NOT(property))) {
+ log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
+ print_proof_failed();
+ basecase.print_model();
+ if(!vcd_file_name.empty())
+ basecase.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ basecase.dump_model_to_json(json_file_name);
+ goto tip_failed;
+ }
+
+ if (basecase.gotTimeout)
+ goto timeout;
- log("Base case for induction length %d proven.\n", inductlen);
- basecase.ez.assume(property);
+ log("Base case for induction length %d proven.\n", inductlen);
+ }
+ else
+ {
+ log("\n[base case %d] Skipping prove for this step (-tempinduct-skip %d).",
+ inductlen, tempinduct_skip);
+ log("\n[base case %d] Problem size so far: %d variables and %d clauses.\n",
+ inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+ }
+ basecase.ez->assume(property);
+ }
// phase 2: proving induction step
- inductstep.setup(inductlen + 1);
- property = inductstep.setup_proof(inductlen + 1);
- inductstep.generate_model();
-
- if (inductlen > 1)
- inductstep.force_unique_state(1, inductlen + 1);
-
- if (inductlen < initsteps)
- {
- log("\n[induction step] Skipping problem with %d variables and %d clauses (below initsteps).\n",
- inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
- inductstep.ez.assume(property);
- }
- else
+ if (!tempinduct_baseonly)
{
- if (!cnf_file_name.empty())
- {
- FILE *f = fopen(cnf_file_name.c_str(), "w");
- if (!f)
- log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
+ inductstep.setup(inductlen + 1);
+ int property = inductstep.setup_proof(inductlen + 1);
+ inductstep.generate_model();
- log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
- cnf_file_name.clear();
+ if (inductlen > 1)
+ inductstep.force_unique_state(1, inductlen + 1);
- inductstep.ez.printDIMACS(f, false);
- fclose(f);
+ if (inductlen <= tempinduct_skip || inductlen <= initsteps || inductlen % stepsize != 0)
+ {
+ if (inductlen < tempinduct_skip)
+ log("\n[induction step %d] Skipping prove for this step (-tempinduct-skip %d).",
+ inductlen, tempinduct_skip);
+ if (inductlen < initsteps)
+ log("\n[induction step %d] Skipping prove for this step (-initsteps %d).",
+ inductlen, tempinduct_skip);
+ if (inductlen % stepsize != 0)
+ log("\n[induction step %d] Skipping prove for this step (-stepsize %d).",
+ inductlen, stepsize);
+ log("\n[induction step %d] Problem size so far: %d variables and %d clauses.\n",
+ inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+ inductstep.ez->assume(property);
}
-
- log("\n[induction step] Solving problem with %d variables and %d clauses..\n",
- inductstep.ez.numCnfVariables(), inductstep.ez.numCnfClauses());
-
- if (!inductstep.solve(inductstep.ez.NOT(property))) {
- if (inductstep.gotTimeout)
- goto timeout;
- log("Induction step proven: SUCCESS!\n");
- print_qed();
- goto tip_success;
+ else
+ {
+ if (!cnf_file_name.empty())
+ {
+ FILE *f = fopen(cnf_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno));
+
+ log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
+ cnf_file_name.clear();
+
+ inductstep.ez->printDIMACS(f, false);
+ fclose(f);
+ }
+
+ log("\n[induction step %d] Solving problem with %d variables and %d clauses..\n",
+ inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+
+ if (!inductstep.solve(inductstep.ez->NOT(property))) {
+ if (inductstep.gotTimeout)
+ goto timeout;
+ log("Induction step proven: SUCCESS!\n");
+ print_qed();
+ goto tip_success;
+ }
+
+ log("Induction step failed. Incrementing induction length.\n");
+ inductstep.ez->assume(property);
+ inductstep.print_model();
}
-
- log("Induction step failed. Incrementing induction length.\n");
- inductstep.ez.assume(property);
- inductstep.print_model();
}
}
+ if (tempinduct_baseonly) {
+ log("\nReached maximum number of time steps -> proved base case for %d steps: SUCCESS!\n", maxsteps);
+ goto tip_success;
+ }
+
log("\nReached maximum number of time steps -> proof failed.\n");
if(!vcd_file_name.empty())
inductstep.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ inductstep.dump_model_to_json(json_file_name);
print_proof_failed();
tip_failed:
@@ -1345,6 +1534,7 @@ struct SatPass : public Pass {
SatHelper sathelper(design, module, enable_undef);
sathelper.sets = sets;
+ sathelper.set_assumes = set_assumes;
sathelper.prove = prove;
sathelper.prove_x = prove_x;
sathelper.prove_asserts = prove_asserts;
@@ -1368,7 +1558,7 @@ struct SatPass : public Pass {
if (seq_len == 0) {
sathelper.setup();
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- sathelper.ez.assume(sathelper.ez.NOT(sathelper.setup_proof()));
+ sathelper.ez->assume(sathelper.ez->NOT(sathelper.setup_proof()));
} else {
std::vector<int> prove_bits;
for (int timestep = 1; timestep <= seq_len; timestep++) {
@@ -1378,7 +1568,7 @@ struct SatPass : public Pass {
prove_bits.push_back(sathelper.setup_proof(timestep));
}
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- sathelper.ez.assume(sathelper.ez.NOT(sathelper.ez.expression(ezSAT::OpAnd, prove_bits)));
+ sathelper.ez->assume(sathelper.ez->NOT(sathelper.ez->expression(ezSAT::OpAnd, prove_bits)));
sathelper.setup_init();
}
sathelper.generate_model();
@@ -1392,7 +1582,7 @@ struct SatPass : public Pass {
log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
cnf_file_name.clear();
- sathelper.ez.printDIMACS(f, false);
+ sathelper.ez->printDIMACS(f, false);
fclose(f);
}
@@ -1400,7 +1590,7 @@ struct SatPass : public Pass {
rerun_solver:
log("\nSolving problem with %d variables and %d clauses..\n",
- sathelper.ez.numCnfVariables(), sathelper.ez.numCnfClauses());
+ sathelper.ez->numCnfVariables(), sathelper.ez->numCnfClauses());
if (sathelper.solve())
{
@@ -1420,6 +1610,8 @@ struct SatPass : public Pass {
if(!vcd_file_name.empty())
sathelper.dump_model_to_vcd(vcd_file_name);
+ if(!json_file_name.empty())
+ sathelper.dump_model_to_json(json_file_name);
if (loopcount != 0) {
loopcount--, rerun_counter++;
@@ -1483,4 +1675,5 @@ struct SatPass : public Pass {
}
}
} SatPass;
-
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 72998f87..6b6846e2 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -2,14 +2,15 @@
OBJS += passes/techmap/techmap.o
OBJS += passes/techmap/simplemap.o
OBJS += passes/techmap/dfflibmap.o
+OBJS += passes/techmap/maccmap.o
OBJS += passes/techmap/libparse.o
ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
OBJS += passes/techmap/extract.o
-OBJS += passes/techmap/maccmap.o
OBJS += passes/techmap/alumacc.o
+OBJS += passes/techmap/dff2dffe.o
endif
GENFILES += passes/techmap/techmap.inc
@@ -23,9 +24,11 @@ passes/techmap/techmap.inc: techlibs/common/techmap.v
passes/techmap/techmap.o: passes/techmap/techmap.inc
-TARGETS += yosys-filterlib
-GENFILES += passes/techmap/filterlib.o
+ifneq ($(CONFIG),emcc)
+TARGETS += yosys-filterlib$(EXE)
+EXTRA_OBJS += passes/techmap/filterlib.o
-yosys-filterlib: passes/techmap/filterlib.o
- $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
+yosys-filterlib$(EXE): passes/techmap/filterlib.o
+ $(P) $(CXX) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
+endif
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 1115eead..dcffed94 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -21,6 +21,9 @@
#include "kernel/sigtools.h"
#include "kernel/macc.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
struct AlumaccWorker
{
RTLIL::Module *module;
@@ -45,51 +48,51 @@ struct AlumaccWorker
RTLIL::SigSpec cached_cf, cached_of, cached_sf;
RTLIL::SigSpec get_lt() {
- if (SIZE(cached_lt) == 0)
+ if (GetSize(cached_lt) == 0)
cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf();
return cached_lt;
}
RTLIL::SigSpec get_gt() {
- if (SIZE(cached_gt) == 0)
+ if (GetSize(cached_gt) == 0)
cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()));
return cached_gt;
}
RTLIL::SigSpec get_eq() {
- if (SIZE(cached_eq) == 0)
+ if (GetSize(cached_eq) == 0)
cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
return cached_eq;
}
RTLIL::SigSpec get_ne() {
- if (SIZE(cached_ne) == 0)
+ if (GetSize(cached_ne) == 0)
cached_ne = alu_cell->module->Not(NEW_ID, get_eq());
return cached_ne;
}
RTLIL::SigSpec get_cf() {
- if (SIZE(cached_cf) == 0) {
+ if (GetSize(cached_cf) == 0) {
cached_cf = alu_cell->getPort("\\CO");
- log_assert(SIZE(cached_cf) >= 1);
- cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[SIZE(cached_cf)-1]);
+ log_assert(GetSize(cached_cf) >= 1);
+ cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1]);
}
return cached_cf;
}
RTLIL::SigSpec get_of() {
- if (SIZE(cached_of) == 0) {
+ if (GetSize(cached_of) == 0) {
cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")};
- log_assert(SIZE(cached_of) >= 2);
- cached_of = alu_cell->module->Xor(NEW_ID, cached_of[SIZE(cached_of)-1], cached_of[SIZE(cached_of)-2]);
+ log_assert(GetSize(cached_of) >= 2);
+ cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]);
}
return cached_of;
}
RTLIL::SigSpec get_sf() {
- if (SIZE(cached_sf) == 0) {
+ if (GetSize(cached_sf) == 0) {
cached_sf = alu_cell->getPort("\\Y");
- cached_sf = cached_sf[SIZE(cached_sf)-1];
+ cached_sf = cached_sf[GetSize(cached_sf)-1];
}
return cached_sf;
}
@@ -181,10 +184,10 @@ struct AlumaccWorker
return true;
if (!port.is_signed && port.do_subtract)
return true;
- if (SIZE(port.in_b))
- port_sizes.push_back(SIZE(port.in_a) + SIZE(port.in_b));
+ if (GetSize(port.in_b))
+ port_sizes.push_back(GetSize(port.in_a) + GetSize(port.in_b));
else
- port_sizes.push_back(SIZE(port.in_a));
+ port_sizes.push_back(GetSize(port.in_a));
}
std::sort(port_sizes.begin(), port_sizes.end());
@@ -221,11 +224,11 @@ struct AlumaccWorker
if (delete_nodes.count(n))
continue;
- for (int i = 0; i < SIZE(n->macc.ports); i++)
+ for (int i = 0; i < GetSize(n->macc.ports); i++)
{
auto &port = n->macc.ports[i];
- if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
+ if (GetSize(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
continue;
auto other_n = sig_macc.at(port.in_a);
@@ -233,13 +236,13 @@ struct AlumaccWorker
if (other_n->users > 1)
continue;
- if (SIZE(other_n->y) != SIZE(n->y) && macc_may_overflow(other_n->macc, SIZE(other_n->y), port.is_signed))
+ if (GetSize(other_n->y) != GetSize(n->y) && macc_may_overflow(other_n->macc, GetSize(other_n->y), port.is_signed))
continue;
log(" merging $macc model for %s into %s.\n", log_id(other_n->cell), log_id(n->cell));
bool do_subtract = port.do_subtract;
- for (int j = 0; j < SIZE(other_n->macc.ports); j++) {
+ for (int j = 0; j < GetSize(other_n->macc.ports); j++) {
if (do_subtract)
other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract;
if (j == 0)
@@ -275,38 +278,38 @@ struct AlumaccWorker
alunode_t *alunode;
for (auto &port : n->macc.ports)
- if (SIZE(port.in_b) > 0) {
+ if (GetSize(port.in_b) > 0) {
goto next_macc;
- } else if (SIZE(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {
+ } else if (GetSize(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {
C.append(port.in_a);
- } else if (SIZE(A) || port.do_subtract) {
- if (SIZE(B))
+ } else if (GetSize(A) || port.do_subtract) {
+ if (GetSize(B))
goto next_macc;
B = port.in_a;
b_signed = port.is_signed;
subtract_b = port.do_subtract;
} else {
- if (SIZE(A))
+ if (GetSize(A))
goto next_macc;
A = port.in_a;
a_signed = port.is_signed;
}
if (!a_signed || !b_signed) {
- if (SIZE(A) == SIZE(n->y))
+ if (GetSize(A) == GetSize(n->y))
a_signed = false;
- if (SIZE(B) == SIZE(n->y))
+ if (GetSize(B) == GetSize(n->y))
b_signed = false;
if (a_signed != b_signed)
goto next_macc;
}
- if (SIZE(A) == 0 && SIZE(C) > 0) {
+ if (GetSize(A) == 0 && GetSize(C) > 0) {
A = C[0];
C.remove(0);
}
- if (SIZE(B) == 0 && SIZE(C) > 0) {
+ if (GetSize(B) == 0 && GetSize(C) > 0) {
B = C[0];
C.remove(0);
}
@@ -314,10 +317,10 @@ struct AlumaccWorker
if (subtract_b)
C.append(RTLIL::S1);
- if (SIZE(C) > 1)
+ if (GetSize(C) > 1)
goto next_macc;
- if (!subtract_b && B < A && SIZE(B))
+ if (!subtract_b && B < A && GetSize(B))
std::swap(A, B);
log(" creating $alu model for $macc %s.\n", log_id(n->cell));
@@ -353,7 +356,7 @@ struct AlumaccWorker
log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
- n->macc.optimize(SIZE(n->y));
+ n->macc.optimize(GetSize(n->y));
n->macc.to_cell(cell);
cell->setPort("\\Y", n->y);
cell->fixup_parameters();
@@ -388,7 +391,7 @@ struct AlumaccWorker
RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
- if (B < A && SIZE(B)) {
+ if (B < A && GetSize(B)) {
cmp_less = !cmp_less;
std::swap(A, B);
}
@@ -406,7 +409,7 @@ struct AlumaccWorker
n->a = A;
n->b = B;
n->c = RTLIL::S1;
- n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B)));
+ n->y = module->addWire(NEW_ID, std::max(GetSize(A), GetSize(B)));
n->is_signed = is_signed;
n->invert_b = true;
sig_alu[RTLIL::SigSig(A, B)].insert(n);
@@ -428,7 +431,7 @@ struct AlumaccWorker
RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
- if (B < A && SIZE(B))
+ if (B < A && GetSize(B))
std::swap(A, B);
alunode_t *n = nullptr;
@@ -452,12 +455,12 @@ struct AlumaccWorker
for (auto &it1 : sig_alu)
for (auto n : it1.second)
{
- if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(n->cmp) == 0)
+ if (GetSize(n->b) == 0 && GetSize(n->c) == 0 && GetSize(n->cmp) == 0)
{
n->alu_cell = module->addPos(NEW_ID, n->a, n->y, n->is_signed);
log(" creating $pos cell for ");
- for (int i = 0; i < SIZE(n->cells); i++)
+ for (int i = 0; i < GetSize(n->cells); i++)
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
@@ -468,17 +471,17 @@ struct AlumaccWorker
alu_counter++;
log(" creating $alu cell for ");
- for (int i = 0; i < SIZE(n->cells); i++)
+ for (int i = 0; i < GetSize(n->cells); i++)
log("%s%s", i ? ", ": "", log_id(n->cells[i]));
log(": %s\n", log_id(n->alu_cell));
n->alu_cell->setPort("\\A", n->a);
n->alu_cell->setPort("\\B", n->b);
- n->alu_cell->setPort("\\CI", SIZE(n->c) ? n->c : RTLIL::S0);
+ n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0);
n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0);
n->alu_cell->setPort("\\Y", n->y);
- n->alu_cell->setPort("\\X", module->addWire(NEW_ID, SIZE(n->y)));
- n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, SIZE(n->y)));
+ n->alu_cell->setPort("\\X", module->addWire(NEW_ID, GetSize(n->y)));
+ n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, GetSize(n->y)));
n->alu_cell->fixup_parameters(n->is_signed, n->is_signed);
for (auto &it : n->cmp)
@@ -495,10 +498,10 @@ struct AlumaccWorker
if (cmp_eq) sig.append(n->get_eq());
if (cmp_ne) sig.append(n->get_ne());
- if (SIZE(sig) > 1)
+ if (GetSize(sig) > 1)
sig = module->ReduceOr(NEW_ID, sig);
- sig.extend(SIZE(cmp_y));
+ sig.extend_u0(GetSize(cmp_y));
module->connect(cmp_y, sig);
}
@@ -535,8 +538,8 @@ struct AlumaccPass : public Pass {
log("\n");
log(" alumacc [selection]\n");
log("\n");
- log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n");
- log("$macc cells.\n");
+ log("This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu\n");
+ log("and $macc cells.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -561,3 +564,4 @@ struct AlumaccPass : public Pass {
}
} AlumaccPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
new file mode 100644
index 00000000..17549bd0
--- /dev/null
+++ b/passes/techmap/dff2dffe.cc
@@ -0,0 +1,337 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "passes/techmap/simplemap.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Dff2dffeWorker
+{
+ RTLIL::Module *module;
+ SigMap sigmap;
+ CellTypes ct;
+
+ RTLIL::IdString direct_to;
+
+ typedef std::pair<RTLIL::Cell*, int> cell_int_t;
+ std::map<RTLIL::SigBit, cell_int_t> bit2mux;
+ std::vector<RTLIL::Cell*> dff_cells;
+ std::map<RTLIL::SigBit, int> bitusers;
+
+ typedef std::map<RTLIL::SigBit, bool> pattern_t;
+ typedef std::set<pattern_t> patterns_t;
+
+
+ Dff2dffeWorker(RTLIL::Module *module, RTLIL::IdString direct_from, RTLIL::IdString direct_to) :
+ module(module), sigmap(module), ct(module->design), direct_to(direct_to)
+ {
+ for (auto wire : module->wires()) {
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ bitusers[bit]++;
+ }
+
+ for (auto cell : module->cells()) {
+ if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") {
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < GetSize(sig_y); i++)
+ bit2mux[sig_y[i]] = cell_int_t(cell, i);
+ }
+ if (direct_to.empty()) {
+ if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+ dff_cells.push_back(cell);
+ } else {
+ if (cell->type == direct_from)
+ dff_cells.push_back(cell);
+ }
+ for (auto conn : cell->connections()) {
+ if (ct.cell_output(cell->type, conn.first))
+ continue;
+ for (auto bit : sigmap(conn.second))
+ bitusers[bit]++;
+ }
+ }
+ }
+
+ patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
+ {
+ patterns_t ret;
+
+ if (d == q) {
+ ret.insert(path);
+ return ret;
+ }
+
+ if (bit2mux.count(d) == 0 || bitusers[d] > 1)
+ return ret;
+
+ cell_int_t mux_cell_int = bit2mux.at(d);
+ RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort("\\B"));
+ RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort("\\S"));
+ int width = GetSize(sig_a), index = mux_cell_int.second;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ if (path.count(sig_s[i]) && path.at(sig_s[i]))
+ {
+ ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ s[i*width + index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\B", s);
+ }
+
+ return ret;
+ }
+
+ pattern_t path_else = path;
+
+ for (int i = 0; i < GetSize(sig_s); i++)
+ {
+ if (path.count(sig_s[i]))
+ continue;
+
+ pattern_t path_this = path;
+ path_else[sig_s[i]] = false;
+ path_this[sig_s[i]] = true;
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
+ ret.insert(pat);
+
+ if (sig_b[i*width + index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B");
+ s[i*width + index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\B", s);
+ }
+ }
+
+ for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
+ ret.insert(pat);
+
+ if (sig_a[index] == q) {
+ RTLIL::SigSpec s = mux_cell_int.first->getPort("\\A");
+ s[index] = RTLIL::Sx;
+ mux_cell_int.first->setPort("\\A", s);
+ }
+
+ return ret;
+ }
+
+ void simplify_patterns(patterns_t&)
+ {
+ // TBD
+ }
+
+ RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates)
+ {
+ RTLIL::SigSpec or_input;
+
+ for (auto pat : patterns)
+ {
+ RTLIL::SigSpec s1, s2;
+ for (auto it : pat) {
+ s1.append(it.first);
+ s2.append(it.second);
+ }
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ or_input.append(y);
+ }
+
+ if (GetSize(or_input) == 0)
+ return RTLIL::S1;
+
+ if (GetSize(or_input) == 1)
+ return or_input;
+
+ RTLIL::SigSpec y = module->addWire(NEW_ID);
+ RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
+
+ if (make_gates) {
+ simplemap(module, c);
+ module->remove(c);
+ }
+
+ return y;
+ }
+
+ void handle_dff_cell(RTLIL::Cell *dff_cell)
+ {
+ RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort("\\D"));
+ RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort("\\Q"));
+
+ std::map<patterns_t, std::set<int>> grouped_patterns;
+ std::set<int> remaining_indices;
+
+ for (int i = 0 ; i < GetSize(sig_d); i++) {
+ patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t());
+ if (!patterns.empty()) {
+ simplify_patterns(patterns);
+ grouped_patterns[patterns].insert(i);
+ } else
+ remaining_indices.insert(i);
+ }
+
+ for (auto &it : grouped_patterns) {
+ RTLIL::SigSpec new_sig_d, new_sig_q;
+ for (int i : it.second) {
+ new_sig_d.append(sig_d[i]);
+ new_sig_q.append(sig_q[i]);
+ }
+ if (!direct_to.empty()) {
+ log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_to), log_signal(new_sig_d), log_signal(new_sig_q));
+ dff_cell->setPort("\\E", make_patterns_logic(it.first, true));
+ dff_cell->type = direct_to;
+ } else
+ if (dff_cell->type == "$dff") {
+ RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false),
+ new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true);
+ log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
+ } else {
+ RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true),
+ new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true);
+ log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
+ }
+ }
+
+ if (!direct_to.empty())
+ return;
+
+ if (remaining_indices.empty()) {
+ log(" removing now obsolete cell %s.\n", log_id(dff_cell));
+ module->remove(dff_cell);
+ } else if (GetSize(remaining_indices) != GetSize(sig_d)) {
+ log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell));
+ RTLIL::SigSpec new_sig_d, new_sig_q;
+ for (int i : remaining_indices) {
+ new_sig_d.append(sig_d[i]);
+ new_sig_q.append(sig_q[i]);
+ }
+ dff_cell->setPort("\\D", new_sig_d);
+ dff_cell->setPort("\\Q", new_sig_q);
+ dff_cell->setParam("\\WIDTH", GetSize(remaining_indices));
+ }
+ }
+
+ void run()
+ {
+ log("Transforming $dff to $dffe cells in module %s:\n", log_id(module));
+ for (auto dff_cell : dff_cells)
+ handle_dff_cell(dff_cell);
+ }
+};
+
+struct Dff2dffePass : public Pass {
+ Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" dff2dffe [selection]\n");
+ log("\n");
+ log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
+ log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n");
+ log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n");
+ log("\n");
+ log(" -unmap\n");
+ log(" operate in the opposite direction: replace $dffe cells with combinations\n");
+ log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n");
+ log("\n");
+ log(" -direct <internal_gate_type> <external_gate_type>\n");
+ log(" map directly to external gate type. <internal_gate_type> can\n");
+ log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n");
+ log(" <external_gate_type> is the cell type name for a cell with an\n");
+ log(" identical interface to the <internal_gate_type>, except it\n");
+ log(" also has an high-active enable port 'E'.\n");
+ log(" Usually <external_gate_type> is an intemediate cell type\n");
+ log(" that is then translated to the final type using 'techmap'.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
+
+ bool unmap_mode = false;
+ RTLIL::IdString direct_from, direct_to;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-unmap") {
+ unmap_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
+ direct_from = RTLIL::escape_id(args[++argidx]);
+ direct_to = RTLIL::escape_id(args[++argidx]);
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ if (!mod->has_processes_warn())
+ {
+ if (unmap_mode) {
+ for (auto cell : mod->selected_cells()) {
+ if (cell->type == "$dffe") {
+ RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D")));
+ mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool());
+ if (cell->getParam("\\EN_POLARITY").as_bool())
+ mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\EN"), tmp);
+ else
+ mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\EN"), tmp);
+ mod->remove(cell);
+ continue;
+ }
+ if (cell->type.substr(0, 7) == "$_DFFE_") {
+ bool clk_pol = cell->type.substr(7, 1) == "P";
+ bool en_pol = cell->type.substr(8, 1) == "P";
+ RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
+ mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol);
+ if (en_pol)
+ mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\E"), tmp);
+ else
+ mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\E"), tmp);
+ mod->remove(cell);
+ continue;
+ }
+ }
+ continue;
+ }
+
+ Dff2dffeWorker worker(mod, direct_from, direct_to);
+ worker.run();
+ }
+ }
+} Dff2dffePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 07993b86..b0318a0b 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -23,7 +23,8 @@
#include <string.h>
#include <errno.h>
-using namespace PASS_DFFLIBMAP;
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct cell_mapping {
std::string cell_name;
@@ -102,12 +103,12 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name,
return false;
}
-static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval)
+static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
- float best_cell_area = 0;
+ double best_cell_area = 0;
if (ast->id != "library")
log_error("Format error in liberty file.\n");
@@ -143,7 +144,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
this_cell_ports[cell_rst_pin] = 'R';
this_cell_ports[cell_next_pin] = 'D';
- float area = 0;
+ double area = 0;
LibertyAst *ar = cell->find("area");
if (ar != NULL && !ar->value.empty())
area = atof(ar->value.c_str());
@@ -192,18 +193,27 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str());
- cell_mappings[cell_type].cell_name = best_cell->args[0];
- cell_mappings[cell_type].ports = best_cell_ports;
+ log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ if (prepare_mode) {
+ cell_mappings[cell_type].cell_name = cell_type;
+ cell_mappings[cell_type].ports["C"] = 'C';
+ if (has_reset)
+ cell_mappings[cell_type].ports["R"] = 'R';
+ cell_mappings[cell_type].ports["D"] = 'D';
+ cell_mappings[cell_type].ports["Q"] = 'Q';
+ } else {
+ cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].ports = best_cell_ports;
+ }
}
}
-static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol)
+static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
{
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
- float best_cell_area = 0;
+ double best_cell_area = 0;
if (ast->id != "library")
log_error("Format error in liberty file.\n");
@@ -235,7 +245,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
this_cell_ports[cell_clr_pin] = 'R';
this_cell_ports[cell_next_pin] = 'D';
- float area = 0;
+ double area = 0;
LibertyAst *ar = cell->find("area");
if (ar != NULL && !ar->value.empty())
area = atof(ar->value.c_str());
@@ -284,9 +294,18 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str());
- cell_mappings[cell_type].cell_name = best_cell->args[0];
- cell_mappings[cell_type].ports = best_cell_ports;
+ log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ if (prepare_mode) {
+ cell_mappings[cell_type].cell_name = cell_type;
+ cell_mappings[cell_type].ports["C"] = 'C';
+ cell_mappings[cell_type].ports["S"] = 'S';
+ cell_mappings[cell_type].ports["R"] = 'R';
+ cell_mappings[cell_type].ports["D"] = 'D';
+ cell_mappings[cell_type].ports["Q"] = 'Q';
+ } else {
+ cell_mappings[cell_type].cell_name = best_cell->args[0];
+ cell_mappings[cell_type].ports = best_cell_ports;
+ }
}
}
@@ -346,8 +365,12 @@ static void map_sr_to_arst(const char *from, const char *to)
if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
return;
- char from_clk_pol = from[8], from_set_pol = from[9], from_clr_pol = from[10];
- char to_clk_pol = to[6], to_rst_pol = to[7], to_rst_val = to[8];
+ char from_clk_pol YS_ATTRIBUTE(unused) = from[8];
+ char from_set_pol = from[9];
+ char from_clr_pol = from[10];
+ char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
+ char to_rst_pol YS_ATTRIBUTE(unused) = to[7];
+ char to_rst_val = to[8];
log_assert(from_clk_pol == to_clk_pol);
log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol);
@@ -383,7 +406,7 @@ static void map_sr_to_arst(const char *from, const char *to)
}
}
-static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
+static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode)
{
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
@@ -402,7 +425,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
module->remove(cell);
cell_mapping &cm = cell_mappings[cell_type];
- RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name);
+ RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name);
for (auto &port : cm.ports) {
RTLIL::SigSpec sig;
@@ -411,7 +434,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
} else
if (port.second == 'q') {
RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
- sig = module->addWire(NEW_ID, SIZE(old_sig));
+ sig = module->addWire(NEW_ID, GetSize(old_sig));
module->addNotGate(NEW_ID, sig, old_sig);
} else
if ('a' <= port.second && port.second <= 'z') {
@@ -438,7 +461,7 @@ struct DfflibmapPass : public Pass {
virtual void help()
{
log("\n");
- log(" dfflibmap -liberty <file> [selection]\n");
+ log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
log("\n");
log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
log("library specified in the given liberty file.\n");
@@ -446,12 +469,17 @@ struct DfflibmapPass : public Pass {
log("This pass may add inverters as needed. Therefore it is recommended to\n");
log("first run this pass and then map the logic paths to the target technology.\n");
log("\n");
+ log("When called with -prepare, this command will convert the internal FF cells\n");
+ log("to the internal cell types that best match the cells found in the given\n");
+ log("liberty file.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
std::string liberty_file;
+ bool prepare_mode = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -461,6 +489,10 @@ struct DfflibmapPass : public Pass {
liberty_file = args[++argidx];
continue;
}
+ if (arg == "-prepare") {
+ prepare_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -475,26 +507,26 @@ struct DfflibmapPass : public Pass {
LibertyParser libparser(f);
f.close();
- find_cell(libparser.ast, "$_DFF_N_", false, false, false, false);
- find_cell(libparser.ast, "$_DFF_P_", true, false, false, false);
-
- find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false);
- find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true);
- find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false);
- find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true);
- find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false);
- find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true);
- find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false);
- find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true);
-
- find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false);
- find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true);
- find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false);
- find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true);
- find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false);
- find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true);
- find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false);
- find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true);
+ find_cell(libparser.ast, "$_DFF_N_", false, false, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_P_", true, false, false, false, prepare_mode);
+
+ find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false, prepare_mode);
+ find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true, prepare_mode);
+
+ find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false, prepare_mode);
+ find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true, prepare_mode);
// try to implement as many cells as possible just by inverting
// the SET and RESET pins. If necessary, implement cell types
@@ -532,9 +564,10 @@ struct DfflibmapPass : public Pass {
for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
- dfflibmap(design, it.second);
+ dfflibmap(design, it.second, prepare_mode);
cell_mappings.clear();
}
} DfflibmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index 221e9e49..ff99040e 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -26,256 +26,240 @@
#include <stdio.h>
#include <string.h>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
using RTLIL::id2cstr;
-namespace
+class SubCircuitSolver : public SubCircuit::Solver
{
- class SubCircuitSolver : public SubCircuit::Solver
- {
- public:
- bool ignore_parameters;
- std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
- std::set<RTLIL::IdString> cell_attr, wire_attr;
+public:
+ bool ignore_parameters;
+ std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters;
+ std::set<RTLIL::IdString> cell_attr, wire_attr;
- SubCircuitSolver() : ignore_parameters(false)
- {
- }
+ SubCircuitSolver() : ignore_parameters(false)
+ {
+ }
- bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr)
- {
- for (auto &it : attr) {
- size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
- if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
- return false;
- }
- return true;
+ bool compareAttributes(const std::set<RTLIL::IdString> &attr, const dict<RTLIL::IdString, RTLIL::Const> &needleAttr, const dict<RTLIL::IdString, RTLIL::Const> &haystackAttr)
+ {
+ for (auto &it : attr) {
+ size_t nc = needleAttr.count(it), hc = haystackAttr.count(it);
+ if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it)))
+ return false;
}
+ return true;
+ }
- RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
- {
- if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
- return value;
-
- #define param_bool(_n) if (param == _n) return value.as_bool();
- param_bool("\\ARST_POLARITY");
- param_bool("\\A_SIGNED");
- param_bool("\\B_SIGNED");
- param_bool("\\CLK_ENABLE");
- param_bool("\\CLK_POLARITY");
- param_bool("\\CLR_POLARITY");
- param_bool("\\EN_POLARITY");
- param_bool("\\SET_POLARITY");
- param_bool("\\TRANSPARENT");
- #undef param_bool
-
- #define param_int(_n) if (param == _n) return value.as_int();
- param_int("\\ABITS")
- param_int("\\A_WIDTH")
- param_int("\\B_WIDTH")
- param_int("\\CTRL_IN_WIDTH")
- param_int("\\CTRL_OUT_WIDTH")
- param_int("\\OFFSET")
- param_int("\\PRIORITY")
- param_int("\\RD_PORTS")
- param_int("\\SIZE")
- param_int("\\STATE_BITS")
- param_int("\\STATE_NUM")
- param_int("\\STATE_NUM_LOG2")
- param_int("\\STATE_RST")
- param_int("\\S_WIDTH")
- param_int("\\TRANS_NUM")
- param_int("\\WIDTH")
- param_int("\\WR_PORTS")
- param_int("\\Y_WIDTH")
- #undef param_int
-
+ RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value)
+ {
+ if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_")
return value;
- }
- virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
- const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
- {
- RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
- RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
+ #define param_bool(_n) if (param == _n) return value.as_bool();
+ param_bool("\\ARST_POLARITY");
+ param_bool("\\A_SIGNED");
+ param_bool("\\B_SIGNED");
+ param_bool("\\CLK_ENABLE");
+ param_bool("\\CLK_POLARITY");
+ param_bool("\\CLR_POLARITY");
+ param_bool("\\EN_POLARITY");
+ param_bool("\\SET_POLARITY");
+ param_bool("\\TRANSPARENT");
+ #undef param_bool
+
+ #define param_int(_n) if (param == _n) return value.as_int();
+ param_int("\\ABITS")
+ param_int("\\A_WIDTH")
+ param_int("\\B_WIDTH")
+ param_int("\\CTRL_IN_WIDTH")
+ param_int("\\CTRL_OUT_WIDTH")
+ param_int("\\OFFSET")
+ param_int("\\PRIORITY")
+ param_int("\\RD_PORTS")
+ param_int("\\SIZE")
+ param_int("\\STATE_BITS")
+ param_int("\\STATE_NUM")
+ param_int("\\STATE_NUM_LOG2")
+ param_int("\\STATE_RST")
+ param_int("\\S_WIDTH")
+ param_int("\\TRANS_NUM")
+ param_int("\\WIDTH")
+ param_int("\\WR_PORTS")
+ param_int("\\Y_WIDTH")
+ #undef param_int
+
+ return value;
+ }
- if (!needleCell || !haystackCell) {
- log_assert(!needleCell && !haystackCell);
- return true;
- }
+ virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData,
+ const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping)
+ {
+ RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData;
+ RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData;
- if (!ignore_parameters) {
- std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
- for (auto &it : needleCell->parameters)
- if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
- needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
- for (auto &it : haystackCell->parameters)
- if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
- haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
- if (needle_param != haystack_param)
- return false;
- }
+ if (!needleCell || !haystackCell) {
+ log_assert(!needleCell && !haystackCell);
+ return true;
+ }
- if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
+ if (!ignore_parameters) {
+ std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param;
+ for (auto &it : needleCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first)))
+ needle_param[it.first] = unified_param(needleCell->type, it.first, it.second);
+ for (auto &it : haystackCell->parameters)
+ if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first)))
+ haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second);
+ if (needle_param != haystack_param)
return false;
+ }
- if (wire_attr.size() > 0)
- {
- RTLIL::Wire *lastNeedleWire = NULL;
- RTLIL::Wire *lastHaystackWire = NULL;
- std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
+ if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
+ return false;
- for (auto &conn : needleCell->connections())
- {
- RTLIL::SigSpec needleSig = conn.second;
- RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
-
- for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
- RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
- if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
- if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
- return false;
- lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
- }
+ if (wire_attr.size() > 0)
+ {
+ RTLIL::Wire *lastNeedleWire = NULL;
+ RTLIL::Wire *lastHaystackWire = NULL;
+ dict<RTLIL::IdString, RTLIL::Const> emptyAttr;
+
+ for (auto &conn : needleCell->connections())
+ {
+ RTLIL::SigSpec needleSig = conn.second;
+ RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
+
+ for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) {
+ RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire;
+ if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire)
+ if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr))
+ return false;
+ lastNeedleWire = needleWire, lastHaystackWire = haystackWire;
}
}
-
- return true;
}
- };
- struct bit_ref_t {
- std::string cell, port;
- int bit;
- };
+ return true;
+ }
+};
- bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
- int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
- {
- SigMap sigmap(mod);
- std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
+struct bit_ref_t {
+ std::string cell, port;
+ int bit;
+};
- if (sel && !sel->selected(mod)) {
- log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
- return false;
- }
+bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL,
+ int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
+{
+ SigMap sigmap(mod);
+ std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
- if (mod->processes.size() > 0) {
- log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
- return false;
- }
+ if (sel && !sel->selected(mod)) {
+ log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
+ return false;
+ }
- if (constports) {
- graph.createNode("$const$0", "$const$0", NULL, true);
- graph.createNode("$const$1", "$const$1", NULL, true);
- graph.createNode("$const$x", "$const$x", NULL, true);
- graph.createNode("$const$z", "$const$z", NULL, true);
- graph.createPort("$const$0", "\\Y", 1);
- graph.createPort("$const$1", "\\Y", 1);
- graph.createPort("$const$x", "\\Y", 1);
- graph.createPort("$const$z", "\\Y", 1);
- graph.markExtern("$const$0", "\\Y", 0);
- graph.markExtern("$const$1", "\\Y", 0);
- graph.markExtern("$const$x", "\\Y", 0);
- graph.markExtern("$const$z", "\\Y", 0);
- }
+ if (mod->processes.size() > 0) {
+ log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name));
+ return false;
+ }
- std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
- if (max_fanout > 0)
- for (auto &cell_it : mod->cells_)
- {
- RTLIL::Cell *cell = cell_it.second;
- if (!sel || sel->selected(mod, cell))
- for (auto &conn : cell->connections()) {
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
- for (auto &bit : conn_sig)
- if (bit.wire != NULL)
- sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
- }
- }
+ if (constports) {
+ graph.createNode("$const$0", "$const$0", NULL, true);
+ graph.createNode("$const$1", "$const$1", NULL, true);
+ graph.createNode("$const$x", "$const$x", NULL, true);
+ graph.createNode("$const$z", "$const$z", NULL, true);
+ graph.createPort("$const$0", "\\Y", 1);
+ graph.createPort("$const$1", "\\Y", 1);
+ graph.createPort("$const$x", "\\Y", 1);
+ graph.createPort("$const$z", "\\Y", 1);
+ graph.markExtern("$const$0", "\\Y", 0);
+ graph.markExtern("$const$1", "\\Y", 0);
+ graph.markExtern("$const$x", "\\Y", 0);
+ graph.markExtern("$const$z", "\\Y", 0);
+ }
- // create graph nodes from cells
+ std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
+ if (max_fanout > 0)
for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (sel && !sel->selected(mod, cell))
- continue;
+ if (!sel || sel->selected(mod, cell))
+ for (auto &conn : cell->connections()) {
+ RTLIL::SigSpec conn_sig = conn.second;
+ sigmap.apply(conn_sig);
+ for (auto &bit : conn_sig)
+ if (bit.wire != NULL)
+ sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
+ }
+ }
- std::string type = cell->type.str();
- if (sel == NULL && type.substr(0, 2) == "\\$")
- type = type.substr(1);
- graph.createNode(cell->name.str(), type, (void*)cell);
+ // create graph nodes from cells
+ for (auto &cell_it : mod->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ if (sel && !sel->selected(mod, cell))
+ continue;
- for (auto &conn : cell->connections())
- {
- graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
+ std::string type = cell->type.str();
+ if (sel == NULL && type.substr(0, 2) == "\\$")
+ type = type.substr(1);
+ graph.createNode(cell->name.str(), type, (void*)cell);
- if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
- continue;
+ for (auto &conn : cell->connections())
+ {
+ graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
+ if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
+ continue;
- for (int i = 0; i < conn_sig.size(); i++)
- {
- auto &bit = conn_sig[i];
-
- if (bit.wire == NULL) {
- if (constports) {
- std::string node = "$const$x";
- if (bit == RTLIL::State::S0) node = "$const$0";
- if (bit == RTLIL::State::S1) node = "$const$1";
- if (bit == RTLIL::State::Sz) node = "$const$z";
- graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
- } else
- graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
- continue;
- }
+ RTLIL::SigSpec conn_sig = conn.second;
+ sigmap.apply(conn_sig);
- if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
- continue;
+ for (int i = 0; i < conn_sig.size(); i++)
+ {
+ auto &bit = conn_sig[i];
+
+ if (bit.wire == NULL) {
+ if (constports) {
+ std::string node = "$const$x";
+ if (bit == RTLIL::State::S0) node = "$const$0";
+ if (bit == RTLIL::State::S1) node = "$const$1";
+ if (bit == RTLIL::State::Sz) node = "$const$z";
+ graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0);
+ } else
+ graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
+ continue;
+ }
- if (sel && !sel->selected(mod, bit.wire))
- continue;
+ if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
+ continue;
- if (sig_bit_ref.count(bit) == 0) {
- bit_ref_t &bit_ref = sig_bit_ref[bit];
- bit_ref.cell = cell->name.str();
- bit_ref.port = conn.first.str();
- bit_ref.bit = i;
- }
+ if (sel && !sel->selected(mod, bit.wire))
+ continue;
+ if (sig_bit_ref.count(bit) == 0) {
bit_ref_t &bit_ref = sig_bit_ref[bit];
- graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
+ bit_ref.cell = cell->name.str();
+ bit_ref.port = conn.first.str();
+ bit_ref.bit = i;
}
- }
- }
-
- // mark external signals (used in non-selected cells)
- for (auto &cell_it : mod->cells_)
- {
- RTLIL::Cell *cell = cell_it.second;
- if (sel && !sel->selected(mod, cell))
- for (auto &conn : cell->connections())
- {
- RTLIL::SigSpec conn_sig = conn.second;
- sigmap.apply(conn_sig);
- for (auto &bit : conn_sig)
- if (sig_bit_ref.count(bit) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[bit];
- graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
- }
- }
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i);
+ }
}
+ }
- // mark external signals (used in module ports)
- for (auto &wire_it : mod->wires_)
- {
- RTLIL::Wire *wire = wire_it.second;
- if (wire->port_id > 0)
+ // mark external signals (used in non-selected cells)
+ for (auto &cell_it : mod->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ if (sel && !sel->selected(mod, cell))
+ for (auto &conn : cell->connections())
{
- RTLIL::SigSpec conn_sig(wire);
+ RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
for (auto &bit : conn_sig)
@@ -284,70 +268,86 @@ namespace
graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
}
}
- }
-
- // graph.print();
- return true;
}
- RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
+ // mark external signals (used in module ports)
+ for (auto &wire_it : mod->wires_)
{
- SigMap sigmap(needle);
- SigSet<std::pair<RTLIL::IdString, int>> sig2port;
-
- // create new cell
- RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
-
- // create cell ports
- for (auto &it : needle->wires_) {
- RTLIL::Wire *wire = it.second;
- if (wire->port_id > 0) {
- for (int i = 0; i < wire->width; i++)
- sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
- cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
- }
+ RTLIL::Wire *wire = wire_it.second;
+ if (wire->port_id > 0)
+ {
+ RTLIL::SigSpec conn_sig(wire);
+ sigmap.apply(conn_sig);
+
+ for (auto &bit : conn_sig)
+ if (sig_bit_ref.count(bit) != 0) {
+ bit_ref_t &bit_ref = sig_bit_ref[bit];
+ graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit);
+ }
}
+ }
- // delete replaced cells and connect new ports
- for (auto &it : match.mappings)
- {
- auto &mapping = it.second;
- RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
- RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
+ // graph.print();
+ return true;
+}
- if (needle_cell == NULL)
- continue;
+RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
+{
+ SigMap sigmap(needle);
+ SigSet<std::pair<RTLIL::IdString, int>> sig2port;
+
+ // create new cell
+ RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name);
+
+ // create cell ports
+ for (auto &it : needle->wires_) {
+ RTLIL::Wire *wire = it.second;
+ if (wire->port_id > 0) {
+ for (int i = 0; i < wire->width; i++)
+ sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i));
+ cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width));
+ }
+ }
- for (auto &conn : needle_cell->connections()) {
- RTLIL::SigSpec sig = sigmap(conn.second);
- if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
- for (int i = 0; i < sig.size(); i++)
- for (auto &port : sig2port.find(sig[i])) {
- RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
- RTLIL::SigSpec new_sig = cell->getPort(port.first);
- new_sig.replace(port.second, bitsig);
- cell->setPort(port.first, new_sig);
- }
+ // delete replaced cells and connect new ports
+ for (auto &it : match.mappings)
+ {
+ auto &mapping = it.second;
+ RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData;
+ RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData;
+
+ if (needle_cell == NULL)
+ continue;
+
+ for (auto &conn : needle_cell->connections()) {
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) {
+ for (int i = 0; i < sig.size(); i++)
+ for (auto &port : sig2port.find(sig[i])) {
+ RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1);
+ RTLIL::SigSpec new_sig = cell->getPort(port.first);
+ new_sig.replace(port.second, bitsig);
+ cell->setPort(port.first, new_sig);
}
}
-
- haystack->remove(haystack_cell);
}
- return cell;
+ haystack->remove(haystack_cell);
}
- bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
- {
- int left_idx = 0, right_idx = 0;
- if (left->attributes.count("\\extract_order") > 0)
- left_idx = left->attributes.at("\\extract_order").as_int();
- if (right->attributes.count("\\extract_order") > 0)
- right_idx = right->attributes.at("\\extract_order").as_int();
- if (left_idx != right_idx)
- return left_idx < right_idx;
- return left->name < right->name;
- }
+ return cell;
+}
+
+bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right)
+{
+ int left_idx = 0, right_idx = 0;
+ if (left->attributes.count("\\extract_order") > 0)
+ left_idx = left->attributes.at("\\extract_order").as_int();
+ if (right->attributes.count("\\extract_order") > 0)
+ right_idx = right->attributes.at("\\extract_order").as_int();
+ if (left_idx != right_idx)
+ return left_idx < right_idx;
+ return left->name < right->name;
}
struct ExtractPass : public Pass {
@@ -518,24 +518,21 @@ struct ExtractPass : public Pass {
if (args[argidx] == "-swap" && argidx+2 < args.size()) {
std::string type = RTLIL::escape_id(args[++argidx]);
std::set<std::string> ports;
- char *ports_str = strdup(args[++argidx].c_str());
- for (char *sptr, *p = strtok_r(ports_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ std::string ports_str = args[++argidx], p;
+ while (!(p = next_token(ports_str, ",\t\r\n ")).empty())
ports.insert(RTLIL::escape_id(p));
- free(ports_str);
solver.addSwappablePorts(type, ports);
continue;
}
if (args[argidx] == "-perm" && argidx+3 < args.size()) {
std::string type = RTLIL::escape_id(args[++argidx]);
std::vector<std::string> map_left, map_right;
- char *left_str = strdup(args[++argidx].c_str());
- char *right_str = strdup(args[++argidx].c_str());
- for (char *sptr, *p = strtok_r(left_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ std::string left_str = args[++argidx];
+ std::string right_str = args[++argidx], p;
+ while (!(p = next_token(left_str, ",\t\r\n ")).empty())
map_left.push_back(RTLIL::escape_id(p));
- for (char *sptr, *p = strtok_r(right_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr))
+ while (!(p = next_token(right_str, ",\t\r\n ")).empty())
map_right.push_back(RTLIL::escape_id(p));
- free(left_str);
- free(right_str);
if (map_left.size() != map_right.size())
log_cmd_error("Arguments to -perm are not a valid permutation!\n");
std::map<std::string, std::string> map;
@@ -665,7 +662,7 @@ struct ExtractPass : public Pass {
log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str());
solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false);
}
- log("Found %zd matches.\n", results.size());
+ log("Found %d matches.\n", GetSize(results));
if (results.size() > 0)
{
@@ -761,3 +758,4 @@ struct ExtractPass : public Pass {
}
} ExtractPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index 784c4cf3..9a14ffa3 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -21,6 +21,9 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static std::string hicell_celltype, hicell_portname;
static std::string locell_celltype, locell_portname;
static bool singleton_mode;
@@ -57,9 +60,7 @@ struct HilomapPass : public Pass {
log("\n");
log(" hilomap [options] [selection]\n");
log("\n");
- log("Map module inputs/outputs to PAD cells from a library. This pass\n");
- log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
- log("the resulting cells to more sophisticated PAD cells.\n");
+ log("Map constants to 'tielo' and 'tiehi' driver cells.\n");
log("\n");
log(" -hicell <celltype> <portname>\n");
log(" Replace constant hi bits with this cell.\n");
@@ -75,7 +76,7 @@ struct HilomapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HILOPAD pass (mapping to constant drivers).\n");
+ log_header("Executing HILOMAP pass (mapping to constant drivers).\n");
hicell_celltype = std::string();
hicell_portname = std::string();
@@ -119,3 +120,4 @@ struct HilomapPass : public Pass {
}
} HilomapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 9cd23ce6..3fba0e61 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -21,7 +21,10 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static void split_portname_pair(std::string &port1, std::string &port2)
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void split_portname_pair(std::string &port1, std::string &port2)
{
size_t pos = port1.find_first_of(':');
if (pos != std::string::npos) {
@@ -59,8 +62,8 @@ struct IopadmapPass : public Pass {
log("\n");
log(" -bits\n");
log(" create individual bit-wide buffers even for ports that\n");
- log(" are wider. (the default behavio is to create word-wide\n");
- log(" buffers use -widthparam to set the word size on the cell.)\n");
+ log(" are wider. (the default behavior is to create word-wide\n");
+ log(" buffers using -widthparam to set the word size on the cell.)\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -111,18 +114,11 @@ struct IopadmapPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = it.second;
-
- if (!design->selected(module) || module->get_bool_attribute("\\blackbox"))
- continue;
-
- for (auto &it2 : module->wires_)
+ for (auto wire : module->selected_wires())
{
- RTLIL::Wire *wire = it2.second;
-
- if (!wire->port_id || !design->selected(module, wire))
+ if (!wire->port_id)
continue;
std::string celltype, portname, portname2;
@@ -207,3 +203,4 @@ struct IopadmapPass : public Pass {
}
} IopadmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 612fa111..def48039 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -29,7 +29,7 @@
#include "kernel/log.h"
#endif
-using namespace PASS_DFFLIBMAP;
+using namespace Yosys;
std::set<std::string> LibertyAst::blacklist;
std::set<std::string> LibertyAst::whitelist;
@@ -43,8 +43,6 @@ LibertyAst::~LibertyAst()
LibertyAst *LibertyAst::find(std::string name)
{
- if (this == NULL)
- return NULL;
for (auto child : children)
if (child->id == name)
return child;
@@ -107,14 +105,14 @@ int LibertyParser::lexer(std::string &str)
}
if (c == '"') {
- str = c;
+ str = "";
while (1) {
c = f.get();
if (c == '\n')
line++;
- str += c;
if (c == '"')
break;
+ str += c;
}
// fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
return 'v';
@@ -244,21 +242,6 @@ void LibertyParser::error()
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
-// This is to not confuse the VIM syntax highlighting
-#define CHECK_VAL_OPEN (
-#define CHECK_VAL_CLOSE )
-
-#define CHECK(result, check) \
- CHECK_VAL_OPEN{ \
- auto _R = (result); \
- if (!(_R check)) { \
- fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
- #result, (long int)_R, #check, __FILE__, __LINE__); \
- abort(); \
- } \
- _R; \
- }CHECK_VAL_CLOSE
-
#define CHECK_NV(result, check) \
do { \
auto _R = (result); \
@@ -280,6 +263,14 @@ void LibertyParser::error()
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+LibertyAst *find_non_null(LibertyAst *node, const char *name)
+{
+ LibertyAst *ret = node->find(name);
+ if (ret == NULL)
+ fprintf(stderr, "Error: expected to find `%s' node.\n", name);
+ return ret;
+}
+
std::string func2vl(std::string str)
{
for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
@@ -388,7 +379,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
if (child->id != "pin")
continue;
CHECK_NV(child->args.size(), == 1);
- LibertyAst *dir = CHECK(child->find("direction"), != NULL);
+ LibertyAst *dir = find_non_null(child, "direction");
LibertyAst *func = child->find("function");
printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
if (func != NULL)
@@ -428,8 +419,8 @@ void gen_verilogsim_cell(LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
- clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
- clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+ clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
+ clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
@@ -449,7 +440,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
}
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
- std::string expr = CHECK(child->find("next_state"), != NULL)->value;
+ std::string expr = find_non_null(child, "next_state")->value;
printf(" // %s\n", expr.c_str());
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
@@ -481,8 +472,8 @@ void gen_verilogsim_cell(LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
- clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value);
- clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value);
+ clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
+ clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
@@ -502,7 +493,7 @@ void gen_verilogsim_cell(LibertyAst *ast)
}
if (!enable_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
- std::string expr = CHECK(child->find("data_in"), != NULL)->value;
+ std::string expr = find_non_null(child, "data_in")->value;
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
printf(" end\n");
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index 24748742..e947bd8c 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -25,7 +25,7 @@
#include <vector>
#include <set>
-namespace PASS_DFFLIBMAP
+namespace Yosys
{
struct LibertyAst
{
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 2d625eef..ffbd6289 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -20,7 +20,8 @@
#include "kernel/yosys.h"
#include "kernel/macc.h"
-extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
struct MaccmapWorker
{
@@ -48,7 +49,7 @@ struct MaccmapWorker
void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract)
{
- a.extend(width, is_signed);
+ a.extend_u0(width, is_signed);
if (do_subtract) {
a = module->Not(NEW_ID, a);
@@ -61,16 +62,16 @@ struct MaccmapWorker
void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract)
{
- if (SIZE(a) < SIZE(b))
+ if (GetSize(a) < GetSize(b))
std::swap(a, b);
- a.extend(width, is_signed);
+ a.extend_u0(width, is_signed);
- if (SIZE(b) > width)
- b.extend(width, is_signed);
+ if (GetSize(b) > width)
+ b.extend_u0(width, is_signed);
- for (int i = 0; i < SIZE(b); i++)
- if (is_signed && i+1 == SIZE(b))
+ for (int i = 0; i < GetSize(b); i++)
+ if (is_signed && i+1 == GetSize(b))
{
a = {module->Not(NEW_ID, a.extract(i, width-i)), RTLIL::SigSpec(0, i)};
add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
@@ -85,7 +86,7 @@ struct MaccmapWorker
void fulladd(RTLIL::SigSpec &in1, RTLIL::SigSpec &in2, RTLIL::SigSpec &in3, RTLIL::SigSpec &out1, RTLIL::SigSpec &out2)
{
- int start_index = 0, stop_index = SIZE(in1);
+ int start_index = 0, stop_index = GetSize(in1);
while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
start_index++;
@@ -95,18 +96,18 @@ struct MaccmapWorker
if (start_index == stop_index)
{
- out1 = RTLIL::SigSpec(0, SIZE(in1));
- out2 = RTLIL::SigSpec(0, SIZE(in1));
+ out1 = RTLIL::SigSpec(0, GetSize(in1));
+ out2 = RTLIL::SigSpec(0, GetSize(in1));
}
else
{
- RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(in1)-stop_index);
+ RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, GetSize(in1)-stop_index);
in1 = in1.extract(start_index, stop_index-start_index);
in2 = in2.extract(start_index, stop_index-start_index);
in3 = in3.extract(start_index, stop_index-start_index);
- int width = SIZE(in1);
+ int width = GetSize(in1);
RTLIL::Wire *w1 = module->addWire(NEW_ID, width);
RTLIL::Wire *w2 = module->addWire(NEW_ID, width);
@@ -164,12 +165,12 @@ struct MaccmapWorker
while (1)
{
- int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(tree_sum_bits);
+ int free_bit_slots = tree_bit_slots(GetSize(summands)) - GetSize(tree_sum_bits);
int max_depth = 0, max_position = 0;
for (int i = 0; i < width; i++)
- if (max_depth <= SIZE(bits.at(i))) {
- max_depth = SIZE(bits.at(i));
+ if (max_depth <= GetSize(bits.at(i))) {
+ max_depth = GetSize(bits.at(i));
max_position = i;
}
@@ -178,14 +179,14 @@ struct MaccmapWorker
int required_bits = 0;
for (int i = 0; i <= max_position; i++)
- if (SIZE(bits.at(i)) == max_depth)
+ if (GetSize(bits.at(i)) == max_depth)
required_bits += 1 << i;
if (required_bits > free_bit_slots)
break;
for (int i = 0; i <= max_position; i++)
- if (SIZE(bits.at(i)) == max_depth) {
+ if (GetSize(bits.at(i)) == max_depth) {
auto it = bits.at(i).begin();
RTLIL::SigBit bit = *it;
for (int k = 0; k < (1 << i); k++, free_bit_slots--)
@@ -199,23 +200,23 @@ struct MaccmapWorker
}
if (!tree_sum_bits.empty())
- log(" packed %d (%d) bits / %d words into adder tree\n", SIZE(tree_sum_bits), unique_tree_bits, count_tree_words);
+ log(" packed %d (%d) bits / %d words into adder tree\n", GetSize(tree_sum_bits), unique_tree_bits, count_tree_words);
- if (SIZE(summands) == 0) {
+ if (GetSize(summands) == 0) {
log_assert(tree_sum_bits.empty());
return RTLIL::SigSpec(0, width);
}
- if (SIZE(summands) == 1) {
+ if (GetSize(summands) == 1) {
log_assert(tree_sum_bits.empty());
return summands.front();
}
- while (SIZE(summands) > 2)
+ while (GetSize(summands) > 2)
{
std::vector<RTLIL::SigSpec> new_summands;
- for (int i = 0; i < SIZE(summands); i += 3)
- if (i+2 < SIZE(summands)) {
+ for (int i = 0; i < GetSize(summands); i += 3)
+ if (i+2 < GetSize(summands)) {
RTLIL::SigSpec in1 = summands[i];
RTLIL::SigSpec in2 = summands[i+1];
RTLIL::SigSpec in3 = summands[i+2];
@@ -256,9 +257,14 @@ struct MaccmapWorker
}
};
+PRIVATE_NAMESPACE_END
+YOSYS_NAMESPACE_BEGIN
+
+extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+
void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
{
- int width = SIZE(cell->getPort("\\Y"));
+ int width = GetSize(cell->getPort("\\Y"));
Macc macc;
macc.from_cell(cell);
@@ -273,15 +279,15 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
}
for (auto &port : macc.ports)
- if (SIZE(port.in_b) == 0)
+ if (GetSize(port.in_b) == 0)
log(" %s %s (%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a),
- SIZE(port.in_a), port.is_signed ? "signed" : "unsigned");
+ GetSize(port.in_a), port.is_signed ? "signed" : "unsigned");
else
log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b),
- SIZE(port.in_a), SIZE(port.in_b), port.is_signed ? "signed" : "unsigned");
+ GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned");
- if (SIZE(macc.bit_ports) != 0)
- log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports));
+ if (GetSize(macc.bit_ports) != 0)
+ log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), GetSize(macc.bit_ports));
if (unmap)
{
@@ -290,10 +296,10 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
for (auto &port : macc.ports) {
summand_t this_summand;
- if (SIZE(port.in_b)) {
+ if (GetSize(port.in_b)) {
this_summand.first = module->addWire(NEW_ID, width);
module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed);
- } else if (SIZE(port.in_a) != width) {
+ } else if (GetSize(port.in_a) != width) {
this_summand.first = module->addWire(NEW_ID, width);
module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
} else {
@@ -306,14 +312,14 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
for (auto &bit : macc.bit_ports)
summands.push_back(summand_t(bit, false));
- if (SIZE(summands) == 0)
+ if (GetSize(summands) == 0)
summands.push_back(summand_t(RTLIL::SigSpec(0, width), false));
- while (SIZE(summands) > 1)
+ while (GetSize(summands) > 1)
{
std::vector<summand_t> new_summands;
- for (int i = 0; i < SIZE(summands); i += 2) {
- if (i+1 < SIZE(summands)) {
+ for (int i = 0; i < GetSize(summands); i += 2) {
+ if (i+1 < GetSize(summands)) {
summand_t this_summand;
this_summand.first = module->addWire(NEW_ID, width);
this_summand.second = summands[i].second && summands[i+1].second;
@@ -342,7 +348,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
MaccmapWorker worker(module, width);
for (auto &port : macc.ports)
- if (SIZE(port.in_b) == 0)
+ if (GetSize(port.in_b) == 0)
worker.add(port.in_a, port.is_signed, port.do_subtract);
else
worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract);
@@ -354,6 +360,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
}
}
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct MaccmapPass : public Pass {
MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
virtual void help()
@@ -392,3 +401,4 @@ struct MaccmapPass : public Pass {
}
} MaccmapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index f8d5d458..9cea5f45 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -17,53 +17,53 @@
*
*/
-#include "kernel/register.h"
+#include "simplemap.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+USING_YOSYS_NAMESPACE
+YOSYS_NAMESPACE_BEGIN
-static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\Y", sig_y[i]);
}
}
-static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
module->connect(RTLIL::SigSig(sig_y, sig_a));
}
-static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- sig_b.extend_u0(SIZE(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
+ sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
+ sig_b.extend_u0(GetSize(sig_y), cell->parameters.at("\\B_SIGNED").as_bool());
if (cell->type == "$xnor")
{
- RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y));
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, GetSize(sig_y));
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
gate->setPort("\\A", sig_t[i]);
gate->setPort("\\Y", sig_y[i]);
@@ -79,7 +79,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$xnor") gate_type = "$_XOR_";
log_assert(!gate_type.empty());
- for (int i = 0; i < SIZE(sig_y); i++) {
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\B", sig_b[i]);
@@ -87,7 +87,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
@@ -182,7 +182,7 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
sig = RTLIL::SigSpec(0, 1);
}
-static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
@@ -202,7 +202,7 @@ static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
gate->setPort("\\Y", sig_y);
}
-static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
@@ -231,13 +231,38 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
gate->setPort("\\Y", sig_y);
}
-static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B");
RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ bool is_ne = cell->type == "$ne" || cell->type == "$nex";
+
+ RTLIL::SigSpec xor_out = module->addWire(NEW_ID, std::max(GetSize(sig_a), GetSize(sig_b)));
+ RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed);
+ simplemap_bitop(module, xor_cell);
+ module->remove(xor_cell);
+
+ RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID);
+ RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out);
+ simplemap_reduce(module, reduce_cell);
+ module->remove(reduce_cell);
+
+ if (!is_ne) {
+ RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y);
+ simplemap_lognot(module, not_cell);
+ module->remove(not_cell);
+ }
+}
- for (int i = 0; i < SIZE(sig_y); i++) {
+void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ for (int i = 0; i < GetSize(sig_y); i++) {
RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
gate->setPort("\\A", sig_a[i]);
gate->setPort("\\B", sig_b[i]);
@@ -246,7 +271,7 @@ static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
RTLIL::SigSpec sig_a = cell->getPort("\\A");
@@ -254,7 +279,7 @@ static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
}
-static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
{
RTLIL::SigSpec sig_ab = cell->getPort("\\A");
sig_ab.append(cell->getPort("\\B"));
@@ -262,7 +287,7 @@ static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
-static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
@@ -282,7 +307,7 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -301,7 +326,29 @@ static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
+ char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
+
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+ std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol);
+
+ for (int i = 0; i < width; i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\E", sig_en);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
+ }
+}
+
+void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -326,7 +373,7 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
@@ -353,7 +400,7 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
-static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
{
int width = cell->parameters.at("\\WIDTH").as_int();
char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
@@ -388,16 +435,37 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
mappers["$logic_not"] = simplemap_lognot;
mappers["$logic_and"] = simplemap_logbin;
mappers["$logic_or"] = simplemap_logbin;
+ mappers["$eq"] = simplemap_eqne;
+ mappers["$eqx"] = simplemap_eqne;
+ mappers["$ne"] = simplemap_eqne;
+ mappers["$nex"] = simplemap_eqne;
mappers["$mux"] = simplemap_mux;
mappers["$slice"] = simplemap_slice;
mappers["$concat"] = simplemap_concat;
mappers["$sr"] = simplemap_sr;
mappers["$dff"] = simplemap_dff;
+ mappers["$dffe"] = simplemap_dffe;
mappers["$dffsr"] = simplemap_dffsr;
mappers["$adff"] = simplemap_adff;
mappers["$dlatch"] = simplemap_dlatch;
}
+void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ static std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ static bool initialized_mappers = false;
+
+ if (!initialized_mappers) {
+ simplemap_get_mappers(mappers);
+ initialized_mappers = true;
+ }
+
+ mappers.at(cell->type)(module, cell);
+}
+
+YOSYS_NAMESPACE_END
+PRIVATE_NAMESPACE_BEGIN
+
struct SimplemapPass : public Pass {
SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
virtual void help()
@@ -440,3 +508,4 @@ struct SimplemapPass : public Pass {
}
} SimplemapPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
new file mode 100644
index 00000000..dc2a395d
--- /dev/null
+++ b/passes/techmap/simplemap.h
@@ -0,0 +1,48 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef SIMPLEMAP_H
+#define SIMPLEMAP_H
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+extern void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
+
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index ed466faa..ab748ed7 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -26,15 +26,20 @@
#include <stdio.h>
#include <string.h>
+#include "simplemap.h"
#include "passes/techmap/techmap.inc"
-// see simplemap.cc
-extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+YOSYS_NAMESPACE_BEGIN
// see maccmap.cc
extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
-static void apply_prefix(std::string prefix, std::string &id)
+YOSYS_NAMESPACE_END
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void apply_prefix(std::string prefix, std::string &id)
{
if (id[0] == '\\')
id = prefix + "." + id.substr(1);
@@ -42,7 +47,7 @@ static void apply_prefix(std::string prefix, std::string &id)
id = "$techmap" + prefix + "." + id;
}
-static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
+void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
std::vector<RTLIL::SigChunk> chunks = sig;
for (auto &chunk : chunks)
@@ -61,6 +66,11 @@ struct TechmapWorker
std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
std::map<RTLIL::Module*, bool> techmap_do_cache;
std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
+ dict<Module*, SigMap> sigmaps;
+
+ pool<IdString> flatten_do_list;
+ pool<IdString> flatten_done_list;
+ pool<Cell*> flatten_keep_list;
struct TechmapWireData {
RTLIL::Wire *wire;
@@ -90,7 +100,7 @@ struct TechmapWorker
std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map;
for (auto conn : cell->connections())
- for (int i = 0; i < SIZE(conn.second); i++) {
+ for (int i = 0; i < GetSize(conn.second); i++) {
RTLIL::SigBit bit = sigmap(conn.second[i]);
if (bit.wire == nullptr) {
if (verbose)
@@ -102,8 +112,10 @@ struct TechmapWorker
connbits_map.at(bit).second, log_id(connbits_map.at(bit).first));
constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i,
log_id(connbits_map.at(bit).first), connbits_map.at(bit).second);
- } else
- connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
+ } else {
+ connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);
+ constmap_info += stringf("|%s %d", log_id(conn.first), i);
+ }
}
return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str());
@@ -122,7 +134,7 @@ struct TechmapWorker
continue;
const char *q = strrchr(p+1, '.');
- p = q ? q : p+1;
+ p = q ? q+1 : p+1;
if (!strncmp(p, "_TECHMAP_", 9)) {
TechmapWireData record;
@@ -146,16 +158,13 @@ struct TechmapWorker
void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl)
{
- if (tpl->memories.size() != 0)
- log_error("Technology map yielded memories -> this is not supported.\n");
-
if (tpl->processes.size() != 0) {
log("Technology map yielded processes:\n");
for (auto &it : tpl->processes)
log(" %s",RTLIL::id2cstr(it.first));
if (autoproc_mode) {
Pass::call_on_module(tpl->design, tpl, "proc");
- log_assert(SIZE(tpl->processes) == 0);
+ log_assert(GetSize(tpl->processes) == 0);
} else
log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n");
}
@@ -169,6 +178,22 @@ struct TechmapWorker
break;
}
+ dict<IdString, IdString> memory_renames;
+
+ for (auto &it : tpl->memories) {
+ std::string m_name = it.first.str();
+ apply_prefix(cell->name.str(), m_name);
+ RTLIL::Memory *m = new RTLIL::Memory;
+ m->name = m_name;
+ m->width = it.second->width;
+ m->start_offset = it.second->start_offset;
+ m->size = it.second->size;
+ m->attributes = it.second->attributes;
+ module->memories[m->name] = m;
+ memory_renames[it.first] = m->name;
+ design->select(module, m);
+ }
+
std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
for (auto &it : tpl->wires_) {
@@ -215,6 +240,11 @@ struct TechmapWorker
if (flatten_mode) {
// more conservative approach:
// connect internal and external wires
+ if (sigmaps.count(module) == 0)
+ sigmaps[module].set(module);
+ if (sigmaps.at(module)(c.first).has_const())
+ log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n",
+ log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second));
module->connect(c);
} else {
// approach that yields nicer outputs:
@@ -245,6 +275,12 @@ struct TechmapWorker
apply_prefix(cell->name.str(), it2.second, module);
port_signal_map.apply(it2.second);
}
+
+ if (c->type == "$memrd" || c->type == "$memwr") {
+ IdString memid = c->getParam("\\MEMID").decode_string();
+ log_assert(memory_renames.count(memid));
+ c->setParam("\\MEMID", Const(memory_renames[memid].str()));
+ }
}
for (auto &it : tpl->connections()) {
@@ -272,7 +308,7 @@ struct TechmapWorker
SigMap sigmap(module);
- TopoSort<RTLIL::Cell*> cells;
+ TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell;
@@ -291,12 +327,28 @@ struct TechmapWorker
continue;
}
+ if (flatten_mode) {
+ bool keepit = cell->get_bool_attribute("\\keep_hierarchy");
+ for (auto &tpl_name : celltypeMap.at(cell_type))
+ if (map->modules_[tpl_name]->get_bool_attribute("\\keep_hierarchy"))
+ keepit = true;
+ if (keepit) {
+ if (!flatten_keep_list[cell]) {
+ log("Keeping %s.%s (found keep_hierarchy property).\n", log_id(module), log_id(cell));
+ flatten_keep_list.insert(cell);
+ }
+ if (!flatten_done_list[cell->type])
+ flatten_do_list.insert(cell->type);
+ continue;
+ }
+ }
+
for (auto &conn : cell->connections())
{
RTLIL::SigSpec sig = sigmap(conn.second);
sig.remove_const();
- if (SIZE(sig) == 0)
+ if (GetSize(sig) == 0)
continue;
for (auto &tpl_name : celltypeMap.at(cell_type)) {
@@ -334,7 +386,7 @@ struct TechmapWorker
{
RTLIL::IdString derived_name = tpl_name;
RTLIL::Module *tpl = map->modules_[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+ std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
if (tpl->get_bool_attribute("\\blackbox"))
continue;
@@ -376,7 +428,7 @@ struct TechmapWorker
int port_counter = 1;
for (auto &c : extmapper_cell->connections_) {
- RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second));
+ RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second));
if (w->name == "\\Y" || w->name == "\\Q")
w->port_output = true;
else
@@ -522,7 +574,7 @@ struct TechmapWorker
tpl = techmap_cache[key];
} else {
if (cell->parameters.size() != 0) {
- derived_name = tpl->derive(map, parameters);
+ derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name);
log_continue = true;
}
@@ -623,7 +675,7 @@ struct TechmapWorker
}
for (auto conn : cell->connections())
- for (int i = 0; i < SIZE(conn.second); i++)
+ for (int i = 0; i < GetSize(conn.second); i++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
@@ -968,7 +1020,7 @@ struct TechmapPass : public Pass {
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
}
- std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
+ dict<RTLIL::IdString, RTLIL::Module*> modules_new;
for (auto &it : map->modules_) {
if (it.first.substr(0, 2) == "\\$")
it.second->name = it.first.substr(1);
@@ -1027,6 +1079,9 @@ struct FlattenPass : public Pass {
log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n");
log("pass is using the current design as mapping library.\n");
log("\n");
+ log("Cells and/or modules with the 'keep_hiearchy' attribute set will not be\n");
+ log("flattened by this command.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -1039,8 +1094,8 @@ struct FlattenPass : public Pass {
worker.flatten_mode = true;
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
- for (auto &it : design->modules_)
- celltypeMap[it.first].insert(it.first);
+ for (auto module : design->modules())
+ celltypeMap[module->name].insert(module->name);
RTLIL::Module *top_mod = NULL;
if (design->full_selection())
@@ -1048,26 +1103,40 @@ struct FlattenPass : public Pass {
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
- bool did_something = true;
std::set<RTLIL::Cell*> handled_cells;
- while (did_something) {
- did_something = false;
- if (top_mod != NULL) {
- if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false))
- did_something = true;
- } else {
- for (auto mod : design->modules())
- if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false))
- did_something = true;
+ if (top_mod != NULL) {
+ worker.flatten_do_list.insert(top_mod->name);
+ while (!worker.flatten_do_list.empty()) {
+ auto mod = design->module(*worker.flatten_do_list.begin());
+ while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
+ worker.flatten_done_list.insert(mod->name);
+ worker.flatten_do_list.erase(mod->name);
}
+ } else {
+ for (auto mod : vector<Module*>(design->modules()))
+ while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { }
}
log("No more expansions possible.\n");
- if (top_mod != NULL) {
- std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto mod : design->modules())
- if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) {
+ if (top_mod != NULL)
+ {
+ pool<RTLIL::IdString> used_modules, new_used_modules;
+ new_used_modules.insert(top_mod->name);
+ while (!new_used_modules.empty()) {
+ pool<RTLIL::IdString> queue;
+ queue.swap(new_used_modules);
+ for (auto modname : queue)
+ used_modules.insert(modname);
+ for (auto modname : queue)
+ for (auto cell : design->module(modname)->cells())
+ if (design->module(cell->type) && !used_modules[cell->type])
+ new_used_modules.insert(cell->type);
+ }
+
+ dict<RTLIL::IdString, RTLIL::Module*> new_modules;
+ for (auto mod : vector<Module*>(design->modules()))
+ if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) {
new_modules[mod->name] = mod;
} else {
log("Deleting now unused module %s.\n", log_id(mod));
@@ -1080,3 +1149,4 @@ struct FlattenPass : public Pass {
}
} FlattenPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
index 0a0ceb1d..09cb4195 100644
--- a/passes/tests/test_abcloop.cc
+++ b/passes/tests/test_abcloop.cc
@@ -21,6 +21,9 @@
#include "kernel/yosys.h"
#include "kernel/satgen.h"
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static uint32_t xorshift32_state = 123456789;
static uint32_t xorshift32(uint32_t limit) {
@@ -33,7 +36,7 @@ static uint32_t xorshift32(uint32_t limit) {
static RTLIL::Wire *getw(std::vector<RTLIL::Wire*> &wires, RTLIL::Wire *w)
{
while (1) {
- int idx = xorshift32(SIZE(wires));
+ int idx = xorshift32(GetSize(wires));
if (wires[idx] != w && !wires[idx]->port_output)
return wires[idx];
}
@@ -124,28 +127,28 @@ static void test_abcloop()
module->fixup_ports();
Pass::call(design, "clean");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok = satgen.importCell(c);
+ bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
log_assert(ok);
}
std::vector<int> in_vec = satgen.importSigSpec(in_sig);
- std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+ std::vector<int> inverse_in_vec = ez->vec_not(in_vec);
std::vector<int> out_vec = satgen.importSigSpec(out_sig);
for (int i = 0; i < 16; i++)
{
std::vector<int> assumptions;
- for (int j = 0; j < SIZE(in_vec); j++)
+ for (int j = 0; j < GetSize(in_vec); j++)
assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
std::vector<bool> results;
- if (!ez.solve(out_vec, results, assumptions)) {
+ if (!ez->solve(out_vec, results, assumptions)) {
log("No stable solution for input %d found -> recreate module.\n", i);
goto recreate_module;
}
@@ -153,10 +156,10 @@ static void test_abcloop()
for (int j = 0; j < 4; j++)
truthtab[i][j] = results[j];
- assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+ assumptions.push_back(ez->vec_ne(out_vec, ez->vec_const(results)));
std::vector<bool> results2;
- if (ez.solve(out_vec, results2, assumptions)) {
+ if (ez->solve(out_vec, results2, assumptions)) {
log("Two stable solutions for input %d found -> recreate module.\n", i);
goto recreate_module;
}
@@ -174,17 +177,17 @@ static void test_abcloop()
log("\n");
log("Pre- and post-abc truth table:\n");
- ezDefaultSAT ez;
+ ezSatPtr ez;
SigMap sigmap(module);
- SatGen satgen(&ez, &sigmap);
+ SatGen satgen(ez.get(), &sigmap);
for (auto c : module->cells()) {
- bool ok = satgen.importCell(c);
+ bool ok YS_ATTRIBUTE(unused) = satgen.importCell(c);
log_assert(ok);
}
std::vector<int> in_vec = satgen.importSigSpec(in_sig);
- std::vector<int> inverse_in_vec = ez.vec_not(in_vec);
+ std::vector<int> inverse_in_vec = ez->vec_not(in_vec);
std::vector<int> out_vec = satgen.importSigSpec(out_sig);
@@ -194,14 +197,14 @@ static void test_abcloop()
for (int i = 0; i < 16; i++)
{
std::vector<int> assumptions;
- for (int j = 0; j < SIZE(in_vec); j++)
+ for (int j = 0; j < GetSize(in_vec); j++)
assumptions.push_back((i & (1 << j)) ? in_vec.at(j) : inverse_in_vec.at(j));
for (int j = 0; j < 4; j++)
truthtab2[i][j] = truthtab[i][j];
std::vector<bool> results;
- if (!ez.solve(out_vec, results, assumptions)) {
+ if (!ez->solve(out_vec, results, assumptions)) {
log("No stable solution for input %d found.\n", i);
found_error = true;
continue;
@@ -210,10 +213,10 @@ static void test_abcloop()
for (int j = 0; j < 4; j++)
truthtab2[i][j] = results[j];
- assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+ assumptions.push_back(ez->vec_ne(out_vec, ez->vec_const(results)));
std::vector<bool> results2;
- if (ez.solve(out_vec, results2, assumptions)) {
+ if (ez->solve(out_vec, results2, assumptions)) {
log("Two stable solutions for input %d found -> recreate module.\n", i);
found_error = true;
}
@@ -262,13 +265,13 @@ struct TestAbcloopPass : public Pass {
xorshift32_state = 0;
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
xorshift32_state = atoi(args[++argidx].c_str());
continue;
}
@@ -283,3 +286,4 @@ struct TestAbcloopPass : public Pass {
}
} TestAbcloopPass;
+PRIVATE_NAMESPACE_END
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index eed0f75f..7c1b671c 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <time.h>
+USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static std::string id(std::string internal_id)
@@ -91,7 +92,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("end\n");
f << stringf("endtask\n\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
{
std::map<std::string, int> signal_in;
std::map<std::string, std::string> signal_const;
@@ -105,7 +106,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
int count_ports = 0;
log("Generating test bench for module `%s'.\n", it->first.c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output) {
count_ports++;
@@ -114,8 +115,8 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
} else if (wire->port_input) {
count_ports++;
bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
- for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); it3++)
- for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); it4++) {
+ for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); ++it3)
+ for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); ++it4) {
if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
continue;
RTLIL::SigSpec &signal = (*it4)->signal;
@@ -134,7 +135,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
}
}
f << stringf("%s %s(\n", id(mod->name.str()).c_str(), idy("uut", mod->name.str()).c_str());
- for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); it2++) {
+ for (auto it2 = mod->wires_.begin(); it2 != mod->wires_.end(); ++it2) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output || wire->port_input)
f << stringf("\t.%s(%s)%s\n", id(wire->name.str()).c_str(),
@@ -145,23 +146,23 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("task %s;\n", idy(mod->name.str(), "reset").c_str());
f << stringf("begin\n");
int delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++)
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
- for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
- for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ for (auto it = signal_in.begin(); it != signal_in.end(); ++it) {
if (signal_const.count(it->first) == 0)
continue;
f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
@@ -194,7 +195,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf(" } = {");
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
- f << stringf(" } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits);
+ f << stringf(" } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits + 1);
}
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -292,7 +293,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("initial begin\n");
f << stringf("\t// $dumpfile(\"testbench.vcd\");\n");
f << stringf("\t// $dumpvars(0, testbench);\n");
- for (auto it = design->modules_.begin(); it != design->modules_.end(); it++)
+ for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it)
if (!it->second->get_bool_attribute("\\gentb_skip"))
f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str());
f << stringf("\t$finish;\n");
@@ -335,9 +336,9 @@ struct TestAutotbBackend : public Backend {
log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
index 1fa90b54..268f2559 100644
--- a/passes/tests/test_cell.cc
+++ b/passes/tests/test_cell.cc
@@ -24,6 +24,9 @@
#include "kernel/macc.h"
#include <algorithm>
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
static uint32_t xorshift32_state = 123456789;
static uint32_t xorshift32(uint32_t limit) {
@@ -33,7 +36,7 @@ static uint32_t xorshift32(uint32_t limit) {
return xorshift32_state % limit;
}
-static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
+static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode, bool muxdiv)
{
RTLIL::Module *module = design->addModule("\\gold");
RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
@@ -199,6 +202,13 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort("\\Y", wire);
}
+ if (muxdiv && (cell_type == "$div" || cell_type == "$mod")) {
+ auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort("\\B"));
+ auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort("\\Y")));
+ module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort("\\Y"));
+ cell->setPort("\\Y", div_out);
+ }
+
if (cell_type == "$alu")
{
wire = module->addWire("\\CI");
@@ -210,12 +220,12 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
cell->setPort("\\BI", wire);
wire = module->addWire("\\X");
- wire->width = SIZE(cell->getPort("\\Y"));
+ wire->width = GetSize(cell->getPort("\\Y"));
wire->port_output = true;
cell->setPort("\\X", wire);
wire = module->addWire("\\CO");
- wire->width = SIZE(cell->getPort("\\Y"));
+ wire->width = GetSize(cell->getPort("\\Y"));
wire->port_output = true;
cell->setPort("\\CO", wire);
}
@@ -227,25 +237,25 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type,
{
RTLIL::SigSpec sig = conn.second;
- if (SIZE(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
+ if (GetSize(sig) == 0 || sig[0].wire == nullptr || sig[0].wire->port_output)
continue;
int n, m;
switch (xorshift32(5))
{
case 0:
- n = xorshift32(SIZE(sig) + 1);
+ n = xorshift32(GetSize(sig) + 1);
for (int i = 0; i < n; i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
case 1:
- n = xorshift32(SIZE(sig) + 1);
- for (int i = n; i < SIZE(sig); i++)
+ n = xorshift32(GetSize(sig) + 1);
+ for (int i = n; i < GetSize(sig); i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
case 2:
- n = xorshift32(SIZE(sig));
- m = xorshift32(SIZE(sig));
+ n = xorshift32(GetSize(sig));
+ m = xorshift32(GetSize(sig));
for (int i = std::min(n, m); i < std::max(n, m); i++)
sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
break;
@@ -268,10 +278,10 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
RTLIL::Module *gate_mod = design->module("\\gate");
ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
- ezDefaultSAT ez1, ez2;
+ ezSatPtr ez1, ez2;
SigMap sigmap(gold_mod);
- SatGen satgen1(&ez1, &sigmap);
- SatGen satgen2(&ez2, &sigmap);
+ SatGen satgen1(ez1.get(), &sigmap);
+ SatGen satgen2(ez2.get(), &sigmap);
satgen2.model_undef = true;
if (!nosat)
@@ -287,19 +297,19 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
for (auto port : gold_mod->ports) {
RTLIL::Wire *wire = gold_mod->wire(port);
if (wire->port_input)
- vlog_file << stringf(" reg [%d:0] %s;\n", SIZE(wire)-1, log_id(wire));
+ vlog_file << stringf(" reg [%d:0] %s;\n", GetSize(wire)-1, log_id(wire));
else
- vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", SIZE(wire)-1, log_id(wire), log_id(wire));
+ vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", GetSize(wire)-1, log_id(wire), log_id(wire));
}
vlog_file << stringf(" %s_expr uut_expr(", uut_name.c_str());
- for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ for (int i = 0; i < GetSize(gold_mod->ports); i++)
vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_expr");
vlog_file << stringf(");\n");
vlog_file << stringf(" %s_expr uut_noexpr(", uut_name.c_str());
- for (int i = 0; i < SIZE(gold_mod->ports); i++)
+ for (int i = 0; i < GetSize(gold_mod->ports); i++)
vlog_file << stringf("%s.%s(%s%s)", i ? ", " : "", log_id(gold_mod->ports[i]), log_id(gold_mod->ports[i]),
gold_mod->wire(gold_mod->ports[i])->port_input ? "" : "_noexpr");
vlog_file << stringf(");\n");
@@ -327,18 +337,18 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_assert(gold_wire != nullptr);
log_assert(gate_wire != nullptr);
log_assert(gold_wire->port_input == gate_wire->port_input);
- log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+ log_assert(GetSize(gold_wire) == GetSize(gate_wire));
if (!gold_wire->port_input)
continue;
RTLIL::Const in_value;
- for (int i = 0; i < SIZE(gold_wire); i++)
+ for (int i = 0; i < GetSize(gold_wire); i++)
in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
if (xorshift32(4) == 0) {
int inv_chance = 1 + xorshift32(8);
- for (int i = 0; i < SIZE(gold_wire); i++)
+ for (int i = 0; i < GetSize(gold_wire); i++)
if (xorshift32(inv_chance) == 0)
in_value.bits[i] = RTLIL::Sx;
}
@@ -352,7 +362,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
gold_ce.set(gold_wire, in_value);
gate_ce.set(gate_wire, in_value);
- if (vlog_file.is_open() && SIZE(in_value) > 0) {
+ if (vlog_file.is_open() && GetSize(in_value) > 0) {
vlog_file << stringf(" %s = 'b%s;\n", log_id(gold_wire), in_value.as_string().c_str());
if (!vlog_pattern_info.empty())
vlog_pattern_info += " ";
@@ -371,7 +381,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_assert(gold_wire != nullptr);
log_assert(gate_wire != nullptr);
log_assert(gold_wire->port_output == gate_wire->port_output);
- log_assert(SIZE(gold_wire) == SIZE(gate_wire));
+ log_assert(GetSize(gold_wire) == GetSize(gate_wire));
if (!gold_wire->port_output)
continue;
@@ -386,7 +396,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
log_error("Failed to eval %s in gate module.\n", log_id(gate_wire));
bool gold_gate_mismatch = false;
- for (int i = 0; i < SIZE(gold_wire); i++) {
+ for (int i = 0; i < GetSize(gold_wire); i++) {
if (gold_outval[i] == RTLIL::Sx)
continue;
if (gold_outval[i] == gate_outval[i])
@@ -406,9 +416,9 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
if (vlog_file.is_open()) {
vlog_file << stringf(" $display(\"[%s] %s expected: %%b, expr: %%b, noexpr: %%b\", %d'b%s, %s_expr, %s_noexpr);\n",
- vlog_pattern_info.c_str(), log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
- vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
- vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), SIZE(gold_outval), gold_outval.as_string().c_str());
+ vlog_pattern_info.c_str(), log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str(), log_id(gold_wire), log_id(gold_wire));
+ vlog_file << stringf(" if (%s_expr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str());
+ vlog_file << stringf(" if (%s_noexpr !== %d'b%s) begin $display(\"ERROR\"); $finish; end\n", log_id(gold_wire), GetSize(gold_outval), gold_outval.as_string().c_str());
}
}
@@ -423,17 +433,17 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
std::vector<int> sat1_model = satgen1.importSigSpec(out_sig);
std::vector<bool> sat1_model_value;
- if (!ez1.solve(sat1_model, sat1_model_value, ez1.vec_eq(sat1_in_sig, sat1_in_val)))
+ if (!ez1->solve(sat1_model, sat1_model_value, ez1->vec_eq(sat1_in_sig, sat1_in_val)))
log_error("Evaluating sat model 1 (no undef modeling) failed!\n");
if (verbose) {
log("SAT 1: ");
- for (int i = SIZE(out_sig)-1; i >= 0; i--)
+ for (int i = GetSize(out_sig)-1; i >= 0; i--)
log("%c", sat1_model_value.at(i) ? '1' : '0');
log("\n");
}
- for (int i = 0; i < SIZE(out_sig); i++) {
+ for (int i = 0; i < GetSize(out_sig); i++) {
if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
continue;
if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false)
@@ -458,18 +468,18 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::
std::vector<bool> sat2_model_value;
- if (!ez2.solve(sat2_model, sat2_model_value, ez2.vec_eq(sat2_in_def_sig, sat2_in_def_val), ez2.vec_eq(sat2_in_undef_sig, sat2_in_undef_val)))
+ if (!ez2->solve(sat2_model, sat2_model_value, ez2->vec_eq(sat2_in_def_sig, sat2_in_def_val), ez2->vec_eq(sat2_in_undef_sig, sat2_in_undef_val)))
log_error("Evaluating sat model 2 (undef modeling) failed!\n");
if (verbose) {
log("SAT 2: ");
- for (int i = SIZE(out_sig)-1; i >= 0; i--)
- log("%c", sat2_model_value.at(SIZE(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
+ for (int i = GetSize(out_sig)-1; i >= 0; i--)
+ log("%c", sat2_model_value.at(GetSize(out_sig) + i) ? 'x' : sat2_model_value.at(i) ? '1' : '0');
log("\n");
}
- for (int i = 0; i < SIZE(out_sig); i++) {
- if (sat2_model_value.at(SIZE(out_sig) + i)) {
+ for (int i = 0; i < GetSize(out_sig); i++) {
+ if (sat2_model_value.at(GetSize(out_sig) + i)) {
if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
continue;
} else {
@@ -505,7 +515,7 @@ struct TestCellPass : public Pass {
log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n");
log("\n");
log("Run with 'all' instead of a cell type to run the test on all supported\n");
- log("cell types.\n");
+ log("cell types. Use for example 'all /$add' for all cell types except $add.\n");
log("\n");
log(" -n {integer}\n");
log(" create this number of cell instances and test them (default = 100).\n");
@@ -516,12 +526,20 @@ struct TestCellPass : public Pass {
log(" -f {ilang_file}\n");
log(" don't generate circuits. instead load the specified ilang file.\n");
log("\n");
+ log(" -w {filename_prefix}\n");
+ log(" don't test anything. just generate the circuits and write them\n");
+ log(" to ilang files with the specified prefix\n");
+ log("\n");
log(" -map {filename}\n");
log(" pass this option to techmap.\n");
log("\n");
- log(" -simplib\n");
+ log(" -simlib\n");
log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
log("\n");
+ log(" -muxdiv\n");
+ log(" when creating test benches with dividers, create an additional mux\n");
+ log(" to mask out the division-by-zero case\n");
+ log("\n");
log(" -script {script_file}\n");
log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
log("\n");
@@ -542,34 +560,39 @@ struct TestCellPass : public Pass {
{
int num_iter = 100;
std::string techmap_cmd = "techmap -assert";
- std::string ilang_file;
+ std::string ilang_file, write_prefix;
xorshift32_state = 0;
std::ofstream vlog_file;
+ bool muxdiv = false;
bool verbose = false;
bool constmode = false;
bool nosat = false;
int argidx;
- for (argidx = 1; argidx < SIZE(args); argidx++)
+ for (argidx = 1; argidx < GetSize(args); argidx++)
{
- if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-n" && argidx+1 < GetSize(args)) {
num_iter = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-s" && argidx+1 < GetSize(args)) {
xorshift32_state = atoi(args[++argidx].c_str());
continue;
}
- if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-map" && argidx+1 < GetSize(args)) {
techmap_cmd += " -map " + args[++argidx];
continue;
}
- if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-f" && argidx+1 < GetSize(args)) {
ilang_file = args[++argidx];
num_iter = 1;
continue;
}
- if (args[argidx] == "-script" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-w" && argidx+1 < GetSize(args)) {
+ write_prefix = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-script" && argidx+1 < GetSize(args)) {
techmap_cmd = "script " + args[++argidx];
continue;
}
@@ -577,6 +600,10 @@ struct TestCellPass : public Pass {
techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
continue;
}
+ if (args[argidx] == "-muxdiv") {
+ muxdiv = true;
+ continue;
+ }
if (args[argidx] == "-const") {
constmode = true;
continue;
@@ -589,7 +616,7 @@ struct TestCellPass : public Pass {
verbose = true;
continue;
}
- if (args[argidx] == "-vlog" && argidx+1 < SIZE(args)) {
+ if (args[argidx] == "-vlog" && argidx+1 < GetSize(args)) {
vlog_file.open(args[++argidx], std::ios_base::trunc);
if (!vlog_file.is_open())
log_cmd_error("Failed to open output file `%s'.\n", args[argidx].c_str());
@@ -660,7 +687,7 @@ struct TestCellPass : public Pass {
cell_types["$macc"] = "*";
cell_types["$fa"] = "*";
- for (; argidx < SIZE(args); argidx++)
+ for (; argidx < GetSize(args); argidx++)
{
if (args[argidx].rfind("-", 0) == 0)
log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
@@ -672,6 +699,15 @@ struct TestCellPass : public Pass {
continue;
}
+ if (args[argidx].substr(0, 1) == "/") {
+ std::vector<std::string> new_selected_cell_types;
+ for (auto it : selected_cell_types)
+ if (it != args[argidx].substr(1))
+ new_selected_cell_types.push_back(it);
+ new_selected_cell_types.swap(selected_cell_types);
+ continue;
+ }
+
if (cell_types.count(args[argidx]) == 0) {
std::string cell_type_list;
int charcount = 100;
@@ -681,7 +717,7 @@ struct TestCellPass : public Pass {
charcount = 0;
} else
cell_type_list += " " + it.first;
- charcount += SIZE(it.first);
+ charcount += GetSize(it.first);
}
log_cmd_error("The cell type `%s' is currently not supported. Try one of these:%s\n",
args[argidx].c_str(), cell_type_list.c_str());
@@ -709,24 +745,28 @@ struct TestCellPass : public Pass {
if (cell_type == "ilang")
Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file);
else
- create_gold_module(design, cell_type, cell_types.at(cell_type), constmode);
- Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
- if (!nosat)
- Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
- if (verbose)
- Pass::call(design, "dump gate");
- Pass::call(design, "dump gold");
- if (!nosat)
- Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
- std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
- if (vlog_file.is_open()) {
- Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
- Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
- Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
- Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
- uut_names.push_back(uut_name);
+ create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
+ if (!write_prefix.empty()) {
+ Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i));
+ } else {
+ Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str()));
+ if (!nosat)
+ Pass::call(design, "miter -equiv -flatten -make_outputs -ignore_gold_x gold gate miter");
+ if (verbose)
+ Pass::call(design, "dump gate");
+ Pass::call(design, "dump gold");
+ if (!nosat)
+ Pass::call(design, "sat -verify -enable_undef -prove trigger 0 -show-inputs -show-outputs miter");
+ std::string uut_name = stringf("uut_%s_%d", cell_type.substr(1).c_str(), i);
+ if (vlog_file.is_open()) {
+ Pass::call(design, stringf("copy gold %s_expr; select %s_expr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected");
+ Pass::call(design, stringf("copy gold %s_noexpr; select %s_noexpr", uut_name.c_str(), uut_name.c_str()));
+ Backend::backend_call(design, &vlog_file, "<test_cell -vlog>", "verilog -selected -noexpr");
+ uut_names.push_back(uut_name);
+ }
+ run_eval_test(design, verbose, nosat, uut_name, vlog_file);
}
- run_eval_test(design, verbose, nosat, uut_name, vlog_file);
delete design;
}
@@ -743,3 +783,4 @@ struct TestCellPass : public Pass {
}
} TestCellPass;
+PRIVATE_NAMESPACE_END