import os import shutil import sys import C_TO_LOGIC import SYN import VHDL from utilities import GET_TOOL_PATH # Tool path constants TOOL_EXE = "p_r" # Default to env if there ENV_TOOL_PATH = GET_TOOL_PATH(TOOL_EXE) if ENV_TOOL_PATH: CC_TOOLS_PR_PATH = ENV_TOOL_PATH CC_TOOLS_PATH = os.path.abspath(os.path.dirname(CC_TOOLS_PR_PATH) + "../../") else: CC_TOOLS_PATH = "/media/1TB/Programs/Linux/cc-toolchain-linux_testing_12.09.24" class ParsedTimingReport: def __init__(self, syn_output): path_report = PathReport(syn_output) self.path_reports = dict() self.path_reports[path_report.path_group] = path_report if len(self.path_reports) == 0: raise Exception(f"Bad synthesis log?:\n{syn_output}") class PathReport: def __init__(self, path_report_text): self.path_delay_ns = None # nanoseconds # Fake clock info since no clock constrainted existed? self.path_group = "clk" self.slack_ns = None self.source_ns_per_clock = None # From latch edge time self.path_group = None # Clock name? self.netlist_resources = set() # Set of strings self.start_reg_name = None self.end_reg_name = None for line in path_report_text.split("\n"): tok = "Maximum Clock Frequency" if tok in line: #print(line) fmax_mhz = float(line.split(":")[1].strip().split(" ")[0]) #print("fmax_mhz",fmax_mhz) self.path_delay_ns = 1000.0 / fmax_mhz # Returns parsed timing report def SYN_AND_REPORT_TIMING( inst_name, Logic, parser_state, TimingParamsLookupTable, total_latency=None, hash_ext=None, use_existing_log_file=True, ): multimain_timing_params = SYN.MultiMainTimingParams() multimain_timing_params.TimingParamsLookupTable = TimingParamsLookupTable return SYN_AND_REPORT_TIMING_NEW( parser_state, multimain_timing_params, inst_name, total_latency, hash_ext, use_existing_log_file, ) # Returns parsed timing report def SYN_AND_REPORT_TIMING_MULTIMAIN(parser_state, multimain_timing_params): return SYN_AND_REPORT_TIMING_NEW(parser_state, multimain_timing_params) # MULTIMAIN OR SINGLE INSTANCE # Returns parsed timing report def SYN_AND_REPORT_TIMING_NEW( parser_state, multimain_timing_params, inst_name=None, total_latency=None, hash_ext=None, use_existing_log_file=True, ): # Which vhdl files? vhdl_files_texts, top_entity_name = SYN.GET_VHDL_FILES_TCL_TEXT_AND_TOP( multimain_timing_params, parser_state, inst_name ) log_file_name = top_entity_name + ".log" # Single inst if inst_name: Logic = parser_state.LogicInstLookupTable[inst_name] # First create syn/imp directory for this logic output_directory = SYN.GET_OUTPUT_DIRECTORY(Logic) else: # Multimain # First create directory for this logic output_directory = SYN.SYN_OUTPUT_DIRECTORY + "/" + SYN.TOP_LEVEL_MODULE if not os.path.exists(output_directory): os.makedirs(output_directory) log_path = output_directory + "/" + log_file_name syn_log_path = output_directory + "/syn_" + log_file_name # Need separate logs? # Use same configs based on to speed up run time? log_to_read = log_path # If log file exists dont run syn if os.path.exists(log_to_read) and use_existing_log_file: # print "SKIPPED:", syn_imp_bash_cmd print("Reading log", log_to_read) f = open(log_path, "r") log_text = f.read() f.close() return ParsedTimingReport(log_text) # Not from log: # Write top level vhdl for this module/multimain if inst_name: VHDL.WRITE_LOGIC_ENTITY( inst_name, Logic, output_directory, parser_state, multimain_timing_params.TimingParamsLookupTable, ) VHDL.WRITE_LOGIC_TOP( inst_name, Logic, output_directory, parser_state, multimain_timing_params.TimingParamsLookupTable, ) else: VHDL.WRITE_MULTIMAIN_TOP(parser_state, multimain_timing_params) # Generate files for this SYN # Write clock constraint and include it constraints_filepath = SYN.WRITE_CLK_CONSTRAINTS_FILE(parser_state, inst_name) clk_to_mhz, constraints_filepath = SYN.GET_CLK_TO_MHZ_AND_CONSTRAINTS_PATH( parser_state, inst_name ) # Generate build scripts # TODO dont base on cc-toolchain directory? CC_TOOLS_YOSYS = CC_TOOLS_PATH + "/bin/yosys/yosys" CC_TOOLS_PR = CC_TOOLS_PATH + "/bin/p_r/p_r" CC_TOOLS_PR_FLAGS = f"-ccf {constraints_filepath}" #-cCP? temp_local_out_dir = CC_TOOLS_PATH + "/workspace/pipelinec_temp_"+top_entity_name shutil.rmtree(temp_local_out_dir, ignore_errors=True) os.makedirs(temp_local_out_dir) os.makedirs(f"{output_directory}/net", exist_ok=True) sh_text = "" sh_text += f""" #!/bin/bash {CC_TOOLS_YOSYS} -ql {syn_log_path} -p 'ghdl --std=08 --warn-no-binding -C --ieee=synopsys {vhdl_files_texts} -e {top_entity_name}; synth_gatemate -top {top_entity_name} -nomx8 -vlog {output_directory}/net/{top_entity_name}_synth.v' &> /dev/null {CC_TOOLS_PR} -i {output_directory}/net/{top_entity_name}_synth.v -o {top_entity_name} {CC_TOOLS_PR_FLAGS} &> {log_path} """ sh_file = top_entity_name + ".sh" sh_path = output_directory + "/" + sh_file f = open(sh_path, "w") f.write(sh_text) f.close() # Run the build script print("Running CC_TOOLS:", sh_path, flush=True) syn_imp_bash_cmd = ( "bash " + sh_path ) C_TO_LOGIC.GET_SHELL_CMD_OUTPUT(syn_imp_bash_cmd, cwd=temp_local_out_dir) f = open(log_path, "r") log_text = f.read() f.close() shutil.rmtree(temp_local_out_dir, ignore_errors=True) return ParsedTimingReport(log_text)