/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2018 whitequark * * 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 checks circuit equivalence before and after an optimization pass.\n"); log("\n"); log(" -run :\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 \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("The following commands are executed by this verification command:\n"); help_script(); log("\n"); } std::string command, techmap_opts; bool assert; void clear_flags() YS_OVERRIDE { command = ""; techmap_opts = ""; assert = 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; } break; } for (; argidx < args.size(); argidx++) { if (command.empty()) { if (args[argidx].substr(0, 1) == "-") 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"); 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 ..."; else opts = techmap_opts; run("techmap -wb -D EQUIV -autoproc" + opts); } if (check_label("prove")) { run("equiv_make gold gate equiv"); 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