| /* |
| * yosys -- Yosys Open SYnthesis Suite |
| * |
| * Copyright (C) 2018 whitequark <whitequark@whitequark.org> |
| * |
| * 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 "kernel/register.h" |
| |
| USING_YOSYS_NAMESPACE |
| PRIVATE_NAMESPACE_BEGIN |
| |
| struct EquivOptPass:public ScriptPass |
| { |
| EquivOptPass() : ScriptPass("equiv_opt", "prove equivalence for optimized circuit") { } |
| |
| void help() YS_OVERRIDE |
| { |
| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| |
| log("\n"); |
| log(" equiv_opt [options] [command]\n"); |
| log("\n"); |
| log("This command uses temporal induction to check circuit equivalence before and\n"); |
| log("after an optimization pass.\n"); |
| log("\n"); |
| log(" -run <from_label>:<to_label>\n"); |
| log(" only run the commands between the labels (see below). an empty\n"); |
| log(" from label is synonymous to the start of the command list, and empty to\n"); |
| log(" label is synonymous to the end of the command list.\n"); |
| log("\n"); |
| log(" -map <filename>\n"); |
| log(" expand the modules in this file before proving equivalence. this is\n"); |
| log(" useful for handling architecture-specific primitives.\n"); |
| log("\n"); |
| log(" -assert\n"); |
| log(" produce an error if the circuits are not equivalent.\n"); |
| log("\n"); |
| log(" -multiclock\n"); |
| log(" run clk2fflogic before equivalence checking.\n"); |
| log("\n"); |
| log(" -async2sync\n"); |
| log(" run async2sync before equivalence checking.\n"); |
| log("\n"); |
| log(" -undef\n"); |
| log(" enable modelling of undef states during equiv_induct.\n"); |
| log("\n"); |
| log("The following commands are executed by this verification command:\n"); |
| help_script(); |
| log("\n"); |
| } |
| |
| std::string command, techmap_opts; |
| bool assert, undef, multiclock, async2sync; |
| |
| void clear_flags() YS_OVERRIDE |
| { |
| command = ""; |
| techmap_opts = ""; |
| assert = false; |
| undef = false; |
| multiclock = false; |
| async2sync = 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++) { |
| if (args[argidx] == "-run" && argidx + 1 < args.size()) { |
| size_t pos = args[argidx + 1].find(':'); |
| if (pos == std::string::npos) |
| break; |
| run_from = args[++argidx].substr(0, pos); |
| run_to = args[argidx].substr(pos + 1); |
| continue; |
| } |
| if (args[argidx] == "-map" && argidx + 1 < args.size()) { |
| techmap_opts += " -map " + args[++argidx]; |
| continue; |
| } |
| if (args[argidx] == "-assert") { |
| assert = true; |
| continue; |
| } |
| if (args[argidx] == "-undef") { |
| undef = true; |
| continue; |
| } |
| if (args[argidx] == "-multiclock") { |
| multiclock = true; |
| continue; |
| } |
| if (args[argidx] == "-async2sync") { |
| async2sync = true; |
| continue; |
| } |
| break; |
| } |
| |
| for (; argidx < args.size(); argidx++) { |
| if (command.empty()) { |
| if (args[argidx].compare(0, 1, "-") == 0) |
| cmd_error(args, argidx, "Unknown option."); |
| } else { |
| command += " "; |
| } |
| command += args[argidx]; |
| } |
| |
| if (command.empty()) |
| log_cmd_error("No optimization pass specified!\n"); |
| |
| if (!design->full_selection()) |
| log_cmd_error("This command only operates on fully selected designs!\n"); |
| |
| if (async2sync && multiclock) |
| log_cmd_error("The '-async2sync' and '-multiclock' options are mutually exclusive!\n"); |
| |
| log_header(design, "Executing EQUIV_OPT pass.\n"); |
| log_push(); |
| |
| run_script(design, run_from, run_to); |
| |
| log_pop(); |
| } |
| |
| void script() YS_OVERRIDE |
| { |
| if (check_label("run_pass")) { |
| run("hierarchy -auto-top"); |
| run("design -save preopt"); |
| if (help_mode) |
| run("[command]"); |
| else |
| run(command); |
| run("design -stash postopt"); |
| } |
| |
| if (check_label("prepare")) { |
| run("design -copy-from preopt -as gold A:top"); |
| run("design -copy-from postopt -as gate A:top"); |
| } |
| |
| if ((!techmap_opts.empty() || help_mode) && check_label("techmap", "(only with -map)")) { |
| string opts; |
| if (help_mode) |
| opts = " -map <filename> ..."; |
| else |
| opts = techmap_opts; |
| run("techmap -wb -D EQUIV -autoproc" + opts); |
| } |
| |
| if (check_label("prove")) { |
| if (multiclock || help_mode) |
| run("clk2fflogic", "(only with -multiclock)"); |
| if (async2sync || help_mode) |
| run("async2sync", " (only with -async2sync)"); |
| run("equiv_make gold gate equiv"); |
| if (help_mode) |
| run("equiv_induct [-undef] equiv"); |
| else if (undef) |
| run("equiv_induct -undef equiv"); |
| else |
| run("equiv_induct equiv"); |
| if (help_mode) |
| run("equiv_status [-assert] equiv"); |
| else if (assert) |
| run("equiv_status -assert equiv"); |
| else |
| run("equiv_status equiv"); |
| } |
| |
| if (check_label("restore")) { |
| run("design -load preopt"); |
| } |
| } |
| } EquivOptPass; |
| |
| PRIVATE_NAMESPACE_END |