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");
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("\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("\n");
- log(" coarse:\n");
- log(" synth -run coarse\n");
+ log(" -nodffe\n");
+ log(" do not use SB_DFFE* cells in output netlist\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(" -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(" 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(" dff2dffe -direct-match $_DFF_*\n");
- log(" techmap -map +/ice40/cells_map.v\n");
- log(" opt_const -mux_undef\n");
- log(" simplemap\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 -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
{
- 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;
+ 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
+ {
+ string run_from, run_to;
+ clear_flags();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
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)
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"))
{
- Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v");
- Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
+ 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(active, run_from, run_to, "flatten"))
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
{
- Pass::call(design, "proc");
- Pass::call(design, "flatten");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
}
- if (check_label(active, run_from, run_to, "coarse"))
+ if (check_label("coarse"))
{
- Pass::call(design, "synth -run coarse");
+ 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 (!nobram && check_label(active, run_from, run_to, "bram"))
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
{
- Pass::call(design, "memory_bram -rules +/ice40/brams.txt");
- Pass::call(design, "techmap -map +/ice40/brams_map.v");
+ run("memory_bram -rules +/ice40/brams.txt");
+ run("techmap -map +/ice40/brams_map.v");
+ run("ice40_braminit");
}
- if (check_label(active, run_from, run_to, "fine"))
+ if (check_label("map"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -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, "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_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"))
{
- Pass::call(design, "abc -lut 4");
- Pass::call(design, "clean");
+ 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)");
+ }
}
- 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;