mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			220 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  *  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() 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("    -blacklist <file>\n");
 | |
| 		log("        Do not match cells or signals that match the names in the file\n");
 | |
| 		log("        (passed to equiv_make).\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("    -nocheck\n");
 | |
| 		log("        disable running check before and after the command under test.\n");
 | |
| 		log("\n");
 | |
| 		log("The following commands are executed by this verification command:\n");
 | |
| 		help_script();
 | |
| 		log("\n");
 | |
| 	}
 | |
| 
 | |
| 	std::string command, techmap_opts, make_opts;
 | |
| 	bool assert, undef, multiclock, async2sync, nocheck;
 | |
| 
 | |
| 	void clear_flags() override
 | |
| 	{
 | |
| 		command = "";
 | |
| 		techmap_opts = "";
 | |
| 		make_opts = "";
 | |
| 		assert = false;
 | |
| 		undef = false;
 | |
| 		multiclock = false;
 | |
| 		async2sync = false;
 | |
| 		nocheck = false;
 | |
| 	}
 | |
| 
 | |
| 	void execute(std::vector < std::string > args, RTLIL::Design * design) 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] == "-blacklist" && argidx + 1 < args.size()) {
 | |
| 				make_opts += " -blacklist " + args[++argidx];
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (args[argidx] == "-assert") {
 | |
| 				assert = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (args[argidx] == "-undef") {
 | |
| 				undef = true;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (args[argidx] == "-nocheck") {
 | |
| 				nocheck = 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() override
 | |
| 	{
 | |
| 		if (check_label("run_pass")) {
 | |
| 			run("hierarchy -auto-top");
 | |
| 			run("design -save preopt");
 | |
| 			if (!nocheck)
 | |
| 				run("check -assert", "(unless -nocheck)");
 | |
| 			if (help_mode)
 | |
| 				run("[command]");
 | |
| 			else
 | |
| 				run(command);
 | |
| 			if (!nocheck)
 | |
| 				run("check -assert", "(unless -nocheck)");
 | |
| 			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)");
 | |
| 			string opts;
 | |
| 			if (help_mode)
 | |
| 				opts = " -blacklist <filename> ...";
 | |
| 			else
 | |
| 				opts = make_opts;
 | |
| 			run("equiv_make" + opts + " 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
 |