diff options
Diffstat (limited to 'passes')
-rw-r--r-- | passes/abc/Makefile.inc | 1 | ||||
-rw-r--r-- | passes/abc/abc.cc | 281 | ||||
-rw-r--r-- | passes/abc/blifparse.cc | 77 | ||||
-rw-r--r-- | passes/abc/blifparse.h | 2 | ||||
-rw-r--r-- | passes/abc/vlparse.cc | 227 | ||||
-rw-r--r-- | passes/abc/vlparse.h | 28 | ||||
-rw-r--r-- | passes/cmds/rename.cc | 45 | ||||
-rw-r--r-- | passes/cmds/select.cc | 20 | ||||
-rw-r--r-- | passes/extract/extract.cc | 2 | ||||
-rw-r--r-- | passes/memory/memory_collect.cc | 21 | ||||
-rw-r--r-- | passes/opt/opt_const.cc | 36 | ||||
-rw-r--r-- | passes/proc/proc_arst.cc | 4 | ||||
-rw-r--r-- | passes/sat/eval.cc | 2 | ||||
-rw-r--r-- | passes/sat/freduce.cc | 689 | ||||
-rw-r--r-- | passes/sat/sat.cc | 239 | ||||
-rw-r--r-- | passes/techmap/dfflibmap.cc | 55 | ||||
-rw-r--r-- | passes/techmap/simplemap.cc | 19 |
17 files changed, 1033 insertions, 715 deletions
diff --git a/passes/abc/Makefile.inc b/passes/abc/Makefile.inc index dbb7496cf..a7c5b02c6 100644 --- a/passes/abc/Makefile.inc +++ b/passes/abc/Makefile.inc @@ -1,7 +1,6 @@ ifeq ($(ENABLE_ABC),1) OBJS += passes/abc/abc.o -OBJS += passes/abc/vlparse.o OBJS += passes/abc/blifparse.o endif diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc index e37f896f2..efba43591 100644 --- a/passes/abc/abc.cc +++ b/passes/abc/abc.cc @@ -21,6 +21,10 @@ // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification // http://www.eecs.berkeley.edu/~alanmi/abc/ +// [[CITE]] Berkeley Logic Interchange Format (BLIF) +// University of California. Berkeley. July 28, 1992 +// http://www.ece.cmu.edu/~ee760/760docs/blif.pdf + // [[CITE]] Kahn's Topological sorting algorithm // 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 @@ -36,7 +40,6 @@ #include <dirent.h> #include <sstream> -#include "vlparse.h" #include "blifparse.h" struct gate_t @@ -54,6 +57,9 @@ static RTLIL::Module *module; static std::vector<gate_t> signal_list; static std::map<RTLIL::SigSpec, 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) { assert(sig.width == 1); @@ -100,6 +106,26 @@ static void mark_port(RTLIL::SigSpec sig) static void extract_cell(RTLIL::Cell *cell) { + 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"])) + return; + + RTLIL::SigSpec sig_d = cell->connections["\\D"]; + RTLIL::SigSpec sig_q = cell->connections["\\Q"]; + + assign_map.apply(sig_d); + assign_map.apply(sig_q); + + map_signal(sig_q, 'f', map_signal(sig_d)); + + module->cells.erase(cell->name); + delete cell; + return; + } + if (cell->type == "$_INV_") { RTLIL::SigSpec sig_a = cell->connections["\\A"]; @@ -135,7 +161,7 @@ static void extract_cell(RTLIL::Cell *cell) else if (cell->type == "$_XOR_") map_signal(sig_y, 'x', mapped_a, mapped_b); else - abort(); + log_abort(); module->cells.erase(cell->name); delete cell; @@ -217,20 +243,21 @@ static void handle_loops() // dot_f = fopen("test.dot", "w"); for (auto &g : signal_list) { - if (g.type == -1) { + if (g.type == -1 || g.type == 'f') { workpool.insert(g.id); - } - if (g.in1 >= 0) { - edges[g.in1].insert(g.id); - in_edges_count[g.id]++; - } - if (g.in2 >= 0 && g.in2 != g.in1) { - edges[g.in2].insert(g.id); - in_edges_count[g.id]++; - } - if (g.in3 >= 0 && g.in3 != g.in2 && g.in3 != g.in1) { - edges[g.in3].insert(g.id); - in_edges_count[g.id]++; + } else { + if (g.in1 >= 0) { + edges[g.in1].insert(g.id); + in_edges_count[g.id]++; + } + if (g.in2 >= 0 && g.in2 != g.in1) { + edges[g.in2].insert(g.id); + in_edges_count[g.id]++; + } + if (g.in3 >= 0 && g.in3 != g.in2 && g.in3 != g.in1) { + edges[g.in3].insert(g.id); + in_edges_count[g.id]++; + } } } @@ -327,7 +354,8 @@ static void handle_loops() fclose(dot_f); } -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) +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) { module = current_module; map_autoidx = RTLIL::autoidx++; @@ -336,14 +364,56 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std signal_list.clear(); assign_map.set(module); + clk_polarity = true; + clk_sig = RTLIL::SigSpec(); + char tempdir_name[] = "/tmp/yosys-abc-XXXXXX"; if (!cleanup) tempdir_name[0] = tempdir_name[4] = '_'; char *p = mkdtemp(tempdir_name); - log_header("Extracting gate netlist of module `%s' to `%s/input.v'..\n", module->name.c_str(), tempdir_name); + log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n", module->name.c_str(), tempdir_name); if (p == NULL) log_error("For some reason mkdtemp() failed!\n"); + 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 (dff_mode && clk_sig.width == 0) + { + int best_dff_counter = 0; + std::map<std::pair<bool, RTLIL::SigSpec>, int> dff_counters; + + 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"))); + if (++dff_counters[key] > best_dff_counter) { + best_dff_counter = dff_counters[key]; + clk_polarity = key.first; + clk_sig = key.second; + } + } + } + + if (dff_mode || !clk_str.empty()) { + if (clk_sig.width == 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) + mark_port(clk_sig); + std::vector<RTLIL::Cell*> cells; cells.reserve(module->cells.size()); for (auto &it : module->cells) @@ -363,60 +433,75 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std handle_loops(); - if (asprintf(&p, "%s/input.v", tempdir_name) < 0) abort(); + if (asprintf(&p, "%s/input.blif", tempdir_name) < 0) log_abort(); FILE *f = fopen(p, "wt"); if (f == NULL) log_error("Opening %s for writing failed: %s\n", p, strerror(errno)); free(p); - fprintf(f, "module netlist ("); - bool first = true; + fprintf(f, ".model netlist\n"); + + int count_input = 0; + fprintf(f, ".inputs"); for (auto &si : signal_list) { - if (!si.is_port) + if (!si.is_port || si.type >= 0) continue; - if (!first) - fprintf(f, ", "); - fprintf(f, "n%d", si.id); - first = false; + fprintf(f, " n%d", si.id); + count_input++; } - fprintf(f, "); // %s\n", module->name.c_str()); + fprintf(f, "\n"); - int count_input = 0, count_output = 0; + int count_output = 0; + fprintf(f, ".outputs"); for (auto &si : signal_list) { - if (si.is_port) { - if (si.type >= 0) - count_output++; - else - count_input++; - } - fprintf(f, "%s n%d; // %s\n", si.is_port ? si.type >= 0 ? - "output" : "input" : "wire", si.id, log_signal(si.sig)); + if (!si.is_port || si.type < 0) + continue; + fprintf(f, " n%d", si.id); + count_output++; } + fprintf(f, "\n"); + + for (auto &si : signal_list) + fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.sig)); + for (auto &si : signal_list) { assert(si.sig.width == 1 && si.sig.chunks.size() == 1); - if (si.sig.chunks[0].wire == NULL) - fprintf(f, "assign n%d = %c;\n", si.id, si.sig.chunks[0].data.bits[0] == RTLIL::State::S1 ? '1' : '0'); + if (si.sig.chunks[0].wire == NULL) { + fprintf(f, ".names n%d\n", si.id); + if (si.sig.chunks[0].data.bits[0] == RTLIL::State::S1) + fprintf(f, "1\n"); + } } int count_gates = 0; for (auto &si : signal_list) { - if (si.type == 'n') - fprintf(f, "not (n%d, n%d);\n", si.id, si.in1); - else if (si.type == 'a') - fprintf(f, "and (n%d, n%d, n%d);\n", si.id, si.in1, si.in2); - else if (si.type == 'o') - fprintf(f, "or (n%d, n%d, n%d);\n", si.id, si.in1, si.in2); - else if (si.type == 'x') - fprintf(f, "xor (n%d, n%d, n%d);\n", si.id, si.in1, si.in2); - else if (si.type == 'm') - fprintf(f, "assign n%d = n%d ? n%d : n%d;\n", si.id, si.in3, si.in2, si.in1); - else if (si.type >= 0) - abort(); + if (si.type == 'n') { + fprintf(f, ".names n%d n%d\n", si.in1, si.id); + fprintf(f, "0 1\n"); + } else if (si.type == 'a') { + 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') { + 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') { + 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') { + 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') { + fprintf(f, ".latch n%d n%d\n", si.in1, si.id); + } else if (si.type >= 0) + log_abort(); if (si.type >= 0) count_gates++; } - fprintf(f, "endmodule\n"); + fprintf(f, ".end\n"); fclose(f); log("Extracted %d gates and %zd wires to a netlist network with %d inputs and %d outputs.\n", @@ -427,7 +512,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std { log_header("Executing ABC.\n"); - if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) abort(); + if (asprintf(&p, "%s/stdcells.genlib", tempdir_name) < 0) log_abort(); f = fopen(p, "wt"); if (f == NULL) log_error("Opening %s for writing failed: %s\n", p, strerror(errno)); @@ -443,7 +528,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std free(p); if (lut_mode) { - if (asprintf(&p, "%s/lutdefs.txt", tempdir_name) < 0) abort(); + if (asprintf(&p, "%s/lutdefs.txt", tempdir_name) < 0) log_abort(); f = fopen(p, "wt"); if (f == NULL) log_error("Opening %s for writing failed: %s\n", p, strerror(errno)); @@ -457,7 +542,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std int buffer_pos = 0; if (!liberty_file.empty()) { buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, - "%s -s -c 'read_verilog %s/input.v; read_lib %s; ", + "%s -s -c 'read_blif %s/input.blif; read_lib %s; ", exe_file.c_str(), tempdir_name, liberty_file.c_str()); if (!constr_file.empty()) buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, @@ -470,21 +555,18 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std } else if (!script_file.empty()) buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, - "%s -s -c 'read_verilog %s/input.v; source %s; ", + "%s -s -c 'read_blif %s/input.blif; source %s; ", exe_file.c_str(), tempdir_name, script_file.c_str()); else if (lut_mode) buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, - "%s -s -c 'read_verilog %s/input.v; read_lut %s/lutdefs.txt; strash; balance; dch; if; ", + "%s -s -c 'read_blif %s/input.blif; read_lut %s/lutdefs.txt; strash; balance; dch; if; ", exe_file.c_str(), tempdir_name, tempdir_name); else buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, - "%s -s -c 'read_verilog %s/input.v; read_library %s/stdcells.genlib; strash; balance; dch; map; ", + "%s -s -c 'read_blif %s/input.blif; read_library %s/stdcells.genlib; strash; balance; dch; map; ", exe_file.c_str(), tempdir_name, tempdir_name); - if (lut_mode) - buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, "write_blif %s/output.blif' 2>&1", tempdir_name); - else - buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, "write_verilog %s/output.v' 2>&1", tempdir_name); + buffer_pos += snprintf(buffer+buffer_pos, 1024-buffer_pos, "write_blif %s/output.blif' 2>&1", tempdir_name); errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand f = popen(buffer, "r"); @@ -504,16 +586,14 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std } } - if (asprintf(&p, "%s/%s", tempdir_name, lut_mode ? "output.blif" : "output.v") < 0) abort(); + if (asprintf(&p, "%s/%s", tempdir_name, "output.blif") < 0) log_abort(); f = fopen(p, "rt"); if (f == NULL) log_error("Can't open ABC output file `%s'.\n", p); -#if 0 - RTLIL::Design *mapped_design = new RTLIL::Design; - frontend_register["verilog"]->execute(f, p, std::vector<std::string>(), mapped_design); -#else - RTLIL::Design *mapped_design = lut_mode ? abc_parse_blif(f) : abc_parse_verilog(f); -#endif + + bool builtin_lib = liberty_file.empty() && script_file.empty() && !lut_mode; + RTLIL::Design *mapped_design = abc_parse_blif(f, builtin_lib ? "\\DFF" : "\\_dff_"); + fclose(f); free(p); @@ -530,11 +610,11 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std } std::map<std::string, int> cell_stats; - if (liberty_file.empty() && script_file.empty() && !lut_mode) + if (builtin_lib) { for (auto &it : mapped_mod->cells) { RTLIL::Cell *c = it.second; - cell_stats[c->type.substr(1)]++; + 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)]); @@ -582,21 +662,46 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std design->select(module, cell); continue; } - assert(0); + 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; + design->select(module, cell); + continue; + } + log_abort(); } } else { - for (auto &it : mapped_mod->cells) { + for (auto &it : mapped_mod->cells) + { RTLIL::Cell *c = it.second; - cell_stats[c->type.substr(1)]++; - if (c->type == "$_const0_" || c->type == "$_const1_") { + 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["\\Y"].chunks[0].wire->name)]); - conn.second = RTLIL::SigSpec(c->type == "$_const0_" ? 0 : 1, 1); + conn.first = RTLIL::SigSpec(module->wires[remap_name(c->connections.begin()->second.chunks[0].wire->name)]); + conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1); module->connections.push_back(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; + design->select(module, cell); + continue; + } RTLIL::Cell *cell = new RTLIL::Cell; cell->type = c->type; cell->parameters = c->parameters; @@ -663,7 +768,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std 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) abort(); + if (asprintf(&p, "%s/%s", tempdir_name, namelist[i]->d_name) < 0) log_abort(); log("Removing `%s'.\n", p); remove(p); free(p); @@ -708,6 +813,16 @@ struct AbcPass : public Pass { log(" -lut <width>\n"); log(" generate netlist using luts of (max) the specified width.\n"); log("\n"); + log(" -dff\n"); + log(" also pass $_DFF_?_ cells through ABC (only one clock domain, if many\n"); + log(" clock domains are present in a module, the one with the largest number\n"); + log(" of $dff cells in it is used)\n"); + log("\n"); + log(" -clk [!]<signal-name>\n"); + log(" use the specified clock domain. (when this option is used in combination\n"); + log(" with -dff, then it falls back to the automatic dection of clock domain\n"); + log(" if the specified clock is not found in a module.)\n"); + log("\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"); @@ -724,8 +839,8 @@ struct AbcPass : public Pass { log_push(); std::string exe_file = rewrite_yosys_exe("yosys-abc"); - std::string script_file, liberty_file, constr_file; - bool cleanup = true; + std::string script_file, liberty_file, constr_file, clk_str; + bool dff_mode = false, cleanup = true; int lut_mode = 0; size_t argidx; @@ -758,6 +873,14 @@ struct AbcPass : public Pass { lut_mode = atoi(args[++argidx].c_str()); continue; } + if (arg == "-dff") { + dff_mode = true; + continue; + } + if (arg == "-clk" && argidx+1 < args.size() && lut_mode == 0) { + clk_str = args[++argidx]; + continue; + } if (arg == "-nocleanup") { cleanup = false; continue; @@ -772,7 +895,7 @@ struct AbcPass : public Pass { 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); + abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str); } assign_map.clear(); diff --git a/passes/abc/blifparse.cc b/passes/abc/blifparse.cc index 17acc843b..2d46d1a8e 100644 --- a/passes/abc/blifparse.cc +++ b/passes/abc/blifparse.cc @@ -22,29 +22,35 @@ #include <stdio.h> #include <string.h> -static bool read_next_line(char *buffer, int &line_count, FILE *f) +static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, FILE *f) { + int buffer_len = 0; buffer[0] = 0; while (1) { - int buffer_len = strlen(buffer); + buffer_len += strlen(buffer + buffer_len); while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' || buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n')) buffer[--buffer_len] = 0; + if (buffer_size-buffer_len < 4096) { + buffer_size *= 2; + buffer = (char*)realloc(buffer, buffer_size); + } + if (buffer_len == 0 || buffer[buffer_len-1] == '\\') { if (buffer[buffer_len-1] == '\\') buffer[--buffer_len] = 0; line_count++; - if (fgets(buffer+buffer_len, 4096-buffer_len, f) == NULL) + if (fgets(buffer+buffer_len, buffer_size-buffer_len, f) == NULL) return false; } else return true; } } -RTLIL::Design *abc_parse_blif(FILE *f) +RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name) { RTLIL::Design *design = new RTLIL::Design; RTLIL::Module *module = new RTLIL::Module; @@ -56,12 +62,13 @@ RTLIL::Design *abc_parse_blif(FILE *f) module->name = "\\netlist"; design->modules[module->name] = module; - char buffer[4096]; + size_t buffer_size = 4096; + char *buffer = (char*)malloc(buffer_size); int line_count = 0; while (1) { - if (!read_next_line(buffer, line_count, f)) + if (!read_next_line(buffer, buffer_size, line_count, f)) goto error; continue_without_read: @@ -83,8 +90,10 @@ RTLIL::Design *abc_parse_blif(FILE *f) if (!strcmp(cmd, ".model")) continue; - if (!strcmp(cmd, ".end")) + if (!strcmp(cmd, ".end")) { + free(buffer); return design; + } if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) { char *p; @@ -101,6 +110,58 @@ RTLIL::Design *abc_parse_blif(FILE *f) continue; } + if (!strcmp(cmd, ".latch")) + { + 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(q)) == 0) { + RTLIL::Wire *wire = new RTLIL::Wire; + wire->name = RTLIL::escape_id(q); + module->add(wire); + } + + 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); + 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); + + 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)); + } + continue; + } + if (!strcmp(cmd, ".names")) { char *p; @@ -122,7 +183,7 @@ RTLIL::Design *abc_parse_blif(FILE *f) if (input_sig.width == 0) { RTLIL::State state = RTLIL::State::Sa; while (1) { - if (!read_next_line(buffer, line_count, f)) + if (!read_next_line(buffer, buffer_size, line_count, f)) goto error; for (int i = 0; buffer[i]; i++) { if (buffer[i] == ' ' || buffer[i] == '\t') diff --git a/passes/abc/blifparse.h b/passes/abc/blifparse.h index 98afedac5..272e4e645 100644 --- a/passes/abc/blifparse.h +++ b/passes/abc/blifparse.h @@ -22,7 +22,7 @@ #include "kernel/rtlil.h" -extern RTLIL::Design *abc_parse_blif(FILE *f); +extern RTLIL::Design *abc_parse_blif(FILE *f, std::string dff_name); #endif diff --git a/passes/abc/vlparse.cc b/passes/abc/vlparse.cc deleted file mode 100644 index fe10f57b1..000000000 --- a/passes/abc/vlparse.cc +++ /dev/null @@ -1,227 +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. - * - */ - -#include "vlparse.h" -#include "kernel/log.h" -#include <stdio.h> -#include <string> - -static int lex_line, lex_tok; -static std::string lex_str; - -static int token(int tok) -{ - lex_tok = tok; -#if 0 - if (lex_tok == 256) - fprintf(stderr, "STR in line %d: >>%s<<\n", lex_line, lex_str.c_str()); - else if (tok >= 32 && tok < 255) - fprintf(stderr, "CHAR in line %d: >>%c<<\n", lex_line, lex_tok); - else - fprintf(stderr, "CHAR in line %d: %d\n", lex_line, lex_tok); -#endif - return tok; -} - -static int lex(FILE *f) -{ - int ch = getc(f); - - while (ch == ' ' || ch == '\t' || ch == '\n') { - if (ch == '\n') - lex_line++; - ch = getc(f); - } - - if (ch <= 0 || 255 < ch) - return token(lex_tok); - - if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_' || ch == '\'') { - lex_str = char(ch); - while (1) { - ch = getc(f); - if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_' || ch == '\'') { - lex_str += char(ch); - continue; - } - break; - } - ungetc(ch, f); - return token(256); - } - - if (ch == '/') { - ch = getc(f); - if (ch == '/') { - while (ch != '\n') - ch = getc(f); - ungetc(ch, f); - return lex(f); - } - ungetc(ch, f); - return token('/'); - } - - return token(ch); -} - -RTLIL::Design *abc_parse_verilog(FILE *f) -{ - RTLIL::Design *design = new RTLIL::Design; - RTLIL::Module *module; - RTLIL::Wire *wire; - RTLIL::Cell *cell; - - int port_count = 1; - lex_line = 1; - - // parse module header - if (lex(f) != 256 || lex_str != "module") - goto error; - if (lex(f) != 256) - goto error; - - module = new RTLIL::Module; - module->name = "\\" + lex_str; - design->modules[module->name] = module; - - if (lex(f) != '(') - goto error; - while (lex(f) != ')') { - if (lex_tok != 256 && lex_tok != ',') - goto error; - } - if (lex(f) != ';') - goto error; - - // parse module body - while (1) - { - if (lex(f) != 256) - goto error; - - if (lex_str == "endmodule") - return design; - - if (lex_str == "input" || lex_str == "output" || lex_str == "wire") - { - std::string mode = lex_str; - while (lex(f) != ';') { - if (lex_tok != 256 && lex_tok != ',') - goto error; - if (lex_tok == 256) { - // printf("%s [%s]\n", mode.c_str(), lex_str.c_str()); - wire = new RTLIL::Wire; - wire->name = "\\" + lex_str; - if (mode == "input") { - wire->port_id = port_count++; - wire->port_input = true; - } - if (mode == "output") { - wire->port_id = port_count++; - wire->port_output = true; - } - module->wires[wire->name] = wire; - } - } - } - else if (lex_str == "assign") - { - std::string lhs, rhs; - - if (lex(f) != 256) - goto error; - lhs = lex_str; - - if (lex(f) != '=') - goto error; - if (lex(f) != 256) - goto error; - rhs = lex_str; - - if (lex(f) != ';') - goto error; - - if (module->wires.count(RTLIL::escape_id(lhs)) == 0) - goto error; - - if (rhs == "1'b0") - module->connections.push_back(RTLIL::SigSig(module->wires.at(RTLIL::escape_id(lhs)), RTLIL::SigSpec(0, 1))); - else if (rhs == "1'b1") - module->connections.push_back(RTLIL::SigSig(module->wires.at(RTLIL::escape_id(lhs)), RTLIL::SigSpec(1, 1))); - else if (module->wires.count(RTLIL::escape_id(rhs)) > 0) - module->connections.push_back(RTLIL::SigSig(module->wires.at(RTLIL::escape_id(lhs)), module->wires.at(RTLIL::escape_id(rhs)))); - else - goto error; - } - else - { - std::string cell_type = lex_str; - - if (lex(f) != 256) - goto error; - - std::string cell_name = lex_str; - - if (lex(f) != '(') - goto error; - - // printf("cell [%s] [%s]\n", cell_type.c_str(), cell_name.c_str()); - cell = new RTLIL::Cell; - cell->type = "\\" + cell_type; - cell->name = "\\" + cell_name; - module->cells[cell->name] = cell; - - lex(f); - while (lex_tok != ')') - { - if (lex_tok != '.' || lex(f) != 256) - goto error; - - std::string cell_port = lex_str; - - if (lex(f) != '(' || lex(f) != 256) - goto error; - - std::string wire_name = lex_str; - - // printf(" [%s] <- [%s]\n", cell_port.c_str(), wire_name.c_str()); - if (module->wires.count("\\" + wire_name) == 0) - goto error; - cell->connections["\\" + cell_port] = RTLIL::SigSpec(module->wires["\\" + wire_name]); - - if (lex(f) != ')' || (lex(f) != ',' && lex_tok != ')')) - goto error; - while (lex_tok == ',') - lex(f); - } - - if (lex(f) != ';') - goto error; - } - } - -error: - log_error("Syntax error in line %d!\n", lex_line); - // delete design; - // return NULL; -} - diff --git a/passes/abc/vlparse.h b/passes/abc/vlparse.h deleted file mode 100644 index 9514c4190..000000000 --- a/passes/abc/vlparse.h +++ /dev/null @@ -1,28 +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 ABC_VLPARSE -#define ABC_VLPARSE - -#include "kernel/rtlil.h" - -extern RTLIL::Design *abc_parse_verilog(FILE *f); - -#endif - diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index a582de56d..519dce452 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -69,17 +69,30 @@ struct RenamePass : public Pass { log("Assign short auto-generated names to all selected wires and cells with private\n"); log("names.\n"); log("\n"); + log(" rename -hide [selection]\n"); + log("\n"); + log("Assign private names (the ones with $-prefix) to all selected wires and cells\n"); + log("with public names. This ignores all selected ports.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { bool flag_enumerate = false; + bool flag_hide = false; + bool got_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; - if (arg == "-enumerate") { + if (arg == "-enumerate" && !got_mode) { flag_enumerate = true; + got_mode = true; + continue; + } + if (arg == "-hide" && !got_mode) { + flag_hide = true; + got_mode = true; continue; } break; @@ -117,6 +130,36 @@ struct RenamePass : public Pass { } } else + if (flag_hide) + { + extra_args(args, argidx, design); + + 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) { + 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); + + std::map<RTLIL::IdString, RTLIL::Cell*> new_cells; + for (auto &it : module->cells) { + if (design->selected(module, it.second)) + if (it.first[0] == '\\') + it.second->name = NEW_ID; + new_cells[it.second->name] = it.second; + } + module->cells.swap(new_cells); + } + } + else { if (argidx+2 != args.size()) log_cmd_error("Invalid number of arguments!\n"); diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index 137f8618a..ec560772e 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -272,6 +272,21 @@ static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::v if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0) selected_wires.insert(it.second); + 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(); + + for (size_t i = 0; i < conn_lhs.size(); i++) { + if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL) + continue; + if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && lhs.selected_members[mod->name].count(conn_lhs[i].wire->name) == 0) + lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--; + if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && lhs.selected_members[mod->name].count(conn_rhs[i].wire->name) == 0) + lhs.selected_members[mod->name].insert(conn_rhs[i].wire->name), sel_objects++, max_objects--; + } + } + for (auto &cell : mod->cells) for (auto &conn : cell.second->connections) { @@ -514,7 +529,10 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } else { size_t pos = arg.find('/'); if (pos == std::string::npos) { - arg_mod = arg; + if (arg.find(':') == std::string::npos) + arg_mod = arg; + else + arg_mod = "*", arg_memb = arg; } else { arg_mod = arg.substr(0, pos); arg_memb = arg.substr(pos+1); diff --git a/passes/extract/extract.cc b/passes/extract/extract.cc index 0c639aeda..aa21e573a 100644 --- a/passes/extract/extract.cc +++ b/passes/extract/extract.cc @@ -499,6 +499,8 @@ struct ExtractPass : public Pass { solver.addSwappablePorts("$xnor", "\\A", "\\B"); solver.addSwappablePorts("$eq", "\\A", "\\B"); solver.addSwappablePorts("$ne", "\\A", "\\B"); + solver.addSwappablePorts("$eqx", "\\A", "\\B"); + solver.addSwappablePorts("$nex", "\\A", "\\B"); solver.addSwappablePorts("$add", "\\A", "\\B"); solver.addSwappablePorts("$mul", "\\A", "\\B"); solver.addSwappablePorts("$logic_and", "\\A", "\\B"); diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index ca1a3666f..ad4df228e 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -20,9 +20,19 @@ #include "kernel/register.h" #include "kernel/log.h" #include <sstream> +#include <algorithm> #include <stdlib.h> #include <assert.h> +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(); +} + static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) { log("Collecting $memrd and $memwr for memory `%s' in module `%s':\n", @@ -48,11 +58,18 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) RTLIL::SigSpec sig_rd_data; std::vector<std::string> del_cell_ids; + 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) + memcells.push_back(cell); + } + + std::sort(memcells.begin(), memcells.end(), memcells_cmp); + for (auto cell : memcells) + { if (cell->type == "$memwr" && cell->parameters["\\MEMID"].decode_string() == memory->name) { wr_ports++; diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc index b7b361e95..0ead97b4e 100644 --- a/passes/opt/opt_const.cc +++ b/passes/opt/opt_const.cc @@ -17,8 +17,6 @@ * */ -#undef MUX_UNDEF_SEL_TO_UNDEF_RESULTS - #include "opt_status.h" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -133,18 +131,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons ACTION_DO("\\Y", input.extract(2, 1)); if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1)); if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); -#ifdef MUX_UNDEF_SEL_TO_UNDEF_RESULTS if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1)); - // TODO: "10 " -> replace with "!S" gate - // TODO: "0 " -> replace with "B AND S" gate - // TODO: " 1 " -> replace with "A OR S" gate - // TODO: "1 " -> replace with "B OR !S" gate (?) - // TODO: " 0 " -> replace with "A AND !S" gate (?) - if (input.match(" *")) ACTION_DO_Y(x); -#endif + if (input.match("10 ")) { + cell->type = "$_INV_"; + cell->connections["\\A"] = input.extract(0, 1); + cell->connections.erase("\\B"); + cell->connections.erase("\\S"); + goto next_cell; + } + if (input.match("01*")) ACTION_DO_Y(x); + if (input.match("10*")) ACTION_DO_Y(x); } - if (cell->type == "$eq" || cell->type == "$ne") + 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"]; @@ -160,22 +159,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons assert(a.chunks.size() == b.chunks.size()); for (size_t i = 0; i < a.chunks.size(); i++) { - if (a.chunks[i].wire == NULL && a.chunks[i].data.bits[0] > RTLIL::State::S1) - continue; - if (b.chunks[i].wire == NULL && b.chunks[i].data.bits[0] > RTLIL::State::S1) + 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) { + 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); + goto next_cell; + } + if (a.chunks[i] == b.chunks[i]) continue; new_a.append(a.chunks[i]); new_b.append(b.chunks[i]); } if (new_a.width == 0) { - RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type == "$eq" ? RTLIL::State::S1 : RTLIL::State::S0); + 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); goto next_cell; } - if (new_a.width != a.width) { + if (new_a.width < a.width || new_b.width < b.width) { new_a.optimize(); new_b.optimize(); cell->connections["\\A"] = new_a; diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index 65dc97bdd..571946573 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -47,7 +47,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp polarity = !polarity; return check_signal(mod, cell->connections["\\A"], ref, polarity); } - if (cell->type == "$eq" && cell->connections["\\Y"] == signal) { + if ((cell->type == "$eq" || cell->type == "$eqx") && cell->connections["\\Y"] == signal) { if (cell->connections["\\A"].is_fully_const()) { if (!cell->connections["\\A"].as_bool()) polarity = !polarity; @@ -59,7 +59,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp return check_signal(mod, cell->connections["\\A"], ref, polarity); } } - if (cell->type == "$ne" && cell->connections["\\Y"] == signal) { + if ((cell->type == "$ne" || cell->type == "$nex") && cell->connections["\\Y"] == signal) { if (cell->connections["\\A"].is_fully_const()) { if (cell->connections["\\A"].as_bool()) polarity = !polarity; diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc index 5d0d35b69..5d36b474c 100644 --- a/passes/sat/eval.cc +++ b/passes/sat/eval.cc @@ -148,7 +148,7 @@ struct VlogHammerReporter ezDefaultSAT ez; SigMap sigmap(module); - SatGen satgen(&ez, design, &sigmap); + SatGen satgen(&ez, &sigmap); satgen.model_undef = model_undef; for (auto &c : module->cells) diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index d57fdd321..4b868b3c9 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -28,337 +28,466 @@ #include <string.h> #include <algorithm> -#define NUM_INITIAL_RANDOM_TEST_VECTORS 10 - namespace { -struct FreduceHelper +bool inv_mode; +int verbose_level; +typedef std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>>> drivers_t; + +struct equiv_bit_t { - RTLIL::Design *design; - RTLIL::Module *module; - bool try_mode; + int depth; + bool inverted; + RTLIL::Cell *drv; + RTLIL::SigBit bit; + + bool operator<(const equiv_bit_t &other) const { + if (depth != other.depth) + return depth < other.depth; + if (inverted != other.inverted) + return inverted < other.inverted; + if (drv != other.drv) + return drv < other.drv; + return bit < other.bit; + } +}; + +struct FindReducedInputs +{ + SigMap &sigmap; + drivers_t &drivers; ezDefaultSAT ez; - SigMap sigmap; - CellTypes ct; + std::set<RTLIL::Cell*> ez_cells; SatGen satgen; - ConstEval ce; - SigPool inputs, nodes; - RTLIL::SigSpec input_sigs; - - SigSet<RTLIL::SigSpec> source_signals; - std::vector<RTLIL::Const> test_vectors; - std::map<RTLIL::SigSpec, RTLIL::Const> node_to_data; - std::map<RTLIL::SigSpec, RTLIL::SigSpec> node_result; - - uint32_t xorshift32_state; - - uint32_t xorshift32() { - xorshift32_state ^= xorshift32_state << 13; - xorshift32_state ^= xorshift32_state >> 17; - xorshift32_state ^= xorshift32_state << 5; - return xorshift32_state; + FindReducedInputs(SigMap &sigmap, drivers_t &drivers) : + sigmap(sigmap), drivers(drivers), satgen(&ez, &sigmap) + { + satgen.model_undef = true; } - FreduceHelper(RTLIL::Design *design, RTLIL::Module *module, bool try_mode) : - design(design), module(module), try_mode(try_mode), - sigmap(module), satgen(&ez, design, &sigmap), ce(module) + void register_cone_worker(std::set<RTLIL::SigBit> &pi, std::set<RTLIL::SigBit> &sigdone, RTLIL::SigBit out) { - ct.setup_internals(); - ct.setup_stdcells(); + if (out.wire == NULL) + return; + if (sigdone.count(out) != 0) + return; + sigdone.insert(out); + + if (drivers.count(out) != 0) { + std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> &drv = drivers.at(out); + if (ez_cells.count(drv.first) == 0) { + satgen.setContext(&sigmap, "A"); + if (!satgen.importCell(drv.first)) + log_error("Can't create SAT model for cell %s (%s)!\n", RTLIL::id2cstr(drv.first->name), RTLIL::id2cstr(drv.first->type)); + satgen.setContext(&sigmap, "B"); + if (!satgen.importCell(drv.first)) + log_abort(); + ez_cells.insert(drv.first); + } + for (auto &bit : drv.second) + register_cone_worker(pi, sigdone, bit); + } else + pi.insert(out); + } - xorshift32_state = 123456789; - xorshift32(); - xorshift32(); - xorshift32(); + void register_cone(std::vector<RTLIL::SigBit> &pi, RTLIL::SigBit out) + { + std::set<RTLIL::SigBit> pi_set, sigdone; + register_cone_worker(pi_set, sigdone, out); + pi.clear(); + pi.insert(pi.end(), pi_set.begin(), pi_set.end()); } - bool run_test(RTLIL::SigSpec test_vec) + void analyze(std::vector<RTLIL::SigBit> &reduced_inputs, RTLIL::SigBit output) { - ce.clear(); - ce.set(input_sigs, test_vec.as_const()); - - for (auto &bit : nodes.bits) { - RTLIL::SigSpec nodesig(bit.first, 1, bit.second), nodeval = nodesig; - if (!ce.eval(nodeval)) { - if (!try_mode) - log_error("Evaluation of node %s failed!\n", log_signal(nodesig)); - log("FAILED: Evaluation of node %s failed!\n", log_signal(nodesig)); - return false; + if (verbose_level >= 1) + log(" Analyzing input cone for signal %s:\n", log_signal(output)); + + std::vector<RTLIL::SigBit> pi; + register_cone(pi, output); + + if (verbose_level >= 1) + log(" Found %d input signals and %d cells.\n", int(pi.size()), int(ez_cells.size())); + + satgen.setContext(&sigmap, "A"); + int output_a = satgen.importSigSpec(output).front(); + int output_undef_a = satgen.importUndefSigSpec(output).front(); + ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, satgen.importUndefSigSpec(pi)))); + + satgen.setContext(&sigmap, "B"); + int output_b = satgen.importSigSpec(output).front(); + int output_undef_b = satgen.importUndefSigSpec(output).front(); + ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, satgen.importUndefSigSpec(pi)))); + + for (size_t i = 0; i < pi.size(); i++) + { + RTLIL::SigSpec test_sig(pi[i]); + RTLIL::SigSpec rest_sig(pi); + rest_sig.remove(i, 1); + + int test_sig_a, test_sig_b; + std::vector<int> rest_sig_a, rest_sig_b; + + satgen.setContext(&sigmap, "A"); + test_sig_a = satgen.importSigSpec(test_sig).front(); + rest_sig_a = satgen.importSigSpec(rest_sig); + + satgen.setContext(&sigmap, "B"); + test_sig_b = satgen.importSigSpec(test_sig).front(); + rest_sig_b = satgen.importSigSpec(rest_sig); + + if (ez.solve(ez.vec_eq(rest_sig_a, rest_sig_b), ez.XOR(output_a, output_b), ez.XOR(test_sig_a, test_sig_b), ez.NOT(output_undef_a), ez.NOT(output_undef_b))) { + if (verbose_level >= 2) + log(" Result for input %s: pass\n", log_signal(test_sig)); + reduced_inputs.push_back(pi[i]); + } else { + if (verbose_level >= 2) + log(" Result for input %s: strip\n", log_signal(test_sig)); } - node_to_data[nodesig].bits.push_back(nodeval.as_const().bits.at(0)); } - return true; + if (verbose_level >= 1) + log(" Reduced input cone contains %d inputs.\n", int(reduced_inputs.size())); } +}; - void dump_node_data() - { - int max_node_len = 20; - for (auto &it : node_to_data) - max_node_len = std::max(max_node_len, int(strlen(log_signal(it.first)))); - log(" full node fingerprints:\n"); - for (auto &it : node_to_data) - log(" %-*s %s\n", max_node_len+5, log_signal(it.first), log_signal(it.second)); - } +struct PerformReduction +{ + SigMap &sigmap; + drivers_t &drivers; + std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs; - bool check(RTLIL::SigSpec sig1, RTLIL::SigSpec sig2) + ezDefaultSAT ez; + SatGen satgen; + + std::vector<int> sat_pi, sat_out, sat_def; + std::vector<RTLIL::SigBit> out_bits, pi_bits; + std::vector<bool> out_inverted; + std::vector<int> out_depth; + + int register_cone_worker(std::set<RTLIL::Cell*> &celldone, std::map<RTLIL::SigBit, int> &sigdepth, RTLIL::SigBit out) { - log(" performing SAT proof: %s == %s ->", log_signal(sig1), log_signal(sig2)); - - std::vector<int> vec1 = satgen.importSigSpec(sig1); - std::vector<int> vec2 = satgen.importSigSpec(sig2); - std::vector<int> model = satgen.importSigSpec(input_sigs); - std::vector<bool> testvect; - - if (ez.solve(model, testvect, ez.vec_ne(vec1, vec2))) { - RTLIL::SigSpec testvect_sig; - for (int i = 0; i < input_sigs.width; i++) - testvect_sig.append(testvect.at(i) ? RTLIL::State::S1 : RTLIL::State::S0); - testvect_sig.optimize(); - log(" failed: %s\n", log_signal(testvect_sig)); - test_vectors.push_back(testvect_sig.as_const()); - if (!run_test(testvect_sig)) - return false; + if (out.wire == NULL) + 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); + if (celldone.count(drv.first) == 0) { + if (!satgen.importCell(drv.first)) + 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; + 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; } else { - log(" success.\n"); - if (!sig1.is_fully_const()) - node_result[sig1].append(sig2); - if (!sig2.is_fully_const()) - node_result[sig2].append(sig1); + pi_bits.push_back(out); + sat_pi.push_back(satgen.importSigSpec(out).front()); + ez.assume(ez.NOT(satgen.importUndefSigSpec(out).front())); } - return true; + + return sigdepth[out]; } - bool analyze_const() + PerformReduction(SigMap &sigmap, drivers_t &drivers, std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> &inv_pairs, std::vector<RTLIL::SigBit> &bits) : + sigmap(sigmap), drivers(drivers), inv_pairs(inv_pairs), satgen(&ez, &sigmap), out_bits(bits) { - for (auto &it : node_to_data) - { - if (node_result.count(it.first)) - continue; - if (it.second == RTLIL::Const(RTLIL::State::S0, it.second.bits.size())) - if (!check(it.first, RTLIL::SigSpec(RTLIL::State::S0))) - return false; - if (it.second == RTLIL::Const(RTLIL::State::S1, it.second.bits.size())) - if (!check(it.first, RTLIL::SigSpec(RTLIL::State::S1))) - return false; + satgen.model_undef = true; + + std::set<RTLIL::Cell*> celldone; + std::map<RTLIL::SigBit, int> sigdepth; + + for (auto &bit : bits) { + out_depth.push_back(register_cone_worker(celldone, sigdepth, bit)); + sat_out.push_back(satgen.importSigSpec(bit).front()); + sat_def.push_back(ez.NOT(satgen.importUndefSigSpec(bit).front())); } - return true; + + if (inv_mode) { + if (!ez.solve(sat_out, out_inverted, ez.expression(ezSAT::OpAnd, sat_def))) + log_error("Solving for initial model failed!\n"); + for (size_t i = 0; i < sat_out.size(); i++) + if (out_inverted.at(i)) + sat_out[i] = ez.NOT(sat_out[i]); + } else + out_inverted = std::vector<bool>(sat_out.size(), false); } - bool analyze_alias() + void analyze(std::vector<std::set<int>> &results, std::map<int, int> &results_map, std::vector<int> &bucket, int level) { - restart: - std::map<RTLIL::Const, RTLIL::SigSpec> reverse_map; + if (bucket.size() <= 1) + return; - for (auto &it : node_to_data) { - if (node_result.count(it.first) && node_result.at(it.first).is_fully_const()) - continue; - reverse_map[it.second].append(it.first); + if (verbose_level == 1) + log("%*s Trying to shatter bucket with %d signals.\n", 2*level, "", int(bucket.size())); + + if (verbose_level > 1) { + std::vector<RTLIL::SigBit> bucket_sigbits; + for (int idx : bucket) + bucket_sigbits.push_back(out_bits[idx]); + RTLIL::SigSpec bucket_sig(bucket_sigbits); + bucket_sig.optimize(); + log("%*s Trying to shatter bucket with %d signals: %s\n", 2*level, "", int(bucket.size()), log_signal(bucket_sig)); } - for (auto &it : reverse_map) - { - if (it.second.width <= 1) - continue; + std::vector<int> sat_list, sat_inv_list; + for (int idx : bucket) { + sat_list.push_back(ez.AND(sat_out[idx], sat_def[idx])); + sat_inv_list.push_back(ez.AND(ez.NOT(sat_out[idx]), sat_def[idx])); + } - it.second.expand(); - for (int i = 0; i < it.second.width; i++) - for (int j = i+1; j < it.second.width; j++) { - RTLIL::SigSpec sig1 = it.second.chunks.at(i), sig2 = it.second.chunks.at(j); - if (node_result.count(sig1) && node_result.count(sig2)) - continue; - if (node_to_data.at(sig1) != node_to_data.at(sig2)) - goto restart; - if (!check(it.second.chunks.at(i), it.second.chunks.at(j))) - return false; + std::vector<int> modelVars = sat_out; + std::vector<bool> model; + + modelVars.insert(modelVars.end(), sat_def.begin(), sat_def.end()); + if (verbose_level >= 2) + modelVars.insert(modelVars.end(), sat_pi.begin(), sat_pi.end()); + + if (ez.solve(modelVars, model, ez.expression(ezSAT::OpOr, sat_list), ez.expression(ezSAT::OpOr, sat_inv_list))) + { + if (verbose_level >= 2) { + for (size_t i = 0; i < pi_bits.size(); i++) + log("%*s -> PI %c == %s\n", 2*level, "", model[2*sat_out.size() + i] ? '1' : '0', log_signal(pi_bits[i])); + for (int idx : bucket) + log("%*s -> OUT %c == %s%s\n", 2*level, "", model[sat_out.size() + idx] ? model[idx] ? '1' : '0' : 'x', + out_inverted.at(idx) ? "~" : "", log_signal(out_bits[idx])); } - } - return true; - } - bool toproot_helper(RTLIL::SigSpec cursor, RTLIL::SigSpec stoplist, RTLIL::SigSpec &donelist, int level) - { - // log(" %*schecking %s: %s\n", level*2, "", log_signal(cursor), log_signal(stoplist)); + std::vector<int> buckets_a; + std::vector<int> buckets_b; - if (stoplist.extract(cursor).width != 0) { - // log(" %*s STOP\n", level*2, ""); - return false; + for (int idx : bucket) { + if (!model[sat_out.size() + idx] || model[idx]) + buckets_a.push_back(idx); + if (!model[sat_out.size() + idx] || !model[idx]) + buckets_b.push_back(idx); + } + analyze(results, results_map, buckets_a, level+1); + analyze(results, results_map, buckets_b, level+1); } + else + { + std::vector<int> undef_slaves; + + for (int idx : bucket) { + std::vector<int> sat_def_list; + for (int idx2 : bucket) + if (idx != idx2) + sat_def_list.push_back(sat_def[idx2]); + if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list))) + undef_slaves.push_back(idx); + } + + if (undef_slaves.size() == bucket.size()) { + if (verbose_level >= 1) + log("%*s Complex undef overlap. None of the signals covers the others.\n", 2*level, ""); + // FIXME: We could try to further shatter a group with complex undef overlaps + return; + } - if (donelist.extract(cursor).width != 0) - return true; + for (int idx : undef_slaves) + out_depth[idx] = std::numeric_limits<int>::max(); - stoplist.append(cursor); - std::set<RTLIL::SigSpec> next = source_signals.find(cursor); + if (verbose_level >= 1) { + log("%*s Found %d equivialent signals:", 2*level, "", int(bucket.size())); + for (int idx : bucket) + log("%s%s%s", idx == bucket.front() ? " " : ", ", out_inverted[idx] ? "~" : "", log_signal(out_bits[idx])); + log("\n"); + } - for (auto &it : next) - if (!toproot_helper(it, stoplist, donelist, level+1)) - return false; + int result_idx = -1; + for (int idx : bucket) { + if (results_map.count(idx) == 0) + continue; + if (result_idx == -1) { + result_idx = results_map.at(idx); + continue; + } + int result_idx2 = results_map.at(idx); + results[result_idx].insert(results[result_idx2].begin(), results[result_idx2].end()); + for (int idx2 : results[result_idx2]) + results_map[idx2] = result_idx; + results[result_idx2].clear(); + } - donelist.append(cursor); - return true; - } + if (result_idx == -1) { + result_idx = results.size(); + results.push_back(std::set<int>()); + } - // KISS topological sort of bits in signal. return one element of sig - // without dependencies to the others (or empty if input is not a DAG). - RTLIL::SigSpec toproot(RTLIL::SigSpec sig) - { - sig.expand(); - // log(" finding topological root in %s:\n", log_signal(sig)); - for (auto &c : sig.chunks) { - RTLIL::SigSpec stoplist = sig, donelist; - stoplist.remove(c); - // log(" testing %s as root:\n", log_signal(c)); - if (toproot_helper(c, stoplist, donelist, 0)) - return c; + results[result_idx].insert(bucket.begin(), bucket.end()); } - return RTLIL::SigSpec(); } - void update_design_for_group(RTLIL::SigSpec root, RTLIL::SigSpec rest) + void analyze(std::vector<std::vector<equiv_bit_t>> &results) { - SigPool unlink; - unlink.add(rest); + std::vector<int> bucket; + for (size_t i = 0; i < sat_out.size(); i++) + bucket.push_back(i); + + std::vector<std::set<int>> results_buf; + std::map<int, int> results_map; + analyze(results_buf, results_map, bucket, 1); - for (auto &cell_it : module->cells) { - RTLIL::Cell *cell = cell_it.second; - if (!ct.cell_known(cell->type)) + for (auto &r : results_buf) + { + if (r.size() <= 1) continue; - for (auto &conn : cell->connections) - if (ct.cell_output(cell->type, conn.first)) { - RTLIL::SigSpec sig = sigmap(conn.second); - sig.expand(); - bool did_something = false; - for (auto &c : sig.chunks) { - if (c.wire == NULL || !unlink.check_any(c)) - continue; - c.wire = new RTLIL::Wire; - c.wire->name = NEW_ID; - module->add(c.wire); - assert(c.width == 1); - c.offset = 0; - did_something = true; - } - if (did_something) { - sig.optimize(); - conn.second = sig; - } - } - } - rest.expand(); - for (auto &c : rest.chunks) { - if (c.wire != NULL && !root.is_fully_const()) { - source_signals.erase(c); - source_signals.insert(c, root); + std::vector<equiv_bit_t> result; + + for (int idx : r) { + equiv_bit_t bit; + bit.depth = out_depth[idx]; + bit.inverted = out_inverted[idx]; + bit.drv = drivers.count(out_bits[idx]) ? drivers.at(out_bits[idx]).first : NULL; + bit.bit = out_bits[idx]; + result.push_back(bit); } - module->connections.push_back(RTLIL::SigSig(c, root)); + + std::sort(result.begin(), result.end()); + + if (result.front().inverted) + for (auto &bit : result) + bit.inverted = !bit.inverted; + + for (size_t i = 1; i < result.size(); i++) { + std::pair<RTLIL::SigBit, RTLIL::SigBit> p(result[0].bit, result[i].bit); + if (inv_pairs.count(p) != 0) + result.erase(result.begin() + i); + } + + if (result.size() > 1) + results.push_back(result); } } +}; - void analyze_groups() +struct FreduceWorker +{ + RTLIL::Module *module; + + SigMap sigmap; + drivers_t drivers; + std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> inv_pairs; + + FreduceWorker(RTLIL::Module *module) : module(module), sigmap(module) { - SigMap to_group_major; - for (auto &it : node_result) { - it.second.expand(); - for (auto &c : it.second.chunks) - to_group_major.add(it.first, c); - } + } - std::map<RTLIL::SigSpec, RTLIL::SigSpec> major_to_rest; - for (auto &it : node_result) - major_to_rest[to_group_major(it.first)].append(it.first); + int run() + { + log("Running functional reduction on module %s:\n", RTLIL::id2cstr(module->name)); - for (auto &it : major_to_rest) - { - RTLIL::SigSig group = it; + CellTypes ct; + ct.setup_internals(); + ct.setup_stdcells(); - if (!it.first.is_fully_const()) { - group.first = toproot(it.second); - if (group.first.width == 0) { - log("Operating on non-DAG input: failed to find topological root for `%s'.\n", log_signal(it.second)); - return; + std::vector<std::set<RTLIL::SigBit>> batches; + for (auto &it : module->wires) + if (it.second->port_input) + batches.push_back(sigmap(it.second).to_sigbit_set()); + for (auto &it : module->cells) { + if (ct.cell_known(it.second->type)) { + std::set<RTLIL::SigBit> inputs, outputs; + 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()); + else + inputs.insert(bits.begin(), bits.end()); } - group.second.remove(group.first); + std::pair<RTLIL::Cell*, std::set<RTLIL::SigBit>> drv(it.second, inputs); + for (auto &bit : outputs) + drivers[bit] = drv; + batches.push_back(outputs); } + 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")))); + } + + int bits_count = 0; + std::map<std::vector<RTLIL::SigBit>, std::vector<RTLIL::SigBit>> buckets; + buckets[std::vector<RTLIL::SigBit>()].push_back(RTLIL::SigBit(RTLIL::State::S0)); + buckets[std::vector<RTLIL::SigBit>()].push_back(RTLIL::SigBit(RTLIL::State::S1)); + for (auto &batch : batches) + { + RTLIL::SigSpec batch_sig(std::vector<RTLIL::SigBit>(batch.begin(), batch.end())); + batch_sig.optimize(); - group.first.optimize(); - group.second.sort_and_unify(); + log(" Finding reduced input cone for signal batch %s%c\n", log_signal(batch_sig), verbose_level ? ':' : '.'); - log(" found group: %s -> %s\n", log_signal(group.first), log_signal(group.second)); - update_design_for_group(group.first, group.second); + FindReducedInputs infinder(sigmap, drivers); + for (auto &bit : batch) { + std::vector<RTLIL::SigBit> inputs; + infinder.analyze(inputs, bit); + buckets[inputs].push_back(bit); + bits_count++; + } } - } + log(" Sorted %d signal bits into %d buckets.\n", bits_count, int(buckets.size())); - void run() - { - log("\nFunctionally reduce module %s:\n", RTLIL::id2cstr(module->name)); - - // find inputs and nodes (nets driven by internal cells) - // add all internal cells to sat solver - - for (auto &cell_it : module->cells) { - RTLIL::Cell *cell = cell_it.second; - if (!ct.cell_known(cell->type)) + std::vector<std::vector<equiv_bit_t>> equiv; + for (auto &bucket : buckets) + { + if (bucket.second.size() == 1) continue; - RTLIL::SigSpec cell_inputs, cell_outputs; - for (auto &conn : cell->connections) - if (ct.cell_output(cell->type, conn.first)) { - nodes.add(sigmap(conn.second)); - cell_outputs.append(sigmap(conn.second)); - } else { - inputs.add(sigmap(conn.second)); - cell_inputs.append(sigmap(conn.second)); - } - cell_inputs.sort_and_unify(); - cell_outputs.sort_and_unify(); - cell_inputs.expand(); - for (auto &c : cell_inputs.chunks) - if (c.wire != NULL) - source_signals.insert(cell_outputs, c); - if (!satgen.importCell(cell)) - log_error("Failed to import cell to SAT solver: %s (%s)\n", - RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); - } - inputs.del(nodes); - nodes.add(inputs); - log(" found %d nodes (%d inputs).\n", int(nodes.size()), int(inputs.size())); - - // initialise input_sigs and add all-zero, all-one and a few random test vectors - - input_sigs = inputs.export_all(); - test_vectors.push_back(RTLIL::SigSpec(RTLIL::State::S0, input_sigs.width).as_const()); - test_vectors.push_back(RTLIL::SigSpec(RTLIL::State::S1, input_sigs.width).as_const()); - - for (int i = 0; i < NUM_INITIAL_RANDOM_TEST_VECTORS; i++) { - RTLIL::SigSpec sig; - for (int j = 0; j < input_sigs.width; j++) - sig.append(xorshift32() % 2 ? RTLIL::State::S1 : RTLIL::State::S0); - sig.optimize(); - assert(sig.width == input_sigs.width); - test_vectors.push_back(sig.as_const()); - } - for (auto &test_vec : test_vectors) - if (!run_test(test_vec)) - return; + RTLIL::SigSpec bucket_sig(bucket.second); + bucket_sig.optimize(); - // run the analysis and update design + log(" Trying to shatter bucket %s%c\n", log_signal(bucket_sig), verbose_level ? ':' : '.'); + PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second); + worker.analyze(equiv); + } - if (!analyze_const()) - return; + 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)); + + RTLIL::SigSpec inv_sig; + for (size_t i = 1; i < grp.size(); i++) + { + 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) + sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second); + + if (grp[i].inverted) + { + if (inv_sig.width == 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); + } - if (!analyze_alias()) - return; + module->connections.push_back(RTLIL::SigSig(grp[i].bit, inv_sig)); + } + else + module->connections.push_back(RTLIL::SigSig(grp[i].bit, grp[0].bit)); - log(" input vector: %s\n", log_signal(input_sigs)); - for (auto &test_vec : test_vectors) - log(" test vector: %s\n", log_signal(test_vec)); + rewired_sigbits++; + } + } - dump_node_data(); - analyze_groups(); + log(" Rewired a total of %d signal bits in module %s.\n", rewired_sigbits, RTLIL::id2cstr(module->name)); + return rewired_sigbits; } }; @@ -374,43 +503,51 @@ 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("removed.\n"); + log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\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"); - log(" -try\n"); - log(" do not issue an error when the analysis fails.\n"); - log(" (usually beacause of logic loops in the design)\n"); + log(" -v, -vv\n"); + log(" enable verbose or very verbose output\n"); + log("\n"); + log(" -inv\n"); + log(" enable explicit handling of inverted signals\n"); log("\n"); - // log(" -enable_invert\n"); - // log(" also detect nodes that are inverse to each other.\n"); - // log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - bool enable_invert = false; - bool try_mode = false; + verbose_level = 0; + inv_mode = false; log_header("Executing FREDUCE pass (perform functional reduction).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-enable_invert") { - enable_invert = true; + if (args[argidx] == "-v") { + verbose_level = 1; continue; } - if (args[argidx] == "-try") { - try_mode = true; + if (args[argidx] == "-vv") { + verbose_level = 2; + continue; + } + if (args[argidx] == "-inv") { + inv_mode = true; continue; } break; } extra_args(args, argidx, design); - for (auto &mod_it : design->modules) - { + int bitcount = 0; + for (auto &mod_it : design->modules) { RTLIL::Module *module = mod_it.second; if (design->selected(module)) - FreduceHelper(design, module, try_mode).run(); + bitcount += FreduceWorker(module).run(); } + + log("Rewired a total of %d signal bits.\n", bitcount); } } FreducePass; diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index e330dfa6d..fef99dfc0 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -44,14 +44,14 @@ struct SatHelper SatGen satgen; // additional constraints - std::vector<std::pair<std::string, std::string>> sets, prove, sets_init; + std::vector<std::pair<std::string, std::string>> sets, prove, prove_x, sets_init; std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at; std::map<int, std::vector<std::string>> unsets_at; // undef constraints bool enable_undef, set_init_undef; - std::vector<std::string> sets_def, sets_undef, sets_all_undef; - std::map<int, std::vector<std::string>> sets_def_at, sets_undef_at, sets_all_undef_at; + std::vector<std::string> sets_def, sets_any_undef, sets_all_undef; + std::map<int, std::vector<std::string>> sets_def_at, sets_any_undef_at, sets_all_undef_at; // model variables std::vector<std::string> shows; @@ -61,7 +61,7 @@ struct SatHelper bool gotTimeout; SatHelper(RTLIL::Design *design, RTLIL::Module *module, bool enable_undef) : - design(design), module(module), sigmap(module), ct(design), satgen(&ez, design, &sigmap) + design(design), module(module), sigmap(module), ct(design), satgen(&ez, &sigmap) { this->enable_undef = enable_undef; satgen.model_undef = enable_undef; @@ -202,6 +202,71 @@ struct SatHelper check_undef_enabled(big_lhs), check_undef_enabled(big_rhs); ez.assume(satgen.signals_eq(big_lhs, big_rhs, timestep)); + // 0 = sets_def + // 1 = sets_any_undef + // 2 = sets_all_undef + std::set<RTLIL::SigSpec> sets_def_undef[3]; + + for (auto &s : sets_def) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[0].insert(sig); + } + + for (auto &s : sets_any_undef) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[1].insert(sig); + } + + for (auto &s : sets_all_undef) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[2].insert(sig); + } + + for (auto &s : sets_def_at[timestep]) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[0].insert(sig); + sets_def_undef[1].erase(sig); + sets_def_undef[2].erase(sig); + } + + for (auto &s : sets_any_undef_at[timestep]) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[0].erase(sig); + sets_def_undef[1].insert(sig); + sets_def_undef[2].erase(sig); + } + + for (auto &s : sets_all_undef_at[timestep]) { + RTLIL::SigSpec sig; + if (!RTLIL::SigSpec::parse(sig, module, s)) + log_cmd_error("Failed to parse set-def expression `%s'.\n", s.c_str()); + sets_def_undef[0].erase(sig); + sets_def_undef[1].erase(sig); + sets_def_undef[2].insert(sig); + } + + 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)); + std::vector<int> undef_sig = satgen.importUndefSigSpec(sig, timestep); + if (t == 0) + ez.assume(ez.NOT(ez.expression(ezSAT::OpOr, undef_sig))); + if (t == 1) + ez.assume(ez.expression(ezSAT::OpOr, undef_sig)); + if (t == 2) + ez.assume(ez.expression(ezSAT::OpAnd, undef_sig)); + } + int import_cell_counter = 0; for (auto &c : module->cells) if (design->selected(module, c.second)) { @@ -219,34 +284,75 @@ struct SatHelper int setup_proof(int timestep = -1) { - assert(prove.size() > 0); + assert(prove.size() + prove_x.size() > 0); RTLIL::SigSpec big_lhs, big_rhs; + std::vector<int> prove_bits; - for (auto &s : prove) + if (prove.size() > 0) { - RTLIL::SigSpec lhs, rhs; + for (auto &s : prove) + { + RTLIL::SigSpec lhs, rhs; + + if (!RTLIL::SigSpec::parse(lhs, module, s.first)) + log_cmd_error("Failed to parse lhs proof expression `%s'.\n", s.first.c_str()); + if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second)) + log_cmd_error("Failed to parse rhs proof expression `%s'.\n", s.second.c_str()); + show_signal_pool.add(sigmap(lhs)); + show_signal_pool.add(sigmap(rhs)); + + if (lhs.width != rhs.width) + 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); + + log("Import proof-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs)); + big_lhs.remove2(lhs, &big_rhs); + big_lhs.append(lhs); + big_rhs.append(rhs); + } - if (!RTLIL::SigSpec::parse(lhs, module, s.first)) - log_cmd_error("Failed to parse lhs proof expression `%s'.\n", s.first.c_str()); - if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second)) - log_cmd_error("Failed to parse rhs proof expression `%s'.\n", s.second.c_str()); - show_signal_pool.add(sigmap(lhs)); - show_signal_pool.add(sigmap(rhs)); + log("Final proof equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs)); + check_undef_enabled(big_lhs), check_undef_enabled(big_rhs); + prove_bits.push_back(satgen.signals_eq(big_lhs, big_rhs, timestep)); + } - if (lhs.width != rhs.width) - 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); + if (prove_x.size() > 0) + { + for (auto &s : prove_x) + { + RTLIL::SigSpec lhs, rhs; + + if (!RTLIL::SigSpec::parse(lhs, module, s.first)) + log_cmd_error("Failed to parse lhs proof-x expression `%s'.\n", s.first.c_str()); + if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second)) + log_cmd_error("Failed to parse rhs proof-x expression `%s'.\n", s.second.c_str()); + show_signal_pool.add(sigmap(lhs)); + show_signal_pool.add(sigmap(rhs)); + + if (lhs.width != rhs.width) + 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); + + log("Import proof-x-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs)); + big_lhs.remove2(lhs, &big_rhs); + big_lhs.append(lhs); + big_rhs.append(rhs); + } - log("Import proof-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs)); - big_lhs.remove2(lhs, &big_rhs); - big_lhs.append(lhs); - big_rhs.append(rhs); + log("Final proof-x equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs)); + + std::vector<int> value_lhs = satgen.importDefSigSpec(big_lhs, timestep); + std::vector<int> value_rhs = satgen.importDefSigSpec(big_rhs, timestep); + + std::vector<int> undef_lhs = satgen.importUndefSigSpec(big_lhs, timestep); + std::vector<int> undef_rhs = satgen.importUndefSigSpec(big_rhs, timestep); + + for (size_t i = 0; i < value_lhs.size(); i++) + prove_bits.push_back(ez.OR(undef_lhs.at(i), ez.AND(ez.NOT(undef_rhs.at(i)), ez.NOT(ez.XOR(value_lhs.at(i), value_rhs.at(i)))))); } - log("Final proof equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs)); - check_undef_enabled(big_lhs), check_undef_enabled(big_rhs); - return satgen.signals_eq(big_lhs, big_rhs, timestep); + return ez.expression(ezSAT::OpAnd, prove_bits); } void force_unique_state(int timestep_from, int timestep_to) @@ -567,17 +673,18 @@ struct SatPass : public Pass { log(" -set <signal> <value>\n"); log(" set the specified signal to the specified value.\n"); log("\n"); - #if 0 log(" -set-def <signal>\n"); log(" add a constraint that all bits of the given signal must be defined\n"); log("\n"); - log(" -set-undef <signal>\n"); + log(" -set-any-undef <signal>\n"); log(" add a constraint that at least one bit of the given signal is undefined\n"); log("\n"); log(" -set-all-undef <signal>\n"); log(" add a constraint that all bits of the given signal are undefined\n"); log("\n"); - #endif + log(" -set-def-inputs\n"); + log(" add -set-def constraints for all module inputs\n"); + log("\n"); log(" -show <signal>\n"); log(" show the model for the specified signal. if no -show option is\n"); log(" passed then a set of signals to be shown is automatically selected.\n"); @@ -596,13 +703,11 @@ struct SatPass : public Pass { log(" set or unset the specified signal to the specified value in the\n"); log(" given timestep. this has priority over a -set for the same signal.\n"); log("\n"); - #if 0 - log(" -set-def <N> <signal>\n"); - log(" -set-undef <N> <signal>\n"); - log(" -set-all-undef <N> <signal>\n"); + 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("\n"); - #endif log(" -set-init <signal> <value>\n"); log(" set the initial value for the register driving the signal to the value\n"); log("\n"); @@ -617,6 +722,10 @@ struct SatPass : public Pass { log(" induction proof it is proven that the condition holds forever after\n"); log(" the number of time steps passed using -seq.\n"); log("\n"); + log(" -prove-x <signal> <value>\n"); + log(" Like -prove, but an undef (x) bit in the lhs matches any value on\n"); + log(" the right hand side. Useful for equivialence checking.\n"); + log("\n"); log(" -maxsteps <N>\n"); log(" Set a maximum length for the induction.\n"); log("\n"); @@ -632,13 +741,13 @@ struct SatPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - std::vector<std::pair<std::string, std::string>> sets, sets_init, prove; + std::vector<std::pair<std::string, std::string>> sets, sets_init, prove, prove_x; 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_undef_at, sets_all_undef_at; - std::vector<std::string> shows, sets_def, sets_undef, sets_all_undef; + 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; - bool verify = false, fail_on_timeout = false, enable_undef = false; - bool ignore_div_by_zero = false, set_init_undef = false, max_undef = true; + bool verify = false, fail_on_timeout = false, enable_undef = false, set_def_inputs = false; + bool ignore_div_by_zero = false, set_init_undef = false, max_undef = false; log_header("Executing SAT pass (solving SAT problems in the circuit).\n"); @@ -682,23 +791,28 @@ struct SatPass : public Pass { max_undef = true; continue; } + if (args[argidx] == "-set-def-inputs") { + enable_undef = true; + set_def_inputs = true; + continue; + } if (args[argidx] == "-set" && argidx+2 < args.size()) { std::string lhs = args[++argidx]; std::string rhs = args[++argidx]; sets.push_back(std::pair<std::string, std::string>(lhs, rhs)); continue; } - if (args[argidx] == "-set-def" && argidx+2 < args.size()) { + if (args[argidx] == "-set-def" && argidx+1 < args.size()) { sets_def.push_back(args[++argidx]); enable_undef = true; continue; } - if (args[argidx] == "-set-undef" && argidx+2 < args.size()) { - sets_undef.push_back(args[++argidx]); + if (args[argidx] == "-set-any-undef" && argidx+1 < args.size()) { + sets_any_undef.push_back(args[++argidx]); enable_undef = true; continue; } - if (args[argidx] == "-set-all-undef" && argidx+2 < args.size()) { + if (args[argidx] == "-set-all-undef" && argidx+1 < args.size()) { sets_all_undef.push_back(args[++argidx]); enable_undef = true; continue; @@ -709,6 +823,13 @@ struct SatPass : public Pass { prove.push_back(std::pair<std::string, std::string>(lhs, rhs)); continue; } + if (args[argidx] == "-prove-x" && argidx+2 < args.size()) { + std::string lhs = args[++argidx]; + std::string rhs = args[++argidx]; + prove_x.push_back(std::pair<std::string, std::string>(lhs, rhs)); + enable_undef = true; + continue; + } if (args[argidx] == "-seq" && argidx+1 < args.size()) { seq_len = atoi(args[++argidx].c_str()); continue; @@ -731,9 +852,9 @@ struct SatPass : public Pass { enable_undef = true; continue; } - if (args[argidx] == "-set-undef-at" && argidx+2 < args.size()) { + if (args[argidx] == "-set-any-undef-at" && argidx+2 < args.size()) { int timestep = atoi(args[++argidx].c_str()); - sets_undef_at[timestep].push_back(args[++argidx]); + sets_any_undef_at[timestep].push_back(args[++argidx]); enable_undef = true; continue; } @@ -773,10 +894,16 @@ struct SatPass : public Pass { if (module == NULL) log_cmd_error("Can't perform SAT on an empty selection!\n"); - if (prove.size() == 0 && verify) + if (prove.size() + prove_x.size() == 0 && verify) log_cmd_error("Got -verify but nothing to prove!\n"); - if (prove.size() > 0 && seq_len > 0) + if (set_def_inputs) { + for (auto &it : module->wires) + if (it.second->port_input) + sets_def.push_back(it.second->name); + } + + if (prove.size() + prove_x.size() > 0 && seq_len > 0) { if (loopcount > 0 || max_undef) log_cmd_error("The options -max, -all, and -max_undef are not supported for temporal induction proofs!\n"); @@ -786,15 +913,16 @@ struct SatPass : public Pass { basecase.sets = sets; basecase.prove = prove; + basecase.prove_x = prove_x; basecase.sets_at = sets_at; basecase.unsets_at = unsets_at; basecase.shows = shows; basecase.timeout = timeout; basecase.sets_def = sets_def; - basecase.sets_undef = sets_undef; + basecase.sets_any_undef = sets_any_undef; basecase.sets_all_undef = sets_all_undef; basecase.sets_def_at = sets_def_at; - basecase.sets_undef_at = sets_undef_at; + basecase.sets_any_undef_at = sets_any_undef_at; basecase.sets_all_undef_at = sets_all_undef_at; basecase.sets_init = sets_init; basecase.set_init_undef = set_init_undef; @@ -806,16 +934,12 @@ struct SatPass : public Pass { inductstep.sets = sets; inductstep.prove = prove; + inductstep.prove_x = prove_x; inductstep.shows = shows; inductstep.timeout = timeout; inductstep.sets_def = sets_def; - inductstep.sets_undef = sets_undef; + inductstep.sets_any_undef = sets_any_undef; inductstep.sets_all_undef = sets_all_undef; - inductstep.sets_def_at = sets_def_at; - inductstep.sets_undef_at = sets_undef_at; - inductstep.sets_all_undef_at = sets_all_undef_at; - inductstep.sets_init = sets_init; - inductstep.set_init_undef = set_init_undef; inductstep.satgen.ignore_div_by_zero = ignore_div_by_zero; inductstep.setup(1); @@ -896,15 +1020,16 @@ struct SatPass : public Pass { sathelper.sets = sets; sathelper.prove = prove; + sathelper.prove_x = prove_x; sathelper.sets_at = sets_at; sathelper.unsets_at = unsets_at; sathelper.shows = shows; sathelper.timeout = timeout; sathelper.sets_def = sets_def; - sathelper.sets_undef = sets_undef; + sathelper.sets_any_undef = sets_any_undef; sathelper.sets_all_undef = sets_all_undef; sathelper.sets_def_at = sets_def_at; - sathelper.sets_undef_at = sets_undef_at; + sathelper.sets_any_undef_at = sets_any_undef_at; sathelper.sets_all_undef_at = sets_all_undef_at; sathelper.sets_init = sets_init; sathelper.set_init_undef = set_init_undef; @@ -912,7 +1037,7 @@ struct SatPass : public Pass { if (seq_len == 0) { sathelper.setup(); - if (sathelper.prove.size() > 0) + if (sathelper.prove.size() + sathelper.prove_x.size() > 0) sathelper.ez.assume(sathelper.ez.NOT(sathelper.setup_proof())); } else { for (int timestep = 1; timestep <= seq_len; timestep++) @@ -939,7 +1064,7 @@ struct SatPass : public Pass { sathelper.maximize_undefs(); } - if (prove.size() == 0) { + if (prove.size() + prove_x.size() == 0) { log("SAT solving finished - model found:\n"); } else { log("SAT proof finished - model found: FAIL!\n"); @@ -965,7 +1090,7 @@ struct SatPass : public Pass { goto timeout; if (rerun_counter) log("SAT solving finished - no more models found (after %d distinct solutions).\n", rerun_counter); - else if (prove.size() == 0) + else if (prove.size() + prove_x.size() == 0) log("SAT solving finished - no model found.\n"); else { log("SAT proof finished - no model found: SUCCESS!\n"); diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 0324afa84..40caf7801 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -106,6 +106,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; + float best_cell_area = 0; if (ast->id != "library") log_error("Format error in liberty file.\n"); @@ -141,6 +142,11 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool this_cell_ports[cell_rst_pin] = 'R'; this_cell_ports[cell_next_pin] = 'D'; + float area = 0; + LibertyAst *ar = cell->find("area"); + if (ar != NULL && !ar->value.empty()) + area = atof(ar->value.c_str()); + int num_pins = 0; bool found_output = false; for (auto pin : cell->children) @@ -174,14 +180,18 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool if (!found_output || (best_cell != NULL && num_pins > best_cell_pins)) continue; + if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area) + continue; + best_cell = cell; best_cell_pins = num_pins; + best_cell_area = area; best_cell_ports.swap(this_cell_ports); continue_cell_loop:; } if (best_cell != NULL) { - log(" cell %s is a direct match for cell type %s.\n", best_cell->args[0].c_str(), cell_type.substr(1).c_str()); + log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str()); cell_mappings[cell_type].cell_name = best_cell->args[0]; cell_mappings[cell_type].ports = best_cell_ports; } @@ -192,6 +202,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; + float best_cell_area = 0; if (ast->id != "library") log_error("Format error in liberty file.\n"); @@ -223,6 +234,11 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo this_cell_ports[cell_clr_pin] = 'R'; this_cell_ports[cell_next_pin] = 'D'; + float area = 0; + LibertyAst *ar = cell->find("area"); + if (ar != NULL && !ar->value.empty()) + area = atof(ar->value.c_str()); + int num_pins = 0; bool found_output = false; for (auto pin : cell->children) @@ -256,14 +272,18 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo if (!found_output || (best_cell != NULL && num_pins > best_cell_pins)) continue; + if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area) + continue; + best_cell = cell; best_cell_pins = num_pins; + best_cell_area = area; best_cell_ports.swap(this_cell_ports); continue_cell_loop:; } if (best_cell != NULL) { - log(" cell %s is a direct match for cell type %s.\n", best_cell->args[0].c_str(), cell_type.substr(1).c_str()); + log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str()); cell_mappings[cell_type].cell_name = best_cell->args[0]; cell_mappings[cell_type].ports = best_cell_ports; } @@ -399,6 +419,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) 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; } @@ -473,16 +494,26 @@ struct DfflibmapPass : public Pass { find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false); find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true); - bool keep_running = true; - while (keep_running) { - keep_running = false; - keep_running |= expand_cellmap("$_DFF_*_", "C"); - keep_running |= expand_cellmap("$_DFF_*??_", "C"); - keep_running |= expand_cellmap("$_DFF_?*?_", "R"); - keep_running |= expand_cellmap("$_DFF_??*_", "DQ"); - keep_running |= expand_cellmap("$_DFFSR_*??_", "C"); - keep_running |= expand_cellmap("$_DFFSR_?*?_", "S"); - keep_running |= expand_cellmap("$_DFFSR_??*_", "R"); + // try to implement as many cells as possible just by inverting + // the SET and RESET pins. If necessary, implement cell types + // by inverting both D and Q. Only invert clock pins if there + // is no other way of implementing the cell. + while (1) + { + if (expand_cellmap("$_DFF_?*?_", "R") || + expand_cellmap("$_DFFSR_?*?_", "S") || + expand_cellmap("$_DFFSR_??*_", "R")) + continue; + + if (expand_cellmap("$_DFF_??*_", "DQ")) + continue; + + if (expand_cellmap("$_DFF_*_", "C") || + expand_cellmap("$_DFF_*??_", "C") || + expand_cellmap("$_DFFSR_*??_", "C")) + continue; + + break; } map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN0_"); diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index fbd86d591..e06a80bbd 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -60,16 +60,28 @@ static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell) 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_y = cell->connections.at("\\Y"); + + module->connections.push_back(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->connections.at("\\A"); - sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool()); + 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(width, cell->parameters.at("\\B_SIGNED").as_bool()); + sig_b.extend_u0(width, cell->parameters.at("\\B_SIGNED").as_bool()); sig_b.expand(); RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); @@ -454,6 +466,7 @@ void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL:: { mappers["$not"] = simplemap_not; mappers["$pos"] = simplemap_pos; + mappers["$bu0"] = simplemap_bu0; mappers["$and"] = simplemap_bitop; mappers["$or"] = simplemap_bitop; mappers["$xor"] = simplemap_bitop; @@ -485,7 +498,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, $and, $or, $xor, $xnor\n"); + log(" $not, $pos, $bu0, $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"); |