Added abc -dff and -clk support
authorClifford Wolf <clifford@clifford.at>
Tue, 31 Dec 2013 20:25:09 +0000 (21:25 +0100)
committerClifford Wolf <clifford@clifford.at>
Tue, 31 Dec 2013 20:25:09 +0000 (21:25 +0100)
passes/abc/abc.cc
passes/abc/blifparse.cc
passes/abc/blifparse.h

index 1e7c66e1442da90b51bfb84af74e46e3b46367d6..efba43591d3ce5263ec084ecc67242e5a93d1ea2 100644 (file)
@@ -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();
index 825d5eab67b8a9fe83bf6715d0e9316d9497e6f5..a630405c63fd4b1523e486b62071174d6ac69284 100644 (file)
@@ -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;
index 98afedac562e68c9994050498444ebe4e674830f..272e4e6459708310ccdec4ed8e583da6b2cd136d 100644 (file)
@@ -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