From 17b99fc87a1abe459115ca7b1c8f903e30e7f30f Mon Sep 17 00:00:00 2001 From: Stephen More Date: Wed, 12 Oct 2022 20:16:47 -0400 Subject: [PATCH 1/7] added mode in hardblock flow to stop after COFFE after running asic flow, added recursive searching for design files in hardblock flow, added support to put intermediary stages of asic flow (synth,pnr,power reporting) into unique directories based on configuration --- analyze_results/condense_reports.py | 169 +++++++++++++++ analyze_results/plot_coffe_results.py | 101 +++++++++ coffe/fpga.py | 4 +- coffe/hardblock_functions.py | 95 +++++--- coffe/utils.py | 13 +- .../dsp_block_hdl/accumulate.v | 50 +++++ .../strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v | 98 +++++++++ .../dsp_block_hdl/half_dsp.v | 79 +++++++ .../dsp_block_hdl/twomadder.v | 64 ++++++ .../strtx_III_dsp_sadegh/dsp_coffe_params.txt | 204 ++++++++++++++++++ .../strtx_III_dsp_sadegh/dsp_hb_settings.txt | 164 ++++++++++++++ 11 files changed, 1007 insertions(+), 34 deletions(-) create mode 100644 analyze_results/condense_reports.py create mode 100755 analyze_results/plot_coffe_results.py create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt create mode 100755 input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt diff --git a/analyze_results/condense_reports.py b/analyze_results/condense_reports.py new file mode 100644 index 0000000..be70918 --- /dev/null +++ b/analyze_results/condense_reports.py @@ -0,0 +1,169 @@ + +import sys +import os +import argparse +import subprocess as sp +import shlex +import csv +import re + +############### PYTHON3 ############### +#This allows for the command to output to console while running but with certain commands it causes issues (awk) +def run_shell_cmd(cmd_str,out_flag): + cmd_lst = shlex.split(cmd_str) + cmd_out = sp.Popen(cmd_lst, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE,env=cur_env) + cmd_stdout = "" + for line in iter(cmd_out.stdout.readline, ""): + if(cmd_out.poll() is None): + cmd_stdout += line.decode("utf-8") + if(out_flag == 1): + sys.stdout.buffer.write(line) + elif(out_flag == 2): + sys.stderr.buffer.write(line) + else: + break + _, cmd_stderr = cmd_out.communicate() + cmd_stderr = cmd_stderr.decode("utf-8") + print("cmd: %s returned with: %d" % (cmd_str,cmd_out.returncode)) + return cmd_stdout, cmd_stderr + +#safe mode for running shell commands +def safe_run_shell_cmd(cmd_str): + cmd_lst = shlex.split(cmd_str) + cmd_out = sp.run(cmd_lst, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE,env=cur_env) + cmd_stdout = cmd_out.stdout.decode("utf-8") + cmd_stderr = cmd_out.stderr.decode("utf-8") + # print("cmd: %s returned with: %d" % (cmd_str,cmd_out.returncode)) + if(cmd_out.returncode != 0): + print(cmd_stderr) + return cmd_stdout, cmd_stderr +############### PYTHON3 ############### + +#return the relative path of top level repo (COFFE in this case) +def find_top_repo(repo_str): + cwd_pwd_list = os.getcwd().split("/") + cwd_pwd_list.reverse() + repo_idx = cwd_pwd_list.index(repo_str) + return "../"*(repo_idx) + +def make_dir(dir_rel_path): + if(not os.path.isdir(dir_rel_path)): + os.mkdir(dir_rel_path) + # print("made directory in the path\n%s" % ( os.getcwd())) + +#creates output directories and move to arch out folder to prepare for scripts to run +def create_out_dirs(hard_params,arch_params): + gen_out_dir_name = "output_files" + os.chdir(arch_params["coffe_repo_path"]) + make_dir(gen_out_dir_name) + os.chdir(gen_out_dir_name) + #make directory for this specific coffe run + make_dir(arch_params["coffe_design_name"]) + os.chdir(arch_params["coffe_design_name"]) + make_dir(hard_params["arch_dir"]) + os.chdir(hard_params["arch_dir"]) + arch_dir = os.getcwd() + os.chdir(arch_params["coffe_repo_path"]) + #return abs path to run ASIC flow from + return arch_dir + +def modify_hb_params(hard_params,arch_params): + # GET DIR NAMES FROM PATHS + for hb_key,hb_val in hard_params.items(): + if "folder" in hb_key: + #takes the abs path and gets dir name + out_dir_name = hb_val.split("/")[-1] + if("synth_" in hb_key): + hard_params["synth_dir"] = out_dir_name + elif("pr_" in hb_key): + hard_params["pnr_dir"] = out_dir_name + elif("primetime_"in hb_key): + hard_params["pt_dir"] = out_dir_name + arch_out_path = arch_params["arch_out_folder"].split("/")[-1] + out_dir_name = arch_out_path.split("/")[-1] + hard_params["arch_dir"] = out_dir_name + +#outputs csv to the report_csv_out dir +def reports_to_csv(report_path): + os.chdir(report_path) + decimal_re = re.compile(r'\d+\.{0,1}\d*') + report_dict = { + 'mode': [], + 'top_level_mod' : [], + 'period': [], + 'wire_model': [], + 'metal_layers' : [], + 'utilization' : [], + 'area': [], + 'delay': [], + 'power': [] + } + for rep in os.listdir(report_path): + report_csv_out_dir = "report_csv_out" + if("report_" in rep): + #parse asic params from rep name + rep_params = rep.split("_") + if(len(rep_params) < 7): + continue + #check to see if its the mode or average of modes reports + #be careful the mode param is only gonna work for dsp block (or other verilog that has mode_0,mode_1 ports to muxes), will have to be generalized in future TODO + if("mode" in rep_params[1]): + report_dict["mode"].append(rep_params[1]) + param_idx = 1 + else: + report_dict["mode"].append("none") + param_idx = 0 + + report_dict["top_level_mod"].append(rep_params[1+param_idx]) + report_dict["period"].append(rep_params[2+param_idx]) + #skip one index for "wire" keyword + report_dict["wire_model"].append(rep_params[3+param_idx]) + report_dict["metal_layers"].append(rep_params[5+param_idx]) + #remove the .txt from the last param in filename + report_dict["utilization"].append(os.path.splitext(rep_params[6+param_idx])[0]) + fd = open(rep,"r") + delay = "" + power = "" + area = "" + for line in fd: + if("area" in line): + area = decimal_re.search(line).group(0) + elif("delay" in line): + delay = decimal_re.search(line).group(0) + elif("power" in line): + power = decimal_re.search(line).group(0) + report_dict['area'].append(area) + report_dict['delay'].append(delay) + report_dict['power'].append(power) + fd.close() + os.chdir(script_path) + make_dir(report_csv_out_dir) + for row_idx in range(len(report_dict["delay"])): + dict_row = [report_dict[key][row_idx] for key in report_dict.keys()] + fd = open(report_csv_out_dir + "/condensed_report.csv","w") + writer = csv.writer(fd) + writer.writerow(report_dict.keys()) + for row_idx in range(len(report_dict["delay"])): + dict_row = [report_dict[key][row_idx] for key in report_dict.keys()] + writer.writerow(dict_row) + fd.close() + return report_dict + +def main(): + global cur_env + cur_env = os.environ.copy() + global script_path + script_path = os.getcwd() + parser = argparse.ArgumentParser() + parser.add_argument('-r','--report_path',type=str,help="path to directory containing coffe report outputs") + args = parser.parse_args() + arg_dict = vars(args) + #create condensed reports + report_pwd = os.path.join(os.getcwd(),arg_dict["report_path"]) + report_dict = reports_to_csv(report_pwd) + + + +if __name__ == "__main__": + main() + diff --git a/analyze_results/plot_coffe_results.py b/analyze_results/plot_coffe_results.py new file mode 100755 index 0000000..de3d5ce --- /dev/null +++ b/analyze_results/plot_coffe_results.py @@ -0,0 +1,101 @@ +import matplotlib.pyplot as plt +import csv +import sys +import argparse + + +def plot_key_vs_freq(data_dict,key=None,cost=False): + #use delay to get + target_freqs = [(1/float(i))*1000 if float(i) != 0 else None for i in data_dict["period"]] + achieved_freqs = [(1/float(i))*1000 if float(i) != 0 else None for i in data_dict["delay"]] + unique_tfreqs = list(set(target_freqs)) + freq_idxs = [None]*len(target_freqs) + #The freq_idxs array stores indexes for each report according to the target frequency + for i,u_tfreq in enumerate(unique_tfreqs): + for j,t_freq in enumerate(target_freqs): + if(t_freq == u_tfreq): + freq_idxs[j] = i + #now we have map from target freq to achived freq, use this to get to lists for each target_freq + tfreq_unique_data = [] + afreq_unique_data = [] + tfreq_unique_data_2 = [] + for i in range(len(unique_tfreqs)): + tfreq_unique_data.append([]) + afreq_unique_data.append([]) + tfreq_unique_data_2.append([]) + for idx,i in enumerate(freq_idxs): + if(cost == False): + tfreq_unique_data[i].append(float(data_dict[key][idx])) + else: + tfreq_unique_data[i].append(float(data_dict["area"][idx])) + tfreq_unique_data_2[i].append(float(data_dict["delay"][idx])) + afreq_unique_data[i].append(achieved_freqs[idx]) + avg_key_val = [None]*len(unique_tfreqs) + avg_achieved_freq = [None]*len(unique_tfreqs) + for i in range(len(unique_tfreqs)): + if(cost == False): + avg_key_val[i] = float(sum(tfreq_unique_data[i]))/float(len(tfreq_unique_data[i])) + else: + avg_key_val[i] = float(sum([area*delay for area,delay in zip(tfreq_unique_data[i],tfreq_unique_data_2[i])])/float(len(tfreq_unique_data[i]))) + avg_achieved_freq[i] = float(sum(afreq_unique_data[i]))/float(len(afreq_unique_data[i])) + fig, ax = plt.subplots(1,2,figsize=(12,5)) + fig.tight_layout(pad=5.0) + ax0_ylabel_str = "" + if(cost == False): + ys = [float(i) for i in data_dict[key]] + fig_name = f"{key}_fig.png" + if(key == "area"): + ax0_ylabel_str = "Area (um2)" + elif(key == "power"): + ax0_ylabel_str = "Power (mW)" + ys = [i*1000 for i in ys] + avg_key_val = [i*1000 for i in avg_key_val] + elif(key == "delay"): + ax0_ylabel_str = "Delay (ns)" + else: + fig_name = "cost_fig.png" + ax0_ylabel_str = "Area (um2) x Delay (ns)" + ys = [float(i)*float(j) for i,j in zip(data_dict["area"],data_dict["delay"])] + + xmin,xmax = (min(achieved_freqs),max(achieved_freqs)) + ymin,ymax = (min(ys), max(ys)) + yrange = ymax - ymin + xrange = xmax - xmin + #data plot for key selected + ax[0].set_xlim(xmin-(xrange/10),xmax+(xrange/10)) + ax[0].set_ylim(ymin-(yrange/10),ymax+(yrange/10)) + ax[0].set_xlabel("Achieved Freq (MHz)") + ax[0].set_ylabel(ax0_ylabel_str) + ax[0].scatter(achieved_freqs,ys,marker='x',c='b') + # average plot + ax[1].set_xlim(xmin-(xrange/10),xmax+(xrange/10)) + ax[1].set_ylim(ymin-(yrange/10),ymax+(yrange/10)) + ax[1].scatter(avg_achieved_freq,avg_key_val,marker='x',c='r') + ax[1].set_xlabel("Achieved Freq (MHz)") + ax[1].set_ylabel("Avg " + ax0_ylabel_str) + plt.savefig(fig_name) + +def read_csv(csv_path): + data_dict = {} + with open(csv_path,'r') as infile: + reader = csv.reader(infile) + header = next(reader) + next(reader) + out_list = [list(i) for i in zip(*reader)] + for idx,key in enumerate(header): + data_dict[key] = out_list[idx] + return data_dict + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-c','--csv_path',type=str,help="path to condensed csv file") + args = parser.parse_args() + arg_dict = vars(args) + data_dict = read_csv(arg_dict['csv_path']) + plot_key_vs_freq(data_dict,"area") + plot_key_vs_freq(data_dict,"delay") + plot_key_vs_freq(data_dict,"power") + plot_key_vs_freq(data_dict,cost=True) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/coffe/fpga.py b/coffe/fpga.py index 9fe222f..f105593 100644 --- a/coffe/fpga.py +++ b/coffe/fpga.py @@ -5175,8 +5175,10 @@ def generate_top(self): if self.parameters['num_dedicated_outputs'] > 0: self.dedicated.generate_top() - # hard flow + # hard block flow self.flow_results = hardblock_functions.hardblock_flow(self.parameters) + if(self.parameters["asic_flow_only"] == True): + sys.exit() #the area returned by the hardblock flow is in um^2. In area_dict, all areas are in nm^2 self.area = self.flow_results[0] * self.parameters['area_scale_factor'] * (1e+6) diff --git a/coffe/hardblock_functions.py b/coffe/hardblock_functions.py index 74690a1..28a1c1e 100644 --- a/coffe/hardblock_functions.py +++ b/coffe/hardblock_functions.py @@ -25,17 +25,11 @@ def hardblock_flow(flow_settings): ########################################### design_files = [] if flow_settings['design_language'] == 'verilog': - for file in os.listdir(os.path.expanduser(flow_settings['design_folder'])): - if file.endswith(".v"): - design_files.append(file) + design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".v")] elif flow_settings['design_language'] == 'vhdl': - for file in os.listdir(os.path.expanduser(flow_settings['design_folder'])): - if file.endswith(".vhdl"): - design_files.append(file) + design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".vhdl")] elif flow_settings['design_language'] == 'sverilog': - for file in os.listdir(os.path.expanduser(flow_settings['design_folder'])): - if file.endswith(".sv"): - design_files.append(file) + design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".sv") or fn.endswith(".v")] subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['synth_folder']) + "\n", shell=True) # Make sure we managed to read the design files assert len(design_files) >= 1 @@ -105,12 +99,11 @@ def hardblock_flow(flow_settings): file.close() # Run the scrip in design compiler shell - subprocess.call('dc_shell-t -f dc_script.tcl', shell=True, executable='/bin/tcsh') + subprocess.call('dc_shell-t -f dc_script.tcl | tee dc.log', shell=True) # clean after DC! subprocess.call('rm -rf command.log', shell=True) subprocess.call('rm -rf default.svf', shell=True) subprocess.call('rm -rf filenames.log', shell=True) - subprocess.call('rm -rf dc_script.tcl', shell=True) # Make sure it worked properly # Open the timing report and make sure the critical path is non-zero: @@ -124,8 +117,18 @@ def hardblock_flow(flow_settings): print "In spite of the warning, the rest of the flow will continue to execute." check_file.close() - #if the user doesn't want to perform place and route, extract the results from DC reports and end + #Copy synthesis results to a unique dir in synth dir + synth_report_str = "period_" + clock_period + "_" + "wire_mdl_" + wire_selection + report_dest_str = os.path.expanduser(flow_settings['synth_folder']) + "/" + synth_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['synth_folder']) + "/*.rpt " + report_dest_str + copy_logs_cmd_str = "cp " + "dc.log "+ "dc_script.tcl " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f dc.log dc_script.tcl',shell=True) + #if the user doesn't want to perform place and route, extract the results from DC reports and end if flow_settings['synthesis_only']: # read total area from the report file: @@ -161,7 +164,7 @@ def hardblock_flow(flow_settings): total_dynamic_power[0] *= 0.000001 else: total_dynamic_power[0] = 0 - file.close() + file.close() # write the final report file: file = open("report.txt" ,"w") @@ -325,13 +328,11 @@ def hardblock_flow(flow_settings): file.close() # Run the scrip in EDI - subprocess.call('encounter -nowin -init edi.tcl', shell=True) + subprocess.call('encounter -nowin -init edi.tcl | tee edi.log', shell=True) # clean after EDI! - subprocess.call('rm -rf edi.tcl', shell=True) - subprocess.call('rm -rf edi.conf', shell=True) subprocess.call('mv encounter.log ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter_log.log', shell=True) subprocess.call('mv encounter.cmd ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter.cmd', shell=True) - + # read total area from the report file: file = open(os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt" ,"r") for line in file: @@ -339,6 +340,17 @@ def hardblock_flow(flow_settings): total_area = re.findall(r'\d+\.{0,1}\d*', line) file.close() + #Copy pnr results to a unique dir in pnr dir + pnr_report_str = synth_report_str + "_" + "metal_layers_" + metal_layer + "_" + "util_" + core_utilization + report_dest_str = os.path.expanduser(flow_settings['pr_folder']) + "/" + pnr_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['pr_folder']) + "/*.rpt " + os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt " + report_dest_str + copy_logs_cmd_str = "cp " + "edi.log " + "edi.tcl " + "edi.conf " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f edi.log edi.conf edi.tcl', shell=True) + if len(flow_settings['mode_signal']) > 0: mode_enabled = True else: @@ -387,25 +399,30 @@ def hardblock_flow(flow_settings): file.write("set sh_enable_page_mode true \n") file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") - file.write("set link_path " + r'"* ' + flow_settings['primetime_lib_name'] + '"' + " \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set target_library " + flow_settings['target_libraries'] + "\n") + file.write("set link_library " + flow_settings['link_libraries'] + "\n") file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") if mode_enabled and x <2**len(flow_settings['mode_signal']): for y in range (0, len(flow_settings['mode_signal'])): file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") file.write("link \n") + + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") - file.write("create_clock -period " + clock_period + " " + flow_settings['clock_pin_name'] + " \n") file.write("read_parasitics -increment " + os.path.expanduser(flow_settings['pr_folder']) + "/spef.spef \n") file.write("report_timing > " + os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt \n") file.write("quit \n") file.close() # run prime time - subprocess.call('dc_shell-t -f primetime.tcl', shell=True) - - # clean after prime time - subprocess.call('rm -rf primetime.tcl', shell=True) + subprocess.call('dc_shell-t -f primetime.tcl | tee pt.log', shell=True) # Read timing parameters file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt" ,"r") @@ -424,12 +441,19 @@ def hardblock_flow(flow_settings): file.write("set sh_enable_page_mode true \n") file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") - file.write("set link_path " + r'"* ' + flow_settings['primetime_lib_name'] + '"' + " \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set target_library " + flow_settings['target_libraries'] + "\n") + file.write("set link_library " + flow_settings['link_libraries'] + "\n") file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") file.write("link \n") - file.write("create_clock -period " + str(total_delay) + " " + flow_settings['clock_pin_name'] + " \n") + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") if mode_enabled and x <2**len(flow_settings['mode_signal']): for y in range (0, len(flow_settings['mode_signal'])): file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") @@ -438,7 +462,7 @@ def hardblock_flow(flow_settings): if flow_settings['generate_activity_file']: file.write("read_saif -input saif.saif -instance_name testbench/uut \n") else: - file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " [all_nets] \n") + file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") #file.write("read_saif -input saif.saif -instance_name testbench/uut \n") #file.write("read_vcd -input ./modelsim_dir/vcd.vcd \n") file.write(r'read_parasitics -increment ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + "\n") @@ -448,12 +472,19 @@ def hardblock_flow(flow_settings): file.close() # run prime time - subprocess.call('dc_shell-t -f primetime_power.tcl', shell=True) - - # clean after prime time - subprocess.call('rm -rf primetime_power.tcl', shell=True) - - + subprocess.call('dc_shell-t -f primetime_power.tcl | tee pt_pwr.log', shell=True) + + #copy reports and logs to a unique dir in pt dir + pt_report_str = pnr_report_str + "_" + "mode_" + str(x) + report_dest_str = os.path.expanduser(flow_settings['primetime_folder']) + "/" + pt_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['primetime_folder']) + "/*.rpt " + report_dest_str + copy_logs_cmd_str = "cp " + "pt.log pt_pwr.log primetime.tcl primetime_power.tcl " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f pt.log pt_pwr.log primetime.tcl primetime_power.tcl', shell=True) + # Read dynamic power file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/power.rpt" ,"r") for line in file: diff --git a/coffe/utils.py b/coffe/utils.py index 5d7dd03..3664eed 100644 --- a/coffe/utils.py +++ b/coffe/utils.py @@ -509,6 +509,8 @@ def load_arch_params(filename): 'FAs_per_flut':2, 'hb_files' : [], 'arch_out_folder': "None", + # 'coffe_design_name' : "coffe_test", + # 'coffe_repo_path' : "None" } params_file = open(filename, 'r') @@ -658,6 +660,10 @@ def load_arch_params(filename): arch_params['hb_files'].append(value) elif param == 'arch_out_folder': arch_params['arch_out_folder'] = value + # elif param == 'coffe_design_name': + # arch_params['coffe_design_name'] = str(value) + # elif param == 'coffe_repo_path': + # arch_params['coffe_repo_path'] = str(value) params_file.close() @@ -704,6 +710,7 @@ def load_hard_params(filename): 'synth_folder': "", 'show_warnings': False, 'synthesis_only': False, + 'asic_flow_only': False, 'read_saif_file': False, 'static_probability': -1.0, 'toggle_rate': -1, @@ -850,6 +857,8 @@ def load_hard_params(filename): hard_params['show_warnings'] = (value == "True") elif param == 'synthesis_only': hard_params['synthesis_only'] = (value == "True") + elif param == 'asic_flow_only': + hard_params['asic_flow_only'] = (value == "True") elif param == 'read_saif_file': hard_params['read_saif_file'] = (value == "True") elif param == 'static_probability': @@ -978,7 +987,9 @@ def check_arch_params (arch_params, filename): if arch_params['enable_bram_module'] == 1 and arch_params['use_finfet'] == True: print_error_not_compatable("finfet", "BRAM") if arch_params['use_finfet'] == True and arch_params['use_fluts'] == True: - print_error_not_compatable("finfet", "flut") + print_error_not_compatable("finfet", "flut") + # if arch_params['coffe_repo_path'].split("/")[-1] != "COFFE": + # print_error (arch_params['coffe_repo_path'],"coffe_repo_path",filename) diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v new file mode 100755 index 0000000..2b401e7 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v @@ -0,0 +1,50 @@ +//Two multipliers and adder + +module accumulate( +A0, +B0, +C0, +clk, +add_previous, +reset, +mode_0, +S +); + +input [71:0] A0; +input [71:0] B0; +input [43:0] C0; +input clk; +input reset; +input add_previous; +input mode_0; +output [143:0] S; + + +wire [37:0] A0pB0; +wire [43:0] accumulated; +reg [37:0] A0pB0_reg; +reg [143:0] S_temp; + +always @(posedge clk) +if (reset) begin + A0pB0_reg <= 38'b0; + S_temp <= 144'b0; + end else begin + A0pB0_reg <= A0pB0; + if (mode_0) begin + S_temp <= {A0[71:0],B0[71:0]}; + end else if (add_previous) begin + S_temp <= { accumulated , 100'd0}; + end else begin + S_temp <= {A0pB0_reg, 100'd0}; + end + +end + + +assign A0pB0 = A0[35:0] + B0[35:0]; +assign accumulated = A0pB0_reg + C0; +assign S = S_temp; + +endmodule diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v new file mode 100755 index 0000000..0e2f684 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v @@ -0,0 +1,98 @@ +module dsp ( +A0, +A1, +B0, +B1, +C0, +C1, +D0, +D1, +E0, +E1, +F0, +F1, +G0, +G1, +H0, +H1, +from_previous, +add_previous, +clk, +mode_0, +mode_1, +reset, +result0, +result1 +); + +input [17:0] A0; +input [17:0] A1; +input [17:0] B0; +input [17:0] B1; +input [17:0] C0; +input [17:0] C1; +input [17:0] D0; +input [17:0] D1; +input [17:0] E0; +input [17:0] E1; +input [17:0] F0; +input [17:0] F1; +input [17:0] G0; +input [17:0] G1; +input [17:0] H0; +input [17:0] H1; +input [43:0] from_previous; +input clk; +input reset; +input mode_0; +input mode_1; +input add_previous; + +output [143:0] result0; +output [143:0] result1; + +wire [143:0] the_output0; +wire [143:0] the_output1; + +half_dsp m0( +.A0 (A0), +.A1 (A1), +.B0 (B0), +.B1 (B1), +.C0 (C0), +.C1 (C1), +.D0 (D0), +.D1 (D1), +.mode_0 (mode_0), +.mode_1 (mode_1), +.from_previous (from_previous), +.add_previous (add_previous), +.clk (clk), +.reset (reset), +.result (the_output0) +); + + +half_dsp m1( +.A0 (E0), +.A1 (E1), +.B0 (F0), +.B1 (F1), +.C0 (G0), +.C1 (G1), +.D0 (H0), +.D1 (H1), +.mode_0 (mode_0), +.mode_1 (mode_1), +.from_previous (the_output0[71:28]), +.add_previous (add_previous), +.clk (clk), +.reset (reset), +.result (the_output1) +); + + +assign result0 = the_output0; +assign result1 = the_output1; + +endmodule \ No newline at end of file diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v new file mode 100755 index 0000000..9f92b91 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v @@ -0,0 +1,79 @@ +module half_dsp ( +A0, +A1, +B0, +B1, +C0, +C1, +D0, +D1, +mode_0, +mode_1, +from_previous, +add_previous, +clk, +reset, +result +); + +input [17:0] A0; +input [17:0] A1; +input [17:0] B0; +input [17:0] B1; +input [17:0] C0; +input [17:0] C1; +input [17:0] D0; +input [17:0] D1; +input [43:0] from_previous; +input clk; +input reset; +input mode_0; +input mode_1; +input add_previous; + +output [143:0] result; + +wire [71:0] partial_0; +wire [71:0] partial_1; +wire [143:0] the_output; + +two_multipliers_one_adder m0( +.A0 (A0), +.A1 (A1), +.B0 (B0), +.B1 (B1), +.clk (clk), +.mode_0 (mode_0), +.mode_1 (mode_1), +.reset (reset), +.P (partial_0) +); + + +two_multipliers_one_adder m1( +.A0 (C0), +.A1 (C1), +.B0 (D0), +.B1 (D1), +.clk (clk), +.mode_0 (mode_0), +.mode_1 (mode_1), +.reset (reset), +.P (partial_1) +); + + +accumulate m2( +.A0 (partial_0), +.B0 (partial_1), +.C0 (from_previous), +.add_previous (add_previous), +.S (the_output), +.clk (clk), +.mode_0 (mode_0), +.reset (reset) +); + +assign result = the_output; + +endmodule \ No newline at end of file diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v new file mode 100755 index 0000000..7f13aa8 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v @@ -0,0 +1,64 @@ +//Two multipliers and adder + +module two_multipliers_one_adder( +A0, +A1, +B0, +B1, +clk, +reset, +mode_0, +mode_1, +P +); + +input [17:0] A0; +input [17:0] A1; +input [17:0] B0; +input [17:0] B1; +input clk; +input reset; +input mode_0; +input mode_1; +output [71:0] P; + + +reg [17:0] A0_registered; +reg [17:0] B0_registered; +reg [17:0] A1_registered; +reg [17:0] B1_registered; + +wire [35:0] A0xB0; +wire [35:0] A1xB1; +wire [36:0] tempsum; + +reg [71:0] moutput; + +always @(posedge clk) +if (reset) begin + A0_registered <= 18'b0; + A1_registered <= 18'b0; + B0_registered <= 18'b0; + B1_registered <= 18'b0; + moutput <= 72'b0; + + end else begin + A0_registered <= A0; + A1_registered <= A1; + B0_registered <= B0; + B1_registered <= B1; + if (mode_0 == 1'b0 && mode_1 ==1'b0) begin + moutput <= {35'd0, tempsum}; + end else if (mode_0 == 1'b1 && mode_1 ==1'b0) begin + moutput <= {A0xB0, A1xB1}; + end else begin + moutput <= {36'd0, A0xB0}; + end +end + +assign A0xB0 = A0_registered * B0_registered; +assign A1xB1 = A1_registered * B1_registered; +assign P = moutput; +assign tempsum = A0xB0 + A1xB1; + +endmodule diff --git a/input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt b/input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt new file mode 100755 index 0000000..13f3c86 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt @@ -0,0 +1,204 @@ +# EXAMPLE COFFE INPUT FILE (BULK TRANSISTORS) +# +# Note: COFFE interprets any line beginning with a '#' as a comment in it's input files. +# +# COFFE input parameters can be divided into 2 groups: +# 1- Parameters describing the FPGA architecture +# 2- Process technology-related parameters +# +# [1] C. Chiasson and V.Betz. "COFFE: Fully-Automated Transistor Sizing for FPGAs", +# IEEE Int. Conf. on Field-Programmable Technology (FPT), 2013 + +####################################### +##### General parameters +####################################### + +#Abs path to COFFE repo +coffe_repo_path=/fs1/eecg/vaughn/morestep/COFFE + +#The directory in which all outputs are generated, makes it easier to make sense of data +coffe_design_name=strtx_III_dsp_sadegh + +#The directory in which output files will be stored. +#If not specified, the directory containing this file is used as output dir. +arch_out_folder=/fs1/eecg/vaughn/morestep/COFFE/output_files/strtx_III_dsp_sadegh/arch_out_dir + +####################################### +##### Architecture Parameters +####################################### + +# The following parameters are the classic VPR architecture parameters +N=10 +K=6 +W=320 +L=4 +I=40 +Fs=3 +Fcin=0.2 +Fcout=0.025 + +# The following architecture parameters are new and help COFFE describe +# a more flexible BLE. See [1] for more details. + +# Number of BLE outputs to general routing +Or=2 + +# Number of BLE outputs to local routing +Ofb=1 + +# Population of local routing MUXes +Fclocal=0.5 + +# Register select: +# Defines whether the FF can accept it's input directly from a BLE input or not. +# To turn register-select off, Rsel=z +# To turn register select on, Rsel= +# where = the name of the BLE input from which the FF can +# accept its input (e.g. a, b, c, etc...). +Rsel=c + +# Register feedback muxes: +# Defines which LUT inputs support register feedback. +# Set Rfb to a string of LUT input names. +# For example: +# Rfb=c tells COFFE to place a register feedback mux on LUT input C. +# Rfb=cd tells COFFE to place a register feedback mux on both LUT inputs C and D. +# Rfb=z tells COFFE that no LUT input should have register feedback muxes. +Rfb=c + +# Do we want to use fracturable Luts? +use_fluts=False +# can be as large as K-1 +#independent_inputs = 0 + +#enable_carry_chain = 1 +#carry_chain_type = skip +#FAs_per_flut = 2 + + +####################################### +##### Memory Block Parameters +####################################### + +# Do we want Block RAM simulation at all? +enable_bram_module = 0 + +#Memory block voltage (low power transistors) +vdd_low_power = 0.95 + + +# Memory technology type can be 'SRAM' or 'MTJ'. +memory_technology = SRAM + +# The following determine the number of address bits used in each of the decoders +# These bits are used to determine the aspect ratio of the memory module +# Please note: if you use a two-bank BRAM, one of the bits below will be decoded by the bank selection address +# To make it controllable, I decided that this bit will always be taken from the row decoder. + +# Row decoder +row_decoder_bits = 8 +# Column decoder +col_decoder_bits = 2 +# Width configurable decoder +conf_decoder_bits = 5 +# Number of RAM banks +number_of_banks = 2 + + +# voltage difference for the sense amp in volts +sense_dv = 0.03 + +# Weakest SRAM cell current in Amps +worst_read_current = 0.0000015 + +#MTJ resisitance values for 4 combinations of nominal/worst case for low/high states +MTJ_Rlow_nominal = 2500 +MTJ_Rhigh_nominal = 6250 +MTJ_Rlow_worstcase = 3060 +MTJ_Rhigh_worstcase = 4840 + + +# BRAM read to write ratio for power measurements: +read_to_write_ratio = 1.0 + +####################################### +##### Process Technology Parameters +####################################### + +# Transistor type can be 'bulk' or 'finfet'. +# Make sure your spice model file matches the transistor type you choose. +transistor_type=bulk + +# The switch type can be 'pass_transistor' or 'transmission_gate'. +switch_type=pass_transistor +#switch_type=transmission_gate + +# Supply voltage +vdd=0.8 + +# SRAM Vdd +vsram=1.0 + +# SRAM Vss +vsram_n=0.0 + +# Gate length (nm) +gate_length=22 + +# This parameter controls the gate length of PMOS level-restorers. For example, setting this paramater +# to 4 sets the gate length to 4x the value of 'gate_legnth'. Increasing the gate length weakens the +# PMOS level-restorer, which is sometimes necessary to ensure proper switching. +rest_length_factor = 1 + +# Minimum transistor diffusion width (nm). +min_tran_width=45 + +# Length of diffusion for a single-finger transistor (nm). +# COFFE uses this when it calculates source/drain parasitic capacitances. +trans_diffusion_length = 52 + +# Minimum-width transistor area (nm^2) +min_width_tran_area = 33864 + +# SRAM area (in number of minimum width transistor areas) +sram_cell_area = 4 + +# Path to SPICE device models file and library to use +model_path=spice_models/ptm_22nm_bulk_hp.l +model_library=22NM_BULK_HP + +####################################### +##### Metal data +##### R in ohms/nm +##### C in fF/nm +##### format: metal=R,C +##### ex: metal=0.054825,0.000175 +####################################### + +# Each 'metal' statement defines a new metal layer. +# COFFE uses two metal layers by default. The first metal layer is where COFFE +# implements all wires except for the general routing wires. They are implemented +# in the second metal layer. + + +# All wires except the general routing wires are implemented in this layer. +metal=0.054825,0.000175 + +# General routing wires will be implemented in this layer +metal=0.007862,0.000215 + +# Memory array wires will be implemented in this layer +metal=0.029240,0.000139 + +# This layer is used in MTJ wordline (if BRAM technology is MTJ) +metal=0.227273,0.000000 + +# If you wanted to, you could define more metal layers by adding more 'metal' +# statements but, by default, COFFE would not use them because it only uses 2 layers. +# The functionality of being able to add any number of metal layers is here to allow +# you to investigate the use of more than 2 metal layers if you wanted to. However, +# making use of more metal layers would require changes to the COFFE source code. + + +# if hybrid blocks are enabled, list configurations here +hb_files = input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt diff --git a/input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt b/input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt new file mode 100755 index 0000000..99c5b55 --- /dev/null +++ b/input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt @@ -0,0 +1,164 @@ +#This is a sample settings file for the hard block flow + +############################################# +########## General Design Settings ########## +############################################# + +# The folder in which all the design files are located: +design_folder=/fs1/eecg/vaughn/morestep/COFFE/input_files/strtx_III_dsp_sadegh/dsp_block_hdl + +# The design language. Should be either 'verilog', 'vhdl' or 'sverilog' +design_language=verilog +# The exponents of delay and area in the cost function. +# cost = (delay ^ delay_cost_exp) * (area ^ area_cost_exp) +delay_cost_exp=1.0 +area_cost_exp=1.0 + + +######################################## +########## Synthesis Settings ########## +######################################## + +# Name of the clock pin in the design +clock_pin_name=clk +## -> this means that this was changed to run hspice on bastet +# Desired clock period in ns +##clock_period=1.53 +#clock_period=1.66 +#clock_period=1.81 +clock_period=2.0 +#clock_period=2.22 +#clock_period=2.5 + +# Name of the top-level entity in the design +#top_level=ASU_conv +top_level=dsp + +# The name of the folder in which post-synthesis files and synthesis reports are to be stored +synth_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/synth + +# Do you want to be informed of warnings during synthesis? + +show_warnings=True + +# Should the flow terminate after synthesis? +# A value of "False" will continue into placement and routing +synthesis_only=False + +# Do you want to provide a saif file for power analysis? +# In case of setting this to "True" a saif.saif file should be provided +read_saif_file=False + +# If you don't want to provide a saif file, specify the switching activity parameters below: +static_probability=0.5 +toggle_rate=25 + +# Should COFFE generate an activity file for the design (using modelsim) +generate_activity_file=False +# Location of the library files. +# if you have more than one library, please provide them similiar to the example below. + +link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" + +target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" + +############################################## +########## Place and Route Settings ########## +############################################## + +# Libraries required in EDI: + +#metal_layers=8 +metal_layers=7 +#metal_layers=6 +#metal_layers=5 + +#names of metal layers starting from the bottom-most layer on the left. use a python list format. +metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] + +#names of metal layers to use for each side of the power ring +#order: top, bottom, left, right +power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] + +#name of the file to use for layer mapping. used for stream out. +#set it to None if you want the tool to create a generic map file +map_file=streamOut.map +wire_selection=WireAreaLowkCon +wire_selection=WireAreaLowkAgr +#wire_selection=WireAreaForZero +#specify names of ground and power pins and nets in the library +gnd_net=VSS +gnd_pin=VSS +pwr_net=VDD +pwr_pin=VDD +tilehi_tielo_cells_between_power_gnd=True + + +#specify footprint names for inverters, buffers, delays. +#this is optional. you can get these values from the lib file. +#you can also specify None, if you can't find them in the lib file. +#SM: not sure if these are the correct standard cells to be using, as there are many options (need to figure out what DX refers to) +inv_footprint=INVD0 +buf_footprint=BUFFD1 +delay_footprint=DEL0 + +#list of filler cell names. use a python list format. +#the names can be obtained from .lib files. +filler_cell_names=["FILL1", "FILL16", "FILL1_LL", "FILL2", "FILL32", "FILL64", "FILL8", "FILL_NW_FA_LL", "FILL_NW_HH", "FILL_NW_LL"] + +#name of the core site in the floorplan. can be obtained from lef files. +core_site_name=core + +#specify the utilization of the core site. you can specify multiple ones on different lines. +##core_utilization=0.85 +core_utilization=0.90 +##core_utilization=0.95 + +lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_9lmT2.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/antenna_9lm.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/tpzn65gpgv2_9lm.lef" + + +best_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2bc.lib" + +standard_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.lib" + +worst_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.lib" + + + +# EDI settings: +power_ring_width=3 +power_ring_spacing=3 +height_to_width_ratio=4.0 + +space_around_core=5 + + +# The folder in which place and route reports and post-routing netlists and spef files will be stored +pr_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/pr + + +############################################## +########## Prime Time Settings ############### +############################################## + +mode_signal=mode_0 +mode_signal=mode_1 + +primetime_lib_path=". /CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" + +primetime_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/pt + +# COFFE parameters: +name=hard_block +num_gen_inputs=288 +crossbar_population=0.5 +height=1 +num_gen_outputs=288 +num_dedicated_outputs=0 +soft_logic_per_block=0.1 +area_scale_factor=0.12 +freq_scale_factor=1.35 +power_scale_factor=0.3 +input_usage=0.8 +num_crossbars=1 +crossbar_modelling=optimistic \ No newline at end of file From 638d1c70711d4962c0074bedd47541e73e566136 Mon Sep 17 00:00:00 2001 From: Stephen More Date: Thu, 13 Oct 2022 02:28:47 -0400 Subject: [PATCH 2/7] cleaned up hardblock flow to make it more understandable, updated readme --- User Manual.md | 56 ++ coffe/hardblock_functions.py | 897 +++++++++--------- coffe/utils.py | 2 +- .../coffe_inp_params.txt | 2 +- .../simple_dsp_slice_65nm/dsp_slice.txt | 58 +- .../dsp_block_hdl/accumulate.v | 0 .../dsp_block_hdl/dsp.v | 0 .../dsp_block_hdl/half_dsp.v | 0 .../dsp_block_hdl/twomadder.v | 0 .../dsp_coffe_params.txt | 8 +- .../dsp_hb_settings.txt | 11 +- 11 files changed, 532 insertions(+), 502 deletions(-) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_block_hdl/accumulate.v (100%) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_block_hdl/dsp.v (100%) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_block_hdl/half_dsp.v (100%) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_block_hdl/twomadder.v (100%) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_coffe_params.txt (92%) rename input_files/{strtx_III_dsp_sadegh => strtx_III_dsp}/dsp_hb_settings.txt (91%) diff --git a/User Manual.md b/User Manual.md index 3e5f183..9b8022b 100644 --- a/User Manual.md +++ b/User Manual.md @@ -29,6 +29,62 @@ To run COFFE, simply run coffe.py and follow the instructions. There are several sample input files in the test directory accompanying COFFE which stimulate all existing features. These files describe what each of the parameters are; simply read them and change them to form your desired architecture. We have also included several tests with COFFE which should smoothly run when using the latest version. To test your setup, you can run those. +# How to run a test for ASIC flow (using stratix III like DSP) +The following test was tested with the following tools: +-Synopsys Design Compiler 2017 +-Cadence Encounter 2009 + +Prerequisites: +Make sure the ASIC tools are on your environments path, this can be done with the following commands: +$(which dc_shell-t) +$(which encounter) + +1. Now the configuration files for the asic tools must be edited to match the environment and ASIC PDK being used +(If you're using UofT servers you can skip this portion as they're already setup) + + open up the following file in editor: + - ~/COFFE/input_files/strtx_III_dsp/dsp_hb_settings.txt + + If you only want to run the asic flow, set the "asic_flow_only" param to True + + - set the "target_libraries" and "link_libraries" parameters to the absolute paths to the standard cell front end .db files provided by semiconductor PDK (surrounded by quotes). + - set the "inv_footprint", "buf_footprint", and "delay_footprint" params to footprints, found in front end .lib files from pdk (found under similar names to "INVD0" "BUFFD1" "DEL0") + + The following params can be found in the PDK back end .lef files + - set "metal_layer_names", "filler_cell_names", "core_site_name" params + - set the "lef_files" param to the absolute path of the .lef files + + Note: + make sure the number of metal layers being used is less than or equal to the number of metal_layer_names defined. + make sure the .lef file has the correct number of metal layers as well + + - set the "best_case_libs", "standard_libs", and "worst_case_libs" to the corresponding absolute paths to PDK ".lib" files + - set the primetime_lib_path to the absolute paths of the following design compiler directories and the front end PDK dirs used + Optional Parameter Changes: + - if desired one can sweep target frequency, number of metal layers, wire load model, core utilization, and mode of operation (this currently only works for dsp block) + - to add additional sweep parameters one would define the variable to be swept again with the new value: + - Ex. + clock_period=2.0 + clock_period=2.5 + etc... +2. run the following command (run this with python2): + - $(python2 coffe.py -i 1 input_files/strtx_III_dsp/dsp_coffe_params.txt) + +3. Once the program has finished go to the following directory: + - ~/COFFE/analyze_results + + run the following command the argument points to where the .txt reports from post ASIC flow exist, which should be the same as the arch_out_folder param in dsp_coffe_params.txt): + - $(python2 condense_results.py -r ../output_files/strtx_III_dsp/arch_out_dir) + + The above command creates a csv file with all reports from the specified directory. + To plot the power, area, and delay results against target frequency run the following command (this requires python3 and matplotlib to be installed): + - $(python3 plot_coffe_results.py -c report_csv_out/condensed_report.csv) + + + + + + ## How to report an issue. If you encounter an issue running COFFE, or if you have any questions about the features we support, please file an issue in github. diff --git a/coffe/hardblock_functions.py b/coffe/hardblock_functions.py index 28a1c1e..56da169 100644 --- a/coffe/hardblock_functions.py +++ b/coffe/hardblock_functions.py @@ -10,7 +10,422 @@ import shutil import math - +def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_selection): + ########################################### + # Synthesis + ########################################### + file = open("dc_script.tcl","w") + file.write("cd " + os.path.expanduser(flow_settings['synth_folder']) + "\n") + file.write("set search_path " + "\"" + " ".join(search_path_dirs) + "\"" + " \n") + if len(design_files) == 1: + file.write("set my_files " + design_files[0] + "\n") + else: + file.write("set my_files [list ") + for entity in design_files: + if not (entity == "parameters.v" or entity == "c_functions.v"): + file.write(entity + " ") + file.write("] \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set link_library " + flow_settings['link_libraries'] + "\n") + file.write("set target_library " + flow_settings['target_libraries'] + "\n") + file.write(r'set power_analysis_mode "averaged"' + "\n") + file.write("define_design_lib WORK -path ./WORK \n") + if flow_settings['design_language'] == 'verilog': + file.write("analyze -f verilog $my_files \n") + elif flow_settings['design_language'] == 'vhdl': + file.write("analyze -f vhdl $my_files \n") + else: + file.write("analyze -f sverilog $my_files \n") + file.write("elaborate $my_top_level \n") + file.write("current_design $my_top_level \n") + file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/checkprecompile.rpt\n") + file.write("link \n") + file.write("uniquify \n") + #If wire_selection is None, then no wireload model is used during synthesis. This does imply results + #are not as accurate (wires don't have any delay and area), but is useful to let the flow work/proceed + #if the std cell library is missing wireload models. + if wire_selection != "None": + file.write(r'set_wire_load_selection ' + wire_selection + " \n") + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") + file.write("compile_ultra\n") + file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt\n") + file.write("link \n") + file.write("write_file -format ddc -hierarchy -output " + os.path.expanduser(flow_settings['synth_folder']) + "/" + flow_settings['top_level'] + ".ddc \n") + if flow_settings['read_saif_file']: + file.write("read_saif saif.saif \n") + else: + file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") + file.write("ungroup -all -flatten \n") + file.write("report_power > " + os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt\n") + file.write("report_area -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt\n") + file.write("report_resources -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/resources.rpt\n") + file.write("report_timing > " + os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt\n") + file.write("change_names -hier -rule verilog \n") + file.write("write -f verilog -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.v\n") + file.write("write_sdf " + os.path.expanduser(flow_settings['synth_folder']) + "/synthsized.sdf \n") + file.write("write_parasitics -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.spef \n") + file.write("write_sdc " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.sdc \n") + file.write("quit \n") + file.close() + + # Run the scrip in design compiler shell + subprocess.call('dc_shell-t -f dc_script.tcl | tee dc.log', shell=True,executable="/bin/bash") + # clean after DC! + subprocess.call('rm -rf command.log', shell=True) + subprocess.call('rm -rf default.svf', shell=True) + subprocess.call('rm -rf filenames.log', shell=True) + + # Make sure it worked properly + # Open the timing report and make sure the critical path is non-zero: + check_file = open(os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt", "r") + for line in check_file: + if "Error" in line: + print "Your design has errors. Refer to check.rpt in synthesis directory" + exit(-1) + elif "Warning" in line and flow_settings['show_warnings']: + print "Your design has warnings. Refer to check.rpt in synthesis directory" + print "In spite of the warning, the rest of the flow will continue to execute." + check_file.close() + + #Copy synthesis results to a unique dir in synth dir + synth_report_str = "period_" + clock_period + "_" + "wire_mdl_" + wire_selection + report_dest_str = os.path.expanduser(flow_settings['synth_folder']) + "/" + synth_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['synth_folder']) + "/*.rpt " + report_dest_str + copy_logs_cmd_str = "cp " + "dc.log "+ "dc_script.tcl " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f dc.log dc_script.tcl',shell=True) + + #if the user doesn't want to perform place and route, extract the results from DC reports and end + if flow_settings['synthesis_only']: + # read total area from the report file: + file = open(os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt" ,"r") + for line in file: + if line.startswith('Total cell area:'): + total_area = re.findall(r'\d+\.{0,1}\d*', line) + file.close() + # Read timing parameters + file = open(os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt" ,"r") + for line in file: + if 'library setup time' in line: + library_setup_time = re.findall(r'\d+\.{0,1}\d*', line) + if 'data arrival time' in line: + data_arrival_time = re.findall(r'\d+\.{0,1}\d*', line) + try: + total_delay = float(library_setup_time[0]) + float(data_arrival_time[0]) + except NameError: + total_delay = float(data_arrival_time[0]) + file.close() + # Read dynamic power + file = open(os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt" ,"r") + for line in file: + if 'Total Dynamic Power' in line: + total_dynamic_power = re.findall(r'\d+\.\d*', line) + total_dynamic_power[0] = float(total_dynamic_power[0]) + if 'mW' in line: + total_dynamic_power[0] *= 0.001 + elif 'uw' in line: + total_dynamic_power[0] *= 0.000001 + else: + total_dynamic_power[0] = 0 + file.close() + # write the final report file: + file = open("report.txt" ,"w") + file.write("total area = " + str(total_area[0]) + "\n") + file.write("total delay = " + str(total_delay) + " ns\n") + file.write("total power = " + str(total_dynamic_power[0]) + " W\n") + file.close() + #return + exit() + return synth_report_str + + +def run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str): + ########################################### + # Place and Route + ########################################### + # generate the EDI (encounter) configuration + file = open("edi.conf", "w") + file.write("global rda_Input \n") + file.write("set cwd .\n\n") + file.write("set rda_Input(ui_leffile) " + flow_settings['lef_files'] + "\n") + file.write("set rda_Input(ui_timelib,min) " + flow_settings['best_case_libs'] + "\n") + file.write("set rda_Input(ui_timelib) " + flow_settings['standard_libs'] + "\n") + file.write("set rda_Input(ui_timelib,max) " + flow_settings['worst_case_libs'] + "\n") + file.write("set rda_Input(ui_netlist) " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.v" + "\n") + file.write("set rda_Input(ui_netlisttype) {Verilog} \n") + file.write("set rda_Input(import_mode) {-treatUndefinedCellAsBbox 0 -keepEmptyModule 1}\n") + file.write("set rda_Input(ui_timingcon_file) " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.sdc" + "\n") + file.write("set rda_Input(ui_topcell) " + flow_settings['top_level'] + "\n\n") + gnd_pin = flow_settings['gnd_pin'] + gnd_net = flow_settings['gnd_net'] + pwr_pin = flow_settings['pwr_pin'] + pwr_net = flow_settings['pwr_net'] + file.write("set rda_Input(ui_gndnet) {" + gnd_net + "} \n") + file.write("set rda_Input(ui_pwrnet) {" + pwr_net + "} \n") + if flow_settings['tilehi_tielo_cells_between_power_gnd'] is True: + file.write("set rda_Input(ui_pg_connections) [list {PIN:" + gnd_pin + ":}" + " {TIEL::} " + "{NET:" + gnd_net + ":} {NET:" + pwr_net + ":}" + " {TIEH::} " + "{PIN:" + pwr_pin + ":} ] \n") + else: + file.write("set rda_Input(ui_pg_connections) [list {PIN:" + gnd_pin + ":} {NET:" + gnd_net + ":} {NET:" + pwr_net + ":} {PIN:" + pwr_pin + ":} ] \n") + file.write("set rda_Input(PIN:" + gnd_pin + ":) {" + gnd_pin + "} \n") + file.write("set rda_Input(TIEL::) {" + gnd_pin + "} \n") + file.write("set rda_Input(NET:" + gnd_net + ":) {" + gnd_net + "} \n") + file.write("set rda_Input(PIN:" + pwr_pin + ":) {" + pwr_pin + "} \n") + file.write("set rda_Input(TIEH::) {" + pwr_pin + "} \n") + file.write("set rda_Input(NET:" + pwr_net + ":) {" + pwr_net + "} \n\n") + if (flow_settings['inv_footprint'] != "None"): + file.write("set rda_Input(ui_inv_footprint) {" + flow_settings['inv_footprint'] + "}\n") + if (flow_settings['buf_footprint'] != "None"): + file.write("set rda_Input(ui_buf_footprint) {" + flow_settings['buf_footprint'] + "}\n") + if (flow_settings['delay_footprint'] != "None"): + file.write("set rda_Input(ui_delay_footprint) {" + flow_settings['delay_footprint'] + "}\n") + file.close() + metal_layer_bottom = flow_settings["metal_layer_names"][0] + metal_layer_second = flow_settings["metal_layer_names"][1] + metal_layer_top = flow_settings["metal_layer_names"][int(metal_layer)-1] + power_ring_metal_top = flow_settings["power_ring_metal_layer_names"][0] + power_ring_metal_bottom = flow_settings["power_ring_metal_layer_names"][1] + power_ring_metal_left = flow_settings["power_ring_metal_layer_names"][2] + power_ring_metal_right = flow_settings["power_ring_metal_layer_names"][3] + # generate the EDI (encounter) script + file = open("edi.tcl", "w") + file.write("loadConfig edi.conf \n") + file.write("floorPlan -site " + flow_settings['core_site_name'] \ + + " -r " + str(flow_settings['height_to_width_ratio']) \ + + " " + str(core_utilization) \ + + " " + str(flow_settings['space_around_core']) \ + + " " + str(flow_settings['space_around_core']) + " ") + file.write(str(flow_settings['space_around_core']) + " " + str(flow_settings['space_around_core']) + "\n") + file.write("setMaxRouteLayer " + str(metal_layer) + " \n") + file.write("fit \n") + file.write("addRing -spacing_bottom " + str(flow_settings['power_ring_spacing']) \ + + " -spacing_right " + str(flow_settings['power_ring_spacing']) \ + + " -spacing_top " + str(flow_settings['power_ring_spacing']) \ + + " -spacing_left " + str(flow_settings['power_ring_spacing']) \ + + " -width_right " + str(flow_settings['power_ring_width']) \ + + " -width_left " + str(flow_settings['power_ring_width']) \ + + " -width_bottom " + str(flow_settings['power_ring_width']) \ + + " -width_top " + str(flow_settings['power_ring_width']) \ + + " -center 1" \ + + " -around core" \ + + " -layer_top " + power_ring_metal_top \ + + " -layer_bottom " + power_ring_metal_bottom \ + + " -layer_left " + power_ring_metal_left \ + + " -layer_right " + power_ring_metal_right \ + + " -nets { " + gnd_net + " " + pwr_net + " }" \ + + " -stacked_via_top_layer "+ metal_layer_top \ + + " -stacked_via_bottom_layer " + metal_layer_bottom + " \n") + file.write("setPlaceMode -fp false -maxRouteLayer " + str(metal_layer) + "\n") + file.write("placeDesign -inPlaceOpt -noPrePlaceOpt \n") + file.write("checkPlace " + flow_settings['top_level'] +" \n") + file.write("trialroute \n") + file.write("buildTimingGraph \n") + file.write("timeDesign -preCTS -idealClock -numPaths 10 -prefix preCTS -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/timeDesignpreCTSReports" + "\n") + file.write("optDesign -preCTS -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/optDesignpreCTSReports" + "\n") + # I won't do a CTS anyway as the blocks are small. + file.write("addFiller -cell {" + " ".join([str(item) for item in flow_settings['filler_cell_names']]) + "} -prefix FILL -merge true \n") + file.write("clearGlobalNets \n") + file.write("globalNetConnect " + gnd_net + " -type pgpin -pin " + gnd_pin + " -inst {} \n") + file.write("globalNetConnect " + pwr_net + " -type pgpin -pin " + pwr_pin + " -inst {} \n") + file.write("globalNetConnect " + gnd_net + " -type net -net " + gnd_net + " \n") + file.write("globalNetConnect " + pwr_net + " -type net -net " + pwr_net + " \n") + file.write("globalNetConnect " + pwr_net + " -type pgpin -pin " + pwr_pin + " -inst * \n") + file.write("globalNetConnect " + gnd_net + " -type pgpin -pin " + gnd_pin + " -inst * \n") + file.write("globalNetConnect " + pwr_net + " -type tiehi -inst * \n") + file.write("globalNetConnect " + gnd_net + " -type tielo -inst * \n") + file.write("sroute -connect { blockPin padPin padRing corePin floatingStripe }" \ + + " -layerChangeRange { " + metal_layer_bottom + " " + metal_layer_top + " }" \ + + " -blockPinTarget { nearestRingStripe nearestTarget }" \ + + " -padPinPortConnect { allPort oneGeom }" \ + + " -checkAlignedSecondaryPin 1" \ + + " -blockPin useLef" \ + + " -allowJogging 1" \ + + " -crossoverViaBottomLayer " + metal_layer_bottom \ + + " -allowLayerChange 1" \ + + " -targetViaTopLayer " + metal_layer_top \ + + " -crossoverViaTopLayer " + metal_layer_top \ + + " -targetViaBottomLayer " + metal_layer_bottom \ + + " -nets { " + gnd_net + " " + pwr_net + " } \n") + file.write("routeDesign -globalDetail\n") + file.write("setExtractRCMode -engine postRoute \n") + file.write("extractRC \n") + file.write("buildTimingGraph \n") + file.write("timeDesign -postRoute -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/timeDesignReports" + "\n") + file.write("optDesign -postRoute -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/optDesignReports" + "\n") + #by default, violations are reported in designname.geom.rpt + file.write("verifyGeometry -report " + (os.path.expanduser(flow_settings['pr_folder']) + "/" + flow_settings['top_level'] + ".geom.rpt") + "\n") + #by default, violations are reported in designname.conn.rpt + file.write("verifyConnectivity -type all -report " + (os.path.expanduser(flow_settings['pr_folder']) + "/" + flow_settings['top_level'] + ".conn.rpt") + "\n") + # report area + file.write("summaryReport -outFile " + os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt \n") + # save design + file.write(r'saveNetlist ' + os.path.expanduser(flow_settings['pr_folder']) + r'/netlist.v' + "\n") + file.write(r'saveDesign ' + os.path.expanduser(flow_settings['pr_folder']) + r'/design.enc' + " \n") + file.write(r'rcOut -spef ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + " \n") + file.write(r'write_sdf -ideal_clock_network ' + os.path.expanduser(flow_settings['pr_folder']) + r'/sdf.sdf' + " \n") + #If the user specified a layer mapping file, then use that. Otherwise, just let the tool create a default one. + if flow_settings['map_file'] != "None": + file.write(r'streamOut ' + os.path.expanduser(flow_settings['pr_folder']) + r'/final.gds2' + ' -mapFile ' + flow_settings['map_file'] + ' -stripes 1 -units 1000 -mode ALL' + "\n") + else: + file.write(r'streamOut ' + os.path.expanduser(flow_settings['pr_folder']) + r'/final.gds2' + ' -stripes 1 -units 1000 -mode ALL' + "\n") + file.write("exit \n") + file.close() + # Run the scrip in EDI + subprocess.call('encounter -nowin -init edi.tcl | tee edi.log', shell=True,executable="/bin/bash") + # clean after EDI! + subprocess.call('mv encounter.log ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter_log.log', shell=True) + subprocess.call('mv encounter.cmd ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter.cmd', shell=True) + # read total area from the report file: + file = open(os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt" ,"r") + for line in file: + if line.startswith('Total area of Core:'): + total_area = re.findall(r'\d+\.{0,1}\d*', line) + file.close() + #Copy pnr results to a unique dir in pnr dir + pnr_report_str = synth_report_str + "_" + "metal_layers_" + metal_layer + "_" + "util_" + core_utilization + report_dest_str = os.path.expanduser(flow_settings['pr_folder']) + "/" + pnr_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['pr_folder']) + "/*.rpt " + os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt " + report_dest_str + copy_logs_cmd_str = "cp " + "edi.log " + "edi.tcl " + "edi.conf " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f edi.log edi.conf edi.tcl', shell=True) + return pnr_report_str, total_area + +def run_sim(): + # Create a modelsim folder + #subprocess.call("mkdir -p"+os.path.expanduser("./modelsim_dir")+"\n", shell=True) + # Create a modelsim .do file: + #subprocess.call("vlib modelsim_dir/libraries"+"\n",shell=True) + # todo: change the address and take it from the user as input + #subprocess.call("vlog -work modelsim_dir/libraries /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/verilog/tcbn65gplus_140b/tcbn65gplus.v /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/verilog/tpzn65gpgv2_140c/tpzn65gpgv2.v"+"\n",shell=True) + file = open("modelsim.do", "w") + file.write("cd " + os.path.expanduser("./modelsim_dir") + "\n") + file.write("vlib work \n") + file.write("vlog -work work ../../test/testbench.v \n") + file.write("vlog -work work ../../pr/netlist.v \n") + file.write("vsim -L work -L libraries testbench\n") + file.write("vcd file vcd.vcd \n") + file.write("vcd add -r testbench/uut/* \n") + file.write("run 1000 ns \n") + file.write("quit \n") + file.close() + subprocess.call('vsim -c -do modelsim.do', shell=True) + subprocess.call('rm -rf modelsim.do', shell=True) + subprocess.call('vcd2wlf ./modelsim_dir/vcd.vcd out.wlf', shell=True) + subprocess.call('wlf2vcd -o test.vcd out.wlf', shell=True) + subprocess.call('vcd2saif -input test.vcd -o saif.saif', shell=True) + +def run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str): + ########################################### + # Primetime + ########################################### + if not mode_enabled: + x = 2**len(flow_settings['mode_signal']) + # backannotate into primetime + # This part should be reported for all the modes in the design. + file = open("primetime.tcl", "w") + file.write("set sh_enable_page_mode true \n") + file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set target_library " + flow_settings['target_libraries'] + "\n") + file.write("set link_library " + flow_settings['link_libraries'] + "\n") + file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") + if mode_enabled and x <2**len(flow_settings['mode_signal']): + for y in range (0, len(flow_settings['mode_signal'])): + file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") + file.write("link \n") + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") + file.write("read_parasitics -increment " + os.path.expanduser(flow_settings['pr_folder']) + "/spef.spef \n") + file.write("report_timing > " + os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt \n") + file.write("quit \n") + file.close() + # run prime time + subprocess.call('dc_shell-t -f primetime.tcl | tee pt.log', shell=True,executable="/bin/bash") + # Read timing parameters + file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt" ,"r") + for line in file: + if 'library setup time' in line: + library_setup_time = re.findall(r'\d+\.{0,1}\d*', line) + if 'data arrival time' in line: + data_arrival_time = re.findall(r'\d+\.{0,1}\d*', line) + try: + total_delay = float(library_setup_time[0]) + float(data_arrival_time[0]) + except NameError: + total_delay = float(data_arrival_time[0]) + file.close() + # Create a script to measure power: + file = open("primetime_power.tcl", "w") + file.write("set sh_enable_page_mode true \n") + file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set target_library " + flow_settings['target_libraries'] + "\n") + file.write("set link_library " + flow_settings['link_libraries'] + "\n") + file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") + file.write("link \n") + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") + if mode_enabled and x <2**len(flow_settings['mode_signal']): + for y in range (0, len(flow_settings['mode_signal'])): + file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") + file.write("set power_enable_analysis TRUE \n") + file.write(r'set power_analysis_mode "averaged"' + "\n") + if flow_settings['generate_activity_file']: + file.write("read_saif -input saif.saif -instance_name testbench/uut \n") + else: + file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") + #file.write("read_saif -input saif.saif -instance_name testbench/uut \n") + #file.write("read_vcd -input ./modelsim_dir/vcd.vcd \n") + file.write(r'read_parasitics -increment ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + "\n") + #file.write("update_power \n") + file.write(r'report_power > ' + os.path.expanduser(flow_settings['primetime_folder']) + r'/power.rpt' + " \n") + file.write("quit\n") + file.close() + + # run prime time + subprocess.call('dc_shell-t -f primetime_power.tcl | tee pt_pwr.log', shell=True,executable="/bin/bash") + #copy reports and logs to a unique dir in pt dir + pt_report_str = pnr_report_str + "_" + "mode_" + str(x) + report_dest_str = os.path.expanduser(flow_settings['primetime_folder']) + "/" + pt_report_str + "_reports" + mkdir_cmd_str = "mkdir -p " + report_dest_str + copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['primetime_folder']) + "/*.rpt " + report_dest_str + copy_logs_cmd_str = "cp " + "pt.log pt_pwr.log primetime.tcl primetime_power.tcl " + report_dest_str + subprocess.call(mkdir_cmd_str,shell=True) + subprocess.call(copy_rep_cmd_str,shell=True) + subprocess.call(copy_logs_cmd_str,shell=True) + subprocess.call('rm -f pt.log pt_pwr.log primetime.tcl primetime_power.tcl', shell=True) + # Read dynamic power + file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/power.rpt" ,"r") + for line in file: + if 'Total Dynamic Power' in line: + total_dynamic_power = re.findall(r'\d+\.{0,1}\d*', line) + total_dynamic_power[0] = float(total_dynamic_power[0]) + if 'mW' in line: + total_dynamic_power[0] *= 0.001 + elif 'uw' in line: + total_dynamic_power[0] *= 0.000001 + else: + total_dynamic_power[0] = 0 + file.close() + return library_setup_time, data_arrival_time, total_delay, total_dynamic_power + # wire loads in the library are WireAreaLowkCon WireAreaLowkAgr WireAreaForZero def hardblock_flow(flow_settings): @@ -20,485 +435,43 @@ def hardblock_flow(flow_settings): lowest_cost_delay = 1.0 lowest_cost_power = 1.0 - ########################################### - # Synthesis - ########################################### design_files = [] if flow_settings['design_language'] == 'verilog': - design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".v")] + ext_re = re.compile(".*.v") elif flow_settings['design_language'] == 'vhdl': - design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".vhdl")] + ext_re = re.compile(".*.vhdl") elif flow_settings['design_language'] == 'sverilog': - design_files = [fn for _, _, fs in os.walk(flow_settings['design_folder']) for fn in fs if fn.endswith(".sv") or fn.endswith(".v")] + ext_re = re.compile(".*(.sv)|(.v)") + + design_folder = os.path.expanduser(flow_settings['design_folder']) + design_files = [fn for _, _, fs in os.walk(design_folder) for fn in fs if ext_re.search(fn)] + search_path_dirs = [] + search_path_dirs.append(design_folder) + for root,dirnames,fnames in os.walk(design_folder): + for dirname,fname in zip(dirnames,fnames): + if(ext_re.search(fname)): + search_path_dirs.append(os.path.join(root,dirname)) subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['synth_folder']) + "\n", shell=True) + subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['pr_folder']) + "\n", shell=True) + subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['primetime_folder']) + "\n", shell=True) # Make sure we managed to read the design files assert len(design_files) >= 1 for clock_period in flow_settings['clock_period']: for wire_selection in flow_settings['wire_selection']: - file = open("dc_script.tcl","w") - file.write("cd " + os.path.expanduser(flow_settings['synth_folder']) + "\n") - file.write("set search_path " + flow_settings['design_folder'] + " \n") - if len(design_files) == 1: - file.write("set my_files " + design_files[0] + "\n") - else: - file.write("set my_files [list ") - for entity in design_files: - if not (entity == "parameters.v" or entity == "c_functions.v"): - file.write(entity + " ") - file.write("] \n") - file.write("set my_top_level " + flow_settings['top_level'] + "\n") - file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") - file.write(r'set power_analysis_mode "averaged"' + "\n") - file.write("define_design_lib WORK -path ./WORK \n") - if flow_settings['design_language'] == 'verilog': - file.write("analyze -f verilog $my_files \n") - elif flow_settings['design_language'] == 'vhdl': - file.write("analyze -f vhdl $my_files \n") - else: - file.write("analyze -f sverilog $my_files \n") - file.write("elaborate $my_top_level \n") - file.write("current_design $my_top_level \n") - file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/checkprecompile.rpt\n") - file.write("link \n") - file.write("uniquify \n") - #If wire_selection is None, then no wireload model is used during synthesis. This does imply results - #are not as accurate (wires don't have any delay and area), but is useful to let the flow work/proceed - #if the std cell library is missing wireload models. - if wire_selection != "None": - file.write(r'set_wire_load_selection ' + wire_selection + " \n") - file.write("set my_period " + str(clock_period) + " \n") - file.write("set find_clock [ find port [list $my_clock_pin] ] \n") - file.write("if { $find_clock != [list] } { \n") - file.write("set clk_name $my_clock_pin \n") - file.write("create_clock -period $my_period $clk_name} \n\n") - file.write("compile_ultra\n") - file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt\n") - file.write("link \n") - file.write("write_file -format ddc -hierarchy -output " + os.path.expanduser(flow_settings['synth_folder']) + "/" + flow_settings['top_level'] + ".ddc \n") - - if flow_settings['read_saif_file']: - file.write("read_saif saif.saif \n") - else: - file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " [all_nets] \n") - - file.write("ungroup -all -flatten \n") - file.write("report_power > " + os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt\n") - file.write("report_area -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt\n") - file.write("report_resources -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/resources.rpt\n") - file.write("report_timing > " + os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt\n") - file.write("change_names -hier -rule verilog \n") - - file.write("write -f verilog -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.v\n") - file.write("write_sdf " + os.path.expanduser(flow_settings['synth_folder']) + "/synthsized.sdf \n") - file.write("write_parasitics -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.spef \n") - file.write("write_sdc " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.sdc \n") - - file.write("quit \n") - file.close() - - # Run the scrip in design compiler shell - subprocess.call('dc_shell-t -f dc_script.tcl | tee dc.log', shell=True) - # clean after DC! - subprocess.call('rm -rf command.log', shell=True) - subprocess.call('rm -rf default.svf', shell=True) - subprocess.call('rm -rf filenames.log', shell=True) - - # Make sure it worked properly - # Open the timing report and make sure the critical path is non-zero: - check_file = open(os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt", "r") - for line in check_file: - if "Error" in line: - print "Your design has errors. Refer to check.rpt in synthesis directory" - exit(-1) - elif "Warning" in line and flow_settings['show_warnings']: - print "Your design has warnings. Refer to check.rpt in synthesis directory" - print "In spite of the warning, the rest of the flow will continue to execute." - check_file.close() - - #Copy synthesis results to a unique dir in synth dir - synth_report_str = "period_" + clock_period + "_" + "wire_mdl_" + wire_selection - report_dest_str = os.path.expanduser(flow_settings['synth_folder']) + "/" + synth_report_str + "_reports" - mkdir_cmd_str = "mkdir -p " + report_dest_str - copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['synth_folder']) + "/*.rpt " + report_dest_str - copy_logs_cmd_str = "cp " + "dc.log "+ "dc_script.tcl " + report_dest_str - subprocess.call(mkdir_cmd_str,shell=True) - subprocess.call(copy_rep_cmd_str,shell=True) - subprocess.call(copy_logs_cmd_str,shell=True) - subprocess.call('rm -f dc.log dc_script.tcl',shell=True) - - #if the user doesn't want to perform place and route, extract the results from DC reports and end - if flow_settings['synthesis_only']: - - # read total area from the report file: - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt" ,"r") - for line in file: - if line.startswith('Total cell area:'): - total_area = re.findall(r'\d+\.{0,1}\d*', line) - file.close() - - # Read timing parameters - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt" ,"r") - for line in file: - if 'library setup time' in line: - library_setup_time = re.findall(r'\d+\.{0,1}\d*', line) - if 'data arrival time' in line: - data_arrival_time = re.findall(r'\d+\.{0,1}\d*', line) - try: - total_delay = float(library_setup_time[0]) + float(data_arrival_time[0]) - except NameError: - total_delay = float(data_arrival_time[0]) - - file.close() - - # Read dynamic power - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt" ,"r") - for line in file: - if 'Total Dynamic Power' in line: - total_dynamic_power = re.findall(r'\d+\.\d*', line) - total_dynamic_power[0] = float(total_dynamic_power[0]) - if 'mW' in line: - total_dynamic_power[0] *= 0.001 - elif 'uw' in line: - total_dynamic_power[0] *= 0.000001 - else: - total_dynamic_power[0] = 0 - file.close() - - # write the final report file: - file = open("report.txt" ,"w") - file.write("total area = " + str(total_area[0]) + "\n") - file.write("total delay = " + str(total_delay) + " ns\n") - file.write("total power = " + str(total_dynamic_power[0]) + " W\n") - file.close() - - #return - exit() - - ########################################### - # Place and Route - ########################################### - subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['pr_folder']) + "\n", shell=True) + synth_report_str = run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_selection) for metal_layer in flow_settings['metal_layers']: for core_utilization in flow_settings['core_utilization']: - # generate the EDI (encounter) configuration - file = open("edi.conf", "w") - file.write("global rda_Input \n") - file.write("set cwd .\n\n") - file.write("set rda_Input(ui_leffile) " + flow_settings['lef_files'] + "\n") - file.write("set rda_Input(ui_timelib,min) " + flow_settings['best_case_libs'] + "\n") - file.write("set rda_Input(ui_timelib) " + flow_settings['standard_libs'] + "\n") - file.write("set rda_Input(ui_timelib,max) " + flow_settings['worst_case_libs'] + "\n") - file.write("set rda_Input(ui_netlist) " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.v" + "\n") - file.write("set rda_Input(ui_netlisttype) {Verilog} \n") - file.write("set rda_Input(import_mode) {-treatUndefinedCellAsBbox 0 -keepEmptyModule 1}\n") - file.write("set rda_Input(ui_timingcon_file) " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.sdc" + "\n") - file.write("set rda_Input(ui_topcell) " + flow_settings['top_level'] + "\n\n") - - gnd_pin = flow_settings['gnd_pin'] - gnd_net = flow_settings['gnd_net'] - pwr_pin = flow_settings['pwr_pin'] - pwr_net = flow_settings['pwr_net'] - file.write("set rda_Input(ui_gndnet) {" + gnd_net + "} \n") - file.write("set rda_Input(ui_pwrnet) {" + pwr_net + "} \n") - - if flow_settings['tilehi_tielo_cells_between_power_gnd'] is True: - file.write("set rda_Input(ui_pg_connections) [list {PIN:" + gnd_pin + ":}" + " {TIEL::} " + "{NET:" + gnd_net + ":} {NET:" + pwr_net + ":}" + " {TIEH::} " + "{PIN:" + pwr_pin + ":} ] \n") - else: - file.write("set rda_Input(ui_pg_connections) [list {PIN:" + gnd_pin + ":} {NET:" + gnd_net + ":} {NET:" + pwr_net + ":} {PIN:" + pwr_pin + ":} ] \n") - - file.write("set rda_Input(PIN:" + gnd_pin + ":) {" + gnd_pin + "} \n") - file.write("set rda_Input(TIEL::) {" + gnd_pin + "} \n") - file.write("set rda_Input(NET:" + gnd_net + ":) {" + gnd_net + "} \n") - file.write("set rda_Input(PIN:" + pwr_pin + ":) {" + pwr_pin + "} \n") - file.write("set rda_Input(TIEH::) {" + pwr_pin + "} \n") - file.write("set rda_Input(NET:" + pwr_net + ":) {" + pwr_net + "} \n\n") - - if (flow_settings['inv_footprint'] != "None"): - file.write("set rda_Input(ui_inv_footprint) {" + flow_settings['inv_footprint'] + "}\n") - - if (flow_settings['buf_footprint'] != "None"): - file.write("set rda_Input(ui_buf_footprint) {" + flow_settings['buf_footprint'] + "}\n") - - if (flow_settings['delay_footprint'] != "None"): - file.write("set rda_Input(ui_delay_footprint) {" + flow_settings['delay_footprint'] + "}\n") - - file.close() - - metal_layer_bottom = flow_settings["metal_layer_names"][0] - metal_layer_second = flow_settings["metal_layer_names"][1] - metal_layer_top = flow_settings["metal_layer_names"][int(metal_layer)-1] - power_ring_metal_top = flow_settings["power_ring_metal_layer_names"][0] - power_ring_metal_bottom = flow_settings["power_ring_metal_layer_names"][1] - power_ring_metal_left = flow_settings["power_ring_metal_layer_names"][2] - power_ring_metal_right = flow_settings["power_ring_metal_layer_names"][3] - - # generate the EDI (encounter) script - file = open("edi.tcl", "w") - file.write("loadConfig edi.conf \n") - file.write("floorPlan -site " + flow_settings['core_site_name'] \ - + " -r " + str(flow_settings['height_to_width_ratio']) \ - + " " + str(core_utilization) \ - + " " + str(flow_settings['space_around_core']) \ - + " " + str(flow_settings['space_around_core']) + " ") - file.write(str(flow_settings['space_around_core']) + " " + str(flow_settings['space_around_core']) + "\n") - file.write("setMaxRouteLayer " + str(metal_layer) + " \n") - file.write("fit \n") - file.write("addRing -spacing_bottom " + str(flow_settings['power_ring_spacing']) \ - + " -spacing_right " + str(flow_settings['power_ring_spacing']) \ - + " -spacing_top " + str(flow_settings['power_ring_spacing']) \ - + " -spacing_left " + str(flow_settings['power_ring_spacing']) \ - + " -width_right " + str(flow_settings['power_ring_width']) \ - + " -width_left " + str(flow_settings['power_ring_width']) \ - + " -width_bottom " + str(flow_settings['power_ring_width']) \ - + " -width_top " + str(flow_settings['power_ring_width']) \ - + " -center 1" \ - + " -around core" \ - + " -layer_top " + power_ring_metal_top \ - + " -layer_bottom " + power_ring_metal_bottom \ - + " -layer_left " + power_ring_metal_left \ - + " -layer_right " + power_ring_metal_right \ - + " -nets { " + gnd_net + " " + pwr_net + " }" \ - + " -stacked_via_top_layer "+ metal_layer_top \ - + " -stacked_via_bottom_layer " + metal_layer_bottom + " \n") - - file.write("setPlaceMode -fp false -maxRouteLayer " + str(metal_layer) + "\n") - file.write("placeDesign -inPlaceOpt -noPrePlaceOpt \n") - file.write("checkPlace " + flow_settings['top_level'] +" \n") - - file.write("trialroute \n") - file.write("buildTimingGraph \n") - file.write("timeDesign -preCTS -idealClock -numPaths 10 -prefix preCTS -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/timeDesignpreCTSReports" + "\n") - file.write("optDesign -preCTS -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/optDesignpreCTSReports" + "\n") - # I won't do a CTS anyway as the blocks are small. - - file.write("addFiller -cell {" + " ".join([str(item) for item in flow_settings['filler_cell_names']]) + "} -prefix FILL -merge true \n") - - file.write("clearGlobalNets \n") - file.write("globalNetConnect " + gnd_net + " -type pgpin -pin " + gnd_pin + " -inst {} \n") - file.write("globalNetConnect " + pwr_net + " -type pgpin -pin " + pwr_pin + " -inst {} \n") - file.write("globalNetConnect " + gnd_net + " -type net -net " + gnd_net + " \n") - file.write("globalNetConnect " + pwr_net + " -type net -net " + pwr_net + " \n") - file.write("globalNetConnect " + pwr_net + " -type pgpin -pin " + pwr_pin + " -inst * \n") - file.write("globalNetConnect " + gnd_net + " -type pgpin -pin " + gnd_pin + " -inst * \n") - file.write("globalNetConnect " + pwr_net + " -type tiehi -inst * \n") - file.write("globalNetConnect " + gnd_net + " -type tielo -inst * \n") - - file.write("sroute -connect { blockPin padPin padRing corePin floatingStripe }" \ - + " -layerChangeRange { " + metal_layer_bottom + " " + metal_layer_top + " }" \ - + " -blockPinTarget { nearestRingStripe nearestTarget }" \ - + " -padPinPortConnect { allPort oneGeom }" \ - + " -checkAlignedSecondaryPin 1" \ - + " -blockPin useLef" \ - + " -allowJogging 1" \ - + " -crossoverViaBottomLayer " + metal_layer_bottom \ - + " -allowLayerChange 1" \ - + " -targetViaTopLayer " + metal_layer_top \ - + " -crossoverViaTopLayer " + metal_layer_top \ - + " -targetViaBottomLayer " + metal_layer_bottom \ - + " -nets { " + gnd_net + " " + pwr_net + " } \n") - - file.write("routeDesign -globalDetail\n") - file.write("setExtractRCMode -engine postRoute \n") - file.write("extractRC \n") - file.write("buildTimingGraph \n") - file.write("timeDesign -postRoute -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/timeDesignReports" + "\n") - file.write("optDesign -postRoute -outDir " + os.path.expanduser(flow_settings['pr_folder']) + "/optDesignReports" + "\n") - - #by default, violations are reported in designname.geom.rpt - file.write("verifyGeometry -report " + (os.path.expanduser(flow_settings['pr_folder']) + "/" + flow_settings['top_level'] + ".geom.rpt") + "\n") - #by default, violations are reported in designname.conn.rpt - file.write("verifyConnectivity -type all -report " + (os.path.expanduser(flow_settings['pr_folder']) + "/" + flow_settings['top_level'] + ".conn.rpt") + "\n") - - # report area - file.write("summaryReport -outFile " + os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt \n") - - # save design - file.write(r'saveNetlist ' + os.path.expanduser(flow_settings['pr_folder']) + r'/netlist.v' + "\n") - file.write(r'saveDesign ' + os.path.expanduser(flow_settings['pr_folder']) + r'/design.enc' + " \n") - file.write(r'rcOut -spef ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + " \n") - file.write(r'write_sdf -ideal_clock_network ' + os.path.expanduser(flow_settings['pr_folder']) + r'/sdf.sdf' + " \n") - #If the user specified a layer mapping file, then use that. Otherwise, just let the tool create a default one. - if flow_settings['map_file'] != "None": - file.write(r'streamOut ' + os.path.expanduser(flow_settings['pr_folder']) + r'/final.gds2' + ' -mapFile ' + flow_settings['map_file'] + ' -stripes 1 -units 1000 -mode ALL' + "\n") - else: - file.write(r'streamOut ' + os.path.expanduser(flow_settings['pr_folder']) + r'/final.gds2' + ' -stripes 1 -units 1000 -mode ALL' + "\n") - file.write("exit \n") - file.close() - - # Run the scrip in EDI - subprocess.call('encounter -nowin -init edi.tcl | tee edi.log', shell=True) - # clean after EDI! - subprocess.call('mv encounter.log ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter_log.log', shell=True) - subprocess.call('mv encounter.cmd ' + os.path.expanduser(flow_settings['pr_folder']) + '/encounter.cmd', shell=True) - - # read total area from the report file: - file = open(os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt" ,"r") - for line in file: - if line.startswith('Total area of Core:'): - total_area = re.findall(r'\d+\.{0,1}\d*', line) - file.close() - - #Copy pnr results to a unique dir in pnr dir - pnr_report_str = synth_report_str + "_" + "metal_layers_" + metal_layer + "_" + "util_" + core_utilization - report_dest_str = os.path.expanduser(flow_settings['pr_folder']) + "/" + pnr_report_str + "_reports" - mkdir_cmd_str = "mkdir -p " + report_dest_str - copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['pr_folder']) + "/*.rpt " + os.path.expanduser(flow_settings['pr_folder']) + "/pr_report.txt " + report_dest_str - copy_logs_cmd_str = "cp " + "edi.log " + "edi.tcl " + "edi.conf " + report_dest_str - subprocess.call(mkdir_cmd_str,shell=True) - subprocess.call(copy_rep_cmd_str,shell=True) - subprocess.call(copy_logs_cmd_str,shell=True) - subprocess.call('rm -f edi.log edi.conf edi.tcl', shell=True) - + pnr_report_str, total_area = run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str) if len(flow_settings['mode_signal']) > 0: mode_enabled = True else: mode_enabled = False the_power = 0.0 - # Optional: use modelsim to generate an activity file for the design: if flow_settings['generate_activity_file'] is True: - # Create a modelsim folder - #subprocess.call("mkdir -p"+os.path.expanduser("./modelsim_dir")+"\n", shell=True) - # Create a modelsim .do file: - #subprocess.call("vlib modelsim_dir/libraries"+"\n",shell=True) - # todo: change the address and take it from the user as input - #subprocess.call("vlog -work modelsim_dir/libraries /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/verilog/tcbn65gplus_140b/tcbn65gplus.v /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/verilog/tpzn65gpgv2_140c/tpzn65gpgv2.v"+"\n",shell=True) - - - file = open("modelsim.do", "w") - file.write("cd " + os.path.expanduser("./modelsim_dir") + "\n") - file.write("vlib work \n") - file.write("vlog -work work ../../test/testbench.v \n") - file.write("vlog -work work ../../pr/netlist.v \n") - file.write("vsim -L work -L libraries testbench\n") - file.write("vcd file vcd.vcd \n") - file.write("vcd add -r testbench/uut/* \n") - file.write("run 1000 ns \n") - file.write("quit \n") - file.close() - - subprocess.call('vsim -c -do modelsim.do', shell=True) - subprocess.call('rm -rf modelsim.do', shell=True) - subprocess.call('vcd2wlf ./modelsim_dir/vcd.vcd out.wlf', shell=True) - subprocess.call('wlf2vcd -o test.vcd out.wlf', shell=True) - subprocess.call('vcd2saif -input test.vcd -o saif.saif', shell=True) - - - ########################################### - # Primetime - ########################################### + run_sim() for x in range(0, 2**len(flow_settings['mode_signal']) + 1): - if not mode_enabled: - x = 2**len(flow_settings['mode_signal']) - # backannotate into primetime - # This part should be reported for all the modes in the design. - subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['primetime_folder']) + "\n", shell=True) - file = open("primetime.tcl", "w") - file.write("set sh_enable_page_mode true \n") - - file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") - file.write("set my_top_level " + flow_settings['top_level'] + "\n") - file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") - - file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") - if mode_enabled and x <2**len(flow_settings['mode_signal']): - for y in range (0, len(flow_settings['mode_signal'])): - file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") - file.write("link \n") - - file.write("set my_period " + str(clock_period) + " \n") - file.write("set find_clock [ find port [list $my_clock_pin] ] \n") - file.write("if { $find_clock != [list] } { \n") - file.write("set clk_name $my_clock_pin \n") - file.write("create_clock -period $my_period $clk_name} \n\n") - - file.write("read_parasitics -increment " + os.path.expanduser(flow_settings['pr_folder']) + "/spef.spef \n") - file.write("report_timing > " + os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt \n") - file.write("quit \n") - file.close() - - # run prime time - subprocess.call('dc_shell-t -f primetime.tcl | tee pt.log', shell=True) - - # Read timing parameters - file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt" ,"r") - for line in file: - if 'library setup time' in line: - library_setup_time = re.findall(r'\d+\.{0,1}\d*', line) - if 'data arrival time' in line: - data_arrival_time = re.findall(r'\d+\.{0,1}\d*', line) - try: - total_delay = float(library_setup_time[0]) + float(data_arrival_time[0]) - except NameError: - total_delay = float(data_arrival_time[0]) - file.close() - # Create a script to measure power: - file = open("primetime_power.tcl", "w") - file.write("set sh_enable_page_mode true \n") - - file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") - file.write("set my_top_level " + flow_settings['top_level'] + "\n") - file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") - - file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") - file.write("link \n") - - file.write("set my_period " + str(clock_period) + " \n") - file.write("set find_clock [ find port [list $my_clock_pin] ] \n") - file.write("if { $find_clock != [list] } { \n") - file.write("set clk_name $my_clock_pin \n") - file.write("create_clock -period $my_period $clk_name} \n\n") - if mode_enabled and x <2**len(flow_settings['mode_signal']): - for y in range (0, len(flow_settings['mode_signal'])): - file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") - file.write("set power_enable_analysis TRUE \n") - file.write(r'set power_analysis_mode "averaged"' + "\n") - if flow_settings['generate_activity_file']: - file.write("read_saif -input saif.saif -instance_name testbench/uut \n") - else: - file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") - #file.write("read_saif -input saif.saif -instance_name testbench/uut \n") - #file.write("read_vcd -input ./modelsim_dir/vcd.vcd \n") - file.write(r'read_parasitics -increment ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + "\n") - #file.write("update_power \n") - file.write(r'report_power > ' + os.path.expanduser(flow_settings['primetime_folder']) + r'/power.rpt' + " \n") - file.write("quit\n") - file.close() - - # run prime time - subprocess.call('dc_shell-t -f primetime_power.tcl | tee pt_pwr.log', shell=True) - - #copy reports and logs to a unique dir in pt dir - pt_report_str = pnr_report_str + "_" + "mode_" + str(x) - report_dest_str = os.path.expanduser(flow_settings['primetime_folder']) + "/" + pt_report_str + "_reports" - mkdir_cmd_str = "mkdir -p " + report_dest_str - copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['primetime_folder']) + "/*.rpt " + report_dest_str - copy_logs_cmd_str = "cp " + "pt.log pt_pwr.log primetime.tcl primetime_power.tcl " + report_dest_str - subprocess.call(mkdir_cmd_str,shell=True) - subprocess.call(copy_rep_cmd_str,shell=True) - subprocess.call(copy_logs_cmd_str,shell=True) - subprocess.call('rm -f pt.log pt_pwr.log primetime.tcl primetime_power.tcl', shell=True) - - # Read dynamic power - file = open(os.path.expanduser(flow_settings['primetime_folder']) + "/power.rpt" ,"r") - for line in file: - if 'Total Dynamic Power' in line: - total_dynamic_power = re.findall(r'\d+\.{0,1}\d*', line) - total_dynamic_power[0] = float(total_dynamic_power[0]) - if 'mW' in line: - total_dynamic_power[0] *= 0.001 - elif 'uw' in line: - total_dynamic_power[0] *= 0.000001 - else: - total_dynamic_power[0] = 0 - file.close() - + library_setup_time, data_arrival_time, total_delay, total_dynamic_power = run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str) # write the final report file: if mode_enabled and x <2**len(flow_settings['mode_signal']): file = open("report_mode" + str(x) + "_" + str(flow_settings['top_level']) + "_" + str(clock_period) + "_" + str(wire_selection) + "_wire_" + str(metal_layer) + "_" + str(core_utilization) + ".txt" ,"w") @@ -510,13 +483,11 @@ def hardblock_flow(flow_settings): file.close() if total_dynamic_power[0] > the_power: the_power = total_dynamic_power[0] - if lowest_cost > math.pow(float(total_area[0]), float(flow_settings['area_cost_exp'])) * math.pow(float(total_delay), float(flow_settings['delay_cost_exp'])): lowest_cost = math.pow(float(total_area[0]), float(flow_settings['area_cost_exp'])) * math.pow(float(total_delay), float(flow_settings['delay_cost_exp'])) lowest_cost_area = float(total_area[0]) lowest_cost_delay = float(total_delay) lowest_cost_power = float(the_power) - del total_dynamic_power[:] del library_setup_time[:] del data_arrival_time[:] diff --git a/coffe/utils.py b/coffe/utils.py index 3664eed..664d72e 100644 --- a/coffe/utils.py +++ b/coffe/utils.py @@ -1197,7 +1197,7 @@ def create_output_dir(arch_file_name, arch_out_folder): arch_desc_words = arch_file_name.split('.') arch_folder = arch_desc_words[0] else: - arch_folder = arch_out_folder + arch_folder = os.path.expanduser(arch_out_folder) if not os.path.exists(arch_folder): os.makedirs(arch_folder) diff --git a/input_files/simple_dsp_slice_65nm/coffe_inp_params.txt b/input_files/simple_dsp_slice_65nm/coffe_inp_params.txt index 7d2ea31..097eb12 100644 --- a/input_files/simple_dsp_slice_65nm/coffe_inp_params.txt +++ b/input_files/simple_dsp_slice_65nm/coffe_inp_params.txt @@ -15,7 +15,7 @@ #The directory in which output files will be stored. #If not specified, the directory containing this file is used as output dir. -arch_out_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/arch_out_dir +arch_out_folder=~/COFFE/output_files/simple_dsp_slice_65nm/arch_out_dir ####################################### ##### Architecture Parameters diff --git a/input_files/simple_dsp_slice_65nm/dsp_slice.txt b/input_files/simple_dsp_slice_65nm/dsp_slice.txt index b142549..cb67c87 100644 --- a/input_files/simple_dsp_slice_65nm/dsp_slice.txt +++ b/input_files/simple_dsp_slice_65nm/dsp_slice.txt @@ -8,7 +8,7 @@ ########## General Design Settings ########## ############################################# # The folder in which all the design files are located: -design_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/input_files/simple_dsp_slice_65nm/dsp_slice_hdl +design_folder=~/COFFE/input_files/simple_dsp_slice_65nm/dsp_slice_hdl # The design language. Should be either 'verilog', 'vhdl' or 'sverilog' design_language=verilog @@ -26,13 +26,13 @@ area_cost_exp=1.0 clock_pin_name=clk # Desired clock period in ns -clock_period=3.0 +clock_period=1.82 # Name of the top-level entity in the design top_level=dsp_slice # The name of the folder in which post-synthesis files and synthesis reports are to be stored -synth_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_synth +synth_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_synth # Do you want to be informed of warnings during synthesis? show_warnings=True @@ -57,10 +57,11 @@ generate_activity_file=False #link_libraries=/usr/local/packages/cadence_2007/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb #link_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb -link_libraries="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db dw_foundation.sldb" +# Using the libraries from 65nm pdk +link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db dw_foundation.sldb" #target_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db -target_libraries=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db +target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.db" ############################################## ########## Place and Route Settings ########## @@ -69,60 +70,63 @@ target_libraries=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vl # Libraries required in EDI: #this can be a list of numbers -metal_layers=4 +metal_layers=6 #names of metal layers starting from the bottom-most layer on the left. use a python list format. -metal_layer_names=["ME1", "ME2", "ME3", "ME4"] +metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right -power_ring_metal_layer_names=["ME1", "ME1", "ME2", "ME2"] +power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] #name of the file to use for layer mapping. used for stream out. #set it to None if you want the tool to create a generic map file map_file=None +#SM: The .lib files in question are in the Front_End tsmc dir #mention the wireload model to be used. this is present in .lib files. #if the library doesn't have wireload models, specify None. #multiple values can be specified. just add more rows like: #wire_selection=WireAreaLowkCon #wire_selection=WireAreaLowkAgr #wire_selection=WireAreaForZero -wire_selection=DEFAULT +wire_selection=WireAreaLowkAgr #specify names of ground and power pins and nets in the library -gnd_net=gnd! -gnd_pin=gnd! -pwr_net=vdd! -pwr_pin=vdd! +gnd_net=VSS! +gnd_pin=VSS! +pwr_net=VDD! +pwr_pin=VDD! tilehi_tielo_cells_between_power_gnd=False + #specify footprint names for inverters, buffers, delays. #this is optional. you can get these values from the lib file. #you can also specify None, if you can't find them in the lib file. -inv_footprint=INVX -buf_footprint=BUFX -delay_footprint=INVX +#SM: not sure if these are the correct standard cells to be using, as there are many options (need to figure out what DX refers to) +inv_footprint=INVD0 +buf_footprint=BUFFD0 +delay_footprint=INVD0 #list of filler cell names. use a python list format. #the names can be obtained from .lib files. -filler_cell_names=["FILL1", "FILL2", "FILL3", "FILL4"] +filler_cell_names=["GFILL", "GFILL10", "GFILL2", "GFILL3", "GFILL4"] #name of the core site in the floorplan. can be obtained from lef files. -core_site_name=Core +core_site_name=core #specify the utilization of the core site. you can specify multiple ones on different lines. -core_utilization=0.70 +core_utilization=0.90 #specify LEF files in the library. remember to specify the tech/header file first and then the file that has macros/cells. -lef_files="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_header.lef /home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_allStdCells.lef" +lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_6lmT1.lef" #list names (full paths) of the .lib files for various corners -best_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib +best_case_libs=/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib -standard_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib +standard_libs=/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib -worst_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib +worst_case_libs=/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib # EDI (Cadence Encounter) settings: power_ring_width=3 @@ -131,7 +135,7 @@ height_to_width_ratio=4.0 space_around_core=10 # The folder in which place and route reports and post-routing netlists and spef files will be stored -pr_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr +pr_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr ############################################## @@ -142,11 +146,11 @@ pr_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp #mode_signal=mode_1 #the directory containing the primetime library and the name of the library file -primetime_lib_path=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys -primetime_lib_name=ceid_vlsiLab_umc65ll_stdCells.db +primetime_lib_path="/CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" +primetime_lib_name=tcbn65gplustc.db # The name of the folder in which primetime results/reports are to be stored -primetime_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pt +primetime_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pt # COFFE parameters: name=hard_block diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v b/input_files/strtx_III_dsp/dsp_block_hdl/accumulate.v similarity index 100% rename from input_files/strtx_III_dsp_sadegh/dsp_block_hdl/accumulate.v rename to input_files/strtx_III_dsp/dsp_block_hdl/accumulate.v diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v b/input_files/strtx_III_dsp/dsp_block_hdl/dsp.v similarity index 100% rename from input_files/strtx_III_dsp_sadegh/dsp_block_hdl/dsp.v rename to input_files/strtx_III_dsp/dsp_block_hdl/dsp.v diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v b/input_files/strtx_III_dsp/dsp_block_hdl/half_dsp.v similarity index 100% rename from input_files/strtx_III_dsp_sadegh/dsp_block_hdl/half_dsp.v rename to input_files/strtx_III_dsp/dsp_block_hdl/half_dsp.v diff --git a/input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v b/input_files/strtx_III_dsp/dsp_block_hdl/twomadder.v similarity index 100% rename from input_files/strtx_III_dsp_sadegh/dsp_block_hdl/twomadder.v rename to input_files/strtx_III_dsp/dsp_block_hdl/twomadder.v diff --git a/input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt b/input_files/strtx_III_dsp/dsp_coffe_params.txt similarity index 92% rename from input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt rename to input_files/strtx_III_dsp/dsp_coffe_params.txt index 13f3c86..f88246b 100755 --- a/input_files/strtx_III_dsp_sadegh/dsp_coffe_params.txt +++ b/input_files/strtx_III_dsp/dsp_coffe_params.txt @@ -14,14 +14,14 @@ ####################################### #Abs path to COFFE repo -coffe_repo_path=/fs1/eecg/vaughn/morestep/COFFE +#coffe_repo_path=/fs1/eecg/vaughn/morestep/COFFE #The directory in which all outputs are generated, makes it easier to make sense of data -coffe_design_name=strtx_III_dsp_sadegh +#coffe_design_name=strtx_III_dsp #The directory in which output files will be stored. #If not specified, the directory containing this file is used as output dir. -arch_out_folder=/fs1/eecg/vaughn/morestep/COFFE/output_files/strtx_III_dsp_sadegh/arch_out_dir +arch_out_folder=~/COFFE/output_files/strtx_III_dsp/arch_out_dir ####################################### ##### Architecture Parameters @@ -201,4 +201,4 @@ metal=0.227273,0.000000 # if hybrid blocks are enabled, list configurations here -hb_files = input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt +hb_files = input_files/strtx_III_dsp/dsp_hb_settings.txt diff --git a/input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt b/input_files/strtx_III_dsp/dsp_hb_settings.txt similarity index 91% rename from input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt rename to input_files/strtx_III_dsp/dsp_hb_settings.txt index 99c5b55..6a313c5 100755 --- a/input_files/strtx_III_dsp_sadegh/dsp_hb_settings.txt +++ b/input_files/strtx_III_dsp/dsp_hb_settings.txt @@ -5,7 +5,7 @@ ############################################# # The folder in which all the design files are located: -design_folder=/fs1/eecg/vaughn/morestep/COFFE/input_files/strtx_III_dsp_sadegh/dsp_block_hdl +design_folder=~/COFFE/input_files/strtx_III_dsp/dsp_block_hdl # The design language. Should be either 'verilog', 'vhdl' or 'sverilog' design_language=verilog @@ -35,7 +35,7 @@ clock_period=2.0 top_level=dsp # The name of the folder in which post-synthesis files and synthesis reports are to be stored -synth_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/synth +synth_folder=~/COFFE/output_files/strtx_III_dsp/synth # Do you want to be informed of warnings during synthesis? @@ -83,7 +83,7 @@ power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] #name of the file to use for layer mapping. used for stream out. #set it to None if you want the tool to create a generic map file map_file=streamOut.map -wire_selection=WireAreaLowkCon +#wire_selection=WireAreaLowkCon wire_selection=WireAreaLowkAgr #wire_selection=WireAreaForZero #specify names of ground and power pins and nets in the library @@ -97,7 +97,6 @@ tilehi_tielo_cells_between_power_gnd=True #specify footprint names for inverters, buffers, delays. #this is optional. you can get these values from the lib file. #you can also specify None, if you can't find them in the lib file. -#SM: not sure if these are the correct standard cells to be using, as there are many options (need to figure out what DX refers to) inv_footprint=INVD0 buf_footprint=BUFFD1 delay_footprint=DEL0 @@ -134,7 +133,7 @@ space_around_core=5 # The folder in which place and route reports and post-routing netlists and spef files will be stored -pr_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/pr +pr_folder=~/COFFE/output_files/strtx_III_dsp/pr ############################################## @@ -146,7 +145,7 @@ mode_signal=mode_1 primetime_lib_path=". /CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" -primetime_folder=~/COFFE/output_files/strtx_III_dsp_sadegh/pt +primetime_folder=~/COFFE/output_files/strtx_III_dsp/pt # COFFE parameters: name=hard_block From 7eba07f103599c5df0fcd2327f9b04824fda1aea Mon Sep 17 00:00:00 2001 From: Stephen More Date: Mon, 17 Oct 2022 10:44:04 -0400 Subject: [PATCH 3/7] added commented parameters using ceid 65nm libs to dsp_slice --- .../simple_dsp_slice_65nm/dsp_slice.txt | 80 ++++++++++++++++--- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/input_files/simple_dsp_slice_65nm/dsp_slice.txt b/input_files/simple_dsp_slice_65nm/dsp_slice.txt index cb67c87..d61b971 100644 --- a/input_files/simple_dsp_slice_65nm/dsp_slice.txt +++ b/input_files/simple_dsp_slice_65nm/dsp_slice.txt @@ -26,7 +26,7 @@ area_cost_exp=1.0 clock_pin_name=clk # Desired clock period in ns -clock_period=1.82 +clock_period=3.0 # Name of the top-level entity in the design top_level=dsp_slice @@ -54,13 +54,21 @@ generate_activity_file=False # Location of the library files. # if you have more than one library, please provide them similiar to the example below. - #link_libraries=/usr/local/packages/cadence_2007/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb #link_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb -# Using the libraries from 65nm pdk + +# uncomment below for UT austin +# link_libraries="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db dw_foundation.sldb" + +# uncomment below for University of Toronto link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db dw_foundation.sldb" #target_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db + +# uncomment below for UT austin +#target_libraries=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db + +# uncomment below for University of Toronto target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.db" ############################################## @@ -70,13 +78,23 @@ target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_En # Libraries required in EDI: #this can be a list of numbers -metal_layers=6 +metal_layers=4 #names of metal layers starting from the bottom-most layer on the left. use a python list format. + +# uncomment below for UT austin +#metal_layer_names=["ME1", "ME2", "ME3", "ME4"] + +# uncomment below for University of Toronto metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right + +# uncomment below for UT austin +# power_ring_metal_layer_names=["ME1", "ME1", "ME2", "ME2"] + +# uncomment below for University of Toronto power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] #name of the file to use for layer mapping. used for stream out. @@ -93,35 +111,69 @@ map_file=None wire_selection=WireAreaLowkAgr #specify names of ground and power pins and nets in the library -gnd_net=VSS! -gnd_pin=VSS! -pwr_net=VDD! -pwr_pin=VDD! + +# uncomment below for University of Toronto +gnd_net=VSS +gnd_pin=VSS +pwr_net=VDD +pwr_pin=VDD + +# uncomment below for UT austin +#gnd_net=gnd! +#gnd_pin=gnd! +#pwr_net=vdd! +#pwr_pin=vdd! + tilehi_tielo_cells_between_power_gnd=False #specify footprint names for inverters, buffers, delays. #this is optional. you can get these values from the lib file. #you can also specify None, if you can't find them in the lib file. -#SM: not sure if these are the correct standard cells to be using, as there are many options (need to figure out what DX refers to) +# uncomment below for University of Toronto inv_footprint=INVD0 buf_footprint=BUFFD0 delay_footprint=INVD0 +# uncomment below for UT austin +#inv_footprint=INVX +#buf_footprint=BUFX +#delay_footprint=INVX + #list of filler cell names. use a python list format. #the names can be obtained from .lib files. + +# uncomment below for University of Toronto filler_cell_names=["GFILL", "GFILL10", "GFILL2", "GFILL3", "GFILL4"] +# uncomment below for UT austin +#filler_cell_names=["FILL1", "FILL2", "FILL3", "FILL4"] + #name of the core site in the floorplan. can be obtained from lef files. + +# uncomment below for University of Toronto core_site_name=core +# uncomment below for UT austin +#core_site_name=Core + #specify the utilization of the core site. you can specify multiple ones on different lines. core_utilization=0.90 - #specify LEF files in the library. remember to specify the tech/header file first and then the file that has macros/cells. +# uncomment below for UT austin +#lef_files="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_header.lef /home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_allStdCells.lef" + +# uncomment below for University of Toronto lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_6lmT1.lef" #list names (full paths) of the .lib files for various corners + +# uncomment below for UT austin +#best_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib +#standard_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib +#worst_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +# uncomment below for University of Toronto best_case_libs=/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib standard_libs=/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib @@ -144,11 +196,17 @@ pr_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr #mode_signal=mode_0 #mode_signal=mode_1 - #the directory containing the primetime library and the name of the library file +# uncomment below for UT austin +#primetime_lib_path=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys +#primetime_lib_name=ceid_vlsiLab_umc65ll_stdCells.db + +# uncomment below for University of Toronto primetime_lib_path="/CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" primetime_lib_name=tcbn65gplustc.db + +#the directory containing the primetime library and the name of the library file # The name of the folder in which primetime results/reports are to be stored primetime_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pt From 29623d3997c8e368782a4008b72ff6d5ff944151 Mon Sep 17 00:00:00 2001 From: Stephen More Date: Mon, 17 Oct 2022 10:49:28 -0400 Subject: [PATCH 4/7] added old version of dsp_slice under dsp_slice_ceid.txt --- .../simple_dsp_slice_65nm/dsp_slice_ceid.txt | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 input_files/simple_dsp_slice_65nm/dsp_slice_ceid.txt diff --git a/input_files/simple_dsp_slice_65nm/dsp_slice_ceid.txt b/input_files/simple_dsp_slice_65nm/dsp_slice_ceid.txt new file mode 100644 index 0000000..88dc564 --- /dev/null +++ b/input_files/simple_dsp_slice_65nm/dsp_slice_ceid.txt @@ -0,0 +1,327 @@ +#This is a sample settings file for the hard block flow. +#The hard block flow is detailed in the paper: +#"COFFE 2: Automatic Modelling and Optimization of Complex and Heterogeneous FPGA Architectures" +#https://dl.acm.org/doi/10.1145/3301298 +#Most of the variables below have comments with them. The paper provides more context and details too. + +############################################# +########## General Design Settings ########## +############################################# +# The folder in which all the design files are located: +design_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/input_files/simple_dsp_slice_65nm/dsp_slice_hdl + +# The design language. Should be either 'verilog', 'vhdl' or 'sverilog' +design_language=verilog + +# The exponents of delay and area in the cost function. +# cost = (delay ^ delay_cost_exp) * (area ^ area_cost_exp) +delay_cost_exp=1.0 +area_cost_exp=1.0 + +######################################## +########## Synthesis Settings ########## +######################################## + +# Name of the clock pin in the design +clock_pin_name=clk + +# Desired clock period in ns +clock_period=3.0 + +# Name of the top-level entity in the design +top_level=dsp_slice + +# The name of the folder in which post-synthesis files and synthesis reports are to be stored +synth_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_synth + +# Do you want to be informed of warnings during synthesis? +show_warnings=True + +# Should the flow terminate after synthesis? +# A value of "False" will continue into placement and routing +synthesis_only=False + +# Do you want to provide a saif file for power analysis? +# In case of setting this to "True" a saif.saif file should be provided +read_saif_file=False + +# If you don't want to provide a saif file, specify the switching activity parameters below: +static_probability=0.5 +toggle_rate=25 + +# Should COFFE generate an activity file for the design (using modelsim) +generate_activity_file=False + +# Location of the library files. +# if you have more than one library, please provide them similiar to the example below. + +#link_libraries=/usr/local/packages/cadence_2007/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb +#link_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb +link_libraries="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db dw_foundation.sldb" + +#target_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db +target_libraries=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db + +############################################## +########## Place and Route Settings ########## +############################################## + +# Libraries required in EDI: + +#this can be a list of numbers +metal_layers=4 + +#names of metal layers starting from the bottom-most layer on the left. use a python list format. +metal_layer_names=["ME1", "ME2", "ME3", "ME4"] + +#names of metal layers to use for each side of the power ring +#order: top, bottom, left, right +power_ring_metal_layer_names=["ME1", "ME1", "ME2", "ME2"] + +#name of the file to use for layer mapping. used for stream out. +#set it to None if you want the tool to create a generic map file +map_file=None + +#mention the wireload model to be used. this is present in .lib files. +#if the library doesn't have wireload models, specify None. +#multiple values can be specified. just add more rows like: +#wire_selection=WireAreaLowkCon +#wire_selection=WireAreaLowkAgr +#wire_selection=WireAreaForZero +wire_selection=DEFAULT + +#specify names of ground and power pins and nets in the library +gnd_net=gnd! +gnd_pin=gnd! +pwr_net=vdd! +pwr_pin=vdd! +tilehi_tielo_cells_between_power_gnd=False + +#specify footprint names for inverters, buffers, delays. +#this is optional. you can get these values from the lib file. +#you can also specify None, if you can't find them in the lib file. +inv_footprint=INVX +buf_footprint=BUFX +delay_footprint=INVX + +#list of filler cell names. use a python list format. +#the names can be obtained from .lib files. +filler_cell_names=["FILL1", "FILL2", "FILL3", "FILL4"] + +#name of the core site in the floorplan. can be obtained from lef files. +core_site_name=Core + +#specify the utilization of the core site. you can specify multiple ones on different lines. +core_utilization=0.70 + +#specify LEF files in the library. remember to specify the tech/header file first and then the file that has macros/cells. +lef_files="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_header.lef /home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_allStdCells.lef" + +#list names (full paths) of the .lib files for various corners +best_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +standard_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +worst_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +# EDI (Cadence Encounter) settings: +power_ring_width=3 +power_ring_spacing=1 +height_to_width_ratio=4.0 +space_around_core=10 + +# The folder in which place and route reports and post-routing netlists and spef files will be stored +pr_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr + + +############################################## +########## Prime Time Settings ############### +############################################## + +#mode_signal=mode_0 +#mode_signal=mode_1 + +#the directory containing the primetime library and the name of the library file +primetime_lib_path=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys +primetime_lib_name=ceid_vlsiLab_umc65ll_stdCells.db + +# The name of the folder in which primetime results/reports are to be stored +primetime_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pt + +# COFFE parameters: +name=hard_block +num_gen_inputs=22 +crossbar_population=0.5 +height=4 +num_gen_outputs=9 +num_dedicated_outputs=0 +soft_logic_per_block=0.1 +area_scale_factor=0.14 +freq_scale_factor=2.32 +power_scale_factor=0.29 +input_usage=0.8 +num_crossbars=1 +crossbar_modelling=optimistic#This is a sample settings file for the hard block flow. +#The hard block flow is detailed in the paper: +#"COFFE 2: Automatic Modelling and Optimization of Complex and Heterogeneous FPGA Architectures" +#https://dl.acm.org/doi/10.1145/3301298 +#Most of the variables below have comments with them. The paper provides more context and details too. + +############################################# +########## General Design Settings ########## +############################################# +# The folder in which all the design files are located: +design_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/input_files/simple_dsp_slice_65nm/dsp_slice_hdl + +# The design language. Should be either 'verilog', 'vhdl' or 'sverilog' +design_language=verilog + +# The exponents of delay and area in the cost function. +# cost = (delay ^ delay_cost_exp) * (area ^ area_cost_exp) +delay_cost_exp=1.0 +area_cost_exp=1.0 + +######################################## +########## Synthesis Settings ########## +######################################## + +# Name of the clock pin in the design +clock_pin_name=clk + +# Desired clock period in ns +clock_period=3.0 + +# Name of the top-level entity in the design +top_level=dsp_slice + +# The name of the folder in which post-synthesis files and synthesis reports are to be stored +synth_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_synth + +# Do you want to be informed of warnings during synthesis? +show_warnings=True + +# Should the flow terminate after synthesis? +# A value of "False" will continue into placement and routing +synthesis_only=False + +# Do you want to provide a saif file for power analysis? +# In case of setting this to "True" a saif.saif file should be provided +read_saif_file=False + +# If you don't want to provide a saif file, specify the switching activity parameters below: +static_probability=0.5 +toggle_rate=25 + +# Should COFFE generate an activity file for the design (using modelsim) +generate_activity_file=False + +# Location of the library files. +# if you have more than one library, please provide them similiar to the example below. + +#link_libraries=/usr/local/packages/cadence_2007/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb +#link_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db dw_foundation.sldb +link_libraries="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db dw_foundation.sldb" + +#target_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db +target_libraries=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db + +############################################## +########## Place and Route Settings ########## +############################################## + +# Libraries required in EDI: + +#this can be a list of numbers +metal_layers=4 + +#names of metal layers starting from the bottom-most layer on the left. use a python list format. +metal_layer_names=["ME1", "ME2", "ME3", "ME4"] + +#names of metal layers to use for each side of the power ring +#order: top, bottom, left, right +power_ring_metal_layer_names=["ME1", "ME1", "ME2", "ME2"] + +#name of the file to use for layer mapping. used for stream out. +#set it to None if you want the tool to create a generic map file +map_file=None + +#mention the wireload model to be used. this is present in .lib files. +#if the library doesn't have wireload models, specify None. +#multiple values can be specified. just add more rows like: +#wire_selection=WireAreaLowkCon +#wire_selection=WireAreaLowkAgr +#wire_selection=WireAreaForZero +wire_selection=DEFAULT + +#specify names of ground and power pins and nets in the library +gnd_net=gnd! +gnd_pin=gnd! +pwr_net=vdd! +pwr_pin=vdd! +tilehi_tielo_cells_between_power_gnd=False + +#specify footprint names for inverters, buffers, delays. +#this is optional. you can get these values from the lib file. +#you can also specify None, if you can't find them in the lib file. +inv_footprint=INVX +buf_footprint=BUFX +delay_footprint=INVX + +#list of filler cell names. use a python list format. +#the names can be obtained from .lib files. +filler_cell_names=["FILL1", "FILL2", "FILL3", "FILL4"] + +#name of the core site in the floorplan. can be obtained from lef files. +core_site_name=Core + +#specify the utilization of the core site. you can specify multiple ones on different lines. +core_utilization=0.70 + +#specify LEF files in the library. remember to specify the tech/header file first and then the file that has macros/cells. +lef_files="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_header.lef /home/projects/ljohn/aarora1/ceid/ceid_umc65ll/lef/ceid_vlsiLab_umc65ll_allStdCells.lef" + +#list names (full paths) of the .lib files for various corners +best_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +standard_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +worst_case_libs=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.lib + +# EDI (Cadence Encounter) settings: +power_ring_width=3 +power_ring_spacing=1 +height_to_width_ratio=4.0 +space_around_core=10 + +# The folder in which place and route reports and post-routing netlists and spef files will be stored +pr_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr + + +############################################## +########## Prime Time Settings ############### +############################################## + +#mode_signal=mode_0 +#mode_signal=mode_1 + +#the directory containing the primetime library and the name of the library file +primetime_lib_path=/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys +primetime_lib_name=ceid_vlsiLab_umc65ll_stdCells.db + +# The name of the folder in which primetime results/reports are to be stored +primetime_folder=/home/projects/ljohn/aarora1/coffe2_aman/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pt + +# COFFE parameters: +name=hard_block +num_gen_inputs=22 +crossbar_population=0.5 +height=4 +num_gen_outputs=9 +num_dedicated_outputs=0 +soft_logic_per_block=0.1 +area_scale_factor=0.14 +freq_scale_factor=2.32 +power_scale_factor=0.29 +input_usage=0.8 +num_crossbars=1 +crossbar_modelling=optimistic \ No newline at end of file From 0b8b6da5467f2068bf1cdc3cfe4c6e46a73cdd7f Mon Sep 17 00:00:00 2001 From: Stephen More Date: Mon, 17 Oct 2022 16:24:54 -0400 Subject: [PATCH 5/7] more refactoring, added preprocessing for parameters taken in from config files but which need to be changed to different formats when written out to tcl scripts, removed the primetime_lib_path parameter as its going to be the same as the libs used in synthesis, added the command line arg to only run hard block synthesis, added option to specify a process_specific_params file which makes it easier for users to distinguish which params need to be changed when changing process libs --- User Manual.md | 4 + coffe.py | 195 +++++++------- coffe/fpga.py | 2 - coffe/hardblock_functions.py | 252 +++++++++++------- coffe/utils.py | 194 ++++++++++---- .../simple_dsp_slice_65nm/dsp_slice.txt | 14 +- input_files/strtx_III_dsp/dsp_hb_settings.txt | 51 ++-- .../strtx_III_dsp/process_specific_params.txt | 62 +++++ unit_test.sh | 15 ++ 9 files changed, 513 insertions(+), 276 deletions(-) create mode 100644 input_files/strtx_III_dsp/process_specific_params.txt create mode 100644 unit_test.sh diff --git a/User Manual.md b/User Manual.md index 9b8022b..de1b76e 100644 --- a/User Manual.md +++ b/User Manual.md @@ -80,6 +80,10 @@ $(which encounter) To plot the power, area, and delay results against target frequency run the following command (this requires python3 and matplotlib to be installed): - $(python3 plot_coffe_results.py -c report_csv_out/condensed_report.csv) +4. A script that runs all of the above commands can be run from COFFE repo: + - $(chmod +x ./unit_test.sh) + - $(./unit_test.sh) + diff --git a/coffe.py b/coffe.py index ebbcd95..db0d19b 100644 --- a/coffe.py +++ b/coffe.py @@ -46,6 +46,8 @@ import datetime import math + + print "\nCOFFE 2.0\n" print "Man is a tool-using animal." print "Without tools he is nothing, with tools he is all." @@ -65,106 +67,113 @@ parser.add_argument('-a', '--area_opt_weight', type=int, default=1, help="area optimization weight") parser.add_argument('-d', '--delay_opt_weight', type=int, default=1, help="delay optimization weight") parser.add_argument('-i', '--max_iterations', type=int, default=6, help="max FPGA sizing iterations") +parser.add_argument('-ho',"--hardblock_only",help="run only a single hardblock through the asic flow", action='store_true',default=False) # quick mode is disabled by default. Try passing -q 0.03 for 3% minimum improvement parser.add_argument('-q', '--quick_mode', type=float, default=-1.0, help="minimum cost function improvement for resizing") args = parser.parse_args() -is_size_transistors = not args.no_sizing - # Load the input architecture description file arch_params_dict = utils.load_arch_params(args.arch_description) - -# Make the top-level spice folder if it doesn't already exist -# if it's already there delete its content arch_folder = utils.create_output_dir(args.arch_description, arch_params_dict['arch_out_folder']) - -# Print the options to both terminal and report file -report_file_path = os.path.join(arch_folder, "report.txt") -utils.print_run_options(args, report_file_path) - -# Print architecture and process details to terminal and report file -utils.print_architecture_params(arch_params_dict, report_file_path) - -# Default_dir is the dir you ran COFFE from. COFFE will be switching directories -# while running HSPICE, this variable is so that we can get back to our starting point -default_dir = os.getcwd() - -# Create an HSPICE interface -spice_interface = spice.SpiceInterface() - -# Record start time -total_start_time = time.time() - -# Create an FPGA instance -fpga_inst = fpga.FPGA(arch_params_dict, args, spice_interface) - -############################################################### -## GENERATE FILES -############################################################### - -# Change to the architecture directory -os.chdir(arch_folder) - -# Generate FPGA and associated SPICE files -fpga_inst.generate(is_size_transistors) - -# Go back to the base directory -os.chdir(default_dir) - -# Extract initial transistor sizes from file and overwrite the -# default initial sizes if this option was used. -if args.initial_sizes != "default" : - utils.use_initial_tran_size(args.initial_sizes, fpga_inst, tran_sizing, arch_params_dict['use_tgate']) - -# Print FPGA implementation details -report_file = open(report_file_path, 'a') -fpga_inst.print_details(report_file) -report_file.close() - -# Go to architecture directory -os.chdir(arch_folder) - -############################################################### -## TRANSISTOR SIZING -############################################################### - -sys.stdout.flush() - -# Size FPGA transistors -if is_size_transistors: - tran_sizing.size_fpga_transistors(fpga_inst, args, spice_interface) +if(args.hardblock_only): + # Change to the architecture directory + for hardblock_fname in arch_params_dict["hb_files"]: + hard_block = fpga._hard_block(hardblock_fname,False) + os.chdir(arch_folder) + hard_block.generate_top() else: - # in case of disabling floorplanning there is no need to - # update delays before updating area. Tried both ways and - # they give exactly the same results - #fpga_inst.update_delays(spice_interface) - - # same thing here no need to update area before calculating - # the lb_height value. Also tested and gave same results - #fpga_inst.update_area() - fpga_inst.lb_height = math.sqrt(fpga_inst.area_dict["tile"]) - fpga_inst.update_area() - fpga_inst.compute_distance() - fpga_inst.update_wires() - fpga_inst.update_wire_rc() - - # commented this part to avoid doing floorplannig for - # a non-sizing run - #fpga_inst.determine_height() - - fpga_inst.update_delays(spice_interface) - -# Obtain Memory core power -if arch_params_dict['enable_bram_module'] == 1: - fpga_inst.update_power(spice_interface) - -# Go back to the base directory -os.chdir(default_dir) - -# Print out final COFFE report to file -utils.print_summary(arch_folder, fpga_inst, total_start_time) - -# Print vpr architecure file -coffe.vpr.print_vpr_file(fpga_inst, arch_folder, arch_params_dict['enable_bram_module']) + is_size_transistors = not args.no_sizing + # Make the top-level spice folder if it doesn't already exist + # if it's already there delete its content + # arch_folder = utils.create_output_dir(args.arch_description, arch_params_dict['arch_out_folder']) + + # Print the options to both terminal and report file + report_file_path = os.path.join(arch_folder, "report.txt") + utils.print_run_options(args, report_file_path) + + # Print architecture and process details to terminal and report file + utils.print_architecture_params(arch_params_dict, report_file_path) + + # Default_dir is the dir you ran COFFE from. COFFE will be switching directories + # while running HSPICE, this variable is so that we can get back to our starting point + default_dir = os.getcwd() + + # Create an HSPICE interface + spice_interface = spice.SpiceInterface() + + # Record start time + total_start_time = time.time() + + # Create an FPGA instance + fpga_inst = fpga.FPGA(arch_params_dict, args, spice_interface) + + ############################################################### + ## GENERATE FILES + ############################################################### + + # Change to the architecture directory + os.chdir(arch_folder) + + # Generate FPGA and associated SPICE files + fpga_inst.generate(is_size_transistors) + + # Go back to the base directory + os.chdir(default_dir) + + # Extract initial transistor sizes from file and overwrite the + # default initial sizes if this option was used. + if args.initial_sizes != "default" : + utils.use_initial_tran_size(args.initial_sizes, fpga_inst, tran_sizing, arch_params_dict['use_tgate']) + + # Print FPGA implementation details + report_file = open(report_file_path, 'a') + fpga_inst.print_details(report_file) + report_file.close() + + # Go to architecture directory + os.chdir(arch_folder) + + ############################################################### + ## TRANSISTOR SIZING + ############################################################### + + sys.stdout.flush() + + # Size FPGA transistors + if is_size_transistors: + tran_sizing.size_fpga_transistors(fpga_inst, args, spice_interface) + else: + # in case of disabling floorplanning there is no need to + # update delays before updating area. Tried both ways and + # they give exactly the same results + #fpga_inst.update_delays(spice_interface) + + # same thing here no need to update area before calculating + # the lb_height value. Also tested and gave same results + #fpga_inst.update_area() + fpga_inst.lb_height = math.sqrt(fpga_inst.area_dict["tile"]) + fpga_inst.update_area() + fpga_inst.compute_distance() + fpga_inst.update_wires() + fpga_inst.update_wire_rc() + + # commented this part to avoid doing floorplannig for + # a non-sizing run + #fpga_inst.determine_height() + + fpga_inst.update_delays(spice_interface) + + # Obtain Memory core power + if arch_params_dict['enable_bram_module'] == 1: + fpga_inst.update_power(spice_interface) + + # Go back to the base directory + os.chdir(default_dir) + + # Print out final COFFE report to file + utils.print_summary(arch_folder, fpga_inst, total_start_time) + + # Print vpr architecure file + coffe.vpr.print_vpr_file(fpga_inst, arch_folder, arch_params_dict['enable_bram_module']) diff --git a/coffe/fpga.py b/coffe/fpga.py index f105593..5d50259 100644 --- a/coffe/fpga.py +++ b/coffe/fpga.py @@ -5177,8 +5177,6 @@ def generate_top(self): # hard block flow self.flow_results = hardblock_functions.hardblock_flow(self.parameters) - if(self.parameters["asic_flow_only"] == True): - sys.exit() #the area returned by the hardblock flow is in um^2. In area_dict, all areas are in nm^2 self.area = self.flow_results[0] * self.parameters['area_scale_factor'] * (1e+6) diff --git a/coffe/hardblock_functions.py b/coffe/hardblock_functions.py index 56da169..48c76ee 100644 --- a/coffe/hardblock_functions.py +++ b/coffe/hardblock_functions.py @@ -10,25 +10,28 @@ import shutil import math -def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_selection): - ########################################### - # Synthesis - ########################################### + +def write_synth_tcl(flow_settings,clock_period,wire_selection): + """ + Writes the dc_script.tcl file which will be executed to run synthesis using Synopsys Design Compiler, tested under 2017 version + """ file = open("dc_script.tcl","w") - file.write("cd " + os.path.expanduser(flow_settings['synth_folder']) + "\n") - file.write("set search_path " + "\"" + " ".join(search_path_dirs) + "\"" + " \n") - if len(design_files) == 1: - file.write("set my_files " + design_files[0] + "\n") + file.write("cd " + flow_settings['synth_folder'] + "\n") + file.write("set search_path " + flow_settings["search_path"] + " \n") + if len(flow_settings["design_files"]) == 1: + file.write("set my_files " + flow_settings["design_files"][0] + "\n") else: file.write("set my_files [list ") - for entity in design_files: + for entity in flow_settings["design_files"]: + #currently set to ignore filenames of parameters.v/c_functions.v this should be updated in the future as its design specific TODO if not (entity == "parameters.v" or entity == "c_functions.v"): file.write(entity + " ") file.write("] \n") file.write("set my_top_level " + flow_settings['top_level'] + "\n") file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") + #after pre_processing function, the target_library and link_library vars should be set (link_library is all files in cwd and target_library) + file.write("set target_library " + flow_settings["target_library"] + "\n") + file.write("set link_library " + flow_settings["link_library"] + "\n") file.write(r'set power_analysis_mode "averaged"' + "\n") file.write("define_design_lib WORK -path ./WORK \n") if flow_settings['design_language'] == 'verilog': @@ -39,7 +42,7 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele file.write("analyze -f sverilog $my_files \n") file.write("elaborate $my_top_level \n") file.write("current_design $my_top_level \n") - file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/checkprecompile.rpt\n") + file.write("check_design > " + flow_settings['synth_folder'] + "/checkprecompile.rpt\n") file.write("link \n") file.write("uniquify \n") #If wire_selection is None, then no wireload model is used during synthesis. This does imply results @@ -53,26 +56,33 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele file.write("set clk_name $my_clock_pin \n") file.write("create_clock -period $my_period $clk_name} \n\n") file.write("compile_ultra\n") - file.write("check_design > " + os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt\n") + file.write("check_design > " + flow_settings['synth_folder'] + "/check.rpt\n") file.write("link \n") - file.write("write_file -format ddc -hierarchy -output " + os.path.expanduser(flow_settings['synth_folder']) + "/" + flow_settings['top_level'] + ".ddc \n") + file.write("write_file -format ddc -hierarchy -output " + flow_settings['synth_folder'] + "/" + flow_settings['top_level'] + ".ddc \n") if flow_settings['read_saif_file']: file.write("read_saif saif.saif \n") else: file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") file.write("ungroup -all -flatten \n") - file.write("report_power > " + os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt\n") - file.write("report_area -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt\n") - file.write("report_resources -nosplit -hierarchy > " + os.path.expanduser(flow_settings['synth_folder']) + "/resources.rpt\n") - file.write("report_timing > " + os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt\n") + file.write("report_power > " + flow_settings['synth_folder'] + "/power.rpt\n") + file.write("report_area -nosplit -hierarchy > " + flow_settings['synth_folder'] + "/area.rpt\n") + file.write("report_resources -nosplit -hierarchy > " + flow_settings['synth_folder'] + "/resources.rpt\n") + file.write("report_timing > " + flow_settings['synth_folder'] + "/timing.rpt\n") file.write("change_names -hier -rule verilog \n") - file.write("write -f verilog -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.v\n") - file.write("write_sdf " + os.path.expanduser(flow_settings['synth_folder']) + "/synthsized.sdf \n") - file.write("write_parasitics -output " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.spef \n") - file.write("write_sdc " + os.path.expanduser(flow_settings['synth_folder']) + "/synthesized.sdc \n") + file.write("write -f verilog -output " + flow_settings['synth_folder'] + "/synthesized.v\n") + file.write("write_sdf " + flow_settings['synth_folder'] + "/synthsized.sdf \n") + file.write("write_parasitics -output " + flow_settings['synth_folder'] + "/synthesized.spef \n") + file.write("write_sdc " + flow_settings['synth_folder'] + "/synthesized.sdc \n") file.write("quit \n") file.close() +#search_path_dirs,design_files, +def run_synth(flow_settings,clock_period,wire_selection): + """" + runs the synthesis flow for specific clock period and wireload model + Prereqs: flow_settings_pre_process() function to properly format params for scripts + """ + write_synth_tcl(flow_settings,clock_period,wire_selection) # Run the scrip in design compiler shell subprocess.call('dc_shell-t -f dc_script.tcl | tee dc.log', shell=True,executable="/bin/bash") # clean after DC! @@ -82,7 +92,7 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele # Make sure it worked properly # Open the timing report and make sure the critical path is non-zero: - check_file = open(os.path.expanduser(flow_settings['synth_folder']) + "/check.rpt", "r") + check_file = open(flow_settings['synth_folder'] + "/check.rpt", "r") for line in check_file: if "Error" in line: print "Your design has errors. Refer to check.rpt in synthesis directory" @@ -94,9 +104,9 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele #Copy synthesis results to a unique dir in synth dir synth_report_str = "period_" + clock_period + "_" + "wire_mdl_" + wire_selection - report_dest_str = os.path.expanduser(flow_settings['synth_folder']) + "/" + synth_report_str + "_reports" + report_dest_str = flow_settings['synth_folder'] + "/" + synth_report_str + "_reports" mkdir_cmd_str = "mkdir -p " + report_dest_str - copy_rep_cmd_str = "cp " + os.path.expanduser(flow_settings['synth_folder']) + "/*.rpt " + report_dest_str + copy_rep_cmd_str = "cp " + flow_settings['synth_folder'] + "/*.rpt " + report_dest_str copy_logs_cmd_str = "cp " + "dc.log "+ "dc_script.tcl " + report_dest_str subprocess.call(mkdir_cmd_str,shell=True) subprocess.call(copy_rep_cmd_str,shell=True) @@ -106,13 +116,13 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele #if the user doesn't want to perform place and route, extract the results from DC reports and end if flow_settings['synthesis_only']: # read total area from the report file: - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/area.rpt" ,"r") + file = open(flow_settings['synth_folder'] + "/area.rpt" ,"r") for line in file: if line.startswith('Total cell area:'): total_area = re.findall(r'\d+\.{0,1}\d*', line) file.close() # Read timing parameters - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/timing.rpt" ,"r") + file = open(flow_settings['synth_folder'] + "/timing.rpt" ,"r") for line in file: if 'library setup time' in line: library_setup_time = re.findall(r'\d+\.{0,1}\d*', line) @@ -124,7 +134,7 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele total_delay = float(data_arrival_time[0]) file.close() # Read dynamic power - file = open(os.path.expanduser(flow_settings['synth_folder']) + "/power.rpt" ,"r") + file = open(flow_settings['synth_folder'] + "/power.rpt" ,"r") for line in file: if 'Total Dynamic Power' in line: total_dynamic_power = re.findall(r'\d+\.\d*', line) @@ -146,11 +156,10 @@ def run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_sele exit() return synth_report_str - -def run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str): - ########################################### - # Place and Route - ########################################### +def write_pnr_script(flow_settings,metal_layer,core_utilization): + """" + writes the tcl script for place and route using Cadence Encounter, tested under 2009 version + """ # generate the EDI (encounter) configuration file = open("edi.conf", "w") file.write("global rda_Input \n") @@ -277,6 +286,12 @@ def run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str): file.write(r'streamOut ' + os.path.expanduser(flow_settings['pr_folder']) + r'/final.gds2' + ' -stripes 1 -units 1000 -mode ALL' + "\n") file.write("exit \n") file.close() +def run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str): + """ + runs place and route using cadence encounter + Prereqs: flow_settings_pre_process() function to properly format params for scripts + """ + write_pnr_script(flow_settings,metal_layer,core_utilization) # Run the scrip in EDI subprocess.call('encounter -nowin -init edi.tcl | tee edi.log', shell=True,executable="/bin/bash") # clean after EDI! @@ -301,6 +316,9 @@ def run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str): return pnr_report_str, total_area def run_sim(): + """ + Runs simulation using a user inputted testbench, not tested and unsure of which hard block its modeling USE AT OWN RISK (ie use saif file option in hardblock settings file) + """ # Create a modelsim folder #subprocess.call("mkdir -p"+os.path.expanduser("./modelsim_dir")+"\n", shell=True) # Create a modelsim .do file: @@ -324,21 +342,53 @@ def run_sim(): subprocess.call('wlf2vcd -o test.vcd out.wlf', shell=True) subprocess.call('vcd2saif -input test.vcd -o saif.saif', shell=True) -def run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str): - ########################################### - # Primetime - ########################################### - if not mode_enabled: - x = 2**len(flow_settings['mode_signal']) +def write_pt_power_script(flow_settings,mode_enabled,clock_period,x): + """" + writes the tcl script for timing analysis using Synopsys Design Compiler, tested under 2017 version + """ + # Create a script to measure power: + file = open("primetime_power.tcl", "w") + file.write("set sh_enable_page_mode true \n") + file.write("set search_path " + flow_settings['search_path'] + " \n") + file.write("set my_top_level " + flow_settings['top_level'] + "\n") + file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") + file.write("set target_library " + flow_settings['target_library'] + "\n") + file.write("set link_library " + flow_settings['link_library'] + "\n") + file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") + file.write("link \n") + file.write("set my_period " + str(clock_period) + " \n") + file.write("set find_clock [ find port [list $my_clock_pin] ] \n") + file.write("if { $find_clock != [list] } { \n") + file.write("set clk_name $my_clock_pin \n") + file.write("create_clock -period $my_period $clk_name} \n\n") + if mode_enabled and x <2**len(flow_settings['mode_signal']): + for y in range (0, len(flow_settings['mode_signal'])): + file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") + file.write("set power_enable_analysis TRUE \n") + file.write(r'set power_analysis_mode "averaged"' + "\n") + if flow_settings['generate_activity_file']: + file.write("read_saif -input saif.saif -instance_name testbench/uut \n") + else: + file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") + #file.write("read_saif -input saif.saif -instance_name testbench/uut \n") + #file.write("read_vcd -input ./modelsim_dir/vcd.vcd \n") + file.write(r'read_parasitics -increment ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + "\n") + #file.write("update_power \n") + file.write(r'report_power > ' + os.path.expanduser(flow_settings['primetime_folder']) + r'/power.rpt' + " \n") + file.write("quit\n") + file.close() + +def write_pt_timing_script(flow_settings,mode_enabled,clock_period,x): + """""" # backannotate into primetime # This part should be reported for all the modes in the design. file = open("primetime.tcl", "w") file.write("set sh_enable_page_mode true \n") - file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") + file.write("set search_path " + flow_settings['search_path'] + " \n") file.write("set my_top_level " + flow_settings['top_level'] + "\n") file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") + file.write("set target_library " + flow_settings['target_library'] + "\n") + file.write("set link_library " + flow_settings['link_library'] + "\n") file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") if mode_enabled and x <2**len(flow_settings['mode_signal']): for y in range (0, len(flow_settings['mode_signal'])): @@ -353,6 +403,11 @@ def run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str): file.write("report_timing > " + os.path.expanduser(flow_settings['primetime_folder']) + "/timing.rpt \n") file.write("quit \n") file.close() + +def run_power_timing(flow_settings,mode_enabled,clock_period,x,pnr_report_str): + if not mode_enabled: + x = 2**len(flow_settings['mode_signal']) + write_pt_timing_script(flow_settings,mode_enabled,clock_period,x) # run prime time subprocess.call('dc_shell-t -f primetime.tcl | tee pt.log', shell=True,executable="/bin/bash") # Read timing parameters @@ -367,38 +422,7 @@ def run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str): except NameError: total_delay = float(data_arrival_time[0]) file.close() - # Create a script to measure power: - file = open("primetime_power.tcl", "w") - file.write("set sh_enable_page_mode true \n") - file.write("set search_path " + flow_settings['primetime_lib_path'] + " \n") - file.write("set my_top_level " + flow_settings['top_level'] + "\n") - file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_libraries'] + "\n") - file.write("set link_library " + flow_settings['link_libraries'] + "\n") - file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") - file.write("link \n") - file.write("set my_period " + str(clock_period) + " \n") - file.write("set find_clock [ find port [list $my_clock_pin] ] \n") - file.write("if { $find_clock != [list] } { \n") - file.write("set clk_name $my_clock_pin \n") - file.write("create_clock -period $my_period $clk_name} \n\n") - if mode_enabled and x <2**len(flow_settings['mode_signal']): - for y in range (0, len(flow_settings['mode_signal'])): - file.write("set_case_analysis " + str((x >> y) & 1) + " " + flow_settings['mode_signal'][y] + " \n") - file.write("set power_enable_analysis TRUE \n") - file.write(r'set power_analysis_mode "averaged"' + "\n") - if flow_settings['generate_activity_file']: - file.write("read_saif -input saif.saif -instance_name testbench/uut \n") - else: - file.write("set_switching_activity -static_probability " + str(flow_settings['static_probability']) + " -toggle_rate " + str(flow_settings['toggle_rate']) + " -base_clock $my_clock_pin -type inputs \n") - #file.write("read_saif -input saif.saif -instance_name testbench/uut \n") - #file.write("read_vcd -input ./modelsim_dir/vcd.vcd \n") - file.write(r'read_parasitics -increment ' + os.path.expanduser(flow_settings['pr_folder']) + r'/spef.spef' + "\n") - #file.write("update_power \n") - file.write(r'report_power > ' + os.path.expanduser(flow_settings['primetime_folder']) + r'/power.rpt' + " \n") - file.write("quit\n") - file.close() - + write_pt_power_script(flow_settings,mode_enabled,clock_period,x) # run prime time subprocess.call('dc_shell-t -f primetime_power.tcl | tee pt_pwr.log', shell=True,executable="/bin/bash") #copy reports and logs to a unique dir in pt dir @@ -425,43 +449,85 @@ def run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str): total_dynamic_power[0] = 0 file.close() return library_setup_time, data_arrival_time, total_delay, total_dynamic_power - -# wire loads in the library are WireAreaLowkCon WireAreaLowkAgr WireAreaForZero -def hardblock_flow(flow_settings): - # Enter all the signals that change modes - lowest_cost = sys.float_info.max - lowest_cost_area = 1.0 - lowest_cost_delay = 1.0 - lowest_cost_power = 1.0 +# #this function adds additional hardblock flow parameters which don't require user input +# def add_hb_params(flow_settings,cur_env): + + +def flow_settings_pre_process(processed_flow_settings,cur_env): + """Takes values from the flow_settings dict and converts them into data structures which can be used to write synthesis script""" + # formatting design_files design_files = [] - if flow_settings['design_language'] == 'verilog': + if processed_flow_settings['design_language'] == 'verilog': ext_re = re.compile(".*.v") - elif flow_settings['design_language'] == 'vhdl': + elif processed_flow_settings['design_language'] == 'vhdl': ext_re = re.compile(".*.vhdl") - elif flow_settings['design_language'] == 'sverilog': + elif processed_flow_settings['design_language'] == 'sverilog': ext_re = re.compile(".*(.sv)|(.v)") - design_folder = os.path.expanduser(flow_settings['design_folder']) + design_folder = os.path.expanduser(processed_flow_settings['design_folder']) design_files = [fn for _, _, fs in os.walk(design_folder) for fn in fs if ext_re.search(fn)] + #The syn_write_tcl_script function expects this to be a list of all design files + processed_flow_settings["design_files"] = design_files + # formatting search_path search_path_dirs = [] + search_path_dirs.append(".") + try: + syn_root = cur_env.get("SYNOPSYS") + search_path_dirs = [os.path.join(syn_root,"libraries",dirname) for dirname in ["syn","syn_ver","sim_ver"] ] + except: + print("could not find 'SYNOPSYS' environment variable set, please run the following command to your sysopsys home directory") + print("export SYNOPSYS=/abs/path/to/synopsys/home") + print("Ex. export SYNOPSYS=/CMC/tools/synopsys/syn_vN-2017.09/") + sys.exit(1) + + for p_lib_path in processed_flow_settings["process_lib_paths"]: + search_path_dirs.append(p_lib_path) search_path_dirs.append(design_folder) for root,dirnames,fnames in os.walk(design_folder): for dirname,fname in zip(dirnames,fnames): if(ext_re.search(fname)): search_path_dirs.append(os.path.join(root,dirname)) - subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['synth_folder']) + "\n", shell=True) - subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['pr_folder']) + "\n", shell=True) - subprocess.call("mkdir -p " + os.path.expanduser(flow_settings['primetime_folder']) + "\n", shell=True) + search_path_str = "\"" + " ".join(search_path_dirs) + "\"" + processed_flow_settings["search_path"] = search_path_str + #formatting target libs + processed_flow_settings["target_library"] = "\"" + " ".join(processed_flow_settings['target_libraries']) + "\"" + processed_flow_settings["link_library"] = "\"" + "* $target_library" + "\"" + #formatting all paths to files to expand them to user space + for flow_key, flow_val in processed_flow_settings.items(): + if("folder" in flow_key): + processed_flow_settings[flow_key] = os.path.expanduser(flow_val) + + #formatting process specific params + processed_flow_settings["lef_files"] = "\"" + " ".join(processed_flow_settings['lef_files']) + "\"" + processed_flow_settings["best_case_libs"] = "\"" + " ".join(processed_flow_settings['best_case_libs']) + "\"" + processed_flow_settings["standard_libs"] = "\"" + " ".join(processed_flow_settings['standard_libs']) + "\"" + processed_flow_settings["worst_case_libs"] = "\"" + " ".join(processed_flow_settings['worst_case_libs']) + "\"" + +# wire loads in the library are WireAreaLowkCon WireAreaLowkAgr WireAreaForZero +def hardblock_flow(flow_settings): + cur_env = os.environ.copy() + #add_hb_params(flow_settings,cur_env) + # processed_flow_settings = {} + processed_flow_settings = flow_settings + flow_settings_pre_process(processed_flow_settings,cur_env) + # Enter all the signals that change modes + lowest_cost = sys.float_info.max + lowest_cost_area = 1.0 + lowest_cost_delay = 1.0 + lowest_cost_power = 1.0 + subprocess.call("mkdir -p " + flow_settings['synth_folder'] + "\n", shell=True) + subprocess.call("mkdir -p " + flow_settings['pr_folder'] + "\n", shell=True) + subprocess.call("mkdir -p " + flow_settings['primetime_folder'] + "\n", shell=True) # Make sure we managed to read the design files - assert len(design_files) >= 1 + assert len(processed_flow_settings["design_files"]) >= 1 for clock_period in flow_settings['clock_period']: for wire_selection in flow_settings['wire_selection']: - synth_report_str = run_synth(flow_settings,search_path_dirs,design_files,clock_period,wire_selection) + synth_report_str = run_synth(processed_flow_settings,clock_period,wire_selection) for metal_layer in flow_settings['metal_layers']: for core_utilization in flow_settings['core_utilization']: - pnr_report_str, total_area = run_pnr(flow_settings,metal_layer,core_utilization,synth_report_str) + pnr_report_str, total_area = run_pnr(processed_flow_settings,metal_layer,core_utilization,synth_report_str) if len(flow_settings['mode_signal']) > 0: mode_enabled = True else: @@ -471,7 +537,7 @@ def hardblock_flow(flow_settings): if flow_settings['generate_activity_file'] is True: run_sim() for x in range(0, 2**len(flow_settings['mode_signal']) + 1): - library_setup_time, data_arrival_time, total_delay, total_dynamic_power = run_power_timing(flow_settings,mode_enabled,clock_period,pnr_report_str) + library_setup_time, data_arrival_time, total_delay, total_dynamic_power = run_power_timing(flow_settings,mode_enabled,clock_period,x,pnr_report_str) # write the final report file: if mode_enabled and x <2**len(flow_settings['mode_signal']): file = open("report_mode" + str(x) + "_" + str(flow_settings['top_level']) + "_" + str(clock_period) + "_" + str(wire_selection) + "_wire_" + str(metal_layer) + "_" + str(core_utilization) + ".txt" ,"w") diff --git a/coffe/utils.py b/coffe/utils.py index 664d72e..b2640cc 100644 --- a/coffe/utils.py +++ b/coffe/utils.py @@ -679,7 +679,24 @@ def load_arch_params(filename): return arch_params +def sanatize_str_input_to_list(value): + """Makes sure unneeded quotes arent included when a string of values is seperated by a space and saved into + string seperated by spaces and surrouneded with quotes""" + vals = (value.strip("\"")).split(" ") + return vals +def check_hard_params(hard_params,optional_params): + """ + This function checks the hardblock/process parameters to make sure that all the parameters have been read in. + Right now, this functions just checks really basic stuff like + checking for unset values + """ + + #TODO make this sort of a documentation for each parameter + for key,val in hard_params.items(): + if ((val == "" or val == -1 or val == -1.0 or val == []) and key not in optional_params): + print("param \"%s\" is unset, please go to your hardblock/process params file and set it" % (key)) + sys.exit(1) def load_hard_params(filename): """ Parse the hard block description file and load values into dictionary. @@ -710,24 +727,23 @@ def load_hard_params(filename): 'synth_folder': "", 'show_warnings': False, 'synthesis_only': False, - 'asic_flow_only': False, 'read_saif_file': False, 'static_probability': -1.0, 'toggle_rate': -1, - 'link_libraries': '', - 'target_libraries': '', - 'lef_files': '', - 'best_case_libs': '', - 'standard_libs': '', - 'worst_case_libs': '', + #'link_libraries': '', + 'target_libraries': [], + 'lef_files': [], + 'best_case_libs': [], + 'standard_libs': [], + 'worst_case_libs': [], 'power_ring_width': -1, 'power_ring_spacing': -1, 'height_to_width_ratio': -1.0, 'core_utilization': [], 'space_around_core': -1, 'pr_folder': "", - 'primetime_lib_path': '', - 'primetime_lib_name': '', + #'primetime_lib_path': '', + #'primetime_lib_name': '', 'primetime_folder': "" , 'delay_cost_exp': 1.0, 'area_cost_exp': 1.0, @@ -748,10 +764,10 @@ def load_hard_params(filename): 'generate_activity_file': False, 'core_site_name':'', 'mode_signal': [], + 'process_lib_paths': [], + 'process_params_file': "", } - - hard_file = open(filename, 'r') for line in hard_file: @@ -813,36 +829,12 @@ def load_hard_params(filename): hard_params['clock_pin_name'] = value elif param == 'clock_period': hard_params['clock_period'].append(value) - elif param == 'wire_selection': - hard_params['wire_selection'].append(value) elif param == 'core_utilization': hard_params['core_utilization'].append(value) - elif param == 'metal_layers': - hard_params['metal_layers'].append(value) - elif param == 'metal_layer_names': - hard_params['metal_layer_names'] += eval(value) - elif param == 'power_ring_metal_layer_names': - hard_params['power_ring_metal_layer_names'] += eval(value) elif param == 'map_file': hard_params['map_file'] = value.strip() - elif param == 'gnd_net': - hard_params['gnd_net'] = value.strip() - elif param == 'gnd_pin': - hard_params['gnd_pin'] = value.strip() - elif param == 'pwr_net': - hard_params['pwr_net'] = value.strip() - elif param == 'pwr_pin': - hard_params['pwr_pin'] = value.strip() elif param == 'tilehi_tielo_cells_between_power_gnd': hard_params['tilehi_tielo_cells_between_power_gnd'] = (value == "True") - elif param == 'inv_footprint': - hard_params['inv_footprint'] = value.strip() - elif param == 'buf_footprint': - hard_params['buf_footprint'] = value.strip() - elif param == 'delay_footprint': - hard_params['delay_footprint'] = value.strip() - elif param == 'filler_cell_names': - hard_params['filler_cell_names'] += eval(value) elif param == 'generate_activity_file': hard_params['generate_activity_file'] = (value == "True") elif param == 'crossbar_modelling': @@ -857,26 +849,12 @@ def load_hard_params(filename): hard_params['show_warnings'] = (value == "True") elif param == 'synthesis_only': hard_params['synthesis_only'] = (value == "True") - elif param == 'asic_flow_only': - hard_params['asic_flow_only'] = (value == "True") elif param == 'read_saif_file': hard_params['read_saif_file'] = (value == "True") elif param == 'static_probability': hard_params['static_probability'] = value elif param == 'toggle_rate': hard_params['toggle_rate'] = value - elif param == 'link_libraries': - hard_params['link_libraries'] = value - elif param == 'target_libraries': - hard_params['target_libraries'] = value - elif param == 'lef_files': - hard_params['lef_files'] = value - elif param == 'best_case_libs': - hard_params['best_case_libs'] = value - elif param == 'standard_libs': - hard_params['standard_libs'] = value - elif param == 'worst_case_libs': - hard_params['worst_case_libs'] = value elif param == 'power_ring_width': hard_params['power_ring_width'] = value elif param == 'power_ring_spacing': @@ -887,18 +865,122 @@ def load_hard_params(filename): hard_params['space_around_core'] = value elif param == 'pr_folder': hard_params['pr_folder'] = value - elif param == 'primetime_lib_path': - hard_params['primetime_lib_path'] = value - elif param == 'primetime_lib_name': - hard_params['primetime_lib_name'] = value elif param == 'primetime_folder': hard_params['primetime_folder'] = value - elif param == 'core_site_name': - hard_params['core_site_name'] = value elif param == 'mode_signal': hard_params['mode_signal'].append(value) - + elif param == "process_params_file": + hard_params["process_params_file"] = value + #To allow for the legacy way of inputting process specific params I'll keep these in (the only reason for having a seperate file is for understandability) + if param == "process_lib_paths": + hard_params["process_lib_paths"] = sanatize_str_input_to_list(value) + elif param == 'target_libraries': + hard_params['target_libraries'] = sanatize_str_input_to_list(value) + elif param == 'lef_files': + hard_params['lef_files'] = sanatize_str_input_to_list(value) + elif param == 'best_case_libs': + hard_params['best_case_libs'] = sanatize_str_input_to_list(value) + elif param == 'standard_libs': + hard_params['standard_libs'] = sanatize_str_input_to_list(value) + elif param == 'worst_case_libs': + hard_params['worst_case_libs'] = sanatize_str_input_to_list(value) + elif param == 'core_site_name': + hard_params['core_site_name'] = value + elif param == 'inv_footprint': + hard_params['inv_footprint'] = value.strip() + elif param == 'buf_footprint': + hard_params['buf_footprint'] = value.strip() + elif param == 'delay_footprint': + hard_params['delay_footprint'] = value.strip() + elif param == 'filler_cell_names': + hard_params['filler_cell_names'] += eval(value) + elif param == 'metal_layer_names': + hard_params['metal_layer_names'] += eval(value) + elif param == 'power_ring_metal_layer_names': + hard_params['power_ring_metal_layer_names'] += eval(value) + elif param == 'metal_layers': + hard_params['metal_layers'].append(value) + elif param == 'gnd_net': + hard_params['gnd_net'] = value.strip() + elif param == 'gnd_pin': + hard_params['gnd_pin'] = value.strip() + elif param == 'pwr_net': + hard_params['pwr_net'] = value.strip() + elif param == 'pwr_pin': + hard_params['pwr_pin'] = value.strip() + elif param == 'wire_selection': + hard_params['wire_selection'].append(value) + hard_file.close() + + if hard_params["process_params_file"] != "": + process_param_file = open(hard_params["process_params_file"],"r") + for line in process_param_file: + # Ignore comment lines + if line.startswith('#'): + continue + + # Remove line feeds and spaces + line = line.replace('\n', '') + line = line.replace('\r', '') + line = line.replace('\t', '') + + # Ignore empty lines + if line == "": + continue + + # Split lines at '=' + words = line.split('=') + if words[0] not in hard_params.keys(): + print("ERROR: Found invalid hard block parameter (" + words[0] + ") in " + filename) + sys.exit() + + param = words[0] + value = words[1] + if param == "process_lib_paths": + hard_params["process_lib_paths"] = sanatize_str_input_to_list(value) + elif param == 'target_libraries': + hard_params['target_libraries'] = sanatize_str_input_to_list(value) + elif param == 'lef_files': + hard_params['lef_files'] = sanatize_str_input_to_list(value) + elif param == 'best_case_libs': + hard_params['best_case_libs'] = sanatize_str_input_to_list(value) + elif param == 'standard_libs': + hard_params['standard_libs'] = sanatize_str_input_to_list(value) + elif param == 'worst_case_libs': + hard_params['worst_case_libs'] = sanatize_str_input_to_list(value) + elif param == 'core_site_name': + hard_params['core_site_name'] = value + elif param == 'inv_footprint': + hard_params['inv_footprint'] = value.strip() + elif param == 'buf_footprint': + hard_params['buf_footprint'] = value.strip() + elif param == 'delay_footprint': + hard_params['delay_footprint'] = value.strip() + elif param == 'filler_cell_names': + hard_params['filler_cell_names'] += eval(value) + elif param == 'metal_layer_names': + hard_params['metal_layer_names'] += eval(value) + elif param == 'power_ring_metal_layer_names': + hard_params['power_ring_metal_layer_names'] += eval(value) + elif param == 'metal_layers': + hard_params['metal_layers'].append(value) + elif param == 'gnd_net': + hard_params['gnd_net'] = value.strip() + elif param == 'gnd_pin': + hard_params['gnd_pin'] = value.strip() + elif param == 'pwr_net': + hard_params['pwr_net'] = value.strip() + elif param == 'pwr_pin': + hard_params['pwr_pin'] = value.strip() + elif param == 'wire_selection': + hard_params['wire_selection'].append(value) + + process_param_file.close() + #TODO make this more accessable outside of the code, but for now this is how I declare optional parameters + optional_params = ["process_params_file","mode_signal"] + check_hard_params(hard_params,optional_params) + return hard_params diff --git a/input_files/simple_dsp_slice_65nm/dsp_slice.txt b/input_files/simple_dsp_slice_65nm/dsp_slice.txt index d61b971..5d39244 100644 --- a/input_files/simple_dsp_slice_65nm/dsp_slice.txt +++ b/input_files/simple_dsp_slice_65nm/dsp_slice.txt @@ -18,6 +18,8 @@ design_language=verilog delay_cost_exp=1.0 area_cost_exp=1.0 +process_lib_paths="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" + ######################################## ########## Synthesis Settings ########## ######################################## @@ -26,7 +28,7 @@ area_cost_exp=1.0 clock_pin_name=clk # Desired clock period in ns -clock_period=3.0 +clock_period=1.82 # Name of the top-level entity in the design top_level=dsp_slice @@ -61,7 +63,7 @@ generate_activity_file=False # link_libraries="/home/projects/ljohn/aarora1/ceid/ceid_umc65ll/synopsys/ceid_vlsiLab_umc65ll_stdCells.db dw_foundation.sldb" # uncomment below for University of Toronto -link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db dw_foundation.sldb" +#link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.db dw_foundation.sldb" #target_libraries=/home/projects/ljohn/aarora1/FreePDK45/FreePDK45/osu_soc/lib/files/gscl45nm.db @@ -78,7 +80,7 @@ target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_En # Libraries required in EDI: #this can be a list of numbers -metal_layers=4 +metal_layers=6 #names of metal layers starting from the bottom-most layer on the left. use a python list format. @@ -86,7 +88,7 @@ metal_layers=4 #metal_layer_names=["ME1", "ME2", "ME3", "ME4"] # uncomment below for University of Toronto -metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6"] +metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "AP"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right @@ -202,8 +204,8 @@ pr_folder=~/COFFE/output_files/simple_dsp_slice_65nm/dsp_slice_pnr #primetime_lib_name=ceid_vlsiLab_umc65ll_stdCells.db # uncomment below for University of Toronto -primetime_lib_path="/CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" -primetime_lib_name=tcbn65gplustc.db +#primetime_lib_path="/CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" +#primetime_lib_name=tcbn65gplustc.db #the directory containing the primetime library and the name of the library file diff --git a/input_files/strtx_III_dsp/dsp_hb_settings.txt b/input_files/strtx_III_dsp/dsp_hb_settings.txt index 6a313c5..4684aab 100755 --- a/input_files/strtx_III_dsp/dsp_hb_settings.txt +++ b/input_files/strtx_III_dsp/dsp_hb_settings.txt @@ -14,6 +14,9 @@ design_language=verilog delay_cost_exp=1.0 area_cost_exp=1.0 +#ASIC flow settings +#path to absolute paths needed for process parameters (relative to coffe home repo) +process_params_file=input_files/strtx_III_dsp/process_specific_params.txt ######################################## ########## Synthesis Settings ########## @@ -21,7 +24,6 @@ area_cost_exp=1.0 # Name of the clock pin in the design clock_pin_name=clk -## -> this means that this was changed to run hspice on bastet # Desired clock period in ns ##clock_period=1.53 #clock_period=1.66 @@ -58,7 +60,7 @@ generate_activity_file=False # Location of the library files. # if you have more than one library, please provide them similiar to the example below. -link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" +#link_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" @@ -69,58 +71,59 @@ target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_En # Libraries required in EDI: #metal_layers=8 -metal_layers=7 +#metal_layers=7 #metal_layers=6 #metal_layers=5 #names of metal layers starting from the bottom-most layer on the left. use a python list format. -metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] +#metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right -power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] +#power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] #name of the file to use for layer mapping. used for stream out. #set it to None if you want the tool to create a generic map file map_file=streamOut.map + #wire_selection=WireAreaLowkCon -wire_selection=WireAreaLowkAgr +#wire_selection=WireAreaLowkAgr #wire_selection=WireAreaForZero #specify names of ground and power pins and nets in the library -gnd_net=VSS -gnd_pin=VSS -pwr_net=VDD -pwr_pin=VDD +#gnd_net=VSS +#gnd_pin=VSS +#pwr_net=VDD +#pwr_pin=VDD + tilehi_tielo_cells_between_power_gnd=True #specify footprint names for inverters, buffers, delays. #this is optional. you can get these values from the lib file. #you can also specify None, if you can't find them in the lib file. -inv_footprint=INVD0 -buf_footprint=BUFFD1 -delay_footprint=DEL0 +#inv_footprint=INVD0 +#buf_footprint=BUFFD1 +#delay_footprint=DEL0 #list of filler cell names. use a python list format. #the names can be obtained from .lib files. -filler_cell_names=["FILL1", "FILL16", "FILL1_LL", "FILL2", "FILL32", "FILL64", "FILL8", "FILL_NW_FA_LL", "FILL_NW_HH", "FILL_NW_LL"] +#filler_cell_names=["FILL1", "FILL16", "FILL1_LL", "FILL2", "FILL32", "FILL64", "FILL8", "FILL_NW_FA_LL", "FILL_NW_HH", "FILL_NW_LL"] #name of the core site in the floorplan. can be obtained from lef files. -core_site_name=core +#core_site_name=core #specify the utilization of the core site. you can specify multiple ones on different lines. -##core_utilization=0.85 +#core_utilization=0.85 core_utilization=0.90 -##core_utilization=0.95 - -lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_9lmT2.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/antenna_9lm.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/tpzn65gpgv2_9lm.lef" +#core_utilization=0.95 +#lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_9lmT2.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/antenna_9lm.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/tpzn65gpgv2_9lm.lef" -best_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2bc.lib" +#best_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2bc.lib" -standard_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.lib" +#standard_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.lib" -worst_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.lib" +#worst_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.lib" @@ -131,11 +134,9 @@ height_to_width_ratio=4.0 space_around_core=5 - # The folder in which place and route reports and post-routing netlists and spef files will be stored pr_folder=~/COFFE/output_files/strtx_III_dsp/pr - ############################################## ########## Prime Time Settings ############### ############################################## @@ -143,8 +144,6 @@ pr_folder=~/COFFE/output_files/strtx_III_dsp/pr mode_signal=mode_0 mode_signal=mode_1 -primetime_lib_path=". /CMC/tools/synopsys/syn_vN-2017.09/libraries/syn /CMC/tools/synopsys/syn_vN-2017.09/dw/syn_ver /CMC/tools/synopsys/syn_vN-2017.09/dw/sim_ver /CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" - primetime_folder=~/COFFE/output_files/strtx_III_dsp/pt # COFFE parameters: diff --git a/input_files/strtx_III_dsp/process_specific_params.txt b/input_files/strtx_III_dsp/process_specific_params.txt new file mode 100644 index 0000000..09018a6 --- /dev/null +++ b/input_files/strtx_III_dsp/process_specific_params.txt @@ -0,0 +1,62 @@ +#This file contains all parameters relevant to process technology, seperated due to inclusion of absolute paths and clarity + +############################################# +############# ASIC Flow Settings ############ +############################################# +process_lib_paths="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" + +# Standard cell libs which we are targeting for synthesis + +target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" + +############################################## +########## Place and Route Settings ########## +############################################## + +# Libraries required in EDI: + +#specify LEF files in the library. remember to specify the tech/header file first and then the file that has macros/cells. +lef_files="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Back_End/lef/tcbn65gplus_200a/lef/tcbn65gplus_9lmT2.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/antenna_9lm.lef /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Back_End/lef/tpzn65gpgv2_140c/mt_2/9lm/lef/tpzn65gpgv2_9lm.lef" + +#list names (full paths) of the .lib files for various corners +best_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplusbc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2bc.lib" +standard_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.lib" +worst_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.lib" + +#metal_layers=8 +metal_layers=7 +#metal_layers=6 +#metal_layers=5 + +#names of metal layers starting from the bottom-most layer on the left. use a python list format. +metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] + +#names of metal layers to use for each side of the power ring +#order: top, bottom, left, right +power_ring_metal_layer_names=["M1", "M1", "M2", "M2"] + +#specify wire load model (options found in library) + +#wire_selection=WireAreaLowkCon +wire_selection=WireAreaLowkAgr +#wire_selection=WireAreaForZero + +#specify names of ground and power pins and nets in the library +gnd_net=VSS +gnd_pin=VSS +pwr_net=VDD +pwr_pin=VDD + +#specify footprint names for inverters, buffers, delays. +#this is optional. you can get these values from the lib file. +#you can also specify None, if you can't find them in the lib file. +inv_footprint=INVD0 +buf_footprint=BUFFD1 +delay_footprint=DEL0 + +#list of filler cell names. use a python list format. +#the names can be obtained from .lib files. +filler_cell_names=["FILL1", "FILL16", "FILL1_LL", "FILL2", "FILL32", "FILL64", "FILL8", "FILL_NW_FA_LL", "FILL_NW_HH", "FILL_NW_LL"] + +#name of the core site in the floorplan. can be obtained from lef files. +core_site_name=core diff --git a/unit_test.sh b/unit_test.sh new file mode 100644 index 0000000..24cdc1f --- /dev/null +++ b/unit_test.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +#This is a unit test, which just makes sure that all stages of the COFFE flow runs, then tests the reporting/plotting utilities +py2=$(which python2) +py3=$(which python3) +if [ $py2 != "" ] || [ $py3 != "" ] +then + #run the coffe flow + python2 coffe.py -ho -i 1 input_files/strtx_III_dsp/dsp_coffe_params.txt + cd ./analyze_results + python3 condense_reports.py -r ../output_files/strtx_III_dsp/arch_out_dir + python3 plot_coffe_results.py -c report_csv_out/condensed_report.csv +else + echo "couldn't find python2 executable" +fi \ No newline at end of file From ebffb6249edfe24a00d1d7a6a22d8ee0e1c3a44a Mon Sep 17 00:00:00 2001 From: Stephen More Date: Tue, 18 Oct 2022 19:55:51 -0400 Subject: [PATCH 6/7] committed changes detailed in most recent edit of PR conversion --- coffe/hardblock_functions.py | 5 +++-- coffe/utils.py | 15 ++++++++++++++- input_files/strtx_III_dsp/dsp_hb_settings.txt | 11 ++++++----- .../strtx_III_dsp/process_specific_params.txt | 17 +++++++++++++++-- unit_test.sh | 4 ++-- 5 files changed, 40 insertions(+), 12 deletions(-) mode change 100644 => 100755 unit_test.sh diff --git a/coffe/hardblock_functions.py b/coffe/hardblock_functions.py index 48c76ee..1a0ef4b 100644 --- a/coffe/hardblock_functions.py +++ b/coffe/hardblock_functions.py @@ -352,7 +352,7 @@ def write_pt_power_script(flow_settings,mode_enabled,clock_period,x): file.write("set search_path " + flow_settings['search_path'] + " \n") file.write("set my_top_level " + flow_settings['top_level'] + "\n") file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_library'] + "\n") + file.write("set target_library " + flow_settings['primetime_libs'] + "\n") file.write("set link_library " + flow_settings['link_library'] + "\n") file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") file.write("link \n") @@ -387,7 +387,7 @@ def write_pt_timing_script(flow_settings,mode_enabled,clock_period,x): file.write("set search_path " + flow_settings['search_path'] + " \n") file.write("set my_top_level " + flow_settings['top_level'] + "\n") file.write("set my_clock_pin " + flow_settings['clock_pin_name'] + "\n") - file.write("set target_library " + flow_settings['target_library'] + "\n") + file.write("set target_library " + flow_settings['primetime_libs'] + "\n") file.write("set link_library " + flow_settings['link_library'] + "\n") file.write("read_verilog " + os.path.expanduser(flow_settings['pr_folder']) + "/netlist.v \n") if mode_enabled and x <2**len(flow_settings['mode_signal']): @@ -504,6 +504,7 @@ def flow_settings_pre_process(processed_flow_settings,cur_env): processed_flow_settings["best_case_libs"] = "\"" + " ".join(processed_flow_settings['best_case_libs']) + "\"" processed_flow_settings["standard_libs"] = "\"" + " ".join(processed_flow_settings['standard_libs']) + "\"" processed_flow_settings["worst_case_libs"] = "\"" + " ".join(processed_flow_settings['worst_case_libs']) + "\"" + processed_flow_settings["primetime_libs"] = "\"" + " ".join(processed_flow_settings['primetime_libs']) + "\"" # wire loads in the library are WireAreaLowkCon WireAreaLowkAgr WireAreaForZero def hardblock_flow(flow_settings): diff --git a/coffe/utils.py b/coffe/utils.py index b2640cc..50114c1 100644 --- a/coffe/utils.py +++ b/coffe/utils.py @@ -697,6 +697,9 @@ def check_hard_params(hard_params,optional_params): if ((val == "" or val == -1 or val == -1.0 or val == []) and key not in optional_params): print("param \"%s\" is unset, please go to your hardblock/process params file and set it" % (key)) sys.exit(1) + elif(key == "pnr_tool" and val != "encounter" and val != "innovus" ): + print("ERROR: pnr_tool must be set as either \"encounter\" or \"innovus\" ") + sys.exit(1) def load_hard_params(filename): """ Parse the hard block description file and load values into dictionary. @@ -743,7 +746,7 @@ def load_hard_params(filename): 'space_around_core': -1, 'pr_folder': "", #'primetime_lib_path': '', - #'primetime_lib_name': '', + 'primetime_libs': [], 'primetime_folder': "" , 'delay_cost_exp': 1.0, 'area_cost_exp': 1.0, @@ -766,6 +769,8 @@ def load_hard_params(filename): 'mode_signal': [], 'process_lib_paths': [], 'process_params_file': "", + #'pnr_tool': "", + #'process_size': "", } hard_file = open(filename, 'r') @@ -871,9 +876,15 @@ def load_hard_params(filename): hard_params['mode_signal'].append(value) elif param == "process_params_file": hard_params["process_params_file"] = value + # elif param == "pnr_tool": + # hard_params["pnr_tool"] = value + # elif param == "process_size": + # hard_params["process_size"] = value #To allow for the legacy way of inputting process specific params I'll keep these in (the only reason for having a seperate file is for understandability) if param == "process_lib_paths": hard_params["process_lib_paths"] = sanatize_str_input_to_list(value) + elif param == "primetime_libs": + hard_params["primetime_libs"] = sanatize_str_input_to_list(value) elif param == 'target_libraries': hard_params['target_libraries'] = sanatize_str_input_to_list(value) elif param == 'lef_files': @@ -975,6 +986,8 @@ def load_hard_params(filename): hard_params['pwr_pin'] = value.strip() elif param == 'wire_selection': hard_params['wire_selection'].append(value) + elif param == "primetime_libs": + hard_params["primetime_libs"] = sanatize_str_input_to_list(value) process_param_file.close() #TODO make this more accessable outside of the code, but for now this is how I declare optional parameters diff --git a/input_files/strtx_III_dsp/dsp_hb_settings.txt b/input_files/strtx_III_dsp/dsp_hb_settings.txt index 4684aab..aed3bde 100755 --- a/input_files/strtx_III_dsp/dsp_hb_settings.txt +++ b/input_files/strtx_III_dsp/dsp_hb_settings.txt @@ -25,7 +25,7 @@ process_params_file=input_files/strtx_III_dsp/process_specific_params.txt # Name of the clock pin in the design clock_pin_name=clk # Desired clock period in ns -##clock_period=1.53 +#clock_period=1.53 #clock_period=1.66 #clock_period=1.81 clock_period=2.0 @@ -70,13 +70,14 @@ target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_En # Libraries required in EDI: +#metal_layers=9 #metal_layers=8 #metal_layers=7 #metal_layers=6 #metal_layers=5 #names of metal layers starting from the bottom-most layer on the left. use a python list format. -#metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] +#metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9","AP"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right @@ -132,7 +133,7 @@ power_ring_width=3 power_ring_spacing=3 height_to_width_ratio=4.0 -space_around_core=5 +space_around_core=10 # The folder in which place and route reports and post-routing netlists and spef files will be stored pr_folder=~/COFFE/output_files/strtx_III_dsp/pr @@ -141,8 +142,8 @@ pr_folder=~/COFFE/output_files/strtx_III_dsp/pr ########## Prime Time Settings ############### ############################################## -mode_signal=mode_0 -mode_signal=mode_1 +#mode_signal=mode_0 +#mode_signal=mode_1 primetime_folder=~/COFFE/output_files/strtx_III_dsp/pt diff --git a/input_files/strtx_III_dsp/process_specific_params.txt b/input_files/strtx_III_dsp/process_specific_params.txt index 09018a6..d624ad2 100644 --- a/input_files/strtx_III_dsp/process_specific_params.txt +++ b/input_files/strtx_III_dsp/process_specific_params.txt @@ -3,10 +3,15 @@ ############################################# ############# ASIC Flow Settings ############ ############################################# +#node size of process in nm +#process_size=65 + process_lib_paths="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c" +######################################## +########## Synthesis Settings ########## +######################################## # Standard cell libs which we are targeting for synthesis - target_libraries="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.db /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.db" ############################################## @@ -23,13 +28,14 @@ best_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/ standard_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gplustc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2tc.lib" worst_case_libs="/CMC/kits/tsmc_65nm_libs/tcbn65gplus/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tcbn65gplus_140b/tcbn65gpluswc.lib /CMC/kits/tsmc_65nm_libs/tpzn65gpgv2/TSMCHOME/digital/Front_End/timing_power_noise/NLDM/tpzn65gpgv2_140c/tpzn65gpgv2wc.lib" + #metal_layers=8 metal_layers=7 #metal_layers=6 #metal_layers=5 #names of metal layers starting from the bottom-most layer on the left. use a python list format. -metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "AP"] +metal_layer_names=["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "AP"] #names of metal layers to use for each side of the power ring #order: top, bottom, left, right @@ -60,3 +66,10 @@ filler_cell_names=["FILL1", "FILL16", "FILL1_LL", "FILL2", "FILL32", "FILL64", " #name of the core site in the floorplan. can be obtained from lef files. core_site_name=core + + +############################################## +############## Power & Timing ################ +############################################## + +primetime_libs="tcbn65gpluswc.db tpzn65gpgv2wc.db" \ No newline at end of file diff --git a/unit_test.sh b/unit_test.sh old mode 100644 new mode 100755 index 24cdc1f..a6900c4 --- a/unit_test.sh +++ b/unit_test.sh @@ -5,8 +5,8 @@ py2=$(which python2) py3=$(which python3) if [ $py2 != "" ] || [ $py3 != "" ] then - #run the coffe flow - python2 coffe.py -ho -i 1 input_files/strtx_III_dsp/dsp_coffe_params.txt + #run the coffe flow, hardblock and full custom + python2 coffe.py -i 1 input_files/strtx_III_dsp/dsp_coffe_params.txt cd ./analyze_results python3 condense_reports.py -r ../output_files/strtx_III_dsp/arch_out_dir python3 plot_coffe_results.py -c report_csv_out/condensed_report.csv From 522361206938eff56b31d02b966d81afdd345a7c Mon Sep 17 00:00:00 2001 From: Stephen More Date: Tue, 18 Oct 2022 20:11:25 -0400 Subject: [PATCH 7/7] added mentioned results to PR --- .../results_archive/condensed_report.csv | 211 +++++++++++++++++ .../results_archive/fig_archives/area_fig.png | Bin 0 -> 26891 bytes .../results_archive/fig_archives/cost_fig.png | Bin 0 -> 36614 bytes .../fig_archives/delay_fig.png | Bin 0 -> 24684 bytes .../fig_archives/power_fig.png | Bin 0 -> 26602 bytes .../final_full_custom_flow_report.txt | 220 ++++++++++++++++++ 6 files changed, 431 insertions(+) create mode 100644 analyze_results/results_archive/condensed_report.csv create mode 100644 analyze_results/results_archive/fig_archives/area_fig.png create mode 100644 analyze_results/results_archive/fig_archives/cost_fig.png create mode 100644 analyze_results/results_archive/fig_archives/delay_fig.png create mode 100644 analyze_results/results_archive/fig_archives/power_fig.png create mode 100644 analyze_results/results_archive/final_full_custom_flow_report.txt diff --git a/analyze_results/results_archive/condensed_report.csv b/analyze_results/results_archive/condensed_report.csv new file mode 100644 index 0000000..71b21e4 --- /dev/null +++ b/analyze_results/results_archive/condensed_report.csv @@ -0,0 +1,211 @@ +delay,wire_model,power,mode,metal_layers,utilization,top_level_mod,area,period +1.96,WireAreaLowkAgr,0.0365025,mode0,8,0.85,dsp,45358.020,2.0 +2.43,WireAreaLowkAgr,0.0299125,mode1,7,0.85,dsp,43101.540,2.5 +1.54,WireAreaLowkAgr,0.0517575,mode1,7,0.90,dsp,54244.242,1.53 +2.48,WireAreaLowkAgr,0.0291045,mode2,5,0.85,dsp,43101.540,2.5 +1.97,WireAreaLowkAgr,0.0365191,mode0,7,0.85,dsp,45358.020,2.0 +1.96,WireAreaLowkAgr,0.0371464,mode3,5,0.85,dsp,45358.020,2.0 +1.54,WireAreaLowkAgr,0.0518646,mode1,8,0.90,dsp,54244.242,1.53 +2.43,WireAreaLowkAgr,0.0298639,mode1,8,0.85,dsp,43101.540,2.5 +1.82,WireAreaLowkAgr,0.0421164,mode1,8,0.90,dsp,45627.003,1.81 +1.96,WireAreaLowkAgr,0.0373565,mode1,7,0.95,dsp,40583.547,2.0 +1.97,WireAreaLowkAgr,0.0363421,mode2,5,0.95,dsp,40583.547,2.0 +2.5,WireAreaLowkAgr,0.0295935,mode0,8,0.95,dsp,38565.072,2.5 +1.95,WireAreaLowkAgr,0.0373582,mode1,8,0.95,dsp,40583.547,2.0 +2.49,WireAreaLowkAgr,0.0295947,mode0,7,0.95,dsp,38565.072,2.5 +2.4,WireAreaLowkAgr,0.0301979,mode3,5,0.95,dsp,38565.072,2.5 +1.54,WireAreaLowkAgr,0.0510703,mode3,8,0.95,dsp,51389.991,1.53 +1.56,WireAreaLowkAgr,0.051137,mode3,7,0.95,dsp,51389.991,1.53 +2.49,WireAreaLowkAgr,0.0297807,none,5,0.90,dsp,40707.072,2.5 +2.49,WireAreaLowkAgr,0.0301064,none,7,0.95,dsp,38565.072,2.5 +2.5,WireAreaLowkAgr,0.0301082,none,8,0.95,dsp,38565.072,2.5 +1.97,WireAreaLowkAgr,0.0372526,none,7,0.85,dsp,45358.020,2.0 +1.96,WireAreaLowkAgr,0.0372499,none,8,0.85,dsp,45358.020,2.0 +1.55,WireAreaLowkAgr,0.0510934,mode0,6,0.85,dsp,57436.848,1.53 +1.57,WireAreaLowkAgr,0.051609,mode1,5,0.95,dsp,51389.991,1.53 +2.49,WireAreaLowkAgr,0.0291751,mode0,5,0.90,dsp,40707.072,2.5 +2.44,WireAreaLowkAgr,0.0296334,mode3,7,0.90,dsp,40707.072,2.5 +1.97,WireAreaLowkAgr,0.0363523,mode2,8,0.90,dsp,42837.885,2.0 +2.44,WireAreaLowkAgr,0.029614,mode3,8,0.90,dsp,40707.072,2.5 +1.96,WireAreaLowkAgr,0.0375534,mode1,5,0.90,dsp,45358.020,2.0 +1.97,WireAreaLowkAgr,0.0363483,mode2,7,0.90,dsp,42837.885,2.0 +1.81,WireAreaLowkAgr,0.0419168,mode3,5,0.90,dsp,45627.003,1.81 +1.52,WireAreaLowkAgr,0.0512255,mode3,5,0.90,dsp,54244.242,1.53 +1.99,WireAreaLowkAgr,0.0370469,none,6,0.95,dsp,40583.547,2.0 +1.6,WireAreaLowkAgr,0.0503564,none,5,0.95,dsp,51389.991,1.53 +2.48,WireAreaLowkAgr,0.029674,none,6,0.85,dsp,43101.540,2.5 +1.6,WireAreaLowkAgr,0.0503613,mode0,7,0.95,dsp,51389.991,1.53 +1.98,WireAreaLowkAgr,0.0370397,mode3,6,0.90,dsp,42837.885,2.0 +2.46,WireAreaLowkAgr,0.0291146,mode2,6,0.90,dsp,40707.072,2.5 +1.61,WireAreaLowkAgr,0.0502925,mode0,8,0.95,dsp,51389.991,1.53 +1.51,WireAreaLowkAgr,0.0505149,mode2,8,0.90,dsp,54244.242,1.53 +1.81,WireAreaLowkAgr,0.0409926,mode2,8,0.90,dsp,45627.003,1.81 +1.54,WireAreaLowkAgr,0.0504273,mode2,7,0.90,dsp,54244.242,1.53 +1.97,WireAreaLowkAgr,0.0374628,mode1,6,0.85,dsp,45358.020,2.0 +2.48,WireAreaLowkAgr,0.0291131,mode0,6,0.85,dsp,43101.540,2.5 +2.46,WireAreaLowkAgr,0.0303835,mode1,6,0.95,dsp,38565.072,2.5 +1.99,WireAreaLowkAgr,0.0363469,mode0,6,0.95,dsp,40583.547,2.0 +1.85,WireAreaLowkAgr,0.0412924,mode0,5,0.90,dsp,45627.003,1.81 +1.58,WireAreaLowkAgr,0.0504908,mode0,5,0.90,dsp,54244.242,1.53 +1.58,WireAreaLowkAgr,0.0502381,mode2,5,0.95,dsp,51389.991,1.53 +1.52,WireAreaLowkAgr,0.0517303,mode3,6,0.85,dsp,57436.848,1.53 +1.85,WireAreaLowkAgr,0.0410574,none,8,0.90,dsp,45627.003,1.81 +1.59,WireAreaLowkAgr,0.0506271,none,8,0.90,dsp,54244.242,1.53 +1.57,WireAreaLowkAgr,0.0505446,none,7,0.90,dsp,54244.242,1.53 +1.98,WireAreaLowkAgr,0.0371744,none,6,0.85,dsp,45358.020,2.0 +1.55,WireAreaLowkAgr,0.0512166,none,5,0.85,dsp,57436.848,1.53 +2.49,WireAreaLowkAgr,0.0301021,none,6,0.95,dsp,38565.072,2.5 +1.69,WireAreaLowkAgr,0.045987,none,5,0.90,dsp,48331.764,1.66 +1.98,WireAreaLowkAgr,0.0364487,mode2,6,0.90,dsp,42837.885,2.0 +2.43,WireAreaLowkAgr,0.0295903,mode3,6,0.90,dsp,40707.072,2.5 +1.55,WireAreaLowkAgr,0.0512508,mode0,8,0.85,dsp,57436.848,1.53 +1.55,WireAreaLowkAgr,0.0511243,mode0,7,0.85,dsp,57436.848,1.53 +2.17,WireAreaLowkAgr,0.0321567,mode2,5,0.90,dsp,41936.661,2.22 +1.71,WireAreaLowkAgr,0.0460939,mode0,8,0.90,dsp,48331.764,1.66 +2.49,WireAreaLowkAgr,0.0295837,mode0,6,0.95,dsp,38565.072,2.5 +1.98,WireAreaLowkAgr,0.037355,mode1,6,0.95,dsp,40583.547,2.0 +1.98,WireAreaLowkAgr,0.036455,mode0,6,0.85,dsp,45358.020,2.0 +1.64,WireAreaLowkAgr,0.0458925,mode2,5,0.90,dsp,48331.764,1.66 +1.55,WireAreaLowkAgr,0.0517896,mode1,6,0.90,dsp,54244.242,1.53 +2.45,WireAreaLowkAgr,0.0298967,mode1,6,0.85,dsp,43101.540,2.5 +1.56,WireAreaLowkAgr,0.0511442,mode3,6,0.95,dsp,51389.991,1.53 +2.19,WireAreaLowkAgr,0.0321895,mode0,8,0.90,dsp,41936.661,2.22 +1.51,WireAreaLowkAgr,0.0510716,mode2,5,0.85,dsp,57436.848,1.53 +2.2,WireAreaLowkAgr,0.0328243,none,5,0.90,dsp,41936.661,2.22 +2.46,WireAreaLowkAgr,0.0303981,mode1,8,0.95,dsp,38565.072,2.5 +1.99,WireAreaLowkAgr,0.0363567,mode0,7,0.95,dsp,40583.547,2.0 +1.97,WireAreaLowkAgr,0.0369377,mode3,5,0.95,dsp,40583.547,2.0 +2.48,WireAreaLowkAgr,0.0303957,mode1,7,0.95,dsp,38565.072,2.5 +1.65,WireAreaLowkAgr,0.0467966,mode3,8,0.90,dsp,48331.764,1.66 +2.4,WireAreaLowkAgr,0.0297153,mode2,5,0.95,dsp,38565.072,2.5 +1.99,WireAreaLowkAgr,0.036357,mode0,8,0.95,dsp,40583.547,2.0 +2.47,WireAreaLowkAgr,0.0291263,mode0,7,0.85,dsp,43101.540,2.5 +2.41,WireAreaLowkAgr,0.0295738,mode3,5,0.85,dsp,43101.540,2.5 +1.96,WireAreaLowkAgr,0.0375062,mode1,8,0.85,dsp,45358.020,2.0 +2.49,WireAreaLowkAgr,0.0290775,mode0,8,0.85,dsp,43101.540,2.5 +1.93,WireAreaLowkAgr,0.0375269,mode1,7,0.85,dsp,45358.020,2.0 +1.96,WireAreaLowkAgr,0.0365478,mode2,5,0.85,dsp,45358.020,2.0 +2.17,WireAreaLowkAgr,0.0330415,mode1,5,0.90,dsp,41936.661,2.22 +1.5,WireAreaLowkAgr,0.0517252,mode3,7,0.85,dsp,57436.848,1.53 +1.51,WireAreaLowkAgr,0.0518918,mode3,8,0.85,dsp,57436.848,1.53 +1.59,WireAreaLowkAgr,0.0505731,none,6,0.90,dsp,54244.242,1.53 +2.0,WireAreaLowkAgr,0.0373043,none,5,0.90,dsp,45358.020,2.0 +2.49,WireAreaLowkAgr,0.0296377,none,8,0.85,dsp,43101.540,2.5 +2.47,WireAreaLowkAgr,0.0296868,none,7,0.85,dsp,43101.540,2.5 +1.99,WireAreaLowkAgr,0.0370461,none,8,0.95,dsp,40583.547,2.0 +1.99,WireAreaLowkAgr,0.0370532,none,7,0.95,dsp,40583.547,2.0 +1.94,WireAreaLowkAgr,0.0369404,mode3,8,0.90,dsp,42837.885,2.0 +2.45,WireAreaLowkAgr,0.0299703,mode1,5,0.90,dsp,40707.072,2.5 +1.5,WireAreaLowkAgr,0.0524305,mode1,5,0.85,dsp,57436.848,1.53 +2.46,WireAreaLowkAgr,0.029159,mode2,7,0.90,dsp,40707.072,2.5 +2.0,WireAreaLowkAgr,0.0365472,mode0,5,0.90,dsp,45358.020,2.0 +1.97,WireAreaLowkAgr,0.0369374,mode3,7,0.90,dsp,42837.885,2.0 +2.17,WireAreaLowkAgr,0.0327108,mode3,8,0.90,dsp,41936.661,2.22 +1.6,WireAreaLowkAgr,0.0503668,mode0,6,0.95,dsp,51389.991,1.53 +2.48,WireAreaLowkAgr,0.0291368,mode2,8,0.90,dsp,40707.072,2.5 +1.63,WireAreaLowkAgr,0.0470838,mode1,5,0.90,dsp,48331.764,1.66 +1.54,WireAreaLowkAgr,0.0504489,mode2,6,0.90,dsp,54244.242,1.53 +1.61,WireAreaLowkAgr,0.0503802,none,8,0.95,dsp,51389.991,1.53 +1.6,WireAreaLowkAgr,0.0504482,none,7,0.95,dsp,51389.991,1.53 +1.81,WireAreaLowkAgr,0.0412662,mode2,5,0.90,dsp,45627.003,1.81 +1.52,WireAreaLowkAgr,0.0504615,mode2,5,0.90,dsp,54244.242,1.53 +1.51,WireAreaLowkAgr,0.0523058,mode1,6,0.85,dsp,57436.848,1.53 +2.43,WireAreaLowkAgr,0.0299144,mode1,6,0.90,dsp,40707.072,2.5 +1.99,WireAreaLowkAgr,0.0364457,mode0,6,0.90,dsp,42837.885,2.0 +1.6,WireAreaLowkAgr,0.0502463,mode0,5,0.95,dsp,51389.991,1.53 +1.54,WireAreaLowkAgr,0.0502788,mode2,8,0.95,dsp,51389.991,1.53 +1.56,WireAreaLowkAgr,0.0503458,mode2,7,0.95,dsp,51389.991,1.53 +1.57,WireAreaLowkAgr,0.0504502,mode0,7,0.90,dsp,54244.242,1.53 +1.98,WireAreaLowkAgr,0.0369409,mode3,6,0.95,dsp,40583.547,2.0 +1.59,WireAreaLowkAgr,0.0505485,mode0,8,0.90,dsp,54244.242,1.53 +2.49,WireAreaLowkAgr,0.029579,mode2,6,0.95,dsp,38565.072,2.5 +1.85,WireAreaLowkAgr,0.0410243,mode0,8,0.90,dsp,45627.003,1.81 +2.45,WireAreaLowkAgr,0.0295732,mode3,6,0.85,dsp,43101.540,2.5 +1.98,WireAreaLowkAgr,0.0364537,mode2,6,0.85,dsp,45358.020,2.0 +1.58,WireAreaLowkAgr,0.0505759,none,5,0.90,dsp,54244.242,1.53 +1.85,WireAreaLowkAgr,0.0413302,none,5,0.90,dsp,45627.003,1.81 +1.99,WireAreaLowkAgr,0.0371539,none,6,0.90,dsp,42837.885,2.0 +1.58,WireAreaLowkAgr,0.0510244,mode3,5,0.95,dsp,51389.991,1.53 +1.52,WireAreaLowkAgr,0.0509735,mode2,6,0.85,dsp,57436.848,1.53 +2.48,WireAreaLowkAgr,0.0300661,mode3,7,0.95,dsp,38565.072,2.5 +2.48,WireAreaLowkAgr,0.0297115,mode0,5,0.95,dsp,38565.072,2.5 +1.97,WireAreaLowkAgr,0.0363503,mode2,8,0.95,dsp,40583.547,2.0 +2.46,WireAreaLowkAgr,0.0300664,mode3,8,0.95,dsp,38565.072,2.5 +1.97,WireAreaLowkAgr,0.0363542,mode2,7,0.95,dsp,40583.547,2.0 +1.97,WireAreaLowkAgr,0.0373457,mode1,5,0.95,dsp,40583.547,2.0 +2.48,WireAreaLowkAgr,0.0290715,mode2,8,0.85,dsp,43101.540,2.5 +1.93,WireAreaLowkAgr,0.0371141,mode3,7,0.85,dsp,45358.020,2.0 +2.0,WireAreaLowkAgr,0.0365472,mode0,5,0.85,dsp,45358.020,2.0 +1.79,WireAreaLowkAgr,0.0423824,mode1,5,0.90,dsp,45627.003,1.81 +2.47,WireAreaLowkAgr,0.0291169,mode2,7,0.85,dsp,43101.540,2.5 +2.41,WireAreaLowkAgr,0.0299025,mode1,5,0.85,dsp,43101.540,2.5 +1.55,WireAreaLowkAgr,0.0518046,mode1,5,0.90,dsp,54244.242,1.53 +1.96,WireAreaLowkAgr,0.0370939,mode3,8,0.85,dsp,45358.020,2.0 +2.49,WireAreaLowkAgr,0.0297566,none,7,0.90,dsp,40707.072,2.5 +2.49,WireAreaLowkAgr,0.0297386,none,8,0.90,dsp,40707.072,2.5 +2.0,WireAreaLowkAgr,0.0373043,none,5,0.85,dsp,45358.020,2.0 +1.55,WireAreaLowkAgr,0.0511177,none,6,0.85,dsp,57436.848,1.53 +2.48,WireAreaLowkAgr,0.030242,none,5,0.95,dsp,38565.072,2.5 +1.51,WireAreaLowkAgr,0.0512787,mode3,8,0.90,dsp,54244.242,1.53 +1.81,WireAreaLowkAgr,0.0416461,mode3,8,0.90,dsp,45627.003,1.81 +1.54,WireAreaLowkAgr,0.0511857,mode3,7,0.90,dsp,54244.242,1.53 +1.96,WireAreaLowkAgr,0.0365478,mode2,5,0.90,dsp,45358.020,2.0 +1.97,WireAreaLowkAgr,0.0373471,mode1,7,0.90,dsp,42837.885,2.0 +2.49,WireAreaLowkAgr,0.0291461,mode0,8,0.90,dsp,40707.072,2.5 +1.94,WireAreaLowkAgr,0.0373501,mode1,8,0.90,dsp,42837.885,2.0 +2.45,WireAreaLowkAgr,0.0296446,mode3,5,0.90,dsp,40707.072,2.5 +2.49,WireAreaLowkAgr,0.029166,mode0,7,0.90,dsp,40707.072,2.5 +1.57,WireAreaLowkAgr,0.0517309,mode1,7,0.95,dsp,51389.991,1.53 +1.57,WireAreaLowkAgr,0.0516606,mode1,8,0.95,dsp,51389.991,1.53 +2.17,WireAreaLowkAgr,0.0330662,mode1,8,0.90,dsp,41936.661,2.22 +1.56,WireAreaLowkAgr,0.0503494,mode2,6,0.95,dsp,51389.991,1.53 +1.51,WireAreaLowkAgr,0.0518349,mode3,5,0.85,dsp,57436.848,1.53 +1.97,WireAreaLowkAgr,0.0365183,mode2,7,0.85,dsp,45358.020,2.0 +1.96,WireAreaLowkAgr,0.0375534,mode1,5,0.85,dsp,45358.020,2.0 +2.43,WireAreaLowkAgr,0.0295375,mode3,8,0.85,dsp,43101.540,2.5 +1.96,WireAreaLowkAgr,0.0364995,mode2,8,0.85,dsp,45358.020,2.0 +2.43,WireAreaLowkAgr,0.0295862,mode3,7,0.85,dsp,43101.540,2.5 +2.48,WireAreaLowkAgr,0.0291135,mode0,5,0.85,dsp,43101.540,2.5 +1.95,WireAreaLowkAgr,0.0369466,mode3,8,0.95,dsp,40583.547,2.0 +2.48,WireAreaLowkAgr,0.0295886,mode2,7,0.95,dsp,38565.072,2.5 +2.4,WireAreaLowkAgr,0.0305283,mode1,5,0.95,dsp,38565.072,2.5 +1.96,WireAreaLowkAgr,0.0369503,mode3,7,0.95,dsp,40583.547,2.0 +1.99,WireAreaLowkAgr,0.0363429,mode0,5,0.95,dsp,40583.547,2.0 +2.49,WireAreaLowkAgr,0.0295873,mode2,8,0.95,dsp,38565.072,2.5 +1.64,WireAreaLowkAgr,0.0466126,mode3,5,0.90,dsp,48331.764,1.66 +1.59,WireAreaLowkAgr,0.0504824,mode0,6,0.90,dsp,54244.242,1.53 +1.97,WireAreaLowkAgr,0.0370519,none,8,0.90,dsp,42837.885,2.0 +1.98,WireAreaLowkAgr,0.0370479,none,7,0.90,dsp,42837.885,2.0 +1.99,WireAreaLowkAgr,0.0370372,none,5,0.95,dsp,40583.547,2.0 +1.6,WireAreaLowkAgr,0.0504607,none,6,0.95,dsp,51389.991,1.53 +2.48,WireAreaLowkAgr,0.0296881,none,5,0.85,dsp,43101.540,2.5 +1.66,WireAreaLowkAgr,0.0472617,mode1,8,0.90,dsp,48331.764,1.66 +1.52,WireAreaLowkAgr,0.0524762,mode1,8,0.85,dsp,57436.848,1.53 +2.44,WireAreaLowkAgr,0.0299422,mode1,8,0.90,dsp,40707.072,2.5 +1.96,WireAreaLowkAgr,0.0371464,mode3,5,0.90,dsp,45358.020,2.0 +1.98,WireAreaLowkAgr,0.0363501,mode0,7,0.90,dsp,42837.885,2.0 +2.47,WireAreaLowkAgr,0.0291681,mode2,5,0.90,dsp,40707.072,2.5 +2.44,WireAreaLowkAgr,0.0299586,mode1,7,0.90,dsp,40707.072,2.5 +2.17,WireAreaLowkAgr,0.0326891,mode3,5,0.90,dsp,41936.661,2.22 +1.51,WireAreaLowkAgr,0.0523326,mode1,7,0.85,dsp,57436.848,1.53 +1.97,WireAreaLowkAgr,0.0363608,mode0,8,0.90,dsp,42837.885,2.0 +1.71,WireAreaLowkAgr,0.0461666,none,8,0.90,dsp,48331.764,1.66 +1.55,WireAreaLowkAgr,0.0510625,none,7,0.85,dsp,57436.848,1.53 +1.55,WireAreaLowkAgr,0.0512834,none,8,0.85,dsp,57436.848,1.53 +1.69,WireAreaLowkAgr,0.0459201,mode0,5,0.90,dsp,48331.764,1.66 +1.54,WireAreaLowkAgr,0.0512172,mode3,6,0.90,dsp,54244.242,1.53 +1.55,WireAreaLowkAgr,0.0512399,mode0,5,0.85,dsp,57436.848,1.53 +1.57,WireAreaLowkAgr,0.0517429,mode1,6,0.95,dsp,51389.991,1.53 +2.17,WireAreaLowkAgr,0.03218,mode2,8,0.90,dsp,41936.661,2.22 +2.48,WireAreaLowkAgr,0.0291217,mode0,6,0.90,dsp,40707.072,2.5 +1.98,WireAreaLowkAgr,0.0374454,mode1,6,0.90,dsp,42837.885,2.0 +1.5,WireAreaLowkAgr,0.0509715,mode2,7,0.85,dsp,57436.848,1.53 +2.2,WireAreaLowkAgr,0.032165,mode0,5,0.90,dsp,41936.661,2.22 +1.51,WireAreaLowkAgr,0.051133,mode2,8,0.85,dsp,57436.848,1.53 +2.48,WireAreaLowkAgr,0.0291045,mode2,6,0.85,dsp,43101.540,2.5 +1.97,WireAreaLowkAgr,0.0370525,mode3,6,0.85,dsp,45358.020,2.0 +1.65,WireAreaLowkAgr,0.0460727,mode2,8,0.90,dsp,48331.764,1.66 +1.98,WireAreaLowkAgr,0.0363406,mode2,6,0.95,dsp,40583.547,2.0 +2.46,WireAreaLowkAgr,0.0300588,mode3,6,0.95,dsp,38565.072,2.5 +2.19,WireAreaLowkAgr,0.0328403,none,8,0.90,dsp,41936.661,2.22 +2.48,WireAreaLowkAgr,0.0297067,none,6,0.90,dsp,40707.072,2.5 diff --git a/analyze_results/results_archive/fig_archives/area_fig.png b/analyze_results/results_archive/fig_archives/area_fig.png new file mode 100644 index 0000000000000000000000000000000000000000..e44a9aa4cb08e75fdcbfe3f1a7b28d8a0e33d652 GIT binary patch literal 26891 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 MCT_iLUCQrY0r)a#ng9R* literal 0 HcmV?d00001 diff --git a/analyze_results/results_archive/fig_archives/power_fig.png b/analyze_results/results_archive/fig_archives/power_fig.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5d9ddd323366af75125bddf34a730df926adae GIT binary patch literal 26602 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 literal 0 HcmV?d00001 diff --git a/analyze_results/results_archive/final_full_custom_flow_report.txt b/analyze_results/results_archive/final_full_custom_flow_report.txt new file mode 100644 index 0000000..d7e4065 --- /dev/null +++ b/analyze_results/results_archive/final_full_custom_flow_report.txt @@ -0,0 +1,220 @@ +Created 2022-10-12 23:43:42.670014 + +---------------------------------------------- + RUN OPTIONS: +---------------------------------------------- + + Transistor sizing: on + Optimization type: global + Number of top combos to re-ERF: 1 + Area optimization weight: 1 + Delay optimization weight: 1 + Maximum number of sizing iterations: 1 + + +------------------------------------------------- + ARCHITECTURE PARAMETERS: +------------------------------------------------- + + Number of BLEs per cluster (N): 10 + LUT size (K): 6 + Channel width (W): 320 + Wire segment length (L): 4 + Number of cluster inputs (I): 40 + Number of BLE outputs to general routing (Or): 2 + Number of BLE outputs to local routing (Ofb): 1 + Total number of cluster outputs (N*Or): 20 + Switch block flexibility (Fs): 3 + Cluster input flexibility (Fcin): 0.2 + Cluster output flexibility (Fcout): 0.025 + Local MUX population (Fclocal): 0.5 + LUT input for register selection MUX (Rsel): c + LUT input(s) for register feedback MUX(es) (Rfb): c + +------------------------------------------------- + PROCESS TECHNOLOGY PARAMETERS: +------------------------------------------------- + + transistor_type = bulk + switch_type = pass_transistor + vdd = 0.8 + vsram = 1.0 + vsram_n = 0.0 + gate_length = 22 + min_tran_width = 45 + min_width_tran_area = 33864 + sram_cell_area = 4.0 + model_path = /autofs/fs1.ece/fs1.eecg.vaughn/morestep/COFFE/spice_models/ptm_22nm_bulk_hp.l + model_library = 22NM_BULK_HP + metal = [(0.054825, 0.000175), (0.007862, 0.000215), (0.02924, 0.000139), (0.227273, 0.0)] + + +|------------------------------------------------------------------------------| +| FPGA Implementation Details | +|------------------------------------------------------------------------------| + + SWITCH BLOCK DETAILS: + Style: two-level MUX + Required MUX size: 10:1 + Implemented MUX size: 12:1 + Level 1 size = 4 + Level 2 size = 3 + Number of unused inputs = 2 + Number of MUXes per tile: 160 + Number of SRAM cells per MUX: 7 + + CONNECTION BLOCK DETAILS: + Style: two-level MUX + Required MUX size: 64:1 + Implemented MUX size: 64:1 + Level 1 size = 8 + Level 2 size = 8 + Number of unused inputs = 0 + Number of MUXes per tile: 40 + Number of SRAM cells per MUX: 16 + + LOCAL MUX DETAILS: + Style: two-level MUX + Required MUX size: 25:1 + Implemented MUX size: 25:1 + Level 1 size = 5 + Level 2 size = 5 + Number of unused inputs = 0 + Number of MUXes per tile: 60 + Number of SRAM cells per MUX: 10 + + LUT DETAILS: + Style: Fully encoded MUX tree + Size: 6-LUT + Internal buffering: 2-stage buffer betweens levels 3 and 4 + Isolation inverters between SRAM and LUT inputs + + LUT INPUT DRIVER DETAILS: + LUT input a type: default + LUT input c type: reg_fb_rsel + LUT input b type: default + LUT input e type: default + LUT input d type: default + LUT input f type: default + + CLUSTER OUTPUT LOAD DETAILS: + Total number of SB inputs connected to cluster output: 8 + Number of 'on' SB MUXes (assumed): 1 + Number of 'partial' SB MUXes: 1 + Number of 'off' SB MUXes: 6 + + ROUTING WIRE LOAD DETAILS: + Number of SB inputs connected to routing wire = 9 + Wire: SB (on = 1, partial = 1, off = 7) + Number of CB inputs connected to routing wire = 16 + Wire: CB (on = 1, partial = 1, off = 14) + Tile 1: SB (on = 1, partial = 1, off = 1); CB (on = 1, partial = 1, off = 2) + Tile 2: SB (on = 0, partial = 0, off = 2); CB (on = 0, partial = 0, off = 4) + Tile 3: SB (on = 0, partial = 0, off = 2); CB (on = 0, partial = 0, off = 4) + Tile 4: SB (on = 0, partial = 0, off = 2); CB (on = 0, partial = 0, off = 4) + + DETAILS OF HARD BLOCK: hard_block + Localmux: + Style: two-level MUX + Required MUX size: 144:1 + Implemented MUX size: 144:1 + Level 1 size = 12 + Level 2 size = 12 + Number of unused inputs = 0 + Number of MUXes per tile: 288 + Number of SRAM cells per MUX: 24 + +|------------------------------------------------------------------------------| + + +|--------------------------------------------------------------------------------------------------| +| Area and Delay Report | +|--------------------------------------------------------------------------------------------------| + + SUBCIRCUIT AREA, DELAY & POWER + ------------------------------ + Subcircuit Area (um^2) Delay (ps) tfall (ps) trise (ps) Power at 250MHz (uW) + sb_mux 1.522 189.1 186.8 189.1 25.55 + sb_mux(with sram) 2.47 189.1 186.8 189.1 25.55 + cb_mux 2.702 174.0 174.0 167.4 3.443 + cb_mux(with sram) 4.869 174.0 174.0 167.4 3.443 + local_mux 1.155 57.59 57.59 56.45 0.336 + local_mux(with sram) 2.51 57.59 57.59 56.45 0.336 + local_ble_output(with sram) 0.748 155.6 155.6 121.5 2.625 + general_ble_output(with sram) 0.559 30.19 30.19 30.05 1.086 + ff 1.228 n/a n/a n/a n/a + lut (with sram) 28.576 160.8 160.8 160.4 n/a + lut_a n/a 445.9 445.9 132.5 2.642 + lut_a_driver 0.341 14.79 14.79 13.81 0.7863 + lut_a_driver_not 0.398 24.39 23.07 24.39 0.7834 + lut_b n/a 443.0 443.0 129.9 2.603 + lut_b_driver 0.311 13.84 13.84 13.83 0.5785 + lut_b_driver_not 0.385 23.05 21.41 23.05 0.6214 + lut_c n/a 439.5 439.5 119.3 2.573 + lut_c_driver 0.791 32.52 32.52 32.15 1.129 + lut_c_driver_not 0.297 39.13 38.5 39.13 0.5226 + lut_d n/a 272.6 272.6 77.11 1.841 + lut_d_driver 0.191 16.62 16.62 15.77 0.4516 + lut_d_driver_not 0.27 24.92 22.14 24.92 0.504 + lut_e n/a 272.3 272.3 72.45 1.734 + lut_e_driver 0.148 18.09 18.09 17.73 0.4111 + lut_e_driver_not 0.213 28.5 24.69 28.5 0.4716 + lut_f n/a 264.1 264.1 57.47 1.625 + lut_f_driver 0.163 13.63 13.63 12.58 0.3934 + lut_f_driver_not 0.238 23.22 20.36 23.22 0.464 + hard_block mux 10.199 200.6 114.1 200.6 3.707 + + + TILE AREA CONTRIBUTIONS + ----------------------- + Block Total Area (um^2) Fraction of total tile area + Tile 1094.718 100% + LUT 323.236 29.527% + FF 12.275 1.121% + BLE output 18.649 1.704% + Local mux 150.578 13.755% + Connection block 194.765 17.791% + Switch block 395.214 36.102% + + HARDBLOCK INFORMATION + --------------------- + Name: hard_block + Core area: 5358.42216 + Local mux area: 2001.0290619 + Local mux area with sram: 2937.3009339 + Total area: 8295.7230939 + + VPR DELAYS + ---------- + Path Delay (ps) + Tdel (routing switch) 1.891e-10 + T_ipin_cblock (connection block mux) 1.74e-10 + CLB input -> BLE input (local CLB routing) 5.759e-11 + LUT output -> BLE input (local feedback) 1.556e-10 + LUT output -> CLB output (logic block output) 3.019e-11 + lut_a 4.7029e-10 + lut_b 4.6605e-10 + lut_c 4.7863e-10 + lut_d 2.9752e-10 + lut_e 3.008e-10 + lut_f 2.8732e-10 + + VPR AREAS + ---------- + grid_logic_tile_area 14904.8765232 + ipin_mux_trans_size (connection block mux) 0.966 + mux_trans_size (routing switch) 1.50823186576 + buf_size (routing switch) 21.6196626435 + + SUMMARY + ------- + Tile Area 1094.72 um^2 + Representative Critical Path Delay 224.6 ps + Cost (area^1 x delay^1) 0.24588 + +|--------------------------------------------------------------------------------------------------| + +Number of HSPICE simulations performed: 73322 +Total time elapsed: 4 hours 7 minutes 2 seconds + +