Run "peepopt" in generic "synth" pass and "synth_ice40"
[yosys.git] / techlibs / ice40 / synth_ice40.cc
index 92d53f4abecf27cf97e2b9fcb77e40bc9e3ac929..f5249e567980e9136b26341217850aeae299cb34 100644 (file)
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
-bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
+struct SynthIce40Pass : public ScriptPass
 {
-       if (label == run_from)
-               active = true;
-       if (label == run_to)
-               active = false;
-       return active;
-}
+       SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { }
 
-struct SynthIce40Pass : public Pass {
-       SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { }
-       virtual void help()
+       void help() YS_OVERRIDE
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
                log("    synth_ice40 [options]\n");
                log("\n");
-               log("This command runs synthesis for iCE40 FPGAs. This work is experimental.\n");
+               log("This command runs synthesis for iCE40 FPGAs.\n");
                log("\n");
                log("    -top <module>\n");
-               log("        use the specified module as top module (default='top')\n");
+               log("        use the specified module as top module\n");
                log("\n");
                log("    -blif <file>\n");
                log("        write the design to the specified BLIF file. writing of an output file\n");
                log("        is omitted if this parameter is not specified.\n");
                log("\n");
                log("    -edif <file>\n");
-               log("        write the design to the specified edif file. writing of an output file\n");
+               log("        write the design to the specified EDIF file. writing of an output file\n");
+               log("        is omitted if this parameter is not specified.\n");
+               log("\n");
+               log("    -json <file>\n");
+               log("        write the design to the specified JSON file. writing of an output file\n");
                log("        is omitted if this parameter is not specified.\n");
                log("\n");
                log("    -run <from_label>:<to_label>\n");
@@ -66,84 +63,68 @@ struct SynthIce40Pass : public Pass {
                log("    -retime\n");
                log("        run 'abc' with -dff option\n");
                log("\n");
+               log("    -relut\n");
+               log("        combine LUTs after synthesis\n");
+               log("\n");
                log("    -nocarry\n");
                log("        do not use SB_CARRY cells in output netlist\n");
                log("\n");
-               log("    -nobram\n");
-               log("        do not use SB_RAM40_4K* cells in output netlist\n");
-               log("\n");
-               log("    -abc2\n");
-               log("        run two passes of 'abc' for slightly improved logic density\n");
+               log("    -nodffe\n");
+               log("        do not use SB_DFFE* cells in output netlist\n");
                log("\n");
+               log("    -dffe_min_ce_use <min_ce_use>\n");
+               log("        do not use SB_DFFE* cells if the resulting CE line would go to less\n");
+               log("        than min_ce_use SB_DFFE*in output netlist\n");
                log("\n");
-               log("The following commands are executed by this synthesis command:\n");
-               log("\n");
-               log("    begin:\n");
-               log("        read_verilog -lib +/ice40/cells_sim.v\n");
-               log("        hierarchy -check -top <top>\n");
-               log("\n");
-               log("    flatten:         (unless -noflatten)\n");
-               log("        proc\n");
-               log("        flatten\n");
-               log("        tribuf -logic\n");
-               log("\n");
-               log("    coarse:\n");
-               log("        synth -run coarse\n");
-               log("\n");
-               log("    bram:            (skip if -nobram)\n");
-               log("        memory_bram -rules +/ice40/brams.txt\n");
-               log("        techmap -map +/ice40/brams_map.v\n");
-               log("\n");
-               log("    fine:\n");
-               log("        opt -fast -mux_undef -undriven -fine\n");
-               log("        memory_map\n");
-               log("        opt -undriven -fine\n");
-               log("        techmap -map +/techmap.v [-map +/ice40/arith_map.v]\n");
-               log("        abc -dff     (only if -retime)\n");
-               log("        ice40_opt\n");
+               log("    -nobram\n");
+               log("        do not use SB_RAM40_4K* cells in output netlist\n");
                log("\n");
-               log("    map_ffs:\n");
-               log("        dffsr2dff\n");
-               log("        dff2dffe -direct-match $_DFF_*\n");
-               log("        techmap -map +/ice40/cells_map.v\n");
-               log("        opt_const -mux_undef\n");
-               log("        simplemap\n");
-               log("        ice40_ffinit\n");
-               log("        ice40_ffssr\n");
-               log("        ice40_opt -full\n");
+               log("    -dsp\n");
+               log("        use iCE40 UltraPlus DSP cells for large arithmetic\n");
                log("\n");
-               log("    map_luts:\n");
-               log("        abc          (only if -abc2)\n");
-               log("        ice40_opt    (only if -abc2)\n");
-               log("        abc -lut 4\n");
-               log("        clean\n");
+               log("    -noabc\n");
+               log("        use built-in Yosys LUT techmapping instead of abc\n");
                log("\n");
-               log("    map_cells:\n");
-               log("        techmap -map +/ice40/cells_map.v\n");
-               log("        clean\n");
+               log("    -abc2\n");
+               log("        run two passes of 'abc' for slightly improved logic density\n");
                log("\n");
-               log("    check:\n");
-               log("        hierarchy -check\n");
-               log("        stat\n");
-               log("        check -noinit\n");
+               log("    -vpr\n");
+               log("        generate an output netlist (and BLIF file) suitable for VPR\n");
+               log("        (this feature is experimental and incomplete)\n");
                log("\n");
-               log("    blif:\n");
-               log("        write_blif -gates -attr -param <file-name>\n");
                log("\n");
-               log("    edif:\n");
-               log("        write_edif <file-name>\n");
+               log("The following commands are executed by this synthesis command:\n");
+               help_script();
                log("\n");
        }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+
+       string top_opt, blif_file, edif_file, json_file;
+       bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
+       int min_ce_use;
+
+       void clear_flags() YS_OVERRIDE
+       {
+               top_opt = "-auto-top";
+               blif_file = "";
+               edif_file = "";
+               json_file = "";
+               nocarry = false;
+               nodffe = false;
+               min_ce_use = -1;
+               nobram = false;
+               dsp = false;
+               flatten = true;
+               retime = false;
+               relut = false;
+               noabc = false;
+               abc2 = false;
+               vpr = false;
+       }
+
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
-               std::string top_opt = "-auto-top";
-               std::string run_from, run_to;
-               std::string blif_file, edif_file;
-               bool nocarry = false;
-               bool nobram = false;
-               bool flatten = true;
-               bool retime = false;
-               bool abc2 = false;
+               string run_from, run_to;
+               clear_flags();
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
@@ -160,6 +141,10 @@ struct SynthIce40Pass : public Pass {
                                edif_file = args[++argidx];
                                continue;
                        }
+                       if (args[argidx] == "-json" && argidx+1 < args.size()) {
+                               json_file = args[++argidx];
+                               continue;
+                       }
                        if (args[argidx] == "-run" && argidx+1 < args.size()) {
                                size_t pos = args[argidx+1].find(':');
                                if (pos == std::string::npos)
@@ -180,116 +165,204 @@ struct SynthIce40Pass : public Pass {
                                retime = true;
                                continue;
                        }
+                       if (args[argidx] == "-relut") {
+                               relut = true;
+                               continue;
+                       }
                        if (args[argidx] == "-nocarry") {
                                nocarry = true;
                                continue;
                        }
+                       if (args[argidx] == "-nodffe") {
+                               nodffe = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-dffe_min_ce_use" && argidx+1 < args.size()) {
+                               min_ce_use = std::stoi(args[++argidx]);
+                               continue;
+                       }
                        if (args[argidx] == "-nobram") {
                                nobram = true;
                                continue;
                        }
+                       if (args[argidx] == "-dsp") {
+                               dsp = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-noabc") {
+                               noabc = true;
+                               continue;
+                       }
                        if (args[argidx] == "-abc2") {
                                abc2 = true;
                                continue;
                        }
+                       if (args[argidx] == "-vpr") {
+                               vpr = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
 
                if (!design->full_selection())
-                       log_cmd_error("This comannd only operates on fully selected designs!\n");
+                       log_cmd_error("This command only operates on fully selected designs!\n");
 
-               bool active = run_from.empty();
-
-               log_header("Executing SYNTH_ICE40 pass.\n");
+               log_header(design, "Executing SYNTH_ICE40 pass.\n");
                log_push();
 
-               if (check_label(active, run_from, run_to, "begin"))
+               run_script(design, run_from, run_to);
+
+               log_pop();
+       }
+
+       void script() YS_OVERRIDE
+       {
+               if (check_label("begin"))
+               {
+                       run("read_verilog -lib +/ice40/cells_sim.v");
+                       run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+                       run("proc");
+               }
+
+               if (flatten && check_label("flatten", "(unless -noflatten)"))
                {
-                       Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v");
-                       Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
+                       run("flatten");
+                       run("tribuf -logic");
+                       run("deminout");
                }
 
-               if (flatten && check_label(active, run_from, run_to, "flatten"))
+               if (check_label("coarse"))
                {
-                       Pass::call(design, "proc");
-                       Pass::call(design, "flatten");
-                       Pass::call(design, "tribuf -logic");
+                       run("opt_expr");
+                       run("opt_clean");
+                       run("check");
+                       run("opt");
+                       run("wreduce");
+                       run("peepopt");
+                       run("opt_clean");
+                       run("share");
+                       run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
+                       run("opt_expr");
+                       run("opt_clean");
+                       if (help_mode || dsp)
+                               run("ice40_dsp", "(if -dsp)");
+                       run("alumacc");
+                       run("opt");
+                       run("fsm");
+                       run("opt -fast");
+                       run("memory -nomap");
+                       run("opt_clean");
                }
 
-               if (check_label(active, run_from, run_to, "coarse"))
+               if (!nobram && check_label("bram", "(skip if -nobram)"))
                {
-                       Pass::call(design, "synth -run coarse");
+                       run("memory_bram -rules +/ice40/brams.txt");
+                       run("techmap -map +/ice40/brams_map.v");
+                       run("ice40_braminit");
                }
 
-               if (!nobram && check_label(active, run_from, run_to, "bram"))
+               if (check_label("map"))
                {
-                       Pass::call(design, "memory_bram -rules +/ice40/brams.txt");
-                       Pass::call(design, "techmap -map +/ice40/brams_map.v");
+                       run("opt -fast -mux_undef -undriven -fine");
+                       run("memory_map");
+                       run("opt -undriven -fine");
                }
 
-               if (check_label(active, run_from, run_to, "fine"))
+               if (check_label("map_gates"))
                {
-                       Pass::call(design, "opt -fast -mux_undef -undriven -fine");
-                       Pass::call(design, "memory_map");
-                       Pass::call(design, "opt -undriven -fine");
                        if (nocarry)
-                               Pass::call(design, "techmap");
+                               run("techmap");
                        else
-                               Pass::call(design, "techmap -map +/techmap.v -map +/ice40/arith_map.v");
-                       if (retime)
-                               Pass::call(design, "abc -dff");
-                       Pass::call(design, "ice40_opt");
+                               run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
+                       if (retime || help_mode)
+                               run("abc -dff", "(only if -retime)");
+                       run("ice40_opt");
                }
 
-               if (check_label(active, run_from, run_to, "map_ffs"))
+               if (check_label("map_ffs"))
                {
-                       Pass::call(design, "dffsr2dff");
-                       Pass::call(design, "dff2dffe -direct-match $_DFF_*");
-                       Pass::call(design, "techmap -map +/ice40/cells_map.v");
-                       Pass::call(design, "opt_const -mux_undef");
-                       Pass::call(design, "simplemap");
-                       Pass::call(design, "ice40_ffinit");
-                       Pass::call(design, "ice40_ffssr");
-                       Pass::call(design, "ice40_opt -full");
+                       run("dffsr2dff");
+                       if (!nodffe)
+                               run("dff2dffe -direct-match $_DFF_*");
+                       if (min_ce_use >= 0) {
+                               run("opt_merge");
+                               run(stringf("dff2dffe -unmap-mince %d", min_ce_use));
+                       }
+                       run("techmap -D NO_LUT -map +/ice40/cells_map.v");
+                       run("opt_expr -mux_undef");
+                       run("simplemap");
+                       run("ice40_ffinit");
+                       run("ice40_ffssr");
+                       run("ice40_opt -full");
                }
 
-               if (check_label(active, run_from, run_to, "map_luts"))
+               if (check_label("map_luts"))
                {
-                       if (abc2) {
-                               Pass::call(design, "abc");
-                               Pass::call(design, "ice40_opt");
+                       if (abc2 || help_mode) {
+                               run("abc", "      (only if -abc2)");
+                               run("ice40_opt", "(only if -abc2)");
+                       }
+                       run("techmap -map +/ice40/latches_map.v");
+                       if (noabc || help_mode) {
+                               run("simplemap", "                               (only if -noabc)");
+                               run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
+                       }
+                       if (!noabc) {
+                               run("abc -dress -lut 4", "(skip if -noabc)");
+                       }
+                       run("clean");
+                       if (relut || help_mode) {
+                               run("ice40_unlut", "                            (only if -relut)");
+                               run("opt_lut -dlogic SB_CARRY:I0=1:I1=2:CI=3", "(only if -relut)");
                        }
-                       Pass::call(design, "abc -lut 4");
-                       Pass::call(design, "clean");
                }
 
-               if (check_label(active, run_from, run_to, "map_cells"))
+               if (check_label("map_cells"))
                {
-                       Pass::call(design, "techmap -map +/ice40/cells_map.v");
-                       Pass::call(design, "clean");
+                       if (vpr)
+                               run("techmap -D NO_LUT -map +/ice40/cells_map.v");
+                       else
+                               run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)");
+
+                       run("clean");
                }
 
-               if (check_label(active, run_from, run_to, "check"))
+               if (check_label("check"))
                {
-                       Pass::call(design, "hierarchy -check");
-                       Pass::call(design, "stat");
-                       Pass::call(design, "check -noinit");
+                       run("hierarchy -check");
+                       run("stat");
+                       run("check -noinit");
                }
 
-               if (check_label(active, run_from, run_to, "blif"))
+               if (check_label("blif"))
                {
-                       if (!blif_file.empty())
-                               Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str()));
+                       if (!blif_file.empty() || help_mode) {
+                               if (vpr || help_mode) {
+                                       run(stringf("opt_clean -purge"),
+                                                       "                                 (vpr mode)");
+                                       run(stringf("write_blif -attr -cname -conn -param %s",
+                                                       help_mode ? "<file-name>" : blif_file.c_str()),
+                                                       " (vpr mode)");
+                               }
+                               if (!vpr)
+                                       run(stringf("write_blif -gates -attr -param %s",
+                                                       help_mode ? "<file-name>" : blif_file.c_str()),
+                                                       "       (non-vpr mode)");
+                       }
                }
 
-               if (check_label(active, run_from, run_to, "edif"))
+               if (check_label("edif"))
                {
-                       if (!edif_file.empty())
-                               Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
+                       if (!edif_file.empty() || help_mode)
+                               run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
                }
 
-               log_pop();
+               if (check_label("json"))
+               {
+                       if (!json_file.empty() || help_mode)
+                               run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+               }
        }
 } SynthIce40Pass;