def run_lec( reference_netlist, implementation_netlist, command_runner=CommandRunner(), temp_dir=Path("."), log_filename="abc.lec.out", abc_exec=None, ): """ Run Logical Equivalence Checking (LEC) between two netlists using ABC .. note :: Usage: vtr.abc.run_lec(<reference_netlist>,<implementation_netlist>,[OPTIONS]) Arguments ========= reference_netlist : The reference netlist to be commpared to implementation_netlist : The implemeted netlist to compare to the reference netlist Other Parameters ---------------- command_runner : A CommandRunner object used to run system commands temp_dir : Directory to run in (created if non-existent) log_filename : File to log result to abc_exec : ABC executable to be run """ temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) if abc_exec is None: abc_exec = str(paths.abc_exe_path) abc_script = ("dsec {ref} {imp}".format(ref=reference_netlist, imp=implementation_netlist), ) abc_script = "; ".join(abc_script) cmd = [abc_exec, "-c", abc_script] output, _ = command_runner.run_system_command(cmd, temp_dir=temp_dir, log_filename=log_filename, indent_depth=1) # Check if ABC's LEC engine passed lec_passed, errored = check_abc_lec_status(output) if errored: abc_script = ("cec {ref} {imp}".format(ref=reference_netlist, imp=implementation_netlist), ) abc_script = "; ".join(abc_script) cmd = [abc_exec, "-c", abc_script] output, _ = command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename="abc.cec.out", indent_depth=1) lec_passed, errored = check_abc_lec_status(output) if lec_passed is None: raise InspectError( "Couldn't determine Logical Equivalence status between {input} <-> {output}" .format(input=reference_netlist, output=implementation_netlist), filename=log_filename, ) if lec_passed is False: raise InspectError( "Logical Equivalence Check failed between {input} <-> {output}". format(input=reference_netlist, output=implementation_netlist), filename=log_filename, ) assert lec_passed
def run( circuit_file, old_netlist, output_netlist, output_activity_file, command_runner=CommandRunner(), temp_dir=Path("."), log_filename="ace.out", ace_exec=None, ace_seed=1, ): """ Runs ACE for activity estimation .. note :: Usage: vtr.ace.run(<circuit_file>,<output_netlist>,<output_activity_file>,[OPTIONS]) Arguments ========= circuit_file : Circuit file to optimize old_netlist : netlist to be anylized output_netlist : File name to output the resulting circuit to output_activity_file : The output activity file Other Parameters ---------------- command_runner : A CommandRunner object used to run system commands temp_dir : Directory to run in (created if non-existent) log_filename : File to log result to ace_exec : ACE executable to be run ace_seed : The ACE seed """ temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir # Verify that files are Paths or convert them to Paths and check that they exist circuit_file = verify_file(circuit_file, "Circuit") old_netlist = verify_file(old_netlist, "Previous netlist") output_netlist = verify_file(output_netlist, "Output netlist", should_exist=False) output_activity_file = verify_file(output_activity_file, "Output activity", should_exist=False) ace_clk_file = temp_dir / "ace_clk.txt" ace_raw = temp_dir / (circuit_file.with_suffix("").stem + ".raw.ace.blif") if ace_exec is None: ace_exec = find_vtr_file("ace") cmd = [ find_vtr_file("extract_clk_from_blif.py"), ace_clk_file.name, circuit_file.name ] command_runner.run_system_command(cmd, temp_dir=temp_dir, log_filename="ace_clk_extraction.out", indent_depth=1) ace_clk = "" with ace_clk_file.open("r") as file: ace_clk = file.readline().strip("\n") cmd = [ ace_exec, "-b", circuit_file.name, "-c", ace_clk, "-n", ace_raw.name, "-o", output_activity_file.name, "-s", str(ace_seed), ] command_runner.run_system_command(cmd, temp_dir=temp_dir, log_filename=log_filename, indent_depth=1) clock_script = find_vtr_file("restore_multiclock_latch.pl") cmd = [clock_script, old_netlist.name, ace_raw.name, output_netlist.name] command_runner.run_system_command(cmd, temp_dir=temp_dir, log_filename="ace_clk_restore.out", indent_depth=1)
def run( architecture_file, circuit_file, include_files, output_netlist, command_runner=CommandRunner(), temp_dir=Path("."), odin_args="--adder_type default", log_filename="odin.out", odin_exec=None, odin_config=None, min_hard_mult_size=3, min_hard_adder_size=1, ): """ Runs ODIN II on the specified architecture file and circuit file .. note :: Usage: vtr.odin.run(<architecture_file>,<circuit_file>,<output_netlist>,[OPTIONS]) Arguments ========= architecture_file : Architecture file to target circuit_file : Circuit file to optimize output_netlist : File name to output the resulting circuit to Other Parameters ---------------- command_runner : A CommandRunner object used to run system commands temp_dir : Directory to run in (created if non-existent) odin_args: A dictionary of keyword arguments to pass on to ODIN II log_filename : File to log result to odin_exec: ODIN II executable to be run odin_config: The ODIN II configuration file min_hard_mult_size : Tells ODIN II the minimum multiplier size that should be implemented using hard multiplier (if available) min_hard_adder_size : Tells ODIN II the minimum adder size that should be implemented using hard adder (if available). """ temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) if odin_args is None: odin_args = OrderedDict() # Verify that files are Paths or convert them to Paths and check that they exist architecture_file = verify_file(architecture_file, "Architecture") circuit_file = verify_file(circuit_file, "Circuit") output_netlist = verify_file(output_netlist, "Output netlist", False) if odin_exec is None: odin_exec = str(paths.odin_exe_path) if odin_config is None: odin_base_config = str(paths.odin_cfg_path) else: odin_base_config = str(Path(odin_config).resolve()) # Copy the config file odin_config = "odin_config.xml" odin_config_full_path = str(temp_dir / odin_config) shutil.copyfile(odin_base_config, odin_config_full_path) # Create a list showing all (.v) and (.vh) files circuit_list = create_circuits_list(circuit_file, include_files) init_config_file( odin_config_full_path, circuit_list, architecture_file.name, output_netlist.name, determine_memory_addr_width(str(architecture_file)), min_hard_mult_size, min_hard_adder_size, ) cmd = [odin_exec] use_odin_simulation = False if "use_odin_simulation" in odin_args: use_odin_simulation = True del odin_args["use_odin_simulation"] for arg, value in odin_args.items(): if isinstance(value, bool) and value: cmd += ["--" + arg] elif isinstance(value, (str, int, float)): cmd += ["--" + arg, str(value)] else: pass cmd += ["-U0"] if "disable_odin_xml" in odin_args: del odin_args["disable_odin_xml"] cmd += [ "-a", architecture_file.name, "-V", circuit_list, "-o", output_netlist.name, ] else: cmd += ["-c", odin_config] command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename=log_filename, indent_depth=1 ) if use_odin_simulation: sim_dir = temp_dir / "simulation_init" sim_dir.mkdir() cmd = [ odin_exec, "-b", output_netlist.name, "-a", architecture_file.name, "-sim_dir", str(sim_dir), "-g", "100", "--best_coverage", "-U0", ] command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename="sim_produce_vector.out", indent_depth=1, )
def run( architecture_file, circuit_file, output_netlist, command_runner=CommandRunner(), temp_dir=Path("."), log_filename="abc.out", abc_exec=None, abc_script=None, abc_rc=None, use_old_abc_script=False, abc_args=None, keep_intermediate_files=True, ): """ Runs ABC to optimize specified file. .. note :: Usage: vtr.abc.run(<architecture_file>,<circuit_file>,<output_netlist>,[OPTIONS]) Arguments ========= architecture_file : Architecture file to target circuit_file : Circuit file to optimize output_netlist : File name to output the resulting circuit to Other Parameters ---------------- command_runner : A CommandRunner object used to run system commands temp_dir : Directory to run in (created if non-existent) log_filename : File to log result to abc_exec : ABC executable to be run abc_script : The script to be run on abc abc_rc : The ABC rc file use_old_abc_script : Enables the use of the old ABC script abc_args : A dictionary of keyword arguments to pass on to ABC keep_intermediate_files : Determines if intermediate files are kept or deleted """ temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) abc_args = OrderedDict() if abc_args is None else abc_args # Verify that files are Paths or convert them to Paths and check that they exist architecture_file = verify_file(architecture_file, "Architecture") circuit_file = verify_file(circuit_file, "Circuit") output_netlist = verify_file(output_netlist, "Output netlist", should_exist=False) blackbox_latches_script = str(paths.blackbox_latches_script_path) clk_list = [] # # Parse arguments # ( abc_args, abc_flow_type, lut_size, abc_run_args, use_old_latches_restoration_script, ) = parse_abc_args(abc_args) lut_size = determine_lut_size( str(architecture_file)) if lut_size is None else lut_size populate_clock_list(circuit_file, blackbox_latches_script, clk_list, command_runner, temp_dir) abc_exec = str(paths.abc_exe_path) if abc_exec is None else abc_exec abc_rc = str(paths.abc_rc_path) if abc_rc is None else abc_rc shutil.copyfile(str(abc_rc), str(temp_dir / "abc.rc")) iterations = len(clk_list) iterations = 1 if iterations == 0 or abc_flow_type != "iterative_bb" else iterations original_script = abc_script input_file = circuit_file.name for i in range(0, iterations): pre_abc_blif = temp_dir / (str(i) + "_" + circuit_file.name) post_abc_blif = temp_dir / (str(i) + "_" + output_netlist.name) post_abc_raw_blif = temp_dir / (str(i) + "_" + output_netlist.with_suffix("").stem + ".raw.abc.blif") if abc_flow_type == "blanket_bb": command_runner.run_system_command( [ blackbox_latches_script, "--input", input_file, "--output", pre_abc_blif.name, ], temp_dir=temp_dir, log_filename=str(i) + "_blackboxing_latch.out", indent_depth=1, ) elif len(clk_list) > i: command_runner.run_system_command( [ blackbox_latches_script, "--clk_list", clk_list[i], "--input", input_file, "--output", pre_abc_blif.name, ], temp_dir=temp_dir, log_filename=str(i) + "_blackboxing_latch.out", indent_depth=1, ) else: pre_abc_blif = input_file abc_script = ("; ".join([ 'echo ""', 'echo "Load Netlist"', 'echo "============"', "read {pre_abc_blif}".format(pre_abc_blif=pre_abc_blif.name), "time", 'echo ""', 'echo "Circuit Info"', 'echo "=========="', "print_stats", "print_latch", "time", 'echo ""', 'echo "LUT Costs"', 'echo "========="', "print_lut", "time", 'echo ""', 'echo "Logic Opt + Techmap"', 'echo "==================="', "strash", "ifraig -v", "scorr -v", "dc2 -v", "dch -f", "if -K {lut_size} -v".format(lut_size=lut_size), "mfs2 -v", "print_stats", "time", 'echo ""', 'echo "Output Netlist"', 'echo "=============="', "write_hie {pre_abc_blif} {post_abc_raw_blif}".format( pre_abc_blif=pre_abc_blif.name, post_abc_raw_blif=post_abc_raw_blif.name, ), "time;", ]) if abc_script is None else "; ".join([ "read {pre_abc_blif}".format(pre_abc_blif=pre_abc_blif.name), "time", "resyn", "resyn2", "if -K {lut_size}".format(lut_size=lut_size), "time", "scleanup", "write_hie {pre_abc_blif} {post_abc_raw_blif}".format( pre_abc_blif=pre_abc_blif.name, post_abc_raw_blif=post_abc_raw_blif.name, ), "print_stats", ]) if use_old_abc_script else abc_script) cmd = [abc_exec, "-c", abc_script] if abc_run_args: cmd.append(abc_run_args) command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename=Path(log_filename).stem + str(i) + Path(log_filename).suffix, indent_depth=1, ) if abc_flow_type != "blanket_bb" and len(clk_list) > i: command_runner.run_system_command( [ blackbox_latches_script, "--restore", clk_list[i], "--input", post_abc_raw_blif.name, "--output", post_abc_blif.name, ], temp_dir=temp_dir, log_filename="restore_latch" + str(i) + ".out", indent_depth=1, ) else: restore_multiclock_info_script = ( str(paths.restore_multiclock_latch_old_script_path) if use_old_latches_restoration_script else str( paths.restore_multiclock_latch_script_path)) command_runner.run_system_command( [ restore_multiclock_info_script, pre_abc_blif.name, post_abc_raw_blif.name, post_abc_blif.name, ], temp_dir=temp_dir, log_filename="restore_latch" + str(i) + ".out", indent_depth=1, ) if abc_flow_type != "iterative_bb": break abc_script = original_script input_file = post_abc_blif.name command_runner.run_system_command( [ blackbox_latches_script, "--input", post_abc_blif.name, "--output", output_netlist.name, "--vanilla", ], temp_dir=temp_dir, log_filename="restore_latch" + str(i) + ".out", indent_depth=1, ) if not keep_intermediate_files: for file in temp_dir.iterdir(): if file.suffix in (".dot", ".v", ".rc"): file.unlink()
def cmp_full_vs_incr_sta( architecture, circuit, circuit_name=None, command_runner=CommandRunner(), vpr_args=None, temp_dir=Path("."), vpr_exec=None, ): """ Sanity check that full STA and the incremental STA produce the same *.net, *.place, *.route files as well as identical timing report files .. note :: Use: vtr.vpr.cmp_full_vs_incr_sta(<architecture>,<circuit_name>,<circuit>,[OPTIONS]) Arguments ========= architecture: Architecture file circuit: Input circuit file Other Parameters ---------------- circuit_name: Name of the circuit file command_runner: CommandRunner object temp_dir: Directory to run in vpr_exec: Path to the VPR executable vpr_args: Extra arguments for VPR """ # Verify that files are Paths or convert them to Paths and check that they exist architecture = verify_file(architecture, "Architecture") circuit = verify_file(circuit, "Circuit") if not circuit_name: circuit_name = circuit.stem default_output_filenames = [ "{}.net".format(circuit_name), "{}.place".format(circuit_name), "{}.route".format(circuit_name), "report_timing.setup.rpt", "report_timing.hold.rpt", "report_unconstrained_timing.setup.rpt", "report_unconstrained_timing.hold.rpt", ] # The full STA flow should have already been run # directly rename the output files for filename in default_output_filenames: cmd = ["mv", filename, "full_sta_{}".format(filename)] command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename="move.out", indent_depth=1 ) # run incremental STA flow incremental_vpr_args = vpr_args incremental_vpr_args["timing_update_type"] = "incremental" run( architecture, circuit, circuit_name, command_runner, temp_dir, log_filename="vpr.incr_sta.out", vpr_exec=vpr_exec, vpr_args=incremental_vpr_args, ) # Rename the incremental STA output files for filename in default_output_filenames: cmd = ["mv", filename, "incremental_sta_{}".format(filename)] command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename="move.out", indent_depth=1 ) failed_msg = "Failed with these files (not identical):" identical = True for filename in default_output_filenames: cmd = [ "diff", "full_sta_{}".format(filename), "incremental_sta_{}".format(filename), ] _, cmd_return_code = command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename="diff.out", indent_depth=1 ) if cmd_return_code: identical = False failed_msg += " {}".format(filename) if not identical: raise InspectError(failed_msg)
def run_second_time( architecture, circuit, circuit_name=None, command_runner=CommandRunner(), temp_dir=Path("."), vpr_exec=None, second_run_args=None, rr_graph_ext=".xml", ): """ Run vpr again with additional parameters. This is used to ensure that files generated by VPR can be re-loaded by it .. note :: Usage: vtr.vpr.run_second_time(<architecture>,<circuit>,[OPTIONS]) Arguments ========= architecture: Architecture file circuit: Input circuit file Other Parameters ---------------- circuit_name: Name of the circuit file command_runner: CommandRunner object temp_dir: Directory to run in log_filename : File to log result to vpr_exec: Path to the VPR executable second_run_args: Extra arguments for VPR """ temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) rr_graph_out_file = "" if "write_rr_graph" in second_run_args: rr_graph_out_file = second_run_args["write_rr_graph"] rr_graph_ext = Path(rr_graph_out_file).suffix rr_graph_out_file2 = "rr_graph2" + rr_graph_ext if "write_rr_graph" in second_run_args: second_run_args["read_rr_graph"] = rr_graph_out_file second_run_args["write_rr_graph"] = rr_graph_out_file2 #run VPR run( architecture, circuit, circuit_name, command_runner, temp_dir, log_filename="vpr_second_run.out", vpr_exec=vpr_exec, vpr_args=second_run_args, ) if "write_rr_graph" in second_run_args: cmd = ["diff", rr_graph_out_file, rr_graph_out_file2] _, diff_result = command_runner.run_system_command( cmd, temp_dir, log_filename="diff.rr_graph.out", indent_depth=1 ) if diff_result: raise InspectError( "failed: vpr (RR Graph XML output not consistent when reloaded)" )
def run_relax_w( architecture, circuit, circuit_name=None, command_runner=CommandRunner(), temp_dir=Path("."), relax_w_factor=1.3, vpr_exec=None, logfile_base="vpr", vpr_args=None, ): """ Runs VPR twice: 1st: To find the minimum channel width 2nd: At relaxed channel width (e.g. for critical path delay) .. note :: Use: vtr.vpr.run_relax_w(<architecture_file>,<circuit_file>,[OPTIONS]) Arguments ========= architecture: Architecture file circuit: Input circuit netlist Other Parameters ---------------- circuit_name: Name of the circuit file command_runner: CommandRunner object temp_dir: Directory to run in relax_w_factor: Factor by which to relax minimum channel width for critical path delay routing vpr_exec: Path to the VPR executable logfile_base: Base name for log files (e.g. "vpr" produces vpr.min_w.out, vpr.relaxed_w.out) vpr_args: Extra arguments for VPR """ if vpr_args is None: vpr_args = OrderedDict() temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) # Verify that files are Paths or convert them to Paths and check that they exist architecture = verify_file(architecture, "Architecture") circuit = verify_file(circuit, "Circuit") vpr_min_w_log = ".".join([logfile_base, "out"]) vpr_relaxed_w_log = ".".join([logfile_base, "crit_path", "out"]) max_router_iterations = None if "max_router_iterations" in vpr_args: max_router_iterations = vpr_args["max_router_iterations"] del vpr_args["max_router_iterations"] if "write_rr_graph" in vpr_args: del vpr_args["write_rr_graph"] if "analysis" in vpr_args: del vpr_args["analysis"] if "route" in vpr_args: del vpr_args["route"] if vpr_exec is None: vpr_exec = find_vtr_file("vpr", is_executable=True) run( architecture, circuit, circuit_name, command_runner, temp_dir, log_filename=vpr_min_w_log, vpr_exec=vpr_exec, vpr_args=vpr_args, ) if ("pack" in vpr_args or "place" in vpr_args) and "route" not in vpr_args: # Don't look for min W if routing was not run return if max_router_iterations: vpr_args["max_router_iterations"] = max_router_iterations min_w = determine_min_w(str(temp_dir / vpr_min_w_log)) relaxed_w = relax_w(min_w, relax_w_factor) vpr_args["route"] = True # Re-route only vpr_args["route_chan_width"] = relaxed_w # At a fixed channel width # VPR does not support performing routing when fixed pins # are specified, and placement is not run; so remove the option run( architecture, circuit, circuit_name, command_runner, temp_dir, log_filename=vpr_relaxed_w_log, vpr_exec=vpr_exec, vpr_args=vpr_args, )
def run( architecture, circuit, circuit_name=None, command_runner=CommandRunner(), temp_dir=Path("."), log_filename="vpr.out", vpr_exec=None, vpr_args=None, ): """ Runs VPR with the specified configuration .. note :: Usage: vtr.vpr.run(<architecture>,<circuit>,[OPTIONS]) Arguments ========= architecture: Architecture file circuit: Input circuit file Other Parameters ---------------- circuit_name: Name of the circuit file command_runner: CommandRunner object temp_dir: Directory to run in log_filename : File to log result to vpr_exec: Path to the VPR executable vpr_args: Extra arguments for VPR """ if vpr_args is None: vpr_args = OrderedDict() temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) if vpr_exec is None: vpr_exec = find_vtr_file("vpr", is_executable=True) # Verify that files are Paths or convert them to Paths and check that they exist architecture = verify_file(architecture, "Architecture") circuit = verify_file(circuit, "Circuit") cmd = [] if circuit_name: cmd = [ vpr_exec, architecture.name, circuit_name, "--circuit_file", circuit.name, ] else: cmd = [vpr_exec, architecture.name, circuit.name] # Translate arbitrary keyword arguments into options for VPR for arg, value in vpr_args.items(): if isinstance(value, bool): if not value: pass cmd += ["--" + arg] else: if isinstance(value, list): cmd += ["--" + arg] for item in value: cmd += [str(item)] else: cmd += ["--" + arg, str(value)] command_runner.run_system_command( cmd, temp_dir=temp_dir, log_filename=log_filename, indent_depth=1 )
def run( architecture, circuit, circuit_name=None, command_runner=CommandRunner(), temp_dir=Path("."), log_filename="vpr.out", vpr_exec=None, vpr_args=None, ): """ Runs VPR with the specified configuration .. note :: Usage: vtr.vpr.run(<architecture>,<circuit>,[OPTIONS]) Arguments ========= architecture: Architecture file circuit: Input circuit file Other Parameters ---------------- circuit_name: Name of the circuit file command_runner: CommandRunner object temp_dir: Directory to run in log_filename : File to log result to vpr_exec: Path to the VPR executable vpr_args: Extra arguments for VPR """ if vpr_args is None: vpr_args = OrderedDict() temp_dir = Path(temp_dir) if not isinstance(temp_dir, Path) else temp_dir temp_dir.mkdir(parents=True, exist_ok=True) if vpr_exec is None: vpr_exec = find_vtr_file("vpr", is_executable=True) # Verify that files are Paths or convert them to Paths and check that they exist architecture = verify_file(architecture, "Architecture") circuit = verify_file(circuit, "Circuit") cmd = [] if circuit_name: cmd = [ vpr_exec, architecture.name, circuit_name, "--circuit_file", circuit.name, ] else: cmd = [vpr_exec, architecture.name, circuit.name] # Translate arbitrary keyword arguments into options for VPR for arg, value in vpr_args.items(): if isinstance(value, bool): if not value: pass cmd += ["--" + arg] else: if isinstance(value, list): cmd += ["--" + arg] for item in value: cmd += [str(item)] else: cmd += ["--" + arg, str(value)] # Extra options to fine-tune LeakSanitizer (LSAN) behaviour. # Note that if VPR was compiled without LSAN these have no effect # 'suppressions=...' Add the LeakSanitizer (LSAN) suppression file # 'exitcode=12' Use a consistent exitcode # (on some systems LSAN don't use the default exit code of 23) # 'fast_unwind_on_malloc=0' Provide more accurate leak stack traces environ[ "LSAN_OPTIONS"] = "suppressions={} exitcode=23 fast_unwind_on_malloc=0".format( find_vtr_file("lsan.supp")) command_runner.run_system_command(cmd, temp_dir=temp_dir, log_filename=log_filename, indent_depth=1)