aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
authorAhmed Irfan <ahmedirfan1983@gmail.com>2014-09-22 11:35:04 +0200
committerAhmed Irfan <ahmedirfan1983@gmail.com>2014-09-22 11:35:04 +0200
commitd3c67ad9b61f602de1100cd264efd227dcacb417 (patch)
tree88c462c53bdab128cd1edbded42483772f82612a /passes
parentb783dbe148e6d246ebd107c0913de2989ab5af48 (diff)
parent13117bb346dd02d2345f716b4403239aebe3d0e2 (diff)
downloadyosys-d3c67ad9b61f602de1100cd264efd227dcacb417.tar.gz
yosys-d3c67ad9b61f602de1100cd264efd227dcacb417.tar.bz2
yosys-d3c67ad9b61f602de1100cd264efd227dcacb417.zip
Merge branch 'master' of https://github.com/cliffordwolf/yosys into btor
added case for memwr cell that is used in muxes (same cell is used more than one time) corrected bug for xnor and logic_not added pmux cell translation Conflicts: backends/btor/btor.cc
Diffstat (limited to 'passes')
-rw-r--r--passes/abc/abc.cc655
-rw-r--r--passes/abc/blifparse.cc82
-rw-r--r--passes/cmds/Makefile.inc6
-rw-r--r--passes/cmds/add.cc23
-rw-r--r--passes/cmds/connect.cc18
-rw-r--r--passes/cmds/connwrappers.cc205
-rw-r--r--passes/cmds/copy.cc9
-rw-r--r--passes/cmds/cover.cc144
-rw-r--r--passes/cmds/delete.cc61
-rw-r--r--passes/cmds/design.cc82
-rw-r--r--passes/cmds/plugin.cc124
-rw-r--r--passes/cmds/rename.cc65
-rw-r--r--passes/cmds/scatter.cc15
-rw-r--r--passes/cmds/scc.cc18
-rw-r--r--passes/cmds/select.cc198
-rw-r--r--passes/cmds/setattr.cc10
-rw-r--r--passes/cmds/setundef.cc70
-rw-r--r--passes/cmds/show.cc139
-rw-r--r--passes/cmds/splice.cc78
-rw-r--r--passes/cmds/splitnets.cc59
-rw-r--r--passes/cmds/stat.cc49
-rw-r--r--passes/cmds/tee.cc88
-rw-r--r--passes/cmds/trace.cc97
-rw-r--r--passes/cmds/write_file.cc76
-rw-r--r--passes/fsm/fsm.cc6
-rw-r--r--passes/fsm/fsm_detect.cc34
-rw-r--r--passes/fsm/fsm_expand.cc104
-rw-r--r--passes/fsm/fsm_export.cc14
-rw-r--r--passes/fsm/fsm_extract.cc249
-rw-r--r--passes/fsm/fsm_info.cc4
-rw-r--r--passes/fsm/fsm_map.cc304
-rw-r--r--passes/fsm/fsm_opt.cc94
-rw-r--r--passes/fsm/fsm_recode.cc36
-rw-r--r--passes/fsm/fsmdata.h22
-rw-r--r--passes/hierarchy/hierarchy.cc166
-rw-r--r--passes/hierarchy/submod.cc105
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc6
-rw-r--r--passes/memory/memory_collect.cc102
-rw-r--r--passes/memory/memory_dff.cc125
-rw-r--r--passes/memory/memory_map.cc513
-rw-r--r--passes/memory/memory_share.cc744
-rw-r--r--passes/memory/memory_unpack.cc40
-rw-r--r--passes/opt/Makefile.inc2
-rw-r--r--passes/opt/opt.cc88
-rw-r--r--passes/opt/opt_clean.cc127
-rw-r--r--passes/opt/opt_const.cc753
-rw-r--r--passes/opt/opt_muxtree.cc93
-rw-r--r--passes/opt/opt_reduce.cc258
-rw-r--r--passes/opt/opt_rmdff.cc84
-rw-r--r--passes/opt/opt_share.cc52
-rw-r--r--passes/opt/opt_status.h26
-rw-r--r--passes/opt/share.cc1171
-rw-r--r--passes/opt/wreduce.cc350
-rw-r--r--passes/proc/proc_arst.cc97
-rw-r--r--passes/proc/proc_clean.cc27
-rw-r--r--passes/proc/proc_dff.cc263
-rw-r--r--passes/proc/proc_init.cc33
-rw-r--r--passes/proc/proc_mux.cc132
-rw-r--r--passes/proc/proc_rmdead.cc13
-rw-r--r--passes/sat/eval.cc115
-rw-r--r--passes/sat/example.ys7
-rw-r--r--passes/sat/expose.cc238
-rw-r--r--passes/sat/freduce.cc133
-rw-r--r--passes/sat/miter.cc200
-rw-r--r--passes/sat/sat.cc313
-rw-r--r--passes/techmap/.gitignore2
-rw-r--r--passes/techmap/Makefile.inc24
-rw-r--r--passes/techmap/alumacc.cc563
-rw-r--r--passes/techmap/dfflibmap.cc60
-rw-r--r--passes/techmap/extract.cc285
-rw-r--r--passes/techmap/hilomap.cc42
-rw-r--r--passes/techmap/iopadmap.cc67
-rw-r--r--passes/techmap/libparse.cc45
-rw-r--r--passes/techmap/libparse.h4
-rw-r--r--passes/techmap/maccmap.cc394
-rw-r--r--passes/techmap/simplemap.cc423
-rw-r--r--passes/techmap/techmap.cc1104
-rw-r--r--passes/tests/Makefile.inc5
-rw-r--r--passes/tests/test_abcloop.cc285
-rw-r--r--passes/tests/test_autotb.cc353
-rw-r--r--passes/tests/test_cell.cc745
82 files changed, 10525 insertions, 3491 deletions
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc
index 5aa13572e..f1d56b23a 100644
--- a/passes/abc/abc.cc
+++ b/passes/abc/abc.cc
@@ -29,65 +29,88 @@
// 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; retime; balance; dch; map; topo"
-#define ABC_COMMAND_CTR "strash; retime; balance; dch; map; topo; buffer; upsize; dnsize; stime"
-#define ABC_COMMAND_LUT "strash; retime; balance; dch; if"
-#define ABC_COMMAND_DFL "strash; retime; balance; dch; map"
+#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_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"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <unistd.h>
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
+#include <cerrno>
#include <sstream>
+#include <climits>
#include "blifparse.h"
+enum class gate_type_t {
+ G_NONE,
+ G_FF,
+ G_NOT,
+ G_AND,
+ G_NAND,
+ G_OR,
+ G_NOR,
+ G_XOR,
+ G_XNOR,
+ G_MUX,
+ G_AOI3,
+ G_OAI3,
+ G_AOI4,
+ G_OAI4
+};
+
+#define G(_name) gate_type_t::G_ ## _name
+
struct gate_t
{
int id;
- char type;
- int in1, in2, in3;
+ gate_type_t type;
+ int in1, in2, in3, in4;
bool is_port;
- RTLIL::SigSpec sig;
+ 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::SigSpec, int> signal_map;
+static std::map<RTLIL::SigBit, int> signal_map;
static bool clk_polarity;
static RTLIL::SigSpec clk_sig;
-static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int in2 = -1, int in3 = -1)
+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)
{
- assert(sig.width == 1);
- assert(sig.chunks.size() == 1);
+ assign_map.apply(bit);
- assign_map.apply(sig);
-
- if (signal_map.count(sig) == 0) {
+ if (signal_map.count(bit) == 0) {
gate_t gate;
gate.id = signal_list.size();
- gate.type = -1;
+ gate.type = G(NONE);
gate.in1 = -1;
gate.in2 = -1;
gate.in3 = -1;
+ gate.in4 = -1;
gate.is_port = false;
- gate.sig = sig;
+ gate.bit = bit;
signal_list.push_back(gate);
- signal_map[sig] = gate.id;
+ signal_map[bit] = gate.id;
}
- gate_t &gate = signal_list[signal_map[sig]];
+ gate_t &gate = signal_list[signal_map[bit]];
- if (gate_type >= 0)
+ if (gate_type != G(NONE))
gate.type = gate_type;
if (in1 >= 0)
gate.in1 = in1;
@@ -95,62 +118,64 @@ static int map_signal(RTLIL::SigSpec sig, char gate_type = -1, int in1 = -1, int
gate.in2 = in2;
if (in3 >= 0)
gate.in3 = in3;
+ if (in4 >= 0)
+ gate.in4 = in4;
return gate.id;
}
static void mark_port(RTLIL::SigSpec sig)
{
- assign_map.apply(sig);
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire != NULL && signal_map.count(c) > 0)
- signal_list[signal_map[c]].is_port = true;
- }
+ 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)
+static void extract_cell(RTLIL::Cell *cell, bool keepff)
{
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
if (clk_polarity != (cell->type == "$_DFF_P_"))
return;
- if (clk_sig != assign_map(cell->connections["\\C"]))
+ if (clk_sig != assign_map(cell->getPort("\\C")))
return;
- RTLIL::SigSpec sig_d = cell->connections["\\D"];
- RTLIL::SigSpec sig_q = cell->connections["\\Q"];
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
+
+ if (keepff)
+ for (auto &c : sig_q.chunks())
+ if (c.wire != NULL)
+ c.wire->attributes["\\keep"] = 1;
assign_map.apply(sig_d);
assign_map.apply(sig_q);
- map_signal(sig_q, 'f', map_signal(sig_d));
+ map_signal(sig_q, G(FF), map_signal(sig_d));
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
- if (cell->type == "$_INV_")
+ if (cell->type == "$_NOT_")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_y);
- map_signal(sig_y, 'n', map_signal(sig_a));
+ map_signal(sig_y, G(NOT), map_signal(sig_a));
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
- if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_")
+ if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -160,25 +185,30 @@ static void extract_cell(RTLIL::Cell *cell)
int mapped_b = map_signal(sig_b);
if (cell->type == "$_AND_")
- map_signal(sig_y, 'a', mapped_a, mapped_b);
+ map_signal(sig_y, G(AND), mapped_a, mapped_b);
+ else if (cell->type == "$_NAND_")
+ map_signal(sig_y, G(NAND), mapped_a, mapped_b);
else if (cell->type == "$_OR_")
- map_signal(sig_y, 'o', mapped_a, mapped_b);
+ map_signal(sig_y, G(OR), mapped_a, mapped_b);
+ else if (cell->type == "$_NOR_")
+ map_signal(sig_y, G(NOR), mapped_a, mapped_b);
else if (cell->type == "$_XOR_")
- map_signal(sig_y, 'x', mapped_a, mapped_b);
+ map_signal(sig_y, G(XOR), mapped_a, mapped_b);
+ else if (cell->type == "$_XNOR_")
+ map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
else
log_abort();
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
if (cell->type == "$_MUX_")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_s = cell->connections["\\S"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
assign_map.apply(sig_a);
assign_map.apply(sig_b);
@@ -189,15 +219,61 @@ static void extract_cell(RTLIL::Cell *cell)
int mapped_b = map_signal(sig_b);
int mapped_s = map_signal(sig_s);
- map_signal(sig_y, 'm', mapped_a, mapped_b, mapped_s);
+ map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s);
+
+ module->remove(cell);
+ return;
+ }
+
+ if (cell->type.in("$_AOI3_", "$_OAI3_"))
+ {
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_c = cell->getPort("\\C");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ assign_map.apply(sig_a);
+ assign_map.apply(sig_b);
+ assign_map.apply(sig_c);
+ assign_map.apply(sig_y);
+
+ int mapped_a = map_signal(sig_a);
+ int mapped_b = map_signal(sig_b);
+ int mapped_c = map_signal(sig_c);
+
+ map_signal(sig_y, cell->type == "$_AOI3_" ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c);
+
+ module->remove(cell);
+ return;
+ }
+
+ if (cell->type.in("$_AOI4_", "$_OAI4_"))
+ {
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_c = cell->getPort("\\C");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+
+ assign_map.apply(sig_a);
+ assign_map.apply(sig_b);
+ assign_map.apply(sig_c);
+ assign_map.apply(sig_d);
+ assign_map.apply(sig_y);
+
+ int mapped_a = map_signal(sig_a);
+ int mapped_b = map_signal(sig_b);
+ int mapped_c = map_signal(sig_c);
+ int mapped_d = map_signal(sig_d);
+
+ map_signal(sig_y, cell->type == "$_AOI4_" ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d);
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
return;
}
}
-static std::string remap_name(std::string abc_name)
+static std::string remap_name(RTLIL::IdString abc_name)
{
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
@@ -211,8 +287,9 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
log("Dumping loop state graph to slide %d.\n", ++nr);
- fprintf(f, "digraph slide%d {\n", nr);
- fprintf(f, " rankdir=\"LR\";\n");
+ fprintf(f, "digraph \"slide%d\" {\n", nr);
+ fprintf(f, " label=\"slide%d\";\n", nr);
+ fprintf(f, " rankdir=\"TD\";\n");
std::set<int> nodes;
for (auto &e : edges) {
@@ -222,7 +299,7 @@ static void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edge
}
for (auto n : nodes)
- fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].sig),
+ fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit),
n, in_counts[n], workpool.count(n) ? ", shape=box" : "");
for (auto &e : edges)
@@ -248,7 +325,7 @@ static void handle_loops()
// dot_f = fopen("test.dot", "w");
for (auto &g : signal_list) {
- if (g.type == -1 || g.type == 'f') {
+ if (g.type == G(NONE) || g.type == G(FF)) {
workpool.insert(g.id);
} else {
if (g.in1 >= 0) {
@@ -263,6 +340,10 @@ static void handle_loops()
edges[g.in3].insert(g.id);
in_edges_count[g.id]++;
}
+ if (g.in4 >= 0 && g.in4 != g.in3 && g.in4 != g.in2 && g.in4 != g.in1) {
+ edges[g.in4].insert(g.id);
+ in_edges_count[g.id]++;
+ }
}
}
@@ -273,10 +354,10 @@ static void handle_loops()
int id = *workpool.begin();
workpool.erase(id);
- // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].sig));
+ // log("Removing non-loop node %d from graph: %s\n", id, log_signal(signal_list[id].bit));
for (int id2 : edges[id]) {
- assert(in_edges_count[id2] > 0);
+ log_assert(in_edges_count[id2] > 0);
if (--in_edges_count[id2] == 0)
workpool.insert(id2);
}
@@ -293,12 +374,12 @@ static void handle_loops()
for (auto &edge_it : edges) {
int id2 = edge_it.first;
- RTLIL::Wire *w1 = signal_list[id1].sig.chunks[0].wire;
- RTLIL::Wire *w2 = signal_list[id2].sig.chunks[0].wire;
- if (w1 != NULL)
- continue;
- else if (w2 == NULL)
+ RTLIL::Wire *w1 = signal_list[id1].bit.wire;
+ RTLIL::Wire *w2 = signal_list[id2].bit.wire;
+ if (w1 == NULL)
id1 = id2;
+ else if (w2 == NULL)
+ continue;
else if (w1->name[0] == '$' && w2->name[0] == '\\')
id1 = id2;
else if (w1->name[0] == '\\' && w2->name[0] == '$')
@@ -307,7 +388,7 @@ static void handle_loops()
id1 = id2;
else if (edges[id1].size() > edges[id2].size())
continue;
- else if (w1->name > w2->name)
+ else if (w2->name.str() < w1->name.str())
id1 = id2;
}
@@ -316,27 +397,27 @@ static void handle_loops()
continue;
}
- RTLIL::Wire *wire = new RTLIL::Wire;
+ log_assert(signal_list[id1].bit.wire != NULL);
+
std::stringstream sstr;
- sstr << "$abcloop$" << (RTLIL::autoidx++);
- wire->name = sstr.str();
- module->wires[wire->name] = wire;
+ sstr << "$abcloop$" << (autoidx++);
+ RTLIL::Wire *wire = module->addWire(sstr.str());
bool first_line = true;
for (int id2 : edges[id1]) {
if (first_line)
log("Breaking loop using new signal %s: %s -> %s\n", log_signal(RTLIL::SigSpec(wire)),
- log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+ log_signal(signal_list[id1].bit), log_signal(signal_list[id2].bit));
else
log(" %*s %s -> %s\n", int(strlen(log_signal(RTLIL::SigSpec(wire)))), "",
- log_signal(signal_list[id1].sig), log_signal(signal_list[id2].sig));
+ log_signal(signal_list[id1].bit), log_signal(signal_list[id2].bit));
first_line = false;
}
int id3 = map_signal(RTLIL::SigSpec(wire));
signal_list[id1].is_port = true;
signal_list[id3].is_port = true;
- assert(id3 == int(in_edges_count.size()));
+ log_assert(id3 == int(in_edges_count.size()));
in_edges_count.push_back(0);
workpool.insert(id3);
@@ -347,10 +428,12 @@ static void handle_loops()
signal_list[id2].in2 = id3;
if (signal_list[id2].in3 == id1)
signal_list[id2].in3 = id3;
+ if (signal_list[id2].in4 == id1)
+ signal_list[id2].in4 = id3;
}
edges[id1].swap(edges[id3]);
- module->connections.push_back(RTLIL::SigSig(signal_list[id3].sig, signal_list[id1].sig));
+ module->connect(RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit));
dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count);
}
}
@@ -359,11 +442,55 @@ static void handle_loops()
fclose(dot_f);
}
+static std::string add_echos_to_abc_cmd(std::string str)
+{
+ std::string new_str, token;
+ for (size_t i = 0; i < str.size(); i++) {
+ token += str[i];
+ 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();
+ }
+ }
+
+ if (!token.empty()) {
+ if (!new_str.empty())
+ new_str += "echo; echo + " + token + "; ";
+ new_str += token;
+ }
+
+ return new_str;
+}
+
+static std::string fold_abc_cmd(std::string str)
+{
+ std::string token, new_str = " ";
+ int char_counter = 10;
+
+ for (size_t i = 0; i <= str.size(); i++) {
+ if (i < str.size())
+ token += str[i];
+ if (i == str.size() || str[i] == ';') {
+ if (char_counter + token.size() > 75)
+ new_str += "\n ", char_counter = 14;
+ new_str += token, char_counter += token.size();
+ token.clear();
+ }
+ }
+
+ 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)
+ 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)
{
module = current_module;
- map_autoidx = RTLIL::autoidx++;
+ map_autoidx = autoidx++;
signal_map.clear();
signal_list.clear();
@@ -393,33 +520,48 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
} else
abc_command = stringf("source %s", script_file.c_str());
} else if (lut_mode)
- abc_command = ABC_COMMAND_LUT;
+ abc_command = fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
else if (!liberty_file.empty())
- abc_command = constr_file.empty() ? ABC_COMMAND_LIB : ABC_COMMAND_CTR;
+ abc_command = constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else
- abc_command = ABC_COMMAND_DFL;
+ abc_command = 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);
+
+ abc_command = add_echos_to_abc_cmd(abc_command);
+
+ 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);
+ }
if (clk_str.empty()) {
if (clk_str[0] == '!') {
clk_polarity = false;
clk_str = clk_str.substr(1);
}
- if (module->wires.count(RTLIL::escape_id(clk_str)) != 0)
- clk_sig = assign_map(RTLIL::SigSpec(module->wires.at(RTLIL::escape_id(clk_str)), 1));
+ if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+ clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
}
- if (dff_mode && clk_sig.width == 0)
+ if (dff_mode && clk_sig.size() == 0)
{
int best_dff_counter = 0;
std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters;
- for (auto &it : module->cells)
+ 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->connections.at("\\C")));
+ 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;
@@ -429,30 +571,30 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
if (dff_mode || !clk_str.empty()) {
- if (clk_sig.width == 0)
+ 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));
}
- if (clk_sig.width != 0)
+ if (clk_sig.size() != 0)
mark_port(clk_sig);
std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &it : module->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);
+ extract_cell(c, keepff);
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute("\\keep"))
mark_port(RTLIL::SigSpec(wire_it.second));
}
- for (auto &cell_it : module->cells)
- for (auto &port_it : cell_it.second->connections)
+ for (auto &cell_it : module->cells_)
+ for (auto &port_it : cell_it.second->connections())
mark_port(port_it.second);
handle_loops();
@@ -468,17 +610,19 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
int count_input = 0;
fprintf(f, ".inputs");
for (auto &si : signal_list) {
- if (!si.is_port || si.type >= 0)
+ if (!si.is_port || si.type != G(NONE))
continue;
fprintf(f, " n%d", si.id);
count_input++;
}
+ if (count_input == 0)
+ fprintf(f, " dummy_input\n");
fprintf(f, "\n");
int count_output = 0;
fprintf(f, ".outputs");
for (auto &si : signal_list) {
- if (!si.is_port || si.type < 0)
+ if (!si.is_port || si.type == G(NONE))
continue;
fprintf(f, " n%d", si.id);
count_output++;
@@ -486,42 +630,70 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
fprintf(f, "\n");
for (auto &si : signal_list)
- fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.sig));
+ fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit));
for (auto &si : signal_list) {
- assert(si.sig.width == 1 && si.sig.chunks.size() == 1);
- if (si.sig.chunks[0].wire == NULL) {
+ if (si.bit.wire == NULL) {
fprintf(f, ".names n%d\n", si.id);
- if (si.sig.chunks[0].data.bits[0] == RTLIL::State::S1)
+ if (si.bit == RTLIL::State::S1)
fprintf(f, "1\n");
}
}
int count_gates = 0;
for (auto &si : signal_list) {
- if (si.type == 'n') {
+ 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 == 'a') {
+ } else if (si.type == G(AND)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "11 1\n");
- } else if (si.type == 'o') {
+ } else if (si.type == G(NAND)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "0- 1\n");
+ fprintf(f, "-0 1\n");
+ } else if (si.type == G(OR)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "-1 1\n");
fprintf(f, "1- 1\n");
- } else if (si.type == 'x') {
+ } else if (si.type == G(NOR)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "00 1\n");
+ } else if (si.type == G(XOR)) {
fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
fprintf(f, "01 1\n");
fprintf(f, "10 1\n");
- } else if (si.type == 'm') {
+ } else if (si.type == G(XNOR)) {
+ fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+ fprintf(f, "00 1\n");
+ fprintf(f, "11 1\n");
+ } else if (si.type == G(MUX)) {
fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
fprintf(f, "1-0 1\n");
fprintf(f, "-11 1\n");
- } else if (si.type == 'f') {
+ } else if (si.type == G(AOI3)) {
+ fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, "-00 1\n");
+ fprintf(f, "0-0 1\n");
+ } else if (si.type == G(OAI3)) {
+ fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
+ fprintf(f, "00- 1\n");
+ fprintf(f, "--0 1\n");
+ } else if (si.type == G(AOI4)) {
+ fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, "-0-0 1\n");
+ fprintf(f, "-00- 1\n");
+ fprintf(f, "0--0 1\n");
+ fprintf(f, "0-0- 1\n");
+ } else if (si.type == G(OAI4)) {
+ fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id);
+ fprintf(f, "00-- 1\n");
+ fprintf(f, "--00 1\n");
+ } else if (si.type == G(FF)) {
fprintf(f, ".latch n%d n%d\n", si.in1, si.id);
- } else if (si.type >= 0)
+ } else if (si.type != G(NONE))
log_abort();
- if (si.type >= 0)
+ if (si.type != G(NONE))
count_gates++;
}
@@ -543,11 +715,18 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
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 INV 1 Y=!A; PIN * INV 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");
fclose(f);
free(p);
@@ -564,10 +743,10 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
std::string buffer;
if (!liberty_file.empty()) {
- buffer += stringf("%s -s -c 'read_blif %s/input.blif; read_lib %s; ",
+ 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 %s; ", constr_file.c_str());
+ buffer += stringf("read_constr -v %s; ", constr_file.c_str());
buffer += abc_command + "; ";
} else
if (lut_mode)
@@ -578,13 +757,53 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
exe_file.c_str(), tempdir_name, tempdir_name, abc_command.c_str());
buffer += stringf("write_blif %s/output.blif' 2>&1", tempdir_name);
+ log("%s\n", buffer.c_str());
+
errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
f = popen(buffer.c_str(), "r");
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)
@@ -609,79 +828,84 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
free(p);
log_header("Re-integrating ABC results.\n");
- RTLIL::Module *mapped_mod = mapped_design->modules["\\netlist"];
+ RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `netlist'.\n");
- for (auto &it : mapped_mod->wires) {
+ for (auto &it : mapped_mod->wires_) {
RTLIL::Wire *w = it.second;
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = remap_name(w->name);
- module->wires[wire->name] = wire;
+ RTLIL::Wire *wire = module->addWire(remap_name(w->name));
design->select(module, wire);
}
std::map<std::string, int> cell_stats;
if (builtin_lib)
{
- for (auto &it : mapped_mod->cells) {
+ for (auto &it : mapped_mod->cells_) {
RTLIL::Cell *c = it.second;
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\ZERO" || c->type == "\\ONE") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1);
- module->connections.push_back(conn);
+ module->connect(conn);
continue;
}
if (c->type == "\\BUF") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- conn.second = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- module->connections.push_back(conn);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]);
+ module->connect(conn);
continue;
}
- if (c->type == "\\INV") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_INV_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ if (c->type == "\\NOT") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
+ 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);
continue;
}
- if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_" + c->type.substr(1) + "_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ 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) + "_");
+ 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)]));
design->select(module, cell);
continue;
}
if (c->type == "\\MUX") {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = "$_MUX_";
- cell->name = remap_name(c->name);
- cell->connections["\\A"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\A"].chunks[0].wire->name)]);
- cell->connections["\\B"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\B"].chunks[0].wire->name)]);
- cell->connections["\\S"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\S"].chunks[0].wire->name)]);
- cell->connections["\\Y"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Y"].chunks[0].wire->name)]);
- module->cells[cell->name] = cell;
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
+ 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)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ design->select(module, cell);
+ continue;
+ }
+ if (c->type == "\\AOI3" || c->type == "\\OAI3") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ 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)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
+ design->select(module, cell);
+ continue;
+ }
+ if (c->type == "\\AOI4" || c->type == "\\OAI4") {
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
+ 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)]));
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
design->select(module, cell);
continue;
}
if (c->type == "\\DFF") {
- log_assert(clk_sig.width == 1);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = clk_polarity ? "$_DFF_P_" : "$_DFF_N_";
- cell->name = remap_name(c->name);
- cell->connections["\\D"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\D"].chunks[0].wire->name)]);
- cell->connections["\\Q"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Q"].chunks[0].wire->name)]);
- cell->connections["\\C"] = clk_sig;
- module->cells[cell->name] = cell;
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ 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);
design->select(module, cell);
continue;
}
@@ -690,54 +914,48 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
}
else
{
- for (auto &it : mapped_mod->cells)
+ for (auto &it : mapped_mod->cells_)
{
RTLIL::Cell *c = it.second;
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\_const0_" || c->type == "\\_const1_") {
RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections.begin()->second.chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
- module->connections.push_back(conn);
+ module->connect(conn);
continue;
}
if (c->type == "\\_dff_") {
- log_assert(clk_sig.width == 1);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = clk_polarity ? "$_DFF_P_" : "$_DFF_N_";
- cell->name = remap_name(c->name);
- cell->connections["\\D"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\D"].chunks[0].wire->name)]);
- cell->connections["\\Q"] = RTLIL::SigSpec(module->wires[remap_name(c->connections["\\Q"].chunks[0].wire->name)]);
- cell->connections["\\C"] = clk_sig;
- module->cells[cell->name] = cell;
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ 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);
design->select(module, cell);
continue;
}
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->type = c->type;
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
cell->parameters = c->parameters;
- cell->name = remap_name(c->name);
- for (auto &conn : c->connections) {
+ for (auto &conn : c->connections()) {
RTLIL::SigSpec newsig;
- for (auto &c : conn.second.chunks) {
+ for (auto &c : conn.second.chunks()) {
if (c.width == 0)
continue;
- assert(c.width == 1);
- newsig.append(module->wires[remap_name(c.wire->name)]);
+ log_assert(c.width == 1);
+ newsig.append(module->wires_[remap_name(c.wire->name)]);
}
- cell->connections[conn.first] = newsig;
+ cell->setPort(conn.first, newsig);
}
- module->cells[cell->name] = cell;
design->select(module, cell);
}
}
- for (auto conn : mapped_mod->connections) {
+ for (auto conn : mapped_mod->connections()) {
if (!conn.first.is_fully_const())
- conn.first = RTLIL::SigSpec(module->wires[remap_name(conn.first.chunks[0].wire->name)]);
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(conn.first.as_wire()->name)]);
if (!conn.second.is_fully_const())
- conn.second = RTLIL::SigSpec(module->wires[remap_name(conn.second.chunks[0].wire->name)]);
- module->connections.push_back(conn);
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(conn.second.as_wire()->name)]);
+ module->connect(conn);
}
for (auto &it : cell_stats)
@@ -748,16 +966,16 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
char buffer[100];
snprintf(buffer, 100, "\\n%d", si.id);
RTLIL::SigSig conn;
- if (si.type >= 0) {
- conn.first = si.sig;
- conn.second = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
+ if (si.type != G(NONE)) {
+ conn.first = si.bit;
+ conn.second = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
out_wires++;
} else {
- conn.first = RTLIL::SigSpec(module->wires[remap_name(buffer)]);
- conn.second = si.sig;
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(buffer)]);
+ conn.second = si.bit;
in_wires++;
}
- module->connections.push_back(conn);
+ module->connect(conn);
}
log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
log("ABC RESULTS: input signals: %8d\n", in_wires);
@@ -776,7 +994,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std
struct dirent **namelist;
int n = scandir(tempdir_name, &namelist, 0, alphasort);
- assert(n >= 0);
+ 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();
@@ -820,16 +1038,32 @@ struct AbcPass : public Pass {
log(" if no -script parameter is given, the following scripts are used:\n");
log("\n");
log(" for -liberty without -constr:\n");
- log(" %s\n", ABC_COMMAND_LIB);
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
+ log("\n");
+ log(" for -liberty with -constr:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
+ log("\n");
+ log(" for -lut:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
+ log("\n");
+ log(" otherwise:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
+ log("\n");
+ log(" -fast\n");
+ log(" use different default scripts that are slightly faster (at the cost\n");
+ log(" of output quality):\n");
+ log("\n");
+ log(" for -liberty without -constr:\n");
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
log("\n");
log(" for -liberty with -constr:\n");
- log(" %s\n", ABC_COMMAND_CTR);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
log(" for -lut:\n");
- log(" %s\n", ABC_COMMAND_LUT);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n");
log(" otherwise:\n");
- log(" %s\n", ABC_COMMAND_DFL);
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
log("\n");
log(" -liberty <file>\n");
log(" generate netlists for the specified cell library (using the liberty\n");
@@ -838,6 +1072,18 @@ struct AbcPass : public Pass {
log(" -constr <file>\n");
log(" pass this file with timing constraints to ABC. use with -liberty.\n");
log("\n");
+ log(" a constr file contains two lines:\n");
+ log(" set_driving_cell <cell_name>\n");
+ log(" set_load <floating_point_number>\n");
+ log("\n");
+ log(" the set_driving_cell statement defines which cell type is assumed to\n");
+ log(" drive the primary inputs and the set_load statement sets the load in\n");
+ log(" femtofarads for each primary output.\n");
+ log("\n");
+ log(" -D <picoseconds>\n");
+ log(" set delay target. the string {D} in the default scripts above is\n");
+ log(" replaced by this option when used, and an empty string otherwise.\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -851,6 +1097,10 @@ struct AbcPass : public Pass {
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("\n");
+ log(" -keepff\n");
+ log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
+ log(" them, for example for equivialence checking.)\n");
+ log("\n");
log(" -nocleanup\n");
log(" when this option is used, the temporary files created by this pass\n");
log(" are not removed. this is useful for debugging.\n");
@@ -869,13 +1119,17 @@ struct AbcPass : public Pass {
log_header("Executing ABC pass (technology mapping using ABC).\n");
log_push();
- std::string exe_file = rewrite_yosys_exe("yosys-abc");
- std::string script_file, liberty_file, constr_file, clk_str;
- bool dff_mode = false, cleanup = true;
+ 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;
size_t argidx;
- char *pwd = get_current_dir_name();
+ char pwd [PATH_MAX];
+ if (!getcwd(pwd, sizeof(pwd))) {
+ log_cmd_error("getcwd failed: %s\n", strerror(errno));
+ log_abort();
+ }
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-exe" && argidx+1 < args.size()) {
@@ -900,10 +1154,18 @@ struct AbcPass : public Pass {
constr_file = std::string(pwd) + "/" + constr_file;
continue;
}
+ if (arg == "-D" && argidx+1 < args.size()) {
+ delay_target = "-D " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
lut_mode = atoi(args[++argidx].c_str());
continue;
}
+ if (arg == "-fast") {
+ fast_mode = true;
+ continue;
+ }
if (arg == "-dff") {
dff_mode = true;
continue;
@@ -912,13 +1174,16 @@ struct AbcPass : public Pass {
clk_str = args[++argidx];
continue;
}
+ if (arg == "-keepff") {
+ keepff = true;
+ continue;
+ }
if (arg == "-nocleanup") {
cleanup = false;
continue;
}
break;
}
- free(pwd);
extra_args(args, argidx, design);
if (lut_mode != 0 && !liberty_file.empty())
@@ -926,12 +1191,12 @@ 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)
+ 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);
+ 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);
}
assign_map.clear();
diff --git a/passes/abc/blifparse.cc b/passes/abc/blifparse.cc
index 2d46d1a8e..1fbb5720d 100644
--- a/passes/abc/blifparse.cc
+++ b/passes/abc/blifparse.cc
@@ -40,7 +40,7 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
}
if (buffer_len == 0 || buffer[buffer_len-1] == '\\') {
- if (buffer[buffer_len-1] == '\\')
+ if (buffer_len > 0 && buffer[buffer_len-1] == '\\')
buffer[--buffer_len] = 0;
line_count++;
if (fgets(buffer+buffer_len, buffer_size-buffer_len, f) == NULL)
@@ -58,9 +58,8 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
RTLIL::Const *lutptr = NULL;
RTLIL::State lut_default_state = RTLIL::State::Sx;
- int port_count = 0;
module->name = "\\netlist";
- design->modules[module->name] = module;
+ design->add(module);
size_t buffer_size = 4096;
char *buffer = (char*)malloc(buffer_size);
@@ -91,6 +90,7 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
continue;
if (!strcmp(cmd, ".end")) {
+ module->fixup_ports();
free(buffer);
return design;
}
@@ -98,14 +98,11 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) {
char *p;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = stringf("\\%s", p);
- wire->port_id = ++port_count;
+ RTLIL::Wire *wire = module->addWire(stringf("\\%s", p));
if (!strcmp(cmd, ".inputs"))
wire->port_input = true;
else
wire->port_output = true;
- module->add(wire);
}
continue;
}
@@ -115,49 +112,34 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
char *d = strtok(NULL, " \t\r\n");
char *q = strtok(NULL, " \t\r\n");
- if (module->wires.count(RTLIL::escape_id(d)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(d);
- module->add(wire);
- }
+ if (module->wires_.count(RTLIL::escape_id(d)) == 0)
+ module->addWire(RTLIL::escape_id(d));
- if (module->wires.count(RTLIL::escape_id(q)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(q);
- module->add(wire);
- }
+ if (module->wires_.count(RTLIL::escape_id(q)) == 0)
+ module->addWire(RTLIL::escape_id(q));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = dff_name;
- cell->connections["\\D"] = module->wires.at(RTLIL::escape_id(d));
- cell->connections["\\Q"] = module->wires.at(RTLIL::escape_id(q));
- module->add(cell);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, dff_name);
+ cell->setPort("\\D", module->wires_.at(RTLIL::escape_id(d)));
+ cell->setPort("\\Q", module->wires_.at(RTLIL::escape_id(q)));
continue;
}
if (!strcmp(cmd, ".gate"))
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- module->add(cell);
-
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
goto error;
- cell->type = RTLIL::escape_id(p);
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(p));
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
char *q = strchr(p, '=');
if (q == NULL || !q[0] || !q[1])
goto error;
*(q++) = 0;
- if (module->wires.count(RTLIL::escape_id(q)) == 0) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = RTLIL::escape_id(q);
- module->add(wire);
- }
- cell->connections[RTLIL::escape_id(p)] = module->wires.at(RTLIL::escape_id(q));
+ if (module->wires_.count(RTLIL::escape_id(q)) == 0)
+ module->addWire(RTLIL::escape_id(q));
+ cell->setPort(RTLIL::escape_id(p), module->wires_.at(RTLIL::escape_id(q)));
}
continue;
}
@@ -168,19 +150,17 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
RTLIL::SigSpec input_sig, output_sig;
while ((p = strtok(NULL, " \t\r\n")) != NULL) {
RTLIL::Wire *wire;
- if (module->wires.count(stringf("\\%s", p)) > 0) {
- wire = module->wires.at(stringf("\\%s", p));
+ if (module->wires_.count(stringf("\\%s", p)) > 0) {
+ wire = module->wires_.at(stringf("\\%s", p));
} else {
- wire = new RTLIL::Wire;
- wire->name = stringf("\\%s", p);
- module->add(wire);
+ wire = module->addWire(stringf("\\%s", p));
}
input_sig.append(wire);
}
- output_sig = input_sig.extract(input_sig.width-1, 1);
- input_sig = input_sig.extract(0, input_sig.width-1);
+ output_sig = input_sig.extract(input_sig.size()-1, 1);
+ input_sig = input_sig.extract(0, input_sig.size()-1);
- if (input_sig.width == 0) {
+ if (input_sig.size() == 0) {
RTLIL::State state = RTLIL::State::Sa;
while (1) {
if (!read_next_line(buffer, buffer_size, line_count, f))
@@ -208,23 +188,17 @@ RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name)
finished_parsing_constval:
if (state == RTLIL::State::Sa)
state = RTLIL::State::S1;
- module->connections.push_back(RTLIL::SigSig(output_sig, state));
+ module->connect(RTLIL::SigSig(output_sig, state));
goto continue_without_read;
}
- input_sig.optimize();
- output_sig.optimize();
-
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$lut";
- cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.width);
- cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.width);
- cell->connections["\\I"] = input_sig;
- cell->connections["\\O"] = output_sig;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
+ cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
+ cell->setPort("\\A", input_sig);
+ cell->setPort("\\Y", output_sig);
lutptr = &cell->parameters.at("\\LUT");
lut_default_state = RTLIL::State::Sx;
- module->add(cell);
continue;
}
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index f01a1c4b5..eba61d1df 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -15,4 +15,10 @@ OBJS += passes/cmds/copy.o
OBJS += passes/cmds/splice.o
OBJS += passes/cmds/scc.o
OBJS += passes/cmds/log.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
diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc
index acee4c46f..e3fde8559 100644
--- a/passes/cmds/add.cc
+++ b/passes/cmds/add.cc
@@ -28,8 +28,8 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
if (module->count_id(name) != 0)
{
- if (module->wires.count(name) > 0)
- wire = module->wires.at(name);
+ if (module->wires_.count(name) > 0)
+ wire = module->wires_.at(name);
if (wire != NULL && wire->width != width)
wire = NULL;
@@ -47,15 +47,12 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
}
else
{
- wire = new RTLIL::Wire;
- wire->name = name;
- wire->width = width;
+ wire = module->addWire(name, width);
wire->port_input = flag_input;
wire->port_output = flag_output;
- module->add(wire);
if (flag_input || flag_output) {
- wire->port_id = module->wires.size();
+ wire->port_id = module->wires_.size();
module->fixup_ports();
}
@@ -65,20 +62,20 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
if (!flag_global)
return;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
- if (design->modules.count(it.second->type) == 0)
+ if (design->modules_.count(it.second->type) == 0)
continue;
- RTLIL::Module *mod = design->modules.at(it.second->type);
+ RTLIL::Module *mod = design->modules_.at(it.second->type);
if (!design->selected_whole_module(mod->name))
continue;
if (mod->get_bool_attribute("\\blackbox"))
continue;
- if (it.second->connections.count(name) > 0)
+ if (it.second->hasPort(name))
continue;
- it.second->connections[name] = wire;
+ it.second->setPort(name, wire);
log("Added connection %s to cell %s.%s (%s).\n", name.c_str(), module->name.c_str(), it.first.c_str(), it.second->type.c_str());
}
}
@@ -139,7 +136,7 @@ struct AddPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected_whole_module(module->name))
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc
index 7da2b9517..30c80f732 100644
--- a/passes/cmds/connect.cc
+++ b/passes/cmds/connect.cc
@@ -27,14 +27,14 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &
{
CellTypes ct(design);
- RTLIL::Wire *dummy_wire = module->new_wire(sig.width, NEW_ID);
+ RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());
- for (auto &it : module->cells)
- for (auto &port : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &port : it.second->connections_)
if (ct.cell_output(it.second->type, port.first))
sigmap(port.second).replace(sig, dummy_wire, &port.second);
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections_)
sigmap(conn.first).replace(sig, dummy_wire, &conn.first);
}
@@ -75,7 +75,7 @@ struct ConnectPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
RTLIL::Module *module = NULL;
- for (auto &it : design->modules) {
+ for (auto &it : design->modules_) {
if (!design->selected(it.second))
continue;
if (module != NULL)
@@ -123,7 +123,7 @@ struct ConnectPass : public Pass {
SigMap sigmap;
if (!flag_nomap)
- for (auto &it : module->connections) {
+ for (auto &it : module->connections()) {
std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector();
std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector();
for (size_t i = 0; i < lhs.size(); i++)
@@ -148,7 +148,7 @@ struct ConnectPass : public Pass {
if (!flag_nounset)
unset_drivers(design, module, sigmap, sig_lhs);
- module->connections.push_back(RTLIL::SigSig(sig_lhs, sig_rhs));
+ module->connect(RTLIL::SigSig(sig_lhs, sig_rhs));
}
else
if (!unset_expr.empty())
@@ -169,14 +169,14 @@ struct ConnectPass : public Pass {
if (flag_nounset)
log_cmd_error("Cant use -port together with -nounset.\n");
- if (module->cells.count(RTLIL::escape_id(port_cell)) == 0)
+ if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
RTLIL::SigSpec sig;
if (!RTLIL::SigSpec::parse_sel(sig, design, module, port_expr))
log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str());
- module->cells.at(RTLIL::escape_id(port_cell))->connections[RTLIL::escape_id(port_port)] = sigmap(sig);
+ module->cells_.at(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
}
else
log_cmd_error("Expected -set, -unset, or -port.\n");
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
new file mode 100644
index 000000000..aac117169
--- /dev/null
+++ b/passes/cmds/connwrappers.cc
@@ -0,0 +1,205 @@
+/*
+ * 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/rtlil.h"
+#include "kernel/log.h"
+
+struct ConnwrappersWorker
+{
+ struct portdecl_t {
+ // key: celltype, portname;
+ std::string widthparam, signparam;
+ bool is_signed;
+ };
+
+ std::set<RTLIL::IdString> decl_celltypes;
+ std::map<std::pair<RTLIL::IdString, RTLIL::IdString>, portdecl_t> decls;
+
+ void add_port(std::string celltype, std::string portname, std::string widthparam, std::string signparam)
+ {
+ std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+ decl_celltypes.insert(key.first);
+
+ if (decls.count(key))
+ log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+ portdecl_t decl;
+ decl.widthparam = RTLIL::escape_id(widthparam);
+ decl.signparam = RTLIL::escape_id(signparam);
+ decl.is_signed = false;
+ decls[key] = decl;
+ }
+
+ void add_port(std::string celltype, std::string portname, std::string widthparam, bool is_signed)
+ {
+ std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
+ decl_celltypes.insert(key.first);
+
+ if (decls.count(key))
+ log_cmd_error("Duplicate port decl: %s %s\n", celltype.c_str(), portname.c_str());
+
+ portdecl_t decl;
+ decl.widthparam = RTLIL::escape_id(widthparam);
+ decl.is_signed = is_signed;
+ decls[key] = decl;
+ }
+
+ void work(RTLIL::Design *design, RTLIL::Module *module)
+ {
+ std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
+ SigMap sigmap(module);
+
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!decl_celltypes.count(cell->type))
+ continue;
+
+ for (auto &conn : cell->connections())
+ {
+ std::pair<RTLIL::IdString, RTLIL::IdString> key(cell->type, conn.first);
+
+ if (!decls.count(key))
+ continue;
+
+ portdecl_t &decl = decls.at(key);
+
+ if (!cell->parameters.count(decl.widthparam))
+ continue;
+
+ if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam))
+ continue;
+
+ int inner_width = cell->parameters.at(decl.widthparam).as_int();
+ int outer_width = conn.second.size();
+ bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool();
+
+ if (inner_width >= outer_width)
+ continue;
+
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed,
+ sig.extract(inner_width, outer_width - inner_width));
+ }
+ }
+
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!design->selected(module, cell))
+ continue;
+
+ for (auto &conn : cell->connections_)
+ {
+ std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
+ RTLIL::SigSpec old_sig;
+
+ for (size_t i = 0; i < sigbits.size(); i++)
+ {
+ if (!extend_map.count(sigbits[i]))
+ continue;
+
+ bool is_signed = extend_map.at(sigbits[i]).first;
+ RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second;
+
+ int extend_width = 0;
+ RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0);
+ while (extend_width < extend_sig.size() && i + extend_width + 1 < sigbits.size() &&
+ sigbits[i + extend_width + 1] == extend_bit) extend_width++;
+
+ if (extend_width == 0)
+ continue;
+
+ if (old_sig.size() == 0)
+ old_sig = conn.second;
+
+ conn.second.replace(i+1, extend_sig.extract(0, extend_width));
+ i += extend_width;
+ }
+
+ if (old_sig.size())
+ log("Connected extended bits of %s.%s:%s: %s -> %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name),
+ RTLIL::id2cstr(conn.first), log_signal(old_sig), log_signal(conn.second));
+ }
+ }
+ }
+};
+
+struct ConnwrappersPass : public Pass {
+ ConnwrappersPass() : Pass("connwrappers", "replace undef values with defined constants") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" connwrappers [options] [selection]\n");
+ log("\n");
+ log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n");
+ log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n");
+ log("of the wrapper outut are signed/unsigned bit extended. This command uses this\n");
+ log("knowlege to rewire the inputs of the driven cells to match the output of\n");
+ log("the driving cell.\n");
+ log("\n");
+ log(" -signed <cell_type> <port_name> <width_param>\n");
+ log(" -unsigned <cell_type> <port_name> <width_param>\n");
+ log(" consider the specified signed/unsigned wrapper output\n");
+ log("\n");
+ log(" -port <cell_type> <port_name> <width_param> <sign_param>\n");
+ log(" use the specified parameter to decide if signed or unsigned\n");
+ log("\n");
+ log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ConnwrappersWorker worker;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-signed" && argidx+3 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true);
+ argidx += 3;
+ continue;
+ }
+ if (args[argidx] == "-unsigned" && argidx+3 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false);
+ argidx += 3;
+ continue;
+ }
+ if (args[argidx] == "-port" && argidx+4 < args.size()) {
+ worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]);
+ argidx += 4;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
+
+ for (auto &mod_it : design->modules_)
+ if (design->selected(mod_it.second))
+ worker.work(design, mod_it.second);
+ }
+} ConnwrappersPass;
+
diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc
index 4b1a8db81..be7758200 100644
--- a/passes/cmds/copy.cc
+++ b/passes/cmds/copy.cc
@@ -41,14 +41,15 @@ struct CopyPass : public Pass {
std::string src_name = RTLIL::escape_id(args[1]);
std::string trg_name = RTLIL::escape_id(args[2]);
- if (design->modules.count(src_name) == 0)
+ if (design->modules_.count(src_name) == 0)
log_cmd_error("Can't find source module %s.\n", src_name.c_str());
- if (design->modules.count(trg_name) != 0)
+ if (design->modules_.count(trg_name) != 0)
log_cmd_error("Target module name %s already exists.\n", trg_name.c_str());
- design->modules[trg_name] = design->modules.at(src_name)->clone();
- design->modules[trg_name]->name = trg_name;
+ RTLIL::Module *new_mod = design->module(src_name)->clone();
+ new_mod->name = trg_name;
+ design->add(new_mod);
}
} CopyPass;
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
new file mode 100644
index 000000000..ac72ba53a
--- /dev/null
+++ b/passes/cmds/cover.cc
@@ -0,0 +1,144 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 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 <sys/types.h>
+#include <unistd.h>
+#include <fnmatch.h>
+
+#include "kernel/register.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+struct CoverPass : public Pass {
+ CoverPass() : Pass("cover", "print code coverage counters") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" cover [options] [pattern]\n");
+ log("\n");
+ log("Print the code coverage counters collected using the cover() macro in the Yosys\n");
+ log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n");
+ log("test bench.\n");
+ log("\n");
+ log(" -q\n");
+ log(" Do not print output to the normal destination (console and/or log file)\n");
+ log("\n");
+ log(" -o file\n");
+ log(" Write output to this file, truncate if exists.\n");
+ log("\n");
+ log(" -a file\n");
+ log(" Write output to this file, append if exists.\n");
+ log("\n");
+ log(" -d dir\n");
+ log(" Write output to a newly created file in the specified directory.\n");
+ log("\n");
+ log("When one or more pattern (shell wildcards) are specified, then only counters\n");
+ log("matching at least one pattern are printed.\n");
+ log("\n");
+ log("\n");
+ log("It is also possible to instruct Yosys to print the coverage counters on program\n");
+ log("exit to a file using environment variables:\n");
+ log("\n");
+ log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n");
+ log("\n");
+ log(" This will create a file (with an auto-generated name) in this\n");
+ log(" directory and write the coverage counters to it.\n");
+ log("\n");
+ log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n");
+ log("\n");
+ log(" This will append the coverage counters to the specified file.\n");
+ log("\n");
+ log("\n");
+ log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n");
+ log("\n");
+ log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n");
+ 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("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::vector<FILE*> out_files;
+ std::vector<std::string> patterns;
+ bool do_log = true;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-q") {
+ do_log = false;
+ continue;
+ }
+ if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
+ const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
+ std::string filename = args[++argidx];
+ if (args[argidx-1] == "-d") {
+ char filename_buffer[4096];
+ snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
+ filename = mkstemps(filename_buffer, 4);
+ }
+ FILE *f = fopen(filename.c_str(), open_mode);
+ if (f == NULL) {
+ for (auto f : out_files)
+ fclose(f);
+ log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ }
+ out_files.push_back(f);
+ continue;
+ }
+ break;
+ }
+ while (argidx < args.size() && args[argidx].substr(0, 1) != "-")
+ patterns.push_back(args[argidx++]);
+ extra_args(args, argidx, design);
+
+ if (do_log) {
+ log_header("Printing code coverage counters.\n");
+ log("\n");
+ }
+
+#ifdef COVER_ACTIVE
+ for (auto &it : get_coverage_data()) {
+ if (!patterns.empty()) {
+ for (auto &p : patterns)
+ if (!fnmatch(p.c_str(), it.first.c_str(), 0))
+ goto pattern_match;
+ continue;
+ }
+ pattern_match:
+ for (auto f : out_files)
+ fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
+ if (do_log)
+ log("%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
+ }
+#else
+ for (auto f : out_files)
+ fclose(f);
+
+ log_cmd_error("Coverage counters are only available in debug builds of Yosys for Linux.\n");
+#endif
+
+ for (auto f : out_files)
+ fclose(f);
+ }
+} CoverPass;
+
diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc
index 1c02752c2..2a91bc9ea 100644
--- a/passes/cmds/delete.cc
+++ b/passes/cmds/delete.cc
@@ -21,21 +21,6 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-struct DeleteWireWorker
-{
- RTLIL::Module *module;
- std::set<std::string> *delete_wires_p;
-
- void operator()(RTLIL::SigSpec &sig) {
- sig.optimize();
- for (auto &c : sig.chunks)
- if (c.wire != NULL && delete_wires_p->count(c.wire->name)) {
- c.wire = module->new_wire(c.width, NEW_ID);
- c.offset = 0;
- }
- }
-};
-
struct DeletePass : public Pass {
DeletePass() : Pass("delete", "delete objects in the design") { }
virtual void help()
@@ -79,9 +64,9 @@ struct DeletePass : public Pass {
}
extra_args(args, argidx, design);
- std::vector<std::string> delete_mods;
+ std::vector<RTLIL::IdString> delete_mods;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (design->selected_whole_module(mod_it.first) && !flag_input && !flag_output) {
delete_mods.push_back(mod_it.first);
@@ -94,7 +79,7 @@ struct DeletePass : public Pass {
RTLIL::Module *module = mod_it.second;
if (flag_input || flag_output) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second)) {
if (flag_input)
it.second->port_input = false;
@@ -105,62 +90,52 @@ struct DeletePass : public Pass {
continue;
}
- std::set<std::string> delete_wires;
- std::set<std::string> delete_cells;
- std::set<std::string> delete_procs;
- std::set<std::string> delete_mems;
+ std::set<RTLIL::Wire*> delete_wires;
+ std::set<RTLIL::Cell*> delete_cells;
+ std::set<RTLIL::IdString> delete_procs;
+ std::set<RTLIL::IdString> delete_mems;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
- delete_wires.insert(it.first);
+ delete_wires.insert(it.second);
for (auto &it : module->memories)
if (design->selected(module, it.second))
delete_mems.insert(it.first);
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second))
- delete_cells.insert(it.first);
+ delete_cells.insert(it.second);
if ((it.second->type == "$memrd" || it.second->type == "$memwr") &&
delete_mems.count(it.second->parameters.at("\\MEMID").decode_string()) != 0)
- delete_cells.insert(it.first);
+ delete_cells.insert(it.second);
}
for (auto &it : module->processes)
if (design->selected(module, it.second))
delete_procs.insert(it.first);
- DeleteWireWorker delete_wire_worker;
- delete_wire_worker.module = module;
- delete_wire_worker.delete_wires_p = &delete_wires;
- module->rewrite_sigspecs(delete_wire_worker);
-
- for (auto &it : delete_wires) {
- delete module->wires.at(it);
- module->wires.erase(it);
- }
-
for (auto &it : delete_mems) {
delete module->memories.at(it);
module->memories.erase(it);
}
- for (auto &it : delete_cells) {
- delete module->cells.at(it);
- module->cells.erase(it);
- }
+ for (auto &it : delete_cells)
+ module->remove(it);
for (auto &it : delete_procs) {
delete module->processes.at(it);
module->processes.erase(it);
}
+ module->remove(delete_wires);
+
module->fixup_ports();
}
for (auto &it : delete_mods) {
- delete design->modules.at(it);
- design->modules.erase(it);
+ delete design->modules_.at(it);
+ design->modules_.erase(it);
}
}
} DeletePass;
diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc
index 80a6c0731..9f800c31f 100644
--- a/passes/cmds/design.cc
+++ b/passes/cmds/design.cc
@@ -22,13 +22,20 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+YOSYS_NAMESPACE_BEGIN
+
+std::map<std::string, RTLIL::Design*> saved_designs;
+std::vector<RTLIL::Design*> pushed_designs;
+
struct DesignPass : public Pass {
DesignPass() : Pass("design", "save, restore and reset current design") { }
- std::map<std::string, RTLIL::Design*> saved_designs;
virtual ~DesignPass() {
for (auto &it : saved_designs)
delete it.second;
saved_designs.clear();
+ for (auto &it : pushed_designs)
+ delete it;
+ pushed_designs.clear();
}
virtual void help()
{
@@ -49,6 +56,16 @@ struct DesignPass : public Pass {
log("Save the current design under the given name and then clear the current design.\n");
log("\n");
log("\n");
+ log(" design -push\n");
+ log("\n");
+ log("Push the current design to the stack and then clear the current design.\n");
+ log("\n");
+ log("\n");
+ log(" design -pop\n");
+ log("\n");
+ log("Reset the current design and pop the last design from the stack.\n");
+ log("\n");
+ log("\n");
log(" design -load <name>\n");
log("\n");
log("Reset the current design and load the design previously saved under the given\n");
@@ -70,6 +87,8 @@ struct DesignPass : public Pass {
{
bool got_mode = false;
bool reset_mode = false;
+ bool push_mode = false;
+ bool pop_mode = false;
RTLIL::Design *copy_from_design = NULL, *copy_to_design = NULL;
std::string save_name, load_name, as_name;
std::vector<RTLIL::Module*> copy_src_modules;
@@ -83,6 +102,16 @@ struct DesignPass : public Pass {
reset_mode = true;
continue;
}
+ if (!got_mode && args[argidx] == "-push") {
+ got_mode = true;
+ push_mode = true;
+ continue;
+ }
+ if (!got_mode && args[argidx] == "-pop") {
+ got_mode = true;
+ pop_mode = true;
+ continue;
+ }
if (!got_mode && args[argidx] == "-save" && argidx+1 < args.size()) {
got_mode = true;
save_name = args[++argidx];
@@ -138,7 +167,7 @@ struct DesignPass : public Pass {
argidx = args.size();
}
- for (auto &it : copy_from_design->modules) {
+ for (auto &it : copy_from_design->modules_) {
if (sel.selected_whole_module(it.first)) {
copy_src_modules.push_back(it.second);
continue;
@@ -151,7 +180,10 @@ struct DesignPass : public Pass {
extra_args(args, argidx, design, false);
if (!got_mode)
- cmd_error(args, argidx, "Missing mode argument (-reset, -save, -load, -copy-from, or -copy-to).");
+ cmd_error(args, argidx, "Missing mode argument.");
+
+ if (pop_mode && pushed_designs.empty())
+ log_cmd_error("No pushed designs.\n");
if (copy_to_design != NULL)
{
@@ -160,21 +192,22 @@ struct DesignPass : public Pass {
for (auto mod : copy_src_modules)
{
- std::string trg_name = as_name.empty() ? mod->name : RTLIL::escape_id(as_name);
+ std::string trg_name = as_name.empty() ? mod->name.str() : RTLIL::escape_id(as_name);
- if (copy_to_design->modules.count(trg_name))
- delete copy_to_design->modules.at(trg_name);
- copy_to_design->modules[trg_name] = mod->clone();
- copy_to_design->modules[trg_name]->name = trg_name;
+ if (copy_to_design->modules_.count(trg_name))
+ delete copy_to_design->modules_.at(trg_name);
+ copy_to_design->modules_[trg_name] = mod->clone();
+ copy_to_design->modules_[trg_name]->name = trg_name;
+ copy_to_design->modules_[trg_name]->design = copy_to_design;
}
}
- if (!save_name.empty())
+ if (!save_name.empty() || push_mode)
{
RTLIL::Design *design_copy = new RTLIL::Design;
- for (auto &it : design->modules)
- design_copy->modules[it.first] = it.second->clone();
+ for (auto &it : design->modules_)
+ design_copy->add(it.second->clone());
design_copy->selection_stack = design->selection_stack;
design_copy->selection_vars = design->selection_vars;
@@ -182,14 +215,18 @@ struct DesignPass : public Pass {
if (saved_designs.count(save_name))
delete saved_designs.at(save_name);
- saved_designs[save_name] = design_copy;
+
+ if (push_mode)
+ pushed_designs.push_back(design_copy);
+ else
+ saved_designs[save_name] = design_copy;
}
- if (reset_mode || !load_name.empty())
+ if (reset_mode || !load_name.empty() || push_mode || pop_mode)
{
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
delete it.second;
- design->modules.clear();
+ design->modules_.clear();
design->selection_stack.clear();
design->selection_vars.clear();
@@ -198,12 +235,15 @@ struct DesignPass : public Pass {
design->selection_stack.push_back(RTLIL::Selection());
}
- if (!load_name.empty())
+ if (!load_name.empty() || pop_mode)
{
- RTLIL::Design *saved_design = saved_designs.at(load_name);
+ RTLIL::Design *saved_design = pop_mode ? pushed_designs.back() : saved_designs.at(load_name);
+
+ if (pop_mode)
+ pushed_designs.pop_back();
- for (auto &it : saved_design->modules)
- design->modules[it.first] = it.second->clone();
+ for (auto &it : saved_design->modules_)
+ design->add(it.second->clone());
design->selection_stack = saved_design->selection_stack;
design->selection_vars = saved_design->selection_vars;
@@ -211,4 +251,6 @@ struct DesignPass : public Pass {
}
}
} DesignPass;
-
+
+YOSYS_NAMESPACE_END
+
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
new file mode 100644
index 000000000..4e8234d16
--- /dev/null
+++ b/passes/cmds/plugin.cc
@@ -0,0 +1,124 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 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"
+
+#ifdef YOSYS_ENABLE_PLUGINS
+# include <dlfcn.h>
+#endif
+
+YOSYS_NAMESPACE_BEGIN
+
+std::map<std::string, void*> loaded_plugins;
+std::map<std::string, std::string> loaded_plugin_aliases;
+
+void load_plugin(std::string filename, std::vector<std::string> aliases)
+{
+#ifdef YOSYS_ENABLE_PLUGINS
+ if (filename.find('/') == std::string::npos)
+ filename = "./" + filename;
+
+ if (!loaded_plugins.count(filename)) {
+ void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl == NULL)
+ log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
+ loaded_plugins[filename] = hdl;
+ Pass::init_register();
+ }
+
+ for (auto &alias : aliases)
+ loaded_plugin_aliases[alias] = filename;
+#else
+ log_error("This version of yosys is built without plugin support.\n");
+#endif
+}
+
+struct PluginPass : public Pass {
+ PluginPass() : Pass("plugin", "load and list loaded plugins") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" plugin [options]\n");
+ log("\n");
+ log("Load and list loaded plugins.\n");
+ log("\n");
+ log(" -i <plugin_filename>\n");
+ log(" Load (install) the specified plugin.\n");
+ log("\n");
+ log(" -a <alias_name>\n");
+ log(" Register the specified alias name for the loaded plugin\n");
+ log("\n");
+ log(" -l\n");
+ log(" List loaded plugins\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string plugin_filename;
+ std::vector<std::string> plugin_aliases;
+ bool list_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if ((args[argidx] == "-i") && argidx+1 < args.size() && plugin_filename.empty()) {
+ plugin_filename = args[++argidx];
+ continue;
+ }
+ if ((args[argidx] == "-a") && argidx+1 < args.size()) {
+ plugin_aliases.push_back(args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-l") {
+ list_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design, false);
+
+ if (!plugin_filename.empty())
+ load_plugin(plugin_filename, plugin_aliases);
+
+ if (list_mode)
+ {
+ log("\n");
+ if (loaded_plugins.empty())
+ log("No plugins loaded.\n");
+ else
+ log("Loaded plugins:\n");
+
+ for (auto &it : loaded_plugins)
+ log(" %s\n", it.first.c_str());
+
+ if (!loaded_plugin_aliases.empty()) {
+ log("\n");
+ int max_alias_len = 1;
+ for (auto &it : loaded_plugin_aliases)
+ max_alias_len = std::max(max_alias_len, SIZE(it.first));
+ for (auto &it : loaded_plugin_aliases)
+ log("Alias: %-*s %s\n", max_alias_len, it.first.c_str(), it.second.c_str());
+ }
+ }
+ }
+} PluginPass;
+
+YOSYS_NAMESPACE_END
+
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 519dce452..91de364fe 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -29,23 +29,17 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
if (module->count_id(to_name))
log_cmd_error("There is already an object `%s' in module `%s'.\n", to_name.c_str(), module->name.c_str());
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.first == from_name) {
- RTLIL::Wire *wire = it.second;
- log("Renaming wire %s to %s in module %s.\n", wire->name.c_str(), to_name.c_str(), module->name.c_str());
- module->wires.erase(wire->name);
- wire->name = to_name;
- module->add(wire);
+ 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);
return;
}
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (it.first == from_name) {
- RTLIL::Cell *cell = it.second;
- log("Renaming cell %s to %s in module %s.\n", cell->name.c_str(), to_name.c_str(), module->name.c_str());
- module->cells.erase(cell->name);
- cell->name = to_name;
- module->add(cell);
+ log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
+ module->rename(it.second, to_name);
return;
}
@@ -64,10 +58,12 @@ struct RenamePass : public Pass {
log("by this command.\n");
log("\n");
log("\n");
- log(" rename -enumerate [selection]\n");
+ log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n");
- log("names.\n");
+ log("names. The -pattern option can be used to set the pattern for the new names.\n");
+ log("The character %% in the pattern is replaced with a integer number. The default\n");
+ log("pattern is '_%%_'.\n");
log("\n");
log(" rename -hide [selection]\n");
log("\n");
@@ -77,6 +73,7 @@ struct RenamePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ std::string pattern_prefix = "_", pattern_suffix = "_";
bool flag_enumerate = false;
bool flag_hide = false;
bool got_mode = false;
@@ -95,6 +92,12 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
+ if (arg == "-pattern" && argidx+1 < args.size() && args[argidx+1].find('%') != std::string::npos) {
+ int pos = args[++argidx].find('%');
+ pattern_prefix = args[argidx].substr(0, pos);
+ pattern_suffix = args[argidx].substr(pos+1);
+ continue;
+ }
break;
}
@@ -102,7 +105,7 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
int counter = 0;
@@ -111,22 +114,22 @@ struct RenamePass : public Pass {
continue;
std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\_%d_", counter++);
+ do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
while (module->count_id(it.second->name) > 0);
new_wires[it.second->name] = it.second;
}
- module->wires.swap(new_wires);
+ module->wires_.swap(new_wires);
std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (it.first[0] == '$' && design->selected(module, it.second))
- do it.second->name = stringf("\\_%d_", counter++);
+ do it.second->name = stringf("\\%s%d%s", pattern_prefix.c_str(), counter++, pattern_suffix.c_str());
while (module->count_id(it.second->name) > 0);
new_cells[it.second->name] = it.second;
}
- module->cells.swap(new_cells);
+ module->cells_.swap(new_cells);
}
}
else
@@ -134,29 +137,29 @@ struct RenamePass : public Pass {
{
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected(module))
continue;
std::map<RTLIL::IdString, RTLIL::Wire*> new_wires;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\' && it.second->port_id == 0)
it.second->name = NEW_ID;
new_wires[it.second->name] = it.second;
}
- module->wires.swap(new_wires);
+ module->wires_.swap(new_wires);
std::map<RTLIL::IdString, RTLIL::Cell*> new_cells;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second))
if (it.first[0] == '\\')
it.second->name = NEW_ID;
new_cells[it.second->name] = it.second;
}
- module->cells.swap(new_cells);
+ module->cells_.swap(new_cells);
}
}
else
@@ -169,19 +172,19 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
- if (design->modules.count(design->selected_active_module) > 0)
- rename_in_module(design->modules.at(design->selected_active_module), from_name, to_name);
+ if (design->modules_.count(design->selected_active_module) > 0)
+ rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
}
else
{
- for (auto &mod : design->modules) {
+ for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name);
log("Renaming module %s to %s.\n", mod.first.c_str(), to_name.c_str());
RTLIL::Module *module = mod.second;
- design->modules.erase(module->name);
+ design->modules_.erase(module->name);
module->name = to_name;
- design->modules[module->name] = module;
+ design->modules_[module->name] = module;
goto rename_ok;
}
}
diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc
index e5f78830e..e09c00123 100644
--- a/passes/cmds/scatter.cc
+++ b/passes/cmds/scatter.cc
@@ -43,25 +43,22 @@ struct ScatterPass : public Pass {
CellTypes ct(design);
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
- for (auto &c : mod_it.second->cells)
- for (auto &p : c.second->connections)
+ for (auto &c : mod_it.second->cells_)
+ for (auto &p : c.second->connections_)
{
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = NEW_ID;
- wire->width = p.second.width;
- mod_it.second->add(wire);
+ RTLIL::Wire *wire = mod_it.second->addWire(NEW_ID, p.second.size());
if (ct.cell_output(c.second->type, p.first)) {
RTLIL::SigSig sigsig(p.second, wire);
- mod_it.second->connections.push_back(sigsig);
+ mod_it.second->connect(sigsig);
} else {
RTLIL::SigSig sigsig(wire, p.second);
- mod_it.second->connections.push_back(sigsig);
+ mod_it.second->connect(sigsig);
}
p.second = wire;
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index f8c351a43..5224f5bc9 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -51,7 +51,7 @@ struct SccWorker
void run(RTLIL::Cell *cell, int depth, int maxDepth)
{
- assert(workQueue.count(cell) > 0);
+ log_assert(workQueue.count(cell) > 0);
workQueue.erase(cell);
cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
@@ -114,11 +114,11 @@ struct SccWorker
SigPool selectedSignals;
SigSet<RTLIL::Cell*> sigToNextCells;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
@@ -132,7 +132,7 @@ struct SccWorker
RTLIL::SigSpec inputSignals, outputSignals;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
bool isInput = true, isOutput = true;
@@ -166,7 +166,7 @@ struct SccWorker
while (workQueue.size() > 0) {
RTLIL::Cell *cell = *workQueue.begin();
- assert(cellStack.size() == 0);
+ log_assert(cellStack.size() == 0);
cellDepth.clear();
run(cell, 0, maxDepth);
}
@@ -191,7 +191,7 @@ struct SccWorker
nextsig.sort_and_unify();
sig = prevsig.extract(nextsig);
- for (auto &chunk : sig.chunks)
+ for (auto &chunk : sig.chunks())
if (chunk.wire != NULL)
sel.selected_members[module->name].insert(chunk.wire->name);
}
@@ -216,7 +216,7 @@ struct SccPass : public Pass {
log("\n");
log(" -all_cell_types\n");
log(" Usually this command only considers internal non-memory cells. With\n");
- log(" this option set, all cells are considered. For unkown cells all ports\n");
+ log(" this option set, all cells are considered. For unknown cells all ports\n");
log(" are assumed to be bidirectional 'inout' ports.\n");
log("\n");
log(" -set_attr <name> <value>\n");
@@ -280,7 +280,7 @@ struct SccPass : public Pass {
RTLIL::Selection newSelection(false);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
{
SccWorker worker(design, mod_it.second, allCellTypes, maxDepth);
@@ -290,7 +290,7 @@ struct SccPass : public Pass {
}
if (selectMode) {
- assert(origSelectPos >= 0);
+ log_assert(origSelectPos >= 0);
design->selection_stack[origSelectPos] = newSelection;
design->selection_stack[origSelectPos].optimize(design);
}
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index a1a64f145..4c540ca67 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -23,6 +23,7 @@
#include "kernel/log.h"
#include <string.h>
#include <fnmatch.h>
+#include <errno.h>
using RTLIL::id2cstr;
@@ -63,6 +64,8 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
if (match_op == '=')
return value == pattern_value;
+ if (match_op == '!')
+ return value != pattern_value;
if (match_op == '<')
return value.as_int() < pattern_value.as_int();
if (match_op == '>')
@@ -82,6 +85,8 @@ static bool match_attr_val(const RTLIL::Const &value, std::string pattern, char
if (match_op == '=')
return value_str == pattern;
+ if (match_op == '!')
+ return value_str != pattern;
if (match_op == '<')
return value_str < pattern;
if (match_op == '>')
@@ -115,9 +120,11 @@ static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes
static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string match_expr)
{
- size_t pos = match_expr.find_first_of("<=>");
+ size_t pos = match_expr.find_first_of("<!=>");
if (pos != std::string::npos) {
+ if (match_expr.substr(pos, 2) == "!=")
+ return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '!');
if (match_expr.substr(pos, 2) == "<=")
return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '[');
if (match_expr.substr(pos, 2) == ">=")
@@ -144,7 +151,7 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
RTLIL::Selection new_sel(false);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
continue;
@@ -154,13 +161,13 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
}
RTLIL::Module *mod = mod_it.second;
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (!lhs.selected_member(mod_it.first, it.first))
new_sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -174,13 +181,13 @@ static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs)
{
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
{
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
{
- if (design->modules.count(cell_it.second->type) == 0)
+ if (design->modules_.count(cell_it.second->type) == 0)
continue;
lhs.selected_modules.insert(cell_it.second->type);
}
@@ -198,7 +205,7 @@ static void select_op_fullmod(RTLIL::Design *design, RTLIL::Selection &lhs)
static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
{
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first))
continue;
@@ -208,11 +215,11 @@ static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
SigMap sigmap(mod_it.second);
SigPool selected_bits;
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (lhs.selected_member(mod_it.first, it.first))
selected_bits.add(sigmap(it.second));
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (!lhs.selected_member(mod_it.first, it.first) && selected_bits.check_any(sigmap(it.second)))
lhs.selected_members[mod_it.first].insert(it.first);
}
@@ -253,7 +260,7 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R
if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
return;
lhs.full_selection = false;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
lhs.selected_modules.insert(it.first);
}
@@ -264,18 +271,18 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R
for (auto &it : rhs.selected_members)
{
- if (design->modules.count(it.first) == 0)
+ if (design->modules_.count(it.first) == 0)
continue;
- RTLIL::Module *mod = design->modules[it.first];
+ RTLIL::Module *mod = design->modules_[it.first];
if (lhs.selected_modules.count(mod->name) > 0)
{
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
lhs.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
lhs.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
lhs.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
lhs.selected_members[mod->name].insert(it.first);
@@ -297,7 +304,7 @@ static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, co
if (lhs.full_selection) {
lhs.full_selection = false;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
lhs.selected_modules.insert(it.first);
}
@@ -361,7 +368,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
{
int sel_objects = 0;
bool is_input, is_output;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (lhs.selected_whole_module(mod_it.first) || !lhs.selected_module(mod_it.first))
continue;
@@ -369,11 +376,11 @@ 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;
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0)
selected_wires.insert(it.second);
- for (auto &conn : mod->connections)
+ for (auto &conn : mod->connections())
{
std::vector<RTLIL::SigBit> conn_lhs = conn.first.to_sigbit_vector();
std::vector<RTLIL::SigBit> conn_rhs = conn.second.to_sigbit_vector();
@@ -388,8 +395,8 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
}
}
- for (auto &cell : mod->cells)
- for (auto &conn : cell.second->connections)
+ for (auto &cell : mod->cells_)
+ for (auto &conn : cell.second->connections())
{
char last_mode = '-';
for (auto &rule : rules) {
@@ -408,7 +415,7 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v
include_match:
is_input = mode == 'x' || ct.cell_input(cell.second->type, conn.first);
is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first);
- for (auto &chunk : conn.second.chunks)
+ 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 (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input))
@@ -483,7 +490,7 @@ static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
for (auto i2 : i1.second)
limits.insert(i2);
} else
- log_cmd_error("Selection %s is not defined!\n", RTLIL::id2cstr(str));
+ log_cmd_error("Selection %s is not defined!\n", RTLIL::unescape_id(str).c_str());
} else
limits.insert(RTLIL::escape_id(str));
}
@@ -540,7 +547,7 @@ static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &se
return;
}
- std::vector<std::string> del_list;
+ std::vector<RTLIL::IdString> del_list;
for (auto mod_name : sel.selected_modules)
if (mod_name != design->selected_active_module)
del_list.push_back(mod_name);
@@ -588,6 +595,13 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
select_op_diff(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
work_stack.pop_back();
} else
+ if (arg == "%D") {
+ if (work_stack.size() < 2)
+ log_cmd_error("Must have at least two elements on the stack for operator %%d.\n");
+ select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]);
+ work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1];
+ work_stack.pop_back();
+ } else
if (arg == "%i") {
if (work_stack.size() < 2)
log_cmd_error("Must have at least two elements on the stack for operator %%i.\n");
@@ -599,14 +613,19 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
select_op_submod(design, work_stack[work_stack.size()-1]);
} else
+ if (arg == "%c") {
+ if (work_stack.size() < 1)
+ log_cmd_error("Must have at least one element on the stack for operator %%c.\n");
+ work_stack.push_back(work_stack.back());
+ } else
if (arg == "%m") {
if (work_stack.size() < 1)
- log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
+ log_cmd_error("Must have at least one element on the stack for operator %%m.\n");
select_op_fullmod(design, work_stack[work_stack.size()-1]);
} else
if (arg == "%a") {
if (work_stack.size() < 1)
- log_cmd_error("Must have at least one element on the stack for operator %%s.\n");
+ log_cmd_error("Must have at least one element on the stack for operator %%a.\n");
select_op_alias(design, work_stack[work_stack.size()-1]);
} else
if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
@@ -635,7 +654,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
if (design->selection_vars.count(set_name) > 0)
work_stack.push_back(design->selection_vars[set_name]);
else
- log_cmd_error("Selection @%s is not defined!\n", RTLIL::id2cstr(set_name));
+ log_cmd_error("Selection @%s is not defined!\n", RTLIL::unescape_id(set_name).c_str());
select_filter_active_mod(design, work_stack.back());
return;
}
@@ -665,7 +684,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
}
sel.full_selection = false;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (arg_mod.substr(0, 2) == "A:") {
if (!match_attr(mod_it.second->attributes, arg_mod.substr(2)))
@@ -681,22 +700,22 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
RTLIL::Module *mod = mod_it.second;
if (arg_memb.substr(0, 2) == "w:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "i:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->port_input && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "o:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->port_output && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "x:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if ((it.second->port_input || it.second->port_output) && match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
@@ -704,7 +723,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
size_t delim = arg_memb.substr(2).find(':');
if (delim == std::string::npos) {
int width = atoi(arg_memb.substr(2).c_str());
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (it.second->width == width)
sel.selected_members[mod->name].insert(it.first);
} else {
@@ -712,7 +731,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
std::string max_str = arg_memb.substr(2+delim+1);
int min_width = min_str.empty() ? 0 : atoi(min_str.c_str());
int max_width = max_str.empty() ? -1 : atoi(max_str.c_str());
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (min_width <= it.second->width && (it.second->width <= max_width || max_width == -1))
sel.selected_members[mod->name].insert(it.first);
}
@@ -723,12 +742,12 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "c:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.first, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "t:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.second->type, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else
@@ -738,13 +757,13 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "a:") {
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_attr(it.second->attributes, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -752,19 +771,19 @@ static void select_stmt(RTLIL::Design *design, std::string arg)
sel.selected_members[mod->name].insert(it.first);
} else
if (arg_memb.substr(0, 2) == "r:") {
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_attr(it.second->parameters, arg_memb.substr(2)))
sel.selected_members[mod->name].insert(it.first);
} else {
if (arg_memb.substr(0, 2) == "n:")
arg_memb = arg_memb.substr(2);
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->memories)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
- for (auto &it : mod->cells)
+ for (auto &it : mod->cells_)
if (match_ids(it.first, arg_memb))
sel.selected_members[mod->name].insert(it.first);
for (auto &it : mod->processes)
@@ -838,6 +857,10 @@ struct SelectPass : public Pass {
log(" selection is non-empty. i.e. produce an error if no object matching\n");
log(" the selection is found.\n");
log("\n");
+ log(" -assert-count N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains exactly N objects.\n");
+ log("\n");
log(" -list\n");
log(" list all objects in the current selection\n");
log("\n");
@@ -951,12 +974,18 @@ struct SelectPass : public Pass {
log(" %%d\n");
log(" pop the top set from the stack and subtract it from the new top\n");
log("\n");
+ log(" %%D\n");
+ log(" like %%d but swap the roles of two top sets on the stack\n");
+ log("\n");
+ log(" %%c\n");
+ log(" create a copy of the top set rom the stack and push it\n");
+ log("\n");
log(" %%x[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
log(" expand top set <num1> num times according to the specified rules.\n");
log(" (i.e. select all cells connected to selected wires and select all\n");
log(" wires connected to selected cells) The rules specify which cell\n");
log(" ports to use for this. the syntax for a rule is a '-' for exclusion\n");
- log(" and a '+' for inclusion, followed by an optional comma seperated\n");
+ log(" and a '+' for inclusion, followed by an optional comma separated\n");
log(" list of cell types followed by an optional comma separated list of\n");
log(" cell ports in square brackets. a rule can also be just a cell or wire\n");
log(" name that limits the expansion (is included but does not go beyond).\n");
@@ -996,6 +1025,7 @@ struct SelectPass : public Pass {
bool got_module = false;
bool assert_none = false;
bool assert_any = false;
+ int assert_count = -1;
std::string write_file;
std::string set_name;
std::string sel_str;
@@ -1022,6 +1052,10 @@ struct SelectPass : public Pass {
assert_any = true;
continue;
}
+ if (arg == "-assert-count" && argidx+1 < args.size()) {
+ assert_count = atoi(args[++argidx].c_str());
+ continue;
+ }
if (arg == "-clear") {
clear_mode = true;
continue;
@@ -1044,9 +1078,9 @@ struct SelectPass : public Pass {
}
if (arg == "-module" && argidx+1 < args.size()) {
RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
- if (design->modules.count(mod_name) == 0)
+ if (design->modules_.count(mod_name) == 0)
log_cmd_error("No such module: %s\n", id2cstr(mod_name));
- design->selected_active_module = mod_name;
+ design->selected_active_module = mod_name.str();
got_module = true;
continue;
}
@@ -1055,7 +1089,7 @@ struct SelectPass : public Pass {
continue;
}
if (arg.size() > 0 && arg[0] == '-')
- log_cmd_error("Unkown option %s.\n", arg.c_str());
+ log_cmd_error("Unknown option %s.\n", arg.c_str());
select_stmt(design, arg);
sel_str += " " + arg;
}
@@ -1066,14 +1100,14 @@ struct SelectPass : public Pass {
if (none_mode && args.size() != 2)
log_cmd_error("Option -none can not be combined with any other options.\n");
- if (add_mode + del_mode + assert_none + assert_any > 1)
- log_cmd_error("Options -add, -del, -assert-none or -assert-any can not be combined.\n");
+ if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) > 1)
+ log_cmd_error("Options -add, -del, -assert-none, -assert-any or -assert-count can not be combined.\n");
- if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any))
- log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none or -assert-any.\n");
+ if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
+ log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any or -assert-count.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none or -assert-any.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any or -assert-count.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1086,7 +1120,7 @@ struct SelectPass : public Pass {
work_stack.pop_back();
}
- assert(design->selection_stack.size() > 0);
+ log_assert(design->selection_stack.size() > 0);
if (clear_mode) {
design->selection_stack.back() = RTLIL::Selection(true);
@@ -1113,18 +1147,18 @@ struct SelectPass : public Pass {
if (work_stack.size() > 0)
sel = &work_stack.back();
sel->optimize(design);
- for (auto mod_it : design->modules)
+ for (auto mod_it : design->modules_)
{
if (sel->selected_whole_module(mod_it.first) && list_mode)
log("%s\n", id2cstr(mod_it.first));
if (sel->selected_module(mod_it.first)) {
- for (auto &it : mod_it.second->wires)
+ 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));
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));
- for (auto &it : mod_it.second->cells)
+ 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));
for (auto &it : mod_it.second->processes)
@@ -1176,6 +1210,34 @@ struct SelectPass : public Pass {
return;
}
+ if (assert_count >= 0)
+ {
+ int total_count = 0;
+ if (work_stack.size() == 0)
+ log_cmd_error("No selection to check.\n");
+ RTLIL::Selection *sel = &work_stack.back();
+ sel->optimize(design);
+ for (auto mod_it : design->modules_)
+ if (sel->selected_module(mod_it.first)) {
+ for (auto &it : mod_it.second->wires_)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->memories)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->cells_)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ for (auto &it : mod_it.second->processes)
+ if (sel->selected_member(mod_it.first, it.first))
+ total_count++;
+ }
+ if (assert_count != total_count)
+ log_error("Assertation failed: selection contains %d elements instead of the asserted %d:%s\n",
+ total_count, assert_count, sel_str.c_str());
+ return;
+ }
+
if (!set_name.empty())
{
if (work_stack.size() == 0)
@@ -1237,15 +1299,15 @@ struct CdPass : public Pass {
std::string modname = RTLIL::escape_id(args[1]);
- if (design->modules.count(modname) == 0 && !design->selected_active_module.empty()) {
+ if (design->modules_.count(modname) == 0 && !design->selected_active_module.empty()) {
RTLIL::Module *module = NULL;
- if (design->modules.count(design->selected_active_module) > 0)
- module = design->modules.at(design->selected_active_module);
- if (module != NULL && module->cells.count(modname) > 0)
- modname = module->cells.at(modname)->type;
+ if (design->modules_.count(design->selected_active_module) > 0)
+ module = design->modules_.at(design->selected_active_module);
+ if (module != NULL && module->cells_.count(modname) > 0)
+ modname = module->cells_.at(modname)->type.str();
}
- if (design->modules.count(modname) > 0) {
+ if (design->modules_.count(modname) > 0) {
design->selected_active_module = modname;
design->selection_stack.back() = RTLIL::Selection();
select_filter_active_mod(design, design->selection_stack.back());
@@ -1253,14 +1315,14 @@ struct CdPass : public Pass {
return;
}
- log_cmd_error("No such module `%s' found!\n", RTLIL::id2cstr(modname));
+ log_cmd_error("No such module `%s' found!\n", RTLIL::unescape_id(modname).c_str());
}
} CdPass;
template<typename T>
static int log_matches(const char *title, std::string pattern, T list)
{
- std::vector<std::string> matches;
+ std::vector<RTLIL::IdString> matches;
for (auto &it : list)
if (pattern.empty() || match_ids(it.first, pattern))
@@ -1306,15 +1368,15 @@ struct LsPass : public Pass {
if (design->selected_active_module.empty())
{
- counter += log_matches("modules", pattern, design->modules);
+ counter += log_matches("modules", pattern, design->modules_);
}
else
- if (design->modules.count(design->selected_active_module) > 0)
+ if (design->modules_.count(design->selected_active_module) > 0)
{
- RTLIL::Module *module = design->modules.at(design->selected_active_module);
- counter += log_matches("wires", pattern, module->wires);
+ 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("cells", pattern, module->cells_);
counter += log_matches("processes", pattern, module->processes);
}
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 8d98df719..029c0ec79 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -98,7 +98,7 @@ struct SetattrPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
@@ -111,7 +111,7 @@ struct SetattrPass : public Pass {
if (!design->selected(module))
continue;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
@@ -119,7 +119,7 @@ struct SetattrPass : public Pass {
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
@@ -164,14 +164,14 @@ struct SetparamPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod : design->modules)
+ for (auto &mod : design->modules_)
{
RTLIL::Module *module = mod.second;
if (!design->selected(module))
continue;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second))
do_setunset(it.second->parameters, setunset_list);
}
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 9d59834c2..c72e64b80 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,35 +23,33 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
-static int next_bit_mode;
-static uint32_t next_bit_state;
-
-static RTLIL::State next_bit()
+struct SetundefWorker
{
- if (next_bit_mode == 0)
- return RTLIL::State::S0;
+ int next_bit_mode;
+ uint32_t next_bit_state;
- if (next_bit_mode == 1)
- return RTLIL::State::S1;
+ RTLIL::State next_bit()
+ {
+ if (next_bit_mode == 0)
+ return RTLIL::State::S0;
- // xorshift32
- next_bit_state ^= next_bit_state << 13;
- next_bit_state ^= next_bit_state >> 17;
- next_bit_state ^= next_bit_state << 5;
- log_assert(next_bit_state != 0);
+ if (next_bit_mode == 1)
+ return RTLIL::State::S1;
- return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
-}
+ // xorshift32
+ next_bit_state ^= next_bit_state << 13;
+ next_bit_state ^= next_bit_state >> 17;
+ next_bit_state ^= next_bit_state << 5;
+ log_assert(next_bit_state != 0);
+
+ return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
-struct SetundefWorker
-{
void operator()(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks)
- if (c.wire == NULL && c.data.bits.at(0) > RTLIL::State::S1)
- c.data.bits.at(0) = next_bit();
- sig.optimize();
+ for (auto &bit : sig)
+ if (bit.wire == NULL && bit.data > RTLIL::State::S1)
+ bit = next_bit();
}
};
@@ -83,6 +81,7 @@ struct SetundefPass : public Pass {
{
bool got_value = false;
bool undriven_mode = false;
+ SetundefWorker worker;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -93,20 +92,20 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-zero") {
got_value = true;
- next_bit_mode = 0;
+ worker.next_bit_mode = 0;
continue;
}
if (args[argidx] == "-one") {
got_value = true;
- next_bit_mode = 1;
+ worker.next_bit_mode = 1;
continue;
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
- next_bit_mode = 2;
- next_bit_state = atoi(args[++argidx].c_str()) + 1;
+ worker.next_bit_mode = 2;
+ worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
- next_bit();
+ worker.next_bit();
continue;
}
break;
@@ -116,7 +115,7 @@ struct SetundefPass : public Pass {
if (!got_value)
log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
@@ -130,27 +129,26 @@ struct SetundefPass : public Pass {
SigMap sigmap(module);
SigPool undriven_signals;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (!it.second->port_input)
undriven_signals.add(sigmap(it.second));
CellTypes ct(design);
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
undriven_signals.del(sigmap(conn.second));
RTLIL::SigSpec sig = undriven_signals.export_all();
- for (auto &c : sig.chunks) {
+ for (auto &c : sig.chunks()) {
RTLIL::SigSpec bits;
for (int i = 0; i < c.width; i++)
- bits.append(next_bit());
- bits.optimize();
- module->connections.push_back(RTLIL::SigSig(c, bits));
+ bits.append(worker.next_bit());
+ module->connect(RTLIL::SigSig(c, bits));
}
}
- module->rewrite_sigspecs(SetundefWorker());
+ module->rewrite_sigspecs(worker);
}
}
} SetundefPass;
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index fdccb4bcc..2218eded2 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -22,7 +22,10 @@
#include "kernel/log.h"
#include <string.h>
#include <dirent.h>
-#include <readline/readline.h>
+
+#ifdef YOSYS_ENABLE_READLINE
+# include <readline/readline.h>
+#endif
using RTLIL::id2cstr;
@@ -45,6 +48,7 @@ struct ShowWorker
RTLIL::Module *module;
uint32_t currentColor;
bool genWidthLabels;
+ bool genSignedLabels;
bool stretchIO;
bool enumerateIds;
bool abbreviateIds;
@@ -54,7 +58,7 @@ struct ShowWorker
const std::vector<std::pair<std::string, RTLIL::Selection>> &color_selections;
const std::vector<std::pair<std::string, RTLIL::Selection>> &label_selections;
- uint32_t xorshift32(uint32_t x) {
+ static uint32_t xorshift32(uint32_t x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
@@ -78,7 +82,7 @@ struct ShowWorker
std::string nextColor(RTLIL::SigSpec sig, std::string defaultColor)
{
sig.sort_and_unify();
- for (auto &c : sig.chunks) {
+ for (auto &c : sig.chunks()) {
if (c.wire != NULL)
for (auto &s : color_selections)
if (s.second.selected_members.count(module->name) > 0 && s.second.selected_members.at(module->name).count(c.wire->name) > 0)
@@ -87,17 +91,17 @@ struct ShowWorker
return defaultColor;
}
- std::string nextColor(RTLIL::SigSig &conn, std::string defaultColor)
+ std::string nextColor(const RTLIL::SigSig &conn, std::string defaultColor)
{
return nextColor(conn.first, nextColor(conn.second, defaultColor));
}
- std::string nextColor(RTLIL::SigSpec &sig)
+ std::string nextColor(const RTLIL::SigSpec &sig)
{
return nextColor(sig, nextColor());
}
- std::string nextColor(RTLIL::SigSig &conn)
+ std::string nextColor(const RTLIL::SigSig &conn)
{
return nextColor(conn, nextColor());
}
@@ -124,7 +128,7 @@ struct ShowWorker
const char *findLabel(std::string member_name)
{
for (auto &s : label_selections)
- if (s.second.selected_member(module->name, RTLIL::escape_id(member_name)))
+ if (s.second.selected_member(module->name, member_name))
return escape(s.first);
return escape(member_name, true);
}
@@ -171,15 +175,13 @@ struct ShowWorker
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check = true)
{
- sig.optimize();
-
- if (sig.chunks.size() == 0) {
+ if (SIZE(sig) == 0) {
fprintf(f, "v%d [ label=\"\" ];\n", single_idx_count);
return stringf("v%d", single_idx_count++);
}
- if (sig.chunks.size() == 1) {
- RTLIL::SigChunk &c = sig.chunks[0];
+ if (sig.is_chunk()) {
+ const RTLIL::SigChunk &c = sig.as_chunk();
if (c.wire != NULL && design->selected_member(module->name, c.wire->name)) {
if (!range_check || c.wire->width == c.width)
return stringf("n%d", id2num(c.wire->name));
@@ -199,13 +201,12 @@ struct ShowWorker
if (net.empty())
{
std::string label_string;
- sig.optimize();
- int pos = sig.width-1;
+ int pos = sig.size()-1;
int idx = single_idx_count++;
- for (int i = int(sig.chunks.size())-1; i >= 0; i--) {
- RTLIL::SigChunk &c = sig.chunks[i];
+ for (int i = int(sig.chunks().size())-1; i >= 0; i--) {
+ const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false);
- assert(!net.empty());
+ log_assert(!net.empty());
if (driver) {
label_string += stringf("<s%d> %d:%d - %d:%d |", i, pos, pos-c.width+1, c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
@@ -225,9 +226,9 @@ struct ShowWorker
if (!port.empty()) {
currentColor = xorshift32(currentColor);
if (driver)
- code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor(sig).c_str(), widthLabel(sig.width).c_str());
+ code += stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port.c_str(), idx, nextColor(sig).c_str(), widthLabel(sig.size()).c_str());
else
- code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.width).c_str());
+ code += stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx, port.c_str(), nextColor(sig).c_str(), widthLabel(sig.size()).c_str());
}
if (node != NULL)
*node = stringf("x%d", idx);
@@ -239,7 +240,7 @@ struct ShowWorker
net_conn_map[net].in.insert(port);
else
net_conn_map[net].out.insert(port);
- net_conn_map[net].bits = sig.width;
+ net_conn_map[net].bits = sig.size();
net_conn_map[net].color = nextColor(sig, net_conn_map[net].color);
}
if (node != NULL)
@@ -299,16 +300,16 @@ struct ShowWorker
dot_id2num_store.clear();
net_conn_map.clear();
- fprintf(f, "digraph \"%s\" {\n", escape(module->name));
+ fprintf(f, "digraph \"%s\" {\n", escape(module->name.str()));
if (!notitle)
- fprintf(f, "label=\"%s\";\n", escape(module->name));
+ fprintf(f, "label=\"%s\";\n", escape(module->name.str()));
fprintf(f, "rankdir=\"LR\";\n");
fprintf(f, "remincross=true;\n");
std::set<std::string> all_sources, all_sinks;
std::map<std::string, std::string> wires_on_demand;
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (!design->selected_member(module->name, it.first))
continue;
const char *shape = "diamond";
@@ -316,14 +317,14 @@ struct ShowWorker
shape = "octagon";
if (it.first[0] == '\\') {
fprintf(f, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
- id2num(it.first), shape, findLabel(it.first),
+ id2num(it.first), shape, findLabel(it.first.str()),
nextColor(RTLIL::SigSpec(it.second), "color=\"black\"").c_str());
if (it.second->port_input)
all_sources.insert(stringf("n%d", id2num(it.first)));
else if (it.second->port_output)
all_sinks.insert(stringf("n%d", id2num(it.first)));
} else {
- wires_on_demand[stringf("n%d", id2num(it.first))] = it.first;
+ wires_on_demand[stringf("n%d", id2num(it.first))] = it.first.str();
}
}
@@ -340,38 +341,43 @@ struct ShowWorker
fprintf(f, "}\n");
}
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (!design->selected_member(module->name, it.first))
continue;
std::vector<RTLIL::IdString> in_ports, out_ports;
- for (auto &conn : it.second->connections) {
+ for (auto &conn : it.second->connections()) {
if (!ct.cell_output(it.second->type, conn.first))
in_ports.push_back(conn.first);
else
out_ports.push_back(conn.first);
}
+ std::sort(in_ports.begin(), in_ports.end(), RTLIL::sort_by_id_str());
+ std::sort(out_ports.begin(), out_ports.end(), RTLIL::sort_by_id_str());
+
std::string label_string = "{{";
for (auto &p : in_ports)
- label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ label_string += stringf("<p%d> %s%s|", id2num(p), escape(p.str()),
+ genSignedLabels && it.second->hasParam(p.str() + "_SIGNED") &&
+ it.second->getParam(p.str() + "_SIGNED").as_bool() ? "*" : "");
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
- label_string += stringf("}|%s\\n%s|{", findLabel(it.first), escape(it.second->type));
+ label_string += stringf("}|%s\\n%s|{", findLabel(it.first.str()), escape(it.second->type.str()));
for (auto &p : out_ports)
- label_string += stringf("<p%d> %s|", id2num(p), escape(p));
+ label_string += stringf("<p%d> %s|", id2num(p), escape(p.str()));
if (label_string[label_string.size()-1] == '|')
label_string = label_string.substr(0, label_string.size()-1);
label_string += "}}";
std::string code;
- for (auto &conn : it.second->connections) {
+ for (auto &conn : it.second->connections()) {
code += gen_portbox(stringf("c%d:p%d", id2num(it.first), id2num(conn.first)),
conn.second, ct.cell_output(it.second->type, conn.first));
}
@@ -383,7 +389,7 @@ struct ShowWorker
else
#endif
fprintf(f, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
- id2num(it.first), label_string.c_str(), findColor(it.first), code.c_str());
+ id2num(it.first), label_string.c_str(), findColor(it.first.str()), code.c_str());
}
for (auto &it : module->processes)
@@ -405,7 +411,7 @@ struct ShowWorker
code += gen_portbox("", sig, false, &node);
fprintf(f, "%s", code.c_str());
net_conn_map[node].out.insert(stringf("p%d", pidx));
- net_conn_map[node].bits = sig.width;
+ net_conn_map[node].bits = sig.size();
net_conn_map[node].color = nextColor(sig, net_conn_map[node].color);
}
@@ -414,25 +420,25 @@ struct ShowWorker
code += gen_portbox("", sig, true, &node);
fprintf(f, "%s", code.c_str());
net_conn_map[node].in.insert(stringf("p%d", pidx));
- net_conn_map[node].bits = sig.width;
+ net_conn_map[node].bits = sig.size();
net_conn_map[node].color = nextColor(sig, net_conn_map[node].color);
}
std::string proc_src = RTLIL::unescape_id(proc->name);
if (proc->attributes.count("\\src") > 0)
proc_src = proc->attributes.at("\\src").decode_string();
- fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx, findLabel(proc->name), proc_src.c_str());
+ fprintf(f, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx, findLabel(proc->name.str()), proc_src.c_str());
}
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections())
{
bool found_lhs_wire = false;
- for (auto &c : conn.first.chunks) {
+ for (auto &c : conn.first.chunks()) {
if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
found_lhs_wire = true;
}
bool found_rhs_wire = false;
- for (auto &c : conn.second.chunks) {
+ for (auto &c : conn.second.chunks()) {
if (c.wire == NULL || design->selected_member(module->name, c.wire->name))
found_rhs_wire = true;
}
@@ -446,11 +452,11 @@ 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.width).c_str());
+ 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.width;
+ 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.width;
+ net_conn_map[left_node].bits = conn.first.size();
net_conn_map[left_node].color = nextColor(conn, net_conn_map[left_node].color);
if (left_node[0] == 'x') {
net_conn_map[right_node].in.insert(left_node);
@@ -487,15 +493,15 @@ struct ShowWorker
fprintf(f, "%s:e -> %s:w [%s, %s];\n", it.first.c_str(), it2.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str());
}
- fprintf(f, "};\n");
+ fprintf(f, "}\n");
}
- ShowWorker(FILE *f, RTLIL::Design *design, std::vector<RTLIL::Design*> &libs, uint32_t colorSeed,
- bool genWidthLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle,
+ 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) :
f(f), design(design), currentColor(colorSeed), genWidthLabels(genWidthLabels),
- stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
+ genSignedLabels(genSignedLabels), stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
notitle(notitle), color_selections(color_selections), label_selections(label_selections)
{
ct.setup_internals();
@@ -509,7 +515,7 @@ struct ShowWorker
design->optimize();
page_counter = 0;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
module = mod_it.second;
if (!design->selected_module(module->name))
@@ -519,7 +525,7 @@ struct ShowWorker
log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue;
} else
- if (module->cells.empty() && module->connections.empty() && module->processes.empty()) {
+ if (module->cells_.empty() && module->connections().empty() && module->processes.empty()) {
log("Skipping empty module %s.\n", id2cstr(module->name));
continue;
} else
@@ -575,6 +581,10 @@ struct ShowPass : public Pass {
log(" -width\n");
log(" annotate busses with a label indicating the width of the bus.\n");
log("\n");
+ log(" -signed\n");
+ log(" mark ports (A, B) that are declarted as signed (using the [AB]_SIGNED\n");
+ log(" cell parameter) with an asterisk next to the port name.\n");
+ log("\n");
log(" -stretch\n");
log(" stretch the graph so all inputs are on the left side and all outputs\n");
log(" (including inout ports) are on the right side.\n");
@@ -591,8 +601,8 @@ struct ShowPass : public Pass {
log(" -notitle\n");
log(" do not add the module name as graph title to the dot file\n");
log("\n");
- log("When no <format> is specified, SVG is used. When no <format> and <viewer> is\n");
- log("specified, 'yosys-svgviewer' is used to display the schematic.\n");
+ log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
+ log("specified, 'xdot' is used to display the schematic.\n");
log("\n");
log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
log("unless another prefix is specified using -prefix <prefix>.\n");
@@ -613,6 +623,7 @@ struct ShowPass : public Pass {
std::vector<RTLIL::Design*> libs;
uint32_t colorSeed = 0;
bool flag_width = false;
+ bool flag_signed = false;
bool flag_stretch = false;
bool flag_pause = false;
bool flag_enum = false;
@@ -655,6 +666,8 @@ struct ShowPass : public Pass {
}
if (arg == "-colors" && argidx+1 < args.size()) {
colorSeed = atoi(args[++argidx].c_str());
+ for (int i = 0; i < 100; i++)
+ colorSeed = ShowWorker::xorshift32(colorSeed);
continue;
}
if (arg == "-format" && argidx+1 < args.size()) {
@@ -665,6 +678,10 @@ struct ShowPass : public Pass {
flag_width= true;
continue;
}
+ if (arg == "-signed") {
+ flag_signed= true;
+ continue;
+ }
if (arg == "-stretch") {
flag_stretch= true;
continue;
@@ -693,10 +710,10 @@ struct ShowPass : public Pass {
if (format != "ps") {
int modcount = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox"))
continue;
- if (mod_it.second->cells.empty() && mod_it.second->connections.empty())
+ if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
continue;
if (design->selected_module(mod_it.first))
modcount++;
@@ -706,13 +723,13 @@ struct ShowPass : public Pass {
}
for (auto filename : libfiles) {
- FILE *f = fopen(filename.c_str(), "rt");
- if (f == NULL)
+ std::ifstream f;
+ f.open(filename.c_str());
+ if (f.fail())
log_error("Can't open lib file `%s'.\n", filename.c_str());
RTLIL::Design *lib = new RTLIL::Design;
- Frontend::frontend_call(lib, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
libs.push_back(lib);
- fclose(f);
}
if (libs.size() > 0)
@@ -728,7 +745,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_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);
fclose(f);
for (auto lib : libs)
@@ -737,8 +754,8 @@ struct ShowPass : public Pass {
if (worker.page_counter == 0)
log_cmd_error("Nothing there to show.\n");
- if (format != "dot") {
- std::string cmd = stringf("dot -T%s -o '%s' '%s'", format.empty() ? "svg" : format.c_str(), out_file.c_str(), dot_file.c_str());
+ 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());
log("Exec: %s\n", cmd.c_str());
if (system(cmd.c_str()) != 0)
log_cmd_error("Shell command failed!\n");
@@ -751,13 +768,14 @@ struct ShowPass : public Pass {
log_cmd_error("Shell command failed!\n");
} else
if (format.empty()) {
- std::string cmd = stringf("fuser -s '%s' || '%s' '%s' &", out_file.c_str(), rewrite_yosys_exe("yosys-svgviewer").c_str(), out_file.c_str());
+ std::string cmd = stringf("fuser -s '%s' || xdot '%s' < '%s' &", 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)
log_cmd_error("Shell command failed!\n");
}
if (flag_pause) {
+ #ifdef YOSYS_ENABLE_READLINE
char *input = NULL;
while ((input = readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL) {
if (input[strspn(input, " \t\r\n")] == 0)
@@ -768,6 +786,9 @@ struct ShowPass : public Pass {
break;
}
}
+ #else
+ log_cmd_error("This version of yosys is built without readline support => 'show -pause' is not available.\n");
+ #endif
}
log_pop();
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 6d920dbc5..d03aaf3b5 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -33,8 +33,8 @@ struct SpliceWorker
bool sel_by_wire;
bool sel_any_bit;
bool no_outputs;
- std::set<std::string> ports;
- std::set<std::string> no_ports;
+ std::set<RTLIL::IdString> ports;
+ std::set<RTLIL::IdString> no_ports;
CellTypes ct;
SigMap sigmap;
@@ -52,7 +52,7 @@ struct SpliceWorker
RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig)
{
- if (sig.width == 0 || sig.is_fully_const())
+ if (sig.size() == 0 || sig.is_fully_const())
return sig;
if (sliced_signals_cache.count(sig))
@@ -69,20 +69,16 @@ struct SpliceWorker
RTLIL::SigSpec new_sig = sig;
- if (sig_a.width != sig.width) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$slice";
+ if (sig_a.size() != sig.size()) {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$slice");
cell->parameters["\\OFFSET"] = offset;
- cell->parameters["\\A_WIDTH"] = sig_a.width;
- cell->parameters["\\Y_WIDTH"] = sig.width;
- cell->connections["\\A"] = sig_a;
- cell->connections["\\Y"] = module->new_wire(sig.width, NEW_ID);
- new_sig = cell->connections["\\Y"];
- module->add(cell);
+ cell->parameters["\\A_WIDTH"] = sig_a.size();
+ cell->parameters["\\Y_WIDTH"] = sig.size();
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\Y", module->addWire(NEW_ID, sig.size()));
+ new_sig = cell->getPort("\\Y");
}
- new_sig.optimize();
sliced_signals_cache[sig] = new_sig;
return new_sig;
@@ -90,7 +86,7 @@ struct SpliceWorker
RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig)
{
- if (sig.width == 0 || sig.is_fully_const())
+ if (sig.size() == 0 || sig.is_fully_const())
return sig;
if (spliced_signals_cache.count(sig))
@@ -131,19 +127,15 @@ struct SpliceWorker
RTLIL::SigSpec new_sig = get_sliced_signal(chunks.front());
for (size_t i = 1; i < chunks.size(); i++) {
RTLIL::SigSpec sig2 = get_sliced_signal(chunks[i]);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$concat";
- cell->parameters["\\A_WIDTH"] = new_sig.width;
- cell->parameters["\\B_WIDTH"] = sig2.width;
- cell->connections["\\A"] = new_sig;
- cell->connections["\\B"] = sig2;
- cell->connections["\\Y"] = module->new_wire(new_sig.width + sig2.width, NEW_ID);
- new_sig = cell->connections["\\Y"];
- module->add(cell);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$concat");
+ cell->parameters["\\A_WIDTH"] = new_sig.size();
+ cell->parameters["\\B_WIDTH"] = sig2.size();
+ cell->setPort("\\A", new_sig);
+ cell->setPort("\\B", sig2);
+ cell->setPort("\\Y", module->addWire(NEW_ID, new_sig.size() + sig2.size()));
+ new_sig = cell->getPort("\\Y");
}
- new_sig.optimize();
spliced_signals_cache[sig] = new_sig;
log(" Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig));
@@ -157,7 +149,7 @@ struct SpliceWorker
driven_bits.push_back(RTLIL::State::Sm);
driven_bits.push_back(RTLIL::State::Sm);
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input) {
RTLIL::SigSpec sig = sigmap(it.second);
driven_chunks.insert(sig);
@@ -166,8 +158,8 @@ struct SpliceWorker
driven_bits.push_back(RTLIL::State::Sm);
}
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections)
+ for (auto &it : module->cells_)
+ for (auto &conn : it.second->connections())
if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) {
RTLIL::SigSpec sig = sigmap(conn.second);
driven_chunks.insert(sig);
@@ -183,14 +175,14 @@ struct SpliceWorker
SigPool selected_bits;
if (!sel_by_cell)
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second))
selected_bits.add(sigmap(it.second));
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (!sel_by_wire && !design->selected(module, it.second))
continue;
- for (auto &conn : it.second->connections)
+ for (auto &conn : it.second->connections_)
if (ct.cell_input(it.second->type, conn.first)) {
if (ports.size() > 0 && !ports.count(conn.first))
continue;
@@ -211,7 +203,7 @@ struct SpliceWorker
std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (!no_outputs && it.second->port_output) {
if (!design->selected(module, it.second))
continue;
@@ -232,15 +224,15 @@ struct SpliceWorker
for (auto &it : rework_wires)
{
- module->wires.erase(it.first->name);
- RTLIL::Wire *new_port = new RTLIL::Wire(*it.first);
- it.first->name = NEW_ID;
+ RTLIL::IdString orig_name = it.first->name;
+ module->rename(it.first, NEW_ID);
+
+ RTLIL::Wire *new_port = module->addWire(orig_name, it.first);
it.first->port_id = 0;
it.first->port_input = false;
it.first->port_output = false;
- module->add(it.first);
- module->add(new_port);
- module->connections.push_back(RTLIL::SigSig(new_port, it.second));
+
+ module->connect(RTLIL::SigSig(new_port, it.second));
}
}
};
@@ -259,12 +251,12 @@ struct SplicePass : public Pass {
log("\n");
log(" -sel_by_cell\n");
log(" only select the cell ports to rewire by the cell. if the selection\n");
- log(" contains a cell, than all cell inputs are rewired, if neccessary.\n");
+ log(" contains a cell, than all cell inputs are rewired, if necessary.\n");
log("\n");
log(" -sel_by_wire\n");
log(" only select the cell ports to rewire by the wire. if the selection\n");
log(" contains a wire, than all cell ports driven by this wire are wired,\n");
- log(" if neccessary.\n");
+ log(" if necessary.\n");
log("\n");
log(" -sel_any_bit\n");
log(" it is sufficient if the driver of any bit of a cell port is selected.\n");
@@ -291,7 +283,7 @@ struct SplicePass : public Pass {
bool sel_by_wire = false;
bool sel_any_bit = false;
bool no_outputs = false;
- std::set<std::string> ports, no_ports;
+ std::set<RTLIL::IdString> ports, no_ports;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -335,7 +327,7 @@ struct SplicePass : public Pass {
log_header("Executing SPLICE pass (creating cells for signal splicing).\n");
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index da9ef43f9..344b03fc2 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -28,33 +28,28 @@ struct SplitnetsWorker
void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format)
{
- RTLIL::Wire *new_wire = new RTLIL::Wire;
-
- new_wire->port_id = wire->port_id;
- new_wire->port_input = wire->port_input;
- new_wire->port_output = wire->port_output;
- new_wire->name = wire->name;
- new_wire->width = width;
+ std::string new_wire_name = wire->name.str();
if (format.size() > 0)
- new_wire->name += format.substr(0, 1);
+ new_wire_name += format.substr(0, 1);
if (width > 1) {
- new_wire->name += stringf("%d", offset+width-1);
+ new_wire_name += stringf("%d", offset+width-1);
if (format.size() > 2)
- new_wire->name += format.substr(2, 1);
+ new_wire_name += format.substr(2, 1);
else
- new_wire->name += ":";
+ new_wire_name += ":";
}
- new_wire->name += stringf("%d", offset);
+ new_wire_name += stringf("%d", offset);
if (format.size() > 1)
- new_wire->name += format.substr(1, 1);
+ new_wire_name += format.substr(1, 1);
- while (module->count_id(new_wire->name) > 0)
- new_wire->name = new_wire->name + "_";
- module->add(new_wire);
+ RTLIL::Wire *new_wire = module->addWire(module->uniquify(new_wire_name), width);
+ new_wire->port_id = wire->port_id;
+ new_wire->port_input = wire->port_input;
+ new_wire->port_output = wire->port_output;
std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end());
@@ -62,11 +57,9 @@ struct SplitnetsWorker
void operator()(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks)
- if (splitmap.count(c.wire) > 0)
- c = splitmap.at(c.wire).at(c.offset);
- sig.optimize();
+ for (auto &bit : sig)
+ if (splitmap.count(bit.wire) > 0)
+ bit = splitmap.at(bit.wire).at(bit.offset);
}
};
@@ -83,7 +76,7 @@ struct SplitnetsPass : public Pass {
log(" -format char1[char2[char3]]\n");
log(" the first char is inserted between the net name and the bit index, the\n");
log(" second char is appended to the netname. e.g. -format () creates net\n");
- log(" names like 'mysignal(42)'. the 3rd character is the range seperation\n");
+ log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
log(" character when creating multi-bit wires. the default is '[]:'.\n");
log("\n");
log(" -ports\n");
@@ -121,7 +114,7 @@ struct SplitnetsPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
@@ -135,16 +128,16 @@ struct SplitnetsPass : public Pass {
std::map<RTLIL::Wire*, std::set<int>> split_wires_at;
- for (auto &c : module->cells)
- for (auto &p : c.second->connections)
+ for (auto &c : module->cells_)
+ for (auto &p : c.second->connections())
{
if (!ct.cell_known(c.second->type))
continue;
if (!ct.cell_output(c.second->type, p.first))
continue;
- RTLIL::SigSpec sig = p.second.optimized();
- for (auto &chunk : sig.chunks) {
+ RTLIL::SigSpec sig = p.second;
+ for (auto &chunk : sig.chunks()) {
if (chunk.wire == NULL)
continue;
if (chunk.wire->port_id == 0 || flag_ports) {
@@ -167,9 +160,9 @@ struct SplitnetsPass : public Pass {
}
else
{
- for (auto &w : module->wires) {
+ for (auto &w : module->wires_) {
RTLIL::Wire *wire = w.second;
- if (wire->width > 1 && (wire->port_id == 0 || flag_ports))
+ if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, w.second))
worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
}
@@ -180,10 +173,10 @@ struct SplitnetsPass : public Pass {
module->rewrite_sigspecs(worker);
- for (auto &it : worker.splitmap) {
- module->wires.erase(it.first->name);
- delete it.first;
- }
+ std::set<RTLIL::Wire*> delete_wires;
+ for (auto &it : worker.splitmap)
+ delete_wires.insert(it.first);
+ module->remove(delete_wires);
module->fixup_ports();
}
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 834770071..19cdaa621 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -63,13 +63,13 @@ namespace
#undef X
}
- statdata_t(RTLIL::Design *design, RTLIL::Module *mod)
+ statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
{
#define X(_name) _name = 0;
STAT_INT_MEMBERS
#undef X
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
{
if (!design->selected(mod, it.second))
continue;
@@ -90,11 +90,35 @@ namespace
num_memory_bits += it.second->width * it.second->size;
}
- for (auto &it : mod->cells) {
+ for (auto &it : mod->cells_)
+ {
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")));
+ }
+
num_cells++;
- num_cells_by_type[it.second->type]++;
+ num_cells_by_type[cell_type]++;
}
for (auto &it : mod->processes) {
@@ -154,28 +178,37 @@ struct StatPass : public Pass {
log(" selected and a module has the 'top' attribute set, this module is used\n");
log(" default value for this option.\n");
log("\n");
+ log(" -width\n");
+ log(" annotate internal cell types with their word width.\n");
+ log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Printing statistics.\n");
+ bool width_mode = false;
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
+ if (args[argidx] == "-width") {
+ width_mode = true;
+ continue;
+ }
if (args[argidx] == "-top" && argidx+1 < args.size()) {
- if (design->modules.count(RTLIL::escape_id(args[argidx+1])) == 0)
+ if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
- top_mod = design->modules.at(RTLIL::escape_id(args[++argidx]));
+ top_mod = design->modules_.at(RTLIL::escape_id(args[++argidx]));
continue;
}
break;
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
if (!design->selected_module(it.first))
continue;
@@ -184,7 +217,7 @@ struct StatPass : public Pass {
if (it.second->get_bool_attribute("\\top"))
top_mod = it.second;
- statdata_t data(design, it.second);
+ statdata_t data(design, it.second, width_mode);
mod_stat[it.first] = data;
log("\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
new file mode 100644
index 000000000..6f80ef72c
--- /dev/null
+++ b/passes/cmds/tee.cc
@@ -0,0 +1,88 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.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/rtlil.h"
+#include "kernel/log.h"
+
+struct TeePass : public Pass {
+ TeePass() : Pass("tee", "redirect command output to file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" tee [-q] [-o logfile|-a logfile] cmd\n");
+ log("\n");
+ log("Execute the specified command, optionally writing the commands output to the\n");
+ log("specified logfile(s).\n");
+ log("\n");
+ log(" -q\n");
+ log(" Do not print output to the normal destination (console and/or log file)\n");
+ log("\n");
+ log(" -o logfile\n");
+ log(" Write output to this file, truncate if exists.\n");
+ log("\n");
+ log(" -a logfile\n");
+ log(" Write output to this file, append if exists.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::vector<FILE*> backup_log_files, files_to_close;
+ backup_log_files = log_files;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-q" && files_to_close.empty()) {
+ log_files.clear();
+ continue;
+ }
+ if ((args[argidx] == "-o" || args[argidx] == "-a") && argidx+1 < args.size()) {
+ const char *open_mode = args[argidx] == "-o" ? "w" : "a+";
+ FILE *f = fopen(args[++argidx].c_str(), open_mode);
+ if (f == NULL) {
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
+ }
+ log_files.push_back(f);
+ files_to_close.push_back(f);
+ continue;
+ }
+ break;
+ }
+
+ try {
+ std::vector<std::string> new_args(args.begin() + argidx, args.end());
+ Pass::call(design, new_args);
+ } catch (log_cmd_error_expection) {
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_files = backup_log_files;
+ throw log_cmd_error_expection();
+ }
+
+ for (auto cf : files_to_close)
+ fclose(cf);
+ log_files = backup_log_files;
+ }
+} TeePass;
+
diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc
new file mode 100644
index 000000000..09293a86b
--- /dev/null
+++ b/passes/cmds/trace.cc
@@ -0,0 +1,97 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.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"
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct TraceMonitor : public RTLIL::Monitor
+{
+ virtual void notify_module_add(RTLIL::Module *module) OVERRIDE
+ {
+ log("#TRACE# Module add: %s\n", log_id(module));
+ }
+
+ virtual void notify_module_del(RTLIL::Module *module) 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
+ {
+ 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
+ {
+ 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
+ {
+ 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
+ {
+ log("#TRACE# Blackout in module %s:\n", log_id(module));
+ }
+};
+
+struct TracePass : public Pass {
+ TracePass() : Pass("trace", "redirect command output to file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" trace cmd\n");
+ log("\n");
+ log("Execute the specified command, logging all changes the command performs on\n");
+ log("the design in real time.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // .. parse options ..
+ break;
+ }
+
+ TraceMonitor monitor;
+ design->monitors.insert(&monitor);
+
+ try {
+ std::vector<std::string> new_args(args.begin() + argidx, args.end());
+ Pass::call(design, new_args);
+ } catch (log_cmd_error_expection) {
+ design->monitors.erase(&monitor);
+ throw log_cmd_error_expection();
+ }
+
+ design->monitors.erase(&monitor);
+ }
+} TracePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc
new file mode 100644
index 000000000..813e215ba
--- /dev/null
+++ b/passes/cmds/write_file.cc
@@ -0,0 +1,76 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.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"
+
+struct WriteFileFrontend : public Frontend {
+ WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_file [options] output_file [input_file]\n");
+ log("\n");
+ log("Write the text fron the input file to the output file.\n");
+ log("\n");
+ log(" -a\n");
+ log(" Append to output file (instead of overwriting)\n");
+ log("\n");
+ log("\n");
+ log("Inside a script the input file can also can a here-document:\n");
+ log("\n");
+ log(" write_file hello.txt <<EOT\n");
+ log(" Hello World!\n");
+ log(" EOT\n");
+ log("\n");
+ }
+ virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*)
+ {
+ bool append_mode = false;
+ std::string output_filename;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-a") {
+ append_mode = true;
+ continue;
+ }
+ break;
+ }
+
+ if (argidx < args.size() && args[argidx].rfind("-", 0) != 0)
+ output_filename = args[argidx++];
+ else
+ log_cmd_error("Missing putput filename.\n");
+
+ extra_args(f, filename, args, argidx);
+
+ FILE *of = fopen(output_filename.c_str(), append_mode ? "a" : "w");
+ char buffer[64 * 1024];
+ size_t bytes;
+
+ while (0 < (bytes = f->readsome(buffer, sizeof(buffer))))
+ fwrite(buffer, bytes, 1, of);
+
+ fclose(of);
+ }
+} WriteFileFrontend;
+
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 13e90910b..2fae76091 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -127,12 +127,12 @@ struct FsmPass : public Pass {
Pass::call(design, "fsm_recode" + fm_set_fsm_file_opt + encoding_opt);
Pass::call(design, "fsm_info");
- if (!flag_nomap)
- Pass::call(design, "fsm_map");
-
if (flag_export)
Pass::call(design, "fsm_export");
+ if (!flag_nomap)
+ Pass::call(design, "fsm_map");
+
log_pop();
}
} FsmPass;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index a8ec19126..2c846a4cf 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -26,7 +26,7 @@
static RTLIL::Module *module;
static SigMap assign_map;
-typedef std::pair<RTLIL::Cell*,std::string> sig2driver_entry_t;
+typedef std::pair<RTLIL::Cell*, RTLIL::IdString> sig2driver_entry_t;
static SigSet<sig2driver_entry_t> sig2driver, sig2user;
static std::set<RTLIL::Cell*> muxtree_cells;
static SigPool sig_at_port;
@@ -50,14 +50,14 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, Sig
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
for (auto &cellport : cellport_list) {
- if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux" && cellport.first->type != "$safe_pmux") || cellport.second != "\\Y")
+ if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y")
return false;
- RTLIL::SigSpec sig_a = assign_map(cellport.first->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cellport.first->connections["\\B"]);
+ RTLIL::SigSpec sig_a = assign_map(cellport.first->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B"));
if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor))
return false;
- for (int i = 0; i < sig_b.width; i += sig_a.width)
- if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.width), recursion_monitor))
+ for (int i = 0; i < sig_b.size(); i += sig_a.size())
+ if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor))
return false;
muxtree_cells.insert(cellport.first);
}
@@ -80,14 +80,14 @@ static bool check_state_users(RTLIL::SigSpec sig)
continue;
if (cellport.second != "\\A" && cellport.second != "\\B")
return false;
- if (cell->connections.count("\\A") == 0 || cell->connections.count("\\B") == 0 || cell->connections.count("\\Y") == 0)
+ if (!cell->hasPort("\\A") || !cell->hasPort("\\B") || !cell->hasPort("\\Y"))
return false;
- for (auto &port_it : cell->connections)
+ for (auto &port_it : cell->connections())
if (port_it.first != "\\A" && port_it.first != "\\B" && port_it.first != "\\Y")
return false;
- if (assign_map(cell->connections["\\A"]) == sig && cell->connections["\\B"].is_fully_const())
+ if (assign_map(cell->getPort("\\A")) == sig && cell->getPort("\\B").is_fully_const())
continue;
- if (assign_map(cell->connections["\\B"]) == sig && cell->connections["\\A"].is_fully_const())
+ if (assign_map(cell->getPort("\\B")) == sig && cell->getPort("\\A").is_fully_const())
continue;
return false;
}
@@ -109,8 +109,8 @@ static void detect_fsm(RTLIL::Wire *wire)
continue;
muxtree_cells.clear();
SigPool recursion_monitor;
- RTLIL::SigSpec sig_q = assign_map(cellport.first->connections["\\Q"]);
- RTLIL::SigSpec sig_d = assign_map(cellport.first->connections["\\D"]);
+ RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q"));
+ RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D"));
if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d, recursion_monitor) && check_state_users(sig_q)) {
log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str());
wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
@@ -148,7 +148,7 @@ struct FsmDetectPass : public Pass {
ct.setup_stdcells();
ct.setup_stdcells_mem();
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -159,8 +159,8 @@ struct FsmDetectPass : public Pass {
sig2driver.clear();
sig2user.clear();
sig_at_port.clear();
- for (auto &cell_it : module->cells)
- for (auto &conn_it : cell_it.second->connections) {
+ for (auto &cell_it : module->cells_)
+ for (auto &conn_it : cell_it.second->connections()) {
if (ct.cell_output(cell_it.second->type, conn_it.first) || !ct.cell_known(cell_it.second->type)) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
@@ -173,11 +173,11 @@ struct FsmDetectPass : public Pass {
}
}
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (wire_it.second->port_id != 0)
sig_at_port.add(assign_map(RTLIL::SigSpec(wire_it.second)));
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (design->selected(module, wire_it.second))
detect_fsm(wire_it.second);
}
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index 5756b10c7..d13643911 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -30,50 +30,50 @@ struct FsmExpand
RTLIL::Module *module;
RTLIL::Cell *fsm_cell;
SigMap assign_map;
- SigSet<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> sig2driver, sig2user;
+ SigSet<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> sig2driver, sig2user;
CellTypes ct;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> merged_set;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> current_set;
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> no_candidate_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> merged_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> current_set;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> no_candidate_set;
bool already_optimized;
int limit_transitions;
bool is_cell_merge_candidate(RTLIL::Cell *cell)
{
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
- if (cell->connections.at("\\A").width < 2)
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ if (cell->getPort("\\A").size() < 2)
return true;
RTLIL::SigSpec new_signals;
- if (cell->connections.count("\\A") > 0)
- new_signals.append(assign_map(cell->connections["\\A"]));
- if (cell->connections.count("\\B") > 0)
- new_signals.append(assign_map(cell->connections["\\B"]));
- if (cell->connections.count("\\S") > 0)
- new_signals.append(assign_map(cell->connections["\\S"]));
- if (cell->connections.count("\\Y") > 0)
- new_signals.append(assign_map(cell->connections["\\Y"]));
+ if (cell->hasPort("\\A"))
+ new_signals.append(assign_map(cell->getPort("\\A")));
+ if (cell->hasPort("\\B"))
+ new_signals.append(assign_map(cell->getPort("\\B")));
+ if (cell->hasPort("\\S"))
+ new_signals.append(assign_map(cell->getPort("\\S")));
+ if (cell->hasPort("\\Y"))
+ new_signals.append(assign_map(cell->getPort("\\Y")));
new_signals.sort_and_unify();
new_signals.remove_const();
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN")));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT")));
- if (new_signals.width > 3)
+ if (new_signals.size() > 3)
return false;
- if (cell->connections.count("\\Y") > 0) {
- new_signals.append(assign_map(cell->connections["\\Y"]));
+ if (cell->hasPort("\\Y")) {
+ new_signals.append(assign_map(cell->getPort("\\Y")));
new_signals.sort_and_unify();
new_signals.remove_const();
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_IN"]));
- new_signals.remove(assign_map(fsm_cell->connections["\\CTRL_OUT"]));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_IN")));
+ new_signals.remove(assign_map(fsm_cell->getPort("\\CTRL_OUT")));
}
- if (new_signals.width > 2)
+ if (new_signals.size() > 2)
return false;
return true;
@@ -83,10 +83,10 @@ struct FsmExpand
{
std::vector<RTLIL::Cell*> cell_list;
- for (auto c : sig2driver.find(assign_map(fsm_cell->connections["\\CTRL_IN"])))
+ for (auto c : sig2driver.find(assign_map(fsm_cell->getPort("\\CTRL_IN"))))
cell_list.push_back(c);
- for (auto c : sig2user.find(assign_map(fsm_cell->connections["\\CTRL_OUT"])))
+ for (auto c : sig2user.find(assign_map(fsm_cell->getPort("\\CTRL_OUT"))))
cell_list.push_back(c);
current_set.clear();
@@ -94,7 +94,7 @@ struct FsmExpand
{
if (merged_set.count(c) > 0 || current_set.count(c) > 0 || no_candidate_set.count(c) > 0)
continue;
- for (auto &p : c->connections) {
+ for (auto &p : c->connections()) {
if (p.first != "\\A" && p.first != "\\B" && p.first != "\\S" && p.first != "\\Y")
goto next_cell;
}
@@ -135,7 +135,7 @@ struct FsmExpand
RTLIL::SigSpec input_sig, output_sig;
- for (auto &p : cell->connections)
+ for (auto &p : cell->connections())
if (ct.cell_output(cell->type, p.first))
output_sig.append(assign_map(p.second));
else
@@ -145,38 +145,42 @@ struct FsmExpand
std::vector<RTLIL::Const> truth_tab;
- for (int i = 0; i < (1 << input_sig.width); i++) {
- RTLIL::Const in_val(i, input_sig.width);
+ for (int i = 0; i < (1 << input_sig.size()); i++) {
+ RTLIL::Const in_val(i, input_sig.size());
RTLIL::SigSpec A, B, S;
- if (cell->connections.count("\\A") > 0)
- A = assign_map(cell->connections["\\A"]);
- if (cell->connections.count("\\B") > 0)
- B = assign_map(cell->connections["\\B"]);
- if (cell->connections.count("\\S") > 0)
- S = assign_map(cell->connections["\\S"]);
+ if (cell->hasPort("\\A"))
+ A = assign_map(cell->getPort("\\A"));
+ if (cell->hasPort("\\B"))
+ B = assign_map(cell->getPort("\\B"));
+ if (cell->hasPort("\\S"))
+ S = assign_map(cell->getPort("\\S"));
A.replace(input_sig, RTLIL::SigSpec(in_val));
B.replace(input_sig, RTLIL::SigSpec(in_val));
S.replace(input_sig, RTLIL::SigSpec(in_val));
- assert(A.is_fully_const());
- assert(B.is_fully_const());
- assert(S.is_fully_const());
+ log_assert(A.is_fully_const());
+ log_assert(B.is_fully_const());
+ log_assert(S.is_fully_const());
truth_tab.push_back(ct.eval(cell, A.as_const(), B.as_const(), S.as_const()));
}
FsmData fsm_data;
fsm_data.copy_from_cell(fsm_cell);
- fsm_data.num_inputs += input_sig.width;
- fsm_cell->connections["\\CTRL_IN"].append(input_sig);
+ fsm_data.num_inputs += input_sig.size();
+ RTLIL::SigSpec new_ctrl_in = fsm_cell->getPort("\\CTRL_IN");
+ new_ctrl_in.append(input_sig);
+ fsm_cell->setPort("\\CTRL_IN", new_ctrl_in);
- fsm_data.num_outputs += output_sig.width;
- fsm_cell->connections["\\CTRL_OUT"].append(output_sig);
+ fsm_data.num_outputs += output_sig.size();
+ RTLIL::SigSpec new_ctrl_out = fsm_cell->getPort("\\CTRL_OUT");
+ new_ctrl_out.append(output_sig);
+ fsm_cell->setPort("\\CTRL_OUT", new_ctrl_out);
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
- for (int i = 0; i < (1 << input_sig.width); i++) {
+ for (int i = 0; i < (1 << input_sig.size()); i++) {
FsmData::transition_t new_tr = tr;
- RTLIL::Const in_val(i, input_sig.width);
+ RTLIL::Const in_val(i, input_sig.size());
RTLIL::Const out_val = truth_tab[i];
RTLIL::SigSpec ctrl_in = new_tr.ctrl_in;
RTLIL::SigSpec ctrl_out = new_tr.ctrl_out;
@@ -201,10 +205,10 @@ struct FsmExpand
assign_map.set(module);
ct.setup_internals();
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *c = cell_it.second;
if (ct.cell_known(c->type) && design->selected(mod, c))
- for (auto &p : c->connections) {
+ for (auto &p : c->connections()) {
if (ct.cell_output(c->type, p.first))
sig2driver.insert(assign_map(p.second), c);
else
@@ -226,10 +230,8 @@ struct FsmExpand
merge_cell_into_fsm(c);
}
- for (auto c : merged_set) {
- module->cells.erase(c->name);
- delete c;
- }
+ for (auto c : merged_set)
+ module->remove(c);
if (merged_set.size() > 0 && !already_optimized)
FsmData::optimize_fsm(fsm_cell, module);
@@ -256,11 +258,11 @@ struct FsmExpandPass : public Pass {
log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
std::vector<RTLIL::Cell*> fsm_cells;
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_cells.push_back(cell_it.second);
for (auto c : fsm_cells) {
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index cc328ce34..b4a6b3f7b 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -32,10 +32,7 @@
* Convert a signal into a KISS-compatible textual representation.
*/
std::string kiss_convert_signal(const RTLIL::SigSpec &sig) {
- if (!sig.is_fully_const()) {
- throw 0;
- }
-
+ log_assert(sig.is_fully_const());
return sig.as_const().as_string();
}
@@ -59,13 +56,12 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st
attr_it = cell->attributes.find("\\fsm_export");
if (!filename.empty()) {
- kiss_name.assign(filename);
+ kiss_name.assign(filename);
} else if (attr_it != cell->attributes.end() && attr_it->second.decode_string() != "") {
kiss_name.assign(attr_it->second.decode_string());
}
else {
- kiss_name.assign(module->name);
- kiss_name.append('-' + cell->name + ".kiss2");
+ kiss_name.assign(log_id(module) + std::string("-") + log_id(cell) + ".kiss2");
}
log("\n");
@@ -174,9 +170,9 @@ struct FsmExportPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) {
attr_it = cell_it.second->attributes.find("\\fsm_export");
if (!flag_noauto || (attr_it != cell_it.second->attributes.end())) {
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index 9cba904a7..451f00fcb 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -31,56 +31,72 @@
static RTLIL::Module *module;
static SigMap assign_map;
-typedef std::pair<std::string, std::string> sig2driver_entry_t;
+typedef std::pair<RTLIL::IdString, RTLIL::IdString> sig2driver_entry_t;
static SigSet<sig2driver_entry_t> sig2driver, sig2trigger;
+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.width, false);
+ sig.extend(dff_out.size(), false);
if (sig == dff_out)
return true;
assign_map.apply(sig);
if (sig.is_fully_const()) {
- sig.optimize();
- assert(sig.chunks.size() == 1);
- if (states.count(sig.chunks[0].data) == 0) {
+ if (sig.is_fully_def() && states.count(sig.as_const()) == 0) {
log(" found state code: %s\n", log_signal(sig));
- states[sig.chunks[0].data] = -1;
+ states[sig.as_const()] = -1;
}
return true;
}
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
- for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || cellport.second != "\\Y") {
+ for (auto &cellport : cellport_list)
+ {
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ if ((cell->type != "$mux" && cell->type != "$pmux") || cellport.second != "\\Y") {
log(" unexpected cell type %s (%s) found in state selection tree.\n", cell->type.c_str(), cell->name.c_str());
return false;
}
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_s = assign_map(cell->connections["\\S"]);
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ RTLIL::SigSpec sig_aa = sig;
+ sig_aa.replace(sig_y, sig_a);
+
+ RTLIL::SigSpec sig_bb;
+ for (int i = 0; i < SIZE(sig_b)/SIZE(sig_a); i++) {
+ RTLIL::SigSpec s = sig;
+ s.replace(sig_y, sig_b.extract(i*SIZE(sig_a), SIZE(sig_a)));
+ sig_bb.append(s);
+ }
+
if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef())
do {
- if (sig_a.is_fully_def())
- *reset_state = sig_a.as_const();
- else if (sig_b.is_fully_def())
- *reset_state = sig_b.as_const();
+ if (sig_aa.is_fully_def())
+ *reset_state = sig_aa.as_const();
+ else if (sig_bb.is_fully_def())
+ *reset_state = sig_bb.as_const();
else
break;
log(" found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state));
} while (0);
- if (ctrl.extract(sig_s).width == 0) {
+
+ if (ctrl.extract(sig_s).size() == 0) {
log(" found ctrl input: %s\n", log_signal(sig_s));
ctrl.append(sig_s);
}
- if (!find_states(sig_a, dff_out, ctrl, states))
+
+ if (!find_states(sig_aa, dff_out, ctrl, states))
return false;
- for (int i = 0; i < sig_b.width/sig_a.width; i++) {
- if (!find_states(sig_b.extract(i*sig_a.width, sig_a.width), dff_out, ctrl, states))
+
+ 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))
return false;
}
}
@@ -90,47 +106,69 @@ 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.width > 0) {
- sig.expand();
- for (auto &chunk : sig.chunks) {
- assert(chunk.width == 1);
- if (dont_care.extract(chunk).width > 0)
- chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
- }
- sig.optimize();
+ if (dont_care.size() > 0) {
+ for (int i = 0; i < SIZE(sig); i++)
+ if (dont_care.extract(sig[i]).size() > 0)
+ sig[i] = noconst_state;
}
ce.assign_map.apply(sig);
ce.values_map.apply(sig);
- sig.expand();
- for (auto &chunk : sig.chunks) {
- assert(chunk.width == 1);
- if (chunk.wire != NULL)
- chunk.wire = NULL, chunk.data = RTLIL::Const(noconst_state);
- }
- sig.optimize();
+ for (int i = 0; i < SIZE(sig); i++)
+ if (sig[i].wire != NULL)
+ sig[i] = noconst_state;
- if (sig.width == 0)
- return RTLIL::Const();
- assert(sig.chunks.size() == 1 && sig.chunks[0].wire == NULL);
- return sig.chunks[0].data;
+ return sig.as_const();
}
static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_data, std::map<RTLIL::Const, int> &states, int state_in, RTLIL::SigSpec ctrl_in, RTLIL::SigSpec ctrl_out, RTLIL::SigSpec dff_in, RTLIL::SigSpec dont_care)
{
+ bool undef_bit_in_next_state_mode = false;
RTLIL::SigSpec undef, constval;
- if (ce.eval(ctrl_out, undef) && ce.eval(dff_in, undef)) {
- assert(ctrl_out.is_fully_const() && dff_in.is_fully_const());
+ if (ce.eval(ctrl_out, undef) && ce.eval(dff_in, undef))
+ {
+ if (0) {
+undef_bit_in_next_state:
+ for (auto &bit : dff_in)
+ if (bit.wire != nullptr) bit = RTLIL::Sm;
+ for (auto &bit : ctrl_out)
+ if (bit.wire != nullptr) bit = RTLIL::Sm;
+ undef_bit_in_next_state_mode = true;
+ }
+
+ log_assert(ctrl_out.is_fully_const() && dff_in.is_fully_const());
+
FsmData::transition_t tr;
- tr.state_in = state_in;
- tr.state_out = states[ce.values_map(ce.assign_map(dff_in)).as_const()];
tr.ctrl_in = sig2const(ce, ctrl_in, RTLIL::State::Sa, dont_care);
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++)
+ ctrl_in_bit_indices[ctrl_in[i]] = i;
+
+ for (auto &it : ctrl_in_bit_indices)
+ if (tr.ctrl_in.bits.at(it.second) == RTLIL::S1 && exclusive_ctrls.count(it.first) != 0)
+ for (auto &dc_bit : exclusive_ctrls.at(it.first))
+ if (ctrl_in_bit_indices.count(dc_bit))
+ tr.ctrl_in.bits.at(ctrl_in_bit_indices.at(dc_bit)) = RTLIL::State::Sa;
+
RTLIL::Const log_state_in = RTLIL::Const(RTLIL::State::Sx, fsm_data.state_bits);
if (state_in >= 0)
- log_state_in = fsm_data.state_table[tr.state_in];
+ log_state_in = fsm_data.state_table.at(state_in);
+
+ if (states.count(ce.values_map(ce.assign_map(dff_in)).as_const()) == 0) {
+ log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transistion!>%s\n",
+ log_signal(log_state_in), log_signal(tr.ctrl_in),
+ log_signal(ce.values_map(ce.assign_map(dff_in))), log_signal(tr.ctrl_out),
+ undef_bit_in_next_state_mode ? " SHORTENED" : "");
+ return;
+ }
+
+ tr.state_in = state_in;
+ tr.state_out = states.at(ce.values_map(ce.assign_map(dff_in)).as_const());
+
if (dff_in.is_fully_def()) {
fsm_data.transition_table.push_back(tr);
log(" transition: %10s %s -> %10s %s\n",
@@ -144,7 +182,11 @@ static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_d
return;
}
- log_assert(undef.width > 0);
+ for (auto &bit : dff_in)
+ if (bit == RTLIL::Sx)
+ goto undef_bit_in_next_state;
+
+ log_assert(undef.size() > 0);
log_assert(ce.stop_signals.check_all(undef));
undef = undef.extract(0, 1);
@@ -155,21 +197,39 @@ static void find_transitions(ConstEval &ce, ConstEval &ce_nostop, FsmData &fsm_d
ce.push();
dont_care.append(undef);
ce.set(undef, constval.as_const());
+ if (exclusive_ctrls.count(undef) && constval == RTLIL::S1)
+ for (auto &bit : exclusive_ctrls.at(undef)) {
+ RTLIL::SigSpec bitval = bit;
+ if (ce.eval(bitval) && bitval != RTLIL::S0)
+ goto found_contradiction_1;
+ else
+ ce.set(bit, RTLIL::S0);
+ }
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+ found_contradiction_1:
ce.pop();
}
else
{
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::Const(0, 1));
- ce_nostop.set(undef, RTLIL::Const(0, 1));
+ ce.set(undef, RTLIL::S0);
+ ce_nostop.set(undef, RTLIL::S0);
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
ce.pop(), ce_nostop.pop();
ce.push(), ce_nostop.push();
- ce.set(undef, RTLIL::Const(1, 1));
- ce_nostop.set(undef, RTLIL::Const(1, 1));
+ ce.set(undef, RTLIL::S1);
+ ce_nostop.set(undef, RTLIL::S1);
+ if (exclusive_ctrls.count(undef))
+ for (auto &bit : exclusive_ctrls.at(undef)) {
+ RTLIL::SigSpec bitval = bit;
+ if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != RTLIL::S0)
+ goto found_contradiction_2;
+ else
+ ce.set(bit, RTLIL::S0), ce_nostop.set(bit, RTLIL::S0);
+ }
find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care);
+ found_contradiction_2:
ce.pop(), ce_nostop.pop();
}
}
@@ -184,24 +244,24 @@ static void extract_fsm(RTLIL::Wire *wire)
RTLIL::SigSpec dff_in(RTLIL::State::Sm, wire->width);
RTLIL::Const reset_state(RTLIL::State::Sx, wire->width);
- RTLIL::SigSpec clk = RTLIL::SigSpec(0, 1);
- RTLIL::SigSpec arst = RTLIL::SigSpec(0, 1);
+ RTLIL::SigSpec clk = RTLIL::S0;
+ RTLIL::SigSpec arst = RTLIL::S0;
bool clk_polarity = true;
bool arst_polarity = true;
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(dff_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
if ((cell->type != "$dff" && cell->type != "$adff") || cellport.second != "\\Q")
continue;
log(" found %s cell for state register: %s\n", cell->type.c_str(), cell->name.c_str());
- RTLIL::SigSpec sig_q = assign_map(cell->connections["\\Q"]);
- RTLIL::SigSpec sig_d = assign_map(cell->connections["\\D"]);
- clk = cell->connections["\\CLK"];
+ RTLIL::SigSpec sig_q = assign_map(cell->getPort("\\Q"));
+ RTLIL::SigSpec sig_d = assign_map(cell->getPort("\\D"));
+ clk = cell->getPort("\\CLK");
clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
if (cell->type == "$adff") {
- arst = cell->connections["\\ARST"];
+ arst = cell->getPort("\\ARST");
arst_polarity = cell->parameters["\\ARST_POLARITY"].as_bool();
reset_state = cell->parameters["\\ARST_VALUE"];
}
@@ -227,6 +287,10 @@ static void extract_fsm(RTLIL::Wire *wire)
log(" fsm extraction failed: state selection tree is not closed.\n");
return;
}
+ if (SIZE(states) <= 1) {
+ log(" fsm extraction failed: at least two states are required.\n");
+ return;
+ }
// find control outputs
// (add the state signals to the list of control outputs. if everything goes right, this signals
@@ -236,10 +300,10 @@ static void extract_fsm(RTLIL::Wire *wire)
cellport_list.clear();
sig2trigger.find(dff_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_y = assign_map(cell->connections["\\Y"]);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
if (cellport.second == "\\A" && !sig_b.is_fully_const())
continue;
if (cellport.second == "\\B" && !sig_a.is_fully_const())
@@ -258,8 +322,8 @@ static void extract_fsm(RTLIL::Wire *wire)
// Initialize fsm data struct
FsmData fsm_data;
- fsm_data.num_inputs = ctrl_in.width;
- fsm_data.num_outputs = ctrl_out.width;
+ fsm_data.num_inputs = ctrl_in.size();
+ fsm_data.num_outputs = ctrl_out.size();
fsm_data.state_bits = wire->width;
fsm_data.reset_state = -1;
for (auto &it : states) {
@@ -283,40 +347,34 @@ static void extract_fsm(RTLIL::Wire *wire)
// create fsm cell
- RTLIL::Cell *fsm_cell = new RTLIL::Cell;
- fsm_cell->name = stringf("$fsm$%s$%d", wire->name.c_str(), RTLIL::autoidx++);
- fsm_cell->type = "$fsm";
- fsm_cell->connections["\\CLK"] = clk;
- fsm_cell->connections["\\ARST"] = arst;
- fsm_cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity ? 1 : 0, 1);
- fsm_cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity ? 1 : 0, 1);
- fsm_cell->connections["\\CTRL_IN"] = ctrl_in;
- fsm_cell->connections["\\CTRL_OUT"] = ctrl_out;
- fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name);
+ RTLIL::Cell *fsm_cell = module->addCell(stringf("$fsm$%s$%d", wire->name.c_str(), autoidx++), "$fsm");
+ fsm_cell->setPort("\\CLK", clk);
+ fsm_cell->setPort("\\ARST", arst);
+ fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? RTLIL::S1 : RTLIL::S0;
+ fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? RTLIL::S1 : RTLIL::S0;
+ fsm_cell->setPort("\\CTRL_IN", ctrl_in);
+ fsm_cell->setPort("\\CTRL_OUT", ctrl_out);
+ fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name.str());
fsm_cell->attributes = wire->attributes;
fsm_data.copy_to_cell(fsm_cell);
- module->cells[fsm_cell->name] = fsm_cell;
// rename original state wire
- module->wires.erase(wire->name);
+ module->wires_.erase(wire->name);
wire->attributes.erase("\\fsm_encoding");
wire->name = stringf("$fsm$oldstate%s", wire->name.c_str());
- module->wires[wire->name] = wire;
+ module->wires_[wire->name] = wire;
// unconnect control outputs from old drivers
cellport_list.clear();
sig2driver.find(ctrl_out, cellport_list);
for (auto &cellport : cellport_list) {
- RTLIL::Cell *cell = module->cells.at(cellport.first);
- RTLIL::SigSpec port_sig = assign_map(cell->connections[cellport.second]);
+ RTLIL::Cell *cell = module->cells_.at(cellport.first);
+ RTLIL::SigSpec port_sig = assign_map(cell->getPort(cellport.second));
RTLIL::SigSpec unconn_sig = port_sig.extract(ctrl_out);
- RTLIL::Wire *unconn_wire = new RTLIL::Wire;
- unconn_wire->name = stringf("$fsm_unconnect$%s$%d", log_signal(unconn_sig), RTLIL::autoidx++);
- unconn_wire->width = unconn_sig.width;
- module->wires[unconn_wire->name] = unconn_wire;
- port_sig.replace(unconn_sig, RTLIL::SigSpec(unconn_wire), &cell->connections[cellport.second]);
+ RTLIL::Wire *unconn_wire = module->addWire(stringf("$fsm_unconnect$%s$%d", log_signal(unconn_sig), autoidx++), unconn_sig.size());
+ port_sig.replace(unconn_sig, RTLIL::SigSpec(unconn_wire), &cell->connections_[cellport.second]);
}
}
@@ -349,7 +407,7 @@ struct FsmExtractPass : public Pass {
ct.setup_stdcells();
ct.setup_stdcells_mem();
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -359,23 +417,32 @@ struct FsmExtractPass : public Pass {
sig2driver.clear();
sig2trigger.clear();
- for (auto &cell_it : module->cells)
- for (auto &conn_it : cell_it.second->connections) {
- if (ct.cell_output(cell_it.second->type, conn_it.first) || !ct.cell_known(cell_it.second->type)) {
+ exclusive_ctrls.clear();
+ for (auto cell : module->cells()) {
+ for (auto &conn_it : cell->connections()) {
+ if (ct.cell_output(cell->type, conn_it.first) || !ct.cell_known(cell->type)) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
- sig2driver.insert(sig, sig2driver_entry_t(cell_it.first, conn_it.first));
+ sig2driver.insert(sig, sig2driver_entry_t(cell->name, conn_it.first));
}
- if (ct.cell_input(cell_it.second->type, conn_it.first) && cell_it.second->connections.count("\\Y") > 0 &&
- cell_it.second->connections["\\Y"].width == 1 && (conn_it.first == "\\A" || conn_it.first == "\\B")) {
+ if (ct.cell_input(cell->type, conn_it.first) && cell->hasPort("\\Y") &&
+ cell->getPort("\\Y").size() == 1 && (conn_it.first == "\\A" || conn_it.first == "\\B")) {
RTLIL::SigSpec sig = conn_it.second;
assign_map.apply(sig);
- sig2trigger.insert(sig, sig2driver_entry_t(cell_it.first, conn_it.first));
+ sig2trigger.insert(sig, sig2driver_entry_t(cell->name, conn_it.first));
}
}
+ if (cell->type == "$pmux") {
+ RTLIL::SigSpec sel_sig = assign_map(cell->getPort("\\S"));
+ for (auto &bit1 : sel_sig)
+ for (auto &bit2 : sel_sig)
+ if (bit1 != bit2)
+ exclusive_ctrls[bit1].insert(bit2);
+ }
+ }
std::vector<RTLIL::Wire*> wire_list;
- for (auto &wire_it : module->wires)
+ for (auto &wire_it : module->wires_)
if (wire_it.second->attributes.count("\\fsm_encoding") > 0 && wire_it.second->attributes["\\fsm_encoding"].decode_string() != "none")
if (design->selected(module, wire_it.second))
wire_list.push_back(wire_it.second);
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index f2d0c1a81..45d68a906 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -43,9 +43,9 @@ struct FsmInfoPass : public Pass {
log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second)) {
log("\n");
log("FSM `%s' from module `%s':\n", cell_it.second->name.c_str(), mod_it.first.c_str());
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index c30cf1fe7..ab6d5671d 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -25,12 +25,26 @@
#include "fsmdata.h"
#include <string.h>
+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++)
+ 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])
+ return false;
+ } else
+ return false;
+ }
+ return true;
+}
+
static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const, std::set<int>> &pattern_cache, std::set<int> &fullstate_cache, int num_states, RTLIL::Wire *state_onehot, RTLIL::SigSpec &ctrl_in, RTLIL::SigSpec output)
{
RTLIL::SigSpec cases_vector;
for (int in_state : fullstate_cache)
- cases_vector.append(RTLIL::SigSpec(state_onehot, 1, in_state));
+ cases_vector.append(RTLIL::SigSpec(state_onehot, in_state));
for (auto &it : pattern_cache)
{
@@ -42,89 +56,74 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
eq_sig_a.append(ctrl_in.extract(j, 1));
eq_sig_b.append(RTLIL::SigSpec(pattern.bits[j]));
}
- eq_sig_a.optimize();
- eq_sig_b.optimize();
for (int in_state : it.second)
if (fullstate_cache.count(in_state) == 0)
- or_sig.append(RTLIL::SigSpec(state_onehot, 1, in_state));
- or_sig.optimize();
+ or_sig.append(RTLIL::SigSpec(state_onehot, in_state));
- if (or_sig.width == 0)
+ if (or_sig.size() == 0)
continue;
RTLIL::SigSpec and_sig;
- if (eq_sig_a.width > 0)
+ if (eq_sig_a.size() > 0)
{
- RTLIL::Wire *eq_wire = new RTLIL::Wire;
- eq_wire->name = NEW_ID;
- module->add(eq_wire);
-
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eq";
- eq_cell->connections["\\A"] = eq_sig_a;
- eq_cell->connections["\\B"] = eq_sig_b;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(eq_wire);
+ RTLIL::Wire *eq_wire = module->addWire(NEW_ID);
+ and_sig.append(RTLIL::SigSpec(eq_wire));
+
+ RTLIL::Cell *eq_cell = module->addCell(NEW_ID, "$eq");
+ eq_cell->setPort("\\A", eq_sig_a);
+ eq_cell->setPort("\\B", eq_sig_b);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(eq_wire));
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(eq_sig_a.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(eq_sig_b.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(eq_sig_a.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(eq_sig_b.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(eq_cell);
-
- and_sig.append(RTLIL::SigSpec(eq_wire));
}
- if (or_sig.width < num_states-int(fullstate_cache.size()))
+ std::set<int> complete_in_state_cache = it.second;
+
+ for (auto &it2 : pattern_cache)
+ 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 (or_sig.width == 1)
+ if (or_sig.size() == 1)
{
and_sig.append(or_sig);
}
else
{
- RTLIL::Wire *or_wire = new RTLIL::Wire;
- or_wire->name = NEW_ID;
- module->add(or_wire);
-
- RTLIL::Cell *or_cell = new RTLIL::Cell;
- or_cell->name = NEW_ID;
- or_cell->type = "$reduce_or";
- or_cell->connections["\\A"] = or_sig;
- or_cell->connections["\\Y"] = RTLIL::SigSpec(or_wire);
+ RTLIL::Wire *or_wire = module->addWire(NEW_ID);
+ and_sig.append(RTLIL::SigSpec(or_wire));
+
+ RTLIL::Cell *or_cell = module->addCell(NEW_ID, "$reduce_or");
+ or_cell->setPort("\\A", or_sig);
+ or_cell->setPort("\\Y", RTLIL::SigSpec(or_wire));
or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
- or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(or_sig.width);
+ or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(or_sig.size());
or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(or_cell);
-
- and_sig.append(RTLIL::SigSpec(or_wire));
}
}
- switch (and_sig.width)
+ switch (and_sig.size())
{
case 2:
{
- RTLIL::Wire *and_wire = new RTLIL::Wire;
- and_wire->name = NEW_ID;
- module->add(and_wire);
-
- RTLIL::Cell *and_cell = new RTLIL::Cell;
- and_cell->name = NEW_ID;
- and_cell->type = "$and";
- and_cell->connections["\\A"] = and_sig.extract(0, 1);
- and_cell->connections["\\B"] = and_sig.extract(1, 1);
- and_cell->connections["\\Y"] = RTLIL::SigSpec(and_wire);
+ RTLIL::Wire *and_wire = module->addWire(NEW_ID);
+ cases_vector.append(RTLIL::SigSpec(and_wire));
+
+ RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$and");
+ and_cell->setPort("\\A", and_sig.extract(0, 1));
+ and_cell->setPort("\\B", and_sig.extract(1, 1));
+ and_cell->setPort("\\Y", RTLIL::SigSpec(and_wire));
and_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
and_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
and_cell->parameters["\\A_WIDTH"] = RTLIL::Const(1);
and_cell->parameters["\\B_WIDTH"] = RTLIL::Const(1);
and_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(and_cell);
-
- cases_vector.append(RTLIL::SigSpec(and_wire));
break;
}
case 1:
@@ -138,20 +137,17 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const
}
}
- if (cases_vector.width > 1) {
- RTLIL::Cell *or_cell = new RTLIL::Cell;
- or_cell->name = NEW_ID;
- or_cell->type = "$reduce_or";
- or_cell->connections["\\A"] = cases_vector;
- or_cell->connections["\\Y"] = output;
+ if (cases_vector.size() > 1) {
+ RTLIL::Cell *or_cell = module->addCell(NEW_ID, "$reduce_or");
+ or_cell->setPort("\\A", cases_vector);
+ or_cell->setPort("\\Y", output);
or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
- or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cases_vector.width);
+ or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cases_vector.size());
or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(or_cell);
- } else if (cases_vector.width == 1) {
- module->connections.push_back(RTLIL::SigSig(output, cases_vector));
+ } else if (cases_vector.size() == 1) {
+ module->connect(RTLIL::SigSig(output, cases_vector));
} else {
- module->connections.push_back(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
+ module->connect(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1)));
}
}
@@ -162,26 +158,16 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
FsmData fsm_data;
fsm_data.copy_from_cell(fsm_cell);
- RTLIL::SigSpec ctrl_in = fsm_cell->connections["\\CTRL_IN"];
- RTLIL::SigSpec ctrl_out = fsm_cell->connections["\\CTRL_OUT"];
+ RTLIL::SigSpec ctrl_in = fsm_cell->getPort("\\CTRL_IN");
+ RTLIL::SigSpec ctrl_out = fsm_cell->getPort("\\CTRL_OUT");
// create state register
- RTLIL::Wire *state_wire = new RTLIL::Wire;
- state_wire->name = fsm_cell->parameters["\\NAME"].decode_string();
- while (module->count_id(state_wire->name) > 0)
- state_wire->name += "_";
- state_wire->width = fsm_data.state_bits;
- module->add(state_wire);
-
- RTLIL::Wire *next_state_wire = new RTLIL::Wire;
- next_state_wire->name = NEW_ID;
- next_state_wire->width = fsm_data.state_bits;
- module->add(next_state_wire);
-
- RTLIL::Cell *state_dff = new RTLIL::Cell;
- state_dff->name = NEW_ID;
- if (fsm_cell->connections["\\ARST"].is_fully_const()) {
+ RTLIL::Wire *state_wire = module->addWire(module->uniquify(fsm_cell->parameters["\\NAME"].decode_string()), fsm_data.state_bits);
+ RTLIL::Wire *next_state_wire = module->addWire(NEW_ID, fsm_data.state_bits);
+
+ RTLIL::Cell *state_dff = module->addCell(NEW_ID, "");
+ if (fsm_cell->getPort("\\ARST").is_fully_const()) {
state_dff->type = "$dff";
} else {
state_dff->type = "$adff";
@@ -190,23 +176,19 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
for (auto &bit : state_dff->parameters["\\ARST_VALUE"].bits)
if (bit != RTLIL::State::S1)
bit = RTLIL::State::S0;
- state_dff->connections["\\ARST"] = fsm_cell->connections["\\ARST"];
+ state_dff->setPort("\\ARST", fsm_cell->getPort("\\ARST"));
}
state_dff->parameters["\\WIDTH"] = RTLIL::Const(fsm_data.state_bits);
state_dff->parameters["\\CLK_POLARITY"] = fsm_cell->parameters["\\CLK_POLARITY"];
- state_dff->connections["\\CLK"] = fsm_cell->connections["\\CLK"];
- state_dff->connections["\\D"] = RTLIL::SigSpec(next_state_wire);
- state_dff->connections["\\Q"] = RTLIL::SigSpec(state_wire);
- module->add(state_dff);
+ state_dff->setPort("\\CLK", fsm_cell->getPort("\\CLK"));
+ state_dff->setPort("\\D", RTLIL::SigSpec(next_state_wire));
+ state_dff->setPort("\\Q", RTLIL::SigSpec(state_wire));
// decode state register
bool encoding_is_onehot = true;
- RTLIL::Wire *state_onehot = new RTLIL::Wire;
- state_onehot->name = NEW_ID;
- state_onehot->width = fsm_data.state_table.size();
- module->add(state_onehot);
+ RTLIL::Wire *state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size());
for (size_t i = 0; i < fsm_data.state_table.size(); i++)
{
@@ -215,111 +197,102 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
for (size_t j = 0; j < state.bits.size(); j++)
if (state.bits[j] == RTLIL::State::S0 || state.bits[j] == RTLIL::State::S1) {
- sig_a.append(RTLIL::SigSpec(state_wire, 1, j));
+ sig_a.append(RTLIL::SigSpec(state_wire, j));
sig_b.append(RTLIL::SigSpec(state.bits[j]));
}
- sig_a.optimize();
- sig_b.optimize();
if (sig_b == RTLIL::SigSpec(RTLIL::State::S1))
{
- module->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(state_onehot, 1, i), sig_a));
+ module->connect(RTLIL::SigSig(RTLIL::SigSpec(state_onehot, i), sig_a));
}
else
{
encoding_is_onehot = false;
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eq";
- eq_cell->connections["\\A"] = sig_a;
- eq_cell->connections["\\B"] = sig_b;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(state_onehot, 1, i);
+ RTLIL::Cell *eq_cell = module->addCell(NEW_ID, "$eq");
+ eq_cell->setPort("\\A", sig_a);
+ eq_cell->setPort("\\B", sig_b);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(state_onehot, i));
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(false);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(false);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_a.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(sig_b.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_a.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(sig_b.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->add(eq_cell);
}
}
// generate next_state signal
- RTLIL::Wire *next_state_onehot = new RTLIL::Wire;
- next_state_onehot->name = NEW_ID;
- next_state_onehot->width = fsm_data.state_table.size();
- module->add(next_state_onehot);
-
- for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+ if (SIZE(fsm_data.state_table) == 1)
{
- std::map<RTLIL::Const, std::set<int>> pattern_cache;
- std::set<int> fullstate_cache;
+ module->connect(next_state_wire, fsm_data.state_table.front());
+ }
+ else
+ {
+ RTLIL::Wire *next_state_onehot = module->addWire(NEW_ID, fsm_data.state_table.size());
- for (size_t j = 0; j < fsm_data.state_table.size(); j++)
- fullstate_cache.insert(j);
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++)
+ {
+ std::map<RTLIL::Const, std::set<int>> pattern_cache;
+ std::set<int> fullstate_cache;
- for (auto &tr : fsm_data.transition_table) {
- if (tr.state_out == int(i))
- pattern_cache[tr.ctrl_in].insert(tr.state_in);
- else
- fullstate_cache.erase(tr.state_in);
- }
+ for (size_t j = 0; j < fsm_data.state_table.size(); j++)
+ fullstate_cache.insert(j);
- implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, 1, i));
- }
+ for (auto &tr : fsm_data.transition_table) {
+ if (tr.state_out == int(i))
+ pattern_cache[tr.ctrl_in].insert(tr.state_in);
+ else
+ fullstate_cache.erase(tr.state_in);
+ }
- if (encoding_is_onehot)
- {
- RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width);
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- RTLIL::Const state = fsm_data.state_table[i];
- int bit_idx = -1;
- for (size_t j = 0; j < state.bits.size(); j++)
- if (state.bits[j] == RTLIL::State::S1)
- bit_idx = j;
- if (bit_idx >= 0)
- next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, 1, i));
+ implement_pattern_cache(module, pattern_cache, fullstate_cache, fsm_data.state_table.size(), state_onehot, ctrl_in, RTLIL::SigSpec(next_state_onehot, i));
}
- log_assert(!next_state_sig.has_marked_bits());
- module->connections.push_back(RTLIL::SigSig(next_state_wire, next_state_sig));
- }
- else
- {
- RTLIL::SigSpec sig_a, sig_b, sig_s;
- int reset_state = fsm_data.reset_state;
- if (reset_state < 0)
- reset_state = 0;
-
- for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
- RTLIL::Const state = fsm_data.state_table[i];
- if (int(i) == fsm_data.reset_state) {
- sig_a = RTLIL::SigSpec(state);
- } else {
- sig_b.append(RTLIL::SigSpec(state));
- sig_s.append(RTLIL::SigSpec(next_state_onehot, 1, i));
+
+ if (encoding_is_onehot)
+ {
+ RTLIL::SigSpec next_state_sig(RTLIL::State::Sm, next_state_wire->width);
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+ RTLIL::Const state = fsm_data.state_table[i];
+ int bit_idx = -1;
+ for (size_t j = 0; j < state.bits.size(); j++)
+ if (state.bits[j] == RTLIL::State::S1)
+ bit_idx = j;
+ if (bit_idx >= 0)
+ next_state_sig.replace(bit_idx, RTLIL::SigSpec(next_state_onehot, i));
}
+ log_assert(!next_state_sig.has_marked_bits());
+ module->connect(RTLIL::SigSig(next_state_wire, next_state_sig));
}
+ else
+ {
+ RTLIL::SigSpec sig_a, sig_b, sig_s;
+ int reset_state = fsm_data.reset_state;
+ if (reset_state < 0)
+ reset_state = 0;
+
+ for (size_t i = 0; i < fsm_data.state_table.size(); i++) {
+ RTLIL::Const state = fsm_data.state_table[i];
+ if (int(i) == fsm_data.reset_state) {
+ sig_a = RTLIL::SigSpec(state);
+ } else {
+ sig_b.append(RTLIL::SigSpec(state));
+ sig_s.append(RTLIL::SigSpec(next_state_onehot, i));
+ }
+ }
- RTLIL::Cell *mux_cell = new RTLIL::Cell;
- mux_cell->name = NEW_ID;
- mux_cell->type = "$safe_pmux";
- mux_cell->connections["\\A"] = sig_a;
- mux_cell->connections["\\B"] = sig_b;
- mux_cell->connections["\\S"] = sig_s;
- mux_cell->connections["\\Y"] = RTLIL::SigSpec(next_state_wire);
- mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.width);
- mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.width);
- module->add(mux_cell);
+ RTLIL::Cell *mux_cell = module->addCell(NEW_ID, "$pmux");
+ mux_cell->setPort("\\A", sig_a);
+ mux_cell->setPort("\\B", sig_b);
+ mux_cell->setPort("\\S", sig_s);
+ mux_cell->setPort("\\Y", RTLIL::SigSpec(next_state_wire));
+ mux_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_a.size());
+ mux_cell->parameters["\\S_WIDTH"] = RTLIL::Const(sig_s.size());
+ }
}
// Generate ctrl_out signal
- RTLIL::Wire *ctrl_out_wire = new RTLIL::Wire;
- ctrl_out_wire->name = NEW_ID;
- ctrl_out_wire->width = fsm_data.num_outputs;
- module->add(ctrl_out_wire);
-
for (int i = 0; i < fsm_data.num_outputs; i++)
{
std::map<RTLIL::Const, std::set<int>> pattern_cache;
@@ -340,8 +313,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module)
// Remove FSM cell
- module->cells.erase(fsm_cell->name);
- delete fsm_cell;
+ module->remove(fsm_cell);
}
struct FsmMapPass : public Pass {
@@ -360,11 +332,11 @@ struct FsmMapPass : public Pass {
log_header("Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
std::vector<RTLIL::Cell*> fsm_cells;
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" && design->selected(mod_it.second, cell_it.second))
fsm_cells.push_back(cell_it.second);
for (auto cell : fsm_cells)
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index 242a505e9..a0e1885ec 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -30,22 +30,62 @@ struct FsmOpt
FsmData fsm_data;
RTLIL::Cell *cell;
RTLIL::Module *module;
+
+ void opt_unreachable_states()
+ {
+ while (1)
+ {
+ std::set<int> unreachable_states;
+ std::vector<FsmData::transition_t> new_transition_table;
+ 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++)
+ if (i != fsm_data.reset_state)
+ unreachable_states.insert(i);
+
+ for (auto &trans : fsm_data.transition_table)
+ unreachable_states.erase(trans.state_out);
+
+ if (unreachable_states.empty())
+ break;
+
+ for (int i = 0; i < SIZE(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);
+ new_state_table.push_back(fsm_data.state_table[i]);
+ }
+
+ for (auto trans : fsm_data.transition_table) {
+ if (unreachable_states.count(trans.state_in))
+ continue;
+ trans.state_in = old_to_new_state.at(trans.state_in);
+ trans.state_out = old_to_new_state.at(trans.state_out);
+ new_transition_table.push_back(trans);
+ }
+
+ new_transition_table.swap(fsm_data.transition_table);
+ new_state_table.swap(fsm_data.state_table);
+ fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
+ }
+ }
bool signal_is_unused(RTLIL::SigSpec sig)
{
- assert(sig.width == 1);
- sig.optimize();
-
- RTLIL::Wire *wire = sig.chunks[0].wire;
- int bit = sig.chunks[0].offset;
+ RTLIL::SigBit bit = sig.to_single_sigbit();
- if (!wire || wire->attributes.count("\\unused_bits") == 0)
+ if (bit.wire == NULL || bit.wire->attributes.count("\\unused_bits") == 0)
return false;
- char *str = strdup(wire->attributes["\\unused_bits"].decode_string().c_str());
+ char *str = strdup(bit.wire->attributes["\\unused_bits"].decode_string().c_str());
for (char *tok = strtok(str, " "); tok != NULL; tok = strtok(NULL, " ")) {
- if (tok[0] && bit == atoi(tok))
+ if (tok[0] && bit.offset == atoi(tok)) {
+ free(str);
return true;
+ }
}
free(str);
@@ -54,12 +94,12 @@ struct FsmOpt
void opt_const_and_unused_inputs()
{
- RTLIL::SigSpec ctrl_in = cell->connections["\\CTRL_IN"];
- std::vector<bool> ctrl_in_used(ctrl_in.width);
+ RTLIL::SigSpec ctrl_in = cell->getPort("\\CTRL_IN");
+ std::vector<bool> ctrl_in_used(ctrl_in.size());
std::vector<FsmData::transition_t> new_transition_table;
for (auto &tr : fsm_data.transition_table) {
- for (int i = 0; i < ctrl_in.width; i++) {
+ for (int i = 0; i < ctrl_in.size(); i++) {
RTLIL::SigSpec ctrl_bit = ctrl_in.extract(i, 1);
if (ctrl_bit.is_fully_const()) {
if (tr.ctrl_in.bits[i] <= RTLIL::State::S1 && RTLIL::SigSpec(tr.ctrl_in.bits[i]) != ctrl_bit)
@@ -75,13 +115,15 @@ struct FsmOpt
for (int i = int(ctrl_in_used.size())-1; i >= 0; i--) {
if (!ctrl_in_used[i]) {
- log(" Removing unused input signal %s.\n", log_signal(cell->connections["\\CTRL_IN"].extract(i, 1)));
+ log(" Removing unused input signal %s.\n", log_signal(cell->getPort("\\CTRL_IN").extract(i, 1)));
for (auto &tr : new_transition_table) {
RTLIL::SigSpec tmp(tr.ctrl_in);
tmp.remove(i, 1);
tr.ctrl_in = tmp.as_const();
}
- cell->connections["\\CTRL_IN"].remove(i, 1);
+ RTLIL::SigSpec new_ctrl_in = cell->getPort("\\CTRL_IN");
+ new_ctrl_in.remove(i, 1);
+ cell->setPort("\\CTRL_IN", new_ctrl_in);
fsm_data.num_inputs--;
}
}
@@ -93,10 +135,12 @@ struct FsmOpt
void opt_unused_outputs()
{
for (int i = 0; i < fsm_data.num_outputs; i++) {
- RTLIL::SigSpec sig = cell->connections["\\CTRL_OUT"].extract(i, 1);
+ RTLIL::SigSpec sig = cell->getPort("\\CTRL_OUT").extract(i, 1);
if (signal_is_unused(sig)) {
log(" Removing unused output signal %s.\n", log_signal(sig));
- cell->connections["\\CTRL_OUT"].remove(i, 1);
+ RTLIL::SigSpec new_ctrl_out = cell->getPort("\\CTRL_OUT");
+ new_ctrl_out.remove(i, 1);
+ cell->setPort("\\CTRL_OUT", new_ctrl_out);
for (auto &tr : fsm_data.transition_table) {
RTLIL::SigSpec tmp(tr.ctrl_out);
tmp.remove(i, 1);
@@ -110,10 +154,10 @@ struct FsmOpt
void opt_alias_inputs()
{
- RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
+ RTLIL::SigSpec &ctrl_in = cell->connections_["\\CTRL_IN"];
- for (int i = 0; i < ctrl_in.width; i++)
- for (int j = i+1; j < ctrl_in.width; j++)
+ for (int i = 0; i < ctrl_in.size(); i++)
+ for (int j = i+1; j < ctrl_in.size(); j++)
if (ctrl_in.extract(i, 1) == ctrl_in.extract(j, 1))
{
log(" Optimize handling of signal %s that is connected to inputs %d and %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
@@ -147,11 +191,11 @@ struct FsmOpt
void opt_feedback_inputs()
{
- RTLIL::SigSpec &ctrl_in = cell->connections["\\CTRL_IN"];
- RTLIL::SigSpec &ctrl_out = cell->connections["\\CTRL_OUT"];
+ RTLIL::SigSpec &ctrl_in = cell->connections_["\\CTRL_IN"];
+ RTLIL::SigSpec &ctrl_out = cell->connections_["\\CTRL_OUT"];
- for (int j = 0; j < ctrl_out.width; j++)
- for (int i = 0; i < ctrl_in.width; i++)
+ for (int j = 0; j < ctrl_out.size(); j++)
+ for (int i = 0; i < ctrl_in.size(); i++)
if (ctrl_in.extract(i, 1) == ctrl_out.extract(j, 1))
{
log(" Optimize handling of signal %s that is connected to input %d and output %d.\n", log_signal(ctrl_in.extract(i, 1)), i, j);
@@ -251,6 +295,8 @@ struct FsmOpt
this->cell = cell;
this->module = module;
+ opt_unreachable_states();
+
opt_unused_outputs();
opt_alias_inputs();
@@ -286,9 +332,9 @@ struct FsmOptPass : public Pass {
log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ for (auto &cell_it : mod_it.second->cells_)
if (cell_it.second->type == "$fsm" and design->selected(mod_it.second, cell_it.second))
FsmData::optimize_fsm(cell_it.second, mod_it.second);
}
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index 5a4e091cf..873ee7a16 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -23,8 +23,9 @@
#include "kernel/consteval.h"
#include "kernel/celltypes.h"
#include "fsmdata.h"
-#include "math.h"
+#include <math.h>
#include <string.h>
+#include <errno.h>
static void fm_set_fsm_print(RTLIL::Cell *cell, RTLIL::Module *module, FsmData &fsm_data, const char *prefix, FILE *f)
{
@@ -52,10 +53,10 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
std::string encoding = cell->attributes.count("\\fsm_encoding") ? cell->attributes.at("\\fsm_encoding").decode_string() : "auto";
log("Recoding FSM `%s' from module `%s' using `%s' encoding:\n", cell->name.c_str(), module->name.c_str(), encoding.c_str());
- if (encoding != "none" && encoding != "one-hot" && encoding != "binary") {
- if (encoding != "auto")
- log(" unkown encoding `%s': using auto (%s) instead.\n", encoding.c_str(), default_encoding.c_str());
- encoding = default_encoding;
+
+ if (encoding != "none" && encoding != "one-hot" && encoding != "binary" && encoding != "auto") {
+ log(" unknown encoding `%s': using auto instead.\n", encoding.c_str());
+ encoding = "auto";
}
if (encoding == "none") {
@@ -69,11 +70,24 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
if (fm_set_fsm_file != NULL)
fm_set_fsm_print(cell, module, fsm_data, "r", fm_set_fsm_file);
+ if (encoding == "auto") {
+ if (!default_encoding.empty())
+ encoding = default_encoding;
+ else
+ encoding = SIZE(fsm_data.state_table) < 32 ? "one-hot" : "binary";
+ log(" mapping auto encoding to `%s` for this FSM.\n", encoding.c_str());
+ }
+
if (encoding == "one-hot") {
fsm_data.state_bits = fsm_data.state_table.size();
} else
- if (encoding == "auto" || encoding == "binary") {
- fsm_data.state_bits = ceil(log2(fsm_data.state_table.size()));
+ if (encoding == "binary") {
+ int new_num_state_bits = ceil(log2(fsm_data.state_table.size()));
+ if (fsm_data.state_bits == new_num_state_bits) {
+ log(" existing encoding is already a packed binary encoding.\n");
+ return;
+ }
+ fsm_data.state_bits = new_num_state_bits;
} else
log_error("FSM encoding `%s' is not supported!\n", encoding.c_str());
@@ -87,7 +101,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs
new_code = RTLIL::Const(RTLIL::State::Sa, fsm_data.state_bits);
new_code.bits[state_idx] = RTLIL::State::S1;
} else
- if (encoding == "auto" || encoding == "binary") {
+ if (encoding == "binary") {
new_code = RTLIL::Const(state_idx, fsm_data.state_bits);
} else
log_abort();
@@ -123,7 +137,7 @@ struct FsmRecodePass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
FILE *fm_set_fsm_file = NULL;
- std::string default_encoding = "one-hot";
+ std::string default_encoding;
log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
size_t argidx;
@@ -143,9 +157,9 @@ struct FsmRecodePass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
- for (auto &cell_it : mod_it.second->cells)
+ 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);
diff --git a/passes/fsm/fsmdata.h b/passes/fsm/fsmdata.h
index 225f34a9d..7a44dd452 100644
--- a/passes/fsm/fsmdata.h
+++ b/passes/fsm/fsmdata.h
@@ -141,29 +141,27 @@ struct FsmData
log("\n");
log(" Input signals:\n");
- RTLIL::SigSpec sig_in = cell->connections["\\CTRL_IN"];
- sig_in.expand();
- for (size_t i = 0; i < sig_in.chunks.size(); i++)
- log(" %3zd: %s\n", i, log_signal(sig_in.chunks[i]));
+ RTLIL::SigSpec sig_in = cell->getPort("\\CTRL_IN");
+ for (int i = 0; i < SIZE(sig_in); i++)
+ log(" %3d: %s\n", i, log_signal(sig_in[i]));
log("\n");
log(" Output signals:\n");
- RTLIL::SigSpec sig_out = cell->connections["\\CTRL_OUT"];
- sig_out.expand();
- for (size_t i = 0; i < sig_out.chunks.size(); i++)
- log(" %3zd: %s\n", i, log_signal(sig_out.chunks[i]));
+ RTLIL::SigSpec sig_out = cell->getPort("\\CTRL_OUT");
+ for (int i = 0; i < SIZE(sig_out); i++)
+ log(" %3d: %s\n", i, log_signal(sig_out[i]));
log("\n");
log(" State encoding:\n");
- for (size_t i = 0; i < state_table.size(); i++)
- log(" %3zd: %10s%s\n", i, log_signal(state_table[i], false),
+ for (int i = 0; i < SIZE(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 (size_t i = 0; i < transition_table.size(); i++) {
+ for (int i = 0; i < SIZE(transition_table); i++) {
transition_t &tr = transition_table[i];
- log(" %5zd: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
+ log(" %5d: %5d %s -> %5d %s\n", i, tr.state_in, log_signal(tr.ctrl_in), tr.state_out, log_signal(tr.ctrl_out));
}
log("\n");
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 50d0e6e47..14bf8d1bd 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -28,20 +28,22 @@
namespace {
struct generate_port_decl_t {
bool input, output;
- std::string portname;
+ 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)
{
- std::set<std::string> found_celltypes;
+ std::set<RTLIL::IdString> found_celltypes;
- for (auto i1 : design->modules)
- for (auto i2 : i1.second->cells)
+ for (auto i1 : design->modules_)
+ for (auto i2 : i1.second->cells_)
{
RTLIL::Cell *cell = i2.second;
- if (cell->type[0] == '$' || design->modules.count(cell->type) > 0)
+ if (design->has(cell->type))
+ continue;
+ 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))
@@ -50,18 +52,18 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
for (auto &celltype : found_celltypes)
{
- std::set<std::string> portnames;
- std::set<std::string> parameters;
- std::map<std::string, int> portwidths;
+ std::set<RTLIL::IdString> portnames;
+ std::set<RTLIL::IdString> parameters;
+ std::map<RTLIL::IdString, int> portwidths;
log("Generate module for cell type %s:\n", celltype.c_str());
- for (auto i1 : design->modules)
- for (auto i2 : i1.second->cells)
+ for (auto i1 : design->modules_)
+ for (auto i2 : i1.second->cells_)
if (i2.second->type == celltype) {
- for (auto &conn : i2.second->connections) {
+ for (auto &conn : i2.second->connections()) {
if (conn.first[0] != '$')
portnames.insert(conn.first);
- portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.width);
+ portwidths[conn.first] = std::max(portwidths[conn.first], conn.second.size());
}
for (auto &para : i2.second->parameters)
parameters.insert(para.first);
@@ -92,13 +94,13 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
}
while (portnames.size() > 0) {
- std::string portname = *portnames.begin();
+ 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)) {
generate_port_decl_t d = decl;
d.portname = portname;
d.index = *indices.begin();
- assert(!indices.empty());
+ log_assert(!indices.empty());
indices.erase(d.index);
ports[d.index-1] = d;
portwidths[d.portname] = std::max(portwidths[d.portname], 1);
@@ -110,23 +112,22 @@ static void generate(RTLIL::Design *design, const std::vector<std::string> &cell
portnames.erase(portname);
}
- assert(indices.empty());
+ log_assert(indices.empty());
RTLIL::Module *mod = new RTLIL::Module;
mod->name = celltype;
mod->attributes["\\blackbox"] = RTLIL::Const(1);
- design->modules[mod->name] = mod;
+ design->add(mod);
for (auto &decl : ports) {
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = decl.portname;
- wire->width = portwidths.at(decl.portname);
+ RTLIL::Wire *wire = mod->addWire(decl.portname, portwidths.at(decl.portname));
wire->port_id = decl.index;
wire->port_input = decl.input;
wire->port_output = decl.output;
- mod->add(wire);
}
+ mod->fixup_ports();
+
for (auto &para : parameters)
log(" ignoring parameter %s.\n", RTLIL::id2cstr(para));
@@ -137,14 +138,33 @@ 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 did_something = false;
+ std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
std::string filename;
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
- if (design->modules.count(cell->type) == 0)
+ if (cell->type.substr(0, 7) == "$array:") {
+ int pos_idx = cell->type.str().find_first_of(':');
+ int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
+ int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
+ int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
+ int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
+ array_cells[cell] = std::pair<int, int>(idx, num);
+ cell->type = cell->type.str().substr(pos_type + 1);
+ }
+
+ if (design->modules_.count(cell->type) == 0)
{
+ if (design->modules_.count("$abstract" + cell->type.str()))
+ {
+ cell->type = design->modules_.at("$abstract" + cell->type.str())->derive(design, cell->parameters);
+ cell->parameters.clear();
+ did_something = true;
+ continue;
+ }
+
if (cell->type[0] == '$')
continue;
@@ -173,7 +193,7 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
continue;
loaded_module:
- if (design->modules.count(cell->type) == 0)
+ 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;
}
@@ -181,15 +201,47 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
if (cell->parameters.size() == 0)
continue;
- if (design->modules.at(cell->type)->get_bool_attribute("\\blackbox"))
+ if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
continue;
- RTLIL::Module *mod = design->modules[cell->type];
+ RTLIL::Module *mod = design->modules_[cell->type];
cell->type = mod->derive(design, cell->parameters);
cell->parameters.clear();
did_something = true;
}
+ for (auto &it : array_cells)
+ {
+ RTLIL::Cell *cell = it.first;
+ int idx = it.second.first, num = it.second.second;
+
+ if (design->modules_.count(cell->type) == 0)
+ log_error("Array cell `%s.%s' of unknown type `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
+
+ RTLIL::Module *mod = design->modules_[cell->type];
+
+ for (auto &conn : cell->connections_) {
+ int conn_size = conn.second.size();
+ RTLIL::IdString portname = conn.first;
+ if (portname.substr(0, 1) == "$") {
+ int port_id = atoi(portname.substr(1).c_str());
+ for (auto &wire_it : mod->wires_)
+ if (wire_it.second->port_id == port_id) {
+ portname = wire_it.first;
+ break;
+ }
+ }
+ if (mod->wires_.count(portname) == 0)
+ log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+ int port_size = mod->wires_.at(portname)->width;
+ if (conn_size == port_size)
+ continue;
+ if (conn_size != port_size*num)
+ log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
+ conn.second = conn.second.extract(port_size*idx, port_size);
+ }
+ }
+
return did_something;
}
@@ -204,27 +256,29 @@ static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &us
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 &it : mod->cells_) {
+ if (design->modules_.count(it.second->type) > 0)
+ hierarchy_worker(design, used, design->modules_[it.second->type], indent+4);
}
}
-static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
+static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
{
std::set<RTLIL::Module*> used;
hierarchy_worker(design, used, top, 0);
std::vector<RTLIL::Module*> del_modules;
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
for (auto mod : del_modules) {
+ if (first_pass && 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);
+ design->modules_.erase(mod->name);
delete mod;
}
@@ -240,7 +294,7 @@ struct HierarchyPass : public Pass {
log(" hierarchy [-check] [-top <module>]\n");
log(" hierarchy -generate <cell-types> <port-decls>\n");
log("\n");
- log("In parametric designs, a module might exists in serveral variations with\n");
+ log("In parametric designs, a module might exists in several variations with\n");
log("different parameter values. This pass looks at all modules in the current\n");
log("design an re-runs the language frontends for the parametric modules as\n");
log("needed.\n");
@@ -255,7 +309,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -libdir <directory>\n");
log(" search for files named <module_name>.v in the specified directory\n");
- log(" for unkown modules and automatically run read_verilog for each\n");
+ log(" for unknown modules and automatically run read_verilog for each\n");
log(" unknown module.\n");
log("\n");
log(" -keep_positionals\n");
@@ -362,10 +416,12 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") {
if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n");
- if (args[argidx][0] != '$' && args[argidx][0] != '\\')
- top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
- else
- top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
+ 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;
+ 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;
+ }
if (top_mod == NULL)
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
continue;
@@ -382,25 +438,25 @@ struct HierarchyPass : public Pass {
log_push();
if (top_mod == NULL)
- for (auto &mod_it : design->modules)
+ 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);
+ hierarchy(design, top_mod, purge_lib, true);
bool did_something = true;
bool did_something_once = false;
while (did_something) {
did_something = false;
- std::vector<std::string> modnames;
- modnames.reserve(design->modules.size());
- for (auto &mod_it : design->modules)
+ 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)
+ if (design->modules_.count(modname) == 0)
continue;
- if (expand_module(design, design->modules[modname], flag_check, libdirs))
+ if (expand_module(design, design->modules_[modname], flag_check, libdirs))
did_something = true;
}
if (did_something)
@@ -409,11 +465,11 @@ struct HierarchyPass : public Pass {
if (top_mod != NULL && did_something_once) {
log_header("Re-running hierarchy analysis..\n");
- hierarchy(design, top_mod, purge_lib);
+ hierarchy(design, top_mod, purge_lib, false);
}
if (top_mod != NULL) {
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (mod_it.second == top_mod)
mod_it.second->attributes["\\top"] = RTLIL::Const(1);
else
@@ -426,21 +482,21 @@ struct HierarchyPass : public Pass {
std::map<std::pair<RTLIL::Module*,int>, RTLIL::IdString> pos_map;
std::vector<std::pair<RTLIL::Module*,RTLIL::Cell*>> pos_work;
- for (auto &mod_it : design->modules)
- for (auto &cell_it : mod_it.second->cells) {
+ for (auto &mod_it : design->modules_)
+ for (auto &cell_it : mod_it.second->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if (design->modules.count(cell->type) == 0)
+ if (design->modules_.count(cell->type) == 0)
continue;
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') {
- pos_mods.insert(design->modules.at(cell->type));
+ pos_mods.insert(design->modules_.at(cell->type));
pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod_it.second, cell));
break;
}
}
for (auto module : pos_mods)
- for (auto &wire_it : module->wires) {
+ for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id > 0)
pos_map[std::pair<RTLIL::Module*,int>(module, wire->port_id)] = wire->name;
@@ -452,10 +508,10 @@ struct HierarchyPass : public Pass {
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;
- for (auto &conn : cell->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);
- std::pair<RTLIL::Module*,int> key(design->modules.at(cell->type), id);
+ std::pair<RTLIL::Module*,int> key(design->modules_.at(cell->type), id);
if (pos_map.count(key) == 0) {
log(" Failed to map positional argument %d of cell %s.%s (%s).\n",
id, RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
@@ -464,7 +520,7 @@ struct HierarchyPass : public Pass {
new_connections[pos_map.at(key)] = conn.second;
} else
new_connections[conn.first] = conn.second;
- cell->connections = new_connections;
+ cell->connections_ = new_connections;
}
}
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index 7d0811254..1b03ab555 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -65,9 +65,9 @@ struct SubmodWorker
flag_found_something = true;
}
- void flag_signal(RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+ void flag_signal(const RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
{
- for (auto &c : sig.chunks)
+ for (auto &c : sig.chunks())
if (c.wire != NULL)
flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
}
@@ -79,24 +79,24 @@ struct SubmodWorker
wire_flags.clear();
for (RTLIL::Cell *cell : submod.cells) {
if (ct.cell_known(cell->type)) {
- for (auto &conn : cell->connections)
+ 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());
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, true, true, true, false, false);
}
}
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (submod.cells.count(cell) > 0)
continue;
if (ct.cell_known(cell->type)) {
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
flag_signal(conn.second, false, false, false, ct.cell_output(cell->type, conn.first), ct.cell_input(cell->type, conn.first));
} else {
flag_found_something = false;
- for (auto &conn : cell->connections)
+ 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());
@@ -105,10 +105,10 @@ struct SubmodWorker
RTLIL::Module *new_mod = new RTLIL::Module;
new_mod->name = submod.full_name;
- design->modules[new_mod->name] = new_mod;
- int port_counter = 1, auto_name_counter = 1;
+ design->add(new_mod);
+ int auto_name_counter = 1;
- std::set<std::string> all_wire_names;
+ std::set<RTLIL::IdString> all_wire_names;
for (auto &it : wire_flags) {
all_wire_names.insert(it.first->name);
}
@@ -123,31 +123,34 @@ struct SubmodWorker
if (wire->port_output)
flags.is_ext_used = true;
- RTLIL::Wire *new_wire = new RTLIL::Wire;
- new_wire->name = wire->name;
- new_wire->width = wire->width;
- new_wire->start_offset = wire->start_offset;
- new_wire->attributes = wire->attributes;
+ bool new_wire_port_input = false;
+ bool new_wire_port_output = false;
if (flags.is_int_driven && flags.is_ext_used)
- new_wire->port_output = true;
+ new_wire_port_output = true;
if (flags.is_ext_driven && flags.is_int_used)
- new_wire->port_input = true;
+ new_wire_port_input = true;
if (flags.is_int_driven && flags.is_ext_driven)
- new_wire->port_input = true, new_wire->port_output = true;
-
- if (new_wire->port_input || new_wire->port_output) {
- new_wire->port_id = port_counter++;
- while (new_wire->name[0] == '$') {
- std::string new_wire_name = stringf("\\n%d", auto_name_counter++);
- if (all_wire_names.count(new_wire_name) == 0) {
- all_wire_names.insert(new_wire_name);
- new_wire->name = new_wire_name;
+ new_wire_port_input = true, new_wire_port_output = true;
+
+ std::string new_wire_name = wire->name.str();
+ if (new_wire_port_input || new_wire_port_output) {
+ while (new_wire_name[0] == '$') {
+ std::string next_wire_name = stringf("\\n%d", auto_name_counter++);
+ if (all_wire_names.count(next_wire_name) == 0) {
+ all_wire_names.insert(next_wire_name);
+ new_wire_name = next_wire_name;
}
}
}
+ RTLIL::Wire *new_wire = new_mod->addWire(new_wire_name, wire->width);
+ new_wire->port_input = new_wire_port_input;
+ new_wire->port_output = new_wire_port_output;
+ new_wire->start_offset = wire->start_offset;
+ new_wire->attributes = wire->attributes;
+
if (new_wire->port_input && new_wire->port_output)
log(" signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
else if (new_wire->port_input)
@@ -157,36 +160,32 @@ struct SubmodWorker
else
log(" signal %s: internal\n", wire->name.c_str());
- new_mod->wires[new_wire->name] = new_wire;
flags.new_wire = new_wire;
}
+ new_mod->fixup_ports();
+
for (RTLIL::Cell *cell : submod.cells) {
- RTLIL::Cell *new_cell = new RTLIL::Cell(*cell);
- for (auto &conn : new_cell->connections)
- for (auto &c : conn.second.chunks)
- if (c.wire != NULL) {
- assert(wire_flags.count(c.wire) > 0);
- c.wire = wire_flags[c.wire].new_wire;
+ RTLIL::Cell *new_cell = new_mod->addCell(cell->name, cell);
+ for (auto &conn : new_cell->connections_)
+ for (auto &bit : conn.second)
+ if (bit.wire != NULL) {
+ log_assert(wire_flags.count(bit.wire) > 0);
+ bit.wire = wire_flags[bit.wire].new_wire;
}
log(" cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
- new_mod->cells[new_cell->name] = new_cell;
- module->cells.erase(cell->name);
- delete cell;
+ module->remove(cell);
}
submod.cells.clear();
- RTLIL::Cell *new_cell = new RTLIL::Cell;
- new_cell->name = submod.full_name;
- new_cell->type = submod.full_name;
+ RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
for (auto &it : wire_flags)
{
RTLIL::Wire *old_wire = it.first;
RTLIL::Wire *new_wire = it.second.new_wire;
if (new_wire->port_id > 0)
- new_cell->connections[new_wire->name] = RTLIL::SigSpec(old_wire);
+ new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
}
- module->cells[new_cell->name] = new_cell;
}
SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, std::string opt_name = std::string()) : design(design), module(module), opt_name(opt_name)
@@ -212,10 +211,10 @@ struct SubmodWorker
if (opt_name.empty())
{
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
it.second->attributes.erase("\\submod");
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
if (cell->attributes.count("\\submod") == 0 || cell->attributes["\\submod"].bits.size() == 0) {
@@ -228,8 +227,8 @@ struct SubmodWorker
if (submodules.count(submod_str) == 0) {
submodules[submod_str].name = submod_str;
- submodules[submod_str].full_name = module->name + "_" + submod_str;
- while (design->modules.count(submodules[submod_str].full_name) != 0 ||
+ submodules[submod_str].full_name = module->name.str() + "_" + submod_str;
+ while (design->modules_.count(submodules[submod_str].full_name) != 0 ||
module->count_id(submodules[submod_str].full_name) != 0)
submodules[submod_str].full_name += "_";
}
@@ -239,7 +238,7 @@ struct SubmodWorker
}
else
{
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
if (!design->selected(module, cell))
@@ -306,18 +305,18 @@ struct SubmodPass : public Pass {
Pass::call(design, "opt_clean");
log_header("Continuing SUBMOD pass.\n");
- std::set<std::string> handled_modules;
+ std::set<RTLIL::IdString> handled_modules;
bool did_something = true;
while (did_something) {
did_something = false;
- std::vector<std::string> queued_modules;
- for (auto &mod_it : design->modules)
+ std::vector<RTLIL::IdString> queued_modules;
+ for (auto &mod_it : design->modules_)
if (handled_modules.count(mod_it.first) == 0 && design->selected_whole_module(mod_it.first))
queued_modules.push_back(mod_it.first);
for (auto &modname : queued_modules)
- if (design->modules.count(modname) != 0) {
- SubmodWorker worker(design, design->modules[modname]);
+ if (design->modules_.count(modname) != 0) {
+ SubmodWorker worker(design, design->modules_[modname]);
handled_modules.insert(modname);
did_something = true;
}
@@ -328,7 +327,7 @@ struct SubmodPass : public Pass {
else
{
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected_module(mod_it.first))
continue;
if (module != NULL)
@@ -338,7 +337,7 @@ struct SubmodPass : public Pass {
if (module == NULL)
log("Nothing selected -> do nothing.\n");
else {
- Pass::call_newsel(design, stringf("opt_clean %s", module->name.c_str()));
+ Pass::call_on_module(design, module, "opt_clean");
log_header("Continuing SUBMOD pass.\n");
SubmodWorker worker(design, module, opt_name);
}
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index 21f17db5b..026c5ff85 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -1,6 +1,7 @@
OBJS += passes/memory/memory.o
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_map.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 680657a79..fc3095535 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -33,6 +33,9 @@ struct MemoryPass : public Pass {
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
log(" memory_dff\n");
+ log(" opt_clean\n");
+ log(" memory_share\n");
+ log(" opt_clean\n");
log(" memory_collect\n");
log(" memory_map (skipped if called with -nomap)\n");
log("\n");
@@ -58,6 +61,9 @@ struct MemoryPass : public Pass {
extra_args(args, argidx, design);
Pass::call(design, "memory_dff");
+ Pass::call(design, "opt_clean");
+ Pass::call(design, "memory_share");
+ Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
if (!flag_nomap)
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 6fe5e162c..9c670f00f 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -22,7 +22,6 @@
#include <sstream>
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
{
@@ -58,12 +57,12 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
RTLIL::SigSpec sig_rd_addr;
RTLIL::SigSpec sig_rd_data;
- std::vector<std::string> del_cell_ids;
+ std::vector<RTLIL::Cell*> del_cells;
std::vector<RTLIL::Cell*> memcells;
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
- if ((cell->type == "$memwr" || cell->type == "$memrd") && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if ((cell->type == "$memwr" || cell->type == "$memrd") && memory->name == cell->parameters["\\MEMID"].decode_string())
memcells.push_back(cell);
}
@@ -71,24 +70,24 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
for (auto cell : memcells)
{
- if (cell->type == "$memwr" && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if (cell->type == "$memwr" && memory->name == cell->parameters["\\MEMID"].decode_string())
{
wr_ports++;
- del_cell_ids.push_back(cell->name);
+ del_cells.push_back(cell);
- RTLIL::SigSpec clk = cell->connections["\\CLK"];
+ 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->connections["\\ADDR"];
- RTLIL::SigSpec data = cell->connections["\\DATA"];
- RTLIL::SigSpec en = cell->connections["\\EN"];
+ 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(1, false);
+ en.extend(memory->width, false);
sig_wr_clk.append(clk);
sig_wr_clk_enable.append(clk_enable);
@@ -98,17 +97,17 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
sig_wr_en.append(en);
}
- if (cell->type == "$memrd" && cell->parameters["\\MEMID"].decode_string() == memory->name)
+ if (cell->type == "$memrd" && memory->name == cell->parameters["\\MEMID"].decode_string())
{
rd_ports++;
- del_cell_ids.push_back(cell->name);
+ del_cells.push_back(cell);
- RTLIL::SigSpec clk = cell->connections["\\CLK"];
+ 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->connections["\\ADDR"];
- RTLIL::SigSpec data = cell->connections["\\DATA"];
+ RTLIL::SigSpec addr = cell->getPort("\\ADDR");
+ RTLIL::SigSpec data = cell->getPort("\\DATA");
clk.extend(1, false);
clk_enable.extend(1, false);
@@ -127,61 +126,48 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory)
}
std::stringstream sstr;
- sstr << "$mem$" << memory->name << "$" << (RTLIL::autoidx++);
+ sstr << "$mem$" << memory->name.str() << "$" << (autoidx++);
- RTLIL::Cell *mem = new RTLIL::Cell;
- mem->name = sstr.str();
- mem->type = "$mem";
-
- mem->parameters["\\MEMID"] = RTLIL::Const(memory->name);
+ RTLIL::Cell *mem = module->addCell(sstr.str(), "$mem");
+ mem->parameters["\\MEMID"] = RTLIL::Const(memory->name.str());
mem->parameters["\\WIDTH"] = RTLIL::Const(memory->width);
mem->parameters["\\OFFSET"] = RTLIL::Const(memory->start_offset);
mem->parameters["\\SIZE"] = RTLIL::Const(memory->size);
mem->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
- sig_wr_clk_enable.optimize();
- sig_wr_clk_polarity.optimize();
-
- assert(sig_wr_clk.width == wr_ports);
- assert(sig_wr_clk_enable.width == wr_ports && sig_wr_clk_enable.is_fully_const());
- assert(sig_wr_clk_polarity.width == wr_ports && sig_wr_clk_polarity.is_fully_const());
- assert(sig_wr_addr.width == wr_ports * addr_bits);
- assert(sig_wr_data.width == wr_ports * memory->width);
- assert(sig_wr_en.width == wr_ports);
+ 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());
+ log_assert(sig_wr_addr.size() == wr_ports * addr_bits);
+ log_assert(sig_wr_data.size() == wr_ports * memory->width);
+ log_assert(sig_wr_en.size() == wr_ports * memory->width);
mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports);
- mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.chunks[0].data : RTLIL::Const(0, 0);
+ mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : RTLIL::Const(0, 0);
- mem->connections["\\WR_CLK"] = sig_wr_clk;
- mem->connections["\\WR_ADDR"] = sig_wr_addr;
- mem->connections["\\WR_DATA"] = sig_wr_data;
- mem->connections["\\WR_EN"] = sig_wr_en;
+ mem->setPort("\\WR_CLK", sig_wr_clk);
+ mem->setPort("\\WR_ADDR", sig_wr_addr);
+ mem->setPort("\\WR_DATA", sig_wr_data);
+ mem->setPort("\\WR_EN", sig_wr_en);
- sig_rd_clk_enable.optimize();
- sig_rd_clk_polarity.optimize();
- sig_rd_transparent.optimize();
-
- assert(sig_rd_clk.width == rd_ports);
- assert(sig_rd_clk_enable.width == rd_ports && sig_rd_clk_enable.is_fully_const());
- assert(sig_rd_clk_polarity.width == rd_ports && sig_rd_clk_polarity.is_fully_const());
- assert(sig_rd_addr.width == rd_ports * addr_bits);
- assert(sig_rd_data.width == rd_ports * memory->width);
+ log_assert(sig_rd_clk.size() == rd_ports);
+ log_assert(sig_rd_clk_enable.size() == rd_ports && sig_rd_clk_enable.is_fully_const());
+ log_assert(sig_rd_clk_polarity.size() == rd_ports && sig_rd_clk_polarity.is_fully_const());
+ log_assert(sig_rd_addr.size() == rd_ports * addr_bits);
+ log_assert(sig_rd_data.size() == rd_ports * memory->width);
mem->parameters["\\RD_PORTS"] = RTLIL::Const(rd_ports);
- mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.chunks[0].data : RTLIL::Const(0, 0);
- mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.chunks[0].data : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : RTLIL::Const(0, 0);
+ mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : RTLIL::Const(0, 0);
- mem->connections["\\RD_CLK"] = sig_rd_clk;
- mem->connections["\\RD_ADDR"] = sig_rd_addr;
- mem->connections["\\RD_DATA"] = sig_rd_data;
+ mem->setPort("\\RD_CLK", sig_rd_clk);
+ mem->setPort("\\RD_ADDR", sig_rd_addr);
+ mem->setPort("\\RD_DATA", sig_rd_data);
- for (auto &id : del_cell_ids) {
- delete module->cells[id];
- module->cells.erase(id);
- }
- module->cells[mem->name] = mem;
+ for (auto c : del_cells)
+ module->remove(c);
}
static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
@@ -213,7 +199,7 @@ struct MemoryCollectPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
handle_module(design, mod_it.second);
}
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 2502a8b61..302ab3abf 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -20,51 +20,41 @@
#include "kernel/register.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <sstream>
static void normalize_sig(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections())
sig.replace(conn.first, conn.second);
}
-static bool find_sig_before_dff(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
+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)
{
normalize_sig(module, sig);
- sig.expand();
- for (size_t i = 0; i < sig.chunks.size(); i++)
+ for (auto &bit : sig)
{
- RTLIL::SigChunk &chunk = sig.chunks[i];
-
- if (chunk.wire == NULL)
+ if (bit.wire == NULL)
continue;
- for (auto &cell_it : module->cells)
+ for (auto cell : dff_cells)
{
- RTLIL::Cell *cell = cell_it.second;
-
- if (cell->type != "$dff")
- continue;
-
if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
- if (cell->connections["\\CLK"] != clk)
+ if (cell->getPort("\\CLK") != clk)
continue;
if (cell->parameters["\\CLK_POLARITY"].as_bool() != clk_polarity)
continue;
}
- RTLIL::SigSpec q_norm = cell->connections[after ? "\\D" : "\\Q"];
+ RTLIL::SigSpec q_norm = cell->getPort(after ? "\\D" : "\\Q");
normalize_sig(module, q_norm);
- RTLIL::SigSpec d = q_norm.extract(chunk, &cell->connections[after ? "\\Q" : "\\D"]);
- if (d.width != 1)
+ RTLIL::SigSpec d = q_norm.extract(bit, &cell->getPort(after ? "\\Q" : "\\D"));
+ if (d.size() != 1)
continue;
- assert(d.chunks.size() == 1);
- chunk = d.chunks[0];
- clk = cell->connections["\\CLK"];
+ bit = d;
+ clk = cell->getPort("\\CLK");
clk_polarity = cell->parameters["\\CLK_POLARITY"].as_bool();
goto replaced_this_bit;
}
@@ -73,44 +63,46 @@ static bool find_sig_before_dff(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLI
replaced_this_bit:;
}
- sig.optimize();
return true;
}
-static void handle_wr_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+static 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());
RTLIL::SigSpec clk = RTLIL::SigSpec(RTLIL::State::Sx);
bool clk_polarity = 0;
- RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
- if (!find_sig_before_dff(module, sig_addr, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_addr = cell->getPort("\\ADDR");
+ if (!find_sig_before_dff(module, dff_cells, sig_addr, clk, clk_polarity)) {
log("no (compatible) $dff for address input found.\n");
return;
}
- RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
- if (!find_sig_before_dff(module, sig_data, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_data = cell->getPort("\\DATA");
+ if (!find_sig_before_dff(module, dff_cells, sig_data, clk, clk_polarity)) {
log("no (compatible) $dff for data input found.\n");
return;
}
- RTLIL::SigSpec sig_en = cell->connections["\\EN"];
- if (!find_sig_before_dff(module, sig_en, clk, clk_polarity)) {
+ RTLIL::SigSpec sig_en = cell->getPort("\\EN");
+ if (!find_sig_before_dff(module, dff_cells, sig_en, clk, clk_polarity)) {
log("no (compatible) $dff for enable input found.\n");
return;
}
if (clk != RTLIL::SigSpec(RTLIL::State::Sx)) {
- cell->connections["\\CLK"] = clk;
- cell->connections["\\ADDR"] = sig_addr;
- cell->connections["\\DATA"] = sig_data;
- cell->connections["\\EN"] = sig_en;
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\ADDR", sig_addr);
+ cell->setPort("\\DATA", sig_data);
+ cell->setPort("\\EN", sig_en);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
log("merged $dff to cell.\n");
+ return;
}
+
+ log("no (compatible) $dff found.\n");
}
static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
@@ -119,36 +111,32 @@ static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig)
sig.sort_and_unify();
std::stringstream sstr;
- sstr << "$memory_dff_disconnected$" << (RTLIL::autoidx++);
+ sstr << "$memory_dff_disconnected$" << (autoidx++);
- RTLIL::Wire *wire = new RTLIL::Wire;
- wire->name = sstr.str();
- wire->width = sig.width;
- module->wires[wire->name] = wire;
+ RTLIL::SigSpec new_sig = module->addWire(sstr.str(), sig.size());
- RTLIL::SigSpec newsig(wire);
-
- for (auto &cell_it : module->cells) {
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$dff")
- cell->connections["\\Q"].replace(sig, newsig);
- }
+ for (auto cell : module->cells())
+ if (cell->type == "$dff") {
+ RTLIL::SigSpec new_q = cell->getPort("\\Q");
+ new_q.replace(sig, new_sig);
+ cell->setPort("\\Q", new_q);
+ }
}
-static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
+static 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());
bool clk_polarity = 0;
RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx);
- RTLIL::SigSpec sig_data = cell->connections["\\DATA"];
- if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true) &&
+ RTLIL::SigSpec sig_data = cell->getPort("\\DATA");
+ if (find_sig_before_dff(module, dff_cells, sig_data, clk_data, clk_polarity, true) &&
clk_data != RTLIL::SigSpec(RTLIL::State::Sx))
{
disconnect_dff(module, sig_data);
- cell->connections["\\CLK"] = clk_data;
- cell->connections["\\DATA"] = sig_data;
+ cell->setPort("\\CLK", clk_data);
+ cell->setPort("\\DATA", sig_data);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
@@ -157,12 +145,12 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
}
RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx);
- RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"];
- if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity) &&
+ RTLIL::SigSpec sig_addr = cell->getPort("\\ADDR");
+ if (find_sig_before_dff(module, dff_cells, sig_addr, clk_addr, clk_polarity) &&
clk_addr != RTLIL::SigSpec(RTLIL::State::Sx))
{
- cell->connections["\\CLK"] = clk_addr;
- cell->connections["\\ADDR"] = sig_addr;
+ cell->setPort("\\CLK", clk_addr);
+ cell->setPort("\\ADDR", sig_addr);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(1);
@@ -173,16 +161,22 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell)
log("no (compatible) $dff found.\n");
}
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_wr_only)
+static void handle_module(RTLIL::Module *module, bool flag_wr_only)
{
- for (auto &cell_it : module->cells) {
- if (!design->selected(module, cell_it.second))
- continue;
- if (cell_it.second->type == "$memwr" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
- handle_wr_cell(module, cell_it.second);
- if (!flag_wr_only && cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool())
- handle_rd_cell(module, cell_it.second);
- }
+ std::vector<RTLIL::Cell*> dff_cells;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$dff")
+ dff_cells.push_back(cell);
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$memwr" && !cell->parameters["\\CLK_ENABLE"].as_bool())
+ handle_wr_cell(module, dff_cells, cell);
+
+ if (!flag_wr_only)
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$memrd" && !cell->parameters["\\CLK_ENABLE"].as_bool())
+ handle_rd_cell(module, dff_cells, cell);
}
struct MemoryDffPass : public Pass {
@@ -217,9 +211,8 @@ struct MemoryDffPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second, flag_wr_only);
+ for (auto mod : design->selected_modules())
+ handle_module(mod, flag_wr_only);
}
} MemoryDffPass;
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index e0e3802d1..eecb6f35d 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -22,316 +22,302 @@
#include <sstream>
#include <set>
#include <stdlib.h>
-#include <assert.h>
-static std::string genid(std::string name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
+struct MemoryMapWorker
{
- std::stringstream sstr;
- sstr << "$memory" << name << token1;
-
- if (i >= 0)
- sstr << "[" << i << "]";
+ RTLIL::Design *design;
+ RTLIL::Module *module;
- sstr << token2;
+ std::map<std::pair<RTLIL::SigSpec, RTLIL::SigSpec>, RTLIL::SigBit> decoder_cache;
- if (j >= 0)
- sstr << "[" << j << "]";
+ std::string genid(RTLIL::IdString name, std::string token1 = "", int i = -1, std::string token2 = "", int j = -1, std::string token3 = "", int k = -1, std::string token4 = "")
+ {
+ std::stringstream sstr;
+ sstr << "$memory" << name.str() << token1;
+
+ if (i >= 0)
+ sstr << "[" << i << "]";
- sstr << token3;
+ sstr << token2;
- if (k >= 0)
- sstr << "[" << k << "]";
+ if (j >= 0)
+ sstr << "[" << j << "]";
- sstr << token4 << "$" << (RTLIL::autoidx++);
- return sstr.str();
-}
+ sstr << token3;
-static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- 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();
-
- // delete unused memory cell
- if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
- module->cells.erase(cell->name);
- delete cell;
- return;
- }
+ if (k >= 0)
+ sstr << "[" << k << "]";
- // all write ports must share the same clock
- RTLIL::SigSpec clocks = cell->connections["\\WR_CLK"];
- RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
- RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
- RTLIL::SigSpec refclock;
- RTLIL::State refclock_pol = RTLIL::State::Sx;
- for (int i = 0; i < clocks.width; i++) {
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(i, 1);
- if (wr_en.is_fully_const() && wr_en.as_int() == 0) {
- static_ports.insert(i);
- continue;
- }
- if (clocks_en.bits[i] != RTLIL::State::S1) {
- RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(i*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(i*mem_width, mem_width);
- if (wr_addr.is_fully_const()) {
- // 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_ports.insert(i);
- continue;
- }
- log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
- cell->name.c_str(), module->name.c_str(), i);
- return;
- }
- if (refclock.width == 0) {
- refclock = clocks.extract(i, 1);
- refclock_pol = clocks_pol.bits[i];
- }
- if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
- log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
- cell->name.c_str(), module->name.c_str(), i);
- return;
- }
+ sstr << token4 << "$" << (autoidx++);
+ return sstr.str();
}
- log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
+ 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));
- std::vector<RTLIL::SigSpec> data_reg_in;
- std::vector<RTLIL::SigSpec> data_reg_out;
+ if (decoder_cache.count(key) == 0) {
+ if (SIZE(addr_sig) < 2) {
+ decoder_cache[key] = module->Eq(NEW_ID, addr_sig, addr_val);
+ } else {
+ int split_at = SIZE(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));
+ decoder_cache[key] = module->And(NEW_ID, left_eq, right_eq);
+ }
+ }
- int count_static = 0;
+ RTLIL::SigBit bit = decoder_cache.at(key);
+ log_assert(bit.wire != nullptr && SIZE(bit.wire) == 1);
+ return bit.wire;
+ }
- for (int i = 0; i < mem_size; i++)
+ void handle_cell(RTLIL::Cell *cell)
{
- if (static_cells_map.count(i) > 0)
- {
- data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
- data_reg_out.push_back(static_cells_map[i]);
- count_static++;
+ 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();
+
+ // delete unused memory cell
+ if (cell->parameters["\\RD_PORTS"].as_int() == 0 && cell->parameters["\\WR_PORTS"].as_int() == 0) {
+ module->remove(cell);
+ return;
}
- else
- {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "", i);
- c->type = "$dff";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- if (clocks_pol.bits.size() > 0) {
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
- c->connections["\\CLK"] = clocks.extract(0, 1);
- } else {
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1);
- c->connections["\\CLK"] = RTLIL::SigSpec(RTLIL::State::S0);
+
+ // all write ports must share the same clock
+ RTLIL::SigSpec clocks = cell->getPort("\\WR_CLK");
+ RTLIL::Const clocks_pol = cell->parameters["\\WR_CLK_POLARITY"];
+ RTLIL::Const clocks_en = cell->parameters["\\WR_CLK_ENABLE"];
+ RTLIL::SigSpec refclock;
+ RTLIL::State refclock_pol = RTLIL::State::Sx;
+ for (int i = 0; i < clocks.size(); i++) {
+ RTLIL::SigSpec wr_en = cell->getPort("\\WR_EN").extract(i * mem_width, mem_width);
+ if (wr_en.is_fully_const() && !wr_en.as_bool()) {
+ static_ports.insert(i);
+ continue;
+ }
+ if (clocks_en.bits[i] != RTLIL::State::S1) {
+ RTLIL::SigSpec wr_addr = cell->getPort("\\WR_ADDR").extract(i*mem_abits, mem_abits);
+ RTLIL::SigSpec wr_data = cell->getPort("\\WR_DATA").extract(i*mem_width, mem_width);
+ if (wr_addr.is_fully_const()) {
+ // 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_ports.insert(i);
+ continue;
+ }
+ log("Not mapping memory cell %s in module %s (write port %d has no clock).\n",
+ cell->name.c_str(), module->name.c_str(), i);
+ return;
+ }
+ if (refclock.size() == 0) {
+ refclock = clocks.extract(i, 1);
+ refclock_pol = clocks_pol.bits[i];
+ }
+ if (clocks.extract(i, 1) != refclock || clocks_pol.bits[i] != refclock_pol) {
+ log("Not mapping memory cell %s in module %s (write clock %d is incompatible with other clocks).\n",
+ cell->name.c_str(), module->name.c_str(), i);
+ return;
}
- module->cells[c->name] = c;
-
- RTLIL::Wire *w_in = new RTLIL::Wire;
- w_in->name = genid(cell->name, "", i, "$d");
- w_in->width = mem_width;
- module->wires[w_in->name] = w_in;
- data_reg_in.push_back(RTLIL::SigSpec(w_in));
- c->connections["\\D"] = data_reg_in.back();
-
- RTLIL::Wire *w_out = new RTLIL::Wire;
- w_out->name = stringf("%s[%d]", cell->parameters["\\MEMID"].decode_string().c_str(), i);
- if (module->wires.count(w_out->name) > 0)
- w_out->name = genid(cell->name, "", i, "$q");
- w_out->width = mem_width;
- w_out->start_offset = mem_offset;
- module->wires[w_out->name] = w_out;
- data_reg_out.push_back(RTLIL::SigSpec(w_out));
- c->connections["\\Q"] = data_reg_out.back();
}
- }
- log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+ log("Mapping memory cell %s in module %s:\n", cell->name.c_str(), module->name.c_str());
- int count_dff = 0, count_mux = 0, count_wrmux = 0;
-
- for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
- {
- RTLIL::SigSpec rd_addr = cell->connections["\\RD_ADDR"].extract(i*mem_abits, mem_abits);
+ std::vector<RTLIL::SigSpec> data_reg_in;
+ std::vector<RTLIL::SigSpec> data_reg_out;
- std::vector<RTLIL::SigSpec> rd_signals;
- rd_signals.push_back(cell->connections["\\RD_DATA"].extract(i*mem_width, mem_width));
+ int count_static = 0;
- if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
+ for (int i = 0; i < mem_size; i++)
{
- if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
+ if (static_cells_map.count(i) > 0)
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdreg", i);
- c->type = "$dff";
- c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
- c->connections["\\D"] = rd_addr;
- module->cells[c->name] = c;
- count_dff++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdreg", i, "$q");
- w->width = mem_abits;
- module->wires[w->name] = w;
-
- c->connections["\\Q"] = RTLIL::SigSpec(w);
- rd_addr = RTLIL::SigSpec(w);
+ data_reg_in.push_back(RTLIL::SigSpec(RTLIL::State::Sz, mem_width));
+ data_reg_out.push_back(static_cells_map[i]);
+ count_static++;
}
else
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdreg", i);
- c->type = "$dff";
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "", i), "$dff");
c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
- c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1);
- c->connections["\\Q"] = rd_signals.back();
- module->cells[c->name] = c;
- count_dff++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdreg", i, "$d");
- w->width = mem_width;
- module->wires[w->name] = w;
-
- rd_signals.clear();
- rd_signals.push_back(RTLIL::SigSpec(w));
- c->connections["\\D"] = rd_signals.back();
+ if (clocks_pol.bits.size() > 0) {
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(clocks_pol.bits[0]);
+ c->setPort("\\CLK", clocks.extract(0, 1));
+ } else {
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(RTLIL::State::S1);
+ c->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::S0));
+ }
+
+ RTLIL::Wire *w_in = module->addWire(genid(cell->name, "", i, "$d"), mem_width);
+ data_reg_in.push_back(RTLIL::SigSpec(w_in));
+ c->setPort("\\D", data_reg_in.back());
+
+ std::string w_out_name = stringf("%s[%d]", cell->parameters["\\MEMID"].decode_string().c_str(), i);
+ if (module->wires_.count(w_out_name) > 0)
+ 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;
+
+ data_reg_out.push_back(RTLIL::SigSpec(w_out));
+ c->setPort("\\Q", data_reg_out.back());
}
}
- for (int j = 0; j < mem_abits; j++)
+ log(" created %d $dff cells and %d static cells of width %d.\n", mem_size-count_static, count_static, mem_width);
+
+ int count_dff = 0, count_mux = 0, count_wrmux = 0;
+
+ for (int i = 0; i < cell->parameters["\\RD_PORTS"].as_int(); i++)
{
- std::vector<RTLIL::SigSpec> next_rd_signals;
+ RTLIL::SigSpec rd_addr = cell->getPort("\\RD_ADDR").extract(i*mem_abits, mem_abits);
+
+ std::vector<RTLIL::SigSpec> rd_signals;
+ rd_signals.push_back(cell->getPort("\\RD_DATA").extract(i*mem_width, mem_width));
- for (size_t k = 0; k < rd_signals.size(); k++)
+ if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1)
{
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$rdmux", i, "", j, "", k);
- c->type = "$mux";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->connections["\\Y"] = rd_signals[k];
- c->connections["\\S"] = rd_addr.extract(mem_abits-j-1, 1);
- module->cells[c->name] = c;
- count_mux++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$a");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\A"] = RTLIL::SigSpec(w);
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$rdmux", i, "", j, "", k, "$b");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\B"] = RTLIL::SigSpec(w);
-
- next_rd_signals.push_back(c->connections["\\A"]);
- next_rd_signals.push_back(c->connections["\\B"]);
+ if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1)
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits);
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ c->setPort("\\D", rd_addr);
+ count_dff++;
+
+ RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$q"), mem_abits);
+
+ c->setPort("\\Q", RTLIL::SigSpec(w));
+ rd_addr = RTLIL::SigSpec(w);
+ }
+ else
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdreg", i), "$dff");
+ c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+ c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]);
+ c->setPort("\\CLK", cell->getPort("\\RD_CLK").extract(i, 1));
+ c->setPort("\\Q", rd_signals.back());
+ count_dff++;
+
+ RTLIL::Wire *w = module->addWire(genid(cell->name, "$rdreg", i, "$d"), mem_width);
+
+ rd_signals.clear();
+ rd_signals.push_back(RTLIL::SigSpec(w));
+ c->setPort("\\D", rd_signals.back());
+ }
}
- next_rd_signals.swap(rd_signals);
- }
+ for (int j = 0; j < mem_abits; j++)
+ {
+ std::vector<RTLIL::SigSpec> next_rd_signals;
- for (int j = 0; j < mem_size; j++)
- module->connections.push_back(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
- }
+ for (size_t k = 0; k < rd_signals.size(); k++)
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$rdmux", i, "", j, "", k), "$mux");
+ c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
+ c->setPort("\\Y", rd_signals[k]);
+ c->setPort("\\S", rd_addr.extract(mem_abits-j-1, 1));
+ count_mux++;
- log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
+ c->setPort("\\A", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$a"), mem_width));
+ c->setPort("\\B", module->addWire(genid(cell->name, "$rdmux", i, "", j, "", k, "$b"), mem_width));
- for (int i = 0; i < mem_size; i++)
- {
- if (static_cells_map.count(i) > 0)
- continue;
+ next_rd_signals.push_back(c->getPort("\\A"));
+ next_rd_signals.push_back(c->getPort("\\B"));
+ }
- RTLIL::SigSpec sig = data_reg_out[i];
+ next_rd_signals.swap(rd_signals);
+ }
- for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
+ for (int j = 0; j < mem_size; j++)
+ module->connect(RTLIL::SigSig(rd_signals[j], data_reg_out[j]));
+ }
+
+ log(" read interface: %d $dff and %d $mux cells.\n", count_dff, count_mux);
+
+ for (int i = 0; i < mem_size; i++)
{
- RTLIL::SigSpec wr_addr = cell->connections["\\WR_ADDR"].extract(j*mem_abits, mem_abits);
- RTLIL::SigSpec wr_data = cell->connections["\\WR_DATA"].extract(j*mem_width, mem_width);
- RTLIL::SigSpec wr_en = cell->connections["\\WR_EN"].extract(j, 1);
-
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wreq", i, "", j);
- c->type = "$eq";
- c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\A_WIDTH"] = cell->parameters["\\ABITS"];
- c->parameters["\\B_WIDTH"] = cell->parameters["\\ABITS"];
- c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- c->connections["\\A"] = RTLIL::SigSpec(i, mem_abits);
- c->connections["\\B"] = wr_addr;
- module->cells[c->name] = c;
- count_wrmux++;
-
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wreq", i, "", j, "$y");
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
-
- if (wr_en != RTLIL::SigSpec(1, 1))
+ if (static_cells_map.count(i) > 0)
+ continue;
+
+ RTLIL::SigSpec sig = data_reg_out[i];
+
+ for (int j = 0; j < cell->parameters["\\WR_PORTS"].as_int(); j++)
{
- c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wren", i, "", j);
- c->type = "$and";
- c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
- c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- c->connections["\\A"] = RTLIL::SigSpec(w);
- c->connections["\\B"] = wr_en;
- module->cells[c->name] = c;
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wren", i, "", j, "$y");
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
+ 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);
+ RTLIL::Wire *w_seladdr = addr_decode(wr_addr, RTLIL::SigSpec(i, mem_abits));
+
+ int wr_offset = 0;
+ while (wr_offset < wr_en.size())
+ {
+ int wr_width = 1;
+ RTLIL::SigSpec wr_bit = wr_en.extract(wr_offset, 1);
+
+ while (wr_offset + wr_width < wr_en.size()) {
+ RTLIL::SigSpec next_wr_bit = wr_en.extract(wr_offset + wr_width, 1);
+ if (next_wr_bit != wr_bit)
+ break;
+ wr_width++;
+ }
+
+ RTLIL::Wire *w = w_seladdr;
+
+ if (wr_bit != RTLIL::SigSpec(1, 1))
+ {
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), "$and");
+ c->parameters["\\A_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\B_SIGNED"] = RTLIL::Const(0);
+ c->parameters["\\A_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\B_WIDTH"] = RTLIL::Const(1);
+ c->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
+ c->setPort("\\A", w);
+ c->setPort("\\B", wr_bit);
+
+ w = module->addWire(genid(cell->name, "$wren", i, "", j, "", wr_offset, "$y"));
+ c->setPort("\\Y", RTLIL::SigSpec(w));
+ }
+
+ RTLIL::Cell *c = module->addCell(genid(cell->name, "$wrmux", i, "", j, "", wr_offset), "$mux");
+ c->parameters["\\WIDTH"] = wr_width;
+ c->setPort("\\A", sig.extract(wr_offset, wr_width));
+ c->setPort("\\B", wr_data.extract(wr_offset, wr_width));
+ c->setPort("\\S", RTLIL::SigSpec(w));
+
+ w = module->addWire(genid(cell->name, "$wrmux", i, "", j, "", wr_offset, "$y"), wr_width);
+ c->setPort("\\Y", w);
+
+ sig.replace(wr_offset, w);
+ wr_offset += wr_width;
+ count_wrmux++;
+ }
}
- c = new RTLIL::Cell;
- c->name = genid(cell->name, "$wrmux", i, "", j);
- c->type = "$mux";
- c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"];
- c->connections["\\A"] = sig;
- c->connections["\\B"] = wr_data;
- c->connections["\\S"] = RTLIL::SigSpec(w);
- module->cells[c->name] = c;
-
- w = new RTLIL::Wire;
- w->name = genid(cell->name, "$wrmux", i, "", j, "$y");
- w->width = mem_width;
- module->wires[w->name] = w;
- c->connections["\\Y"] = RTLIL::SigSpec(w);
- sig = RTLIL::SigSpec(w);
+ module->connect(RTLIL::SigSig(data_reg_in[i], sig));
}
- module->connections.push_back(RTLIL::SigSig(data_reg_in[i], sig));
- }
-
- log(" write interface: %d blocks of $eq, $and and $mux cells.\n", count_wrmux);
+ log(" write interface: %d write mux blocks.\n", count_wrmux);
- module->cells.erase(cell->name);
- delete cell;
- return;
-}
+ module->remove(cell);
+ }
-static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
-{
- std::vector<RTLIL::Cell*> cells;
- for (auto &it : module->cells)
- if (it.second->type == "$mem" && design->selected(module, it.second))
- cells.push_back(it.second);
- for (auto cell : cells)
- handle_cell(module, cell);
-}
+ MemoryMapWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module)
+ {
+ std::vector<RTLIL::Cell*> cells;
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$mem" && design->selected(module, cell))
+ cells.push_back(cell);
+ for (auto cell : cells)
+ handle_cell(cell);
+ }
+};
struct MemoryMapPass : public Pass {
MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { }
@@ -348,9 +334,8 @@ struct MemoryMapPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- handle_module(design, mod_it.second);
+ for (auto mod : design->selected_modules())
+ MemoryMapWorker(design, mod);
}
} MemoryMapPass;
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
new file mode 100644
index 000000000..3ae0cd2c7
--- /dev/null
+++ b/passes/memory/memory_share.cc
@@ -0,0 +1,744 @@
+/*
+ * 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"
+#include "kernel/modtools.h"
+
+PRIVATE_NAMESPACE_BEGIN
+
+static bool memcells_cmp(RTLIL::Cell *a, RTLIL::Cell *b)
+{
+ if (a->type == "$memrd" && b->type == "$memrd")
+ return a->name < b->name;
+ if (a->type == "$memrd" || b->type == "$memrd")
+ return (a->type == "$memrd") < (b->type == "$memrd");
+ return a->parameters.at("\\PRIORITY").as_int() < b->parameters.at("\\PRIORITY").as_int();
+}
+
+struct MemoryShareWorker
+{
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+ SigMap sigmap, sigmap_xmux;
+ ModWalker modwalker;
+ CellTypes cone_ct;
+
+ std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>> sig_to_mux;
+ std::map<std::set<std::map<RTLIL::SigBit, bool>>, RTLIL::SigBit> conditions_logic_cache;
+
+
+ // -----------------------------------------------------------------
+ // Converting feedbacks to async read ports to proper enable signals
+ // -----------------------------------------------------------------
+
+ bool find_data_feedback(const std::set<RTLIL::SigBit> &async_rd_bits, RTLIL::SigBit sig,
+ std::map<RTLIL::SigBit, bool> &state, std::set<std::map<RTLIL::SigBit, bool>> &conditions)
+ {
+ if (async_rd_bits.count(sig)) {
+ conditions.insert(state);
+ return true;
+ }
+
+ if (sig_to_mux.count(sig) == 0)
+ return false;
+
+ RTLIL::Cell *cell = sig_to_mux.at(sig).first;
+ int bit_idx = sig_to_mux.at(sig).second;
+
+ std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = sigmap(cell->getPort("\\S"));
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+ log_assert(sig_y.at(bit_idx) == sig);
+
+ for (int i = 0; i < int(sig_s.size()); i++)
+ if (state.count(sig_s[i]) && state.at(sig_s[i]) == true) {
+ if (find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), state, conditions)) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.replace(bit_idx + i*sig_y.size(), RTLIL::State::Sx);
+ cell->setPort("\\B", new_b);
+ }
+ return false;
+ }
+
+
+ for (int i = 0; i < int(sig_s.size()); i++)
+ {
+ if (state.count(sig_s[i]) && state.at(sig_s[i]) == false)
+ continue;
+
+ std::map<RTLIL::SigBit, bool> new_state = state;
+ new_state[sig_s[i]] = true;
+
+ if (find_data_feedback(async_rd_bits, sig_b.at(bit_idx + i*sig_y.size()), new_state, conditions)) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.replace(bit_idx + i*sig_y.size(), RTLIL::State::Sx);
+ cell->setPort("\\B", new_b);
+ }
+ }
+
+ std::map<RTLIL::SigBit, bool> new_state = state;
+ for (int i = 0; i < int(sig_s.size()); i++)
+ new_state[sig_s[i]] = false;
+
+ if (find_data_feedback(async_rd_bits, sig_a.at(bit_idx), new_state, conditions)) {
+ RTLIL::SigSpec new_a = cell->getPort("\\A");
+ new_a.replace(bit_idx, RTLIL::State::Sx);
+ cell->setPort("\\A", new_a);
+ }
+
+ return false;
+ }
+
+ RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, int &created_conditions)
+ {
+ if (conditions_logic_cache.count(conditions))
+ return conditions_logic_cache.at(conditions);
+
+ RTLIL::SigSpec terms;
+ for (auto &cond : conditions) {
+ RTLIL::SigSpec sig1, sig2;
+ for (auto &it : cond) {
+ sig1.append_bit(it.first);
+ sig2.append_bit(it.second ? RTLIL::State::S1 : RTLIL::State::S0);
+ }
+ terms.append(module->Ne(NEW_ID, sig1, sig2));
+ created_conditions++;
+ }
+
+ if (terms.size() > 1)
+ terms = module->ReduceAnd(NEW_ID, terms);
+
+ return conditions_logic_cache[conditions] = terms;
+ }
+
+ void translate_rd_feedback_to_en(std::string memid, std::vector<RTLIL::Cell*> &rd_ports, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ std::map<RTLIL::SigSpec, std::vector<std::set<RTLIL::SigBit>>> async_rd_bits;
+ std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map;
+ std::set<RTLIL::SigBit> non_feedback_nets;
+
+ for (auto wire_it : module->wires_)
+ if (wire_it.second->port_output) {
+ std::vector<RTLIL::SigBit> bits = RTLIL::SigSpec(wire_it.second);
+ non_feedback_nets.insert(bits.begin(), bits.end());
+ }
+
+ for (auto cell_it : module->cells_)
+ {
+ RTLIL::Cell *cell = cell_it.second;
+ bool ignore_data_port = false;
+
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ {
+ std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = sigmap(cell->getPort("\\S"));
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+
+ non_feedback_nets.insert(sig_s.begin(), sig_s.end());
+
+ for (int i = 0; i < int(sig_y.size()); i++) {
+ muxtree_upstream_map[sig_y[i]].insert(sig_a[i]);
+ for (int j = 0; j < int(sig_s.size()); j++)
+ muxtree_upstream_map[sig_y[i]].insert(sig_b[i + j*sig_y.size()]);
+ }
+
+ continue;
+ }
+
+ if ((cell->type == "$memwr" || cell->type == "$memrd") &&
+ cell->parameters.at("\\MEMID").decode_string() == memid)
+ ignore_data_port = true;
+
+ for (auto conn : cell_it.second->connections())
+ {
+ if (ignore_data_port && conn.first == "\\DATA")
+ continue;
+ std::vector<RTLIL::SigBit> bits = sigmap(conn.second);
+ non_feedback_nets.insert(bits.begin(), bits.end());
+ }
+ }
+
+ std::set<RTLIL::SigBit> expand_non_feedback_nets = non_feedback_nets;
+ while (!expand_non_feedback_nets.empty())
+ {
+ std::set<RTLIL::SigBit> new_expand_non_feedback_nets;
+
+ for (auto &bit : expand_non_feedback_nets)
+ if (muxtree_upstream_map.count(bit))
+ for (auto &new_bit : muxtree_upstream_map.at(bit))
+ if (!non_feedback_nets.count(new_bit)) {
+ non_feedback_nets.insert(new_bit);
+ new_expand_non_feedback_nets.insert(new_bit);
+ }
+
+ expand_non_feedback_nets.swap(new_expand_non_feedback_nets);
+ }
+
+ for (auto cell : rd_ports)
+ {
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool())
+ continue;
+
+ RTLIL::SigSpec sig_addr = sigmap(cell->getPort("\\ADDR"));
+ std::vector<RTLIL::SigBit> sig_data = sigmap(cell->getPort("\\DATA"));
+
+ for (int i = 0; i < int(sig_data.size()); i++)
+ if (non_feedback_nets.count(sig_data[i]))
+ goto not_pure_feedback_port;
+
+ async_rd_bits[sig_addr].resize(std::max(async_rd_bits.size(), sig_data.size()));
+ for (int i = 0; i < int(sig_data.size()); i++)
+ async_rd_bits[sig_addr][i].insert(sig_data[i]);
+
+ not_pure_feedback_port:;
+ }
+
+ if (async_rd_bits.empty())
+ return;
+
+ log("Populating enable bits on write ports of memory %s.%s with aync read feedback:\n", log_id(module), log_id(memid));
+
+ for (auto cell : wr_ports)
+ {
+ RTLIL::SigSpec sig_addr = sigmap_xmux(cell->getPort("\\ADDR"));
+ if (!async_rd_bits.count(sig_addr))
+ continue;
+
+ log(" Analyzing write port %s.\n", log_id(cell));
+
+ std::vector<RTLIL::SigBit> cell_data = cell->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> cell_en = cell->getPort("\\EN");
+
+ int created_conditions = 0;
+ for (int i = 0; i < int(cell_data.size()); i++)
+ if (cell_en[i] != RTLIL::SigBit(RTLIL::State::S0))
+ {
+ std::map<RTLIL::SigBit, bool> state;
+ std::set<std::map<RTLIL::SigBit, bool>> conditions;
+
+ if (cell_en[i].wire != NULL) {
+ state[cell_en[i]] = false;
+ conditions.insert(state);
+ }
+
+ find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions);
+ cell_en[i] = conditions_to_logic(conditions, created_conditions);
+ }
+
+ if (created_conditions) {
+ log(" Added enable logic for %d different cases.\n", created_conditions);
+ cell->setPort("\\EN", cell_en);
+ }
+ }
+ }
+
+
+ // ------------------------------------------------------
+ // Consolidate write ports that write to the same address
+ // ------------------------------------------------------
+
+ RTLIL::SigSpec mask_en_naive(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
+ {
+ // this is the naive version of the function that does not care about grouping the EN bits.
+
+ RTLIL::SigSpec inv_mask_bits = module->Not(NEW_ID, mask_bits);
+ RTLIL::SigSpec inv_mask_bits_filtered = module->Mux(NEW_ID, RTLIL::SigSpec(RTLIL::State::S1, bits.size()), inv_mask_bits, do_mask);
+ RTLIL::SigSpec result = module->And(NEW_ID, inv_mask_bits_filtered, bits);
+ return result;
+ }
+
+ RTLIL::SigSpec mask_en_grouped(RTLIL::SigSpec do_mask, RTLIL::SigSpec bits, RTLIL::SigSpec mask_bits)
+ {
+ // this version of the function preserves the bit grouping in the EN bits.
+
+ std::vector<RTLIL::SigBit> v_bits = bits;
+ std::vector<RTLIL::SigBit> v_mask_bits = mask_bits;
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, std::pair<int, std::vector<int>>> groups;
+ RTLIL::SigSpec grouped_bits, grouped_mask_bits;
+
+ for (int i = 0; i < bits.size(); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
+ if (groups.count(key) == 0) {
+ groups[key].first = grouped_bits.size();
+ grouped_bits.append_bit(v_bits[i]);
+ grouped_mask_bits.append_bit(v_mask_bits[i]);
+ }
+ groups[key].second.push_back(i);
+ }
+
+ std::vector<RTLIL::SigBit> grouped_result = mask_en_naive(do_mask, grouped_bits, grouped_mask_bits);
+ RTLIL::SigSpec result;
+
+ for (int i = 0; i < bits.size(); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_bits[i], v_mask_bits[i]);
+ result.append_bit(grouped_result.at(groups.at(key).first));
+ }
+
+ return result;
+ }
+
+ void merge_en_data(RTLIL::SigSpec &merged_en, RTLIL::SigSpec &merged_data, RTLIL::SigSpec next_en, RTLIL::SigSpec next_data)
+ {
+ std::vector<RTLIL::SigBit> v_old_en = merged_en;
+ std::vector<RTLIL::SigBit> v_next_en = next_en;
+
+ // The new merged_en signal is just the old merged_en signal and next_en OR'ed together.
+ // But of course we need to preserve the bit grouping..
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, int> groups;
+ std::vector<RTLIL::SigBit> grouped_old_en, grouped_next_en;
+ RTLIL::SigSpec new_merged_en;
+
+ for (int i = 0; i < int(v_old_en.size()); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
+ if (groups.count(key) == 0) {
+ groups[key] = grouped_old_en.size();
+ grouped_old_en.push_back(key.first);
+ grouped_next_en.push_back(key.second);
+ }
+ }
+
+ std::vector<RTLIL::SigBit> grouped_new_en = module->Or(NEW_ID, grouped_old_en, grouped_next_en);
+
+ for (int i = 0; i < int(v_old_en.size()); i++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(v_old_en[i], v_next_en[i]);
+ new_merged_en.append_bit(grouped_new_en.at(groups.at(key)));
+ }
+
+ // Create the new merged_data signal.
+
+ RTLIL::SigSpec new_merged_data(RTLIL::State::Sx, merged_data.size());
+
+ RTLIL::SigSpec old_data_set = module->And(NEW_ID, merged_en, merged_data);
+ RTLIL::SigSpec old_data_unset = module->And(NEW_ID, merged_en, module->Not(NEW_ID, merged_data));
+
+ RTLIL::SigSpec new_data_set = module->And(NEW_ID, next_en, next_data);
+ RTLIL::SigSpec new_data_unset = module->And(NEW_ID, next_en, module->Not(NEW_ID, next_data));
+
+ new_merged_data = module->Or(NEW_ID, new_merged_data, old_data_set);
+ new_merged_data = module->And(NEW_ID, new_merged_data, module->Not(NEW_ID, old_data_unset));
+
+ new_merged_data = module->Or(NEW_ID, new_merged_data, new_data_set);
+ new_merged_data = module->And(NEW_ID, new_merged_data, module->Not(NEW_ID, new_data_unset));
+
+ // Update merged_* signals
+
+ merged_en = new_merged_en;
+ merged_data = new_merged_data;
+ }
+
+ void consolidate_wr_by_addr(std::string memid, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ if (wr_ports.size() <= 1)
+ return;
+
+ log("Consolidating write ports of memory %s.%s by address:\n", log_id(module), log_id(memid));
+
+ std::map<RTLIL::SigSpec, int> last_port_by_addr;
+ std::vector<std::vector<bool>> active_bits_on_port;
+
+ bool cache_clk_enable = false;
+ bool cache_clk_polarity = false;
+ RTLIL::SigSpec cache_clk;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ RTLIL::Cell *cell = wr_ports.at(i);
+ RTLIL::SigSpec addr = sigmap_xmux(cell->getPort("\\ADDR"));
+
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool() != cache_clk_enable ||
+ (cache_clk_enable && (sigmap(cell->getPort("\\CLK")) != cache_clk ||
+ cell->parameters.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
+ {
+ cache_clk_enable = cell->parameters.at("\\CLK_ENABLE").as_bool();
+ cache_clk_polarity = cell->parameters.at("\\CLK_POLARITY").as_bool();
+ cache_clk = sigmap(cell->getPort("\\CLK"));
+ last_port_by_addr.clear();
+
+ if (cache_clk_enable)
+ log(" New clock domain: %s %s\n", cache_clk_polarity ? "posedge" : "negedge", log_signal(cache_clk));
+ else
+ log(" New clock domain: unclocked\n");
+ }
+
+ log(" Port %d (%s) has addr %s.\n", i, log_id(cell), log_signal(addr));
+
+ log(" Active bits: ");
+ std::vector<RTLIL::SigBit> en_bits = sigmap(cell->getPort("\\EN"));
+ active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
+ for (int k = int(en_bits.size())-1; k >= 0; k--) {
+ active_bits_on_port[i][k] = en_bits[k].wire != NULL || en_bits[k].data != RTLIL::State::S0;
+ log("%c", active_bits_on_port[i][k] ? '1' : '0');
+ }
+ log("\n");
+
+ if (last_port_by_addr.count(addr))
+ {
+ int last_i = last_port_by_addr.at(addr);
+ log(" Merging port %d into this one.\n", last_i);
+
+ bool found_overlapping_bits = false;
+ for (int k = 0; k < int(en_bits.size()); k++) {
+ if (active_bits_on_port[i][k] && active_bits_on_port[last_i][k])
+ found_overlapping_bits = true;
+ active_bits_on_port[i][k] = active_bits_on_port[i][k] || active_bits_on_port[last_i][k];
+ }
+
+ // Force this ports addr input to addr directly (skip don't care muxes)
+
+ cell->setPort("\\ADDR", addr);
+
+ // If any of the ports between `last_i' and `i' write to the same address, this
+ // will have priority over whatever `last_i` wrote. So we need to revisit those
+ // ports and mask the EN bits accordingly.
+
+ RTLIL::SigSpec merged_en = sigmap(wr_ports[last_i]->getPort("\\EN"));
+
+ for (int j = last_i+1; j < i; j++)
+ {
+ if (wr_ports[j] == NULL)
+ continue;
+
+ for (int k = 0; k < int(en_bits.size()); k++)
+ if (active_bits_on_port[i][k] && active_bits_on_port[j][k])
+ goto found_overlapping_bits_i_j;
+
+ if (0) {
+ found_overlapping_bits_i_j:
+ log(" Creating collosion-detect logic for port %d.\n", j);
+ RTLIL::SigSpec is_same_addr = module->addWire(NEW_ID);
+ module->addEq(NEW_ID, addr, wr_ports[j]->getPort("\\ADDR"), is_same_addr);
+ merged_en = mask_en_grouped(is_same_addr, merged_en, sigmap(wr_ports[j]->getPort("\\EN")));
+ }
+ }
+
+ // Then we need to merge the (masked) EN and the DATA signals.
+
+ RTLIL::SigSpec merged_data = wr_ports[last_i]->getPort("\\DATA");
+ if (found_overlapping_bits) {
+ log(" Creating logic for merging DATA and EN ports.\n");
+ merge_en_data(merged_en, merged_data, sigmap(cell->getPort("\\EN")), sigmap(cell->getPort("\\DATA")));
+ } else {
+ RTLIL::SigSpec cell_en = sigmap(cell->getPort("\\EN"));
+ RTLIL::SigSpec cell_data = sigmap(cell->getPort("\\DATA"));
+ for (int k = 0; k < int(en_bits.size()); k++)
+ if (!active_bits_on_port[last_i][k]) {
+ merged_en.replace(k, cell_en.extract(k, 1));
+ merged_data.replace(k, cell_data.extract(k, 1));
+ }
+ }
+
+ // Connect the new EN and DATA signals and remove the old write port.
+
+ cell->setPort("\\EN", merged_en);
+ cell->setPort("\\DATA", merged_data);
+
+ module->remove(wr_ports[last_i]);
+ wr_ports[last_i] = NULL;
+
+ log(" Active bits: ");
+ std::vector<RTLIL::SigBit> en_bits = sigmap(cell->getPort("\\EN"));
+ active_bits_on_port.push_back(std::vector<bool>(en_bits.size()));
+ for (int k = int(en_bits.size())-1; k >= 0; k--)
+ log("%c", active_bits_on_port[i][k] ? '1' : '0');
+ log("\n");
+ }
+
+ last_port_by_addr[addr] = i;
+ }
+
+ // Clean up `wr_ports': remove all NULL entries
+
+ std::vector<RTLIL::Cell*> wr_ports_with_nulls;
+ wr_ports_with_nulls.swap(wr_ports);
+
+ for (auto cell : wr_ports_with_nulls)
+ if (cell != NULL)
+ wr_ports.push_back(cell);
+ }
+
+
+ // --------------------------------------------------------
+ // Consolidate write ports using sat-based resource sharing
+ // --------------------------------------------------------
+
+ void consolidate_wr_using_sat(std::string memid, std::vector<RTLIL::Cell*> &wr_ports)
+ {
+ if (wr_ports.size() <= 1)
+ return;
+
+ ezDefaultSAT ez;
+ SatGen satgen(&ez, &modwalker.sigmap);
+
+ // find list of considered ports and port pairs
+
+ std::set<int> considered_ports;
+ std::set<int> considered_port_pairs;
+
+ for (int i = 0; i < int(wr_ports.size()); i++) {
+ std::vector<RTLIL::SigBit> bits = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
+ for (auto bit : bits)
+ if (bit == RTLIL::State::S1)
+ goto port_is_always_active;
+ if (modwalker.has_drivers(bits))
+ considered_ports.insert(i);
+ port_is_always_active:;
+ }
+
+ log("Consolidating write ports of memory %s.%s using sat-based resource sharing:\n", log_id(module), log_id(memid));
+
+ bool cache_clk_enable = false;
+ bool cache_clk_polarity = false;
+ RTLIL::SigSpec cache_clk;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ RTLIL::Cell *cell = wr_ports.at(i);
+
+ if (cell->parameters.at("\\CLK_ENABLE").as_bool() != cache_clk_enable ||
+ (cache_clk_enable && (sigmap(cell->getPort("\\CLK")) != cache_clk ||
+ cell->parameters.at("\\CLK_POLARITY").as_bool() != cache_clk_polarity)))
+ {
+ cache_clk_enable = cell->parameters.at("\\CLK_ENABLE").as_bool();
+ cache_clk_polarity = cell->parameters.at("\\CLK_POLARITY").as_bool();
+ cache_clk = sigmap(cell->getPort("\\CLK"));
+ }
+ else if (i > 0 && considered_ports.count(i-1) && considered_ports.count(i))
+ considered_port_pairs.insert(i);
+
+ if (cache_clk_enable)
+ log(" Port %d (%s) on %s %s: %s\n", i, log_id(cell),
+ cache_clk_polarity ? "posedge" : "negedge", log_signal(cache_clk),
+ considered_ports.count(i) ? "considered" : "not considered");
+ else
+ log(" Port %d (%s) unclocked: %s\n", i, log_id(cell),
+ considered_ports.count(i) ? "considered" : "not considered");
+ }
+
+ if (considered_port_pairs.size() < 1) {
+ log(" No two subsequent ports in same clock domain considered -> nothing to consolidate.\n");
+ return;
+ }
+
+ // create SAT representation of common input cone of all considered EN signals
+
+ std::set<RTLIL::Cell*> sat_cells;
+ std::set<RTLIL::SigBit> bits_queue;
+ std::map<int, int> port_to_sat_variable;
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ 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));
+
+ std::vector<RTLIL::SigBit> bits = sig;
+ bits_queue.insert(bits.begin(), bits.end());
+ }
+
+ while (!bits_queue.empty())
+ {
+ std::set<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];
+ bits_queue.insert(cell_inputs.begin(), cell_inputs.end());
+ sat_cells.insert(pbit.cell);
+ }
+ }
+
+ 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());
+
+ // merge subsequent ports if possible
+
+ for (int i = 0; i < int(wr_ports.size()); i++)
+ {
+ if (!considered_port_pairs.count(i))
+ continue;
+
+ 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));
+
+ RTLIL::SigSpec last_addr = wr_ports[i-1]->getPort("\\ADDR");
+ RTLIL::SigSpec last_data = wr_ports[i-1]->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> last_en = modwalker.sigmap(wr_ports[i-1]->getPort("\\EN"));
+
+ RTLIL::SigSpec this_addr = wr_ports[i]->getPort("\\ADDR");
+ RTLIL::SigSpec this_data = wr_ports[i]->getPort("\\DATA");
+ std::vector<RTLIL::SigBit> this_en = modwalker.sigmap(wr_ports[i]->getPort("\\EN"));
+
+ RTLIL::SigBit this_en_active = module->ReduceOr(NEW_ID, this_en);
+
+ wr_ports[i]->setPort("\\ADDR", module->Mux(NEW_ID, last_addr, this_addr, this_en_active));
+ wr_ports[i]->setPort("\\DATA", module->Mux(NEW_ID, last_data, this_data, this_en_active));
+
+ std::map<std::pair<RTLIL::SigBit, RTLIL::SigBit>, int> groups_en;
+ RTLIL::SigSpec grouped_last_en, grouped_this_en, en;
+ RTLIL::Wire *grouped_en = module->addWire(NEW_ID, 0);
+
+ for (int j = 0; j < int(this_en.size()); j++) {
+ std::pair<RTLIL::SigBit, RTLIL::SigBit> key(last_en[j], this_en[j]);
+ if (!groups_en.count(key)) {
+ grouped_last_en.append_bit(last_en[j]);
+ grouped_this_en.append_bit(this_en[j]);
+ groups_en[key] = grouped_en->width;
+ grouped_en->width++;
+ }
+ en.append(RTLIL::SigSpec(grouped_en, groups_en[key]));
+ }
+
+ module->addMux(NEW_ID, grouped_last_en, grouped_this_en, this_en_active, grouped_en);
+ wr_ports[i]->setPort("\\EN", en);
+
+ module->remove(wr_ports[i-1]);
+ wr_ports[i-1] = NULL;
+ }
+
+ // Clean up `wr_ports': remove all NULL entries
+
+ std::vector<RTLIL::Cell*> wr_ports_with_nulls;
+ wr_ports_with_nulls.swap(wr_ports);
+
+ for (auto cell : wr_ports_with_nulls)
+ if (cell != NULL)
+ wr_ports.push_back(cell);
+ }
+
+
+ // -------------
+ // Setup and run
+ // -------------
+
+ MemoryShareWorker(RTLIL::Design *design, RTLIL::Module *module) :
+ design(design), module(module), sigmap(module)
+ {
+ std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex;
+
+ sigmap_xmux = sigmap;
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (cell->type == "$memrd")
+ memindex[cell->parameters.at("\\MEMID").decode_string()].first.push_back(cell);
+
+ if (cell->type == "$memwr")
+ memindex[cell->parameters.at("\\MEMID").decode_string()].second.push_back(cell);
+
+ if (cell->type == "$mux")
+ {
+ RTLIL::SigSpec sig_a = sigmap_xmux(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap_xmux(cell->getPort("\\B"));
+
+ if (sig_a.is_fully_undef())
+ sigmap_xmux.add(cell->getPort("\\Y"), sig_b);
+ else if (sig_b.is_fully_undef())
+ sigmap_xmux.add(cell->getPort("\\Y"), sig_a);
+ }
+
+ if (cell->type == "$mux" || cell->type == "$pmux")
+ {
+ std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y"));
+ for (int i = 0; i < int(sig_y.size()); i++)
+ sig_to_mux[sig_y[i]] = std::pair<RTLIL::Cell*, int>(cell, i);
+ }
+ }
+
+ for (auto &it : memindex) {
+ std::sort(it.second.first.begin(), it.second.first.end(), memcells_cmp);
+ std::sort(it.second.second.begin(), it.second.second.end(), memcells_cmp);
+ translate_rd_feedback_to_en(it.first, it.second.first, it.second.second);
+ consolidate_wr_by_addr(it.first, it.second.second);
+ }
+
+ cone_ct.setup_internals();
+ cone_ct.cell_types.erase("$mul");
+ cone_ct.cell_types.erase("$mod");
+ cone_ct.cell_types.erase("$div");
+ cone_ct.cell_types.erase("$pow");
+ cone_ct.cell_types.erase("$shl");
+ cone_ct.cell_types.erase("$shr");
+ cone_ct.cell_types.erase("$sshl");
+ cone_ct.cell_types.erase("$sshr");
+ cone_ct.cell_types.erase("$shift");
+ cone_ct.cell_types.erase("$shiftx");
+
+ modwalker.setup(design, module, &cone_ct);
+
+ for (auto &it : memindex)
+ consolidate_wr_using_sat(it.first, it.second.second);
+ }
+};
+
+struct MemorySharePass : public Pass {
+ MemorySharePass() : Pass("memory_share", "consolidate memory ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_share [selection]\n");
+ log("\n");
+ log("This pass merges share-able memory ports into single memory ports.\n");
+ log("\n");
+ log("The following methods are used to consolidate the number of memory ports:\n");
+ log("\n");
+ log(" - When write ports are connected to async read ports accessing the same\n");
+ log(" address, then this feedback path is converted to a write port with\n");
+ log(" byte/part enable signals.\n");
+ log("\n");
+ log(" - When multiple write ports access the same address then this is converted\n");
+ log(" to a single write port with a more complex data and/or enable logic path.\n");
+ log("\n");
+ log(" - When multiple write ports are never accessed at the same time (a SAT\n");
+ log(" solver is used to determine this), then the ports are merged into a single\n");
+ log(" write port.\n");
+ log("\n");
+ log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
+ log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
+ log("optimizations) such as opt_share.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
+ extra_args(args, 1, design);
+ for (auto module : design->selected_modules())
+ MemoryShareWorker(design, module);
+ }
+} MemorySharePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 782c0cd79..5a4c4eac9 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -22,7 +22,6 @@
#include <sstream>
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
{
@@ -32,7 +31,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
RTLIL::IdString mem_name = RTLIL::escape_id(memory->parameters.at("\\MEMID").decode_string());
while (module->memories.count(mem_name) != 0)
- mem_name += stringf("_%d", RTLIL::autoidx++);
+ mem_name = mem_name.str() + stringf("_%d", autoidx++);
RTLIL::Memory *mem = new RTLIL::Memory;
mem->name = mem_name;
@@ -47,51 +46,44 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory)
for (int i = 0; i < num_rd_ports; i++)
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$memrd";
- cell->parameters["\\MEMID"] = mem_name;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$memrd");
+ cell->parameters["\\MEMID"] = mem_name.str();
cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS");
cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH");
cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_ENABLE")).extract(i, 1).as_const();
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\TRANSPARENT"] = RTLIL::SigSpec(memory->parameters.at("\\RD_TRANSPARENT")).extract(i, 1).as_const();
- cell->connections["\\CLK"] = memory->connections.at("\\RD_CLK").extract(i, 1);
- cell->connections["\\ADDR"] = memory->connections.at("\\RD_ADDR").extract(i*abits, abits);
- cell->connections["\\DATA"] = memory->connections.at("\\RD_DATA").extract(i*mem->width, mem->width);
- module->add(cell);
+ cell->setPort("\\CLK", memory->getPort("\\RD_CLK").extract(i, 1));
+ cell->setPort("\\ADDR", memory->getPort("\\RD_ADDR").extract(i*abits, abits));
+ cell->setPort("\\DATA", memory->getPort("\\RD_DATA").extract(i*mem->width, mem->width));
}
for (int i = 0; i < num_wr_ports; i++)
{
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$memwr";
- cell->parameters["\\MEMID"] = mem_name;
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$memwr");
+ cell->parameters["\\MEMID"] = mem_name.str();
cell->parameters["\\ABITS"] = memory->parameters.at("\\ABITS");
cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH");
cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_ENABLE")).extract(i, 1).as_const();
cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\WR_CLK_POLARITY")).extract(i, 1).as_const();
cell->parameters["\\PRIORITY"] = i;
- cell->connections["\\CLK"] = memory->connections.at("\\WR_CLK").extract(i, 1);
- cell->connections["\\EN"] = memory->connections.at("\\WR_EN").extract(i, 1);
- cell->connections["\\ADDR"] = memory->connections.at("\\WR_ADDR").extract(i*abits, abits);
- cell->connections["\\DATA"] = memory->connections.at("\\WR_DATA").extract(i*mem->width, mem->width);
- module->add(cell);
+ cell->setPort("\\CLK", memory->getPort("\\WR_CLK").extract(i, 1));
+ cell->setPort("\\EN", memory->getPort("\\WR_EN").extract(i*mem->width, mem->width));
+ cell->setPort("\\ADDR", memory->getPort("\\WR_ADDR").extract(i*abits, abits));
+ cell->setPort("\\DATA", memory->getPort("\\WR_DATA").extract(i*mem->width, mem->width));
}
- module->cells.erase(memory->name);
- delete memory;
+ module->remove(memory);
}
static void handle_module(RTLIL::Design *design, RTLIL::Module *module)
{
std::vector<RTLIL::IdString> memcells;
- for (auto &cell_it : module->cells)
+ for (auto &cell_it : module->cells_)
if (cell_it.second->type == "$mem" && design->selected(module, cell_it.second))
memcells.push_back(cell_it.first);
for (auto &it : memcells)
- handle_memory(module, module->cells.at(it));
+ handle_memory(module, module->cells_.at(it));
}
struct MemoryUnpackPass : public Pass {
@@ -109,7 +101,7 @@ struct MemoryUnpackPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
log_header("Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
handle_module(design, mod_it.second);
}
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 9dfb32c87..3a8d27f93 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -6,4 +6,6 @@ OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
OBJS += passes/opt/opt_const.o
+OBJS += passes/opt/share.o
+OBJS += passes/opt/wreduce.o
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index 8f4725e1c..b20521d1e 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -17,43 +17,55 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
-bool OPT_DID_SOMETHING;
-
struct OptPass : public Pass {
OptPass() : Pass("opt", "perform simple optimizations") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt [-purge] [-mux_undef] [-mux_bool] [-undriven] [selection]\n");
+ log(" opt [options] [selection]\n");
log("\n");
log("This pass calls all the other opt_* passes in a useful order. This performs\n");
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\n");
+ log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-fine] [-keepdc]\n");
log(" opt_share -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
- log(" opt_reduce\n");
+ log(" opt_reduce [-fine]\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(" 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_share\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven]\n");
- log(" while [changed design]\n");
+ log(" while <changed design in opt_rmdff>\n");
+ log("\n");
+ log("Note: Options in square brackets (such as [-keepdc]) are passed through to\n");
+ log("the opt_* commands when given to 'opt'.\n");
+ log("\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string opt_clean_args;
std::string opt_const_args;
+ std::string opt_reduce_args;
+ bool fast_mode = false;
log_header("Executing OPT pass (performing simple optimizations).\n");
log_push();
@@ -76,32 +88,56 @@ struct OptPass : public Pass {
opt_const_args += " -undriven";
continue;
}
+ if (args[argidx] == "-fine") {
+ opt_const_args += " -fine";
+ opt_reduce_args += " -fine";
+ continue;
+ }
+ if (args[argidx] == "-keepdc") {
+ opt_const_args += " -keepdc";
+ continue;
+ }
+ if (args[argidx] == "-fast") {
+ fast_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- log_header("Optimizing in-memory representation of design.\n");
- design->optimize();
-
- Pass::call(design, "opt_const");
- Pass::call(design, "opt_share -nomux");
- while (1) {
- OPT_DID_SOMETHING = false;
- Pass::call(design, "opt_muxtree");
- Pass::call(design, "opt_reduce");
- Pass::call(design, "opt_share");
- Pass::call(design, "opt_rmdff");
+ if (fast_mode)
+ {
+ while (1) {
+ Pass::call(design, "opt_const" + opt_const_args);
+ Pass::call(design, "opt_share");
+ design->scratchpad_unset("opt.did_something");
+ Pass::call(design, "opt_rmdff");
+ if (design->scratchpad_get_bool("opt.did_something") == false)
+ break;
+ Pass::call(design, "opt_clean" + opt_clean_args);
+ log_header("Rerunning OPT passes. (Removed registers in this run.)\n");
+ }
Pass::call(design, "opt_clean" + opt_clean_args);
+ }
+ else
+ {
Pass::call(design, "opt_const" + opt_const_args);
- if (OPT_DID_SOMETHING == false)
- break;
- log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ Pass::call(design, "opt_share -nomux");
+ while (1) {
+ design->scratchpad_unset("opt.did_something");
+ Pass::call(design, "opt_muxtree");
+ Pass::call(design, "opt_reduce" + opt_reduce_args);
+ Pass::call(design, "opt_share");
+ Pass::call(design, "opt_rmdff");
+ Pass::call(design, "opt_clean" + opt_clean_args);
+ Pass::call(design, "opt_const" + opt_const_args);
+ if (design->scratchpad_get_bool("opt.did_something") == false)
+ break;
+ log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ }
}
- log_header("Optimizing in-memory representation of design.\n");
- design->optimize();
-
- log_header("Finished OPT passes. (There is nothing left to do.)\n");
+ log_header(fast_mode ? "Finished fast OPT passes." : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 733a1cbf1..5046752f9 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -17,13 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -35,12 +33,12 @@ static int count_rm_cells, count_rm_wires;
static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
{
SigMap assign_map(module);
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> queue, unused;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
SigSet<RTLIL::Cell*> wire2driver;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
- for (auto &it2 : cell->connections) {
+ for (auto &it2 : cell->connections()) {
if (!ct.cell_input(cell->type, it2.first)) {
RTLIL::SigSpec sig = it2.second;
assign_map.apply(sig);
@@ -52,7 +50,7 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
unused.insert(cell);
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
std::set<RTLIL::Cell*> cell_list;
@@ -66,11 +64,11 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
while (queue.size() > 0)
{
- std::set<RTLIL::Cell*, RTLIL::sort_by_name<RTLIL::Cell>> new_queue;
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
for (auto cell : queue)
unused.erase(cell);
for (auto cell : queue) {
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
if (!ct.cell_output(cell->type, it.first)) {
std::set<RTLIL::Cell*> cell_list;
RTLIL::SigSpec sig = it.second;
@@ -89,10 +87,9 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
for (auto cell : unused) {
if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
- OPT_DID_SOMETHING = true;
- module->cells.erase(cell->name);
+ module->design->scratchpad_set_bool("opt.did_something", true);
+ module->remove(cell);
count_rm_cells++;
- delete cell;
}
}
@@ -104,15 +101,10 @@ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
return count;
}
-static bool compare_signals(RTLIL::SigSpec &s1, RTLIL::SigSpec &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
+static bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
{
- assert(s1.width == 1);
- assert(s2.width == 1);
- assert(s1.chunks.size() == 1);
- assert(s2.chunks.size() == 1);
-
- RTLIL::Wire *w1 = s1.chunks[0].wire;
- RTLIL::Wire *w2 = s2.chunks[0].wire;
+ RTLIL::Wire *w1 = s1.wire;
+ RTLIL::Wire *w2 = s2.wire;
if (w1 == NULL || w2 == NULL)
return w2 == NULL;
@@ -146,11 +138,12 @@ static bool compare_signals(RTLIL::SigSpec &s1, RTLIL::SigSpec &s2, SigPool &reg
static bool check_public_name(RTLIL::IdString id)
{
- if (id[0] == '$')
+ const std::string &id_str = id.str();
+ if (id_str[0] == '$')
return false;
- if (id.substr(0, 2) == "\\_" && (id[id.size()-1] == '_' || id.find("_[") != std::string::npos))
+ if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos))
return false;
- if (id.find(".$") != std::string::npos)
+ if (id_str.find(".$") != std::string::npos)
return false;
return true;
}
@@ -161,54 +154,54 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
SigPool connected_signals;
if (!purge_mode)
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_reg.cell_known(cell->type))
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
if (ct_reg.cell_output(cell->type, it2.first))
register_signals.add(it2.second);
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
connected_signals.add(it2.second);
}
SigMap assign_map(module);
std::set<RTLIL::SigSpec> direct_sigs;
std::set<RTLIL::Wire*> direct_wires;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
if (ct_all.cell_known(cell->type))
- for (auto &it2 : cell->connections)
+ for (auto &it2 : cell->connections())
if (ct_all.cell_output(cell->type, it2.first))
direct_sigs.insert(assign_map(it2.second));
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (direct_sigs.count(assign_map(it.second)) || it.second->port_input)
direct_wires.insert(it.second);
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++) {
- RTLIL::SigSpec s1 = RTLIL::SigSpec(wire, 1, i), s2 = assign_map(s1);
+ RTLIL::SigBit s1 = RTLIL::SigBit(wire, i), s2 = assign_map(s1);
if (!compare_signals(s1, s2, register_signals, connected_signals, direct_wires))
assign_map.add(s1);
}
}
- module->connections.clear();
+ module->connections_.clear();
SigPool used_signals;
SigPool used_signals_nodrivers;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
- for (auto &it2 : cell->connections) {
+ for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
used_signals.add(it2.second);
if (!ct.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
}
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
@@ -224,47 +217,43 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
}
- std::vector<RTLIL::Wire*> del_wires;
- for (auto &it : module->wires) {
- RTLIL::Wire *wire = it.second;
- if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0) {
+ std::vector<RTLIL::Wire*> maybe_del_wires;
+ for (auto wire : module->wires())
+ {
+ if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep")) {
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
- if (!used_signals.check_any(s2) && wire->port_id == 0) {
- del_wires.push_back(wire);
+ if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
+ maybe_del_wires.push_back(wire);
} else {
- s1.expand();
- s2.expand();
- assert(s1.chunks.size() == s2.chunks.size());
+ log_assert(SIZE(s1) == SIZE(s2));
RTLIL::SigSig new_conn;
- for (size_t i = 0; i < s1.chunks.size(); i++)
- if (s1.chunks[i] != s2.chunks[i]) {
- new_conn.first.append(s1.chunks[i]);
- new_conn.second.append(s2.chunks[i]);
+ for (int i = 0; i < SIZE(s1); i++)
+ if (s1[i] != s2[i]) {
+ new_conn.first.append_bit(s1[i]);
+ new_conn.second.append_bit(s2[i]);
}
- if (new_conn.first.width > 0) {
- new_conn.first.optimize();
- new_conn.second.optimize();
+ if (new_conn.first.size() > 0) {
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
- module->connections.push_back(new_conn);
+ module->connect(new_conn);
}
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
- del_wires.push_back(wire);
+ maybe_del_wires.push_back(wire);
}
+
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
- sig.expand();
- for (size_t i = 0; i < sig.chunks.size(); i++) {
- if (sig.chunks[i].wire == NULL)
+ for (int i = 0; i < SIZE(sig); i++) {
+ if (sig[i].wire == NULL)
continue;
- if (!used_signals_nodrivers.check_any(sig)) {
+ if (!used_signals_nodrivers.check(sig[i])) {
if (!unused_bits.empty())
unused_bits += " ";
- unused_bits += stringf("%zd", i);
+ unused_bits += stringf("%d", i);
}
}
if (unused_bits.empty() || wire->port_id != 0)
@@ -276,18 +265,22 @@ static void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool
}
}
+
+ std::set<RTLIL::Wire*> del_wires;
+
int del_wires_count = 0;
- for (auto wire : del_wires)
+ for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str());
del_wires_count++;
}
- module->wires.erase(wire->name);
- count_rm_wires++;
- delete wire;
+ del_wires.insert(wire);
}
+ module->remove(del_wires);
+ count_rm_wires += del_wires.size();;
+
if (del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
}
@@ -345,7 +338,7 @@ struct OptCleanPass : public Pass {
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
- for (auto &mod_it : design->modules) {
+ 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));
@@ -374,10 +367,10 @@ struct CleanPass : public Pass {
log("\n");
log("This is identical to 'opt_clean', but less verbose.\n");
log("\n");
- log("When commands are seperated using the ';;' token, this command will be executed\n");
+ log("When commands are separated using the ';;' token, this command will be executed\n");
log("between the commands.\n");
log("\n");
- log("When commands are seperated using the ';;;' token, this command will be executed\n");
+ log("When commands are separated using the ';;;' token, this command will be executed\n");
log("in -purge mode between the commands.\n");
log("\n");
}
@@ -409,12 +402,12 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (design->selected_whole_module(mod_it.first) && mod_it.second->processes.size() == 0)
do {
- OPT_DID_SOMETHING = false;
+ design->scratchpad_unset("opt.did_something");
rmunused_module(mod_it.second, purge_mode, false);
- } while (OPT_DID_SOMETHING);
+ } while (design->scratchpad_get_bool("opt.did_something"));
}
if (count_rm_cells > 0 || count_rm_wires > 0)
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc
index 34d1a69c1..f9b78c053 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_const.cc
@@ -17,19 +17,18 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
+#include "kernel/utils.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
-#include <set>
+#include <algorithm>
static bool did_something;
-void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
+static void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
{
CellTypes ct(design);
SigMap sigmap(module);
@@ -37,95 +36,350 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals;
SigPool all_signals;
- for (auto &it : module->cells)
- for (auto &conn : it.second->connections) {
- if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first))
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections()) {
+ if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
driven_signals.add(sigmap(conn.second));
- if (!ct.cell_known(it.second->type) || ct.cell_input(it.second->type, conn.first))
+ if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first))
used_signals.add(sigmap(conn.second));
}
- for (auto &it : module->wires) {
- if (it.second->port_input)
- driven_signals.add(sigmap(it.second));
- if (it.second->port_output)
- used_signals.add(sigmap(it.second));
- all_signals.add(sigmap(it.second));
+ for (auto wire : module->wires()) {
+ if (wire->port_input)
+ driven_signals.add(sigmap(wire));
+ if (wire->port_output)
+ used_signals.add(sigmap(wire));
+ all_signals.add(sigmap(wire));
}
all_signals.del(driven_signals);
RTLIL::SigSpec undriven_signals = all_signals.export_all();
- for (auto &c : undriven_signals.chunks)
+ for (auto &c : undriven_signals.chunks())
{
RTLIL::SigSpec sig = c;
if (c.wire->name[0] == '$')
sig = used_signals.extract(sig);
- if (sig.width == 0)
+ if (sig.size() == 0)
continue;
log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
- module->connections.push_back(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
- OPT_DID_SOMETHING = true;
+ module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
+ did_something = true;
}
}
-void replace_cell(RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
+static 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->connections[out_port];
+ RTLIL::SigSpec Y = cell->getPort(out_port);
+ out_val.extend_u0(Y.size(), false);
+
log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
cell->type.c_str(), cell->name.c_str(), info.c_str(),
module->name.c_str(), log_signal(Y), log_signal(out_val));
- // ILANG_BACKEND::dump_cell(stderr, "--> ", cell);
- module->connections.push_back(RTLIL::SigSig(Y, out_val));
- module->cells.erase(cell->name);
- delete cell;
- OPT_DID_SOMETHING = true;
+ // log_cell(cell);
+ assign_map.add(Y, out_val);
+ module->connect(Y, out_val);
+ module->remove(cell);
did_something = true;
}
-void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool)
+static bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap)
+{
+ std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A";
+
+ bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
+ bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool();
+
+ RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name));
+ RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
+
+ sig_a.extend_u0(sig_y.size(), a_signed);
+ sig_b.extend_u0(sig_y.size(), b_signed);
+
+ std::vector<RTLIL::SigBit> bits_a = sig_a, bits_b = sig_b, bits_y = sig_y;
+
+ 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++)
+ {
+ int group_idx = GRP_DYN;
+ RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i];
+
+ if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1))
+ bit_a = bit_b = RTLIL::State::S1;
+
+ if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0))
+ bit_a = bit_b = RTLIL::State::S0;
+
+ if (bit_a.wire == NULL && bit_b.wire == NULL)
+ group_idx = GRP_CONST_AB;
+ else if (bit_a.wire == NULL)
+ group_idx = GRP_CONST_A;
+ else if (bit_b.wire == NULL && commutative)
+ group_idx = GRP_CONST_A, std::swap(bit_a, bit_b);
+ else if (bit_b.wire == NULL)
+ group_idx = GRP_CONST_B;
+
+ grouped_bits[group_idx][std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit_a, bit_b)].insert(bits_y[i]);
+ }
+
+ for (int i = 0; i < GRP_N; i++)
+ if (SIZE(grouped_bits[i]) == SIZE(bits_y))
+ return false;
+
+ log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
+ log_id(cell->type), log_id(cell), log_id(module));
+
+ for (int i = 0; i < GRP_N; i++)
+ {
+ if (grouped_bits[i].empty())
+ continue;
+
+ RTLIL::Wire *new_y = module->addWire(NEW_ID, SIZE(grouped_bits[i]));
+ RTLIL::SigSpec new_a, new_b;
+ RTLIL::SigSig new_conn;
+
+ for (auto &it : grouped_bits[i]) {
+ for (auto &bit : it.second) {
+ new_conn.first.append_bit(bit);
+ new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.size()));
+ }
+ new_a.append_bit(it.first.first);
+ new_b.append_bit(it.first.second);
+ }
+
+ RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
+
+ c->setPort("\\A", new_a);
+ c->parameters["\\A_WIDTH"] = new_a.size();
+ c->parameters["\\A_SIGNED"] = false;
+
+ if (b_name == "\\B") {
+ c->setPort("\\B", new_b);
+ c->parameters["\\B_WIDTH"] = new_b.size();
+ c->parameters["\\B_SIGNED"] = false;
+ }
+
+ c->setPort("\\Y", new_y);
+ c->parameters["\\Y_WIDTH"] = new_y->width;
+ c->check();
+
+ module->connect(new_conn);
+
+ log(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
+ if (b_name == "\\B")
+ log(", B=%s", log_signal(new_b));
+ log("\n");
+ }
+
+ cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
+
+ module->remove(cell);
+ did_something = true;
+ 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)
{
if (!design->selected(module))
return;
+ CellTypes ct_combinational;
+ ct_combinational.setup_internals();
+ ct_combinational.setup_stdcells();
+
SigMap assign_map(module);
std::map<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
- std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &cell_it : module->cells)
- if (design->selected(module, cell_it.second)) {
- if ((cell_it.second->type == "$_INV_" || cell_it.second->type == "$not" || cell_it.second->type == "$logic_not") &&
- cell_it.second->connections["\\A"].width == 1 && cell_it.second->connections["\\Y"].width == 1)
- invert_map[assign_map(cell_it.second->connections["\\Y"])] = assign_map(cell_it.second->connections["\\A"]);
- cells.push_back(cell_it.second);
+ 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;
+
+ for (auto cell : module->cells())
+ if (design->selected(module, cell) && cell->type[0] == '$') {
+ if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") &&
+ cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1)
+ invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A"));
+ if (ct_combinational.cell_known(cell->type))
+ for (auto &conn : cell->connections()) {
+ RTLIL::SigSpec sig = assign_map(conn.second);
+ sig.remove_const();
+ if (ct_combinational.cell_input(cell->type, conn.first))
+ cell_to_inbit[cell].insert(sig.begin(), sig.end());
+ if (ct_combinational.cell_output(cell->type, conn.first))
+ for (auto &bit : sig)
+ outbit_to_cell[bit].insert(cell);
+ }
+ cells.node(cell);
}
- for (auto cell : cells)
+ for (auto &it_right : cell_to_inbit)
+ for (auto &it_sigbit : it_right.second)
+ for (auto &it_left : outbit_to_cell[it_sigbit])
+ cells.edge(it_left, it_right.first);
+
+ cells.sort();
+
+ for (auto cell : cells.sorted)
{
-#define ACTION_DO(_p_, _s_) do { replace_cell(module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
+#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
- if ((cell->type == "$_INV_" || cell->type == "$not" || cell->type == "$logic_not") &&
- invert_map.count(assign_map(cell->connections["\\A"])) != 0) {
- replace_cell(module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->connections["\\A"])));
+ if (do_fine)
+ {
+ if (cell->type == "$not" || cell->type == "$pos" ||
+ cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor")
+ if (group_cell_inputs(module, cell, true, assign_map))
+ goto next_cell;
+
+ if (cell->type == "$reduce_and")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+
+ RTLIL::State new_a = RTLIL::State::S1;
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_a == RTLIL::State::S1)
+ new_a = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S0) {
+ new_a = RTLIL::State::S0;
+ break;
+ } else if (bit.wire != NULL) {
+ new_a = RTLIL::State::Sm;
+ }
+
+ if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
+ cover("opt.opt_const.fine.$reduce_and");
+ log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
+ cell->setPort("\\A", sig_a = new_a);
+ cell->parameters.at("\\A_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+
+ RTLIL::State new_a = RTLIL::State::S0;
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_a == RTLIL::State::S0)
+ new_a = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S1) {
+ new_a = RTLIL::State::S1;
+ break;
+ } else if (bit.wire != NULL) {
+ new_a = RTLIL::State::Sm;
+ }
+
+ if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
+ cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
+ log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
+ cell->setPort("\\A", sig_a = new_a);
+ cell->parameters.at("\\A_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+
+ if (cell->type == "$logic_and" || cell->type == "$logic_or")
+ {
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+
+ RTLIL::State new_b = RTLIL::State::S0;
+ for (auto &bit : sig_b.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx) {
+ if (new_b == RTLIL::State::S0)
+ new_b = RTLIL::State::Sx;
+ } else if (bit == RTLIL::State::S1) {
+ new_b = RTLIL::State::S1;
+ break;
+ } else if (bit.wire != NULL) {
+ new_b = RTLIL::State::Sm;
+ }
+
+ if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
+ cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str());
+ log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
+ cell->setPort("\\B", sig_b = new_b);
+ cell->parameters.at("\\B_WIDTH") = 1;
+ did_something = true;
+ }
+ }
+ }
+
+ if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) {
+ cover("opt.opt_const.one_high");
+ replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1);
goto next_cell;
}
- if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->connections["\\S"])) != 0) {
- RTLIL::SigSpec tmp = cell->connections["\\A"];
- cell->connections["\\A"] = cell->connections["\\B"];
- cell->connections["\\B"] = tmp;
- cell->connections["\\S"] = invert_map.at(assign_map(cell->connections["\\S"]));
- OPT_DID_SOMETHING = true;
+ if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) {
+ cover("opt.opt_const.one_low");
+ replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0);
+ goto next_cell;
+ }
+
+ if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
+ cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
+ cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
+ cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" ||
+ cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow")
+ {
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec();
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ sig_a = RTLIL::SigSpec();
+
+ for (auto &bit : sig_a.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx)
+ goto found_the_x_bit;
+
+ for (auto &bit : sig_b.to_sigbit_vector())
+ if (bit == RTLIL::State::Sx)
+ goto found_the_x_bit;
+
+ if (0) {
+ found_the_x_bit:
+ cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
+ if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
+ cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
+ replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx);
+ else
+ replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size()));
+ goto next_cell;
+ }
+ }
+
+ if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
+ invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
+ cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
+ replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
+ goto next_cell;
+ }
+
+ if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
+ cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
+ log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
+ RTLIL::SigSpec tmp = cell->getPort("\\A");
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->setPort("\\B", tmp);
+ cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S"))));
did_something = true;
goto next_cell;
}
- if (cell->type == "$_INV_") {
- RTLIL::SigSpec input = cell->connections["\\A"];
+ if (cell->type == "$_NOT_") {
+ RTLIL::SigSpec input = cell->getPort("\\A");
assign_map.apply(input);
if (input.match("1")) ACTION_DO_Y(0);
if (input.match("0")) ACTION_DO_Y(1);
@@ -134,8 +388,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_AND_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match(" 0")) ACTION_DO_Y(0);
if (input.match("0 ")) ACTION_DO_Y(0);
@@ -153,8 +407,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_OR_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match(" 1")) ACTION_DO_Y(1);
if (input.match("1 ")) ACTION_DO_Y(1);
@@ -172,8 +426,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_XOR_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.match("00")) ACTION_DO_Y(0);
if (input.match("01")) ACTION_DO_Y(1);
@@ -187,9 +441,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$_MUX_") {
RTLIL::SigSpec input;
- input.append(cell->connections["\\S"]);
- input.append(cell->connections["\\B"]);
- input.append(cell->connections["\\A"]);
+ input.append(cell->getPort("\\S"));
+ input.append(cell->getPort("\\B"));
+ input.append(cell->getPort("\\A"));
assign_map.apply(input);
if (input.extract(2, 1) == input.extract(1, 1))
ACTION_DO("\\Y", input.extract(2, 1));
@@ -197,10 +451,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
if (input.match("10 ")) {
- cell->type = "$_INV_";
- cell->connections["\\A"] = input.extract(0, 1);
- cell->connections.erase("\\B");
- cell->connections.erase("\\S");
+ cover("opt.opt_const.mux_to_inv");
+ cell->type = "$_NOT_";
+ cell->setPort("\\A", input.extract(0, 1));
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\S");
goto next_cell;
}
if (input.match("11 ")) ACTION_DO_Y(1);
@@ -217,8 +472,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
{
- RTLIL::SigSpec a = cell->connections["\\A"];
- RTLIL::SigSpec b = cell->connections["\\B"];
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ RTLIL::SigSpec b = cell->getPort("\\B");
if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) {
int width = std::max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int());
@@ -227,78 +482,189 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
RTLIL::SigSpec new_a, new_b;
- a.expand(), b.expand();
- assert(a.chunks.size() == b.chunks.size());
- for (size_t i = 0; i < a.chunks.size(); i++) {
- if (a.chunks[i].wire == NULL && b.chunks[i].wire == NULL && a.chunks[i].data.bits[0] != b.chunks[i].data.bits[0] &&
- a.chunks[i].data.bits[0] <= RTLIL::State::S1 && b.chunks[i].data.bits[0] <= RTLIL::State::S1) {
+ log_assert(SIZE(a) == SIZE(b));
+ for (int i = 0; i < SIZE(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);
- replace_cell(module, cell, "empty", "\\Y", new_y);
+ replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
goto next_cell;
}
- if (a.chunks[i] == b.chunks[i])
+ if (a[i] == b[i])
continue;
- new_a.append(a.chunks[i]);
- new_b.append(b.chunks[i]);
+ new_a.append(a[i]);
+ new_b.append(b[i]);
}
- if (new_a.width == 0) {
+ 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);
- replace_cell(module, cell, "empty", "\\Y", new_y);
+ replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
goto next_cell;
}
- if (new_a.width < a.width || new_b.width < b.width) {
- new_a.optimize();
- new_b.optimize();
- cell->connections["\\A"] = new_a;
- cell->connections["\\B"] = new_b;
- cell->parameters["\\A_WIDTH"] = new_a.width;
- cell->parameters["\\B_WIDTH"] = new_b.width;
+ if (new_a.size() < a.size() || new_b.size() < b.size()) {
+ cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\B", new_b);
+ cell->parameters["\\A_WIDTH"] = new_a.size();
+ cell->parameters["\\B_WIDTH"] = new_b.size();
}
}
if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 &&
cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1)
{
- RTLIL::SigSpec a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec b = assign_map(cell->connections["\\B"]);
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
if (a.is_fully_const()) {
- RTLIL::SigSpec tmp;
- tmp = a, a = b, b = tmp;
- cell->connections["\\A"] = a;
- cell->connections["\\B"] = b;
+ 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);
}
if (b.is_fully_const()) {
if (b.as_bool() == (cell->type == "$eq")) {
RTLIL::SigSpec input = b;
- ACTION_DO("\\Y", cell->connections["\\A"]);
+ ACTION_DO("\\Y", cell->getPort("\\A"));
} else {
+ cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not";
cell->parameters.erase("\\B_WIDTH");
cell->parameters.erase("\\B_SIGNED");
- cell->connections.erase("\\B");
+ cell->unsetPort("\\B");
+ did_something = true;
+ }
+ goto next_cell;
+ }
+ }
+
+ if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const())
+ {
+ bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool();
+ int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool());
+
+ if (cell->type.in("$shl", "$sshl"))
+ shift_bits *= -1;
+
+ 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());
+
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ int idx = i + shift_bits;
+ if (0 <= idx && idx < SIZE(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];
+ }
+
+ cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
+
+ log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
+ log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
+
+ module->connect(cell->getPort("\\Y"), sig_y);
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ if (!keepdc)
+ {
+ bool identity_wrt_a = false;
+ bool identity_wrt_b = false;
+
+ if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor")
+ {
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false)
+ identity_wrt_b = true;
+
+ if (b.is_fully_const() && b.as_bool() == false)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
+ {
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (b.is_fully_const() && b.as_bool() == false)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$mul")
+ {
+ RTLIL::SigSpec a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (a.is_fully_const() && a.size() <= 32 && a.as_int() == 1)
+ identity_wrt_b = true;
+
+ if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
+ identity_wrt_a = true;
+ }
+
+ if (cell->type == "$div")
+ {
+ RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
+
+ if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1)
+ identity_wrt_a = true;
+ }
+
+ if (identity_wrt_a || identity_wrt_b)
+ {
+ if (identity_wrt_a)
+ cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ if (identity_wrt_b)
+ cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+
+ log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
+
+ if (!identity_wrt_a) {
+ cell->setPort("\\A", cell->getPort("\\B"));
+ cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH");
+ cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED");
}
+
+ cell->type = "$pos";
+ cell->unsetPort("\\B");
+ cell->parameters.erase("\\B_WIDTH");
+ cell->parameters.erase("\\B_SIGNED");
+ cell->check();
+
+ did_something = true;
goto next_cell;
}
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->connections["\\A"] == RTLIL::SigSpec(0, 1) && cell->connections["\\B"] == RTLIL::SigSpec(1, 1)) {
- replace_cell(module, cell, "mux_bool", "\\Y", cell->connections["\\S"]);
+ cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
goto next_cell;
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
- cell->connections["\\A"] == RTLIL::SigSpec(1, 1) && cell->connections["\\B"] == RTLIL::SigSpec(0, 1)) {
- cell->connections["\\A"] = cell->connections["\\S"];
- cell->connections.erase("\\B");
- cell->connections.erase("\\S");
+ cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
+ cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
+ cell->setPort("\\A", cell->getPort("\\S"));
+ cell->unsetPort("\\B");
+ cell->unsetPort("\\S");
if (cell->type == "$mux") {
cell->parameters["\\A_WIDTH"] = cell->parameters["\\WIDTH"];
cell->parameters["\\Y_WIDTH"] = cell->parameters["\\WIDTH"];
@@ -306,15 +672,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters.erase("\\WIDTH");
cell->type = "$not";
} else
- cell->type = "$_INV_";
- OPT_DID_SOMETHING = true;
+ cell->type = "$_NOT_";
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->connections["\\A"] == RTLIL::SigSpec(0, 1)) {
- cell->connections["\\A"] = cell->connections["\\S"];
- cell->connections.erase("\\S");
+ if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
+ cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
+ 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"];
@@ -325,14 +692,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->type = "$and";
} else
cell->type = "$_AND_";
- OPT_DID_SOMETHING = true;
did_something = true;
goto next_cell;
}
- if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->connections["\\B"] == RTLIL::SigSpec(1, 1)) {
- cell->connections["\\B"] = cell->connections["\\S"];
- cell->connections.erase("\\S");
+ if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
+ cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str());
+ log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
+ 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"];
@@ -342,87 +710,88 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters.erase("\\WIDTH");
cell->type = "$or";
} else
- cell->type = "$_or_";
- OPT_DID_SOMETHING = true;
+ cell->type = "$_OR_";
did_something = true;
goto next_cell;
}
if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) {
RTLIL::SigSpec new_a, new_b, new_s;
- int width = cell->connections.at("\\A").width;
- if ((cell->connections.at("\\A").is_fully_undef() && cell->connections.at("\\B").is_fully_undef()) ||
- cell->connections.at("\\S").is_fully_undef()) {
- replace_cell(module, cell, "mux undef", "\\Y", cell->connections.at("\\A"));
+ int width = cell->getPort("\\A").size();
+ if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
+ cell->getPort("\\S").is_fully_undef()) {
+ cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
goto next_cell;
}
- for (int i = 0; i < cell->connections.at("\\S").width; i++) {
- RTLIL::SigSpec old_b = cell->connections.at("\\B").extract(i*width, width);
- RTLIL::SigSpec old_s = cell->connections.at("\\S").extract(i, 1);
+ for (int i = 0; i < cell->getPort("\\S").size(); i++) {
+ RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width);
+ RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1);
if (old_b.is_fully_undef() || old_s.is_fully_undef())
continue;
new_b.append(old_b);
new_s.append(old_s);
}
- new_a = cell->connections.at("\\A");
- if (new_a.is_fully_undef() && new_s.width > 0) {
- new_a = new_b.extract((new_s.width-1)*width, width);
- new_b = new_b.extract(0, (new_s.width-1)*width);
- new_s = new_s.extract(0, new_s.width-1);
+ new_a = cell->getPort("\\A");
+ if (new_a.is_fully_undef() && new_s.size() > 0) {
+ new_a = new_b.extract((new_s.size()-1)*width, width);
+ new_b = new_b.extract(0, (new_s.size()-1)*width);
+ new_s = new_s.extract(0, new_s.size()-1);
}
- if (new_s.width == 0) {
- replace_cell(module, cell, "mux undef", "\\Y", new_a);
+ if (new_s.size() == 0) {
+ cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
- replace_cell(module, cell, "mux undef", "\\Y", new_s);
+ cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str());
+ replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
goto next_cell;
}
- if (cell->connections.at("\\S").width != new_s.width) {
- cell->connections.at("\\A") = new_a;
- cell->connections.at("\\B") = new_b;
- cell->connections.at("\\S") = new_s;
- if (new_s.width > 1) {
+ 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));
+ cell->setPort("\\A", new_a);
+ cell->setPort("\\B", new_b);
+ cell->setPort("\\S", new_s);
+ if (new_s.size() > 1) {
cell->type = "$pmux";
- cell->parameters["\\S_WIDTH"] = new_s.width;
+ cell->parameters["\\S_WIDTH"] = new_s.size();
} else {
cell->type = "$mux";
cell->parameters.erase("\\S_WIDTH");
}
- OPT_DID_SOMETHING = true;
did_something = true;
}
}
#define FOLD_1ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->connections["\\A"]; \
+ RTLIL::SigSpec a = cell->getPort("\\A"); \
assign_map.apply(a); \
if (a.is_fully_const()) { \
- a.optimize(); \
- if (a.chunks.empty()) a.chunks.push_back(RTLIL::SigChunk()); \
RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \
- RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, dummy_arg, \
+ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters["\\A_SIGNED"].as_bool(), false, \
cell->parameters["\\Y_WIDTH"].as_int())); \
- replace_cell(module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
+ cover("opt.opt_const.const.$" #_t); \
+ replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
goto next_cell; \
} \
}
#define FOLD_2ARG_CELL(_t) \
if (cell->type == "$" #_t) { \
- RTLIL::SigSpec a = cell->connections["\\A"]; \
- RTLIL::SigSpec b = cell->connections["\\B"]; \
+ RTLIL::SigSpec a = cell->getPort("\\A"); \
+ RTLIL::SigSpec b = cell->getPort("\\B"); \
assign_map.apply(a), assign_map.apply(b); \
if (a.is_fully_const() && b.is_fully_const()) { \
- a.optimize(), b.optimize(); \
- if (a.chunks.empty()) a.chunks.push_back(RTLIL::SigChunk()); \
- if (b.chunks.empty()) b.chunks.push_back(RTLIL::SigChunk()); \
- RTLIL::SigSpec y(RTLIL::const_ ## _t(a.chunks[0].data, b.chunks[0].data, \
+ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \
cell->parameters["\\A_SIGNED"].as_bool(), \
cell->parameters["\\B_SIGNED"].as_bool(), \
cell->parameters["\\Y_WIDTH"].as_int())); \
- replace_cell(module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
+ cover("opt.opt_const.const.$" #_t); \
+ replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
goto next_cell; \
} \
}
@@ -447,6 +816,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
FOLD_2ARG_CELL(shr)
FOLD_2ARG_CELL(sshl)
FOLD_2ARG_CELL(sshr)
+ FOLD_2ARG_CELL(shift)
+ FOLD_2ARG_CELL(shiftx)
FOLD_2ARG_CELL(lt)
FOLD_2ARG_CELL(le)
@@ -467,13 +838,78 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
// be very conservative with optimizing $mux cells as we do not want to break mux trees
if (cell->type == "$mux") {
- RTLIL::SigSpec input = assign_map(cell->connections["\\S"]);
- RTLIL::SigSpec inA = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec inB = assign_map(cell->connections["\\B"]);
+ RTLIL::SigSpec input = assign_map(cell->getPort("\\S"));
+ RTLIL::SigSpec inA = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec inB = assign_map(cell->getPort("\\B"));
if (input.is_fully_const())
- ACTION_DO("\\Y", input.as_bool() ? cell->connections["\\B"] : cell->connections["\\A"]);
+ ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A"));
else if (inA == inB)
- ACTION_DO("\\Y", cell->connections["\\A"]);
+ ACTION_DO("\\Y", cell->getPort("\\A"));
+ }
+
+ if (!keepdc && cell->type == "$mul")
+ {
+ bool a_signed = cell->parameters["\\A_SIGNED"].as_bool();
+ bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ bool swapped_ab = false;
+
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ if (sig_b.is_fully_const() && sig_b.size() <= 32)
+ std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true;
+
+ if (sig_a.is_fully_def() && sig_a.size() <= 32)
+ {
+ int a_val = sig_a.as_int();
+
+ if (a_val == 0)
+ {
+ cover("opt.opt_const.mul_shift.zero");
+
+ log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
+ cell->name.c_str(), module->name.c_str());
+
+ module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ for (int i = 1; i < (a_signed ? sig_a.size()-1 : sig_a.size()); i++)
+ if (a_val == (1 << i))
+ {
+ if (swapped_ab)
+ cover("opt.opt_const.mul_shift.swapped");
+ else
+ cover("opt.opt_const.mul_shift.unswapped");
+
+ log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ a_val, cell->name.c_str(), module->name.c_str(), i);
+
+ 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"];
+ }
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
+
+ while (SIZE(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_SIGNED"] = false;
+ cell->setPort("\\B", new_b);
+ cell->check();
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
}
next_cell:;
@@ -503,12 +939,23 @@ struct OptConstPass : public Pass {
log(" -undriven\n");
log(" replace undriven nets with undef (x) constants\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)
{
bool mux_undef = false;
bool mux_bool = false;
bool undriven = false;
+ bool do_fine = false;
+ bool keepdc = false;
log_header("Executing OPT_CONST pass (perform const folding).\n");
log_push();
@@ -527,21 +974,31 @@ struct OptConstPass : public Pass {
undriven = true;
continue;
}
+ if (args[argidx] == "-fine") {
+ do_fine = true;
+ continue;
+ }
+ if (args[argidx] == "-keepdc") {
+ keepdc = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
+ for (auto module : design->modules())
{
if (undriven)
- replace_undriven(design, mod_it.second);
+ replace_undriven(design, module);
do {
do {
did_something = false;
- replace_const_cells(design, mod_it.second, false, mux_undef, mux_bool);
+ replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc);
+ if (did_something)
+ design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
- replace_const_cells(design, mod_it.second, true, mux_undef, mux_bool);
+ replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc);
} while (did_something);
}
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 47100869c..2c5dcf668 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -17,13 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -36,7 +34,11 @@ struct OptMuxtreeWorker
SigMap assign_map;
int removed_count;
- typedef std::pair<RTLIL::Wire*,int> bitDef_t;
+ 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;
@@ -79,21 +81,20 @@ struct OptMuxtreeWorker
// .ctrl_sigs
// .input_sigs
// .const_activated
- for (auto &cell_it : module->cells)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux")
+ if (cell->type == "$mux" || cell->type == "$pmux")
{
- RTLIL::SigSpec sig_a = cell->connections["\\A"];
- RTLIL::SigSpec sig_b = cell->connections["\\B"];
- RTLIL::SigSpec sig_s = cell->connections["\\S"];
- RTLIL::SigSpec sig_y = cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
muxinfo_t muxinfo;
muxinfo.cell = cell;
- for (int i = 0; i < sig_s.width; i++) {
- RTLIL::SigSpec sig = sig_b.extract(i*sig_a.width, sig_a.width);
+ for (int i = 0; i < sig_s.size(); i++) {
+ RTLIL::SigSpec sig = sig_b.extract(i*sig_a.size(), sig_a.size());
RTLIL::SigSpec ctrl_sig = assign_map(sig_s.extract(i, 1));
portinfo_t portinfo;
for (int idx : sig2bits(sig)) {
@@ -126,15 +127,15 @@ struct OptMuxtreeWorker
}
else
{
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
for (int idx : sig2bits(it.second))
bit2info[idx].seen_non_mux = true;
}
}
}
- for (auto &it : module->wires) {
- if (it.second->port_output)
- for (int idx : sig2bits(RTLIL::SigSpec(it.second)))
+ for (auto wire : module->wires()) {
+ if (wire->port_output)
+ for (int idx : sig2bits(RTLIL::SigSpec(wire)))
bit2info[idx].seen_non_mux = true;
}
@@ -177,7 +178,6 @@ struct OptMuxtreeWorker
} else {
log(" dead port %zd/%zd on %s %s.\n", port_idx+1, mi.ports.size(),
mi.cell->type.c_str(), mi.cell->name.c_str());
- OPT_DID_SOMETHING = true;
removed_count++;
}
}
@@ -186,32 +186,30 @@ struct OptMuxtreeWorker
continue;
if (live_ports.size() == 0) {
- module->cells.erase(mi.cell->name);
- delete mi.cell;
+ module->remove(mi.cell);
continue;
}
- RTLIL::SigSpec sig_a = mi.cell->connections["\\A"];
- RTLIL::SigSpec sig_b = mi.cell->connections["\\B"];
- RTLIL::SigSpec sig_s = mi.cell->connections["\\S"];
- RTLIL::SigSpec sig_y = mi.cell->connections["\\Y"];
+ RTLIL::SigSpec sig_a = mi.cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = mi.cell->getPort("\\B");
+ RTLIL::SigSpec sig_s = mi.cell->getPort("\\S");
+ RTLIL::SigSpec sig_y = mi.cell->getPort("\\Y");
RTLIL::SigSpec sig_ports = sig_b;
sig_ports.append(sig_a);
if (live_ports.size() == 1)
{
- RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.width, sig_a.width);
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_in));
- module->cells.erase(mi.cell->name);
- delete mi.cell;
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[0]*sig_a.size(), sig_a.size());
+ module->connect(RTLIL::SigSig(sig_y, sig_in));
+ module->remove(mi.cell);
}
else
{
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.width, sig_a.width);
+ RTLIL::SigSpec sig_in = sig_ports.extract(live_ports[i]*sig_a.size(), sig_a.size());
if (i == live_ports.size()-1) {
new_sig_a = sig_in;
} else {
@@ -220,14 +218,14 @@ struct OptMuxtreeWorker
}
}
- mi.cell->connections["\\A"] = new_sig_a;
- mi.cell->connections["\\B"] = new_sig_b;
- mi.cell->connections["\\S"] = new_sig_s;
- if (new_sig_s.width == 1) {
+ 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) {
mi.cell->type = "$mux";
mi.cell->parameters.erase("\\S_WIDTH");
} else {
- mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+ mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
}
}
}
@@ -259,10 +257,8 @@ struct OptMuxtreeWorker
{
std::vector<int> results;
assign_map.apply(sig);
- sig.expand();
- for (auto &c : sig.chunks)
- if (c.wire != NULL) {
- bitDef_t bit(c.wire, c.offset);
+ for (auto &bit : sig)
+ if (bit.wire != NULL) {
if (bit2num.count(bit) == 0) {
bitinfo_t info;
info.num = bit2info.size();
@@ -309,13 +305,17 @@ struct OptMuxtreeWorker
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);
+ std::vector<int> parent_muxes;
for (int m : muxinfo.ports[port_idx].input_muxes) {
if (knowledge.visited_muxes.count(m) > 0)
continue;
knowledge.visited_muxes.insert(m);
+ parent_muxes.push_back(m);
+ }
+ for (int m : parent_muxes)
eval_mux(knowledge, m);
+ for (int m : parent_muxes)
knowledge.visited_muxes.erase(m);
- }
if (port_idx < int(muxinfo.ports.size())-1 && !muxinfo.ports[port_idx].const_activated)
knowledge.known_active.pop_back();
@@ -393,6 +393,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
knowledge_t knowledge;
+ knowledge.visited_muxes.insert(mux_idx);
eval_mux(knowledge, mux_idx);
}
};
@@ -418,19 +419,21 @@ struct OptMuxtreePass : public Pass {
extra_args(args, 1, design);
int total_count = 0;
- 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 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));
continue;
}
- if (mod_it.second->processes.size() > 0) {
- log("Skipping module %s as it contains processes.\n", id2cstr(mod_it.second->name));
+ if (mod->processes.size() > 0) {
+ log("Skipping module %s as it contains processes.\n", log_id(mod));
} else {
- OptMuxtreeWorker worker(design, mod_it.second);
+ OptMuxtreeWorker worker(design, mod);
total_count += worker.removed_count;
}
}
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Removed %d multiplexer ports.\n", total_count);
}
} OptMuxtreePass;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index dd1299810..e9e2bb399 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -17,14 +17,11 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
-#include "libs/sha1/sha1.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -43,97 +40,95 @@ struct OptReduceWorker
return;
cells.erase(cell);
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- sig_a.sort_and_unify();
- sig_a.expand();
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ std::set<RTLIL::SigBit> new_sig_a_bits;
- RTLIL::SigSpec new_sig_a;
- for (auto &chunk : sig_a.chunks)
+ for (auto &bit : sig_a.to_sigbit_set())
{
- if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S0) {
+ if (bit == RTLIL::State::S0) {
if (cell->type == "$reduce_and") {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::S0);
+ new_sig_a_bits.clear();
+ new_sig_a_bits.insert(RTLIL::State::S0);
break;
}
continue;
}
- if (chunk.wire == NULL && chunk.data.bits[0] == RTLIL::State::S1) {
+ if (bit == RTLIL::State::S1) {
if (cell->type == "$reduce_or") {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::S1);
+ new_sig_a_bits.clear();
+ new_sig_a_bits.insert(RTLIL::State::S1);
break;
}
continue;
}
- if (chunk.wire == NULL) {
- new_sig_a = RTLIL::SigSpec(RTLIL::State::Sx);
- break;
+ if (bit.wire == NULL) {
+ new_sig_a_bits.insert(bit);
+ continue;
}
bool imported_children = false;
- for (auto child_cell : drivers.find(chunk)) {
+ for (auto child_cell : drivers.find(bit)) {
if (child_cell->type == cell->type) {
opt_reduce(cells, drivers, child_cell);
- new_sig_a.append(child_cell->connections["\\A"]);
+ if (child_cell->getPort("\\Y")[0] == bit) {
+ std::set<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_set();
+ new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end());
+ } else
+ new_sig_a_bits.insert(RTLIL::State::S0);
imported_children = true;
}
}
if (!imported_children)
- new_sig_a.append(chunk);
+ new_sig_a_bits.insert(bit);
}
- new_sig_a.sort_and_unify();
- if (new_sig_a != sig_a || sig_a.width != cell->connections["\\A"].width) {
+ RTLIL::SigSpec new_sig_a(new_sig_a_bits);
+
+ if (new_sig_a != sig_a || sig_a.size() != cell->getPort("\\A").size()) {
log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a));
did_something = true;
- OPT_DID_SOMETHING = true;
total_count++;
}
- cell->connections["\\A"] = new_sig_a;
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.width);
+ cell->setPort("\\A", new_sig_a);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.size());
return;
}
void opt_mux(RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = assign_map(cell->connections["\\A"]);
- RTLIL::SigSpec sig_b = assign_map(cell->connections["\\B"]);
- RTLIL::SigSpec sig_s = assign_map(cell->connections["\\S"]);
+ RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S"));
RTLIL::SigSpec new_sig_b, new_sig_s;
std::set<RTLIL::SigSpec> handled_sig;
handled_sig.insert(sig_a);
- for (int i = 0; i < sig_s.width; i++)
+ for (int i = 0; i < sig_s.size(); i++)
{
- RTLIL::SigSpec this_b = sig_b.extract(i*sig_a.width, sig_a.width);
+ RTLIL::SigSpec this_b = sig_b.extract(i*sig_a.size(), sig_a.size());
if (handled_sig.count(this_b) > 0)
continue;
RTLIL::SigSpec this_s = sig_s.extract(i, 1);
- for (int j = i+1; j < sig_s.width; j++) {
- RTLIL::SigSpec that_b = sig_b.extract(j*sig_a.width, sig_a.width);
+ for (int j = i+1; j < sig_s.size(); j++) {
+ RTLIL::SigSpec that_b = sig_b.extract(j*sig_a.size(), sig_a.size());
if (this_b == that_b)
this_s.append(sig_s.extract(j, 1));
}
- if (this_s.width > 1)
+ if (this_s.size() > 1)
{
- RTLIL::Wire *reduce_or_wire = new RTLIL::Wire;
- reduce_or_wire->name = NEW_ID;
- module->wires[reduce_or_wire->name] = reduce_or_wire;
-
- RTLIL::Cell *reduce_or_cell = new RTLIL::Cell;
- reduce_or_cell->name = NEW_ID;
- reduce_or_cell->type = "$reduce_or";
- reduce_or_cell->connections["\\A"] = this_s;
+ RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, "$reduce_or");
+ reduce_or_cell->setPort("\\A", this_s);
reduce_or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.width);
+ reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.size());
reduce_or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- module->cells[reduce_or_cell->name] = reduce_or_cell;
+ RTLIL::Wire *reduce_or_wire = module->addWire(NEW_ID);
this_s = RTLIL::SigSpec(reduce_or_wire);
- reduce_or_cell->connections["\\Y"] = this_s;
+ reduce_or_cell->setPort("\\Y", this_s);
}
new_sig_b.append(this_b);
@@ -141,26 +136,24 @@ struct OptReduceWorker
handled_sig.insert(this_b);
}
- if (new_sig_s.width != sig_s.width) {
+ if (new_sig_s.size() != sig_s.size()) {
log(" New ctrl vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_s));
did_something = true;
- OPT_DID_SOMETHING = true;
total_count++;
}
- if (new_sig_s.width == 0)
+ if (new_sig_s.size() == 0)
{
- module->connections.push_back(RTLIL::SigSig(cell->connections["\\Y"], cell->connections["\\A"]));
- assign_map.add(cell->connections["\\Y"], cell->connections["\\A"]);
- module->cells.erase(cell->name);
- delete cell;
+ module->connect(RTLIL::SigSig(cell->getPort("\\Y"), cell->getPort("\\A")));
+ assign_map.add(cell->getPort("\\Y"), cell->getPort("\\A"));
+ module->remove(cell);
}
else
{
- cell->connections["\\B"] = new_sig_b;
- cell->connections["\\S"] = new_sig_s;
- if (new_sig_s.width > 1) {
- cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.width);
+ cell->setPort("\\B", new_sig_b);
+ cell->setPort("\\S", new_sig_s);
+ if (new_sig_s.size() > 1) {
+ cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size());
} else {
cell->type = "$mux";
cell->parameters.erase("\\S_WIDTH");
@@ -168,7 +161,85 @@ struct OptReduceWorker
}
}
- OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module) :
+ void opt_mux_bits(RTLIL::Cell *cell)
+ {
+ std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort("\\A")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort("\\B")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort("\\Y")).to_sigbit_vector();
+
+ std::vector<RTLIL::SigBit> new_sig_y;
+ RTLIL::SigSig old_sig_conn;
+
+ std::vector<std::vector<RTLIL::SigBit>> consolidated_in_tuples;
+ std::map<std::vector<RTLIL::SigBit>, RTLIL::SigBit> consolidated_in_tuples_map;
+
+ for (int i = 0; i < int(sig_y.size()); i++)
+ {
+ std::vector<RTLIL::SigBit> in_tuple;
+ bool all_tuple_bits_same = true;
+
+ in_tuple.push_back(sig_a.at(i));
+ for (int j = i; j < int(sig_b.size()); j += int(sig_a.size())) {
+ if (sig_b.at(j) != sig_a.at(i))
+ all_tuple_bits_same = false;
+ in_tuple.push_back(sig_b.at(j));
+ }
+
+ if (all_tuple_bits_same)
+ {
+ old_sig_conn.first.append_bit(sig_y.at(i));
+ old_sig_conn.second.append_bit(sig_a.at(i));
+ }
+ else if (consolidated_in_tuples_map.count(in_tuple))
+ {
+ old_sig_conn.first.append_bit(sig_y.at(i));
+ old_sig_conn.second.append_bit(consolidated_in_tuples_map.at(in_tuple));
+ }
+ else
+ {
+ consolidated_in_tuples_map[in_tuple] = sig_y.at(i);
+ consolidated_in_tuples.push_back(in_tuple);
+ new_sig_y.push_back(sig_y.at(i));
+ }
+ }
+
+ if (new_sig_y.size() != sig_y.size())
+ {
+ log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str());
+ log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
+ log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+
+ cell->setPort("\\A", RTLIL::SigSpec());
+ for (auto &in_tuple : consolidated_in_tuples) {
+ RTLIL::SigSpec new_a = cell->getPort("\\A");
+ new_a.append(in_tuple.at(0));
+ cell->setPort("\\A", new_a);
+ }
+
+ cell->setPort("\\B", RTLIL::SigSpec());
+ for (int i = 1; i <= cell->getPort("\\S").size(); i++)
+ for (auto &in_tuple : consolidated_in_tuples) {
+ RTLIL::SigSpec new_b = cell->getPort("\\B");
+ new_b.append(in_tuple.at(i));
+ cell->setPort("\\B", new_b);
+ }
+
+ cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size());
+ cell->setPort("\\Y", new_sig_y);
+
+ log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")),
+ log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y")));
+ log(" New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second));
+
+ module->connect(old_sig_conn);
+ module->check();
+
+ did_something = true;
+ total_count++;
+ }
+ }
+
+ OptReduceWorker(RTLIL::Design *design, RTLIL::Module *module, bool do_fine) :
design(design), module(module), assign_map(module)
{
log(" Optimizing cells in module %s.\n", module->name.c_str());
@@ -176,6 +247,35 @@ struct OptReduceWorker
total_count = 0;
did_something = true;
+ SigPool mem_wren_sigs;
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$mem")
+ mem_wren_sigs.add(assign_map(cell->getPort("\\WR_EN")));
+ if (cell->type == "$memwr")
+ mem_wren_sigs.add(assign_map(cell->getPort("\\EN")));
+ }
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Q"))))
+ mem_wren_sigs.add(assign_map(cell->getPort("\\D")));
+ }
+
+ bool keep_expanding_mem_wren_sigs = true;
+ while (keep_expanding_mem_wren_sigs) {
+ keep_expanding_mem_wren_sigs = false;
+ for (auto &cell_it : module->cells_) {
+ RTLIL::Cell *cell = cell_it.second;
+ if (cell->type == "$mux" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y")))) {
+ if (!mem_wren_sigs.check_all(assign_map(cell->getPort("\\A"))) ||
+ !mem_wren_sigs.check_all(assign_map(cell->getPort("\\B"))))
+ keep_expanding_mem_wren_sigs = true;
+ mem_wren_sigs.add(assign_map(cell->getPort("\\A")));
+ mem_wren_sigs.add(assign_map(cell->getPort("\\B")));
+ }
+ }
+ }
+
while (did_something)
{
did_something = false;
@@ -189,11 +289,11 @@ struct OptReduceWorker
SigSet<RTLIL::Cell*> drivers;
std::set<RTLIL::Cell*> cells;
- for (auto &cell_it : module->cells) {
+ for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
if (cell->type != type || !design->selected(module, cell))
continue;
- drivers.insert(assign_map(cell->connections["\\Y"]), cell);
+ drivers.insert(assign_map(cell->getPort("\\Y")), cell);
cells.insert(cell);
}
@@ -205,11 +305,19 @@ struct OptReduceWorker
// merge identical inputs on $mux and $pmux cells
- for (auto &cell_it : module->cells)
+ std::vector<RTLIL::Cell*> cells;
+
+ for (auto &it : module->cells_)
+ if ((it.second->type == "$mux" || it.second->type == "$pmux") && design->selected(module, it.second))
+ cells.push_back(it.second);
+
+ for (auto cell : cells)
{
- RTLIL::Cell *cell = cell_it.second;
- if ((cell->type != "$mux" && cell->type != "$pmux" && cell->type != "$safe_pmux") || !design->selected(module, cell))
- continue;
+ // this optimization is to aggressive for most coarse-grain applications.
+ // but we always want it for multiplexers driving write enable ports.
+ if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y"))))
+ opt_mux_bits(cell);
+
opt_mux(cell);
}
}
@@ -222,7 +330,7 @@ struct OptReducePass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_reduce [selection]\n");
+ log(" opt_reduce [options] [selection]\n");
log("\n");
log("This pass performs two interlinked optimizations:\n");
log("\n");
@@ -232,20 +340,40 @@ struct OptReducePass : public Pass {
log("2. it identifies duplicated inputs to MUXes and replaces them with a single\n");
log("input with the original control signals OR'ed together.\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)
{
+ bool do_fine = false;
+
log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
- extra_args(args, 1, design);
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-fine") {
+ do_fine = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
- OptReduceWorker worker(design, mod_it.second);
- total_count += worker.total_count;
+ do {
+ OptReduceWorker worker(design, mod_it.second, 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);
log("Performed a total of %d changes.\n", total_count);
}
} OptReducePass;
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index 9a438537c..48f406f65 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -17,7 +17,6 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
@@ -33,34 +32,34 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
RTLIL::Const val_cp, val_rp, val_rv;
if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\C"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1);
}
else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" &&
(dff->type[6] == 'N' || dff->type[6] == 'P') &&
(dff->type[7] == 'N' || dff->type[7] == 'P') &&
(dff->type[8] == '0' || dff->type[8] == '1')) {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\C"];
- sig_r = dff->connections["\\R"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\C");
+ sig_r = dff->getPort("\\R");
val_cp = RTLIL::Const(dff->type[6] == 'P', 1);
val_rp = RTLIL::Const(dff->type[7] == 'P', 1);
val_rv = RTLIL::Const(dff->type[8] == '1', 1);
}
else if (dff->type == "$dff") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\CLK"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
}
else if (dff->type == "$adff") {
- sig_d = dff->connections["\\D"];
- sig_q = dff->connections["\\Q"];
- sig_c = dff->connections["\\CLK"];
- sig_r = dff->connections["\\ARST"];
+ sig_d = dff->getPort("\\D");
+ sig_q = dff->getPort("\\Q");
+ sig_c = dff->getPort("\\CLK");
+ sig_r = dff->getPort("\\ARST");
val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1);
val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1);
val_rv = dff->parameters["\\ARST_VALUE"];
@@ -85,55 +84,55 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
std::set<RTLIL::Cell*> muxes;
mux_drivers.find(sig_d, muxes);
for (auto mux : muxes) {
- RTLIL::SigSpec sig_a = assign_map(mux->connections.at("\\A"));
- RTLIL::SigSpec sig_b = assign_map(mux->connections.at("\\B"));
+ RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A"));
+ RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B"));
if (sig_a == sig_q && sig_b.is_fully_const()) {
RTLIL::SigSig conn(sig_q, sig_b);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
if (sig_b == sig_q && sig_a.is_fully_const()) {
RTLIL::SigSig conn(sig_q, sig_a);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
}
}
- if (sig_c.is_fully_const() && (!sig_r.width || !has_init)) {
+ if (sig_c.is_fully_const() && (!sig_r.size() || !has_init)) {
if (val_rv.bits.size() == 0)
val_rv = val_init;
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_undef() && sig_r.width && !has_init) {
+ if (sig_d.is_fully_undef() && sig_r.size() && !has_init) {
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_undef() && !sig_r.width && has_init) {
+ if (sig_d.is_fully_undef() && !sig_r.size() && has_init) {
RTLIL::SigSig conn(sig_q, val_init);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d.is_fully_const() && !sig_r.width && !has_init) {
+ if (sig_d.is_fully_const() && !sig_r.size() && !has_init) {
RTLIL::SigSig conn(sig_q, sig_d);
- mod->connections.push_back(conn);
+ mod->connect(conn);
goto delete_dff;
}
- if (sig_d == sig_q && !(sig_r.width && has_init)) {
- if (sig_r.width) {
+ if (sig_d == sig_q && !(sig_r.size() && has_init)) {
+ if (sig_r.size()) {
RTLIL::SigSig conn(sig_q, val_rv);
- mod->connections.push_back(conn);
+ mod->connect(conn);
}
if (has_init) {
RTLIL::SigSig conn(sig_q, val_init);
- mod->connections.push_back(conn);
+ mod->connect(conn);
}
goto delete_dff;
}
@@ -142,9 +141,7 @@ static bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
delete_dff:
log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str());
- OPT_DID_SOMETHING = true;
- mod->cells.erase(dff->name);
- delete dff;
+ mod->remove(dff);
return true;
}
@@ -167,23 +164,23 @@ struct OptRmdffPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
assign_map.set(mod_it.second);
dff_init_map.set(mod_it.second);
- for (auto &it : mod_it.second->wires)
+ for (auto &it : mod_it.second->wires_)
if (it.second->attributes.count("\\init") != 0)
dff_init_map.add(it.second, it.second->attributes.at("\\init"));
mux_drivers.clear();
- std::vector<std::string> dff_list;
- for (auto &it : mod_it.second->cells) {
+ std::vector<RTLIL::IdString> dff_list;
+ for (auto &it : mod_it.second->cells_) {
if (it.second->type == "$mux" || it.second->type == "$pmux") {
- if (it.second->connections.at("\\A").width == it.second->connections.at("\\B").width)
- mux_drivers.insert(assign_map(it.second->connections.at("\\Y")), it.second);
+ if (it.second->getPort("\\A").size() == it.second->getPort("\\B").size())
+ mux_drivers.insert(assign_map(it.second->getPort("\\Y")), it.second);
continue;
}
if (!design->selected(mod_it.second, it.second))
@@ -203,14 +200,17 @@ struct OptRmdffPass : public Pass {
}
for (auto &id : dff_list) {
- if (mod_it.second->cells.count(id) > 0 &&
- handle_dff(mod_it.second, mod_it.second->cells[id]))
+ if (mod_it.second->cells_.count(id) > 0 &&
+ handle_dff(mod_it.second, mod_it.second->cells_[id]))
total_count++;
}
}
assign_map.clear();
mux_drivers.clear();
+
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Replaced %d DFF cells.\n", total_count);
}
} OptRmdffPass;
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc
index eb639d8ab..4b76a5a2d 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_share.cc
@@ -17,14 +17,12 @@
*
*/
-#include "opt_status.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include "kernel/celltypes.h"
#include "libs/sha1/sha1.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <set>
@@ -61,12 +59,12 @@ struct OptShareWorker
if (cell_hash_cache.count(cell) > 0)
return cell_hash_cache[cell];
- std::string hash_string = cell->type + "\n";
+ std::string hash_string = cell->type.str() + "\n";
for (auto &it : cell->parameters)
- hash_string += "P " + it.first + "=" + it.second.as_string() + "\n";
+ hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n";
- const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections;
+ const std::map<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections();
std::map<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" ||
@@ -96,24 +94,19 @@ struct OptShareWorker
continue;
RTLIL::SigSpec sig = it.second;
assign_map.apply(sig);
- hash_string += "C " + it.first + "=";
- for (auto &chunk : sig.chunks) {
+ hash_string += "C " + it.first.str() + "=";
+ for (auto &chunk : sig.chunks()) {
if (chunk.wire)
- hash_string += "{" + chunk.wire->name + " " +
+ hash_string += "{" + chunk.wire->name.str() + " " +
int_to_hash_string(chunk.offset) + " " +
int_to_hash_string(chunk.width) + "}";
else
- hash_string += chunk.data.as_string();
+ hash_string += RTLIL::Const(chunk.data).as_string();
}
hash_string += "\n";
}
- unsigned char hash[20];
- char hash_hex_string[41];
- sha1::calc(hash_string.c_str(), hash_string.size(), hash);
- sha1::toHexString(hash, hash_hex_string);
- cell_hash_cache[cell] = hash_hex_string;
-
+ cell_hash_cache[cell] = sha1(hash_string);
return cell_hash_cache[cell];
}
#endif
@@ -135,8 +128,8 @@ struct OptShareWorker
return true;
}
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections;
- std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections;
+ std::map<RTLIL::IdString, RTLIL::SigSpec> conn1 = cell1->connections();
+ std::map<RTLIL::IdString, RTLIL::SigSpec> conn2 = cell2->connections();
for (auto &it : conn1) {
if (ct.cell_output(cell1->type, it.first))
@@ -180,8 +173,8 @@ struct OptShareWorker
}
if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) {
- std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->connections.at("\\Q")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector();
for (size_t i = 0; i < q1.size(); i++)
if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) {
lt = q1.at(i) < q2.at(i);
@@ -230,14 +223,13 @@ struct OptShareWorker
if (mode_nomux) {
ct.cell_types.erase("$mux");
ct.cell_types.erase("$pmux");
- ct.cell_types.erase("$safe_pmux");
}
log("Finding identical cells in module `%s'.\n", module->name.c_str());
assign_map.set(module);
dff_init_map.set(module);
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->attributes.count("\\init") != 0)
dff_init_map.add(it.second, it.second->attributes.at("\\init"));
@@ -248,8 +240,8 @@ struct OptShareWorker
cell_hash_cache.clear();
#endif
std::vector<RTLIL::Cell*> cells;
- cells.reserve(module->cells.size());
- for (auto &it : module->cells) {
+ cells.reserve(module->cells_.size());
+ for (auto &it : module->cells_) {
if (ct.cell_known(it.second->type) && design->selected(module, it.second))
cells.push_back(it.second);
}
@@ -261,20 +253,18 @@ struct OptShareWorker
if (sharemap.count(cell) > 0) {
did_something = true;
log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
- for (auto &it : cell->connections) {
+ for (auto &it : cell->connections()) {
if (ct.cell_output(cell->type, it.first)) {
- RTLIL::SigSpec other_sig = sharemap[cell]->connections[it.first];
+ RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first);
log(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig));
- module->connections.push_back(RTLIL::SigSig(it.second, other_sig));
+ module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig);
}
}
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
- module->cells.erase(cell->name);
- OPT_DID_SOMETHING = true;
+ module->remove(cell);
total_count++;
- delete cell;
} else {
sharemap[cell] = cell;
}
@@ -316,13 +306,15 @@ struct OptSharePass : public Pass {
extra_args(args, argidx, design);
int total_count = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
if (!design->selected(mod_it.second))
continue;
OptShareWorker worker(design, mod_it.second, mode_nomux);
total_count += worker.total_count;
}
+ if (total_count)
+ design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count);
}
} OptSharePass;
diff --git a/passes/opt/opt_status.h b/passes/opt/opt_status.h
deleted file mode 100644
index 3d12baa7d..000000000
--- a/passes/opt/opt_status.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 OPT_STATUS_H
-#define OPT_STATUS_H
-
-extern bool OPT_DID_SOMETHING;
-
-#endif
-
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
new file mode 100644
index 000000000..74b049bb6
--- /dev/null
+++ b/passes/opt/share.cc
@@ -0,0 +1,1171 @@
+/*
+ * 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"
+#include "kernel/modtools.h"
+#include "kernel/utils.h"
+
+PRIVATE_NAMESPACE_BEGIN
+
+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;
+};
+
+struct ShareWorker
+{
+ ShareWorkerConfig config;
+ std::set<RTLIL::IdString> generic_ops;
+
+ RTLIL::Design *design;
+ RTLIL::Module *module;
+
+ CellTypes fwd_ct, cone_ct;
+ ModWalker modwalker;
+ ModIndex mi;
+
+ std::set<RTLIL::Cell*> cells_to_remove;
+ std::set<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;
+
+
+ // ------------------------------------------------------------------------------
+ // Find terminal bits -- i.e. bits that do not (exclusively) feed into a mux tree
+ // ------------------------------------------------------------------------------
+
+ std::set<RTLIL::SigBit> terminal_bits;
+
+ void find_terminal_bits()
+ {
+ std::set<RTLIL::SigBit> queue_bits;
+ std::set<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];
+ queue_bits.insert(bits.begin(), bits.end());
+ }
+
+ terminal_bits.insert(queue_bits.begin(), queue_bits.end());
+
+ while (!queue_bits.empty())
+ {
+ std::set<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();
+ 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];
+ terminal_bits.insert(bits.begin(), bits.end());
+ queue_bits.insert(bits.begin(), bits.end());
+ visited_cells.insert(pbit.cell);
+ }
+ }
+ }
+ }
+
+
+ // ---------------------------------------------------
+ // Find shareable cells and compatible groups of cells
+ // ---------------------------------------------------
+
+ std::set<RTLIL::Cell*, RTLIL::sort_by_name_str<RTLIL::Cell>> shareable_cells;
+
+ void find_shareable_cells()
+ {
+ for (auto &it : module->cells_)
+ {
+ RTLIL::Cell *cell = it.second;
+
+ if (!design->selected(module, cell) || !modwalker.ct.cell_known(cell->type))
+ continue;
+
+ for (auto &bit : modwalker.cell_outputs[cell])
+ if (terminal_bits.count(bit))
+ goto not_a_muxed_cell;
+
+ if (0)
+ not_a_muxed_cell:
+ continue;
+
+ if (config.opt_force) {
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$memrd") {
+ if (!cell->parameters.at("\\CLK_ENABLE").as_bool())
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod") {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 4)
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 8)
+ shareable_cells.insert(cell);
+ continue;
+ }
+
+ if (generic_ops.count(cell->type)) {
+ if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 10)
+ shareable_cells.insert(cell);
+ continue;
+ }
+ }
+ }
+
+ bool is_shareable_pair(RTLIL::Cell *c1, RTLIL::Cell *c2)
+ {
+ if (c1->type != c2->type)
+ return false;
+
+ if (c1->type == "$memrd")
+ {
+ if (c1->parameters.at("\\MEMID").decode_string() != c2->parameters.at("\\MEMID").decode_string())
+ return false;
+
+ return true;
+ }
+
+ if (config.generic_uni_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ }
+
+ return true;
+ }
+
+ if (config.generic_bin_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ if (std::max(a1_width, a2_width) > 2 * std::min(a1_width, a2_width)) return false;
+ if (std::max(b1_width, b2_width) > 2 * std::min(b1_width, b2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) return false;
+ }
+
+ return true;
+ }
+
+ if (config.generic_cbin_ops.count(c1->type))
+ {
+ if (!config.opt_aggressive)
+ {
+ int a1_width = c1->parameters.at("\\A_WIDTH").as_int();
+ int b1_width = c1->parameters.at("\\B_WIDTH").as_int();
+ int y1_width = c1->parameters.at("\\Y_WIDTH").as_int();
+
+ int a2_width = c2->parameters.at("\\A_WIDTH").as_int();
+ int b2_width = c2->parameters.at("\\B_WIDTH").as_int();
+ int y2_width = c2->parameters.at("\\Y_WIDTH").as_int();
+
+ int min1_width = std::min(a1_width, b1_width);
+ int max1_width = std::max(a1_width, b1_width);
+
+ int min2_width = std::min(a2_width, b2_width);
+ int max2_width = std::max(a2_width, b2_width);
+
+ if (std::max(min1_width, min2_width) > 2 * std::min(min1_width, min2_width)) return false;
+ if (std::max(max1_width, max2_width) > 2 * std::min(max1_width, max2_width)) return false;
+ if (std::max(y1_width, y2_width) > 2 * std::min(y1_width, y2_width)) 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;
+
+ for (auto &it : c2->parameters)
+ if (c1->parameters.count(it.first) == 0 || c1->parameters.at(it.first) != it.second)
+ return false;
+
+ return true;
+ }
+
+ void find_shareable_partners(std::vector<RTLIL::Cell*> &results, RTLIL::Cell *cell)
+ {
+ results.clear();
+ for (auto c : shareable_cells)
+ if (c != cell && is_shareable_pair(c, cell))
+ results.push_back(c);
+ }
+
+
+ // -----------------------
+ // Create replacement cell
+ // -----------------------
+
+ RTLIL::Cell *make_supercell(RTLIL::Cell *c1, RTLIL::Cell *c2, RTLIL::SigSpec act, std::set<RTLIL::Cell*> &supercell_aux)
+ {
+ log_assert(c1->type == c2->type);
+
+ if (config.generic_uni_ops.count(c1->type))
+ {
+ if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ new_a.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\A", new_a);
+ }
+ unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ unsigned_cell->check();
+ }
+
+ bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
+ log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
+
+ RTLIL::SigSpec a1 = c1->getPort("\\A");
+ RTLIL::SigSpec y1 = c1->getPort("\\Y");
+
+ RTLIL::SigSpec a2 = c2->getPort("\\A");
+ RTLIL::SigSpec y2 = c2->getPort("\\Y");
+
+ int a_width = std::max(a1.size(), a2.size());
+ int y_width = std::max(y1.size(), y2.size());
+
+ a1.extend_u0(a_width, a_signed);
+ a2.extend_u0(a_width, a_signed);
+
+ RTLIL::SigSpec a = module->addWire(NEW_ID, a_width);
+ supercell_aux.insert(module->addMux(NEW_ID, a2, a1, act, a));
+
+ RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell->parameters["\\A_SIGNED"] = a_signed;
+ supercell->parameters["\\A_WIDTH"] = a_width;
+ supercell->parameters["\\Y_WIDTH"] = y_width;
+ supercell->setPort("\\A", a);
+ supercell->setPort("\\Y", y);
+
+ supercell_aux.insert(module->addPos(NEW_ID, y, y1));
+ supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type))
+ {
+ bool modified_src_cells = false;
+
+ if (config.generic_cbin_ops.count(c1->type))
+ {
+ int score_unflipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) +
+ std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int());
+
+ int score_flipped = std::max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) +
+ std::max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int());
+
+ if (score_flipped < score_unflipped)
+ {
+ RTLIL::SigSpec tmp = c2->getPort("\\A");
+ c2->setPort("\\A", c2->getPort("\\B"));
+ c2->setPort("\\B", tmp);
+
+ std::swap(c2->parameters.at("\\A_WIDTH"), c2->parameters.at("\\B_WIDTH"));
+ std::swap(c2->parameters.at("\\A_SIGNED"), c2->parameters.at("\\B_SIGNED"));
+ modified_src_cells = true;
+ }
+ }
+
+ if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool())
+
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A");
+ new_a.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\A", new_a);
+ }
+ unsigned_cell->parameters.at("\\A_SIGNED") = true;
+ modified_src_cells = true;
+ }
+
+ if (c1->parameters.at("\\B_SIGNED").as_bool() != c2->parameters.at("\\B_SIGNED").as_bool())
+ {
+ RTLIL::Cell *unsigned_cell = c1->parameters.at("\\B_SIGNED").as_bool() ? c2 : c1;
+ if (unsigned_cell->getPort("\\B").to_sigbit_vector().back() != RTLIL::State::S0) {
+ unsigned_cell->parameters.at("\\B_WIDTH") = unsigned_cell->parameters.at("\\B_WIDTH").as_int() + 1;
+ RTLIL::SigSpec new_b = unsigned_cell->getPort("\\B");
+ new_b.append_bit(RTLIL::State::S0);
+ unsigned_cell->setPort("\\B", new_b);
+ }
+ unsigned_cell->parameters.at("\\B_SIGNED") = true;
+ modified_src_cells = true;
+ }
+
+ if (modified_src_cells) {
+ c1->check();
+ c2->check();
+ }
+
+ bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool();
+ bool b_signed = c1->parameters.at("\\B_SIGNED").as_bool();
+
+ log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool());
+ log_assert(b_signed == c2->parameters.at("\\B_SIGNED").as_bool());
+
+ if (c1->type == "$shl" || c1->type == "$shr" || c1->type == "$sshl" || c1->type == "$sshr")
+ b_signed = false;
+
+ RTLIL::SigSpec a1 = c1->getPort("\\A");
+ RTLIL::SigSpec b1 = c1->getPort("\\B");
+ RTLIL::SigSpec y1 = c1->getPort("\\Y");
+
+ RTLIL::SigSpec a2 = c2->getPort("\\A");
+ RTLIL::SigSpec b2 = c2->getPort("\\B");
+ RTLIL::SigSpec y2 = c2->getPort("\\Y");
+
+ int a_width = std::max(a1.size(), a2.size());
+ int b_width = std::max(b1.size(), b2.size());
+ int y_width = std::max(y1.size(), y2.size());
+
+ if (c1->type == "$shr" && a_signed)
+ {
+ a_width = std::max(y_width, a_width);
+
+ if (a1.size() < y1.size()) a1.extend_u0(y1.size(), true);
+ if (a2.size() < y2.size()) a2.extend_u0(y2.size(), true);
+
+ a1.extend_u0(a_width, false);
+ a2.extend_u0(a_width, false);
+ }
+ else
+ {
+ a1.extend_u0(a_width, a_signed);
+ a2.extend_u0(a_width, a_signed);
+ }
+
+ b1.extend_u0(b_width, b_signed);
+ b2.extend_u0(b_width, b_signed);
+
+ RTLIL::SigSpec a = module->addWire(NEW_ID, a_width);
+ RTLIL::SigSpec b = module->addWire(NEW_ID, b_width);
+
+ supercell_aux.insert(module->addMux(NEW_ID, a2, a1, act, a));
+ supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b));
+
+ RTLIL::Wire *y = module->addWire(NEW_ID, y_width);
+
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type);
+ supercell->parameters["\\A_SIGNED"] = a_signed;
+ supercell->parameters["\\B_SIGNED"] = b_signed;
+ supercell->parameters["\\A_WIDTH"] = a_width;
+ supercell->parameters["\\B_WIDTH"] = b_width;
+ supercell->parameters["\\Y_WIDTH"] = y_width;
+ supercell->setPort("\\A", a);
+ supercell->setPort("\\B", b);
+ supercell->setPort("\\Y", y);
+ supercell->check();
+
+ supercell_aux.insert(module->addPos(NEW_ID, y, y1));
+ supercell_aux.insert(module->addPos(NEW_ID, y, y2));
+
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ if (c1->type == "$memrd")
+ {
+ RTLIL::Cell *supercell = module->addCell(NEW_ID, c1);
+ supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort("\\DATA"), c2->getPort("\\DATA")));
+ supercell_aux.insert(supercell);
+ return supercell;
+ }
+
+ log_abort();
+ }
+
+
+ // -------------------------------------------
+ // Finding forbidden control inputs for a cell
+ // -------------------------------------------
+
+ std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> forbidden_controls_cache;
+
+ const std::set<RTLIL::SigBit> &find_forbidden_controls(RTLIL::Cell *cell)
+ {
+ if (recursion_state.count(cell)) {
+ static std::set<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;
+
+ modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]);
+
+ for (auto &bit : pbits) {
+ if ((bit.cell->type == "$mux" || bit.cell->type == "$pmux") && bit.port == "\\S")
+ forbidden_controls_cache[cell].insert(bit.cell->getPort("\\S").extract(bit.offset, 1));
+ consumer_cells.insert(bit.cell);
+ }
+
+ recursion_state.insert(cell);
+
+ for (auto c : consumer_cells)
+ if (fwd_ct.cell_known(c->type)) {
+ const std::set<RTLIL::SigBit> &bits = find_forbidden_controls(c);
+ forbidden_controls_cache[cell].insert(bits.begin(), bits.end());
+ }
+
+ log_assert(recursion_state.count(cell));
+ recursion_state.erase(cell);
+
+ return forbidden_controls_cache[cell];
+ }
+
+
+ // --------------------------------------------------------
+ // Finding control inputs and activation pattern for a cell
+ // --------------------------------------------------------
+
+ std::map<RTLIL::Cell*, std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>>> activation_patterns_cache;
+
+ bool sort_check_activation_pattern(std::pair<RTLIL::SigSpec, RTLIL::Const> &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++) {
+ RTLIL::SigBit b = p_first_bits[i];
+ RTLIL::State v = p.second.bits[i];
+ if (p_bits.count(b) && p_bits.at(b) != v)
+ return false;
+ p_bits[b] = v;
+ }
+
+ p.first = RTLIL::SigSpec();
+ p.second.bits.clear();
+
+ for (auto &it : p_bits) {
+ p.first.append_bit(it.first);
+ p.second.bits.push_back(it.second);
+ }
+
+ return true;
+ }
+
+ void optimize_activation_patterns(std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> & /* 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)
+ {
+ if (recursion_state.count(cell)) {
+ static std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> 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;
+
+ 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>());
+ return activation_patterns_cache.at(cell);
+ }
+ for (auto &pbit : modwalker.signal_consumers[bit]) {
+ log_assert(fwd_ct.cell_known(pbit.cell->type));
+ if ((pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") && (pbit.port == "\\A" || pbit.port == "\\B"))
+ driven_data_muxes.insert(pbit.cell);
+ else
+ driven_cells.insert(pbit.cell);
+ }
+ }
+
+ recursion_state.insert(cell);
+
+ for (auto c : driven_data_muxes)
+ {
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &c_patterns = find_cell_activation_patterns(c, indent);
+
+ bool used_in_a = false;
+ std::set<int> used_in_b_parts;
+
+ int width = c->parameters.at("\\WIDTH").as_int();
+ std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort("\\A"));
+ std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort("\\B"));
+ std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort("\\S"));
+
+ for (auto &bit : sig_a)
+ if (cell_out_bits.count(bit))
+ used_in_a = true;
+
+ for (int i = 0; i < SIZE(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++)
+ 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);
+ }
+
+ for (int idx : used_in_b_parts)
+ for (auto p : c_patterns) {
+ p.first.append_bit(sig_s[idx]), p.second.bits.push_back(RTLIL::State::S1);
+ if (sort_check_activation_pattern(p))
+ activation_patterns_cache[cell].insert(p);
+ }
+ }
+
+ for (auto c : driven_cells) {
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &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));
+ recursion_state.erase(cell);
+
+ optimize_activation_patterns(activation_patterns_cache[cell]);
+ if (activation_patterns_cache[cell].empty()) {
+ log("%sFound cell that is never activated: %s\n", indent, log_id(cell));
+ RTLIL::SigSpec cell_outputs = modwalker.cell_outputs[cell];
+ module->connect(RTLIL::SigSig(cell_outputs, RTLIL::SigSpec(RTLIL::State::Sx, cell_outputs.size())));
+ cells_to_remove.insert(cell);
+ }
+
+ return activation_patterns_cache[cell];
+ }
+
+ RTLIL::SigSpec bits_from_activation_patterns(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns)
+ {
+ std::set<RTLIL::SigBit> all_bits;
+ for (auto &it : activation_patterns) {
+ std::vector<RTLIL::SigBit> bits = it.first;
+ all_bits.insert(bits.begin(), bits.end());
+ }
+
+ RTLIL::SigSpec signal;
+ for (auto &bit : all_bits)
+ signal.append_bit(bit);
+
+ 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)
+ {
+ for (auto &p : in)
+ {
+ std::vector<RTLIL::SigBit> p_first = p.first;
+ std::pair<RTLIL::SigSpec, RTLIL::Const> new_p;
+
+ for (int i = 0; i < SIZE(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));
+ }
+
+ out.insert(new_p);
+ }
+ }
+
+ RTLIL::SigSpec make_cell_activation_logic(const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &activation_patterns, std::set<RTLIL::Cell*> &supercell_aux)
+ {
+ RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0);
+
+ for (auto &p : activation_patterns) {
+ all_cases_wire->width++;
+ supercell_aux.insert(module->addEq(NEW_ID, p.first, p.second, RTLIL::SigSpec(all_cases_wire, all_cases_wire->width - 1)));
+ }
+
+ if (all_cases_wire->width == 1)
+ return all_cases_wire;
+
+ RTLIL::Wire *result_wire = module->addWire(NEW_ID);
+ supercell_aux.insert(module->addReduceOr(NEW_ID, all_cases_wire, result_wire));
+ return result_wire;
+ }
+
+
+ // -------------------------------------------------------------------------------------
+ // Helper functions used to make sure that this pass does not introduce new logic loops.
+ // -------------------------------------------------------------------------------------
+
+ bool module_has_scc()
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ TopoSort<RTLIL::Cell*> 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;
+
+ for (auto cell : module->cells())
+ if (ct.cell_known(cell->type))
+ for (auto &conn : cell->connections()) {
+ if (ct.cell_output(cell->type, conn.first))
+ for (auto bit : topo_sigmap(conn.second)) {
+ cell_to_bits[cell].insert(bit);
+ topo_bit_drivers[bit].insert(cell);
+ }
+ else
+ for (auto bit : topo_sigmap(conn.second))
+ bit_to_cells[bit].insert(cell);
+ }
+
+ for (auto &it : cell_to_bits)
+ {
+ RTLIL::Cell *c1 = it.first;
+
+ for (auto bit : it.second)
+ for (auto c2 : bit_to_cells[bit])
+ toposort.edge(c1, c2);
+ }
+
+ bool found_scc = !toposort.sort();
+ topo_cell_drivers = std::move(toposort.database);
+
+ if (found_scc && toposort.analyze_loops)
+ for (auto &loop : toposort.loops) {
+ log("### loop ###\n");
+ for (auto &c : loop)
+ log("%s (%s)\n", log_id(c), log_id(c->type));
+ }
+
+ return found_scc;
+ }
+
+ bool find_in_input_cone_worker(RTLIL::Cell *root, RTLIL::Cell *needle, std::set<RTLIL::Cell*> &stop)
+ {
+ if (root == needle)
+ return true;
+
+ if (stop.count(root))
+ return false;
+
+ stop.insert(root);
+
+ for (auto c : topo_cell_drivers[root])
+ if (find_in_input_cone_worker(c, needle, stop))
+ return true;
+ return false;
+ }
+
+ bool find_in_input_cone(RTLIL::Cell *root, RTLIL::Cell *needle)
+ {
+ std::set<RTLIL::Cell*> stop;
+ return find_in_input_cone_worker(root, needle, stop);
+ }
+
+ bool is_part_of_scc(RTLIL::Cell *cell)
+ {
+ CellTypes ct;
+ ct.setup_internals();
+ ct.setup_stdcells();
+
+ std::set<RTLIL::Cell*> queue, covered;
+ queue.insert(cell);
+
+ while (!queue.empty())
+ {
+ std::set<RTLIL::Cell*> new_queue;
+
+ for (auto c : queue) {
+ if (!ct.cell_known(c->type))
+ continue;
+ for (auto &conn : c->connections())
+ if (ct.cell_input(c->type, conn.first))
+ for (auto bit : conn.second)
+ for (auto &pi : mi.query_ports(bit))
+ if (ct.cell_known(pi.cell->type) && ct.cell_output(pi.cell->type, pi.port))
+ new_queue.insert(pi.cell);
+ covered.insert(c);
+ }
+
+ queue.clear();
+ for (auto c : new_queue) {
+ if (cells_to_remove.count(c))
+ continue;
+ if (c == cell)
+ return true;
+ if (!covered.count(c))
+ queue.insert(c);
+ }
+ }
+
+ return false;
+ }
+
+
+ // -------------
+ // Setup and run
+ // -------------
+
+ ShareWorker(ShareWorkerConfig config, RTLIL::Design *design, RTLIL::Module *module) :
+ config(config), design(design), module(module), mi(module)
+ {
+ bool before_scc = module_has_scc();
+
+ 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());
+
+ fwd_ct.setup_internals();
+
+ cone_ct.setup_internals();
+ cone_ct.cell_types.erase("$mul");
+ cone_ct.cell_types.erase("$mod");
+ cone_ct.cell_types.erase("$div");
+ cone_ct.cell_types.erase("$pow");
+ cone_ct.cell_types.erase("$shl");
+ cone_ct.cell_types.erase("$shr");
+ cone_ct.cell_types.erase("$sshl");
+ cone_ct.cell_types.erase("$sshr");
+
+ modwalker.setup(design, module);
+
+ find_terminal_bits();
+ find_shareable_cells();
+
+ if (shareable_cells.size() < 2)
+ return;
+
+ log("Found %d cells in module %s that may be considered for resource sharing.\n",
+ SIZE(shareable_cells), log_id(module));
+
+ 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));
+
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &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()) {
+ log(" Cell is never active. Sharing is pointless, we simply remove it.\n");
+ cells_to_remove.insert(cell);
+ continue;
+ }
+
+ if (cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ 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));
+
+ std::vector<RTLIL::Cell*> candidates;
+ find_shareable_partners(candidates, cell);
+
+ if (candidates.empty()) {
+ log(" No candidates found.\n");
+ continue;
+ }
+
+ log(" Found %d candidates:", SIZE(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));
+
+ const std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> &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()) {
+ log(" Cell is never active. Sharing is pointless, we simply remove it.\n");
+ shareable_cells.erase(other_cell);
+ cells_to_remove.insert(other_cell);
+ continue;
+ }
+
+ if (other_cell_activation_patterns.count(std::pair<RTLIL::SigSpec, RTLIL::Const>())) {
+ 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));
+
+ 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);
+
+ std::set<RTLIL::SigBit> union_forbidden_controls;
+ union_forbidden_controls.insert(cell_forbidden_controls.begin(), cell_forbidden_controls.end());
+ union_forbidden_controls.insert(other_cell_forbidden_controls.begin(), other_cell_forbidden_controls.end());
+
+ 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;
+
+ 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);
+
+ optimize_activation_patterns(filtered_cell_activation_patterns);
+ optimize_activation_patterns(filtered_other_cell_activation_patterns);
+
+ ezDefaultSAT ez;
+ SatGen satgen(&ez, &modwalker.sigmap);
+
+ std::set<RTLIL::Cell*> sat_cells;
+ std::set<RTLIL::SigBit> bits_queue;
+
+ std::vector<int> cell_active, other_cell_active;
+ RTLIL::SigSpec all_ctrl_signals;
+
+ 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)));
+ 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)));
+ all_ctrl_signals.append(p.first);
+ }
+
+ for (auto &bit : cell_activation_signals.to_sigbit_vector())
+ bits_queue.insert(bit);
+
+ for (auto &bit : other_cell_activation_signals.to_sigbit_vector())
+ bits_queue.insert(bit);
+
+ while (!bits_queue.empty())
+ {
+ std::set<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)) {
+ if (config.opt_fast && modwalker.cell_outputs[pbit.cell].size() >= 4)
+ continue;
+ // log(" Adding cell %s (%s) to SAT problem.\n", log_id(pbit.cell), log_id(pbit.cell->type));
+ bits_queue.insert(modwalker.cell_inputs[pbit.cell].begin(), modwalker.cell_inputs[pbit.cell].end());
+ satgen.importCell(pbit.cell);
+ sat_cells.insert(pbit.cell);
+ }
+
+ if (config.opt_fast && sat_cells.size() > 100)
+ break;
+ }
+
+ 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))) {
+ 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();
+
+ 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)));
+
+ log(" Size of SAT problem: %d cells, %d variables, %d clauses\n",
+ SIZE(sat_cells), ez.numCnfVariables(), ez.numCnfClauses());
+
+ 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("%c", sat_model_values[i] ? '1' : '0');
+ log("\n");
+ continue;
+ }
+
+ log(" According to the SAT solver this pair of cells can be shared.\n");
+
+ if (find_in_input_cone(cell, other_cell)) {
+ log(" Sharing not possible: %s is in input cone of %s.\n", log_id(other_cell), log_id(cell));
+ continue;
+ }
+
+ if (find_in_input_cone(other_cell, cell)) {
+ log(" Sharing not possible: %s is in input cone of %s.\n", log_id(cell), log_id(other_cell));
+ continue;
+ }
+
+ shareable_cells.erase(other_cell);
+
+ int cell_select_score = 0;
+ int other_cell_select_score = 0;
+
+ for (auto &p : filtered_cell_activation_patterns)
+ cell_select_score += p.first.size();
+
+ for (auto &p : filtered_other_cell_activation_patterns)
+ other_cell_select_score += p.first.size();
+
+ RTLIL::Cell *supercell;
+ std::set<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);
+ log(" Activation signal for %s: %s\n", log_id(cell), log_signal(act));
+ } else {
+ RTLIL::SigSpec act = make_cell_activation_logic(filtered_other_cell_activation_patterns, supercell_aux);
+ supercell = make_supercell(other_cell, cell, act, supercell_aux);
+ log(" Activation signal for %s: %s\n", log_id(other_cell), log_signal(act));
+ }
+
+ log(" New cell: %s (%s)\n", log_id(supercell), log_id(supercell->type));
+
+ cells_to_remove.insert(cell);
+ cells_to_remove.insert(other_cell);
+
+ for (auto c : supercell_aux)
+ if (is_part_of_scc(c))
+ goto do_rollback;
+
+ if (0) {
+ do_rollback:
+ log(" New topology contains loops! Rolling back..\n");
+ cells_to_remove.erase(cell);
+ cells_to_remove.erase(other_cell);
+ shareable_cells.insert(other_cell);
+ for (auto cc : supercell_aux)
+ module->remove(cc);
+ continue;
+ }
+
+ std::set<std::pair<RTLIL::SigSpec, RTLIL::Const>> 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);
+ activation_patterns_cache[supercell] = supercell_activation_patterns;
+ shareable_cells.insert(supercell);
+
+ for (auto bit : topo_sigmap(all_ctrl_signals))
+ for (auto c : topo_bit_drivers[bit])
+ topo_cell_drivers[supercell].insert(c);
+
+ topo_cell_drivers[supercell].insert(topo_cell_drivers[cell].begin(), topo_cell_drivers[cell].end());
+ topo_cell_drivers[supercell].insert(topo_cell_drivers[other_cell].begin(), topo_cell_drivers[other_cell].end());
+
+ topo_cell_drivers[cell] = { supercell };
+ topo_cell_drivers[other_cell] = { supercell };
+
+ if (config.limit > 0)
+ config.limit--;
+
+ break;
+ }
+ }
+
+ if (!cells_to_remove.empty()) {
+ log("Removing %d cells in module %s:\n", SIZE(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);
+ }
+ }
+
+ log_assert(recursion_state.empty());
+
+ bool after_scc = before_scc || module_has_scc();
+ log_assert(before_scc == after_scc);
+ }
+};
+
+struct SharePass : public Pass {
+ SharePass() : Pass("share", "perform sat-based resource sharing") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" share [options] [selection]\n");
+ log("\n");
+ log("This pass merges shareable resources into a single resource. A SAT solver\n");
+ log("is used to determine if two resources are share-able.\n");
+ log("\n");
+ log(" -force\n");
+ log(" Per default the selection of cells that is considered for sharing is\n");
+ log(" narrowed using a list of cell types. With this option all selected\n");
+ log(" cells are considered for resource sharing.\n");
+ log("\n");
+ log(" IMPORTANT NOTE: If the -all option is used then no cells with internal\n");
+ log(" state must be selected!\n");
+ log("\n");
+ log(" -aggressive\n");
+ log(" Per default some heuristics are used to reduce the number of cells\n");
+ log(" considered for resource sharing to only large resources. This options\n");
+ log(" turns this heuristics off, resulting in much more cells being considered\n");
+ log(" for resource sharing.\n");
+ log("\n");
+ log(" -fast\n");
+ log(" Only consider the simple part of the control logic in SAT solving, resulting\n");
+ log(" in much easier SAT problems at the cost of maybe missing some oportunities\n");
+ log(" for resource sharing.\n");
+ log("\n");
+ log(" -limit N\n");
+ log(" Only perform the first N merges, then stop. This is useful for debugging.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ShareWorkerConfig config;
+
+ config.limit = -1;
+ config.opt_force = false;
+ config.opt_aggressive = false;
+ config.opt_fast = false;
+
+ config.generic_uni_ops.insert("$not");
+ // config.generic_uni_ops.insert("$pos");
+ config.generic_uni_ops.insert("$neg");
+
+ config.generic_cbin_ops.insert("$and");
+ config.generic_cbin_ops.insert("$or");
+ config.generic_cbin_ops.insert("$xor");
+ config.generic_cbin_ops.insert("$xnor");
+
+ config.generic_bin_ops.insert("$shl");
+ config.generic_bin_ops.insert("$shr");
+ config.generic_bin_ops.insert("$sshl");
+ config.generic_bin_ops.insert("$sshr");
+
+ config.generic_bin_ops.insert("$lt");
+ config.generic_bin_ops.insert("$le");
+ config.generic_bin_ops.insert("$eq");
+ config.generic_bin_ops.insert("$ne");
+ config.generic_bin_ops.insert("$eqx");
+ config.generic_bin_ops.insert("$nex");
+ config.generic_bin_ops.insert("$ge");
+ config.generic_bin_ops.insert("$gt");
+
+ config.generic_cbin_ops.insert("$add");
+ config.generic_cbin_ops.insert("$mul");
+
+ config.generic_bin_ops.insert("$sub");
+ config.generic_bin_ops.insert("$div");
+ config.generic_bin_ops.insert("$mod");
+ // config.generic_bin_ops.insert("$pow");
+
+ config.generic_uni_ops.insert("$logic_not");
+ config.generic_cbin_ops.insert("$logic_and");
+ config.generic_cbin_ops.insert("$logic_or");
+
+ log_header("Executing SHARE pass (SAT-based resource sharing).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-force") {
+ config.opt_force = true;
+ continue;
+ }
+ if (args[argidx] == "-aggressive") {
+ config.opt_aggressive = true;
+ continue;
+ }
+ if (args[argidx] == "-fast") {
+ config.opt_fast = true;
+ continue;
+ }
+ if (args[argidx] == "-limit" && argidx+1 < args.size()) {
+ config.limit = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto &mod_it : design->modules_)
+ if (design->selected(mod_it.second))
+ ShareWorker(config, design, mod_it.second);
+ }
+} SharePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
new file mode 100644
index 000000000..58a6d1b0d
--- /dev/null
+++ b/passes/opt/wreduce.cc
@@ -0,0 +1,350 @@
+/*
+ * 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/modtools.h"
+
+USING_YOSYS_NAMESPACE
+using namespace RTLIL;
+
+PRIVATE_NAMESPACE_BEGIN
+
+struct WreduceConfig
+{
+ std::set<IdString> supported_cell_types;
+
+ WreduceConfig()
+ {
+ supported_cell_types = {
+ "$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"
+ };
+ }
+};
+
+struct WreduceWorker
+{
+ WreduceConfig *config;
+ Module *module;
+ ModIndex mi;
+
+ std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
+ std::set<SigBit> work_queue_bits;
+
+ WreduceWorker(WreduceConfig *config, Module *module) :
+ config(config), module(module), mi(module) { }
+
+ void run_cell_mux(Cell *cell)
+ {
+ // Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused
+
+ SigSpec sig_a = mi.sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = mi.sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = mi.sigmap(cell->getPort("\\S"));
+ SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
+ std::vector<SigBit> bits_removed;
+
+ for (int i = SIZE(sig_y)-1; i >= 0; i--)
+ {
+ auto info = mi.query(sig_y[i]);
+ if (!info->is_output && SIZE(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])
+ goto no_match_ab;
+ if (sig_b[k*SIZE(sig_a) + i] != Sx)
+ ref = sig_b[k*SIZE(sig_a) + i];
+ }
+ if (0)
+ no_match_ab:
+ break;
+ bits_removed.push_back(ref);
+ }
+
+ if (bits_removed.empty())
+ return;
+
+ SigSpec sig_removed;
+ for (int i = SIZE(bits_removed)-1; i >= 0; i--)
+ sig_removed.append_bit(bits_removed[i]);
+
+ if (SIZE(bits_removed) == SIZE(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);
+ return;
+ }
+
+ 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));
+
+ int n_removed = SIZE(sig_removed);
+ int n_kept = SIZE(sig_y) - SIZE(sig_removed);
+
+ SigSpec new_work_queue_bits;
+ new_work_queue_bits.append(sig_a.extract(n_kept, n_removed));
+ new_work_queue_bits.append(sig_y.extract(n_kept, n_removed));
+
+ SigSpec new_sig_a = sig_a.extract(0, n_kept);
+ 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 (auto bit : new_work_queue_bits)
+ work_queue_bits.insert(bit);
+
+ cell->setPort("\\A", new_sig_a);
+ cell->setPort("\\B", new_sig_b);
+ cell->setPort("\\Y", new_sig_y);
+ cell->fixup_parameters();
+
+ module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
+ }
+
+ void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
+ {
+ port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
+ SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port)));
+
+ if (port == 'B' && cell->type.in("$shl", "$shr", "$sshl", "$sshr"))
+ port_signed = false;
+
+ int bits_removed = 0;
+ if (SIZE(sig) > max_port_size) {
+ bits_removed = SIZE(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++;
+ } 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++;
+ }
+
+ 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));
+ cell->setPort(stringf("\\%c", port), sig);
+ did_something = true;
+ }
+ }
+
+ void run_cell(Cell *cell)
+ {
+ bool did_something = false;
+
+ if (!cell->type.in(config->supported_cell_types))
+ return;
+
+ if (cell->type.in("$mux", "$pmux"))
+ return run_cell_mux(cell);
+
+
+ // 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;
+
+ 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")));
+ }
+
+ bool port_a_signed = false;
+ bool port_b_signed = false;
+
+ if (max_port_a_size >= 0 && cell->type != "$shiftx")
+ run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
+
+ if (max_port_b_size >= 0)
+ run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something);
+
+
+ // Reduce size of port Y based on sizes for A and B and unused bits in Y
+
+ SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
+
+ int bits_removed = 0;
+ 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)
+ {
+ auto info = mi.query(sig[SIZE(sig)-1]);
+
+ if (info->is_output || SIZE(info->ports) > 1)
+ break;
+
+ sig.remove(SIZE(sig)-1);
+ bits_removed++;
+ }
+ }
+
+ if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor"))
+ {
+ 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"));
+
+ int max_y_size = std::max(a_size, b_size);
+
+ if (cell->type == "$add")
+ max_y_size++;
+
+ 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);
+ bits_removed++;
+ }
+ }
+
+ if (SIZE(sig) == 0) {
+ log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->remove(cell);
+ return;
+ }
+
+ 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));
+ cell->setPort("\\Y", sig);
+ did_something = true;
+ }
+
+ if (did_something) {
+ cell->fixup_parameters();
+ run_cell(cell);
+ }
+ }
+
+ static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
+ {
+ int count = w->attributes.size();
+ count -= w->attributes.count("\\src");
+ count -= w->attributes.count("\\unused_bits");
+ return count;
+ }
+
+ void run()
+ {
+ for (auto c : module->selected_cells())
+ work_queue_cells.insert(c);
+
+ while (!work_queue_cells.empty())
+ {
+ work_queue_bits.clear();
+ for (auto c : work_queue_cells)
+ run_cell(c);
+
+ work_queue_cells.clear();
+ for (auto bit : work_queue_bits)
+ for (auto port : mi.query_ports(bit))
+ if (module->selected(port.cell))
+ work_queue_cells.insert(port.cell);
+ }
+
+ for (auto w : module->selected_wires())
+ {
+ int unused_top_bits = 0;
+
+ if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
+ continue;
+
+ for (int i = SIZE(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))
+ 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);
+ }
+ }
+ }
+};
+
+struct WreducePass : public Pass {
+ WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" wreduce [options] [selection]\n");
+ log("\n");
+ log("This command reduces the word size of operations. For example it will replace\n");
+ log("the 32 bit adders in the following code with adders of more appropriate widths:\n");
+ log("\n");
+ log(" module test(input [3:0] a, b, c, output [7:0] y);\n");
+ log(" assign y = a + b + c + 1;\n");
+ log(" endmodule\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, Design *design)
+ {
+ WreduceConfig config;
+
+ log_header("Executing WREDUCE pass (reducing word size of cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ if (module->has_processes_warn())
+ continue;
+
+ WreduceWorker worker(&config, module);
+ worker.run();
+ }
+ }
+} WreducePass;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 571946573..f11b328f0 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -28,47 +28,52 @@ extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count
static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, bool &polarity)
{
- if (signal.width != 1)
+ if (signal.size() != 1)
return false;
if (signal == ref)
return true;
- for (auto &cell_it : mod->cells) {
- RTLIL::Cell *cell = cell_it.second;
- if (cell->type == "$reduce_or" && cell->connections["\\Y"] == signal)
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
- if (cell->type == "$reduce_bool" && cell->connections["\\Y"] == signal)
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
- if (cell->type == "$logic_not" && cell->connections["\\Y"] == signal) {
+ for (auto cell : mod->cells())
+ {
+ if (cell->type == "$reduce_or" && cell->getPort("\\Y") == signal)
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
+
+ if (cell->type == "$reduce_bool" && cell->getPort("\\Y") == signal)
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
+
+ if (cell->type == "$logic_not" && cell->getPort("\\Y") == signal) {
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
- if (cell->type == "$not" && cell->connections["\\Y"] == signal) {
+
+ if (cell->type == "$not" && cell->getPort("\\Y") == signal) {
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
- if ((cell->type == "$eq" || cell->type == "$eqx") && cell->connections["\\Y"] == signal) {
- if (cell->connections["\\A"].is_fully_const()) {
- if (!cell->connections["\\A"].as_bool())
+
+ if ((cell->type == "$eq" || cell->type == "$eqx") && cell->getPort("\\Y") == signal) {
+ if (cell->getPort("\\A").is_fully_const()) {
+ if (!cell->getPort("\\A").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\B"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\B"), ref, polarity);
}
- if (cell->connections["\\B"].is_fully_const()) {
- if (!cell->connections["\\B"].as_bool())
+ if (cell->getPort("\\B").is_fully_const()) {
+ if (!cell->getPort("\\B").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
}
- if ((cell->type == "$ne" || cell->type == "$nex") && cell->connections["\\Y"] == signal) {
- if (cell->connections["\\A"].is_fully_const()) {
- if (cell->connections["\\A"].as_bool())
+
+ if ((cell->type == "$ne" || cell->type == "$nex") && cell->getPort("\\Y") == signal) {
+ if (cell->getPort("\\A").is_fully_const()) {
+ if (cell->getPort("\\A").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\B"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\B"), ref, polarity);
}
- if (cell->connections["\\B"].is_fully_const()) {
- if (cell->connections["\\B"].as_bool())
+ if (cell->getPort("\\B").is_fully_const()) {
+ if (cell->getPort("\\B").as_bool())
polarity = !polarity;
- return check_signal(mod, cell->connections["\\A"], ref, polarity);
+ return check_signal(mod, cell->getPort("\\A"), ref, polarity);
}
}
}
@@ -80,13 +85,13 @@ static void apply_const(RTLIL::Module *mod, const RTLIL::SigSpec rspec, RTLIL::S
{
for (auto &action : cs->actions) {
if (unknown)
- rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.width), &rval);
+ rspec.replace(action.first, RTLIL::SigSpec(RTLIL::State::Sm, action.second.size()), &rval);
else
rspec.replace(action.first, action.second, &rval);
}
for (auto sw : cs->switches) {
- if (sw->signal.width == 0) {
+ if (sw->signal.size() == 0) {
for (auto cs2 : sw->cases)
apply_const(mod, rspec, rval, cs2, const_sig, polarity, unknown);
}
@@ -156,16 +161,18 @@ restart_proc_arst:
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
bool polarity = sync->type == RTLIL::SyncType::STp;
if (check_signal(mod, root_sig, sync->signal, polarity)) {
- log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
- sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
+ if (proc->syncs.size() == 1) {
+ log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+ } else {
+ log("Found async reset %s in `%s.%s'.\n", log_signal(sync->signal), mod->name.c_str(), proc->name.c_str());
+ sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0;
+ }
for (auto &action : sync->actions) {
RTLIL::SigSpec rspec = action.second;
- RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
- rspec.expand(), rval.expand();
- for (int i = 0; i < int(rspec.chunks.size()); i++)
- if (rspec.chunks[i].wire == NULL)
- rval.chunks[i] = rspec.chunks[i];
- rspec.optimize(), rval.optimize();
+ RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size());
+ for (int i = 0; i < SIZE(rspec); i++)
+ if (rspec[i].wire == NULL)
+ rval[i] = rspec[i];
RTLIL::SigSpec last_rval;
for (int count = 0; rval != last_rval; count++) {
last_rval = rval;
@@ -234,28 +241,28 @@ struct ProcArstPass : public Pass {
extra_args(args, argidx, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second)) {
- SigMap assign_map(mod_it.second);
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto mod : design->modules())
+ if (design->selected(mod)) {
+ SigMap assign_map(mod);
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
- proc_arst(mod_it.second, proc_it.second, assign_map);
- if (global_arst.empty() || mod_it.second->wires.count(global_arst) == 0)
+ proc_arst(mod, proc_it.second, assign_map);
+ if (global_arst.empty() || mod->wire(global_arst) == nullptr)
continue;
std::vector<RTLIL::SigSig> arst_actions;
for (auto sync : proc_it.second->syncs)
if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn)
for (auto &act : sync->actions) {
RTLIL::SigSpec arst_sig, arst_val;
- for (auto &chunk : act.first.chunks)
+ 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);
arst_sig.append(chunk);
arst_val.append(value.extract(chunk.offset, chunk.width));
}
- if (arst_sig.width) {
+ if (arst_sig.size()) {
log("Added global reset to process %s: %s <- %s\n",
proc_it.first.c_str(), log_signal(arst_sig), log_signal(arst_val));
arst_actions.push_back(RTLIL::SigSig(arst_sig, arst_val));
@@ -264,7 +271,7 @@ struct ProcArstPass : public Pass {
if (!arst_actions.empty()) {
RTLIL::SyncRule *sync = new RTLIL::SyncRule;
sync->type = global_arst_neg ? RTLIL::SyncType::ST0 : RTLIL::SyncType::ST1;
- sync->signal = mod_it.second->wires.at(global_arst);
+ sync->signal = mod->wire(global_arst);
sync->actions = arst_actions;
proc_it.second->syncs.push_back(sync);
}
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 83554df90..1e3dd9ce7 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -27,7 +27,7 @@ extern void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count
void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth)
{
- if (sw->signal.width > 0 && sw->signal.is_fully_const())
+ if (sw->signal.size() > 0 && sw->signal.is_fully_const())
{
int found_matching_case_idx = -1;
for (int i = 0; i < int(sw->cases.size()) && found_matching_case_idx < 0; i++)
@@ -59,7 +59,8 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
sw->signal = RTLIL::SigSpec();
}
- if (sw->cases.size() == 1 && (sw->signal.width == 0 || sw->cases[0]->compare.empty()))
+ if (parent->switches.front() == sw && sw->cases.size() == 1 &&
+ (sw->signal.size() == 0 || sw->cases[0]->compare.empty()))
{
did_something = true;
for (auto &action : sw->cases[0]->actions)
@@ -91,7 +92,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did
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++) {
- if (cs->actions[i].first.width == 0) {
+ if (cs->actions[i].first.size() == 0) {
did_something = true;
cs->actions.erase(cs->actions.begin() + (i--));
}
@@ -114,7 +115,7 @@ static void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_coun
bool did_something = true;
for (size_t i = 0; i < proc->syncs.size(); i++) {
for (size_t j = 0; j < proc->syncs[i]->actions.size(); j++)
- if (proc->syncs[i]->actions[j].first.width == 0)
+ if (proc->syncs[i]->actions[j].first.size() == 0)
proc->syncs[i]->actions.erase(proc->syncs[i]->actions.begin() + (j--));
if (proc->syncs[i]->actions.size() == 0) {
delete proc->syncs[i];
@@ -149,23 +150,23 @@ struct ProcCleanPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules) {
- std::vector<std::string> delme;
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ std::vector<RTLIL::IdString> delme;
+ if (!design->selected(mod))
continue;
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
- proc_clean(mod_it.second, proc_it.second, total_count);
+ proc_clean(mod, proc_it.second, total_count);
if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 &&
proc_it.second->root_case.actions.size() == 0) {
- log("Removing empty process `%s.%s'.\n", mod_it.first.c_str(), proc_it.second->name.c_str());
+ log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str());
delme.push_back(proc_it.first);
}
}
for (auto &id : delme) {
- delete mod_it.second->processes[id];
- mod_it.second->processes.erase(id);
+ delete mod->processes[id];
+ mod->processes.erase(id);
}
}
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 2ec498fb2..e69e8023d 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -24,7 +24,6 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
{
@@ -32,7 +31,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
for (auto sync : proc->syncs)
for (auto &action : sync->actions)
- if (action.first.width > 0) {
+ if (action.first.size() > 0) {
lvalue = action.first;
lvalue.sort_and_unify();
break;
@@ -44,7 +43,7 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
this_lvalue.append(action.first);
this_lvalue.sort_and_unify();
RTLIL::SigSpec common_sig = this_lvalue.extract(lvalue);
- if (common_sig.width > 0)
+ if (common_sig.size() > 0)
lvalue = common_sig;
}
@@ -54,8 +53,8 @@ static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
static 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.width);
- RTLIL::SigSpec sig_sr_clr = RTLIL::SigSpec(0, sig_d.width);
+ RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.size());
+ RTLIL::SigSpec sig_sr_clr = RTLIL::SigSpec(0, sig_d.size());
for (auto &it : async_rules)
{
@@ -72,91 +71,70 @@ static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::S
else
log_abort();
- if (sync_low_signals.width > 1) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$reduce_or";
+ if (sync_low_signals.size() > 1) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_low_signals;
- cell->connections["\\Y"] = sync_low_signals = NEW_WIRE(mod, 1);
- mod->add(cell);
+ cell->setPort("\\A", sync_low_signals);
+ cell->setPort("\\Y", sync_low_signals = mod->addWire(NEW_ID));
}
- if (sync_low_signals.width > 0) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$not";
+ if (sync_low_signals.size() > 0) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$not");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_low_signals;
- cell->connections["\\Y"] = NEW_WIRE(mod, 1);
- sync_high_signals.append(cell->connections["\\Y"]);
- mod->add(cell);
+ cell->setPort("\\A", sync_low_signals);
+ cell->setPort("\\Y", mod->addWire(NEW_ID));
+ sync_high_signals.append(cell->getPort("\\Y"));
}
- if (sync_high_signals.width > 1) {
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$reduce_or";
+ if (sync_high_signals.size() > 1) {
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_high_signals.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_high_signals.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = sync_high_signals;
- cell->connections["\\Y"] = sync_high_signals = NEW_WIRE(mod, 1);
- mod->add(cell);
+ cell->setPort("\\A", sync_high_signals);
+ cell->setPort("\\Y", sync_high_signals = mod->addWire(NEW_ID));
}
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- inv_cell->name = NEW_ID;
- inv_cell->type = "$not";
+ RTLIL::Cell *inv_cell = mod->addCell(NEW_ID, "$not");
inv_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- inv_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_d.width);
- inv_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_d.width);
- inv_cell->connections["\\A"] = sync_value;
- inv_cell->connections["\\Y"] = sync_value_inv = NEW_WIRE(mod, sig_d.width);
- mod->add(inv_cell);
-
- RTLIL::Cell *mux_set_cell = new RTLIL::Cell;
- mux_set_cell->name = NEW_ID;
- mux_set_cell->type = "$mux";
- mux_set_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
- mux_set_cell->connections["\\A"] = sig_sr_set;
- mux_set_cell->connections["\\B"] = sync_value;
- mux_set_cell->connections["\\S"] = sync_high_signals;
- mux_set_cell->connections["\\Y"] = sig_sr_set = NEW_WIRE(mod, sig_d.width);
- mod->add(mux_set_cell);
-
- RTLIL::Cell *mux_clr_cell = new RTLIL::Cell;
- mux_clr_cell->name = NEW_ID;
- mux_clr_cell->type = "$mux";
- mux_clr_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
- mux_clr_cell->connections["\\A"] = sig_sr_clr;
- mux_clr_cell->connections["\\B"] = sync_value_inv;
- mux_clr_cell->connections["\\S"] = sync_high_signals;
- mux_clr_cell->connections["\\Y"] = sig_sr_clr = NEW_WIRE(mod, sig_d.width);
- mod->add(mux_clr_cell);
+ inv_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_d.size());
+ inv_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_d.size());
+ inv_cell->setPort("\\A", sync_value);
+ inv_cell->setPort("\\Y", sync_value_inv = mod->addWire(NEW_ID, sig_d.size()));
+
+ RTLIL::Cell *mux_set_cell = mod->addCell(NEW_ID, "$mux");
+ mux_set_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
+ mux_set_cell->setPort("\\A", sig_sr_set);
+ mux_set_cell->setPort("\\B", sync_value);
+ mux_set_cell->setPort("\\S", sync_high_signals);
+ mux_set_cell->setPort("\\Y", sig_sr_set = mod->addWire(NEW_ID, sig_d.size()));
+
+ RTLIL::Cell *mux_clr_cell = mod->addCell(NEW_ID, "$mux");
+ mux_clr_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
+ mux_clr_cell->setPort("\\A", sig_sr_clr);
+ mux_clr_cell->setPort("\\B", sync_value_inv);
+ mux_clr_cell->setPort("\\S", sync_high_signals);
+ mux_clr_cell->setPort("\\Y", sig_sr_clr = mod->addWire(NEW_ID, sig_d.size()));
}
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = "$dffsr";
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
cell->attributes = proc->attributes;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
- cell->connections["\\D"] = sig_d;
- cell->connections["\\Q"] = sig_q;
- cell->connections["\\CLK"] = clk;
- cell->connections["\\SET"] = sig_sr_set;
- cell->connections["\\CLR"] = sig_sr_clr;
- mod->add(cell);
+ cell->setPort("\\D", sig_d);
+ cell->setPort("\\Q", sig_q);
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\SET", sig_sr_set);
+ cell->setPort("\\CLR", sig_sr_clr);
log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n",
cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
@@ -166,56 +144,44 @@ static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec
bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
{
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::SigSpec sig_set_inv = NEW_WIRE(mod, sig_in.width);
- RTLIL::SigSpec sig_sr_set = NEW_WIRE(mod, sig_in.width);
- RTLIL::SigSpec sig_sr_clr = NEW_WIRE(mod, sig_in.width);
+ RTLIL::SigSpec sig_set_inv = mod->addWire(NEW_ID, sig_in.size());
+ RTLIL::SigSpec sig_sr_set = mod->addWire(NEW_ID, sig_in.size());
+ RTLIL::SigSpec sig_sr_clr = mod->addWire(NEW_ID, sig_in.size());
- RTLIL::Cell *inv_set = new RTLIL::Cell;
- inv_set->name = NEW_ID;
- inv_set->type = "$not";
+ RTLIL::Cell *inv_set = mod->addCell(NEW_ID, "$not");
inv_set->parameters["\\A_SIGNED"] = RTLIL::Const(0);
- inv_set->parameters["\\A_WIDTH"] = RTLIL::Const(sig_in.width);
- inv_set->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_in.width);
- inv_set->connections["\\A"] = sig_set;
- inv_set->connections["\\Y"] = sig_set_inv;
- mod->add(inv_set);
-
- RTLIL::Cell *mux_sr_set = new RTLIL::Cell;
- mux_sr_set->name = NEW_ID;
- mux_sr_set->type = "$mux";
- mux_sr_set->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
- mux_sr_set->connections[set_polarity ? "\\A" : "\\B"] = RTLIL::Const(0, sig_in.width);
- mux_sr_set->connections[set_polarity ? "\\B" : "\\A"] = sig_set;
- mux_sr_set->connections["\\Y"] = sig_sr_set;
- mux_sr_set->connections["\\S"] = set;
- mod->add(mux_sr_set);
-
- RTLIL::Cell *mux_sr_clr = new RTLIL::Cell;
- mux_sr_clr->name = NEW_ID;
- mux_sr_clr->type = "$mux";
- mux_sr_clr->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
- mux_sr_clr->connections[set_polarity ? "\\A" : "\\B"] = RTLIL::Const(0, sig_in.width);
- mux_sr_clr->connections[set_polarity ? "\\B" : "\\A"] = sig_set_inv;
- mux_sr_clr->connections["\\Y"] = sig_sr_clr;
- mux_sr_clr->connections["\\S"] = set;
- mod->add(mux_sr_clr);
-
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = "$dffsr";
+ inv_set->parameters["\\A_WIDTH"] = RTLIL::Const(sig_in.size());
+ inv_set->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_in.size());
+ inv_set->setPort("\\A", sig_set);
+ inv_set->setPort("\\Y", sig_set_inv);
+
+ RTLIL::Cell *mux_sr_set = mod->addCell(NEW_ID, "$mux");
+ mux_sr_set->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
+ mux_sr_set->setPort(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
+ mux_sr_set->setPort(set_polarity ? "\\B" : "\\A", sig_set);
+ mux_sr_set->setPort("\\Y", sig_sr_set);
+ mux_sr_set->setPort("\\S", set);
+
+ RTLIL::Cell *mux_sr_clr = mod->addCell(NEW_ID, "$mux");
+ mux_sr_clr->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
+ mux_sr_clr->setPort(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
+ mux_sr_clr->setPort(set_polarity ? "\\B" : "\\A", sig_set_inv);
+ mux_sr_clr->setPort("\\Y", sig_sr_clr);
+ mux_sr_clr->setPort("\\S", set);
+
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
cell->attributes = proc->attributes;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
- cell->connections["\\D"] = sig_in;
- cell->connections["\\Q"] = sig_out;
- cell->connections["\\CLK"] = clk;
- cell->connections["\\SET"] = sig_sr_set;
- cell->connections["\\CLR"] = sig_sr_clr;
- mod->add(cell);
+ cell->setPort("\\D", sig_in);
+ cell->setPort("\\Q", sig_out);
+ cell->setPort("\\CLK", clk);
+ cell->setPort("\\SET", sig_sr_set);
+ cell->setPort("\\CLR", sig_sr_clr);
log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell->type.c_str(), cell->name.c_str(),
clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
@@ -225,26 +191,23 @@ static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_
bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
{
std::stringstream sstr;
- sstr << "$procdff$" << (RTLIL::autoidx++);
+ sstr << "$procdff$" << (autoidx++);
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = sstr.str();
- cell->type = arst ? "$adff" : "$dff";
+ RTLIL::Cell *cell = mod->addCell(sstr.str(), arst ? "$adff" : "$dff");
cell->attributes = proc->attributes;
- mod->cells[cell->name] = cell;
- cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.width);
+ cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
if (arst) {
cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1);
cell->parameters["\\ARST_VALUE"] = val_rst;
}
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
- cell->connections["\\D"] = sig_in;
- cell->connections["\\Q"] = sig_out;
+ cell->setPort("\\D", sig_in);
+ cell->setPort("\\Q", sig_out);
if (arst)
- cell->connections["\\ARST"] = *arst;
- cell->connections["\\CLK"] = clk;
+ cell->setPort("\\ARST", *arst);
+ cell->setPort("\\CLK", clk);
log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
if (arst)
@@ -259,14 +222,14 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
RTLIL::SigSpec sig = find_any_lvalue(proc);
bool free_sync_level = false;
- if (sig.width == 0)
+ if (sig.size() == 0)
break;
log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
mod->name.c_str(), log_signal(sig), mod->name.c_str(), proc->name.c_str());
- RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
- RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
+ RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
RTLIL::SyncRule *sync_level = NULL;
RTLIL::SyncRule *sync_edge = NULL;
RTLIL::SyncRule *sync_always = NULL;
@@ -276,16 +239,16 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
for (auto sync : proc->syncs)
for (auto &action : sync->actions)
{
- if (action.first.extract(sig).width == 0)
+ if (action.first.extract(sig).size() == 0)
continue;
if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
if (sync_level != NULL && sync_level != sync) {
// log_error("Multiple level sensitive events found for this signal!\n");
many_async_rules[rstval].insert(sync_level);
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
}
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
sig.replace(action.first, action.second, &rstval);
sync_level = sync;
}
@@ -315,7 +278,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
{
sync_level = new RTLIL::SyncRule;
sync_level->type = RTLIL::SyncType::ST1;
- sync_level->signal = NEW_WIRE(mod, 1);
+ sync_level->signal = mod->addWire(NEW_ID);
sync_level->actions.push_back(RTLIL::SigSig(sig, rstval));
free_sync_level = true;
@@ -324,26 +287,23 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
inputs.append(it->signal);
compare.append(it->type == RTLIL::SyncType::ST0 ? RTLIL::State::S1 : RTLIL::State::S0);
}
- assert(inputs.width == compare.width);
+ log_assert(inputs.size() == compare.size());
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = "$ne";
+ RTLIL::Cell *cell = mod->addCell(NEW_ID, "$ne");
cell->parameters["\\A_SIGNED"] = RTLIL::Const(false, 1);
cell->parameters["\\B_SIGNED"] = RTLIL::Const(false, 1);
- cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.width);
- cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.width);
+ cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.size());
+ cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.size());
cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- cell->connections["\\A"] = inputs;
- cell->connections["\\B"] = compare;
- cell->connections["\\Y"] = sync_level->signal;
- mod->add(cell);
+ cell->setPort("\\A", inputs);
+ cell->setPort("\\B", compare);
+ cell->setPort("\\Y", sync_level->signal);
many_async_rules.clear();
}
else
{
- rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.width);
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
sync_level = NULL;
}
}
@@ -352,15 +312,16 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
ce.assign_map.apply(rstval);
ce.assign_map.apply(sig);
- insig.optimize();
- rstval.optimize();
- sig.optimize();
+ if (rstval == sig) {
+ rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
+ sync_level = NULL;
+ }
if (sync_always) {
if (sync_edge || sync_level || many_async_rules.size() > 0)
log_error("Mixed always event with edge and/or level sensitive events!\n");
log(" created direct connection (no actual register cell created).\n");
- mod->connections.push_back(RTLIL::SigSig(sig, insig));
+ mod->connect(RTLIL::SigSig(sig, insig));
continue;
}
@@ -381,7 +342,7 @@ static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
sync_edge->signal, sync_level->signal, proc);
}
else
- gen_dff(mod, insig, rstval.chunks[0].data, sig,
+ gen_dff(mod, insig, rstval.as_const(), sig,
sync_edge->type == RTLIL::SyncType::STp,
sync_level && sync_level->type == RTLIL::SyncType::ST1,
sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc);
@@ -409,12 +370,12 @@ struct ProcDffPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second)) {
- ConstEval ce(mod_it.second);
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_dff(mod_it.second, proc_it.second, ce);
+ for (auto mod : design->modules())
+ if (design->selected(mod)) {
+ ConstEval ce(mod);
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_dff(mod, proc_it.second, ce);
}
}
} ProcDffPass;
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index fca20fda2..c72840c02 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -25,10 +25,9 @@
static void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule)
{
- assert(rule.compare.size() == 0);
+ log_assert(rule.compare.size() == 0);
while (1) {
- sig.optimize();
RTLIL::SigSpec tmp = sig;
for (auto &it : rule.actions)
tmp.replace(it.first, it.second);
@@ -53,23 +52,21 @@ static void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
RTLIL::SigSpec lhs = action.first;
RTLIL::SigSpec rhs = action.second;
- lhs.optimize();
proc_get_const(rhs, proc->root_case);
if (!rhs.is_fully_const())
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
int offset = 0;
- for (size_t i = 0; i < lhs.chunks.size(); i++) {
- if (lhs.chunks[i].wire == NULL)
- continue;
- RTLIL::Wire *wire = lhs.chunks[i].wire;
- RTLIL::SigSpec value = rhs.extract(offset, lhs.chunks[i].width);
- if (value.width != wire->width)
- log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs.chunks[i]), log_signal(value));
- log(" Setting init value: %s = %s\n", log_signal(wire), log_signal(value));
- wire->attributes["\\init"] = value.as_const();
- offset += wire->width;
+ for (auto &lhs_c : lhs.chunks()) {
+ if (lhs_c.wire != NULL) {
+ RTLIL::SigSpec value = rhs.extract(offset, lhs_c.width);
+ if (value.size() != lhs_c.wire->width)
+ log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs_c), log_signal(value));
+ log(" Setting init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(value));
+ lhs_c.wire->attributes["\\init"] = value.as_const();
+ }
+ offset += lhs_c.width;
}
}
}
@@ -104,11 +101,11 @@ struct ProcInitPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_init(mod_it.second, proc_it.second);
+ for (auto mod : design->modules())
+ if (design->selected(mod))
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_init(mod, proc_it.second);
}
} ProcInitPass;
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 9b2f83885..c00b00a2a 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -23,19 +23,18 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
static RTLIL::SigSpec find_any_lvalue(const RTLIL::CaseRule *cs)
{
for (auto &action : cs->actions) {
- if (action.first.width)
+ if (action.first.size())
return action.first;
}
for (auto sw : cs->switches)
for (auto cs2 : sw->cases) {
RTLIL::SigSpec sig = find_any_lvalue(cs2);
- if (sig.width)
+ if (sig.size())
return sig;
}
@@ -46,7 +45,7 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
{
for (auto &action : cs->actions) {
RTLIL::SigSpec lvalue = action.first.extract(sig);
- if (lvalue.width)
+ if (lvalue.size())
sig = lvalue;
}
@@ -58,56 +57,44 @@ static void extract_core_signal(const RTLIL::CaseRule *cs, RTLIL::SigSpec &sig)
static 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$" << (RTLIL::autoidx++);
+ sstr << "$procmux$" << (autoidx++);
- RTLIL::Wire *cmp_wire = new RTLIL::Wire;
- cmp_wire->name = sstr.str() + "_CMP";
- cmp_wire->width = 0;
- mod->wires[cmp_wire->name] = cmp_wire;
+ RTLIL::Wire *cmp_wire = mod->addWire(sstr.str() + "_CMP", 0);
for (auto comp : compare)
{
RTLIL::SigSpec sig = signal;
- sig.expand();
- comp.expand();
// get rid of don't-care bits
- assert(sig.width == comp.width);
- for (int i = 0; i < comp.width; i++)
- if (comp.chunks[i].wire == NULL && comp.chunks[i].data.bits[0] == RTLIL::State::Sa) {
- sig.remove(i, 1);
- comp.remove(i--, 1);
+ log_assert(sig.size() == comp.size());
+ for (int i = 0; i < comp.size(); i++)
+ if (comp[i] == RTLIL::State::Sa) {
+ sig.remove(i);
+ comp.remove(i--);
}
- if (comp.width == 0)
+ if (comp.size() == 0)
return RTLIL::SigSpec();
- sig.optimize();
- comp.optimize();
- if (sig.width == 1 && comp == RTLIL::SigSpec(1,1))
+ if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1))
{
- mod->connections.push_back(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++), sig));
+ mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig));
}
else
{
// create compare cell
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- std::stringstream sstr2;
- sstr2 << sstr.str() << "_CMP" << cmp_wire->width;
- eq_cell->name = sstr2.str();
- eq_cell->type = "$eq";
+ RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq");
eq_cell->attributes = sw->attributes;
- mod->cells[eq_cell->name] = eq_cell;
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
eq_cell->parameters["\\B_SIGNED"] = RTLIL::Const(0);
- eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.width);
- eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.width);
+ eq_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig.size());
+ eq_cell->parameters["\\B_WIDTH"] = RTLIL::Const(comp.size());
eq_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- eq_cell->connections["\\A"] = sig;
- eq_cell->connections["\\B"] = comp;
- eq_cell->connections["\\Y"] = RTLIL::SigSpec(cmp_wire, 1, cmp_wire->width++);
+ eq_cell->setPort("\\A", sig);
+ eq_cell->setPort("\\B", comp);
+ eq_cell->setPort("\\Y", RTLIL::SigSpec(cmp_wire, cmp_wire->width++));
}
}
@@ -118,24 +105,18 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
}
else
{
- ctrl_wire = new RTLIL::Wire;
- ctrl_wire->name = sstr.str() + "_CTRL";
- ctrl_wire->width = 1;
- mod->wires[ctrl_wire->name] = ctrl_wire;
+ ctrl_wire = mod->addWire(sstr.str() + "_CTRL");
// reduce cmp vector to one logic signal
- RTLIL::Cell *any_cell = new RTLIL::Cell;
- any_cell->name = sstr.str() + "_ANY";
- any_cell->type = "$reduce_or";
+ RTLIL::Cell *any_cell = mod->addCell(sstr.str() + "_ANY", "$reduce_or");
any_cell->attributes = sw->attributes;
- mod->cells[any_cell->name] = any_cell;
any_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
any_cell->parameters["\\A_WIDTH"] = RTLIL::Const(cmp_wire->width);
any_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
- any_cell->connections["\\A"] = cmp_wire;
- any_cell->connections["\\Y"] = RTLIL::SigSpec(ctrl_wire);
+ any_cell->setPort("\\A", cmp_wire);
+ any_cell->setPort("\\Y", RTLIL::SigSpec(ctrl_wire));
}
return RTLIL::SigSpec(ctrl_wire);
@@ -143,10 +124,10 @@ static RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
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)
{
- assert(when_signal.width == else_signal.width);
+ log_assert(when_signal.size() == else_signal.size());
std::stringstream sstr;
- sstr << "$procmux$" << (RTLIL::autoidx++);
+ sstr << "$procmux$" << (autoidx++);
// the trivial cases
if (compare.size() == 0 || when_signal == else_signal)
@@ -154,28 +135,22 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
// compare results
RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
- if (ctrl_sig.width == 0)
+ if (ctrl_sig.size() == 0)
return when_signal;
- assert(ctrl_sig.width == 1);
+ log_assert(ctrl_sig.size() == 1);
// prepare multiplexer output signal
- RTLIL::Wire *result_wire = new RTLIL::Wire;
- result_wire->name = sstr.str() + "_Y";
- result_wire->width = when_signal.width;
- mod->wires[result_wire->name] = result_wire;
+ RTLIL::Wire *result_wire = mod->addWire(sstr.str() + "_Y", when_signal.size());
// create the multiplexer itself
- RTLIL::Cell *mux_cell = new RTLIL::Cell;
- mux_cell->name = sstr.str();
- mux_cell->type = "$mux";
+ RTLIL::Cell *mux_cell = mod->addCell(sstr.str(), "$mux");
mux_cell->attributes = sw->attributes;
- mod->cells[mux_cell->name] = mux_cell;
- mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.width);
- mux_cell->connections["\\A"] = else_signal;
- mux_cell->connections["\\B"] = when_signal;
- mux_cell->connections["\\S"] = ctrl_sig;
- mux_cell->connections["\\Y"] = RTLIL::SigSpec(result_wire);
+ mux_cell->parameters["\\WIDTH"] = RTLIL::Const(when_signal.size());
+ mux_cell->setPort("\\A", else_signal);
+ mux_cell->setPort("\\B", when_signal);
+ mux_cell->setPort("\\S", ctrl_sig);
+ mux_cell->setPort("\\Y", RTLIL::SigSpec(result_wire));
last_mux_cell = mux_cell;
return RTLIL::SigSpec(result_wire);
@@ -183,15 +158,22 @@ static RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal,
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)
{
- assert(last_mux_cell != NULL);
- assert(when_signal.width == last_mux_cell->connections["\\A"].width);
+ log_assert(last_mux_cell != NULL);
+ log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
- assert(ctrl_sig.width == 1);
+ log_assert(ctrl_sig.size() == 1);
last_mux_cell->type = "$pmux";
- last_mux_cell->connections["\\S"].append(ctrl_sig);
- last_mux_cell->connections["\\B"].append(when_signal);
- last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->connections["\\S"].width;
+
+ RTLIL::SigSpec new_s = last_mux_cell->getPort("\\S");
+ new_s.append(ctrl_sig);
+ last_mux_cell->setPort("\\S", new_s);
+
+ RTLIL::SigSpec new_b = last_mux_cell->getPort("\\B");
+ new_b.append(when_signal);
+ last_mux_cell->setPort("\\B", new_b);
+
+ 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)
@@ -208,7 +190,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
// detect groups of parallel cases
std::vector<int> pgroups(sw->cases.size());
if (!sw->get_bool_attribute("\\parallel_case")) {
- BitPatternPool pool(sw->signal.width);
+ BitPatternPool pool(sw->signal.size());
bool extra_group_for_next_case = false;
for (size_t i = 0; i < sw->cases.size(); i++) {
RTLIL::CaseRule *cs2 = sw->cases[i];
@@ -224,7 +206,7 @@ static RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, RTLIL::CaseRule *cs
if (cs2->compare.empty())
pgroups[i] = pgroups[i-1]+1;
if (pgroups[i] != pgroups[i-1])
- pool = BitPatternPool(sw->signal.width);
+ pool = BitPatternPool(sw->signal.size());
}
for (auto pat : cs2->compare)
if (!pat.is_fully_const())
@@ -258,7 +240,7 @@ static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
{
RTLIL::SigSpec sig = find_any_lvalue(&proc->root_case);
- if (sig.width == 0)
+ if (sig.size() == 0)
break;
if (first) {
@@ -270,8 +252,8 @@ static void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
log(" creating decoder for signal `%s'.\n", log_signal(sig));
- RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.width));
- mod->connections.push_back(RTLIL::SigSig(sig, value));
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
+ mod->connect(RTLIL::SigSig(sig, value));
}
}
@@ -293,11 +275,11 @@ struct ProcMuxPass : public Pass {
extra_args(args, 1, design);
- for (auto &mod_it : design->modules)
- if (design->selected(mod_it.second))
- for (auto &proc_it : mod_it.second->processes)
- if (design->selected(mod_it.second, proc_it.second))
- proc_mux(mod_it.second, proc_it.second);
+ for (auto mod : design->modules())
+ if (design->selected(mod))
+ for (auto &proc_it : mod->processes)
+ if (design->selected(mod, proc_it.second))
+ proc_mux(mod, proc_it.second);
}
} ProcMuxPass;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index d5fbef0d2..fe3532da8 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -23,7 +23,6 @@
#include <sstream>
#include <stdlib.h>
#include <stdio.h>
-#include <assert.h>
#include <set>
static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
@@ -32,7 +31,7 @@ static void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
for (size_t i = 0; i < sw->cases.size(); i++)
{
- bool is_default = sw->cases[i]->compare.size() == 0 && !pool.empty();
+ bool is_default = SIZE(sw->cases[i]->compare) == 0 && (!pool.empty() || SIZE(sw->signal) == 0);
for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) {
RTLIL::SigSpec sig = sw->cases[i]->compare[j];
@@ -79,18 +78,18 @@ struct ProcRmdeadPass : public Pass {
extra_args(args, 1, design);
int total_counter = 0;
- for (auto &mod_it : design->modules) {
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ if (!design->selected(mod))
continue;
- for (auto &proc_it : mod_it.second->processes) {
- if (!design->selected(mod_it.second, proc_it.second))
+ for (auto &proc_it : mod->processes) {
+ if (!design->selected(mod, proc_it.second))
continue;
int counter = 0;
for (auto switch_it : proc_it.second->root_case.switches)
proc_rmdead(switch_it, counter);
if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter,
- proc_it.first.c_str(), mod_it.first.c_str());
+ proc_it.first.c_str(), log_id(mod));
total_counter += counter;
}
}
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 5c38cc2cf..f07ad943c 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -44,7 +44,7 @@ struct BruteForceEquivChecker
void run_checker(RTLIL::SigSpec &inputs)
{
- if (inputs.width < mod1_inputs.width) {
+ if (inputs.size() < mod1_inputs.size()) {
RTLIL::SigSpec inputs0 = inputs, inputs1 = inputs;
inputs0.append(RTLIL::Const(0, 1));
inputs1.append(RTLIL::Const(1, 1));
@@ -53,8 +53,6 @@ struct BruteForceEquivChecker
return;
}
- inputs.optimize();
-
ConstEval ce1(mod1), ce2(mod2);
ce1.set(mod1_inputs, inputs.as_const());
ce2.set(mod2_inputs, inputs.as_const());
@@ -70,11 +68,9 @@ struct BruteForceEquivChecker
log_signal(undef2), log_signal(mod1_inputs), log_signal(inputs));
if (ignore_x_mod1) {
- sig1.expand(), sig2.expand();
- for (size_t i = 0; i < sig1.chunks.size(); i++)
- if (sig1.chunks.at(i) == RTLIL::SigChunk(RTLIL::State::Sx))
- sig2.chunks.at(i) = RTLIL::SigChunk(RTLIL::State::Sx);
- sig1.optimize(), sig2.optimize();
+ for (int i = 0; i < SIZE(sig1); i++)
+ if (sig1[i] == RTLIL::State::Sx)
+ sig2[i] = RTLIL::State::Sx;
}
if (sig1 != sig2) {
@@ -91,16 +87,16 @@ struct BruteForceEquivChecker
mod1(mod1), mod2(mod2), counter(0), errors(0), ignore_x_mod1(ignore_x_mod1)
{
log("Checking for equivialence (brute-force): %s vs %s\n", mod1->name.c_str(), mod2->name.c_str());
- for (auto &w : mod1->wires)
+ for (auto &w : mod1->wires_)
{
RTLIL::Wire *wire1 = w.second;
if (wire1->port_id == 0)
continue;
- if (mod2->wires.count(wire1->name) == 0)
+ if (mod2->wires_.count(wire1->name) == 0)
log_cmd_error("Port %s in module 1 has no counterpart in module 2!\n", wire1->name.c_str());
- RTLIL::Wire *wire2 = mod2->wires.at(wire1->name);
+ RTLIL::Wire *wire2 = mod2->wires_.at(wire1->name);
if (wire1->width != wire2->width || wire1->port_input != wire2->port_input || wire1->port_output != wire2->port_output)
log_cmd_error("Port %s in module 1 does not match its counterpart in module 2!\n", wire1->name.c_str());
@@ -151,17 +147,17 @@ struct VlogHammerReporter
SatGen satgen(&ez, &sigmap);
satgen.model_undef = model_undef;
- for (auto &c : module->cells)
+ 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));
- std::vector<int> y_vec = satgen.importDefSigSpec(module->wires.at("\\y"));
+ std::vector<int> y_vec = satgen.importDefSigSpec(module->wires_.at("\\y"));
std::vector<bool> y_values;
if (model_undef) {
- std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wires.at("\\y"));
+ std::vector<int> y_undef_vec = satgen.importUndefSigSpec(module->wires_.at("\\y"));
y_vec.insert(y_vec.end(), y_undef_vec.begin(), y_undef_vec.end());
}
@@ -171,12 +167,11 @@ struct VlogHammerReporter
if (!ez.solve(y_vec, y_values))
log_error("Failed to find solution to SAT problem.\n");
- expected_y.expand();
- for (int i = 0; i < expected_y.width; i++) {
+ for (int i = 0; i < expected_y.size(); i++) {
RTLIL::State solution_bit = y_values.at(i) ? RTLIL::State::S1 : RTLIL::State::S0;
- RTLIL::State expected_bit = expected_y.chunks.at(i).data.bits.at(0);
+ RTLIL::State expected_bit = expected_y[i].data;
if (model_undef) {
- if (y_values.at(expected_y.width+i))
+ if (y_values.at(expected_y.size()+i))
solution_bit = RTLIL::State::Sx;
} else {
if (expected_bit == RTLIL::State::Sx)
@@ -184,17 +179,16 @@ struct VlogHammerReporter
}
if (solution_bit != expected_bit) {
std::string sat_bits, rtl_bits;
- for (int k = expected_y.width-1; k >= 0; k--) {
- if (model_undef && y_values.at(expected_y.width+k))
+ for (int k = expected_y.size()-1; k >= 0; k--) {
+ if (model_undef && y_values.at(expected_y.size()+k))
sat_bits += "x";
else
sat_bits += y_values.at(k) ? "1" : "0";
- rtl_bits += expected_y.chunks.at(k).data.bits.at(0) == RTLIL::State::Sx ? "x" :
- expected_y.chunks.at(k).data.bits.at(0) == RTLIL::State::S1 ? "1" : "0";
+ rtl_bits += expected_y[k] == RTLIL::State::Sx ? "x" : expected_y[k] == RTLIL::State::S1 ? "1" : "0";
}
log_error("Found error in SAT model: y[%d] = %s, should be %s:\n SAT: %s\n RTL: %s\n %*s^\n",
int(i), log_signal(solution_bit), log_signal(expected_bit),
- sat_bits.c_str(), rtl_bits.c_str(), expected_y.width-i-1, "");
+ sat_bits.c_str(), rtl_bits.c_str(), expected_y.size()-i-1, "");
}
}
@@ -203,16 +197,16 @@ struct VlogHammerReporter
std::vector<int> cmp_vars;
std::vector<bool> cmp_vals;
- std::vector<bool> y_undef(y_values.begin() + expected_y.width, y_values.end());
+ std::vector<bool> y_undef(y_values.begin() + expected_y.size(), y_values.end());
- for (int i = 0; i < expected_y.width; i++)
+ for (int i = 0; i < expected_y.size(); i++)
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)))
log_error("Failed to find solution with toggled bit!\n");
- cmp_vars.push_back(y_vec.at(expected_y.width + i));
+ cmp_vars.push_back(y_vec.at(expected_y.size() + i));
cmp_vals.push_back(true);
}
else
@@ -220,7 +214,7 @@ struct VlogHammerReporter
cmp_vars.push_back(y_vec.at(i));
cmp_vals.push_back(y_values.at(i));
- cmp_vars.push_back(y_vec.at(expected_y.width + i));
+ cmp_vars.push_back(y_vec.at(expected_y.size() + i));
cmp_vals.push_back(false);
}
@@ -258,10 +252,10 @@ struct VlogHammerReporter
std::vector<RTLIL::State> bits(patterns[idx].bits.begin(), patterns[idx].bits.begin() + total_input_width);
for (int i = 0; i < int(inputs.size()); i++) {
- RTLIL::Wire *wire = module->wires.at(inputs[i]);
+ RTLIL::Wire *wire = module->wires_.at(inputs[i]);
for (int j = input_widths[i]-1; j >= 0; j--) {
- ce.set(RTLIL::SigSpec(wire, 1, j), bits.back());
- recorded_set_vars.append(RTLIL::SigSpec(wire, 1, j));
+ ce.set(RTLIL::SigSpec(wire, j), bits.back());
+ recorded_set_vars.append(RTLIL::SigSpec(wire, j));
recorded_set_vals.bits.push_back(bits.back());
bits.pop_back();
}
@@ -274,32 +268,30 @@ struct VlogHammerReporter
}
}
- if (module->wires.count("\\y") == 0)
+ if (module->wires_.count("\\y") == 0)
log_error("No output wire (y) found in module %s!\n", RTLIL::id2cstr(module->name));
- RTLIL::SigSpec sig(module->wires.at("\\y"));
+ RTLIL::SigSpec sig(module->wires_.at("\\y"));
RTLIL::SigSpec undef;
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));
- ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.width));
+ ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
}
log("++VAL++ %d %s %s #\n", idx, module_name.c_str(), sig.as_const().as_string().c_str());
if (module_name == "rtl") {
rtl_sig = sig;
- rtl_sig.expand();
sat_check(module, recorded_set_vars, recorded_set_vals, sig, false);
sat_check(module, recorded_set_vars, recorded_set_vals, sig, true);
- } else if (rtl_sig.width > 0) {
- sig.expand();
- if (rtl_sig.width != sig.width)
+ } 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 < sig.width; i++)
- if (rtl_sig.chunks.at(i).data.bits.at(0) == RTLIL::State::Sx)
- sig.chunks.at(i).data.bits.at(0) = RTLIL::State::Sx;
+ for (int i = 0; i < SIZE(sig); i++)
+ if (rtl_sig[i] == RTLIL::State::Sx)
+ sig[i] = RTLIL::State::Sx;
}
log("++RPT++ %d%s %s %s\n", idx, input_pattern_list.c_str(), sig.as_const().as_string().c_str(), module_name.c_str());
@@ -314,10 +306,10 @@ struct VlogHammerReporter
{
for (auto name : split(module_list, ",")) {
RTLIL::IdString esc_name = RTLIL::escape_id(module_prefix + name);
- if (design->modules.count(esc_name) == 0)
+ if (design->modules_.count(esc_name) == 0)
log_error("Can't find module %s in current design!\n", name.c_str());
log("Using module %s (%s).\n", esc_name.c_str(), name.c_str());
- modules.push_back(design->modules.at(esc_name));
+ modules.push_back(design->modules_.at(esc_name));
module_names.push_back(name);
}
@@ -326,9 +318,9 @@ struct VlogHammerReporter
int width = -1;
RTLIL::IdString esc_name = RTLIL::escape_id(name);
for (auto mod : modules) {
- if (mod->wires.count(esc_name) == 0)
+ if (mod->wires_.count(esc_name) == 0)
log_error("Can't find input %s in module %s!\n", name.c_str(), RTLIL::id2cstr(mod->name));
- RTLIL::Wire *port = mod->wires.at(esc_name);
+ RTLIL::Wire *port = mod->wires_.at(esc_name);
if (!port->port_input || port->port_output)
log_error("Wire %s in module %s is not an input!\n", name.c_str(), RTLIL::id2cstr(mod->name));
if (width >= 0 && width != port->width)
@@ -350,7 +342,7 @@ struct VlogHammerReporter
}
if (!RTLIL::SigSpec::parse(sig, NULL, pattern) || !sig.is_fully_const())
log_error("Failed to parse pattern %s!\n", pattern.c_str());
- if (sig.width < total_input_width)
+ if (sig.size() < total_input_width)
log_error("Pattern %s is to short!\n", pattern.c_str());
patterns.push_back(sig.as_const());
if (invert_pattern) {
@@ -424,11 +416,11 @@ struct EvalPass : public Pass {
/* this should only be used for regression testing of ConstEval -- see vloghammer */
std::string mod1_name = RTLIL::escape_id(args[++argidx]);
std::string mod2_name = RTLIL::escape_id(args[++argidx]);
- if (design->modules.count(mod1_name) == 0)
+ if (design->modules_.count(mod1_name) == 0)
log_error("Can't find module `%s'!\n", mod1_name.c_str());
- if (design->modules.count(mod2_name) == 0)
+ if (design->modules_.count(mod2_name) == 0)
log_error("Can't find module `%s'!\n", mod2_name.c_str());
- BruteForceEquivChecker checker(design->modules.at(mod1_name), design->modules.at(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x");
+ BruteForceEquivChecker checker(design->modules_.at(mod1_name), design->modules_.at(mod2_name), args[argidx-2] == "-brute_force_equiv_checker_x");
if (checker.errors > 0)
log_cmd_error("Modules are not equivialent!\n");
log("Verified %s = %s (using brute-force check on %d cases).\n",
@@ -450,7 +442,7 @@ struct EvalPass : public Pass {
extra_args(args, argidx, design);
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second)) {
if (module)
log_cmd_error("Only one module must be selected for the EVAL pass! (selected: %s and %s)\n",
@@ -470,16 +462,16 @@ struct EvalPass : public Pass {
log_cmd_error("Failed to parse rhs set expression `%s'.\n", it.second.c_str());
if (!rhs.is_fully_const())
log_cmd_error("Right-hand-side set expression `%s' is not constant.\n", it.second.c_str());
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- it.first.c_str(), log_signal(lhs), lhs.width, it.second.c_str(), log_signal(rhs), rhs.width);
+ it.first.c_str(), log_signal(lhs), lhs.size(), it.second.c_str(), log_signal(rhs), rhs.size());
ce.set(lhs, rhs.as_const());
}
if (shows.size() == 0) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_output)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (tables.empty())
@@ -488,12 +480,11 @@ struct EvalPass : public Pass {
RTLIL::SigSpec signal, value, undef;
if (!RTLIL::SigSpec::parse_sel(signal, design, module, it))
log_cmd_error("Failed to parse show expression `%s'.\n", it.c_str());
- signal.optimize();
value = signal;
if (set_undef) {
while (!ce.eval(value, undef)) {
log("Failed to evaluate signal %s: Missing value for %s. -> setting to undef\n", log_signal(signal), log_signal(undef));
- ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.width));
+ ce.set(undef, RTLIL::Const(RTLIL::State::Sx, undef.size()));
undef = RTLIL::SigSpec();
}
log("Eval result: %s = %s.\n", log_signal(signal), log_signal(value));
@@ -526,15 +517,15 @@ struct EvalPass : public Pass {
}
std::vector<std::string> tab_line;
- for (auto &c : tabsigs.chunks)
+ for (auto &c : tabsigs.chunks())
tab_line.push_back(log_signal(c));
tab_sep_colidx = tab_line.size();
- for (auto &c : signal.chunks)
+ for (auto &c : signal.chunks())
tab_line.push_back(log_signal(c));
tab.push_back(tab_line);
tab_line.clear();
- RTLIL::Const tabvals(0, tabsigs.width);
+ RTLIL::Const tabvals(0, tabsigs.size());
do
{
ce.push();
@@ -548,19 +539,19 @@ struct EvalPass : public Pass {
log_signal(tabsigs), log_signal(tabvals), log_signal(this_undef));
return;
}
- ce.set(this_undef, RTLIL::Const(RTLIL::State::Sx, this_undef.width));
+ ce.set(this_undef, RTLIL::Const(RTLIL::State::Sx, this_undef.size()));
undef.append(this_undef);
this_undef = RTLIL::SigSpec();
}
int pos = 0;
- for (auto &c : tabsigs.chunks) {
+ for (auto &c : tabsigs.chunks()) {
tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width)));
pos += c.width;
}
pos = 0;
- for (auto &c : signal.chunks) {
+ for (auto &c : signal.chunks()) {
tab_line.push_back(log_signal(value.extract(pos, c.width)));
pos += c.width;
}
@@ -602,7 +593,7 @@ struct EvalPass : public Pass {
}
log("\n");
- if (undef.width > 0) {
+ if (undef.size() > 0) {
undef.sort_and_unify();
log("Assumend undef (x) value for the following singals: %s\n\n", log_signal(undef));
}
diff --git a/passes/sat/example.ys b/passes/sat/example.ys
index 11f5b924b..cc72faac0 100644
--- a/passes/sat/example.ys
+++ b/passes/sat/example.ys
@@ -1,13 +1,14 @@
read_verilog example.v
proc; opt_clean
+echo on
sat -set y 1'b1 example001
sat -set y 1'b1 example002
sat -set y_sshl 8'hf0 -set y_sshr 8'hf0 -set sh 4'd3 example003
-sat -set y 1'b1 example004
+sat -set y 1'b1 -ignore_unknown_cells example004
sat -show rst,counter -set-at 3 y 1'b1 -seq 4 example004
-sat -prove y 1'b0 -show rst,counter,y example004
-sat -prove y 1'b0 -show rst,counter,y -set-at 1 rst 1'b1 -seq 1 example004
+sat -prove y 1'b0 -show rst,counter,y -ignore_unknown_cells example004
+sat -prove y 1'b0 -tempinduct -show rst,counter,y -set-at 1 rst 1'b1 -seq 1 example004
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 2ac7b35f6..e856fdf76 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -27,7 +27,7 @@ struct dff_map_info_t {
RTLIL::SigSpec sig_d, sig_clk, sig_arst;
bool clk_polarity, arst_polarity;
RTLIL::Const arst_value;
- std::vector<std::string> cells;
+ std::vector<RTLIL::IdString> cells;
};
struct dff_map_bit_info_t {
@@ -37,7 +37,7 @@ struct dff_map_bit_info_t {
RTLIL::Cell *cell;
};
-static bool consider_wire(RTLIL::Wire *wire, std::map<std::string, dff_map_info_t> &dff_dq_map)
+static 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,11 +46,11 @@ static bool consider_wire(RTLIL::Wire *wire, std::map<std::string, dff_map_info_
return true;
}
-static bool consider_cell(RTLIL::Design *design, std::set<std::string> &dff_cells, RTLIL::Cell *cell)
+static 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;
- if (cell->type.at(0) == '\\' && !design->modules.count(cell->type))
+ if (cell->type[0] == '\\' && !design->modules_.count(cell->type))
return false;
return true;
}
@@ -73,7 +73,7 @@ static bool compare_cells(RTLIL::Cell *cell1, RTLIL::Cell *cell2)
return true;
}
-static void find_dff_wires(std::set<std::string> &dff_wires, RTLIL::Module *module)
+static void find_dff_wires(std::set<RTLIL::IdString> &dff_wires, RTLIL::Module *module)
{
CellTypes ct;
ct.setup_internals_mem();
@@ -82,23 +82,23 @@ static void find_dff_wires(std::set<std::string> &dff_wires, RTLIL::Module *modu
SigMap sigmap(module);
SigPool dffsignals;
- for (auto &it : module->cells) {
- if (ct.cell_known(it.second->type) && it.second->connections.count("\\Q"))
- dffsignals.add(sigmap(it.second->connections.at("\\Q")));
+ for (auto &it : module->cells_) {
+ if (ct.cell_known(it.second->type) && it.second->hasPort("\\Q"))
+ dffsignals.add(sigmap(it.second->getPort("\\Q")));
}
- for (auto &it : module->wires) {
+ for (auto &it : module->wires_) {
if (dffsignals.check_any(it.second))
dff_wires.insert(it.first);
}
}
-static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL::Design *design, RTLIL::Module *module)
+static 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);
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (!design->selected(module, it.second))
continue;
@@ -113,10 +113,10 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
info.cell = it.second;
if (info.cell->type == "$dff") {
- info.bit_clk = sigmap(info.cell->connections.at("\\CLK")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
- std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->connections.at("\\D")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
for (size_t i = 0; i < sig_d.size(); i++) {
info.bit_d = sig_d.at(i);
bit_info[sig_q.at(i)] = info;
@@ -125,12 +125,12 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
if (info.cell->type == "$adff") {
- info.bit_clk = sigmap(info.cell->connections.at("\\CLK")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->connections.at("\\ARST")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\CLK")).to_single_sigbit();
+ info.bit_arst = sigmap(info.cell->getPort("\\ARST")).to_single_sigbit();
info.clk_polarity = info.cell->parameters.at("\\CLK_POLARITY").as_bool();
info.arst_polarity = info.cell->parameters.at("\\ARST_POLARITY").as_bool();
- std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->connections.at("\\D")).to_sigbit_vector();
- std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->connections.at("\\Q")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_d = sigmap(info.cell->getPort("\\D")).to_sigbit_vector();
+ std::vector<RTLIL::SigBit> sig_q = sigmap(info.cell->getPort("\\Q")).to_sigbit_vector();
std::vector<RTLIL::State> arst_value = info.cell->parameters.at("\\ARST_VALUE").bits;
for (size_t i = 0; i < sig_d.size(); i++) {
info.bit_d = sig_d.at(i);
@@ -141,27 +141,27 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") {
- info.bit_clk = sigmap(info.cell->connections.at("\\C")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
info.clk_polarity = info.cell->type == "$_DFF_P_";
- info.bit_d = sigmap(info.cell->connections.at("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->connections.at("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
continue;
}
if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") {
- info.bit_clk = sigmap(info.cell->connections.at("\\C")).to_single_sigbit();
- info.bit_arst = sigmap(info.cell->connections.at("\\R")).to_single_sigbit();
+ info.bit_clk = sigmap(info.cell->getPort("\\C")).to_single_sigbit();
+ info.bit_arst = sigmap(info.cell->getPort("\\R")).to_single_sigbit();
info.clk_polarity = info.cell->type[6] == 'P';
info.arst_polarity = info.cell->type[7] == 'P';
info.arst_value = info.cell->type[0] == '1' ? RTLIL::State::S1 : RTLIL::State::S0;
- info.bit_d = sigmap(info.cell->connections.at("\\D")).to_single_sigbit();
- bit_info[sigmap(info.cell->connections.at("\\Q")).to_single_sigbit()] = info;
+ info.bit_d = sigmap(info.cell->getPort("\\D")).to_single_sigbit();
+ bit_info[sigmap(info.cell->getPort("\\Q")).to_single_sigbit()] = info;
continue;
}
}
- std::map<std::string, dff_map_info_t> empty_dq_map;
- for (auto &it : module->wires)
+ std::map<RTLIL::IdString, dff_map_info_t> empty_dq_map;
+ for (auto &it : module->wires_)
{
if (!consider_wire(it.second, empty_dq_map))
continue;
@@ -208,11 +208,11 @@ static void create_dff_dq_map(std::map<std::string, dff_map_info_t> &map, RTLIL:
}
}
-static void add_new_wire(RTLIL::Module *module, RTLIL::Wire *wire)
+static RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width = 1)
{
- if (module->count_id(wire->name))
- log_error("Attempting to create wire %s, but a wire of this name exists already! Hint: Try another value for -sep.\n", RTLIL::id2cstr(wire->name));
- module->add(wire);
+ 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));
+ return module->addWire(name, width);
}
struct ExposePass : public Pass {
@@ -259,6 +259,8 @@ struct ExposePass : public Pass {
bool flag_evert_dff = false;
std::string sep = ".";
+ log_header("Executing EXPOSE pass (exposing internal signals as outputs).\n");
+
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
@@ -292,15 +294,15 @@ struct ExposePass : public Pass {
CellTypes ct(design);
- std::map<RTLIL::Module*, std::map<std::string, dff_map_info_t>> dff_dq_maps;
- std::map<RTLIL::Module*, std::set<std::string>> dff_cells;
+ std::map<RTLIL::Module*, std::map<RTLIL::IdString, dff_map_info_t>> dff_dq_maps;
+ std::map<RTLIL::Module*, std::set<RTLIL::IdString>> dff_cells;
if (flag_evert_dff)
{
RTLIL::Module *first_module = NULL;
- std::set<std::string> shared_dff_wires;
+ std::set<RTLIL::IdString> shared_dff_wires;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
if (!design->selected(mod_it.second))
continue;
@@ -315,11 +317,11 @@ struct ExposePass : public Pass {
shared_dff_wires.insert(it.first);
first_module = mod_it.second;
} else {
- std::set<std::string> new_shared_dff_wires;
+ std::set<RTLIL::IdString> new_shared_dff_wires;
for (auto &it : shared_dff_wires) {
if (!dff_dq_maps[mod_it.second].count(it))
continue;
- if (!compare_wires(first_module->wires.at(it), mod_it.second->wires.at(it)))
+ if (!compare_wires(first_module->wires_.at(it), mod_it.second->wires_.at(it)))
continue;
new_shared_dff_wires.insert(it);
}
@@ -330,7 +332,7 @@ struct ExposePass : public Pass {
if (flag_shared)
for (auto &map_it : dff_dq_maps)
{
- std::map<std::string, dff_map_info_t> new_map;
+ std::map<RTLIL::IdString, dff_map_info_t> new_map;
for (auto &it : map_it.second)
if (shared_dff_wires.count(it.first))
new_map[it.first] = it.second;
@@ -343,33 +345,33 @@ struct ExposePass : public Pass {
dff_cells[it1.first].insert(it3);
}
- std::set<std::string> shared_wires, shared_cells;
- std::set<std::string> used_names;
+ std::set<RTLIL::IdString> shared_wires, shared_cells;
+ std::set<RTLIL::IdString> used_names;
if (flag_shared)
{
RTLIL::Module *first_module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
continue;
- std::set<std::string> dff_wires;
+ std::set<RTLIL::IdString> dff_wires;
if (flag_dff)
find_dff_wires(dff_wires, module);
if (first_module == NULL)
{
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (design->selected(module, it.second) && consider_wire(it.second, dff_dq_maps[module]))
if (!flag_dff || dff_wires.count(it.first))
shared_wires.insert(it.first);
if (flag_evert)
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
if (design->selected(module, it.second) && consider_cell(design, dff_cells[module], it.second))
shared_cells.insert(it.first);
@@ -377,22 +379,22 @@ struct ExposePass : public Pass {
}
else
{
- std::vector<std::string> delete_shared_wires, delete_shared_cells;
+ std::vector<RTLIL::IdString> delete_shared_wires, delete_shared_cells;
for (auto &it : shared_wires)
{
RTLIL::Wire *wire;
- if (module->wires.count(it) == 0)
+ if (module->wires_.count(it) == 0)
goto delete_shared_wire;
- wire = module->wires.at(it);
+ wire = module->wires_.at(it);
if (!design->selected(module, wire))
goto delete_shared_wire;
if (!consider_wire(wire, dff_dq_maps[module]))
goto delete_shared_wire;
- if (!compare_wires(first_module->wires.at(it), wire))
+ if (!compare_wires(first_module->wires_.at(it), wire))
goto delete_shared_wire;
if (flag_dff && !dff_wires.count(it))
goto delete_shared_wire;
@@ -407,16 +409,16 @@ struct ExposePass : public Pass {
{
RTLIL::Cell *cell;
- if (module->cells.count(it) == 0)
+ if (module->cells_.count(it) == 0)
goto delete_shared_cell;
- cell = module->cells.at(it);
+ cell = module->cells_.at(it);
if (!design->selected(module, cell))
goto delete_shared_cell;
if (!consider_cell(design, dff_cells[module], cell))
goto delete_shared_cell;
- if (!compare_cells(first_module->cells.at(it), cell))
+ if (!compare_cells(first_module->cells_.at(it), cell))
goto delete_shared_cell;
if (0)
@@ -432,23 +434,22 @@ struct ExposePass : public Pass {
}
}
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
{
RTLIL::Module *module = mod_it.second;
if (!design->selected(module))
continue;
- std::set<std::string> dff_wires;
+ std::set<RTLIL::IdString> dff_wires;
if (flag_dff && !flag_shared)
find_dff_wires(dff_wires, module);
SigMap sigmap(module);
SigMap out_to_in_map;
- std::vector<RTLIL::Wire*> new_wires;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
{
if (flag_shared) {
if (shared_wires.count(it.first) == 0)
@@ -466,29 +467,23 @@ struct ExposePass : public Pass {
}
if (flag_cut) {
- RTLIL::Wire *in_wire = new RTLIL::Wire;
- in_wire->name = it.second->name + sep + "i";
- in_wire->width = it.second->width;
+ RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
in_wire->port_input = true;
out_to_in_map.add(sigmap(it.second), in_wire);
- new_wires.push_back(in_wire);
}
}
if (flag_cut)
{
- for (auto it : new_wires)
- add_new_wire(module, it);
-
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (!ct.cell_known(it.second->type))
continue;
- for (auto &conn : it.second->connections)
+ for (auto &conn : it.second->connections_)
if (ct.cell_input(it.second->type, conn.first))
conn.second = out_to_in_map(sigmap(conn.second));
}
- for (auto &conn : module->connections)
+ for (auto &conn : module->connections_)
conn.second = out_to_in_map(sigmap(conn.second));
}
@@ -496,35 +491,29 @@ struct ExposePass : public Pass {
for (auto &dq : dff_dq_maps[module])
{
- if (!module->wires.count(dq.first))
+ if (!module->wires_.count(dq.first))
continue;
- RTLIL::Wire *wire = module->wires.at(dq.first);
+ RTLIL::Wire *wire = module->wires_.at(dq.first);
std::set<RTLIL::SigBit> wire_bits_set = sigmap(wire).to_sigbit_set();
std::vector<RTLIL::SigBit> wire_bits_vec = sigmap(wire).to_sigbit_vector();
dff_map_info_t &info = dq.second;
- RTLIL::Wire *wire_dummy_q = new RTLIL::Wire;
- wire_dummy_q->name = NEW_ID;
- wire_dummy_q->width = 0;
- add_new_wire(module, wire_dummy_q);
+ RTLIL::Wire *wire_dummy_q = add_new_wire(module, NEW_ID, 0);
for (auto &cell_name : info.cells) {
- RTLIL::Cell *cell = module->cells.at(cell_name);
- std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->connections.at("\\Q")).to_sigbit_vector();
+ RTLIL::Cell *cell = module->cells_.at(cell_name);
+ std::vector<RTLIL::SigBit> cell_q_bits = sigmap(cell->getPort("\\Q")).to_sigbit_vector();
for (auto &bit : cell_q_bits)
if (wire_bits_set.count(bit))
bit = RTLIL::SigBit(wire_dummy_q, wire_dummy_q->width++);
- cell->connections.at("\\Q") = cell_q_bits;
+ cell->setPort("\\Q", cell_q_bits);
}
- RTLIL::Wire *wire_q = new RTLIL::Wire;
- wire_q->name = wire->name + sep + "q";
- wire_q->width = wire->width;
+ RTLIL::Wire *wire_q = add_new_wire(module, wire->name.str() + sep + "q", wire->width);
wire_q->port_input = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_q->name));
- add_new_wire(module, wire_q);
RTLIL::SigSig connect_q;
for (size_t i = 0; i < wire_bits_vec.size(); i++) {
@@ -534,71 +523,55 @@ struct ExposePass : public Pass {
connect_q.second.append(RTLIL::SigBit(wire_q, i));
set_q_bits.insert(wire_bits_vec[i]);
}
- module->connections.push_back(connect_q);
+ module->connect(connect_q);
- RTLIL::Wire *wire_d = new RTLIL::Wire;
- wire_d->name = wire->name + sep + "d";
- wire_d->width = wire->width;
+ RTLIL::Wire *wire_d = add_new_wire(module, wire->name.str() + sep + "d", wire->width);
wire_d->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_d->name));
- add_new_wire(module, wire_d);
- module->connections.push_back(RTLIL::SigSig(wire_d, info.sig_d));
+ module->connect(RTLIL::SigSig(wire_d, info.sig_d));
- RTLIL::Wire *wire_c = new RTLIL::Wire;
- wire_c->name = wire->name + sep + "c";
+ RTLIL::Wire *wire_c = add_new_wire(module, wire->name.str() + sep + "c");
wire_c->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_c->name));
- add_new_wire(module, wire_c);
if (info.clk_polarity) {
- module->connections.push_back(RTLIL::SigSig(wire_c, info.sig_clk));
+ module->connect(RTLIL::SigSig(wire_c, info.sig_clk));
} else {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = NEW_ID;
- c->type = "$not";
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
c->parameters["\\A_SIGNED"] = 0;
c->parameters["\\A_WIDTH"] = 1;
c->parameters["\\Y_WIDTH"] = 1;
- c->connections["\\A"] = info.sig_clk;
- c->connections["\\Y"] = wire_c;
- module->add(c);
+ c->setPort("\\A", info.sig_clk);
+ c->setPort("\\Y", wire_c);
}
if (info.sig_arst != RTLIL::State::Sm)
{
- RTLIL::Wire *wire_r = new RTLIL::Wire;
- wire_r->name = wire->name + sep + "r";
+ RTLIL::Wire *wire_r = add_new_wire(module, wire->name.str() + sep + "r");
wire_r->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_r->name));
- add_new_wire(module, wire_r);
if (info.arst_polarity) {
- module->connections.push_back(RTLIL::SigSig(wire_r, info.sig_arst));
+ module->connect(RTLIL::SigSig(wire_r, info.sig_arst));
} else {
- RTLIL::Cell *c = new RTLIL::Cell;
- c->name = NEW_ID;
- c->type = "$not";
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$not");
c->parameters["\\A_SIGNED"] = 0;
c->parameters["\\A_WIDTH"] = 1;
c->parameters["\\Y_WIDTH"] = 1;
- c->connections["\\A"] = info.sig_arst;
- c->connections["\\Y"] = wire_r;
- module->add(c);
+ c->setPort("\\A", info.sig_arst);
+ c->setPort("\\Y", wire_r);
}
- RTLIL::Wire *wire_v = new RTLIL::Wire;
- wire_v->name = wire->name + sep + "v";
- wire_v->width = wire->width;
+ RTLIL::Wire *wire_v = add_new_wire(module, wire->name.str() + sep + "v", wire->width);
wire_v->port_output = true;
log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire_v->name));
- add_new_wire(module, wire_v);
- module->connections.push_back(RTLIL::SigSig(wire_v, info.arst_value));
+ module->connect(RTLIL::SigSig(wire_v, info.arst_value));
}
}
if (flag_evert)
{
- std::vector<std::string> delete_cells;
+ std::vector<RTLIL::Cell*> delete_cells;
- for (auto &it : module->cells)
+ for (auto &it : module->cells_)
{
if (flag_shared) {
if (shared_cells.count(it.first) == 0)
@@ -610,66 +583,59 @@ struct ExposePass : public Pass {
RTLIL::Cell *cell = it.second;
- if (design->modules.count(cell->type))
+ if (design->modules_.count(cell->type))
{
- RTLIL::Module *mod = design->modules.at(cell->type);
+ RTLIL::Module *mod = design->modules_.at(cell->type);
- for (auto &it : mod->wires)
+ for (auto &it : mod->wires_)
{
RTLIL::Wire *p = it.second;
if (!p->port_input && !p->port_output)
continue;
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = cell->name + sep + RTLIL::unescape_id(p->name);
- w->width = p->width;
+ RTLIL::Wire *w = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(p->name), p->width);
if (p->port_input)
w->port_output = true;
if (p->port_output)
w->port_input = true;
- add_new_wire(module, w);
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
+ log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
RTLIL::SigSpec sig;
- if (cell->connections.count(p->name) != 0)
- sig = cell->connections.at(p->name);
+ if (cell->hasPort(p->name))
+ sig = cell->getPort(p->name);
sig.extend(w->width);
if (w->port_input)
- module->connections.push_back(RTLIL::SigSig(sig, w));
+ module->connect(RTLIL::SigSig(sig, w));
else
- module->connections.push_back(RTLIL::SigSig(w, sig));
+ module->connect(RTLIL::SigSig(w, sig));
}
}
else
{
- for (auto &it : cell->connections)
+ for (auto &it : cell->connections())
{
- RTLIL::Wire *w = new RTLIL::Wire;
- w->name = cell->name + sep + RTLIL::unescape_id(it.first);
- w->width = it.second.width;
+ RTLIL::Wire *w = add_new_wire(module, cell->name.str() + sep + RTLIL::unescape_id(it.first), it.second.size());
if (ct.cell_input(cell->type, it.first))
w->port_output = true;
if (ct.cell_output(cell->type, it.first))
w->port_input = true;
- add_new_wire(module, w);
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name));
+ log("New module port: %s/%s (%s)\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(w->name), RTLIL::id2cstr(cell->type));
if (w->port_input)
- module->connections.push_back(RTLIL::SigSig(it.second, w));
+ module->connect(RTLIL::SigSig(it.second, w));
else
- module->connections.push_back(RTLIL::SigSig(w, it.second));
+ module->connect(RTLIL::SigSig(w, it.second));
}
}
- delete_cells.push_back(cell->name);
+ delete_cells.push_back(cell);
}
- for (auto &it : delete_cells) {
- log("Removing cell: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it));
- delete module->cells.at(it);
- module->cells.erase(it);
+ for (auto cell : delete_cells) {
+ log("Removing cell: %s/%s (%s)\n", log_id(module), log_id(cell), log_id(cell->type));
+ module->remove(cell);
}
}
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 81250b000..bfed0005d 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -31,8 +31,9 @@
namespace {
bool inv_mode;
-int verbose_level;
+int verbose_level, reduce_counter, reduce_stop_at;
typedef std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>>> drivers_t;
+std::string dump_prefix;
struct equiv_bit_t
{
@@ -112,13 +113,13 @@ struct FindReducedInputs
size_t idx_bits = get_bits(idx);
if (sat_pi_uniq_bitvec.size() != idx_bits) {
- sat_pi_uniq_bitvec.push_back(ez.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())));
}
log_assert(sat_pi_uniq_bitvec.size() == idx_bits);
- sat_pi[bit] = ez.literal(stringf("pi_%s", log_signal(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++)
@@ -243,7 +244,6 @@ struct PerformReduction
return 0;
if (sigdepth.count(out) != 0)
return sigdepth.at(out);
- sigdepth[out] = 0;
if (drivers.count(out) != 0) {
std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> &drv = drivers.at(out);
@@ -252,17 +252,18 @@ struct PerformReduction
log_error("Can't create SAT model for cell %s (%s)!\n", RTLIL::id2cstr(drv.first->name), RTLIL::id2cstr(drv.first->type));
celldone.insert(drv.first);
}
- int max_child_dept = 0;
+ int max_child_depth = 0;
for (auto &bit : drv.second)
- max_child_dept = std::max(register_cone_worker(celldone, sigdepth, bit), max_child_dept);
- sigdepth[out] = max_child_dept + 1;
+ max_child_depth = std::max(register_cone_worker(celldone, sigdepth, bit), max_child_depth);
+ sigdepth[out] = max_child_depth + 1;
} else {
pi_bits.push_back(out);
sat_pi.push_back(satgen.importSigSpec(out).front());
ez.assume(ez.NOT(satgen.importUndefSigSpec(out).front()));
+ sigdepth[out] = 0;
}
- return sigdepth[out];
+ return sigdepth.at(out);
}
PerformReduction(SigMap &sigmap, drivers_t &drivers, std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs, std::vector<RTLIL::SigBit> &bits, int cone_size) :
@@ -348,7 +349,7 @@ struct PerformReduction
std::vector<RTLIL::SigBit> bucket_sigbits;
for (int idx : bucket)
bucket_sigbits.push_back(out_bits[idx]);
- log("%s Trying to shatter bucket with %d signals: %s\n", indt, int(bucket.size()), log_signal(RTLIL::SigSpec(bucket_sigbits).optimized()));
+ log("%s Trying to shatter bucket with %d signals: %s\n", indt, int(bucket.size()), log_signal(bucket_sigbits));
}
std::vector<int> sat_set_list, sat_clr_list;
@@ -493,7 +494,7 @@ struct PerformReduction
std::vector<RTLIL::SigBit> r_sigbits;
for (int idx : r)
r_sigbits.push_back(out_bits[idx]);
- log(" Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(RTLIL::SigSpec(r_sigbits).optimized()));
+ log(" Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(r_sigbits));
}
std::vector<int> undef_slaves;
@@ -559,6 +560,38 @@ struct FreduceWorker
{
}
+ bool find_bit_in_cone(std::set<RTLIL::Cell*> &celldone, RTLIL::SigBit needle, RTLIL::SigBit haystack)
+ {
+ if (needle == haystack)
+ return true;
+ if (haystack.wire == NULL || needle.wire == NULL || drivers.count(haystack) == 0)
+ return false;
+
+ std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> &drv = drivers.at(haystack);
+
+ if (celldone.count(drv.first))
+ return false;
+ celldone.insert(drv.first);
+
+ for (auto &bit : drv.second)
+ if (find_bit_in_cone(celldone, needle, bit))
+ return true;
+ return false;
+ }
+
+ bool find_bit_in_cone(RTLIL::SigBit needle, RTLIL::SigBit haystack)
+ {
+ std::set<RTLIL::Cell*> celldone;
+ return find_bit_in_cone(celldone, needle, haystack);
+ }
+
+ void dump()
+ {
+ std::string filename = stringf("%s_%s_%05d.il", dump_prefix.c_str(), RTLIL::id2cstr(module->name), reduce_counter);
+ log("%s Writing dump file `%s'.\n", reduce_counter ? " " : "", filename.c_str());
+ Pass::call(design, stringf("dump -outfile %s %s", filename.c_str(), design->selected_active_module.empty() ? module->name.c_str() : ""));
+ }
+
int run()
{
log("Running functional reduction on module %s:\n", RTLIL::id2cstr(module->name));
@@ -569,15 +602,15 @@ struct FreduceWorker
int bits_full_total = 0;
std::vector<std::set<RTLIL::SigBit>> batches;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input) {
batches.push_back(sigmap(it.second).to_sigbit_set());
bits_full_total += it.second->width;
}
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (ct.cell_known(it.second->type)) {
std::set<RTLIL::SigBit> inputs, outputs;
- for (auto &port : it.second->connections) {
+ for (auto &port : it.second->connections()) {
std::vector<RTLIL::SigBit> bits = sigmap(port.second).to_sigbit_vector();
if (ct.cell_output(it.second->type, port.first))
outputs.insert(bits.begin(), bits.end());
@@ -590,8 +623,8 @@ struct FreduceWorker
batches.push_back(outputs);
bits_full_total += outputs.size();
}
- if (inv_mode && it.second->type == "$_INV_")
- inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(it.second->connections.at("\\A")), sigmap(it.second->connections.at("\\Y"))));
+ if (inv_mode && it.second->type == "$_NOT_")
+ inv_pairs.insert(std::pair<RTLIL::SigBit, RTLIL::SigBit>(sigmap(it.second->getPort("\\A")), sigmap(it.second->getPort("\\Y"))));
}
int bits_count = 0;
@@ -607,7 +640,7 @@ struct FreduceWorker
found_selected_wire:
log(" Finding reduced input cone for signal batch %s%c\n",
- log_signal(RTLIL::SigSpec(std::vector<RTLIL::SigBit>(batch.begin(), batch.end())).optimized()), verbose_level ? ':' : '.');
+ log_signal(batch), verbose_level ? ':' : '.');
FindReducedInputs infinder(sigmap, drivers);
for (auto &bit : batch) {
@@ -630,12 +663,12 @@ struct FreduceWorker
continue;
if (bucket.first.size() == 0) {
- log(" Finding const values for bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.');
+ log(" Finding const values for bucket %s%c\n", log_signal(bucket.second), verbose_level ? ':' : '.');
PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second, bucket.first.size());
for (size_t idx = 0; idx < bucket.second.size(); idx++)
worker.analyze_const(equiv, idx);
} else {
- log(" Trying to shatter bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.');
+ log(" Trying to shatter bucket %s%c\n", log_signal(bucket.second), verbose_level ? ':' : '.');
PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second, bucket.first.size());
worker.analyze(equiv, 100 * bucket_count / (buckets.size() + 1));
}
@@ -644,11 +677,14 @@ struct FreduceWorker
std::map<RTLIL::SigBit, int> bitusage;
module->rewrite_sigspecs(CountBitUsage(sigmap, bitusage));
+ if (!dump_prefix.empty())
+ dump();
+
log(" Rewiring %d equivialent groups:\n", int(equiv.size()));
int rewired_sigbits = 0;
for (auto &grp : equiv)
{
- log(" Using as master for group: %s\n", log_signal(grp.front().bit));
+ log(" [%05d] Using as master for group: %s\n", ++reduce_counter, log_signal(grp.front().bit));
RTLIL::SigSpec inv_sig;
for (size_t i = 1; i < grp.size(); i++)
@@ -663,35 +699,45 @@ struct FreduceWorker
continue;
}
+ if (find_bit_in_cone(grp[i].bit, grp.front().bit)) {
+ log(" Skipping dependency of master: %s\n", log_signal(grp[i].bit));
+ continue;
+ }
+
log(" Connect slave%s: %s\n", grp[i].inverted ? " using inverter" : "", log_signal(grp[i].bit));
RTLIL::Cell *drv = drivers.at(grp[i].bit).first;
- RTLIL::Wire *dummy_wire = module->new_wire(1, NEW_ID);
- for (auto &port : drv->connections)
+ RTLIL::Wire *dummy_wire = module->addWire(NEW_ID);
+ for (auto &port : drv->connections_)
if (ct.cell_output(drv->type, port.first))
sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second);
if (grp[i].inverted)
{
- if (inv_sig.width == 0)
+ if (inv_sig.size() == 0)
{
- inv_sig = module->new_wire(1, NEW_ID);
-
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- inv_cell->name = NEW_ID;
- inv_cell->type = "$_INV_";
- inv_cell->connections["\\A"] = grp[0].bit;
- inv_cell->connections["\\Y"] = inv_sig;
- module->add(inv_cell);
+ inv_sig = module->addWire(NEW_ID);
+
+ RTLIL::Cell *inv_cell = module->addCell(NEW_ID, "$_NOT_");
+ inv_cell->setPort("\\A", grp[0].bit);
+ inv_cell->setPort("\\Y", inv_sig);
}
- module->connections.push_back(RTLIL::SigSig(grp[i].bit, inv_sig));
+ module->connect(RTLIL::SigSig(grp[i].bit, inv_sig));
}
else
- module->connections.push_back(RTLIL::SigSig(grp[i].bit, grp[0].bit));
+ module->connect(RTLIL::SigSig(grp[i].bit, grp[0].bit));
rewired_sigbits++;
}
+
+ if (!dump_prefix.empty())
+ dump();
+
+ if (reduce_counter == reduce_stop_at) {
+ log(" Reached limit passed using -stop option. Skipping all further reductions.\n");
+ break;
+ }
}
log(" Rewired a total of %d signal bits in module %s.\n", rewired_sigbits, RTLIL::id2cstr(module->name));
@@ -711,7 +757,7 @@ struct FreducePass : public Pass {
log("\n");
log("This pass performs functional reduction in the circuit. I.e. if two nodes are\n");
log("equivialent, they are merged to one node and one of the redundant drivers is\n");
- log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\n");
+ log("disconnected. A subsequent call to 'clean' will remove the redundant drivers.\n");
log("\n");
log(" -v, -vv\n");
log(" enable verbose or very verbose output\n");
@@ -719,6 +765,14 @@ struct FreducePass : public Pass {
log(" -inv\n");
log(" enable explicit handling of inverted signals\n");
log("\n");
+ log(" -stop <n>\n");
+ log(" stop after <n> reduction operations. this is mostly used for\n");
+ log(" debugging the freduce command itself.\n");
+ log("\n");
+ log(" -dump <prefix>\n");
+ log(" dump the design to <prefix>_<module>_<num>.il after each reduction\n");
+ log(" operation. this is mostly used for debugging the freduce command.\n");
+ log("\n");
log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n");
log("equivialent nodes.\n");
log("\n");
@@ -728,8 +782,11 @@ struct FreducePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ reduce_counter = 0;
+ reduce_stop_at = 0;
verbose_level = 0;
inv_mode = false;
+ dump_prefix = std::string();
log_header("Executing FREDUCE pass (perform functional reduction).\n");
@@ -747,12 +804,20 @@ struct FreducePass : public Pass {
inv_mode = true;
continue;
}
+ if (args[argidx] == "-stop" && argidx+1 < args.size()) {
+ reduce_stop_at = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-dump" && argidx+1 < args.size()) {
+ dump_prefix = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
int bitcount = 0;
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
RTLIL::Module *module = mod_it.second;
if (design->selected(module))
bitcount += FreduceWorker(design, module).run();
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index db12cb57d..b3adefb92 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -27,6 +27,9 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
bool flag_make_outputs = false;
bool flag_make_outcmp = false;
bool flag_make_assert = false;
+ bool flag_flatten = false;
+
+ log_header("Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -47,32 +50,36 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
flag_make_assert = true;
continue;
}
+ if (args[argidx] == "-flatten") {
+ flag_flatten = true;
+ continue;
+ }
break;
}
if (argidx+3 != args.size() || args[argidx].substr(0, 1) == "-")
that->cmd_error(args, argidx, "command argument error");
- std::string gold_name = RTLIL::escape_id(args[argidx++]);
- std::string gate_name = RTLIL::escape_id(args[argidx++]);
- std::string miter_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString gold_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString gate_name = RTLIL::escape_id(args[argidx++]);
+ RTLIL::IdString miter_name = RTLIL::escape_id(args[argidx++]);
- if (design->modules.count(gold_name) == 0)
+ if (design->modules_.count(gold_name) == 0)
log_cmd_error("Can't find gold module %s!\n", gold_name.c_str());
- if (design->modules.count(gate_name) == 0)
+ if (design->modules_.count(gate_name) == 0)
log_cmd_error("Can't find gate module %s!\n", gate_name.c_str());
- if (design->modules.count(miter_name) != 0)
+ if (design->modules_.count(miter_name) != 0)
log_cmd_error("There is already a module %s!\n", gate_name.c_str());
- RTLIL::Module *gold_module = design->modules.at(gold_name);
- RTLIL::Module *gate_module = design->modules.at(gate_name);
+ RTLIL::Module *gold_module = design->modules_.at(gold_name);
+ RTLIL::Module *gate_module = design->modules_.at(gate_name);
- for (auto &it : gold_module->wires) {
+ for (auto &it : gold_module->wires_) {
RTLIL::Wire *w1 = it.second, *w2;
if (w1->port_id == 0)
continue;
- if (gate_module->wires.count(it.second->name) == 0)
+ if (gate_module->wires_.count(it.second->name) == 0)
goto match_gold_port_error;
- w2 = gate_module->wires.at(it.second->name);
+ w2 = gate_module->wires_.at(it.second->name);
if (w1->port_input != w2->port_input)
goto match_gold_port_error;
if (w1->port_output != w2->port_output)
@@ -84,13 +91,13 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
log_cmd_error("No matching port in gate module was found for %s!\n", it.second->name.c_str());
}
- for (auto &it : gate_module->wires) {
+ for (auto &it : gate_module->wires_) {
RTLIL::Wire *w1 = it.second, *w2;
if (w1->port_id == 0)
continue;
- if (gold_module->wires.count(it.second->name) == 0)
+ if (gold_module->wires_.count(it.second->name) == 0)
goto match_gate_port_error;
- w2 = gold_module->wires.at(it.second->name);
+ w2 = gold_module->wires_.at(it.second->name);
if (w1->port_input != w2->port_input)
goto match_gate_port_error;
if (w1->port_output != w2->port_output)
@@ -102,187 +109,151 @@ static void create_miter_equiv(struct Pass *that, std::vector<std::string> args,
log_cmd_error("No matching port in gold module was found for %s!\n", it.second->name.c_str());
}
+ log("Creating miter cell \"%s\" with gold cell \"%s\" and gate cell \"%s\".\n", RTLIL::id2cstr(miter_name), RTLIL::id2cstr(gold_name), RTLIL::id2cstr(gate_name));
+
RTLIL::Module *miter_module = new RTLIL::Module;
miter_module->name = miter_name;
- design->modules[miter_name] = miter_module;
-
- RTLIL::Cell *gold_cell = new RTLIL::Cell;
- gold_cell->name = "\\gold";
- gold_cell->type = gold_name;
- miter_module->add(gold_cell);
+ design->add(miter_module);
- RTLIL::Cell *gate_cell = new RTLIL::Cell;
- gate_cell->name = "\\gate";
- gate_cell->type = gate_name;
- miter_module->add(gate_cell);
+ RTLIL::Cell *gold_cell = miter_module->addCell("\\gold", gold_name);
+ RTLIL::Cell *gate_cell = miter_module->addCell("\\gate", gate_name);
RTLIL::SigSpec all_conditions;
- for (auto &it : gold_module->wires)
+ for (auto &it : gold_module->wires_)
{
RTLIL::Wire *w1 = it.second;
if (w1->port_input)
{
- RTLIL::Wire *w2 = new RTLIL::Wire;
- w2->name = "\\in_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2 = miter_module->addWire("\\in_" + RTLIL::unescape_id(w1->name), w1->width);
w2->port_input = true;
- w2->width = w1->width;
- miter_module->add(w2);
- gold_cell->connections[w1->name] = w2;
- gate_cell->connections[w1->name] = w2;
+ gold_cell->setPort(w1->name, w2);
+ gate_cell->setPort(w1->name, w2);
}
if (w1->port_output)
{
- RTLIL::Wire *w2_gold = new RTLIL::Wire;
- w2_gold->name = "\\gold_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2_gold = miter_module->addWire("\\gold_" + RTLIL::unescape_id(w1->name), w1->width);
w2_gold->port_output = flag_make_outputs;
- w2_gold->width = w1->width;
- miter_module->add(w2_gold);
- RTLIL::Wire *w2_gate = new RTLIL::Wire;
- w2_gate->name = "\\gate_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w2_gate = miter_module->addWire("\\gate_" + RTLIL::unescape_id(w1->name), w1->width);
w2_gate->port_output = flag_make_outputs;
- w2_gate->width = w1->width;
- miter_module->add(w2_gate);
- gold_cell->connections[w1->name] = w2_gold;
- gate_cell->connections[w1->name] = w2_gate;
+ gold_cell->setPort(w1->name, w2_gold);
+ gate_cell->setPort(w1->name, w2_gate);
RTLIL::SigSpec this_condition;
if (flag_ignore_gold_x)
{
- RTLIL::SigSpec gold_x = miter_module->new_wire(w2_gold->width, NEW_ID);
+ RTLIL::SigSpec gold_x = miter_module->addWire(NEW_ID, w2_gold->width);
for (int i = 0; i < w2_gold->width; i++) {
- RTLIL::Cell *eqx_cell = new RTLIL::Cell;
- eqx_cell->name = NEW_ID;
- eqx_cell->type = "$eqx";
+ RTLIL::Cell *eqx_cell = miter_module->addCell(NEW_ID, "$eqx");
eqx_cell->parameters["\\A_WIDTH"] = 1;
eqx_cell->parameters["\\B_WIDTH"] = 1;
eqx_cell->parameters["\\Y_WIDTH"] = 1;
eqx_cell->parameters["\\A_SIGNED"] = 0;
eqx_cell->parameters["\\B_SIGNED"] = 0;
- eqx_cell->connections["\\A"] = RTLIL::SigSpec(w2_gold, 1, i);
- eqx_cell->connections["\\B"] = RTLIL::State::Sx;
- eqx_cell->connections["\\Y"] = gold_x.extract(i, 1);
- miter_module->add(eqx_cell);
+ eqx_cell->setPort("\\A", RTLIL::SigSpec(w2_gold, i));
+ eqx_cell->setPort("\\B", RTLIL::State::Sx);
+ eqx_cell->setPort("\\Y", gold_x.extract(i, 1));
}
- RTLIL::SigSpec gold_masked = miter_module->new_wire(w2_gold->width, NEW_ID);
- RTLIL::SigSpec gate_masked = miter_module->new_wire(w2_gate->width, NEW_ID);
+ RTLIL::SigSpec gold_masked = miter_module->addWire(NEW_ID, w2_gold->width);
+ RTLIL::SigSpec gate_masked = miter_module->addWire(NEW_ID, w2_gate->width);
- RTLIL::Cell *or_gold_cell = new RTLIL::Cell;
- or_gold_cell->name = NEW_ID;
- or_gold_cell->type = "$or";
+ RTLIL::Cell *or_gold_cell = miter_module->addCell(NEW_ID, "$or");
or_gold_cell->parameters["\\A_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\B_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\Y_WIDTH"] = w2_gold->width;
or_gold_cell->parameters["\\A_SIGNED"] = 0;
or_gold_cell->parameters["\\B_SIGNED"] = 0;
- or_gold_cell->connections["\\A"] = w2_gold;
- or_gold_cell->connections["\\B"] = gold_x;
- or_gold_cell->connections["\\Y"] = gold_masked;
- miter_module->add(or_gold_cell);
-
- RTLIL::Cell *or_gate_cell = new RTLIL::Cell;
- or_gate_cell->name = NEW_ID;
- or_gate_cell->type = "$or";
+ or_gold_cell->setPort("\\A", w2_gold);
+ or_gold_cell->setPort("\\B", gold_x);
+ or_gold_cell->setPort("\\Y", gold_masked);
+
+ RTLIL::Cell *or_gate_cell = miter_module->addCell(NEW_ID, "$or");
or_gate_cell->parameters["\\A_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\B_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\Y_WIDTH"] = w2_gate->width;
or_gate_cell->parameters["\\A_SIGNED"] = 0;
or_gate_cell->parameters["\\B_SIGNED"] = 0;
- or_gate_cell->connections["\\A"] = w2_gate;
- or_gate_cell->connections["\\B"] = gold_x;
- or_gate_cell->connections["\\Y"] = gate_masked;
- miter_module->add(or_gate_cell);
-
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eqx";
+ or_gate_cell->setPort("\\A", w2_gate);
+ or_gate_cell->setPort("\\B", gold_x);
+ or_gate_cell->setPort("\\Y", gate_masked);
+
+ RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
eq_cell->parameters["\\Y_WIDTH"] = 1;
eq_cell->parameters["\\A_SIGNED"] = 0;
eq_cell->parameters["\\B_SIGNED"] = 0;
- eq_cell->connections["\\A"] = gold_masked;
- eq_cell->connections["\\B"] = gate_masked;
- eq_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- this_condition = eq_cell->connections["\\Y"];
- miter_module->add(eq_cell);
+ eq_cell->setPort("\\A", gold_masked);
+ eq_cell->setPort("\\B", gate_masked);
+ eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ this_condition = eq_cell->getPort("\\Y");
}
else
{
- RTLIL::Cell *eq_cell = new RTLIL::Cell;
- eq_cell->name = NEW_ID;
- eq_cell->type = "$eqx";
+ RTLIL::Cell *eq_cell = miter_module->addCell(NEW_ID, "$eqx");
eq_cell->parameters["\\A_WIDTH"] = w2_gold->width;
eq_cell->parameters["\\B_WIDTH"] = w2_gate->width;
eq_cell->parameters["\\Y_WIDTH"] = 1;
eq_cell->parameters["\\A_SIGNED"] = 0;
eq_cell->parameters["\\B_SIGNED"] = 0;
- eq_cell->connections["\\A"] = w2_gold;
- eq_cell->connections["\\B"] = w2_gate;
- eq_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- this_condition = eq_cell->connections["\\Y"];
- miter_module->add(eq_cell);
+ eq_cell->setPort("\\A", w2_gold);
+ eq_cell->setPort("\\B", w2_gate);
+ eq_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ this_condition = eq_cell->getPort("\\Y");
}
if (flag_make_outcmp)
{
- RTLIL::Wire *w_cmp = new RTLIL::Wire;
- w_cmp->name = "\\cmp_" + RTLIL::unescape_id(w1->name);
+ RTLIL::Wire *w_cmp = miter_module->addWire("\\cmp_" + RTLIL::unescape_id(w1->name));
w_cmp->port_output = true;
- miter_module->add(w_cmp);
- miter_module->connections.push_back(RTLIL::SigSig(w_cmp, this_condition));
+ miter_module->connect(RTLIL::SigSig(w_cmp, this_condition));
}
all_conditions.append(this_condition);
}
}
- if (all_conditions.width != 1) {
- RTLIL::Cell *reduce_cell = new RTLIL::Cell;
- reduce_cell->name = NEW_ID;
- reduce_cell->type = "$reduce_and";
- reduce_cell->parameters["\\A_WIDTH"] = all_conditions.width;
+ if (all_conditions.size() != 1) {
+ RTLIL::Cell *reduce_cell = miter_module->addCell(NEW_ID, "$reduce_and");
+ reduce_cell->parameters["\\A_WIDTH"] = all_conditions.size();
reduce_cell->parameters["\\Y_WIDTH"] = 1;
reduce_cell->parameters["\\A_SIGNED"] = 0;
- reduce_cell->connections["\\A"] = all_conditions;
- reduce_cell->connections["\\Y"] = miter_module->new_wire(1, NEW_ID);
- all_conditions = reduce_cell->connections["\\Y"];
- miter_module->add(reduce_cell);
+ reduce_cell->setPort("\\A", all_conditions);
+ reduce_cell->setPort("\\Y", miter_module->addWire(NEW_ID));
+ all_conditions = reduce_cell->getPort("\\Y");
}
if (flag_make_assert) {
- RTLIL::Cell *assert_cell = new RTLIL::Cell;
- assert_cell->name = NEW_ID;
- assert_cell->type = "$assert";
- assert_cell->connections["\\A"] = all_conditions;
- assert_cell->connections["\\EN"] = RTLIL::SigSpec(1, 1);
- miter_module->add(assert_cell);
+ RTLIL::Cell *assert_cell = miter_module->addCell(NEW_ID, "$assert");
+ assert_cell->setPort("\\A", all_conditions);
+ assert_cell->setPort("\\EN", RTLIL::SigSpec(1, 1));
}
- RTLIL::Wire *w_trigger = new RTLIL::Wire;
- w_trigger->name = "\\trigger";
+ RTLIL::Wire *w_trigger = miter_module->addWire("\\trigger");
w_trigger->port_output = true;
- miter_module->add(w_trigger);
- RTLIL::Cell *not_cell = new RTLIL::Cell;
- not_cell->name = NEW_ID;
- not_cell->type = "$not";
- not_cell->parameters["\\A_WIDTH"] = all_conditions.width;
- not_cell->parameters["\\A_WIDTH"] = all_conditions.width;
+ RTLIL::Cell *not_cell = miter_module->addCell(NEW_ID, "$not");
+ not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
+ not_cell->parameters["\\A_WIDTH"] = all_conditions.size();
not_cell->parameters["\\Y_WIDTH"] = w_trigger->width;
not_cell->parameters["\\A_SIGNED"] = 0;
- not_cell->connections["\\A"] = all_conditions;
- not_cell->connections["\\Y"] = w_trigger;
- miter_module->add(not_cell);
+ not_cell->setPort("\\A", all_conditions);
+ not_cell->setPort("\\Y", w_trigger);
miter_module->fixup_ports();
+
+ if (flag_flatten) {
+ log_push();
+ Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;");
+ log_pop();
+ }
}
struct MiterPass : public Pass {
@@ -313,6 +284,9 @@ struct MiterPass : public Pass {
log(" -make_assert\n");
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
+ log(" -flatten\n");
+ log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index c08271590..fd0abf4a5 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
+#include <errno.h>
+#include <string.h>
namespace {
@@ -92,19 +94,35 @@ struct SatHelper
RTLIL::SigSpec big_lhs, big_rhs;
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
{
if (it.second->attributes.count("\\init") == 0)
continue;
RTLIL::SigSpec lhs = sigmap(it.second);
RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
- log_assert(lhs.width == rhs.width);
+ log_assert(lhs.size() == rhs.size());
+
+ RTLIL::SigSpec removed_bits;
+ for (int i = 0; i < lhs.size(); i++) {
+ RTLIL::SigSpec bit = lhs.extract(i, 1);
+ if (!satgen.initial_state.check_all(bit)) {
+ removed_bits.append(bit);
+ lhs.remove(i, 1);
+ rhs.remove(i, 1);
+ i--;
+ }
+ }
- log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
+ if (removed_bits.size())
+ 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));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
}
for (auto &s : sets_init)
@@ -118,9 +136,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -130,7 +148,6 @@ struct SatHelper
if (!satgen.initial_state.check_all(big_lhs)) {
RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
- rem.optimize();
log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
}
@@ -144,17 +161,17 @@ struct SatHelper
RTLIL::SigSpec rem = satgen.initial_state.export_all();
rem.remove(big_lhs);
big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.width));
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
}
if (set_init_zero) {
RTLIL::SigSpec rem = satgen.initial_state.export_all();
rem.remove(big_lhs);
big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.width));
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
}
- if (big_lhs.width == 0) {
+ if (big_lhs.size() == 0) {
log("No constraints for initial state found.\n\n");
return;
}
@@ -187,9 +204,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -208,11 +225,11 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
- log("Import set-constraint for timestep: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ log("Import set-constraint for this timestep: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
big_lhs.append(lhs);
big_rhs.append(rhs);
@@ -226,7 +243,7 @@ struct SatHelper
log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.c_str());
show_signal_pool.add(sigmap(lhs));
- log("Import unset-constraint for timestep: %s\n", log_signal(lhs));
+ log("Import unset-constraint for this timestep: %s\n", log_signal(lhs));
big_lhs.remove2(lhs, &big_rhs);
}
@@ -289,7 +306,7 @@ struct SatHelper
for (int t = 0; t < 3; t++)
for (auto &sig : sets_def_undef[t]) {
- log("Import %s constraint for timestep: %s\n", t == 0 ? "def" : t == 1 ? "any_undef" : "all_undef", log_signal(sig));
+ 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)));
@@ -300,11 +317,11 @@ struct SatHelper
}
int import_cell_counter = 0;
- for (auto &c : module->cells)
+ 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)
+ for (auto &p : c.second->connections())
if (ct.cell_output(c.second->type, p.first))
show_drivers.insert(sigmap(p.second), c.second);
import_cell_counter++;
@@ -318,7 +335,7 @@ struct SatHelper
int setup_proof(int timestep = -1)
{
- assert(prove.size() || prove_x.size() || prove_asserts);
+ log_assert(prove.size() || prove_x.size() || prove_asserts);
RTLIL::SigSpec big_lhs, big_rhs;
std::vector<int> prove_bits;
@@ -336,9 +353,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Proof expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import proof-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -364,9 +381,9 @@ struct SatHelper
show_signal_pool.add(sigmap(lhs));
show_signal_pool.add(sigmap(rhs));
- if (lhs.width != rhs.width)
+ if (lhs.size() != rhs.size())
log_cmd_error("Proof-x expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.width, s.second.c_str(), log_signal(rhs), rhs.width);
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
log("Import proof-x-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
big_lhs.remove2(lhs, &big_rhs);
@@ -389,10 +406,8 @@ struct SatHelper
if (prove_asserts) {
RTLIL::SigSpec asserts_a, asserts_en;
satgen.getAsserts(asserts_a, asserts_en, timestep);
- asserts_a.expand();
- asserts_en.expand();
- for (size_t i = 0; i < asserts_a.chunks.size(); i++)
- log("Import proof for assert: %s when %s.\n", log_signal(asserts_a.chunks[i]), log_signal(asserts_en.chunks[i]));
+ for (int i = 0; i < SIZE(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));
}
@@ -490,7 +505,7 @@ struct SatHelper
final_signals.add(sig);
} else {
for (auto &d : drivers)
- for (auto &p : d->connections) {
+ for (auto &p : d->connections()) {
if (d->type == "$dff" && p.first == "\\CLK")
continue;
if (d->type.substr(0, 6) == "$_DFF_" && p.first == "\\C")
@@ -521,12 +536,12 @@ struct SatHelper
std::vector<int> modelUndefExpressions;
- for (auto &c : modelSig.chunks)
+ for (auto &c : modelSig.chunks())
if (c.wire != NULL)
{
ModelBlockInfo info;
RTLIL::SigSpec chunksig = c;
- info.width = chunksig.width;
+ info.width = chunksig.size();
info.description = log_signal(chunksig);
for (int timestep = -1; timestep <= max_timestep; timestep++)
@@ -551,7 +566,7 @@ struct SatHelper
// Add initial state signals as collected by satgen
//
modelSig = satgen.initial_state.export_all();
- for (auto &c : modelSig.chunks)
+ for (auto &c : modelSig.chunks())
if (c.wire != NULL)
{
ModelBlockInfo info;
@@ -559,7 +574,7 @@ struct SatHelper
info.timestep = 0;
info.offset = modelExpressions.size();
- info.width = chunksig.width;
+ info.width = chunksig.size();
info.description = log_signal(chunksig);
modelInfo.insert(info);
@@ -631,6 +646,109 @@ struct SatHelper
log(" no model variables selected for display.\n");
}
+ void dump_model_to_vcd(std::string vcd_file_name)
+ {
+ FILE *f = fopen(vcd_file_name.c_str(), "w");
+ if (!f)
+ log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno));
+
+ log("Dumping SAT model to VCD file %s\n", vcd_file_name.c_str());
+
+ time_t timestamp;
+ struct tm* now;
+ char stime[128] = {};
+ time(&timestamp);
+ now = localtime(&timestamp);
+ strftime(stime, sizeof(stime), "%c", now);
+
+ std::string module_fname = "unknown";
+ auto apos = module->attributes.find("\\src");
+ if(apos != module->attributes.end())
+ module_fname = module->attributes["\\src"].decode_string();
+
+ fprintf(f, "$date\n");
+ fprintf(f, " %s\n", stime);
+ fprintf(f, "$end\n");
+ fprintf(f, "$version\n");
+ 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",
+ module->name.c_str(), module_fname.c_str());
+ fprintf(f, "$end\n");
+
+ // VCD has some limits on internal (non-display) identifier names, so make legal ones
+ std::map<std::string, std::string> vcdnames;
+
+ fprintf(f, "$timescale 1ns\n"); // arbitrary time scale since actual clock period is unknown/unimportant
+ fprintf(f, "$scope module %s $end\n", module->name.c_str());
+ for (auto &info : modelInfo)
+ {
+ if (vcdnames.find(info.description) != vcdnames.end())
+ continue;
+
+ char namebuf[16];
+ snprintf(namebuf, sizeof(namebuf), "v%d", static_cast<int>(vcdnames.size()));
+ vcdnames[info.description] = namebuf;
+
+ // Even display identifiers can't use some special characters
+ std::string legal_desc = info.description.c_str();
+ for (auto &c : legal_desc) {
+ if(c == '$')
+ c = '_';
+ if(c == ':')
+ c = '_';
+ }
+
+ fprintf(f, "$var wire %d %s %s $end\n", info.width, namebuf, legal_desc.c_str());
+
+ // Need to look at first *two* cycles!
+ // We need to put a name on all variables but those without an initialization clause
+ // have no value at timestep 0
+ if(info.timestep > 1)
+ break;
+ }
+ fprintf(f, "$upscope $end\n");
+ fprintf(f, "$enddefinitions $end\n");
+ fprintf(f, "$dumpvars\n");
+
+ static const char bitvals[] = "01xzxx";
+
+ int last_timestep = -2;
+ for (auto &info : modelInfo)
+ {
+ RTLIL::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;
+ }
+
+ if (info.timestep != last_timestep) {
+ if(last_timestep == 0)
+ fprintf(f, "$end\n");
+ else
+ fprintf(f, "#%d\n", info.timestep);
+ last_timestep = info.timestep;
+ }
+
+ if(info.width == 1) {
+ fprintf(f, "%c%s\n", bitvals[value.bits[0]], vcdnames[info.description].c_str());
+ } else {
+ fprintf(f, "b");
+ for(int k=info.width-1; k >= 0; k --) //need to flip bit ordering for VCD
+ fprintf(f, "%c", bitvals[value.bits[k]]);
+ fprintf(f, " %s\n", vcdnames[info.description].c_str());
+ }
+ }
+
+ if (last_timestep == -2)
+ log(" no model variables selected for display.\n");
+
+ fclose(f);
+ }
+
void invalidate_model(bool max_undef)
{
std::vector<int> clause;
@@ -756,7 +874,7 @@ struct SatPass : public Pass {
log(" -set-def-at <N> <signal>\n");
log(" -set-any-undef-at <N> <signal>\n");
log(" -set-all-undef-at <N> <signal>\n");
- log(" add undef contraints in the given timestep.\n");
+ log(" add undef constraints in the given timestep.\n");
log("\n");
log(" -set-init <signal> <value>\n");
log(" set the initial value for the register driving the signal to the value\n");
@@ -770,6 +888,13 @@ struct SatPass : public Pass {
log(" -set-init-zero\n");
log(" set all initial states (not set using -set-init) to zero\n");
log("\n");
+ log(" -dump_vcd <vcd-file-name>\n");
+ log(" dump SAT model (counter example in proof) to VCD 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");
+ log("\n");
log("The following additional options can be used to set up a proof. If also -seq\n");
log("is passed, a temporal induction proof is performed.\n");
log("\n");
@@ -792,9 +917,15 @@ struct SatPass : public Pass {
log(" -prove-asserts\n");
log(" Prove that all asserts in the design hold.\n");
log("\n");
+ log(" -prove-skip <N>\n");
+ log(" Do not enforce the prove-condition for the first <N> time steps.\n");
+ log("\n");
log(" -maxsteps <N>\n");
log(" Set a maximum length for the induction.\n");
log("\n");
+ log(" -initsteps <N>\n");
+ log(" Set initial length for the induction.\n");
+ log("\n");
log(" -timeout <N>\n");
log(" Maximum number of seconds a single SAT instance may take.\n");
log("\n");
@@ -817,11 +948,12 @@ struct SatPass : public Pass {
std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at;
std::map<int, std::vector<std::string>> unsets_at, sets_def_at, sets_any_undef_at, sets_all_undef_at;
std::vector<std::string> shows, sets_def, sets_any_undef, sets_all_undef;
- int loopcount = 0, seq_len = 0, maxsteps = 0, timeout = 0;
+ int loopcount = 0, seq_len = 0, maxsteps = 0, initsteps = 0, timeout = 0, prove_skip = 0;
bool verify = false, fail_on_timeout = false, enable_undef = false, set_def_inputs = false;
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;
log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
@@ -861,6 +993,10 @@ struct SatPass : public Pass {
maxsteps = atoi(args[++argidx].c_str());
continue;
}
+ if (args[argidx] == "-initsteps" && argidx+1 < args.size()) {
+ initsteps = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-ignore_div_by_zero") {
ignore_div_by_zero = true;
continue;
@@ -926,6 +1062,10 @@ struct SatPass : public Pass {
prove_asserts = true;
continue;
}
+ if (args[argidx] == "-prove-skip" && argidx+1 < args.size()) {
+ prove_skip = atoi(args[++argidx].c_str());
+ continue;
+ }
if (args[argidx] == "-seq" && argidx+1 < args.size()) {
seq_len = atoi(args[++argidx].c_str());
continue;
@@ -995,12 +1135,20 @@ struct SatPass : public Pass {
ignore_unknown_cells = true;
continue;
}
+ if (args[argidx] == "-dump_vcd" && argidx+1 < args.size()) {
+ vcd_file_name = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-dump_cnf" && argidx+1 < args.size()) {
+ cnf_file_name = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
RTLIL::Module *module = NULL;
- for (auto &mod_it : design->modules)
+ for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second)) {
if (module)
log_cmd_error("Only one module must be selected for the SAT pass! (selected: %s and %s)\n",
@@ -1013,25 +1161,31 @@ struct SatPass : public Pass {
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");
+
+ 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");
+
if (set_init_undef + set_init_zero + set_init_def > 1)
log_cmd_error("The options -set-init-undef, -set-init-def, and -set-init-zero are exclusive!\n");
if (set_def_inputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input)
- sets_def.push_back(it.second->name);
+ sets_def.push_back(it.second->name.str());
}
if (show_inputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_input)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (show_outputs) {
- for (auto &it : module->wires)
+ for (auto &it : module->wires_)
if (it.second->port_output)
- shows.push_back(it.second->name);
+ shows.push_back(it.second->name.str());
}
if (tempinduct)
@@ -1107,6 +1261,8 @@ struct SatPass : public Pass {
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;
}
@@ -1125,24 +1281,47 @@ struct SatPass : public Pass {
if (inductlen > 1)
inductstep.force_unique_state(1, inductlen + 1);
- 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;
+ 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 (!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("Induction step failed. Incrementing induction length.\n");
- inductstep.ez.assume(property);
+ log("Dumping CNF to file `%s'.\n", cnf_file_name.c_str());
+ cnf_file_name.clear();
+
+ inductstep.ez.printDIMACS(f, false);
+ fclose(f);
+ }
- inductstep.print_model();
+ 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;
+ }
+
+ log("Induction step failed. Incrementing induction length.\n");
+ inductstep.ez.assume(property);
+ inductstep.print_model();
+ }
}
log("\nReached maximum number of time steps -> proof failed.\n");
+ if(!vcd_file_name.empty())
+ inductstep.dump_model_to_vcd(vcd_file_name);
print_proof_failed();
tip_failed:
@@ -1195,7 +1374,8 @@ struct SatPass : public Pass {
for (int timestep = 1; timestep <= seq_len; timestep++) {
sathelper.setup(timestep);
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
- prove_bits.push_back(sathelper.setup_proof(timestep));
+ if (timestep > prove_skip)
+ 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)));
@@ -1203,10 +1383,18 @@ struct SatPass : public Pass {
}
sathelper.generate_model();
-#if 0
- // print CNF for debugging
- sathelper.ez.printDIMACS(stdout, true);
-#endif
+ 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();
+
+ sathelper.ez.printDIMACS(f, false);
+ fclose(f);
+ }
int rerun_counter = 0;
@@ -1230,6 +1418,9 @@ struct SatPass : public Pass {
sathelper.print_model();
+ if(!vcd_file_name.empty())
+ sathelper.dump_model_to_vcd(vcd_file_name);
+
if (loopcount != 0) {
loopcount--, rerun_counter++;
sathelper.invalidate_model(max_undef);
diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore
index ca9d3942c..e6dcc6bc0 100644
--- a/passes/techmap/.gitignore
+++ b/passes/techmap/.gitignore
@@ -1 +1 @@
-stdcells.inc
+techmap.inc
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index ae1ebbb56..72998f87b 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -2,24 +2,30 @@
OBJS += passes/techmap/techmap.o
OBJS += passes/techmap/simplemap.o
OBJS += passes/techmap/dfflibmap.o
+OBJS += passes/techmap/libparse.o
+
+ifneq ($(SMALL),1)
OBJS += passes/techmap/iopadmap.o
OBJS += passes/techmap/hilomap.o
-OBJS += passes/techmap/libparse.o
OBJS += passes/techmap/extract.o
+OBJS += passes/techmap/maccmap.o
+OBJS += passes/techmap/alumacc.o
+endif
-GENFILES += passes/techmap/stdcells.inc
+GENFILES += passes/techmap/techmap.inc
-passes/techmap/stdcells.inc: techlibs/common/stdcells.v
- echo "// autogenerated from $<" > $@.new
- od -v -td1 -w1 $< | awk 'BEGIN { print "static char stdcells_code[] = {"; } $$2 != "" { print $$2 ","; } \
- END { print 0 "};"; }' | fmt >> $@.new
- mv $@.new $@
+passes/techmap/techmap.inc: techlibs/common/techmap.v
+ $(P) echo "// autogenerated from $<" > $@.new
+ $(Q) echo "static char stdcells_code[] = {" >> $@.new
+ $(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new
+ $(Q) echo "0};" >> $@.new
+ $(Q) mv $@.new $@
-passes/techmap/techmap.o: passes/techmap/stdcells.inc
+passes/techmap/techmap.o: passes/techmap/techmap.inc
TARGETS += yosys-filterlib
GENFILES += passes/techmap/filterlib.o
yosys-filterlib: passes/techmap/filterlib.o
- $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
+ $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS)
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
new file mode 100644
index 000000000..1115eead5
--- /dev/null
+++ b/passes/techmap/alumacc.cc
@@ -0,0 +1,563 @@
+/*
+ * 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/macc.h"
+
+struct AlumaccWorker
+{
+ RTLIL::Module *module;
+ SigMap sigmap;
+
+ struct maccnode_t {
+ Macc macc;
+ RTLIL::Cell *cell;
+ RTLIL::SigSpec y;
+ int users;
+ };
+
+ struct alunode_t
+ {
+ std::vector<RTLIL::Cell*> cells;
+ RTLIL::SigSpec a, b, c, y;
+ std::vector<std::tuple<bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
+ bool is_signed, invert_b;
+
+ RTLIL::Cell *alu_cell;
+ RTLIL::SigSpec cached_lt, cached_gt, cached_eq, cached_ne;
+ RTLIL::SigSpec cached_cf, cached_of, cached_sf;
+
+ RTLIL::SigSpec get_lt() {
+ if (SIZE(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)
+ 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)
+ cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"));
+ return cached_eq;
+ }
+
+ RTLIL::SigSpec get_ne() {
+ if (SIZE(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) {
+ 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]);
+ }
+ return cached_cf;
+ }
+
+ RTLIL::SigSpec get_of() {
+ if (SIZE(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]);
+ }
+ return cached_of;
+ }
+
+ RTLIL::SigSpec get_sf() {
+ if (SIZE(cached_sf) == 0) {
+ cached_sf = alu_cell->getPort("\\Y");
+ cached_sf = cached_sf[SIZE(cached_sf)-1];
+ }
+ return cached_sf;
+ }
+ };
+
+ std::map<RTLIL::SigBit, int> bit_users;
+ std::map<RTLIL::SigSpec, maccnode_t*> sig_macc;
+ std::map<RTLIL::SigSig, std::set<alunode_t*>> sig_alu;
+ int macc_counter, alu_counter;
+
+ AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module)
+ {
+ macc_counter = 0;
+ alu_counter = 0;
+ }
+
+ void count_bit_users()
+ {
+ for (auto port : module->ports)
+ for (auto bit : sigmap(module->wire(port)))
+ bit_users[bit]++;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ for (auto bit : sigmap(conn.second))
+ bit_users[bit]++;
+ }
+
+ void extract_macc()
+ {
+ for (auto cell : module->selected_cells())
+ {
+ if (!cell->type.in("$pos", "$neg", "$add", "$sub", "$mul"))
+ continue;
+
+ log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type));
+
+ maccnode_t *n = new maccnode_t;
+ Macc::port_t new_port;
+
+ n->cell = cell;
+ n->y = sigmap(cell->getPort("\\Y"));
+ n->users = 0;
+
+ for (auto bit : n->y)
+ n->users = std::max(n->users, bit_users.at(bit) - 1);
+
+ if (cell->type.in("$pos", "$neg"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = cell->type == "$neg";
+ n->macc.ports.push_back(new_port);
+ }
+
+ if (cell->type.in("$add", "$sub"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = false;
+ n->macc.ports.push_back(new_port);
+
+ new_port.in_a = sigmap(cell->getPort("\\B"));
+ new_port.is_signed = cell->getParam("\\B_SIGNED").as_bool();
+ new_port.do_subtract = cell->type == "$sub";
+ n->macc.ports.push_back(new_port);
+ }
+
+ if (cell->type.in("$mul"))
+ {
+ new_port.in_a = sigmap(cell->getPort("\\A"));
+ new_port.in_b = sigmap(cell->getPort("\\B"));
+ new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ new_port.do_subtract = false;
+ n->macc.ports.push_back(new_port);
+ }
+
+ log_assert(sig_macc.count(n->y) == 0);
+ sig_macc[n->y] = n;
+ }
+ }
+
+ static bool macc_may_overflow(Macc &macc, int width, bool is_signed)
+ {
+ std::vector<int> port_sizes;
+
+ for (auto &port : macc.ports) {
+ if (port.is_signed != is_signed)
+ 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));
+ else
+ port_sizes.push_back(SIZE(port.in_a));
+ }
+
+ std::sort(port_sizes.begin(), port_sizes.end());
+
+ int acc_sum = 0, acc_shift = 0;
+ for (int sz : port_sizes) {
+ while ((sz - acc_shift) > 20) {
+ if (acc_sum & 1)
+ acc_sum++;
+ acc_sum = acc_sum >> 1;
+ acc_shift++;
+ }
+ acc_sum += (1 << (sz - acc_shift)) - 1;
+ }
+
+ while (acc_sum) {
+ acc_sum = acc_sum >> 1;
+ acc_shift++;
+ }
+
+ return acc_shift > width;
+ }
+
+ void merge_macc()
+ {
+ while (1)
+ {
+ std::set<maccnode_t*> delete_nodes;
+
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+
+ if (delete_nodes.count(n))
+ continue;
+
+ for (int i = 0; i < SIZE(n->macc.ports); i++)
+ {
+ auto &port = n->macc.ports[i];
+
+ if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
+ continue;
+
+ auto other_n = sig_macc.at(port.in_a);
+
+ 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))
+ 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++) {
+ if (do_subtract)
+ other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract;
+ if (j == 0)
+ n->macc.ports[i--] = other_n->macc.ports[j];
+ else
+ n->macc.ports.push_back(other_n->macc.ports[j]);
+ }
+
+ delete_nodes.insert(other_n);
+ }
+ }
+
+ if (delete_nodes.empty())
+ break;
+
+ for (auto n : delete_nodes) {
+ sig_macc.erase(n->y);
+ delete n;
+ }
+ }
+ }
+
+ void macc_to_alu()
+ {
+ std::set<maccnode_t*> delete_nodes;
+
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+ RTLIL::SigSpec A, B, C = n->macc.bit_ports;
+ bool a_signed = false, b_signed = false;
+ bool subtract_b = false;
+ alunode_t *alunode;
+
+ for (auto &port : n->macc.ports)
+ if (SIZE(port.in_b) > 0) {
+ goto next_macc;
+ } else if (SIZE(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))
+ goto next_macc;
+ B = port.in_a;
+ b_signed = port.is_signed;
+ subtract_b = port.do_subtract;
+ } else {
+ if (SIZE(A))
+ goto next_macc;
+ A = port.in_a;
+ a_signed = port.is_signed;
+ }
+
+ if (!a_signed || !b_signed) {
+ if (SIZE(A) == SIZE(n->y))
+ a_signed = false;
+ if (SIZE(B) == SIZE(n->y))
+ b_signed = false;
+ if (a_signed != b_signed)
+ goto next_macc;
+ }
+
+ if (SIZE(A) == 0 && SIZE(C) > 0) {
+ A = C[0];
+ C.remove(0);
+ }
+
+ if (SIZE(B) == 0 && SIZE(C) > 0) {
+ B = C[0];
+ C.remove(0);
+ }
+
+ if (subtract_b)
+ C.append(RTLIL::S1);
+
+ if (SIZE(C) > 1)
+ goto next_macc;
+
+ if (!subtract_b && B < A && SIZE(B))
+ std::swap(A, B);
+
+ log(" creating $alu model for $macc %s.\n", log_id(n->cell));
+
+ alunode = new alunode_t;
+ alunode->cells.push_back(n->cell);
+ alunode->is_signed = a_signed;
+ alunode->invert_b = subtract_b;
+
+ alunode->a = A;
+ alunode->b = B;
+ alunode->c = C;
+ alunode->y = n->y;
+
+ sig_alu[RTLIL::SigSig(A, B)].insert(alunode);
+ delete_nodes.insert(n);
+ next_macc:;
+ }
+
+ for (auto n : delete_nodes) {
+ sig_macc.erase(n->y);
+ delete n;
+ }
+ }
+
+ void replace_macc()
+ {
+ for (auto &it : sig_macc)
+ {
+ auto n = it.second;
+ auto cell = module->addCell(NEW_ID, "$macc");
+ macc_counter++;
+
+ log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell));
+
+ n->macc.optimize(SIZE(n->y));
+ n->macc.to_cell(cell);
+ cell->setPort("\\Y", n->y);
+ cell->fixup_parameters();
+ module->remove(n->cell);
+ delete n;
+ }
+
+ sig_macc.clear();
+ }
+
+ void extract_cmp_alu()
+ {
+ std::vector<RTLIL::Cell*> lge_cells, eq_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type.in("$lt", "$le", "$ge", "$gt"))
+ lge_cells.push_back(cell);
+ if (cell->type.in("$eq", "$eqx", "$ne", "$nex"))
+ eq_cells.push_back(cell);
+ }
+
+ for (auto cell : lge_cells)
+ {
+ log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type));
+
+ bool cmp_less = cell->type.in("$lt", "$le");
+ bool cmp_equal = cell->type.in("$le", "$ge");
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+
+ RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
+ RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+
+ if (B < A && SIZE(B)) {
+ cmp_less = !cmp_less;
+ std::swap(A, B);
+ }
+
+ alunode_t *n = nullptr;
+
+ for (auto node : sig_alu[RTLIL::SigSig(A, B)])
+ if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ n = node;
+ break;
+ }
+
+ if (n == nullptr) {
+ n = new alunode_t;
+ n->a = A;
+ n->b = B;
+ n->c = RTLIL::S1;
+ n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B)));
+ n->is_signed = is_signed;
+ n->invert_b = true;
+ sig_alu[RTLIL::SigSig(A, B)].insert(n);
+ log(" new $alu\n");
+ } else {
+ log(" merged with %s.\n", log_id(n->cells.front()));
+ }
+
+ n->cells.push_back(cell);
+ n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y));
+ }
+
+ for (auto cell : eq_cells)
+ {
+ bool cmp_equal = cell->type.in("$eq", "$eqx");
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+
+ RTLIL::SigSpec A = sigmap(cell->getPort("\\A"));
+ RTLIL::SigSpec B = sigmap(cell->getPort("\\B"));
+ RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y"));
+
+ if (B < A && SIZE(B))
+ std::swap(A, B);
+
+ alunode_t *n = nullptr;
+
+ for (auto node : sig_alu[RTLIL::SigSig(A, B)])
+ if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) {
+ n = node;
+ break;
+ }
+
+ if (n != nullptr) {
+ log(" creating $alu model for %s (%s): merged with %s.\n", log_id(cell), log_id(cell->type), log_id(n->cells.front()));
+ n->cells.push_back(cell);
+ n->cmp.push_back(std::make_tuple(false, false, cmp_equal, !cmp_equal, Y));
+ }
+ }
+ }
+
+ void replace_alu()
+ {
+ for (auto &it1 : sig_alu)
+ for (auto n : it1.second)
+ {
+ if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(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++)
+ log("%s%s", i ? ", ": "", log_id(n->cells[i]));
+ log(": %s\n", log_id(n->alu_cell));
+
+ goto delete_node;
+ }
+
+ n->alu_cell = module->addCell(NEW_ID, "$alu");
+ alu_counter++;
+
+ log(" creating $alu cell for ");
+ for (int i = 0; i < SIZE(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("\\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->fixup_parameters(n->is_signed, n->is_signed);
+
+ for (auto &it : n->cmp)
+ {
+ bool cmp_lt = std::get<0>(it);
+ bool cmp_gt = std::get<1>(it);
+ bool cmp_eq = std::get<2>(it);
+ bool cmp_ne = std::get<3>(it);
+ RTLIL::SigSpec cmp_y = std::get<4>(it);
+
+ RTLIL::SigSpec sig;
+ if (cmp_lt) sig.append(n->get_lt());
+ if (cmp_gt) sig.append(n->get_gt());
+ if (cmp_eq) sig.append(n->get_eq());
+ if (cmp_ne) sig.append(n->get_ne());
+
+ if (SIZE(sig) > 1)
+ sig = module->ReduceOr(NEW_ID, sig);
+
+ sig.extend(SIZE(cmp_y));
+ module->connect(cmp_y, sig);
+ }
+
+ delete_node:
+ for (auto c : n->cells)
+ module->remove(c);
+ delete n;
+ }
+
+ sig_alu.clear();
+ }
+
+ void run()
+ {
+ log("Extracting $alu and $macc cells in module %s:\n", log_id(module));
+
+ count_bit_users();
+ extract_macc();
+ merge_macc();
+ macc_to_alu();
+ replace_macc();
+ extract_cmp_alu();
+ replace_alu();
+
+ log(" created %d $alu and %d $macc cells.\n", alu_counter, macc_counter);
+ }
+};
+
+struct AlumaccPass : public Pass {
+ AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ 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("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ // if (args[argidx] == "-foobar") {
+ // foobar_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ if (!mod->has_processes_warn()) {
+ AlumaccWorker worker(mod);
+ worker.run();
+ }
+ }
+} AlumaccPass;
+
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 23d93353f..07993b868 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -21,6 +21,7 @@
#include "kernel/log.h"
#include "libparse.h"
#include <string.h>
+#include <errno.h>
using namespace PASS_DFFLIBMAP;
@@ -28,7 +29,7 @@ struct cell_mapping {
std::string cell_name;
std::map<std::string, char> ports;
};
-static std::map<std::string, cell_mapping> cell_mappings;
+static std::map<RTLIL::IdString, cell_mapping> cell_mappings;
static void logmap(std::string dff)
{
@@ -318,7 +319,7 @@ static bool expand_cellmap(std::string pattern, std::string inv)
bool return_status = false;
for (auto &it : cell_mappings) {
- std::string from = it.first, to = it.first;
+ std::string from = it.first.str(), to = it.first.str();
if (from.size() != pattern.size())
continue;
for (size_t i = 0; i < from.size(); i++) {
@@ -342,7 +343,7 @@ static bool expand_cellmap(std::string pattern, std::string inv)
static void map_sr_to_arst(const char *from, const char *to)
{
- if (cell_mappings.count(to) > 0)
+ 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];
@@ -387,45 +388,45 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module)
log("Mapping DFF cells in module `%s':\n", module->name.c_str());
std::vector<RTLIL::Cell*> cell_list;
- for (auto &it : module->cells) {
+ for (auto &it : module->cells_) {
if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0)
cell_list.push_back(it.second);
}
std::map<std::string, int> stats;
- for (auto cell : cell_list) {
- cell_mapping &cm = cell_mappings[cell->type];
- RTLIL::Cell *new_cell = new RTLIL::Cell;
- new_cell->name = cell->name;
- new_cell->type = "\\" + cm.cell_name;
+ for (auto cell : cell_list)
+ {
+ auto cell_type = cell->type;
+ auto cell_name = cell->name;
+ auto cell_connections = cell->connections();
+ module->remove(cell);
+
+ cell_mapping &cm = cell_mappings[cell_type];
+ RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name);
+
for (auto &port : cm.ports) {
RTLIL::SigSpec sig;
if ('A' <= port.second && port.second <= 'Z') {
- sig = cell->connections[std::string("\\") + port.second];
+ sig = cell_connections[std::string("\\") + port.second];
+ } 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));
+ module->addNotGate(NEW_ID, sig, old_sig);
} else
if ('a' <= port.second && port.second <= 'z') {
- sig = cell->connections[std::string("\\") + char(port.second - ('a' - 'A'))];
- RTLIL::Cell *inv_cell = new RTLIL::Cell;
- RTLIL::Wire *inv_wire = new RTLIL::Wire;
- inv_cell->name = stringf("$dfflibmap$inv$%d", RTLIL::autoidx);
- inv_wire->name = stringf("$dfflibmap$sig$%d", RTLIL::autoidx++);
- inv_cell->type = "$_INV_";
- inv_cell->connections[port.second == 'q' ? "\\Y" : "\\A"] = sig;
- sig = RTLIL::SigSpec(inv_wire);
- inv_cell->connections[port.second == 'q' ? "\\A" : "\\Y"] = sig;
- module->cells[inv_cell->name] = inv_cell;
- module->wires[inv_wire->name] = inv_wire;
+ sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
+ sig = module->NotGate(NEW_ID, sig);
} else
if (port.second == '0' || port.second == '1') {
sig = RTLIL::SigSpec(port.second == '0' ? 0 : 1, 1);
} else
if (port.second != 0)
log_abort();
- new_cell->connections["\\" + port.first] = sig;
+ new_cell->setPort("\\" + port.first, sig);
}
- stats[stringf(" mapped %%d %s cells to %s cells.\n", cell->type.c_str(), new_cell->type.c_str())]++;
- module->cells[cell->name] = new_cell;
- delete cell;
+
+ stats[stringf(" mapped %%d %s cells to %s cells.\n", cell_type.c_str(), new_cell->type.c_str())]++;
}
for (auto &stat: stats)
@@ -467,11 +468,12 @@ struct DfflibmapPass : public Pass {
if (liberty_file.empty())
log_cmd_error("Missing `-liberty liberty_file' option!\n");
- FILE *f = fopen(liberty_file.c_str(), "r");
- if (f == NULL)
+ std::ifstream f;
+ f.open(liberty_file.c_str());
+ if (f.fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(f);
- fclose(f);
+ f.close();
find_cell(libparser.ast, "$_DFF_N_", false, false, false, false);
find_cell(libparser.ast, "$_DFF_P_", true, false, false, false);
@@ -528,7 +530,7 @@ struct DfflibmapPass : public Pass {
log(" final dff cell mappings:\n");
logmap_all();
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
dfflibmap(design, it.second);
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index eff14ff01..221e9e49d 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -23,7 +23,6 @@
#include "libs/subcircuit/subcircuit.h"
#include <algorithm>
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -34,8 +33,14 @@ namespace
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;
+ 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) {
@@ -46,12 +51,70 @@ namespace
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
+
+ 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;
+ if (!needleCell || !haystackCell) {
+ log_assert(!needleCell && !haystackCell);
+ return true;
+ }
+
+ 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 (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes))
return false;
@@ -61,16 +124,13 @@ namespace
RTLIL::Wire *lastHaystackWire = NULL;
std::map<RTLIL::IdString, RTLIL::Const> emptyAttr;
- for (auto &conn : needleCell->connections)
+ for (auto &conn : needleCell->connections())
{
RTLIL::SigSpec needleSig = conn.second;
- RTLIL::SigSpec haystackSig = haystackCell->connections.at(portMapping.at(conn.first));
-
- needleSig.expand();
- haystackSig.expand();
+ RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str()));
- for (int i = 0; i < std::min(needleSig.width, haystackSig.width); i++) {
- RTLIL::Wire *needleWire = needleSig.chunks.at(i).wire, *haystackWire = haystackSig.chunks.at(i).wire;
+ 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;
@@ -92,7 +152,7 @@ namespace
int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL)
{
SigMap sigmap(mod);
- std::map<RTLIL::SigChunk, bit_ref_t> sig_bit_ref;
+ std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref;
if (sel && !sel->selected(mod)) {
log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name));
@@ -121,111 +181,106 @@ namespace
std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count;
if (max_fanout > 0)
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (!sel || sel->selected(mod, cell))
- for (auto &conn : cell->connections) {
+ for (auto &conn : cell->connections()) {
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (chunk.wire != NULL)
- sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)]++;
+ for (auto &bit : conn_sig)
+ if (bit.wire != NULL)
+ sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++;
}
}
// create graph nodes from cells
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
continue;
- std::string type = cell->type;
+ std::string type = cell->type.str();
if (sel == NULL && type.substr(0, 2) == "\\$")
type = type.substr(1);
- graph.createNode(cell->name, type, (void*)cell);
+ graph.createNode(cell->name.str(), type, (void*)cell);
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
- graph.createPort(cell->name, conn.first, conn.second.width);
+ graph.createPort(cell->name.str(), conn.first.str(), conn.second.size());
if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0)
continue;
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (size_t i = 0; i < conn_sig.chunks.size(); i++)
+ for (int i = 0; i < conn_sig.size(); i++)
{
- auto &chunk = conn_sig.chunks[i];
- assert(chunk.width == 1);
+ auto &bit = conn_sig[i];
- if (chunk.wire == NULL) {
+ if (bit.wire == NULL) {
if (constports) {
std::string node = "$const$x";
- if (chunk.data.bits[0] == RTLIL::State::S0) node = "$const$0";
- if (chunk.data.bits[0] == RTLIL::State::S1) node = "$const$1";
- if (chunk.data.bits[0] == RTLIL::State::Sz) node = "$const$z";
- graph.createConnection(cell->name, conn.first, i, node, "\\Y", 0);
+ 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, conn.first, i, int(chunk.data.bits[0]));
+ graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data));
continue;
}
- if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout)
+ if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout)
continue;
- if (sel && !sel->selected(mod, chunk.wire))
+ if (sel && !sel->selected(mod, bit.wire))
continue;
- if (sig_bit_ref.count(chunk) == 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
- bit_ref.cell = cell->name;
- bit_ref.port = conn.first;
+ 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;
}
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
- graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name, conn.first, i);
+ 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 non-selected cells)
- for (auto &cell_it : mod->cells)
+ for (auto &cell_it : mod->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (sel && !sel->selected(mod, cell))
- for (auto &conn : cell->connections)
+ for (auto &conn : cell->connections())
{
RTLIL::SigSpec conn_sig = conn.second;
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (sig_bit_ref.count(chunk) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
+ 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);
}
}
}
// mark external signals (used in module ports)
- for (auto &wire_it : mod->wires)
+ for (auto &wire_it : mod->wires_)
{
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id > 0)
{
RTLIL::SigSpec conn_sig(wire);
sigmap.apply(conn_sig);
- conn_sig.expand();
- for (auto &chunk : conn_sig.chunks)
- if (sig_bit_ref.count(chunk) != 0) {
- bit_ref_t &bit_ref = sig_bit_ref[chunk];
+ 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);
}
}
@@ -238,21 +293,18 @@ namespace
RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match)
{
SigMap sigmap(needle);
- SigSet<std::pair<std::string, int>> sig2port;
+ SigSet<std::pair<RTLIL::IdString, int>> sig2port;
// create new cell
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = stringf("$extract$%s$%d", needle->name.c_str(), RTLIL::autoidx++);
- cell->type = needle->name;
- haystack->add(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) {
+ 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, 1, i)), std::pair<std::string, int>(wire->name, i));
- cell->connections[wire->name] = RTLIL::SigSpec(RTLIL::State::Sz, wire->width);
+ 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));
}
}
@@ -266,20 +318,20 @@ namespace
if (needle_cell == NULL)
continue;
- for (auto &conn : needle_cell->connections) {
+ for (auto &conn : needle_cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
- if (mapping.portMapping.count(conn.first) > 0 && sig2port.has(sigmap(sig))) {
- sig.expand();
- for (int i = 0; i < sig.width; i++)
- for (auto &port : sig2port.find(sig.chunks[i])) {
- RTLIL::SigSpec bitsig = haystack_cell->connections.at(mapping.portMapping[conn.first]).extract(i, 1);
- cell->connections.at(port.first).replace(port.second, bitsig);
+ 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->cells.erase(haystack_cell->name);
- delete haystack_cell;
+ haystack->remove(haystack_cell);
}
return cell;
@@ -315,6 +367,10 @@ struct ExtractPass : public Pass {
log(" use the modules in this file as reference. This option can be used\n");
log(" multiple times.\n");
log("\n");
+ log(" -map %%<design-name>\n");
+ log(" use the modules in this in-memory design as reference. This option can\n");
+ log(" be used multiple times.\n");
+ log("\n");
log(" -verbose\n");
log(" print debug output while analyzing\n");
log("\n");
@@ -347,6 +403,12 @@ struct ExtractPass : public Pass {
log(" -wire_attr <attribute_name>\n");
log(" Attributes on wires with the given name must match.\n");
log("\n");
+ log(" -ignore_parameters\n");
+ log(" Do not use parameters when matching cells.\n");
+ log("\n");
+ log(" -ignore_param <cell_type> <parameter_name>\n");
+ log(" Do not use this parameter when matching cells.\n");
+ log("\n");
log("This pass does not operate on modules with uprocessed processes in it.\n");
log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
log("\n");
@@ -494,6 +556,15 @@ struct ExtractPass : public Pass {
solver.wire_attr.insert(RTLIL::escape_id(args[++argidx]));
continue;
}
+ if (args[argidx] == "-ignore_parameters") {
+ solver.ignore_parameters = true;
+ continue;
+ }
+ if (args[argidx] == "-ignore_param" && argidx+2 < args.size()) {
+ solver.ignored_parameters.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2])));
+ argidx += 2;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -524,16 +595,33 @@ struct ExtractPass : public Pass {
if (!mine_mode)
{
map = new RTLIL::Design;
- for (auto &filename : map_filenames) {
- FILE *f = fopen(filename.c_str(), "rt");
- if (f == NULL)
- log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
- Frontend::frontend_call(map, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
- fclose(f);
-
- if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
- Pass::call(map, "proc");
- Pass::call(map, "opt_clean");
+ for (auto &filename : map_filenames)
+ {
+ if (filename.substr(0, 1) == "%")
+ {
+ if (!saved_designs.count(filename.substr(1))) {
+ delete map;
+ log_cmd_error("Can't saved design `%s'.\n", filename.c_str()+1);
+ }
+ for (auto mod : saved_designs.at(filename.substr(1))->modules())
+ if (!map->has(mod->name))
+ map->add(mod->clone());
+ }
+ else
+ {
+ std::ifstream f;
+ f.open(filename.c_str());
+ if (f.fail()) {
+ delete map;
+ log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
+ }
+ Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
+ f.close();
+
+ if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") {
+ Pass::call(map, "proc");
+ Pass::call(map, "opt_clean");
+ }
}
}
}
@@ -544,7 +632,7 @@ struct ExtractPass : public Pass {
log_header("Creating graphs for SubCircuit library.\n");
if (!mine_mode)
- for (auto &mod_it : map->modules) {
+ for (auto &mod_it : map->modules_) {
SubCircuit::Graph mod_graph;
std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first);
log("Creating needle graph %s.\n", graph_name.c_str());
@@ -555,7 +643,7 @@ struct ExtractPass : public Pass {
}
}
- for (auto &mod_it : design->modules) {
+ for (auto &mod_it : design->modules_) {
SubCircuit::Graph mod_graph;
std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first);
log("Creating haystack graph %s.\n", graph_name.c_str());
@@ -613,7 +701,7 @@ struct ExtractPass : public Pass {
log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits);
log(" primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name));
for (auto &node : result.nodes)
- log(" %s", id2cstr(node.nodeId));
+ log(" %s", RTLIL::unescape_id(node.nodeId).c_str());
log("\n");
for (auto &it : result.matchesPerGraph)
log(" matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second);
@@ -628,49 +716,44 @@ struct ExtractPass : public Pass {
cells.insert((RTLIL::Cell*)node.userData);
for (auto cell : cells)
- for (auto &conn : cell->connections) {
+ for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
- for (auto &chunk : sig.chunks)
+ for (auto &chunk : sig.chunks())
if (chunk.wire != NULL)
wires.insert(chunk.wire);
}
RTLIL::Module *newMod = new RTLIL::Module;
newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits);
- map->modules[newMod->name] = newMod;
+ map->add(newMod);
- int portCounter = 1;
for (auto wire : wires) {
- RTLIL::Wire *newWire = new RTLIL::Wire;
- newWire->name = wire->name;
- newWire->width = wire->width;
- newWire->port_id = portCounter++;
+ RTLIL::Wire *newWire = newMod->addWire(wire->name, wire->width);
newWire->port_input = true;
newWire->port_output = true;
- newMod->add(newWire);
}
+ newMod->fixup_ports();
+
for (auto cell : cells) {
- RTLIL::Cell *newCell = new RTLIL::Cell;
- newCell->name = cell->name;
- newCell->type = cell->type;
+ RTLIL::Cell *newCell = newMod->addCell(cell->name, cell->type);
newCell->parameters = cell->parameters;
- for (auto &conn : cell->connections) {
- RTLIL::SigSpec sig = sigmap(conn.second);
- for (auto &chunk : sig.chunks)
+ for (auto &conn : cell->connections()) {
+ std::vector<RTLIL::SigChunk> chunks = sigmap(conn.second);
+ for (auto &chunk : chunks)
if (chunk.wire != NULL)
- chunk.wire = newMod->wires.at(chunk.wire->name);
- newCell->connections[conn.first] = sig;
+ chunk.wire = newMod->wires_.at(chunk.wire->name);
+ newCell->setPort(conn.first, chunks);
}
- newMod->add(newCell);
}
}
- FILE *f = fopen(mine_outfile.c_str(), "wt");
- if (f == NULL)
+ std::ofstream f;
+ f.open(mine_outfile.c_str(), std::ofstream::trunc);
+ if (f.fail())
log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
- Backend::backend_call(map, f, mine_outfile, "ilang");
- fclose(f);
+ Backend::backend_call(map, &f, mine_outfile, "ilang");
+ f.close();
}
delete map;
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index bc5caa38c..784c4cf31 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -26,36 +26,28 @@ static std::string locell_celltype, locell_portname;
static bool singleton_mode;
static RTLIL::Module *module;
-static RTLIL::SigChunk last_hi, last_lo;
+static RTLIL::SigBit last_hi, last_lo;
void hilomap_worker(RTLIL::SigSpec &sig)
{
- sig.expand();
- for (auto &c : sig.chunks) {
- if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S1) && !hicell_celltype.empty()) {
- if (!singleton_mode || last_hi.width == 0) {
- last_hi = RTLIL::SigChunk(NEW_WIRE(module, 1));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(hicell_celltype);
- cell->connections[RTLIL::escape_id(hicell_portname)] = last_hi;
- module->add(cell);
+ for (auto &bit : sig) {
+ if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) {
+ if (!singleton_mode || last_hi == RTLIL::State::Sm) {
+ last_hi = module->addWire(NEW_ID);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype));
+ cell->setPort(RTLIL::escape_id(hicell_portname), last_hi);
}
- c = last_hi;
+ bit = last_hi;
}
- if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S0) && !locell_celltype.empty()) {
- if (!singleton_mode || last_lo.width == 0) {
- last_lo = RTLIL::SigChunk(NEW_WIRE(module, 1));
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(locell_celltype);
- cell->connections[RTLIL::escape_id(locell_portname)] = last_lo;
- module->add(cell);
+ if (bit == RTLIL::State::S0 && !locell_celltype.empty()) {
+ if (!singleton_mode || last_lo == RTLIL::State::Sm) {
+ last_lo = module->addWire(NEW_ID);
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype));
+ cell->setPort(RTLIL::escape_id(locell_portname), last_lo);
}
- c = last_lo;
+ bit = last_lo;
}
}
- sig.optimize();
}
struct HilomapPass : public Pass {
@@ -112,15 +104,15 @@ struct HilomapPass : public Pass {
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
module = it.second;
if (!design->selected(module))
continue;
- last_hi = RTLIL::SigChunk();
- last_lo = RTLIL::SigChunk();
+ last_hi = RTLIL::State::Sm;
+ last_lo = RTLIL::State::Sm;
module->rewrite_sigspecs(hilomap_worker);
}
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index b98214977..9cd23ce6f 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -57,6 +57,11 @@ struct IopadmapPass : public Pass {
log(" -nameparam <param_name>\n");
log(" Use the specified parameter to set the port name.\n");
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("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
@@ -66,6 +71,7 @@ struct IopadmapPass : public Pass {
std::string outpad_celltype, outpad_portname, outpad_portname2;
std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2;
std::string widthparam, nameparam;
+ bool flag_bits = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -97,18 +103,22 @@ struct IopadmapPass : public Pass {
nameparam = args[++argidx];
continue;
}
+ if (arg == "-bits") {
+ flag_bits = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto &it : design->modules)
+ for (auto &it : design->modules_)
{
RTLIL::Module *module = it.second;
- if (!design->selected(module))
+ if (!design->selected(module) || module->get_bool_attribute("\\blackbox"))
continue;
- for (auto &it2 : module->wires)
+ for (auto &it2 : module->wires_)
{
RTLIL::Wire *wire = it2.second;
@@ -146,31 +156,46 @@ struct IopadmapPass : public Pass {
} else
log_abort();
- if (wire->width != 1 && widthparam.empty()) {
- log("Don't map multi-bit port %s.%s: Missing option -widthparam.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
+ if (!flag_bits && wire->width != 1 && widthparam.empty()) {
+ log("Don't map multi-bit port %s.%s: Missing option -widthparam or -bits.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
continue;
}
log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str());
- RTLIL::Cell *cell = new RTLIL::Cell;
- cell->name = NEW_ID;
- cell->type = RTLIL::escape_id(celltype);
- cell->connections[RTLIL::escape_id(portname)] = RTLIL::SigSpec(wire);
+ RTLIL::Wire *new_wire = NULL;
if (!portname2.empty()) {
- RTLIL::Wire *new_wire = new RTLIL::Wire;
- *new_wire = *wire;
- wire->name = NEW_ID;
- module->wires[wire->name] = wire;
- module->wires[new_wire->name] = new_wire;
- cell->connections[RTLIL::escape_id(portname2)] = RTLIL::SigSpec(new_wire);
+ new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(new_wire, wire);
+ }
+
+ if (flag_bits)
+ {
+ for (int i = 0; i < wire->width; i++)
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i));
+ if (!portname2.empty())
+ cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire, i));
+ if (!widthparam.empty())
+ cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1);
+ if (!nameparam.empty())
+ cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i));
+ cell->attributes["\\keep"] = RTLIL::Const(1);
+ }
+ }
+ else
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire));
+ if (!portname2.empty())
+ cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire));
+ if (!widthparam.empty())
+ cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
+ if (!nameparam.empty())
+ cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
+ cell->attributes["\\keep"] = RTLIL::Const(1);
}
- if (!widthparam.empty())
- cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width);
- if (!nameparam.empty())
- cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name));
- cell->attributes["\\keep"] = RTLIL::Const(1);
- module->add(cell);
wire->port_id = 0;
wire->port_input = false;
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 8cbb8e2be..612fa1117 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -21,6 +21,10 @@
#include <stdlib.h>
#include <string.h>
+#include <istream>
+#include <fstream>
+#include <iostream>
+
#ifndef FILTERLIB
#include "kernel/log.h"
#endif
@@ -63,9 +67,10 @@ void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_o
}
fprintf(f, "%s%s", indent.c_str(), id.c_str());
- if (!args.empty()) {
+ if (!args.empty() || !children.empty()) {
+ fprintf(f, "(");
for (size_t i = 0; i < args.size(); i++)
- fprintf(f, "%s%s", i > 0 ? ", " : "(", args[i].c_str());
+ fprintf(f, "%s%s", i > 0 ? ", " : "", args[i].c_str());
fprintf(f, ")");
}
if (!value.empty())
@@ -84,19 +89,19 @@ int LibertyParser::lexer(std::string &str)
int c;
do {
- c = fgetc(f);
+ c = f.get();
} while (c == ' ' || c == '\t' || c == '\r');
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
while (1) {
- c = fgetc(f);
+ c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c;
else
break;
}
- ungetc(c, f);
+ f.unget();
// fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
return 'v';
}
@@ -104,7 +109,7 @@ int LibertyParser::lexer(std::string &str)
if (c == '"') {
str = c;
while (1) {
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
line++;
str += c;
@@ -116,34 +121,34 @@ int LibertyParser::lexer(std::string &str)
}
if (c == '/') {
- c = fgetc(f);
+ c = f.get();
if (c == '*') {
int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c;
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
line++;
}
return lexer(str);
} else if (c == '/') {
while (c > 0 && c != '\n')
- c = fgetc(f);
+ c = f.get();
line++;
return lexer(str);
}
- ungetc(c, f);
+ f.unget();
// fprintf(stderr, "LEX: char >>/<<\n");
return '/';
}
if (c == '\\') {
- c = fgetc(f);
+ c = f.get();
if (c == '\r')
- c = fgetc(f);
+ c = f.get();
if (c == '\n')
return lexer(str);
- ungetc(c, f);
+ f.unget();
return '\\';
}
@@ -607,16 +612,20 @@ int main(int argc, char **argv)
}
}
- FILE *f = stdin;
+ std::istream *f = &std::cin;
+
if (argc == 3) {
- f = fopen(argv[2], "r");
- if (f == NULL) {
+ std::ifstream *ff = new std::ifstream;
+ ff->open(argv[2]);
+ if (ff->fail()) {
+ delete ff;
fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
usage();
}
+ f = ff;
}
- LibertyParser parser(f);
+ LibertyParser parser(*f);
if (parser.ast) {
if (flag_verilogsim)
gen_verilogsim(parser.ast);
@@ -625,7 +634,7 @@ int main(int argc, char **argv)
}
if (argc == 3)
- fclose(f);
+ delete f;
return 0;
}
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index eff268bbb..247487424 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -41,10 +41,10 @@ namespace PASS_DFFLIBMAP
struct LibertyParser
{
- FILE *f;
+ std::istream &f;
int line;
LibertyAst *ast;
- LibertyParser(FILE *f) : f(f), line(1), ast(parse()) {}
+ LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
int lexer(std::string &str);
LibertyAst *parse();
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
new file mode 100644
index 000000000..2d625eefe
--- /dev/null
+++ b/passes/techmap/maccmap.cc
@@ -0,0 +1,394 @@
+/*
+ * 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/macc.h"
+
+extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false);
+
+struct MaccmapWorker
+{
+ std::vector<std::set<RTLIL::SigBit>> bits;
+ RTLIL::Module *module;
+ int width;
+
+ MaccmapWorker(RTLIL::Module *module, int width) : module(module), width(width)
+ {
+ bits.resize(width);
+ }
+
+ void add(RTLIL::SigBit bit, int position)
+ {
+ if (position >= width || bit == RTLIL::S0)
+ return;
+
+ if (bits.at(position).count(bit)) {
+ bits.at(position).erase(bit);
+ add(bit, position+1);
+ } else {
+ bits.at(position).insert(bit);
+ }
+ }
+
+ void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract)
+ {
+ a.extend(width, is_signed);
+
+ if (do_subtract) {
+ a = module->Not(NEW_ID, a);
+ add(RTLIL::S1, 0);
+ }
+
+ for (int i = 0; i < width; i++)
+ add(a[i], i);
+ }
+
+ void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract)
+ {
+ if (SIZE(a) < SIZE(b))
+ std::swap(a, b);
+
+ a.extend(width, is_signed);
+
+ if (SIZE(b) > width)
+ b.extend(width, is_signed);
+
+ for (int i = 0; i < SIZE(b); i++)
+ if (is_signed && i+1 == SIZE(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);
+ add({b[i], RTLIL::SigSpec(0, i)}, false, do_subtract);
+ }
+ else
+ {
+ add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract);
+ a = {a.extract(0, width-1), RTLIL::S0};
+ }
+ }
+
+ 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);
+
+ while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0)
+ start_index++;
+
+ while (start_index < stop_index && in1[stop_index-1] == RTLIL::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0)
+ stop_index--;
+
+ if (start_index == stop_index)
+ {
+ out1 = RTLIL::SigSpec(0, SIZE(in1));
+ out2 = RTLIL::SigSpec(0, SIZE(in1));
+ }
+ else
+ {
+ RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(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);
+ RTLIL::Wire *w1 = module->addWire(NEW_ID, width);
+ RTLIL::Wire *w2 = module->addWire(NEW_ID, width);
+
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$fa");
+ cell->setParam("\\WIDTH", width);
+ cell->setPort("\\A", in1);
+ cell->setPort("\\B", in2);
+ cell->setPort("\\C", in3);
+ cell->setPort("\\Y", w1);
+ cell->setPort("\\X", w2);
+
+ out1 = {out_zeros_msb, w1, out_zeros_lsb};
+ out2 = {out_zeros_msb, w2, out_zeros_lsb};
+ }
+ }
+
+ int tree_bit_slots(int n)
+ {
+ #if 0
+ int retval = 1;
+ while (n > 2) {
+ retval += n / 3;
+ n = 2*(n / 3) + (n % 3);
+ }
+ return retval;
+ #else
+ return std::max(n - 1, 0);
+ #endif
+ }
+
+ RTLIL::SigSpec synth()
+ {
+ std::vector<RTLIL::SigSpec> summands;
+ std::vector<RTLIL::SigBit> tree_sum_bits;
+ int unique_tree_bits = 0;
+ int count_tree_words = 0;
+
+ while (1)
+ {
+ RTLIL::SigSpec summand(0, width);
+ bool got_data_bits = false;
+
+ for (int i = 0; i < width; i++)
+ if (!bits.at(i).empty()) {
+ auto it = bits.at(i).begin();
+ summand[i] = *it;
+ bits.at(i).erase(it);
+ got_data_bits = true;
+ }
+
+ if (!got_data_bits)
+ break;
+
+ summands.push_back(summand);
+
+ while (1)
+ {
+ int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(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));
+ max_position = i;
+ }
+
+ if (max_depth == 0 || max_position > 4)
+ break;
+
+ int required_bits = 0;
+ for (int i = 0; i <= max_position; i++)
+ if (SIZE(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) {
+ auto it = bits.at(i).begin();
+ RTLIL::SigBit bit = *it;
+ for (int k = 0; k < (1 << i); k++, free_bit_slots--)
+ tree_sum_bits.push_back(bit);
+ bits.at(i).erase(it);
+ unique_tree_bits++;
+ }
+
+ count_tree_words++;
+ }
+ }
+
+ 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);
+
+ if (SIZE(summands) == 0) {
+ log_assert(tree_sum_bits.empty());
+ return RTLIL::SigSpec(0, width);
+ }
+
+ if (SIZE(summands) == 1) {
+ log_assert(tree_sum_bits.empty());
+ return summands.front();
+ }
+
+ while (SIZE(summands) > 2)
+ {
+ std::vector<RTLIL::SigSpec> new_summands;
+ for (int i = 0; i < SIZE(summands); i += 3)
+ if (i+2 < SIZE(summands)) {
+ RTLIL::SigSpec in1 = summands[i];
+ RTLIL::SigSpec in2 = summands[i+1];
+ RTLIL::SigSpec in3 = summands[i+2];
+ RTLIL::SigSpec out1, out2;
+ fulladd(in1, in2, in3, out1, out2);
+ RTLIL::SigBit extra_bit = RTLIL::S0;
+ if (!tree_sum_bits.empty()) {
+ extra_bit = tree_sum_bits.back();
+ tree_sum_bits.pop_back();
+ }
+ new_summands.push_back(out1);
+ new_summands.push_back({out2.extract(0, width-1), extra_bit});
+ } else {
+ new_summands.push_back(summands[i]);
+ i -= 2;
+ }
+ summands.swap(new_summands);
+ }
+
+
+ RTLIL::Cell *c = module->addCell(NEW_ID, "$alu");
+ c->setPort("\\A", summands.front());
+ c->setPort("\\B", summands.back());
+ c->setPort("\\CI", RTLIL::S0);
+ c->setPort("\\BI", RTLIL::S0);
+ c->setPort("\\Y", module->addWire(NEW_ID, width));
+ c->setPort("\\X", module->addWire(NEW_ID, width));
+ c->setPort("\\CO", module->addWire(NEW_ID, width));
+ c->fixup_parameters();
+
+ if (!tree_sum_bits.empty()) {
+ c->setPort("\\CI", tree_sum_bits.back());
+ tree_sum_bits.pop_back();
+ }
+ log_assert(tree_sum_bits.empty());
+
+ return c->getPort("\\Y");
+ }
+};
+
+void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
+{
+ int width = SIZE(cell->getPort("\\Y"));
+
+ Macc macc;
+ macc.from_cell(cell);
+
+ RTLIL::SigSpec all_input_bits;
+ all_input_bits.append(cell->getPort("\\A"));
+ all_input_bits.append(cell->getPort("\\B"));
+
+ if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) {
+ module->connect(cell->getPort("\\Y"), RTLIL::SigSpec(RTLIL::Sx, width));
+ return;
+ }
+
+ for (auto &port : macc.ports)
+ if (SIZE(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");
+ 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");
+
+ if (SIZE(macc.bit_ports) != 0)
+ log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports));
+
+ if (unmap)
+ {
+ typedef std::pair<RTLIL::SigSpec, bool> summand_t;
+ std::vector<summand_t> summands;
+
+ for (auto &port : macc.ports) {
+ summand_t this_summand;
+ if (SIZE(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) {
+ this_summand.first = module->addWire(NEW_ID, width);
+ module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
+ } else {
+ this_summand.first = port.in_a;
+ }
+ this_summand.second = port.do_subtract;
+ summands.push_back(this_summand);
+ }
+
+ for (auto &bit : macc.bit_ports)
+ summands.push_back(summand_t(bit, false));
+
+ if (SIZE(summands) == 0)
+ summands.push_back(summand_t(RTLIL::SigSpec(0, width), false));
+
+ while (SIZE(summands) > 1)
+ {
+ std::vector<summand_t> new_summands;
+ for (int i = 0; i < SIZE(summands); i += 2) {
+ if (i+1 < SIZE(summands)) {
+ summand_t this_summand;
+ this_summand.first = module->addWire(NEW_ID, width);
+ this_summand.second = summands[i].second && summands[i+1].second;
+ if (summands[i].second == summands[i+1].second)
+ module->addAdd(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first);
+ else if (summands[i].second)
+ module->addSub(NEW_ID, summands[i+1].first, summands[i].first, this_summand.first);
+ else if (summands[i+1].second)
+ module->addSub(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first);
+ else
+ log_abort();
+ new_summands.push_back(this_summand);
+ } else
+ new_summands.push_back(summands[i]);
+ }
+ summands.swap(new_summands);
+ }
+
+ if (summands.front().second)
+ module->addNeg(NEW_ID, summands.front().first, cell->getPort("\\Y"));
+ else
+ module->connect(cell->getPort("\\Y"), summands.front().first);
+ }
+ else
+ {
+ MaccmapWorker worker(module, width);
+
+ for (auto &port : macc.ports)
+ if (SIZE(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);
+
+ for (auto &bit : macc.bit_ports)
+ worker.add(bit, 0);
+
+ module->connect(cell->getPort("\\Y"), worker.synth());
+ }
+}
+
+struct MaccmapPass : public Pass {
+ MaccmapPass() : Pass("maccmap", "mapping macc cells") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" maccmap [-unmap] [selection]\n");
+ log("\n");
+ log("This pass maps $macc cells to yosys gate primitives. When the -unmap option is\n");
+ log("used then the $macc cell is mapped to $and, $sub, etc. cells instead.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool unmap_mode = false;
+
+ log_header("Executing MACCMAP pass (map $macc cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-unmap") {
+ unmap_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto mod : design->selected_modules())
+ for (auto cell : mod->selected_cells())
+ if (cell->type == "$macc") {
+ log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
+ maccmap(mod, cell, unmap_mode);
+ mod->remove(cell);
+ }
+ }
+} MaccmapPass;
+
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index e67b1e055..f8d5d4584 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -21,84 +21,52 @@
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
-extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
- sig_a.expand();
+ sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ for (int i = 0; i < SIZE(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)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
-
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
-}
-
-static void simplemap_bu0(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool());
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
+ module->connect(RTLIL::SigSig(sig_y, sig_a));
}
static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\Y_WIDTH").as_int();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
- sig_a.expand();
-
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
- sig_b.extend_u0(width, cell->parameters.at("\\B_SIGNED").as_bool());
- sig_b.expand();
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
+ 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());
if (cell->type == "$xnor")
{
- RTLIL::SigSpec sig_t = module->new_wire(width, NEW_ID);
- sig_t.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_t.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y));
+
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_t[i]);
+ gate->setPort("\\Y", sig_y[i]);
}
sig_y = sig_t;
@@ -111,38 +79,33 @@ 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 < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_b.chunks.at(i);
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ for (int i = 0; i < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_b[i]);
+ gate->setPort("\\Y", sig_y[i]);
}
}
static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.expand();
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
-
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_a.width == 0) {
- if (cell->type == "$reduce_and") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
- if (cell->type == "$reduce_or") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
- if (cell->type == "$reduce_xor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
- if (cell->type == "$reduce_xnor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width)));
- if (cell->type == "$reduce_bool") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width)));
+ if (sig_a.size() == 0) {
+ if (cell->type == "$reduce_and") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == "$reduce_or") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == "$reduce_xor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
+ if (cell->type == "$reduce_xnor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size())));
+ if (cell->type == "$reduce_bool") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
return;
}
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
@@ -154,122 +117,106 @@ static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$reduce_bool") gate_type = "$_OR_";
log_assert(!gate_type.empty());
- RTLIL::SigSpec *last_output = NULL;
+ RTLIL::Cell *last_output_cell = NULL;
- while (sig_a.width > 1)
+ while (sig_a.size() > 1)
{
- RTLIL::SigSpec sig_t = module->new_wire(sig_a.width / 2, NEW_ID);
- sig_t.expand();
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2);
- for (int i = 0; i < sig_a.width; i += 2)
+ for (int i = 0; i < sig_a.size(); i += 2)
{
- if (i+1 == sig_a.width) {
- sig_t.append(sig_a.chunks.at(i));
+ if (i+1 == sig_a.size()) {
+ sig_t.append(sig_a[i]);
continue;
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_a.chunks.at(i+1);
- gate->connections["\\Y"] = sig_t.chunks.at(i/2);
- last_output = &gate->connections["\\Y"];
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_a[i+1]);
+ gate->setPort("\\Y", sig_t[i/2]);
+ last_output_cell = gate;
}
sig_a = sig_t;
}
if (cell->type == "$reduce_xnor") {
- RTLIL::SigSpec sig_t = module->new_wire(1, NEW_ID);
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a;
- gate->connections["\\Y"] = sig_t;
- last_output = &gate->connections["\\Y"];
- module->add(gate);
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\Y", sig_t);
+ last_output_cell = gate;
sig_a = sig_t;
}
- if (last_output == NULL) {
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
+ if (last_output_cell == NULL) {
+ module->connect(RTLIL::SigSig(sig_y, sig_a));
} else {
- *last_output = sig_y;
+ last_output_cell->setPort("\\Y", sig_y);
}
}
static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
{
- sig.expand();
-
- while (sig.width > 1)
+ while (sig.size() > 1)
{
- RTLIL::SigSpec sig_t = module->new_wire(sig.width / 2, NEW_ID);
- sig_t.expand();
+ RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2);
- for (int i = 0; i < sig.width; i += 2)
+ for (int i = 0; i < sig.size(); i += 2)
{
- if (i+1 == sig.width) {
- sig_t.append(sig.chunks.at(i));
+ if (i+1 == sig.size()) {
+ sig_t.append(sig[i]);
continue;
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_OR_";
- gate->connections["\\A"] = sig.chunks.at(i);
- gate->connections["\\B"] = sig.chunks.at(i+1);
- gate->connections["\\Y"] = sig_t.chunks.at(i/2);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_OR_");
+ gate->setPort("\\A", sig[i]);
+ gate->setPort("\\B", sig[i+1]);
+ gate->setPort("\\Y", sig_t[i/2]);
}
sig = sig_t;
}
- if (sig.width == 0)
+ if (sig.size() == 0)
sig = RTLIL::SigSpec(0, 1);
}
static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_INV_";
- gate->connections["\\A"] = sig_a;
- gate->connections["\\Y"] = sig_y;
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_");
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\Y", sig_y);
}
static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
logic_reduce(module, sig_a);
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
+ RTLIL::SigSpec sig_b = cell->getPort("\\B");
logic_reduce(module, sig_b);
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
- if (sig_y.width == 0)
+ if (sig_y.size() == 0)
return;
- if (sig_y.width > 1) {
- module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1)));
+ if (sig_y.size() > 1) {
+ module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1)));
sig_y = sig_y.extract(0, 1);
}
@@ -278,54 +225,41 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
if (cell->type == "$logic_or") gate_type = "$_OR_";
log_assert(!gate_type.empty());
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\A"] = sig_a;
- gate->connections["\\B"] = sig_b;
- gate->connections["\\Y"] = sig_y;
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\A", sig_a);
+ gate->setPort("\\B", sig_b);
+ gate->setPort("\\Y", sig_y);
}
static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
{
- int width = cell->parameters.at("\\WIDTH").as_int();
-
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- sig_a.expand();
-
- RTLIL::SigSpec sig_b = cell->connections.at("\\B");
- sig_b.expand();
-
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- sig_y.expand();
-
- for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = "$_MUX_";
- gate->connections["\\A"] = sig_a.chunks.at(i);
- gate->connections["\\B"] = sig_b.chunks.at(i);
- gate->connections["\\S"] = cell->connections.at("\\S");
- gate->connections["\\Y"] = sig_y.chunks.at(i);
- module->add(gate);
+ 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 < SIZE(sig_y); i++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_");
+ gate->setPort("\\A", sig_a[i]);
+ gate->setPort("\\B", sig_b[i]);
+ gate->setPort("\\S", cell->getPort("\\S"));
+ gate->setPort("\\Y", sig_y[i]);
}
}
static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
- RTLIL::SigSpec sig_a = cell->connections.at("\\A");
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.width)));
+ RTLIL::SigSpec sig_a = cell->getPort("\\A");
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size())));
}
static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
{
- RTLIL::SigSpec sig_ab = cell->connections.at("\\A");
- sig_ab.append(cell->connections.at("\\B"));
- RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
- module->connections.push_back(RTLIL::SigSig(sig_y, sig_ab));
+ RTLIL::SigSpec sig_ab = cell->getPort("\\A");
+ sig_ab.append(cell->getPort("\\B"));
+ RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+ module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
@@ -334,25 +268,17 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
- sig_s.expand();
-
- RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
- sig_r.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_s = cell->getPort("\\SET");
+ RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\S"] = sig_s.chunks.at(i);
- gate->connections["\\R"] = sig_r.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\S", sig_s[i]);
+ gate->setPort("\\R", sig_r[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -361,24 +287,17 @@ static 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';
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_DFF_%c_", clk_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -389,32 +308,21 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
-
- RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
- sig_s.expand();
-
- RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
- sig_r.expand();
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_s = cell->getPort("\\SET");
+ RTLIL::SigSpec sig_r = cell->getPort("\\CLR");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\S"] = sig_s.chunks.at(i);
- gate->connections["\\R"] = sig_r.chunks.at(i);
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\S", sig_s[i]);
+ gate->setPort("\\R", sig_r[i]);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -428,27 +336,20 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
while (int(rst_val.size()) < width)
rst_val.push_back(RTLIL::State::S0);
- RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
- RTLIL::SigSpec sig_rst = cell->connections.at("\\ARST");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ RTLIL::SigSpec sig_clk = cell->getPort("\\CLK");
+ RTLIL::SigSpec sig_rst = cell->getPort("\\ARST");
+ RTLIL::SigSpec sig_d = cell->getPort("\\D");
+ RTLIL::SigSpec sig_q = cell->getPort("\\Q");
std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0;
- gate->connections["\\C"] = sig_clk;
- gate->connections["\\R"] = sig_rst;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0);
+ gate->setPort("\\C", sig_clk);
+ gate->setPort("\\R", sig_rst);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
@@ -457,32 +358,24 @@ static 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';
- RTLIL::SigSpec sig_en = cell->connections.at("\\EN");
-
- RTLIL::SigSpec sig_d = cell->connections.at("\\D");
- sig_d.expand();
-
- RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
- sig_q.expand();
+ 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("$_DLATCH_%c_", en_pol);
for (int i = 0; i < width; i++) {
- RTLIL::Cell *gate = new RTLIL::Cell;
- gate->name = NEW_ID;
- gate->type = gate_type;
- gate->connections["\\E"] = sig_en;
- gate->connections["\\D"] = sig_d.chunks.at(i);
- gate->connections["\\Q"] = sig_q.chunks.at(i);
- module->add(gate);
+ RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type);
+ gate->setPort("\\E", sig_en);
+ gate->setPort("\\D", sig_d[i]);
+ gate->setPort("\\Q", sig_q[i]);
}
}
-void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
+void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
{
mappers["$not"] = simplemap_not;
mappers["$pos"] = simplemap_pos;
- mappers["$bu0"] = simplemap_bu0;
mappers["$and"] = simplemap_bitop;
mappers["$or"] = simplemap_bitop;
mappers["$xor"] = simplemap_bitop;
@@ -516,7 +409,7 @@ struct SimplemapPass : public Pass {
log("This pass maps a small selection of simple coarse-grain cells to yosys gate\n");
log("primitives. The following internal cell types are mapped by this pass:\n");
log("\n");
- log(" $not, $pos, $bu0, $and, $or, $xor, $xnor\n");
+ log(" $not, $pos, $and, $or, $xor, $xnor\n");
log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
log(" $logic_not, $logic_and, $logic_or, $mux\n");
log(" $sr, $dff, $dffsr, $adff, $dlatch\n");
@@ -527,25 +420,21 @@ struct SimplemapPass : public Pass {
log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
- std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
+ std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
simplemap_get_mappers(mappers);
- for (auto &mod_it : design->modules) {
- if (!design->selected(mod_it.second))
+ for (auto mod : design->modules()) {
+ if (!design->selected(mod))
continue;
- std::vector<RTLIL::Cell*> delete_cells;
- for (auto &cell_it : mod_it.second->cells) {
- if (mappers.count(cell_it.second->type) == 0)
+ std::vector<RTLIL::Cell*> cells = mod->cells();
+ for (auto cell : cells) {
+ if (mappers.count(cell->type) == 0)
continue;
- if (!design->selected(mod_it.second, cell_it.second))
+ if (!design->selected(mod, cell))
continue;
- log("Mapping %s.%s (%s).\n", RTLIL::id2cstr(mod_it.first), RTLIL::id2cstr(cell_it.first), RTLIL::id2cstr(cell_it.second->type));
- mappers.at(cell_it.second->type)(mod_it.second, cell_it.second);
- delete_cells.push_back(cell_it.second);
- }
- for (auto &it : delete_cells) {
- mod_it.second->cells.erase(it->name);
- delete it;
+ log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type));
+ mappers.at(cell->type)(mod, cell);
+ mod->remove(cell);
}
}
}
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index eeeebd111..ed466faa1 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -17,18 +17,22 @@
*
*/
-#include "kernel/register.h"
+#include "kernel/yosys.h"
+#include "kernel/utils.h"
#include "kernel/sigtools.h"
-#include "kernel/log.h"
+#include "libs/sha1/sha1.h"
+
#include <stdlib.h>
-#include <assert.h>
#include <stdio.h>
#include <string.h>
-#include "passes/techmap/stdcells.inc"
+#include "passes/techmap/techmap.inc"
// see simplemap.cc
-extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
+
+// 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)
{
@@ -40,327 +44,712 @@ static void apply_prefix(std::string prefix, std::string &id)
static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module)
{
- for (size_t i = 0; i < sig.chunks.size(); i++) {
- if (sig.chunks[i].wire == NULL)
- continue;
- std::string wire_name = sig.chunks[i].wire->name;
- apply_prefix(prefix, wire_name);
- assert(module->wires.count(wire_name) > 0);
- sig.chunks[i].wire = module->wires[wire_name];
- }
+ std::vector<RTLIL::SigChunk> chunks = sig;
+ for (auto &chunk : chunks)
+ if (chunk.wire != NULL) {
+ std::string wire_name = chunk.wire->name.str();
+ apply_prefix(prefix, wire_name);
+ log_assert(module->wires_.count(wire_name) > 0);
+ chunk.wire = module->wires_[wire_name];
+ }
+ sig = chunks;
}
-std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
-std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
-std::map<RTLIL::Module*, bool> techmap_do_cache;
-
-struct TechmapWireData {
- RTLIL::Wire *wire;
- RTLIL::SigSpec value;
-};
+struct TechmapWorker
+{
+ std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers;
+ std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache;
+ std::map<RTLIL::Module*, bool> techmap_do_cache;
+ std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue;
-typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
+ struct TechmapWireData {
+ RTLIL::Wire *wire;
+ RTLIL::SigSpec value;
+ };
-static TechmapWires techmap_find_special_wires(RTLIL::Module *module)
-{
- TechmapWires result;
+ typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires;
- if (module == NULL)
- return result;
+ bool extern_mode;
+ bool assert_mode;
+ bool flatten_mode;
+ bool recursive_mode;
+ bool autoproc_mode;
- for (auto &it : module->wires) {
- const char *p = it.first.c_str();
- if (*p == '$')
- continue;
-
- const char *q = strrchr(p+1, '.');
- p = q ? q : p+1;
-
- if (!strncmp(p, "_TECHMAP_", 9)) {
- TechmapWireData record;
- record.wire = it.second;
- record.value = it.second;
- result[p].push_back(record);
- it.second->attributes["\\keep"] = RTLIL::Const(1);
- it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
- }
+ TechmapWorker()
+ {
+ extern_mode = false;
+ assert_mode = false;
+ flatten_mode = false;
+ recursive_mode = false;
+ autoproc_mode = false;
}
- if (!result.empty()) {
- SigMap sigmap(module);
- for (auto &it1 : result)
- for (auto &it2 : it1.second)
- sigmap.apply(it2.value);
+ std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
+ {
+ std::string constmap_info;
+ std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map;
+
+ for (auto conn : cell->connections())
+ for (int i = 0; i < SIZE(conn.second); i++) {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ if (bit.wire == nullptr) {
+ if (verbose)
+ log(" Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit));
+ constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data);
+ } else if (connbits_map.count(bit)) {
+ if (verbose)
+ log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first),
+ 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);
+ }
+
+ return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str());
}
- return result;
-}
+ TechmapWires techmap_find_special_wires(RTLIL::Module *module)
+ {
+ TechmapWires result;
-static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, bool flatten_mode)
-{
- log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name));
-
- if (tpl->memories.size() != 0)
- log_error("Technology map yielded memories -> this is not supported.\n");
-
- if (tpl->processes.size() != 0)
- log_error("Technology map yielded processes -> this is not supported.\n");
-
- std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
-
- for (auto &it : tpl->wires) {
- if (it.second->port_id > 0)
- positional_ports[stringf("$%d", it.second->port_id)] = it.first;
- RTLIL::Wire *w = new RTLIL::Wire(*it.second);
- apply_prefix(cell->name, w->name);
- w->port_input = false;
- w->port_output = false;
- w->port_id = 0;
- if (it.second->get_bool_attribute("\\_techmap_special_"))
- w->attributes.clear();
- module->wires[w->name] = w;
- design->select(module, w);
- }
+ if (module == NULL)
+ return result;
+
+ for (auto &it : module->wires_) {
+ const char *p = it.first.c_str();
+ if (*p == '$')
+ continue;
- SigMap port_signal_map;
+ const char *q = strrchr(p+1, '.');
+ p = q ? q : p+1;
- for (auto &it : cell->connections) {
- RTLIL::IdString portname = it.first;
- if (positional_ports.count(portname) > 0)
- portname = positional_ports.at(portname);
- if (tpl->wires.count(portname) == 0 || tpl->wires.at(portname)->port_id == 0) {
- if (portname.substr(0, 1) == "$")
- log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
- continue;
+ if (!strncmp(p, "_TECHMAP_", 9)) {
+ TechmapWireData record;
+ record.wire = it.second;
+ record.value = it.second;
+ result[p].push_back(record);
+ it.second->attributes["\\keep"] = RTLIL::Const(1);
+ it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1);
+ }
}
- RTLIL::Wire *w = tpl->wires.at(portname);
- RTLIL::SigSig c;
- if (w->port_output) {
- c.first = it.second;
- c.second = RTLIL::SigSpec(w);
- apply_prefix(cell->name, c.second, module);
- } else {
- c.first = RTLIL::SigSpec(w);
- c.second = it.second;
- apply_prefix(cell->name, c.first, module);
+
+ if (!result.empty()) {
+ SigMap sigmap(module);
+ for (auto &it1 : result)
+ for (auto &it2 : it1.second)
+ sigmap.apply(it2.value);
}
- if (c.second.width > c.first.width)
- c.second.remove(c.first.width, c.second.width - c.first.width);
- if (c.second.width < c.first.width)
- c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width));
- assert(c.first.width == c.second.width);
-#if 0
- // more conservative approach:
- // connect internal and external wires
- module->connections.push_back(c);
-#else
- // approach that yields nicer outputs:
- // replace internal wires that are connected to external wires
- if (w->port_output)
- port_signal_map.add(c.second, c.first);
- else
- port_signal_map.add(c.first, c.second);
-#endif
+
+ return result;
}
- for (auto &it : tpl->cells) {
- RTLIL::Cell *c = new RTLIL::Cell(*it.second);
- if (!flatten_mode && c->type.substr(0, 2) == "\\$")
- c->type = c->type.substr(1);
- apply_prefix(cell->name, c->name);
- for (auto &it2 : c->connections) {
- apply_prefix(cell->name, it2.second, module);
- port_signal_map.apply(it2.second);
+ 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);
+ } else
+ log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n");
}
- module->cells[c->name] = c;
- design->select(module, c);
- }
- for (auto &it : tpl->connections) {
- RTLIL::SigSig c = it;
- apply_prefix(cell->name, c.first, module);
- apply_prefix(cell->name, c.second, module);
- port_signal_map.apply(c.first);
- port_signal_map.apply(c.second);
- module->connections.push_back(c);
- }
+ std::string orig_cell_name;
+ if (!flatten_mode)
+ for (auto &it : tpl->cells_)
+ if (it.first == "\\_TECHMAP_REPLACE_") {
+ orig_cell_name = cell->name.str();
+ module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
+ break;
+ }
- module->cells.erase(cell->name);
- delete cell;
-}
+ std::map<RTLIL::IdString, RTLIL::IdString> positional_ports;
+
+ for (auto &it : tpl->wires_) {
+ if (it.second->port_id > 0)
+ positional_ports[stringf("$%d", it.second->port_id)] = it.first;
+ std::string w_name = it.second->name.str();
+ apply_prefix(cell->name.str(), w_name);
+ RTLIL::Wire *w = module->addWire(w_name, it.second);
+ w->port_input = false;
+ w->port_output = false;
+ w->port_id = 0;
+ if (it.second->get_bool_attribute("\\_techmap_special_"))
+ w->attributes.clear();
+ design->select(module, w);
+ }
-static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
- const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap, bool flatten_mode)
-{
- if (!design->selected(module))
- return false;
+ SigMap port_signal_map;
+
+ for (auto &it : cell->connections()) {
+ RTLIL::IdString portname = it.first;
+ if (positional_ports.count(portname) > 0)
+ portname = positional_ports.at(portname);
+ if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) {
+ if (portname.substr(0, 1) == "$")
+ log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
+ continue;
+ }
+ RTLIL::Wire *w = tpl->wires_.at(portname);
+ RTLIL::SigSig c;
+ if (w->port_output) {
+ c.first = it.second;
+ c.second = RTLIL::SigSpec(w);
+ apply_prefix(cell->name.str(), c.second, module);
+ } else {
+ c.first = RTLIL::SigSpec(w);
+ c.second = it.second;
+ apply_prefix(cell->name.str(), c.first, module);
+ }
+ if (c.second.size() > c.first.size())
+ c.second.remove(c.first.size(), c.second.size() - c.first.size());
+ if (c.second.size() < c.first.size())
+ c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size()));
+ log_assert(c.first.size() == c.second.size());
+ if (flatten_mode) {
+ // more conservative approach:
+ // connect internal and external wires
+ module->connect(c);
+ } else {
+ // approach that yields nicer outputs:
+ // replace internal wires that are connected to external wires
+ if (w->port_output)
+ port_signal_map.add(c.second, c.first);
+ else
+ port_signal_map.add(c.first, c.second);
+ }
+ }
+
+ for (auto &it : tpl->cells_)
+ {
+ std::string c_name = it.second->name.str();
+
+ if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_")
+ c_name = orig_cell_name;
+ else
+ apply_prefix(cell->name.str(), c_name);
+
+ RTLIL::Cell *c = module->addCell(c_name, it.second);
+ design->select(module, c);
+
+ if (!flatten_mode && c->type.substr(0, 2) == "\\$")
+ c->type = c->type.substr(1);
- bool log_continue = false;
- bool did_something = false;
- std::vector<std::string> cell_names;
+ for (auto &it2 : c->connections_) {
+ apply_prefix(cell->name.str(), it2.second, module);
+ port_signal_map.apply(it2.second);
+ }
+ }
+
+ for (auto &it : tpl->connections()) {
+ RTLIL::SigSig c = it;
+ apply_prefix(cell->name.str(), c.first, module);
+ apply_prefix(cell->name.str(), c.second, module);
+ port_signal_map.apply(c.first);
+ port_signal_map.apply(c.second);
+ module->connect(c);
+ }
- for (auto &cell_it : module->cells)
- cell_names.push_back(cell_it.first);
+ module->remove(cell);
+ }
- for (auto &cell_name : cell_names)
+ bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells,
+ const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion)
{
- if (module->cells.count(cell_name) == 0)
- continue;
+ std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
+
+ if (!design->selected(module))
+ return false;
- RTLIL::Cell *cell = module->cells[cell_name];
+ bool log_continue = false;
+ bool did_something = false;
- if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
- continue;
+ SigMap sigmap(module);
- if (celltypeMap.count(cell->type) == 0)
- continue;
+ 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;
- for (auto &tpl_name : celltypeMap.at(cell->type))
+ for (auto cell : module->cells())
{
- std::string derived_name = tpl_name;
- RTLIL::Module *tpl = map->modules[tpl_name];
- std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+ if (!design->selected(module, cell) || handled_cells.count(cell) > 0)
+ continue;
- if (!flatten_mode)
- {
- if (tpl->get_bool_attribute("\\techmap_simplemap")) {
- log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
- if (simplemap_mappers.count(cell->type) == 0)
- log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
- simplemap_mappers.at(cell->type)(module, cell);
- module->cells.erase(cell->name);
- delete cell;
- cell = NULL;
- did_something = true;
- break;
- }
+ std::string cell_type = cell->type.str();
+ if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ cell_type = cell_type.substr(1);
- for (auto conn : cell->connections) {
- if (conn.first.substr(0, 1) == "$")
- continue;
- if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0)
- continue;
- if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
- goto next_tpl;
- parameters[conn.first] = conn.second.as_const();
- }
+ if (celltypeMap.count(cell_type) == 0) {
+ if (assert_mode && cell_type.back() != '_')
+ log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type));
+ continue;
+ }
- if (0) {
- next_tpl:
- continue;
- }
+ for (auto &conn : cell->connections())
+ {
+ RTLIL::SigSpec sig = sigmap(conn.second);
+ sig.remove_const();
- if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
- parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
- }
+ if (SIZE(sig) == 0)
+ continue;
- std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
- if (techmap_cache.count(key) > 0) {
- tpl = techmap_cache[key];
- } else {
- if (cell->parameters.size() != 0) {
- derived_name = tpl->derive(map, parameters);
- tpl = map->modules[derived_name];
- log_continue = true;
+ for (auto &tpl_name : celltypeMap.at(cell_type)) {
+ RTLIL::Module *tpl = map->modules_[tpl_name];
+ RTLIL::Wire *port = tpl->wire(conn.first);
+ if (port && port->port_input)
+ cell_to_inbit[cell].insert(sig.begin(), sig.end());
+ if (port && port->port_output)
+ for (auto &bit : sig)
+ outbit_to_cell[bit].insert(cell);
}
- techmap_cache[key] = tpl;
}
- if (flatten_mode)
- techmap_do_cache[tpl] = true;
+ cells.node(cell);
+ }
+
+ for (auto &it_right : cell_to_inbit)
+ for (auto &it_sigbit : it_right.second)
+ for (auto &it_left : outbit_to_cell[it_sigbit])
+ cells.edge(it_left, it_right.first);
+
+ cells.sort();
+
+ for (auto cell : cells.sorted)
+ {
+ log_assert(handled_cells.count(cell) == 0);
+ log_assert(cell == module->cell(cell->name));
+ bool mapped_cell = false;
+
+ std::string cell_type = cell->type.str();
+ if (in_recursion && cell_type.substr(0, 2) == "\\$")
+ cell_type = cell_type.substr(1);
- if (techmap_do_cache.count(tpl) == 0)
+ for (auto &tpl_name : celltypeMap.at(cell_type))
{
- bool keep_running = true;
- techmap_do_cache[tpl] = true;
+ RTLIL::IdString derived_name = tpl_name;
+ RTLIL::Module *tpl = map->modules_[tpl_name];
+ std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters;
+
+ if (tpl->get_bool_attribute("\\blackbox"))
+ continue;
- while (keep_running)
+ if (!flatten_mode)
{
- TechmapWires twd = techmap_find_special_wires(tpl);
- keep_running = false;
-
- for (auto &it : twd["_TECHMAP_FAIL_"]) {
- RTLIL::SigSpec value = it.value;
- if (value.is_fully_const() && value.as_bool()) {
- log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
- derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
- techmap_do_cache[tpl] = false;
+ std::string extmapper_name;
+
+ if (tpl->get_bool_attribute("\\techmap_simplemap"))
+ extmapper_name = "simplemap";
+
+ if (tpl->get_bool_attribute("\\techmap_maccmap"))
+ extmapper_name = "maccmap";
+
+ if (tpl->attributes.count("\\techmap_wrap"))
+ extmapper_name = "wrap";
+
+ if (!extmapper_name.empty())
+ {
+ cell->type = cell_type;
+
+ if ((extern_mode && !in_recursion) || extmapper_name == "wrap")
+ {
+ std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type));
+
+ for (auto &c : cell->parameters)
+ m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second));
+
+ if (extmapper_name == "wrap")
+ m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string());
+
+ RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design;
+ RTLIL::Module *extmapper_module = extmapper_design->module(m_name);
+
+ if (extmapper_module == nullptr)
+ {
+ extmapper_module = extmapper_design->addModule(m_name);
+ RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell);
+
+ int port_counter = 1;
+ for (auto &c : extmapper_cell->connections_) {
+ RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second));
+ if (w->name == "\\Y" || w->name == "\\Q")
+ w->port_output = true;
+ else
+ w->port_input = true;
+ w->port_id = port_counter++;
+ c.second = w;
+ }
+
+ extmapper_module->fixup_ports();
+ extmapper_module->check();
+
+ if (extmapper_name == "simplemap") {
+ log("Creating %s with simplemap.\n", log_id(extmapper_module));
+ if (simplemap_mappers.count(extmapper_cell->type) == 0)
+ log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type));
+ simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell);
+ extmapper_module->remove(extmapper_cell);
+ }
+
+ if (extmapper_name == "maccmap") {
+ log("Creating %s with maccmap.\n", log_id(extmapper_module));
+ if (extmapper_cell->type != "$macc")
+ log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type));
+ maccmap(extmapper_module, extmapper_cell);
+ extmapper_module->remove(extmapper_cell);
+ }
+
+ if (extmapper_name == "wrap") {
+ std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
+ log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
+ Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
+ log_continue = true;
+ }
+ }
+
+ cell->type = extmapper_module->name;
+ cell->parameters.clear();
+
+ if (!extern_mode || in_recursion) {
+ tpl = extmapper_module;
+ goto use_wrapper_tpl;
+ }
+
+ log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
+ }
+ else
+ {
+ log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
+
+ if (extmapper_name == "simplemap") {
+ if (simplemap_mappers.count(cell->type) == 0)
+ log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type));
+ simplemap_mappers.at(cell->type)(module, cell);
+ }
+
+ if (extmapper_name == "maccmap") {
+ if (cell->type != "$macc")
+ log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type));
+ maccmap(module, cell);
+ }
+
+ module->remove(cell);
+ cell = NULL;
}
- }
- if (!techmap_do_cache[tpl])
+ did_something = true;
+ mapped_cell = true;
break;
+ }
- for (auto &it : twd)
- {
- if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
+ for (auto conn : cell->connections()) {
+ if (conn.first.substr(0, 1) == "$")
+ continue;
+ if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0)
continue;
+ if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0)
+ goto next_tpl;
+ parameters[conn.first] = conn.second.as_const();
+ }
+
+ if (0) {
+ next_tpl:
+ continue;
+ }
+
+ if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0)
+ parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type);
+
+ for (auto conn : cell->connections()) {
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
+ for (auto &bit : v)
+ bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0);
+ parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ }
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector();
+ for (auto &bit : v)
+ if (bit.wire != NULL)
+ bit = RTLIL::SigBit(RTLIL::State::Sx);
+ parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const();
+ }
+ }
+
+ int unique_bit_id_counter = 0;
+ std::map<RTLIL::SigBit, int> unique_bit_id;
+ unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++;
+ unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++;
+
+ for (auto conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ for (auto &bit : sigmap(conn.second).to_sigbit_vector())
+ if (unique_bit_id.count(bit) == 0)
+ unique_bit_id[bit] = unique_bit_id_counter++;
+ }
- auto &data = it.second.front();
+ int bits = 0;
+ for (int i = 0; i < 32; i++)
+ if (((unique_bit_id_counter-1) & (1 << i)) != 0)
+ bits = i;
+ if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_"))
+ parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits;
+
+ for (auto conn : cell->connections())
+ if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) {
+ RTLIL::Const value;
+ for (auto &bit : sigmap(conn.second).to_sigbit_vector()) {
+ RTLIL::Const chunk(unique_bit_id.at(bit), bits);
+ value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end());
+ }
+ parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value;
+ }
+ }
- if (!data.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
+ if (0) {
+ use_wrapper_tpl:;
+ // do not register techmap_wrap modules with techmap_cache
+ } else {
+ std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters);
+ if (techmap_cache.count(key) > 0) {
+ tpl = techmap_cache[key];
+ } else {
+ if (cell->parameters.size() != 0) {
+ derived_name = tpl->derive(map, parameters);
+ tpl = map->module(derived_name);
+ log_continue = true;
+ }
+ techmap_cache[key] = tpl;
+ }
+ }
- tpl->wires.erase(data.wire->name);
- const char *p = data.wire->name.c_str();
- const char *q = strrchr(p+1, '.');
- q = q ? q : p+1;
+ if (flatten_mode) {
+ techmap_do_cache[tpl] = true;
+ } else {
+ RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false));
+ if (constmapped_tpl != nullptr)
+ tpl = constmapped_tpl;
+ }
- assert(!strncmp(q, "_TECHMAP_DO_", 12));
- std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
- while (tpl->wires.count(new_name))
- new_name += "_";
- data.wire->name = new_name;
- tpl->add(data.wire);
+ if (techmap_do_cache.count(tpl) == 0)
+ {
+ bool keep_running = true;
+ techmap_do_cache[tpl] = true;
- std::string cmd_string = data.value.as_const().decode_string();
+ std::set<std::string> techmap_wire_names;
- RTLIL::Selection tpl_mod_sel(false);
- tpl_mod_sel.select(tpl);
- map->selection_stack.push_back(tpl_mod_sel);
- Pass::call(map, cmd_string);
- map->selection_stack.pop_back();
+ while (keep_running)
+ {
+ TechmapWires twd = techmap_find_special_wires(tpl);
+ keep_running = false;
+
+ for (auto &it : twd)
+ techmap_wire_names.insert(it.first);
+
+ for (auto &it : twd["_TECHMAP_FAIL_"]) {
+ RTLIL::SigSpec value = it.value;
+ if (value.is_fully_const() && value.as_bool()) {
+ log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
+ derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value));
+ techmap_do_cache[tpl] = false;
+ }
+ }
- keep_running = true;
- break;
+ if (!techmap_do_cache[tpl])
+ break;
+
+ for (auto &it : twd)
+ {
+ if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty())
+ continue;
+
+ auto &data = it.second.front();
+
+ if (!data.value.is_fully_const())
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value));
+
+ techmap_wire_names.erase(it.first);
+
+ const char *p = data.wire->name.c_str();
+ const char *q = strrchr(p+1, '.');
+ q = q ? q : p+1;
+
+ std::string cmd_string = data.value.as_const().decode_string();
+
+ restart_eval_cmd_string:
+ if (cmd_string.rfind("CONSTMAP; ", 0) == 0)
+ {
+ cmd_string = cmd_string.substr(strlen("CONSTMAP; "));
+
+ log("Analyzing pattern of constant bits for this cell:\n");
+ RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true);
+ log("Creating constmapped module `%s'.\n", log_id(new_tpl_name));
+ log_assert(map->module(new_tpl_name) == nullptr);
+
+ RTLIL::Module *new_tpl = map->addModule(new_tpl_name);
+ tpl->cloneInto(new_tpl);
+
+ techmap_do_cache.erase(tpl);
+ techmap_do_cache[new_tpl] = true;
+ tpl = new_tpl;
+
+ std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap;
+ std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits;
+
+ for (auto wire : tpl->wires().to_vector())
+ {
+ if (!wire->port_input || wire->port_output)
+ continue;
+
+ RTLIL::IdString port_name = wire->name;
+ tpl->rename(wire, NEW_ID);
+
+ RTLIL::Wire *new_wire = tpl->addWire(port_name, wire);
+ wire->port_input = false;
+ wire->port_id = 0;
+
+ for (int i = 0; i < wire->width; i++) {
+ port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i);
+ port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i);
+ }
+ }
+
+ for (auto conn : cell->connections())
+ for (int i = 0; i < SIZE(conn.second); i++)
+ {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
+
+ if (bit.wire == nullptr)
+ {
+ RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+ port_connmap.at(oldbit) = bit;
+ }
+ else if (cellbits_to_tplbits.count(bit))
+ {
+ RTLIL::SigBit oldbit = port_new2old_map.at(tplbit);
+ port_connmap.at(oldbit) = cellbits_to_tplbits[bit];
+ }
+ else
+ cellbits_to_tplbits[bit] = tplbit;
+ }
+
+ RTLIL::SigSig port_conn;
+ for (auto &it : port_connmap) {
+ port_conn.first.append_bit(it.first);
+ port_conn.second.append_bit(it.second);
+ }
+ tpl->connect(port_conn);
+
+ tpl->check();
+ goto restart_eval_cmd_string;
+ }
+
+ if (cmd_string.rfind("RECURSION; ", 0) == 0)
+ {
+ cmd_string = cmd_string.substr(strlen("RECURSION; "));
+ while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
+ goto restart_eval_cmd_string;
+ }
+
+ Pass::call_on_module(map, tpl, cmd_string);
+
+ log_assert(!strncmp(q, "_TECHMAP_DO_", 12));
+ std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12);
+ while (tpl->wires_.count(new_name))
+ new_name += "_";
+ tpl->rename(data.wire->name, new_name);
+
+ keep_running = true;
+ break;
+ }
+ }
+
+ TechmapWires twd = techmap_find_special_wires(tpl);
+ for (auto &it : twd) {
+ if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
+ log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
+ if (techmap_do_cache[tpl])
+ for (auto &it2 : it.second)
+ if (!it2.value.is_fully_const())
+ log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
+ techmap_wire_names.erase(it.first);
+ }
+
+ for (auto &it : techmap_wire_names)
+ log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it));
+
+ if (recursive_mode) {
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
+ }
+ while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
}
}
- TechmapWires twd = techmap_find_special_wires(tpl);
- for (auto &it : twd) {
- if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_")
- log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str());
- if (techmap_do_cache[tpl])
- for (auto &it2 : it.second)
- if (!it2.value.is_fully_const())
- log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value));
+ if (techmap_do_cache.at(tpl) == false)
+ continue;
+
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
}
- }
- if (techmap_do_cache.at(tpl) == false)
- continue;
+ if (extern_mode && !in_recursion)
+ {
+ std::string m_name = stringf("$extern:%s", log_id(tpl));
- if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
- log_continue = false;
+ if (!design->module(m_name))
+ {
+ RTLIL::Module *m = design->addModule(m_name);
+ tpl->cloneInto(m);
+
+ for (auto cell : m->cells()) {
+ if (cell->type.substr(0, 2) == "\\$")
+ cell->type = cell->type.substr(1);
+ }
+
+ module_queue.insert(m);
+ }
+
+ log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
+ cell->type = m_name;
+ cell->parameters.clear();
+ }
+ else
+ {
+ log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl));
+ techmap_module_worker(design, module, cell, tpl);
+ cell = NULL;
+ }
+ did_something = true;
+ mapped_cell = true;
+ break;
}
- techmap_module_worker(design, module, cell, tpl, flatten_mode);
- did_something = true;
- cell = NULL;
- break;
+ if (assert_mode && !mapped_cell)
+ log_error("(ASSERT MODE) Failed to map cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
+
+ handled_cells.insert(cell);
}
- handled_cells.insert(cell);
- }
+ if (log_continue) {
+ log_header("Continuing TECHMAP pass.\n");
+ log_continue = false;
+ }
- if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
- log_continue = false;
+ return did_something;
}
-
- return did_something;
-}
+};
struct TechmapPass : public Pass {
TechmapPass() : Pass("techmap", "generic technology mapper") { }
@@ -380,11 +769,34 @@ struct TechmapPass : public Pass {
log(" transforms the internal RTL cells to the internal gate\n");
log(" library.\n");
log("\n");
+ log(" -map %%<design-name>\n");
+ log(" like -map above, but with an in-memory design instead of a file.\n");
+ log("\n");
log(" -share_map filename\n");
log(" like -map, but look for the file in the share directory (where the\n");
log(" yosys data files are). this is mainly used internally when techmap\n");
log(" is called from other commands.\n");
log("\n");
+ log(" -extern\n");
+ log(" load the cell implementations as separate modules into the design\n");
+ log(" instead of inlining them.\n");
+ log("\n");
+ log(" -max_iter <number>\n");
+ log(" only run the specified number of iterations.\n");
+ log("\n");
+ log(" -recursive\n");
+ log(" instead of the iterative breadth-first algorithm use a recursive\n");
+ log(" depth-first algorithm. both methods should yield equivialent results,\n");
+ log(" but may differ in performance.\n");
+ log("\n");
+ log(" -autoproc\n");
+ log(" Automatically call \"proc\" on implementations that contain processes.\n");
+ log("\n");
+ log(" -assert\n");
+ log(" this option will cause techmap to exit with an error if it can't map\n");
+ log(" a selected cell. only cell types that end on an underscore are accepted\n");
+ log(" as final cell types by this mode.\n");
+ log("\n");
log(" -D <define>, -I <incdir>\n");
log(" this options are passed as-is to the verilog frontend for loading the\n");
log(" map file. Note that the verilog frontend is also called with the\n");
@@ -397,6 +809,13 @@ struct TechmapPass : public Pass {
log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
log("\n");
+ log("When a module in the map file has the 'techmap_maccmap' attribute set, techmap\n");
+ log("will use 'maccmap' (see 'help maccmap') to map cells matching the module.\n");
+ log("\n");
+ log("When a module in the map file has the 'techmap_wrap' attribute set, techmap\n");
+ log("will create a wrapper for the cell and then run the command string that the\n");
+ log("attribute is set to on the wrapper module.\n");
+ log("\n");
log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n");
log("or *._TECHMAP_* are special wires that are used to pass instructions from\n");
log("the mapping module to the techmap command. At the moment the following special\n");
@@ -421,6 +840,20 @@ struct TechmapPass : public Pass {
log(" wire to start out as non-constant and evaluate to a constant value\n");
log(" during processing of other _TECHMAP_DO_* commands.\n");
log("\n");
+ log(" A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n");
+ log(" in this case techmap will create a copy for each distinct configuration\n");
+ log(" of constant inputs and shorted inputs at this point and import the\n");
+ log(" constant and connected bits into the map module. All further commands\n");
+ log(" are executed in this copy. This is a very convenient way of creating\n");
+ log(" optimizied specializations of techmap modules without using the special\n");
+ log(" parameters described below.\n");
+ log("\n");
+ log(" A _TECHMAP_DO_* command may start with the special token 'RECURSION; '.\n");
+ log(" then techmap will recursively replace the cells in the module with their\n");
+ log(" implementation. This is not affected by the -max_iter option.\n");
+ log("\n");
+ log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n");
+ log("\n");
log("In addition to this special wires, techmap also supports special parameters in\n");
log("modules in the map file:\n");
log("\n");
@@ -428,11 +861,28 @@ struct TechmapPass : public Pass {
log(" When a parameter with this name exists, it will be set to the type name\n");
log(" of the cell that matches the module.\n");
log("\n");
+ log(" _TECHMAP_CONSTMSK_<port-name>_\n");
+ log(" _TECHMAP_CONSTVAL_<port-name>_\n");
+ log(" When this pair of parameters is available in a module for a port, then\n");
+ log(" former has a 1-bit for each constant input bit and the latter has the\n");
+ log(" value for this bit. The unused bits of the latter are set to undef (x).\n");
+ log("\n");
+ log(" _TECHMAP_BITS_CONNMAP_\n");
+ log(" _TECHMAP_CONNMAP_<port-name>_\n");
+ log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n");
+ log(" exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing\n");
+ log(" N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single\n");
+ log(" bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.\n");
+ log(" This can be used to detect shorted inputs.\n");
+ log("\n");
log("When a module in the map file has a parameter where the according cell in the\n");
log("design has a port, the module from the map file is only used if the port in\n");
log("the design is connected to a constant value. The parameter is then set to the\n");
log("constant value.\n");
log("\n");
+ log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n");
+ log("of the cell that is beeing replaced.\n");
+ log("\n");
log("See 'help extract' for a pass that does the opposite thing.\n");
log("\n");
log("See 'help flatten' for a pass that does flatten the design (which is\n");
@@ -444,17 +894,28 @@ struct TechmapPass : public Pass {
log_header("Executing TECHMAP pass (map to technology primitives).\n");
log_push();
+ TechmapWorker worker;
+ simplemap_get_mappers(worker.simplemap_mappers);
+
std::vector<std::string> map_files;
std::string verilog_frontend = "verilog -ignore_redef";
+ int max_iter = -1;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-map" && argidx+1 < args.size()) {
- map_files.push_back(args[++argidx]);
+ if (args[argidx+1].substr(0, 2) == "+/")
+ map_files.push_back(proc_share_dirname() + args[++argidx].substr(2));
+ else
+ map_files.push_back(args[++argidx]);
continue;
}
if (args[argidx] == "-share_map" && argidx+1 < args.size()) {
- map_files.push_back(get_share_file_name(args[++argidx]));
+ map_files.push_back(proc_share_dirname() + args[++argidx]);
+ continue;
+ }
+ if (args[argidx] == "-max_iter" && argidx+1 < args.size()) {
+ max_iter = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-D" && argidx+1 < args.size()) {
@@ -465,36 +926,58 @@ struct TechmapPass : public Pass {
verilog_frontend += " -I " + args[++argidx];
continue;
}
+ if (args[argidx] == "-assert") {
+ worker.assert_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-extern") {
+ worker.extern_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-recursive") {
+ worker.recursive_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-autoproc") {
+ worker.autoproc_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- simplemap_get_mappers(simplemap_mappers);
-
RTLIL::Design *map = new RTLIL::Design;
if (map_files.empty()) {
- FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt");
- Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend);
- fclose(f);
+ std::istringstream f(stdcells_code);
+ Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else
- for (auto &fn : map_files) {
- FILE *f = fopen(fn.c_str(), "rt");
- if (f == NULL)
- log_cmd_error("Can't open map file `%s'\n", fn.c_str());
- Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
- fclose(f);
- }
+ for (auto &fn : map_files)
+ if (fn.substr(0, 1) == "%") {
+ if (!saved_designs.count(fn.substr(1))) {
+ delete map;
+ log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1);
+ }
+ for (auto mod : saved_designs.at(fn.substr(1))->modules())
+ if (!map->has(mod->name))
+ map->add(mod->clone());
+ } else {
+ std::ifstream f;
+ f.open(fn.c_str());
+ if (f.fail())
+ log_cmd_error("Can't open map file `%s'\n", fn.c_str());
+ Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
+ }
std::map<RTLIL::IdString, RTLIL::Module*> modules_new;
- for (auto &it : map->modules) {
+ for (auto &it : map->modules_) {
if (it.first.substr(0, 2) == "\\$")
it.second->name = it.first.substr(1);
modules_new[it.second->name] = it.second;
}
- map->modules.swap(modules_new);
+ map->modules_.swap(modules_new);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
- for (auto &it : map->modules) {
+ std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
+ for (auto &it : map->modules_) {
if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) {
char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str());
for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n"))
@@ -504,22 +987,30 @@ struct TechmapPass : public Pass {
celltypeMap[it.first].insert(it.first);
}
- bool did_something = true;
- std::set<RTLIL::Cell*> handled_cells;
- while (did_something) {
- did_something = false;
- for (auto &mod_it : design->modules)
- if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false))
- did_something = true;
- if (did_something)
- design->check();
+ for (auto module : design->modules())
+ worker.module_queue.insert(module);
+
+ while (!worker.module_queue.empty())
+ {
+ RTLIL::Module *module = *worker.module_queue.begin();
+ worker.module_queue.erase(module);
+
+ bool did_something = true;
+ std::set<RTLIL::Cell*> handled_cells;
+ while (did_something) {
+ did_something = false;
+ if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false))
+ did_something = true;
+ if (did_something)
+ module->check();
+ if (max_iter > 0 && --max_iter == 0)
+ break;
+ }
}
log("No more expansions possible.\n");
- techmap_cache.clear();
- techmap_do_cache.clear();
- simplemap_mappers.clear();
delete map;
+
log_pop();
}
} TechmapPass;
@@ -544,26 +1035,29 @@ struct FlattenPass : public Pass {
extra_args(args, 1, design);
- std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap;
- for (auto &it : design->modules)
+ TechmapWorker worker;
+ 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);
RTLIL::Module *top_mod = NULL;
if (design->full_selection())
- for (auto &mod_it : design->modules)
- if (mod_it.second->get_bool_attribute("\\top"))
- top_mod = mod_it.second;
+ for (auto mod : design->modules())
+ 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 (techmap_module(design, top_mod, design, handled_cells, celltypeMap, true))
+ if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false))
did_something = true;
} else {
- for (auto &mod_it : design->modules)
- if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true))
+ for (auto mod : design->modules())
+ if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false))
did_something = true;
}
}
@@ -572,18 +1066,16 @@ struct FlattenPass : public Pass {
if (top_mod != NULL) {
std::map<RTLIL::IdString, RTLIL::Module*> new_modules;
- for (auto &mod_it : design->modules)
- if (mod_it.second == top_mod) {
- new_modules[mod_it.first] = mod_it.second;
+ for (auto mod : design->modules())
+ if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) {
+ new_modules[mod->name] = mod;
} else {
- log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first));
- delete mod_it.second;
+ log("Deleting now unused module %s.\n", log_id(mod));
+ delete mod;
}
- design->modules.swap(new_modules);
+ design->modules_.swap(new_modules);
}
- techmap_cache.clear();
- techmap_do_cache.clear();
log_pop();
}
} FlattenPass;
diff --git a/passes/tests/Makefile.inc b/passes/tests/Makefile.inc
new file mode 100644
index 000000000..531943d78
--- /dev/null
+++ b/passes/tests/Makefile.inc
@@ -0,0 +1,5 @@
+
+OBJS += passes/tests/test_autotb.o
+OBJS += passes/tests/test_cell.o
+OBJS += passes/tests/test_abcloop.o
+
diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc
new file mode 100644
index 000000000..0a0ceb1d1
--- /dev/null
+++ b/passes/tests/test_abcloop.cc
@@ -0,0 +1,285 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.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"
+
+static uint32_t xorshift32_state = 123456789;
+
+static uint32_t xorshift32(uint32_t limit) {
+ xorshift32_state ^= xorshift32_state << 13;
+ xorshift32_state ^= xorshift32_state >> 17;
+ xorshift32_state ^= xorshift32_state << 5;
+ return xorshift32_state % limit;
+}
+
+static RTLIL::Wire *getw(std::vector<RTLIL::Wire*> &wires, RTLIL::Wire *w)
+{
+ while (1) {
+ int idx = xorshift32(SIZE(wires));
+ if (wires[idx] != w && !wires[idx]->port_output)
+ return wires[idx];
+ }
+}
+
+static void test_abcloop()
+{
+ log("Rng seed value: %u\n", int(xorshift32_state));
+
+ RTLIL::Design *design = new RTLIL::Design;
+ RTLIL::Module *module = nullptr;
+ RTLIL::SigSpec in_sig, out_sig;
+
+ bool truthtab[16][4];
+ int create_cycles = 0;
+
+ while (1)
+ {
+ module = design->addModule("\\uut");
+ create_cycles++;
+
+ in_sig = {};
+ out_sig = {};
+
+ std::vector<RTLIL::Wire*> wires;
+
+ for (int i = 0; i < 4; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\i%d", i));
+ w->port_input = true;
+ wires.push_back(w);
+ in_sig.append(w);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\o%d", i));
+ w->port_output = true;
+ wires.push_back(w);
+ out_sig.append(w);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ RTLIL::Wire *w = module->addWire(stringf("\\t%d", i));
+ wires.push_back(w);
+ }
+
+ for (auto w : wires)
+ if (!w->port_input)
+ switch (xorshift32(12))
+ {
+ case 0:
+ module->addNotGate(w->name.str() + "g", getw(wires, w), w);
+ break;
+ case 1:
+ module->addAndGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 2:
+ module->addNandGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 3:
+ module->addOrGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 4:
+ module->addNorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 5:
+ module->addXorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 6:
+ module->addXnorGate(w->name.str() + "g", getw(wires, w), getw(wires, w), w);
+ break;
+ case 7:
+ module->addMuxGate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 8:
+ module->addAoi3Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 9:
+ module->addOai3Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 10:
+ module->addAoi4Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ case 11:
+ module->addOai4Gate(w->name.str() + "g", getw(wires, w), getw(wires, w), getw(wires, w), getw(wires, w), w);
+ break;
+ }
+
+ module->fixup_ports();
+ Pass::call(design, "clean");
+
+ ezDefaultSAT ez;
+ SigMap sigmap(module);
+ SatGen satgen(&ez, &sigmap);
+
+ for (auto c : module->cells()) {
+ bool ok = 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> 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++)
+ 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)) {
+ log("No stable solution for input %d found -> recreate module.\n", i);
+ goto recreate_module;
+ }
+
+ for (int j = 0; j < 4; j++)
+ truthtab[i][j] = results[j];
+
+ assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+
+ std::vector<bool> results2;
+ if (ez.solve(out_vec, results2, assumptions)) {
+ log("Two stable solutions for input %d found -> recreate module.\n", i);
+ goto recreate_module;
+ }
+ }
+ break;
+
+ recreate_module:
+ design->remove(module);
+ }
+
+ log("Found viable UUT after %d cycles:\n", create_cycles);
+ Pass::call(design, "write_ilang");
+ Pass::call(design, "abc");
+
+ log("\n");
+ log("Pre- and post-abc truth table:\n");
+
+ ezDefaultSAT ez;
+ SigMap sigmap(module);
+ SatGen satgen(&ez, &sigmap);
+
+ for (auto c : module->cells()) {
+ bool ok = 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> out_vec = satgen.importSigSpec(out_sig);
+
+ bool found_error = false;
+ bool truthtab2[16][4];
+
+ for (int i = 0; i < 16; i++)
+ {
+ std::vector<int> assumptions;
+ for (int j = 0; j < SIZE(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)) {
+ log("No stable solution for input %d found.\n", i);
+ found_error = true;
+ continue;
+ }
+
+ for (int j = 0; j < 4; j++)
+ truthtab2[i][j] = results[j];
+
+ assumptions.push_back(ez.vec_ne(out_vec, ez.vec_const(results)));
+
+ std::vector<bool> results2;
+ if (ez.solve(out_vec, results2, assumptions)) {
+ log("Two stable solutions for input %d found -> recreate module.\n", i);
+ found_error = true;
+ }
+ }
+
+ for (int i = 0; i < 16; i++) {
+ log("%3d ", i);
+ for (int j = 0; j < 4; j++)
+ log("%c", truthtab[i][j] ? '1' : '0');
+ log(" ");
+ for (int j = 0; j < 4; j++)
+ log("%c", truthtab2[i][j] ? '1' : '0');
+ for (int j = 0; j < 4; j++)
+ if (truthtab[i][j] != truthtab2[i][j]) {
+ found_error = true;
+ log(" !");
+ break;
+ }
+ log("\n");
+ }
+
+ log_assert(found_error == false);
+ log("\n");
+}
+
+struct TestAbcloopPass : public Pass {
+ TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_abcloop [options]\n");
+ log("\n");
+ log("Test handling of logic loops in ABC.\n");
+ log("\n");
+ log(" -n {integer}\n");
+ log(" create this number of circuits and test them (default = 100).\n");
+ log("\n");
+ log(" -s {positive_integer}\n");
+ log(" use this value as rng seed value (default = unix time).\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ {
+ int num_iter = 100;
+ xorshift32_state = 0;
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ xorshift32_state = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+
+ if (xorshift32_state == 0)
+ xorshift32_state = time(NULL) & 0x7fffffff;
+
+ for (int i = 0; i < num_iter; i++)
+ test_abcloop();
+ }
+} TestAbcloopPass;
+
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
new file mode 100644
index 000000000..eed0f75f9
--- /dev/null
+++ b/passes/tests/test_autotb.cc
@@ -0,0 +1,353 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+PRIVATE_NAMESPACE_BEGIN
+
+static std::string id(std::string internal_id)
+{
+ const char *str = internal_id.c_str();
+ bool do_escape = false;
+
+ if (*str == '\\')
+ str++;
+
+ if ('0' <= *str && *str <= '9')
+ do_escape = true;
+
+ for (int i = 0; str[i]; i++) {
+ if ('0' <= str[i] && str[i] <= '9')
+ continue;
+ if ('a' <= str[i] && str[i] <= 'z')
+ continue;
+ if ('A' <= str[i] && str[i] <= 'Z')
+ continue;
+ if (str[i] == '_')
+ continue;
+ do_escape = true;
+ break;
+ }
+
+ if (do_escape)
+ return "\\" + std::string(str) + " ";
+ return std::string(str);
+}
+
+static std::string idx(std::string str)
+{
+ if (str[0] == '\\')
+ return str.substr(1);
+ return str;
+}
+
+static std::string idy(std::string str1, std::string str2 = std::string(), std::string str3 = std::string())
+{
+ str1 = idx(str1);
+ if (!str2.empty())
+ str1 += "_" + idx(str2);
+ if (!str3.empty())
+ str1 += "_" + idx(str3);
+ return id(str1);
+}
+
+static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
+{
+ f << stringf("module testbench;\n\n");
+
+ f << stringf("integer i;\n\n");
+
+ f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
+ f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
+ f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
+ f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL)));
+ f << stringf("reg [31:0] xorshift128_t;\n\n");
+ f << stringf("task xorshift128;\n");
+ f << stringf("begin\n");
+ f << stringf("\txorshift128_t = xorshift128_x ^ (xorshift128_x << 11);\n");
+ f << stringf("\txorshift128_x = xorshift128_y;\n");
+ f << stringf("\txorshift128_y = xorshift128_z;\n");
+ f << stringf("\txorshift128_z = xorshift128_w;\n");
+ f << stringf("\txorshift128_w = xorshift128_w ^ (xorshift128_w >> 19) ^ xorshift128_t ^ (xorshift128_t >> 8);\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ 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;
+ std::map<std::string, int> signal_clk;
+ std::map<std::string, int> signal_out;
+
+ RTLIL::Module *mod = it->second;
+
+ if (mod->get_bool_attribute("\\gentb_skip"))
+ continue;
+
+ 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++) {
+ RTLIL::Wire *wire = it2->second;
+ if (wire->port_output) {
+ count_ports++;
+ signal_out[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ f << stringf("wire [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
+ } 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++) {
+ if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
+ continue;
+ RTLIL::SigSpec &signal = (*it4)->signal;
+ for (auto &c : signal.chunks())
+ if (c.wire == wire)
+ is_clksignal = true;
+ }
+ if (is_clksignal && wire->attributes.count("\\gentb_constant") == 0) {
+ signal_clk[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ } else {
+ signal_in[idy("sig", mod->name.str(), wire->name.str())] = wire->width;
+ if (wire->attributes.count("\\gentb_constant") != 0)
+ signal_const[idy("sig", mod->name.str(), wire->name.str())] = wire->attributes["\\gentb_constant"].as_string();
+ }
+ f << stringf("reg [%d:0] %s;\n", wire->width-1, idy("sig", mod->name.str(), wire->name.str()).c_str());
+ }
+ }
+ 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++) {
+ 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(),
+ idy("sig", mod->name.str(), wire->name.str()).c_str(), --count_ports ? "," : "");
+ }
+ f << stringf(");\n\n");
+
+ 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++)
+ 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++)
+ 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++) {
+ 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++)
+ 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++) {
+ 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++) {
+ 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());
+ }
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "update_data").c_str());
+ f << stringf("begin\n");
+ delay_counter = 0;
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ if (signal_const.count(it->first) > 0)
+ continue;
+ f << stringf("\txorshift128;\n");
+ f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
+ }
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "update_clock").c_str());
+ f << stringf("begin\n");
+ if (signal_clk.size()) {
+ f << stringf("\txorshift128;\n");
+ f << stringf("\t{");
+ int total_clock_bits = 0;
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
+ total_clock_bits += it->second;
+ }
+ 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("end\n");
+ f << stringf("endtask\n\n");
+
+ char shorthand = 'A';
+ std::vector<std::string> header1;
+ std::string header2 = "";
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "print_status").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
+ if (signal_in.size())
+ for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
+ f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, {");
+ header2 += " ";
+ if (signal_clk.size()) {
+ for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
+ f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ } else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, {");
+ header2 += " ";
+ if (signal_out.size()) {
+ for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
+ f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
+ int len = it->second;
+ if (len > 1)
+ header2 += "/", len--;
+ while (len > 1)
+ header2 += "-", len--;
+ if (len > 0)
+ header2 += shorthand, len--;
+ header1.push_back(" " + it->first);
+ header1.back()[0] = shorthand++;
+ }
+ } else {
+ f << stringf(" 1'bx");
+ header2 += "#";
+ }
+ f << stringf(" }, $time, i);\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "print_header").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT#\");\n");
+ for (auto &hdr : header1)
+ f << stringf("\t$display(\"#OUT# %s\");\n", hdr.c_str());
+ f << stringf("\t$display(\"#OUT#\");\n");
+ f << stringf("\t$display(\"#OUT# %s\");\n", header2.c_str());
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+
+ f << stringf("task %s;\n", idy(mod->name.str(), "test").c_str());
+ f << stringf("begin\n");
+ f << stringf("\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str());
+ f << stringf("\t%s;\n", idy(mod->name.str(), "reset").c_str());
+ f << stringf("\tfor (i=0; i<%d; i=i+1) begin\n", num_iter);
+ f << stringf("\t\tif (i %% 20 == 0) %s;\n", idy(mod->name.str(), "print_header").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "update_data").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "update_clock").c_str());
+ f << stringf("\t\t#100; %s;\n", idy(mod->name.str(), "print_status").c_str());
+ f << stringf("\tend\n");
+ f << stringf("end\n");
+ f << stringf("endtask\n\n");
+ }
+
+ 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++)
+ 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");
+ f << stringf("end\n\n");
+
+ f << stringf("endmodule\n");
+}
+
+struct TestAutotbBackend : public Backend {
+ TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_autotb [options] [filename]\n");
+ log("\n");
+ log("Automatically create primitive verilog test benches for all modules in the\n");
+ log("design. The generated testbenches toggle the input pins of the module in\n");
+ log("a semi-random manner and dumps the resulting output signals.\n");
+ log("\n");
+ log("This can be used to check the synthesis results for simple circuits by\n");
+ log("comparing the testbench output for the input files and the synthesis results.\n");
+ log("\n");
+ log("The backend automatically detects clock signals. Additionally a signal can\n");
+ log("be forced to be interpreted as clock signal by setting the attribute\n");
+ log("'gentb_clock' on the signal.\n");
+ log("\n");
+ log("The attribute 'gentb_constant' can be used to force a signal to a constant\n");
+ log("value after initialization. This can e.g. be used to force a reset signal\n");
+ log("low in order to explore more inner states in a state machine.\n");
+ log("\n");
+ log(" -n <int>\n");
+ log(" number of iterations the test bench shuld run (default = 1000)\n");
+ log("\n");
+ }
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ int num_iter = 1000;
+
+ log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n");
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ break;
+ }
+
+ extra_args(f, filename, args, argidx);
+ autotest(*f, design, num_iter);
+ }
+} TestAutotbBackend;
+
+PRIVATE_NAMESPACE_END
+
diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc
new file mode 100644
index 000000000..1fa90b540
--- /dev/null
+++ b/passes/tests/test_cell.cc
@@ -0,0 +1,745 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2014 Johann Glaser <Johann.Glaser@gmx.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/consteval.h"
+#include "kernel/macc.h"
+#include <algorithm>
+
+static uint32_t xorshift32_state = 123456789;
+
+static uint32_t xorshift32(uint32_t limit) {
+ xorshift32_state ^= xorshift32_state << 13;
+ xorshift32_state ^= xorshift32_state >> 17;
+ xorshift32_state ^= xorshift32_state << 5;
+ return xorshift32_state % limit;
+}
+
+static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, std::string cell_type_flags, bool constmode)
+{
+ RTLIL::Module *module = design->addModule("\\gold");
+ RTLIL::Cell *cell = module->addCell("\\UUT", cell_type);
+ RTLIL::Wire *wire;
+
+ if (cell_type == "$fa")
+ {
+ int width = 1 + xorshift32(8);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\B");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\B", wire);
+
+ wire = module->addWire("\\C");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\C", wire);
+
+ wire = module->addWire("\\X");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\X", wire);
+
+ wire = module->addWire("\\Y");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+ }
+
+ if (cell_type == "$lcu")
+ {
+ int width = 1 + xorshift32(8);
+
+ wire = module->addWire("\\P");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\P", wire);
+
+ wire = module->addWire("\\G");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\G", wire);
+
+ wire = module->addWire("\\CI");
+ wire->port_input = true;
+ cell->setPort("\\CI", wire);
+
+ wire = module->addWire("\\CO");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\CO", wire);
+ }
+
+ if (cell_type == "$macc")
+ {
+ Macc macc;
+ int width = 1 + xorshift32(8);
+ int depth = 1 + xorshift32(6);
+ int mulbits_a = 0, mulbits_b = 0;
+
+ RTLIL::Wire *wire_a = module->addWire("\\A");
+ wire_a->width = 0;
+ wire_a->port_input = true;
+
+ for (int i = 0; i < depth; i++)
+ {
+ int size_a = xorshift32(width) + 1;
+ int size_b = depth > 4 ? 0 : xorshift32(width) + 1;
+
+ if (mulbits_a + size_a*size_b <= 96 && mulbits_b + size_a + size_b <= 16 && xorshift32(2) == 1) {
+ mulbits_a += size_a * size_b;
+ mulbits_b += size_a + size_b;
+ } else
+ size_b = 0;
+
+ Macc::port_t this_port;
+
+ wire_a->width += size_a;
+ this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
+
+ wire_a->width += size_b;
+ this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
+
+ this_port.is_signed = xorshift32(2) == 1;
+ this_port.do_subtract = xorshift32(2) == 1;
+ macc.ports.push_back(this_port);
+ }
+
+ wire = module->addWire("\\B");
+ wire->width = xorshift32(mulbits_a ? xorshift32(4)+1 : xorshift32(16)+1);
+ wire->port_input = true;
+ macc.bit_ports = wire;
+
+ wire = module->addWire("\\Y");
+ wire->width = width;
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+
+ macc.to_cell(cell);
+ }
+
+ if (cell_type == "$lut")
+ {
+ int width = 1 + xorshift32(6);
+
+ wire = module->addWire("\\A");
+ wire->width = width;
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+
+ wire = module->addWire("\\Y");
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+
+ RTLIL::SigSpec config;
+ for (int i = 0; i < (1 << width); i++)
+ config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0);
+
+ cell->setParam("\\LUT", config.as_const());
+ }
+
+ if (cell_type_flags.find('A') != std::string::npos) {
+ wire = module->addWire("\\A");
+ wire->width = 1 + xorshift32(8);
+ wire->port_input = true;
+ cell->setPort("\\A", wire);
+ }
+
+ if (cell_type_flags.find('B') != std::string::npos) {
+ wire = module->addWire("\\B");
+ if (cell_type_flags.find('h') != std::string::npos)
+ wire->width = 1 + xorshift32(6);
+ else
+ wire->width = 1 + xorshift32(8);
+ wire->port_input = true;
+ cell->setPort("\\B", wire);
+ }
+
+ if (cell_type_flags.find('S') != std::string::npos && xorshift32(2)) {
+ if (cell_type_flags.find('A') != std::string::npos)
+ cell->parameters["\\A_SIGNED"] = true;
+ if (cell_type_flags.find('B') != std::string::npos)
+ cell->parameters["\\B_SIGNED"] = true;
+ }
+
+ if (cell_type_flags.find('s') != std::string::npos) {
+ if (cell_type_flags.find('A') != std::string::npos && xorshift32(2))
+ cell->parameters["\\A_SIGNED"] = true;
+ if (cell_type_flags.find('B') != std::string::npos && xorshift32(2))
+ cell->parameters["\\B_SIGNED"] = true;
+ }
+
+ if (cell_type_flags.find('Y') != std::string::npos) {
+ wire = module->addWire("\\Y");
+ wire->width = 1 + xorshift32(8);
+ wire->port_output = true;
+ cell->setPort("\\Y", wire);
+ }
+
+ if (cell_type == "$alu")
+ {
+ wire = module->addWire("\\CI");
+ wire->port_input = true;
+ cell->setPort("\\CI", wire);
+
+ wire = module->addWire("\\BI");
+ wire->port_input = true;
+ cell->setPort("\\BI", wire);
+
+ wire = module->addWire("\\X");
+ wire->width = SIZE(cell->getPort("\\Y"));
+ wire->port_output = true;
+ cell->setPort("\\X", wire);
+
+ wire = module->addWire("\\CO");
+ wire->width = SIZE(cell->getPort("\\Y"));
+ wire->port_output = true;
+ cell->setPort("\\CO", wire);
+ }
+
+ if (constmode)
+ {
+ auto conn_list = cell->connections();
+ for (auto &conn : conn_list)
+ {
+ RTLIL::SigSpec sig = conn.second;
+
+ if (SIZE(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);
+ 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++)
+ sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ break;
+ case 2:
+ n = xorshift32(SIZE(sig));
+ m = xorshift32(SIZE(sig));
+ for (int i = std::min(n, m); i < std::max(n, m); i++)
+ sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0;
+ break;
+ }
+
+ cell->setPort(conn.first, sig);
+ }
+ }
+
+ module->fixup_ports();
+ cell->fixup_parameters();
+ cell->check();
+}
+
+static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file)
+{
+ log("Eval testing:%c", verbose ? '\n' : ' ');
+
+ RTLIL::Module *gold_mod = design->module("\\gold");
+ RTLIL::Module *gate_mod = design->module("\\gate");
+ ConstEval gold_ce(gold_mod), gate_ce(gate_mod);
+
+ ezDefaultSAT ez1, ez2;
+ SigMap sigmap(gold_mod);
+ SatGen satgen1(&ez1, &sigmap);
+ SatGen satgen2(&ez2, &sigmap);
+ satgen2.model_undef = true;
+
+ if (!nosat)
+ for (auto cell : gold_mod->cells()) {
+ satgen1.importCell(cell);
+ satgen2.importCell(cell);
+ }
+
+ if (vlog_file.is_open())
+ {
+ vlog_file << stringf("\nmodule %s;\n", uut_name.c_str());
+
+ 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));
+ else
+ vlog_file << stringf(" wire [%d:0] %s_expr, %s_noexpr;\n", SIZE(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++)
+ 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++)
+ 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");
+
+ vlog_file << stringf(" task run;\n");
+ vlog_file << stringf(" begin\n");
+ vlog_file << stringf(" $display(\"%s\");\n", uut_name.c_str());
+ }
+
+ for (int i = 0; i < 64; i++)
+ {
+ log(verbose ? "\n" : ".");
+ gold_ce.clear();
+ gate_ce.clear();
+
+ RTLIL::SigSpec in_sig, in_val;
+ RTLIL::SigSpec out_sig, out_val;
+ std::string vlog_pattern_info;
+
+ for (auto port : gold_mod->ports)
+ {
+ RTLIL::Wire *gold_wire = gold_mod->wire(port);
+ RTLIL::Wire *gate_wire = gate_mod->wire(port);
+
+ 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));
+
+ if (!gold_wire->port_input)
+ continue;
+
+ RTLIL::Const in_value;
+ for (int i = 0; i < SIZE(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++)
+ if (xorshift32(inv_chance) == 0)
+ in_value.bits[i] = RTLIL::Sx;
+ }
+
+ if (verbose)
+ log("%s: %s\n", log_id(gold_wire), log_signal(in_value));
+
+ in_sig.append(gold_wire);
+ in_val.append(in_value);
+
+ gold_ce.set(gold_wire, in_value);
+ gate_ce.set(gate_wire, in_value);
+
+ if (vlog_file.is_open() && SIZE(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 += " ";
+ vlog_pattern_info += stringf("%s=%s", log_id(gold_wire), log_signal(in_value));
+ }
+ }
+
+ if (vlog_file.is_open())
+ vlog_file << stringf(" #1;\n");
+
+ for (auto port : gold_mod->ports)
+ {
+ RTLIL::Wire *gold_wire = gold_mod->wire(port);
+ RTLIL::Wire *gate_wire = gate_mod->wire(port);
+
+ 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));
+
+ if (!gold_wire->port_output)
+ continue;
+
+ RTLIL::SigSpec gold_outval(gold_wire);
+ RTLIL::SigSpec gate_outval(gate_wire);
+
+ if (!gold_ce.eval(gold_outval))
+ log_error("Failed to eval %s in gold module.\n", log_id(gold_wire));
+
+ if (!gate_ce.eval(gate_outval))
+ 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++) {
+ if (gold_outval[i] == RTLIL::Sx)
+ continue;
+ if (gold_outval[i] == gate_outval[i])
+ continue;
+ gold_gate_mismatch = true;
+ break;
+ }
+
+ if (gold_gate_mismatch)
+ log_error("Mismatch in output %s: gold:%s != gate:%s\n", log_id(gate_wire), log_signal(gold_outval), log_signal(gate_outval));
+
+ if (verbose)
+ log("%s: %s\n", log_id(gold_wire), log_signal(gold_outval));
+
+ out_sig.append(gold_wire);
+ out_val.append(gold_outval);
+
+ 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());
+ }
+ }
+
+ if (verbose)
+ log("EVAL: %s\n", out_val.as_string().c_str());
+
+ if (!nosat)
+ {
+ std::vector<int> sat1_in_sig = satgen1.importSigSpec(in_sig);
+ std::vector<int> sat1_in_val = satgen1.importSigSpec(in_val);
+
+ 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)))
+ 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--)
+ log("%c", sat1_model_value.at(i) ? '1' : '0');
+ log("\n");
+ }
+
+ for (int i = 0; i < SIZE(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)
+ continue;
+ if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true)
+ continue;
+ log_error("Mismatch in sat model 1 (no undef modeling) output!\n");
+ }
+
+ std::vector<int> sat2_in_def_sig = satgen2.importDefSigSpec(in_sig);
+ std::vector<int> sat2_in_def_val = satgen2.importDefSigSpec(in_val);
+
+ std::vector<int> sat2_in_undef_sig = satgen2.importUndefSigSpec(in_sig);
+ std::vector<int> sat2_in_undef_val = satgen2.importUndefSigSpec(in_val);
+
+ std::vector<int> sat2_model_def_sig = satgen2.importDefSigSpec(out_sig);
+ std::vector<int> sat2_model_undef_sig = satgen2.importUndefSigSpec(out_sig);
+
+ std::vector<int> sat2_model;
+ sat2_model.insert(sat2_model.end(), sat2_model_def_sig.begin(), sat2_model_def_sig.end());
+ sat2_model.insert(sat2_model.end(), sat2_model_undef_sig.begin(), sat2_model_undef_sig.end());
+
+ 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)))
+ 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');
+ log("\n");
+ }
+
+ for (int i = 0; i < SIZE(out_sig); i++) {
+ if (sat2_model_value.at(SIZE(out_sig) + i)) {
+ if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1)
+ continue;
+ } else {
+ if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false)
+ continue;
+ if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true)
+ continue;
+ }
+ log_error("Mismatch in sat model 2 (undef modeling) output!\n");
+ }
+ }
+ }
+
+ if (vlog_file.is_open()) {
+ vlog_file << stringf(" end\n");
+ vlog_file << stringf(" endtask\n");
+ vlog_file << stringf("endmodule\n");
+ }
+
+ if (!verbose)
+ log(" ok.\n");
+}
+
+struct TestCellPass : public Pass {
+ TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" test_cell [options] {cell-types}\n");
+ log("\n");
+ log("Tests the internal implementation of the given cell type (for example '$add')\n");
+ 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("\n");
+ log(" -n {integer}\n");
+ log(" create this number of cell instances and test them (default = 100).\n");
+ log("\n");
+ log(" -s {positive_integer}\n");
+ log(" use this value as rng seed value (default = unix time).\n");
+ log("\n");
+ log(" -f {ilang_file}\n");
+ log(" don't generate circuits. instead load the specified ilang file.\n");
+ log("\n");
+ log(" -map {filename}\n");
+ log(" pass this option to techmap.\n");
+ log("\n");
+ log(" -simplib\n");
+ log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n");
+ log("\n");
+ log(" -script {script_file}\n");
+ log(" instead of calling \"techmap\", call \"script {script_file}\".\n");
+ log("\n");
+ log(" -const\n");
+ log(" set some input bits to random constant values\n");
+ log("\n");
+ log(" -nosat\n");
+ log(" do not check SAT model or run SAT equivalence checking\n");
+ log("\n");
+ log(" -v\n");
+ log(" print additional debug information to the console\n");
+ log("\n");
+ log(" -vlog {filename}\n");
+ log(" create a verilog test bench to test simlib and write_verilog\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+ {
+ int num_iter = 100;
+ std::string techmap_cmd = "techmap -assert";
+ std::string ilang_file;
+ xorshift32_state = 0;
+ std::ofstream vlog_file;
+ bool verbose = false;
+ bool constmode = false;
+ bool nosat = false;
+
+ int argidx;
+ for (argidx = 1; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx] == "-n" && argidx+1 < SIZE(args)) {
+ num_iter = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-s" && argidx+1 < SIZE(args)) {
+ xorshift32_state = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-map" && argidx+1 < SIZE(args)) {
+ techmap_cmd += " -map " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-f" && argidx+1 < SIZE(args)) {
+ ilang_file = args[++argidx];
+ num_iter = 1;
+ continue;
+ }
+ if (args[argidx] == "-script" && argidx+1 < SIZE(args)) {
+ techmap_cmd = "script " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-simlib") {
+ techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc";
+ continue;
+ }
+ if (args[argidx] == "-const") {
+ constmode = true;
+ continue;
+ }
+ if (args[argidx] == "-nosat") {
+ nosat = true;
+ continue;
+ }
+ if (args[argidx] == "-v") {
+ verbose = true;
+ continue;
+ }
+ if (args[argidx] == "-vlog" && argidx+1 < SIZE(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());
+ continue;
+ }
+ break;
+ }
+
+ if (xorshift32_state == 0) {
+ xorshift32_state = time(NULL) & 0x7fffffff;
+ log("Rng seed value: %d\n", int(xorshift32_state));
+ }
+
+ std::map<std::string, std::string> cell_types;
+ std::vector<std::string> selected_cell_types;
+
+ cell_types["$not"] = "ASY";
+ cell_types["$pos"] = "ASY";
+ cell_types["$neg"] = "ASY";
+
+ cell_types["$and"] = "ABSY";
+ cell_types["$or"] = "ABSY";
+ cell_types["$xor"] = "ABSY";
+ cell_types["$xnor"] = "ABSY";
+
+ cell_types["$reduce_and"] = "ASY";
+ cell_types["$reduce_or"] = "ASY";
+ cell_types["$reduce_xor"] = "ASY";
+ cell_types["$reduce_xnor"] = "ASY";
+ cell_types["$reduce_bool"] = "ASY";
+
+ cell_types["$shl"] = "ABshY";
+ cell_types["$shr"] = "ABshY";
+ cell_types["$sshl"] = "ABshY";
+ cell_types["$sshr"] = "ABshY";
+ cell_types["$shift"] = "ABshY";
+ cell_types["$shiftx"] = "ABshY";
+
+ cell_types["$lt"] = "ABSY";
+ cell_types["$le"] = "ABSY";
+ cell_types["$eq"] = "ABSY";
+ cell_types["$ne"] = "ABSY";
+ // cell_types["$eqx"] = "ABSY";
+ // cell_types["$nex"] = "ABSY";
+ cell_types["$ge"] = "ABSY";
+ cell_types["$gt"] = "ABSY";
+
+ cell_types["$add"] = "ABSY";
+ cell_types["$sub"] = "ABSY";
+ cell_types["$mul"] = "ABSY";
+ cell_types["$div"] = "ABSY";
+ cell_types["$mod"] = "ABSY";
+ // cell_types["$pow"] = "ABsY";
+
+ cell_types["$logic_not"] = "ASY";
+ cell_types["$logic_and"] = "ABSY";
+ cell_types["$logic_or"] = "ABSY";
+
+ // cell_types["$mux"] = "A";
+ // cell_types["$pmux"] = "A";
+ // cell_types["$slice"] = "A";
+ // cell_types["$concat"] = "A";
+ // cell_types["$assert"] = "A";
+
+ cell_types["$lut"] = "*";
+ cell_types["$alu"] = "ABSY";
+ cell_types["$lcu"] = "*";
+ cell_types["$macc"] = "*";
+ cell_types["$fa"] = "*";
+
+ for (; argidx < SIZE(args); argidx++)
+ {
+ if (args[argidx].rfind("-", 0) == 0)
+ log_cmd_error("Unexpected option: %s\n", args[argidx].c_str());
+
+ if (args[argidx] == "all") {
+ for (auto &it : cell_types)
+ if (std::count(selected_cell_types.begin(), selected_cell_types.end(), it.first) == 0)
+ selected_cell_types.push_back(it.first);
+ continue;
+ }
+
+ if (cell_types.count(args[argidx]) == 0) {
+ std::string cell_type_list;
+ int charcount = 100;
+ for (auto &it : cell_types) {
+ if (charcount > 60) {
+ cell_type_list += "\n" + it.first;
+ charcount = 0;
+ } else
+ cell_type_list += " " + it.first;
+ charcount += SIZE(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());
+ }
+
+ if (std::count(selected_cell_types.begin(), selected_cell_types.end(), args[argidx]) == 0)
+ selected_cell_types.push_back(args[argidx]);
+ }
+
+ if (!ilang_file.empty()) {
+ if (!selected_cell_types.empty())
+ log_cmd_error("Do not specify any cell types when using -f.\n");
+ selected_cell_types.push_back("ilang");
+ }
+
+ if (selected_cell_types.empty())
+ log_cmd_error("No cell type to test specified.\n");
+
+ std::vector<std::string> uut_names;
+
+ for (auto cell_type : selected_cell_types)
+ for (int i = 0; i < num_iter; i++)
+ {
+ RTLIL::Design *design = new RTLIL::Design;
+ 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);
+ }
+ run_eval_test(design, verbose, nosat, uut_name, vlog_file);
+ delete design;
+ }
+
+ if (vlog_file.is_open()) {
+ vlog_file << "\nmodule testbench;\n";
+ for (auto &uut : uut_names)
+ vlog_file << stringf(" %s %s ();\n", uut.c_str(), uut.c_str());
+ vlog_file << " initial begin\n";
+ for (auto &uut : uut_names)
+ vlog_file << " " << uut << ".run;\n";
+ vlog_file << " end\n";
+ vlog_file << "endmodule\n";
+ }
+ }
+} TestCellPass;
+