diff options
-rw-r--r-- | passes/abc/abc.cc | 177 | ||||
-rw-r--r-- | passes/abc/blifparse.cc | 28 | ||||
-rw-r--r-- | passes/abc/blifparse.h | 2 |
3 files changed, 173 insertions, 34 deletions
diff --git a/passes/abc/abc.cc b/passes/abc/abc.cc index 1e7c66e14..efba43591 100644 --- a/passes/abc/abc.cc +++ b/passes/abc/abc.cc @@ -57,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); @@ -103,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"]; @@ -138,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; @@ -220,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]++; + } } } @@ -330,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++; @@ -339,6 +364,9 @@ 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] = '_'; @@ -347,6 +375,45 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std 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) @@ -366,7 +433,7 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std handle_loops(); - if (asprintf(&p, "%s/input.blif", 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)); @@ -426,8 +493,10 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std 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) - abort(); + log_abort(); if (si.type >= 0) count_gates++; } @@ -443,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)); @@ -459,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)); @@ -522,7 +591,8 @@ static void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std if (f == NULL) log_error("Can't open ABC output file `%s'.\n", p); - RTLIL::Design *mapped_design = abc_parse_blif(f); + 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); @@ -540,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)]); @@ -592,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; @@ -673,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); @@ -718,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"); @@ -734,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; @@ -768,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; @@ -782,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 825d5eab6..a630405c6 100644 --- a/passes/abc/blifparse.cc +++ b/passes/abc/blifparse.cc @@ -44,7 +44,7 @@ static bool read_next_line(char *buffer, int &line_count, FILE *f) } } -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; @@ -101,6 +101,32 @@ 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; 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 |