mirror of https://github.com/lnis-uofu/SOFA.git
145 lines
6.5 KiB
Python
145 lines
6.5 KiB
Python
#####################################################################
|
|
# Python script to execute Design Compiler Synthesis for a given template tcl script
|
|
# This script will
|
|
# - Create the tcl script as synthesis recipe
|
|
# - Run Design Compiler
|
|
# - Analyze output log files and return succeed or failure
|
|
#####################################################################
|
|
|
|
import sys
|
|
import os
|
|
from os.path import dirname, abspath, isfile
|
|
import shutil
|
|
import re
|
|
import argparse
|
|
import logging
|
|
import subprocess
|
|
|
|
#####################################################################
|
|
# Initialize logger
|
|
#####################################################################
|
|
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
|
|
#####################################################################
|
|
# Main function of this script, so that it can be called by other scripts
|
|
#####################################################################
|
|
def main(args):
|
|
#####################################################################
|
|
# Parse the options
|
|
#####################################################################
|
|
parser = argparse.ArgumentParser(description='Run Synopsys Design Compiler Synthesis for an input netlist')
|
|
parser.add_argument('--rtl_netlist', required=True,
|
|
help='Specify the file path to the RTL netlist as input')
|
|
parser.add_argument('--recipe_template', required=True,
|
|
help='Specify the file path to tcl script contain template synthesis recipe')
|
|
parser.add_argument('--technology_library', required=True,
|
|
help='Specify the technology library which the RTL netlist will be mapped to')
|
|
parser.add_argument('--project_workspace', required=True,
|
|
help='Specify the directory to run Design Compiler')
|
|
args = parser.parse_args(args)
|
|
|
|
run_dc_batch_synth(args.rtl_netlist, args.recipe_template, args.technology_library, args.project_workspace)
|
|
|
|
#####################################################################
|
|
# A function to execute a single-run of Design Compiler for a RTL design
|
|
#####################################################################
|
|
def run_dc_synth(rtl_netlist, rtl_design_name, recipe_template, technology_library, project_workspace):
|
|
project_abs_path = os.path.abspath(project_workspace)
|
|
if not os.path.isdir(project_abs_path):
|
|
logging.debug("Creating Design Compiler project directory : " + project_abs_path + " ...\n")
|
|
os.makedirs(project_abs_path, exist_ok=True)
|
|
logging.debug("Done\n")
|
|
|
|
#####################################################################
|
|
# Create the Tcl script for Design Compiler
|
|
#####################################################################
|
|
# Get absolute path to the template tcl script, it must be valid
|
|
template_tcl_path = os.path.abspath(recipe_template)
|
|
assert(isfile(template_tcl_path))
|
|
|
|
# Create output file handler
|
|
tcl_file_path = project_abs_path + "/" + os.path.basename(rtl_design_name) + "_dc.tcl"
|
|
logging.debug("Generating Tcl script from template recipe: " + tcl_file_path)
|
|
|
|
tcl_file = open(tcl_file_path, "w")
|
|
|
|
with open(template_tcl_path, "r") as wp:
|
|
template_tcl_file = wp.readlines()
|
|
for line_num, curr_line in enumerate(template_tcl_file):
|
|
line2output = curr_line
|
|
# Replace keywords with custom values
|
|
line2output = re.sub("TECH_DB_VAR", technology_library, curr_line)
|
|
line2output = re.sub("DESIGN_NAME_VAR", rtl_design_name, curr_line)
|
|
line2output = re.sub("RTL_NETLIST_VAR", rtl_netlist, curr_line)
|
|
# Finished processing
|
|
# Output the line
|
|
tcl_file.write(line2output)
|
|
|
|
tcl_file.close()
|
|
logging.debug("Done")
|
|
|
|
#####################################################################
|
|
# Run Design Compiler
|
|
#####################################################################
|
|
curr_dir = os.getcwd()
|
|
# Change to the project directory
|
|
os.chdir(project_abs_path)
|
|
logging.debug("Changed to directory: " + project_abs_path)
|
|
|
|
# Run Design Compiler
|
|
dc_log_file_path = project_abs_path + "/" + os.path.basename(rtl_design_name) + "_dc.log"
|
|
dc_shell_bin = "dc_shell"
|
|
dc_shell_cmd = dc_shell_bin + " -f " + os.path.abspath(tcl_file_path) + " > " + dc_log_file_path
|
|
logging.debug("Running Design Compiler by : " + dc_shell_cmd)
|
|
subprocess.run(dc_shell_cmd, shell=True, check=True)
|
|
|
|
# Go back to current directory
|
|
os.chdir(curr_dir)
|
|
|
|
#####################################################################
|
|
# Main function of this script, so that it can be called by other scripts
|
|
#####################################################################
|
|
def run_dc_batch_synth(rtl_netlist, recipe_template, technology_library, project_workspace):
|
|
#####################################################################
|
|
# Check options:
|
|
# - Input files must be valid
|
|
# Otherwise, error out
|
|
#####################################################################
|
|
if not isfile(rtl_netlist):
|
|
logging.error("Invalid RTL netlist: " + rtr_netlist + "\nFile does not exist!\n")
|
|
exit(1)
|
|
|
|
if not isfile(recipe_template):
|
|
logging.error("Invalid recipe template: " + recipe_template + "\nFile does not exist!\n")
|
|
exit(1)
|
|
|
|
if not isfile(technology_library):
|
|
logging.error("Invalid technology library: " + technology_library + "\nFile does not exist!\n")
|
|
exit(1)
|
|
|
|
#####################################################################
|
|
# Collect all the RTL designs to synthesis from the RTL netlist
|
|
#####################################################################
|
|
rtl_design_names = []
|
|
with open(rtl_netlist, "r") as wp:
|
|
rtl_file = wp.readlines()
|
|
# If a line starts with 'module', it is an RTL design to be synthesized
|
|
for line_num, curr_line in enumerate(rtl_file):
|
|
if (curr_line.startswith("module")):
|
|
# Get the design name
|
|
rtl_design_name = re.findall("module(\s+)(\w+)\(", curr_line)[0][1]
|
|
rtl_design_names.append(rtl_design_name)
|
|
|
|
logging.info("Found " + str(len(rtl_design_names)) + " RTL designs to synthesize")
|
|
|
|
# Get absolute path to the template tcl script, it must be valid
|
|
rtl_netlist_abs_path = os.path.abspath(rtl_netlist)
|
|
assert(isfile(rtl_netlist_abs_path))
|
|
|
|
for rtl_design_name in rtl_design_names:
|
|
logging.info("Running Design Compiler for design: " + rtl_design_name)
|
|
run_dc_synth(rtl_netlist_abs_path, rtl_design_name, recipe_template, technology_library, project_workspace)
|
|
logging.info("Done")
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|