2019-08-29 23:13:18 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Script Name : run_fpga_flow.py
# Description : This script designed to run different flows supported by
# OpensFPGA project.
# Args : python3 run_fpga_flow.py --help
# Author : Ganesh Gore
2019-11-16 20:10:04 -06:00
# Email : ganesh.gore@utah.edu
2019-08-29 23:13:18 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-09 17:49:05 -05:00
import os
2019-08-16 10:44:50 -05:00
import sys
2019-08-09 17:49:05 -05:00
import shutil
import time
2021-02-03 11:34:34 -06:00
import traceback
2019-08-22 18:01:38 -05:00
from datetime import timedelta
2019-08-09 17:49:05 -05:00
import shlex
import glob
2020-11-25 18:22:41 -06:00
import json
2019-08-09 17:49:05 -05:00
import argparse
from configparser import ConfigParser , ExtendedInterpolation
import logging
2020-11-25 18:22:41 -06:00
from envyaml import EnvYAML
2019-08-09 17:49:05 -05:00
import glob
import subprocess
import threading
from string import Template
2019-08-15 15:39:58 -05:00
import re
2019-08-09 17:49:05 -05:00
import xml . etree . ElementTree as ET
2019-08-22 18:01:38 -05:00
from importlib import util
2022-11-21 16:21:31 -06:00
2019-08-22 18:01:38 -05:00
if util . find_spec ( " humanize " ) :
import humanize
2019-08-09 17:49:05 -05:00
2019-08-29 23:13:18 -05:00
if sys . version_info [ 0 ] < 3 :
raise Exception ( " run_fpga_task script must be using Python 3 " )
2019-08-15 15:39:58 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Initialise general paths for the script
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Copy directory where flow file exist
2019-08-09 17:49:05 -05:00
flow_script_dir = os . path . dirname ( os . path . abspath ( __file__ ) )
2019-08-15 15:39:58 -05:00
# Find OpenFPGA base directory
2022-11-21 16:21:31 -06:00
openfpga_base_dir = os . path . abspath ( os . path . join ( flow_script_dir , os . pardir , os . pardir ) )
2019-08-15 15:39:58 -05:00
# Copy directory from where script is laucnhed
# [req to resolve relative paths provided while launching script]
2019-08-09 17:49:05 -05:00
launch_dir = os . getcwd ( )
2019-08-15 15:39:58 -05:00
# Path section to append in configuration file to interpolate path
2019-08-31 22:55:32 -05:00
task_script_dir = os . path . dirname ( os . path . abspath ( __file__ ) )
2022-11-21 16:21:31 -06:00
script_env_vars = {
" PATH " : {
" OPENFPGA_FLOW_PATH " : task_script_dir ,
" ARCH_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " arch " ) ,
" OPENFPGA_SHELLSCRIPT_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " OpenFPGAShellScripts " ) ,
" BENCH_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " benchmarks " ) ,
" TECH_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " tech " ) ,
" SPICENETLIST_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " SpiceNetlists " ) ,
" VERILOG_PATH " : os . path . join ( " $ { PATH:OPENFPGA_PATH} " , " VerilogNetlists " ) ,
" OPENFPGA_PATH " : os . path . abspath ( os . path . join ( task_script_dir , os . pardir , os . pardir ) ) ,
}
}
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-15 15:39:58 -05:00
# Reading command-line argument
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-15 15:39:58 -05:00
# Helper function to provide better alignment to help print
2022-11-21 16:21:31 -06:00
def formatter ( prog ) :
return argparse . HelpFormatter ( prog , max_help_position = 60 )
2019-08-15 15:39:58 -05:00
parser = argparse . ArgumentParser ( formatter_class = formatter )
# Mandatory arguments
2022-11-21 16:21:31 -06:00
parser . add_argument ( " arch_file " , type = str )
parser . add_argument ( " benchmark_files " , type = str , nargs = " + " )
2020-07-27 19:10:43 -05:00
# parser.add_argument('extraArgs', nargs=argparse.REMAINDER)
2022-11-21 16:21:31 -06:00
parser . add_argument ( " otherthings " , nargs = " * " )
2019-08-15 15:39:58 -05:00
# Optional arguments
2022-11-21 16:21:31 -06:00
parser . add_argument ( " --top_module " , type = str , default = " top " )
parser . add_argument ( " --fpga_flow " , type = str , default = " yosys_vpr " )
parser . add_argument ( " --flow_config " , type = str , help = " CAD tools path overrides default setting " )
parser . add_argument (
" --run_dir " ,
type = str ,
default = os . path . join ( openfpga_base_dir , " tmp " ) ,
help = " Directory to store intermidiate file & final results " ,
)
2023-12-12 12:00:50 -06:00
parser . add_argument ( " --default_tool_path " , type = str , default = os . path . join ( flow_script_dir , os . pardir , " misc " , " fpgaflow_default_tool_path.conf " ) , help = " The configuraton file contains paths to tools as well as keywords to be extracted from logs " )
2022-11-21 16:21:31 -06:00
parser . add_argument (
" --openfpga_shell_template " ,
type = str ,
default = os . path . join ( " openfpga_flow " , " openfpga_shell_scripts " , " example_script.openfpga " ) ,
help = " Sample openfpga shell script " ,
)
parser . add_argument ( " --openfpga_arch_file " , type = str , help = " Openfpga architecture file for shell " )
parser . add_argument (
" --arch_variable_file " , type = str , default = None , help = " Openfpga architecture file for shell "
)
2020-07-27 19:10:43 -05:00
# parser.add_argument('--openfpga_sim_setting_file', type=str,
# help="Openfpga simulation file for shell")
# parser.add_argument('--external_fabric_key_file', type=str,
# help="Key file for shell")
2022-11-21 16:21:31 -06:00
parser . add_argument (
" --yosys_tmpl " ,
type = str ,
default = None ,
help = " Alternate yosys template, generates top_module.blif " ,
)
parser . add_argument (
" --ys_rewrite_tmpl " ,
type = str ,
default = None ,
help = " Alternate yosys template, to rewrite verilog netlist " ,
)
parser . add_argument ( " --verific " , action = " store_true " , help = " Run yosys with verific enabled " )
parser . add_argument ( " --disp " , action = " store_true " , help = " Open display while running VPR " )
parser . add_argument ( " --debug " , action = " store_true " , help = " Run script in debug mode " )
2019-08-15 15:39:58 -05:00
2019-08-22 18:00:59 -05:00
# Blif_VPR Only flow arguments
2022-11-21 16:21:31 -06:00
parser . add_argument ( " --activity_file " , type = str , help = " Activity file used while running yosys flow " )
parser . add_argument (
" --base_verilog " ,
type = str ,
help = " Original Verilog file to run verification in " + " blif_VPR flow " ,
)
2019-08-22 18:00:59 -05:00
2019-08-15 15:39:58 -05:00
# ACE2 and power estimation related arguments
2022-11-21 16:21:31 -06:00
parser . add_argument ( " --K " , type = int , help = " LUT Size, if not specified extracted from arch file " )
parser . add_argument ( " --power " , action = " store_true " )
parser . add_argument ( " --power_tech " , type = str , help = " Power tech xml file for power calculation " )
parser . add_argument ( " --ace_d " , type = float , help = " Specify the default signal density of PIs in ACE2 " )
parser . add_argument (
" --ace_p " , type = float , help = " Specify the default signal probablity of PIs in ACE2 "
)
parser . add_argument ( " --black_box_ace " , action = " store_true " )
2019-08-15 15:39:58 -05:00
# VPR Options
2022-11-21 16:21:31 -06:00
parser . add_argument ( " --min_route_chan_width " , type = float , help = " Turn on min_route_chan_width " )
parser . add_argument (
" --max_route_width_retry " ,
type = int ,
default = 100 ,
help = " Maximum iterations to perform to reroute " ,
)
parser . add_argument ( " --fix_route_chan_width " , type = int , help = " Turn on fix_route_chan_width " )
parser . add_argument (
" --vpr_timing_pack_off " , action = " store_true " , help = " Turn off the timing-driven pack for vpr "
)
parser . add_argument (
" --vpr_place_clb_pin_remap " , action = " store_true " , help = " Turn on place_clb_pin_remap in VPR "
)
parser . add_argument (
" --vpr_max_router_iteration " , type = int , help = " Specify the max router iteration in VPR "
)
parser . add_argument (
" --vpr_route_breadthfirst " ,
action = " store_true " ,
help = " Use the breadth-first routing algorithm of VPR " ,
)
parser . add_argument (
" --vpr_use_tileable_route_chan_width " ,
action = " store_true " ,
help = " Turn on the conversion to " + " tileable_route_chan_width in VPR " ,
)
2019-08-15 15:39:58 -05:00
# VPR - FPGA-X2P Extension
2022-11-21 16:21:31 -06:00
X2PParse = parser . add_argument_group ( " VPR-FPGA-X2P Extension " )
X2PParse . add_argument (
" --vpr_fpga_x2p_rename_illegal_port " ,
action = " store_true " ,
help = " Rename illegal ports option of VPR FPGA SPICE " ,
)
X2PParse . add_argument (
" --vpr_fpga_x2p_signal_density_weight " ,
type = float ,
help = " Specify the signal_density_weight of VPR FPGA SPICE " ,
)
X2PParse . add_argument (
" --vpr_fpga_x2p_sim_window_size " ,
type = float ,
help = " specify the sim_window_size of VPR FPGA SPICE " ,
)
X2PParse . add_argument (
" --vpr_fpga_x2p_compact_routing_hierarchy " ,
action = " store_true " ,
help = " Compact_routing_hierarchy " ,
)
X2PParse . add_argument (
" --vpr_fpga_x2p_duplicate_grid_pin " , action = " store_true " , help = " Added duplicated grid pin "
)
2019-08-15 15:39:58 -05:00
# VPR - FPGA-SPICE Extension
2022-11-21 16:21:31 -06:00
SPParse = parser . add_argument_group ( " FPGA-SPICE Extension " )
SPParse . add_argument ( " --vpr_fpga_spice " , action = " store_true " , help = " Print SPICE netlists in VPR " )
SPParse . add_argument (
" --vpr_fpga_spice_sim_mt_num " , type = int , help = " Specify the option sim_mt_num of VPR FPGA SPICE "
)
SPParse . add_argument (
" --vpr_fpga_spice_print_component_tb " ,
action = " store_true " ,
help = " Output component-level testbench " ,
)
SPParse . add_argument (
" --vpr_fpga_spice_print_grid_tb " , action = " store_true " , help = " Output grid-level testbench "
)
SPParse . add_argument (
" --vpr_fpga_spice_print_top_testbench " ,
action = " store_true " ,
help = " Output full-chip-level testbench " ,
)
SPParse . add_argument (
" --vpr_fpga_spice_leakage_only " ,
action = " store_true " ,
help = " Turn on leakage_only mode in VPR FPGA SPICE " ,
)
SPParse . add_argument (
" --vpr_fpga_spice_parasitic_net_estimation_off " ,
action = " store_true " ,
help = " Turn off parasitic_net_estimation in VPR FPGA SPICE " ,
)
SPParse . add_argument (
" --vpr_fpga_spice_testbench_load_extraction_off " ,
action = " store_true " ,
help = " Turn off testbench_load_extraction in VPR FPGA SPICE " ,
)
SPParse . add_argument ( " --vpr_fpga_spice_simulator_path " , type = str , help = " Specify simulator path " )
2019-08-15 15:39:58 -05:00
# VPR - FPGA-Verilog Extension
2022-11-21 16:21:31 -06:00
VeriPar = parser . add_argument_group ( " FPGA-Verilog Extension " )
VeriPar . add_argument (
" --vpr_fpga_verilog " , action = " store_true " , help = " Generator verilog of VPR FPGA SPICE "
)
VeriPar . add_argument (
" --vpr_fpga_verilog_dir " , type = str , help = " path to store generated verilog files "
)
VeriPar . add_argument (
" --vpr_fpga_verilog_include_timing " ,
action = " store_true " ,
help = " Print delay specification in Verilog files " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_include_signal_init " ,
action = " store_true " ,
help = " Print signal initialization in Verilog files " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_autocheck_top_testbench " ,
action = " store_true " ,
help = " Print autochecked top-level " + " testbench for Verilog Generator of VPR FPGA SPICE " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_formal_verification_top_netlist " ,
action = " store_true " ,
help = " Print formal top Verilog files " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_include_icarus_simulator " ,
action = " store_true " ,
help = " dd syntax and definition " + " required to use Icarus Verilog simulator " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_user_defined_template " , action = " store_true " , help = " Unknown parameter "
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_report_timing_tcl " ,
action = " store_true " ,
help = " Generate tcl script useful " + " for timing report generation " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_report_timing_rpt_path " ,
type = str ,
help = " Specify path for report timing results " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_sdc_pnr " ,
action = " store_true " ,
help = " Generate sdc file to constraint Hardware P&R " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_sdc_analysis " , action = " store_true " , help = " Generate sdc file to do STA "
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_top_tb " ,
action = " store_true " ,
help = " Print top-level testbench for Verilog Generator " + " of VPR FPGA SPICE " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_input_blif_tb " ,
action = " store_true " ,
help = " Print testbench " + " for input blif file in Verilog Generator " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_print_simulation_ini " ,
action = " store_true " ,
help = " Create simulation INI file " ,
)
VeriPar . add_argument (
" --vpr_fpga_verilog_explicit_mapping " , action = " store_true " , help = " Explicit Mapping "
)
2019-08-15 15:39:58 -05:00
# VPR - FPGA-Bitstream Extension
2022-11-21 16:21:31 -06:00
BSparse = parser . add_argument_group ( " FPGA-Bitstream Extension " )
BSparse . add_argument (
" --vpr_fpga_bitstream_generator " , action = " store_true " , help = " Generate FPGA-SPICE bitstream "
)
2019-08-15 15:39:58 -05:00
# Regression test option
2022-11-21 16:21:31 -06:00
RegParse = parser . add_argument_group ( " Regression Test Extension " )
RegParse . add_argument (
" --end_flow_with_test " , action = " store_true " , help = " Run verification test at the end "
)
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-15 15:39:58 -05:00
# Global varaibles declaration
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-22 18:01:38 -05:00
# Setting up print and logging system
2022-11-21 16:21:31 -06:00
logging . basicConfig ( level = logging . INFO , stream = sys . stdout , format = " %(levelname)s - %(message)s " )
logger = logging . getLogger ( " OpenFPGA_Flow_Logs " )
2019-08-22 18:01:38 -05:00
2019-08-15 15:39:58 -05:00
# variable to store script_configuration and cad tool paths
config , cad_tools = None , None
2019-08-22 18:01:38 -05:00
ExecTime = { }
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Main program starts here
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2019-08-15 15:39:58 -05:00
2019-08-09 17:49:05 -05:00
def main ( ) :
2022-11-21 16:21:31 -06:00
logger . debug ( " Script Launched in " + os . getcwd ( ) )
2023-12-12 12:00:50 -06:00
check_required_file ( args . default_tool_path )
read_script_config ( args . default_tool_path )
2019-08-15 15:39:58 -05:00
validate_command_line_arguments ( )
2019-08-09 17:49:05 -05:00
prepare_run_directory ( args . run_dir )
2022-11-21 16:21:31 -06:00
if args . fpga_flow == " yosys_vpr " :
2019-08-09 17:49:05 -05:00
logger . info ( ' Running " yosys_vpr " Flow ' )
run_yosys_with_abc ( )
2019-10-15 17:08:25 -05:00
# TODO Make it optional if activity file is provided
2019-08-22 18:01:38 -05:00
if args . power :
2021-02-03 20:07:48 -06:00
run_ace2 ( )
run_pro_blif_3arg ( )
2021-03-08 01:21:07 -06:00
else :
2021-02-16 17:53:13 -06:00
# Make a copy of the blif file to be compatible with vpr flow
2022-11-21 16:21:31 -06:00
shutil . copy ( args . top_module + " _yosys_out.blif " , args . top_module + " .blif " )
2021-02-16 17:53:13 -06:00
# Always Generate the post-synthesis verilog files
run_rewrite_verilog ( )
2022-11-21 16:21:31 -06:00
if args . fpga_flow == " vpr_blif " :
2019-08-22 18:00:59 -05:00
collect_files_for_vpr ( )
2022-11-21 16:21:31 -06:00
if args . fpga_flow == " yosys " :
2022-01-06 03:44:11 -06:00
run_yosys_with_abc ( )
if not ( args . fpga_flow == " yosys " ) :
logger . info ( " Running OpenFPGA Shell Engine " )
run_openfpga_shell ( )
if args . end_flow_with_test :
run_netlists_verification ( )
2019-08-22 18:01:38 -05:00
ExecTime [ " End " ] = time . time ( )
2022-11-21 16:21:31 -06:00
def timestr ( x ) :
return (
humanize . naturaldelta ( timedelta ( seconds = x ) )
if " humanize " in sys . modules
else str ( int ( x ) ) + " Sec "
)
if args . fpga_flow == " yosys " :
TimeInfo = " Openfpga_flow completed, " + " Total Time Taken %s " % timestr (
ExecTime [ " End " ] - ExecTime [ " Start " ]
)
2022-01-06 03:44:11 -06:00
else :
2022-11-21 16:21:31 -06:00
TimeInfo = (
" Openfpga_flow completed, "
+ " Total Time Taken %s " % timestr ( ExecTime [ " End " ] - ExecTime [ " Start " ] )
+ " VPR Time %s " % timestr ( ExecTime [ " VPREnd " ] - ExecTime [ " VPRStart " ] )
)
TimeInfo + = (
" Verification Time %s "
% timestr ( ExecTime [ " VerificationEnd " ] - ExecTime [ " VerificationStart " ] )
if args . end_flow_with_test
else " "
)
2019-08-22 18:01:38 -05:00
logger . info ( TimeInfo )
2019-08-09 17:49:05 -05:00
exit ( )
2022-11-21 16:21:31 -06:00
2019-08-09 17:49:05 -05:00
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Subroutines starts here
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2023-12-12 12:00:50 -06:00
def check_required_file ( default_tool_path ) :
2023-02-11 19:12:04 -06:00
""" Function ensure existace of all required files for the script """
2019-08-15 15:39:58 -05:00
files_dict = {
2023-12-12 12:00:50 -06:00
" CAD TOOL PATH " : default_tool_path
2023-12-12 15:14:47 -06:00
,
2019-08-15 15:39:58 -05:00
}
for filename , filepath in files_dict . items ( ) :
if not os . path . isfile ( filepath ) :
2021-10-18 05:45:35 -05:00
clean_up_and_exit ( " Not able to locate default file " + filename )
2019-08-15 15:39:58 -05:00
2023-12-12 12:00:50 -06:00
def read_script_config ( default_tool_path ) :
2023-02-11 19:12:04 -06:00
""" This fucntion reads default CAD tools path from configuration file """
2019-08-15 15:39:58 -05:00
global config , cad_tools
config = ConfigParser ( interpolation = ExtendedInterpolation ( ) )
config . read_dict ( script_env_vars )
2023-12-12 12:00:50 -06:00
default_cad_tool_conf = default_tool_path
2019-08-15 15:39:58 -05:00
config . read_file ( open ( default_cad_tool_conf ) )
2019-08-31 16:19:34 -05:00
if args . flow_config :
config . read_file ( open ( args . flow_config ) )
2019-08-16 10:44:50 -05:00
if not " CAD_TOOLS_PATH " in config . sections ( ) :
clean_up_and_exit ( " Missing CAD_TOOLS_PATH in openfpga_flow config " )
2019-08-15 15:39:58 -05:00
cad_tools = config [ " CAD_TOOLS_PATH " ]
2020-11-25 18:22:41 -06:00
if args . arch_variable_file :
_ , file_extension = os . path . splitext ( args . arch_variable_file )
if file_extension in [ " .yml " , " .yaml " ] :
script_env_vars [ " PATH " ] . update (
2022-11-21 16:21:31 -06:00
EnvYAML ( args . arch_variable_file , include_environment = False )
)
if file_extension in [
" .json " ,
] :
2020-11-25 18:22:41 -06:00
with open ( args . arch_variable_file , " r " ) as fp :
script_env_vars [ " PATH " ] . update ( json . load ( fp ) )
2019-08-15 15:39:58 -05:00
def validate_command_line_arguments ( ) :
2022-11-21 16:21:31 -06:00
"""
2021-02-03 11:34:34 -06:00
This function validate the command line arguments
FLOW_SCRIPT_CONFIG - > valid_flows :
Key is used to validate if the request flow is supported by the script
CMD_ARGUMENT_DEPENDANCY :
Validates the dependencies of the command arguments
Checks the following file exists and replaces them with an absolute path
- All architecture files
- Benchmark files
- Power tech files
- Run directory
- Activity file
- Base verilog file
2022-11-21 16:21:31 -06:00
"""
2021-10-18 04:13:42 -05:00
logger . info ( " Validating command line arguments " )
2019-08-19 22:28:23 -05:00
2019-08-21 12:08:13 -05:00
if args . debug :
logger . info ( " Setting loggger in debug mode " )
logger . setLevel ( logging . DEBUG )
2019-08-19 22:28:23 -05:00
# Check if flow supported
if not args . fpga_flow in config . get ( " FLOW_SCRIPT_CONFIG " , " valid_flows " ) :
2019-08-22 18:01:38 -05:00
clean_up_and_exit ( " %s Flow not supported " % args . fpga_flow )
2019-08-19 22:28:23 -05:00
# Check if argument list is consistant
for eacharg , dependent in config . items ( " CMD_ARGUMENT_DEPENDANCY " ) :
if getattr ( args , eacharg , None ) :
dependent = dependent . split ( " , " )
for eachdep in dependent :
if not any ( [ getattr ( args , i , 0 ) for i in eachdep . split ( " | " ) ] ) :
2022-11-21 16:21:31 -06:00
clean_up_and_exit (
" ' %s ' argument depends on ( %s ) arguments "
% ( eacharg , " , " . join ( dependent ) . replace ( " | " , " or " ) )
)
2019-08-09 17:49:05 -05:00
2021-02-03 11:34:34 -06:00
# Check if architecrue files exists
2019-08-09 17:49:05 -05:00
args . arch_file = os . path . abspath ( args . arch_file )
if not os . path . isfile ( args . arch_file ) :
2022-11-21 16:21:31 -06:00
clean_up_and_exit ( " VPR architecture file not found. - %s " % args . arch_file )
2021-02-03 11:34:34 -06:00
args . openfpga_arch_file = os . path . abspath ( args . openfpga_arch_file )
if not os . path . isfile ( args . openfpga_arch_file ) :
2022-11-21 16:21:31 -06:00
clean_up_and_exit ( " OpenFPGA architecture file not found. - %s " % args . openfpga_arch_file )
2019-08-09 17:49:05 -05:00
# Filter provided benchmark files
for index , everyinput in enumerate ( args . benchmark_files ) :
args . benchmark_files [ index ] = os . path . abspath ( everyinput )
2019-08-19 22:28:23 -05:00
if os . path . isdir ( args . benchmark_files [ index ] ) :
logger . warning ( " Skipping directory in bench %s " % everyinput )
2022-11-21 16:21:31 -06:00
logger . warning (
" Directory is not support in benchmark list " + " use wildcard pattern to add files "
)
2019-08-19 22:28:23 -05:00
continue
2019-08-09 17:49:05 -05:00
for everyfile in glob . glob ( args . benchmark_files [ index ] ) :
if not os . path . isfile ( everyfile ) :
2022-11-21 16:21:31 -06:00
clean_up_and_exit ( " Failed to copy benchmark file - %s " % args . arch_file )
2019-08-15 15:39:58 -05:00
2019-08-19 22:28:23 -05:00
# Filter provided powertech files
2019-08-15 15:39:58 -05:00
if args . power_tech :
args . power_tech = os . path . abspath ( args . power_tech )
if not os . path . isfile ( args . power_tech ) :
2022-11-21 16:21:31 -06:00
clean_up_and_exit ( " Power Tech file not found. - %s " % args . power_tech )
2019-08-16 10:44:50 -05:00
2019-08-19 22:28:23 -05:00
# Expand run directory to absolute path
2019-08-16 10:44:50 -05:00
args . run_dir = os . path . abspath ( args . run_dir )
2022-08-01 19:02:28 -05:00
if args . power :
2022-11-21 16:21:31 -06:00
if args . activity_file :
args . activity_file = os . path . abspath ( args . activity_file )
2019-08-22 18:00:59 -05:00
if args . base_verilog :
args . base_verilog = os . path . abspath ( args . base_verilog )
2019-08-09 17:49:05 -05:00
def prepare_run_directory ( run_dir ) :
"""
Prepares run directory to run
1. Change current directory to run_dir
2. Copy architecture XML file to run_dir
3. Copy circuit files to run_dir
"""
logger . info ( " Run directory : %s " % run_dir )
if os . path . isdir ( run_dir ) :
no_of_files = len ( next ( os . walk ( run_dir ) ) [ 2 ] )
2021-02-03 11:34:34 -06:00
shutil . rmtree ( run_dir )
2019-08-09 17:49:05 -05:00
os . makedirs ( run_dir )
# Clean run_dir is created change working directory
os . chdir ( run_dir )
2020-04-11 17:45:22 -05:00
# Create arch dir in run_dir and copy flattened architecture file
2019-08-09 17:49:05 -05:00
os . mkdir ( " arch " )
2022-11-21 16:21:31 -06:00
tmpl = Template ( open ( args . arch_file , encoding = " utf-8 " ) . read ( ) )
2019-08-09 17:49:05 -05:00
arch_filename = os . path . basename ( args . arch_file )
args . arch_file = os . path . join ( run_dir , " arch " , arch_filename )
2022-11-21 16:21:31 -06:00
with open ( args . arch_file , " w " , encoding = " utf-8 " ) as archfile :
2020-11-25 23:09:36 -06:00
archfile . write ( tmpl . safe_substitute ( script_env_vars [ " PATH " ] ) )
2019-08-09 17:49:05 -05:00
2022-11-21 16:21:31 -06:00
if args . openfpga_arch_file :
tmpl = Template ( open ( args . openfpga_arch_file , encoding = " utf-8 " ) . read ( ) )
2020-04-11 17:45:22 -05:00
arch_filename = os . path . basename ( args . openfpga_arch_file )
args . openfpga_arch_file = os . path . join ( run_dir , " arch " , arch_filename )
2022-11-21 16:21:31 -06:00
with open ( args . openfpga_arch_file , " w " , encoding = " utf-8 " ) as archfile :
2020-11-25 23:09:36 -06:00
archfile . write ( tmpl . safe_substitute ( script_env_vars [ " PATH " ] ) )
2020-04-11 17:45:22 -05:00
2020-07-22 12:57:04 -05:00
# Sanitize provided openshell template, if provided
2022-11-21 16:21:31 -06:00
if args . openfpga_shell_template :
2020-07-22 12:57:04 -05:00
if not os . path . isfile ( args . openfpga_shell_template or " " ) :
2022-11-21 16:21:31 -06:00
logger . error ( " Openfpga shell file - %s " % args . openfpga_shell_template )
clean_up_and_exit (
" Provided openfpga_shell_template "
+ f " { args . openfpga_shell_template } file not found "
)
2020-07-22 12:57:04 -05:00
else :
2022-11-21 16:21:31 -06:00
shutil . copy ( args . openfpga_shell_template , args . top_module + " _template.openfpga " )
2020-07-22 12:57:04 -05:00
2020-04-11 17:45:22 -05:00
# Create benchmark dir in run_dir and copy flattern architecture file
2019-08-09 17:49:05 -05:00
os . mkdir ( " benchmark " )
try :
for index , eachfile in enumerate ( args . benchmark_files ) :
args . benchmark_files [ index ] = shutil . copy2 (
2022-11-21 16:21:31 -06:00
eachfile , os . path . join ( os . curdir , " benchmark " )
)
2019-08-09 17:49:05 -05:00
except :
logger . exception ( " Failed to copy all benchmark file to run_dir " )
def clean_up_and_exit ( msg , clean = False ) :
2019-08-16 10:44:50 -05:00
logger . error ( " Current working directory : " + os . getcwd ( ) )
2019-08-09 17:49:05 -05:00
logger . error ( msg )
2019-08-15 15:39:58 -05:00
logger . error ( " Exiting . . . . . . " )
2019-08-18 13:26:05 -05:00
exit ( 1 )
2019-08-09 17:49:05 -05:00
2022-11-21 16:21:31 -06:00
2021-10-29 08:34:27 -05:00
def create_yosys_params ( ) :
2019-08-09 17:49:05 -05:00
tree = ET . parse ( args . arch_file )
root = tree . getroot ( )
try :
2022-11-21 16:21:31 -06:00
lut_size = max (
[
int ( pb_type . find ( " input " ) . get ( " num_pins " ) )
for pb_type in root . iter ( " pb_type " )
if pb_type . get ( " class " ) == " lut "
]
)
2019-08-16 14:36:39 -05:00
logger . info ( " Extracted lut_size size from arch XML = %s " , lut_size )
2019-08-09 17:49:05 -05:00
logger . info ( " Running Yosys with lut_size = %s " , lut_size )
except :
logger . exception ( " Failed to extract lut_size from XML file " )
clean_up_and_exit ( " " )
2019-08-15 15:39:58 -05:00
args . K = lut_size
2019-08-09 17:49:05 -05:00
# Yosys script parameter mapping
2021-03-16 17:45:57 -05:00
ys_params = script_env_vars [ " PATH " ]
2021-10-29 08:34:27 -05:00
for indx in range ( 0 , len ( OpenFPGAArgs ) , 2 ) :
tmpVar = OpenFPGAArgs [ indx ] [ 2 : ] . upper ( )
2022-11-21 16:21:31 -06:00
ys_params [ tmpVar ] = OpenFPGAArgs [ indx + 1 ]
2021-10-29 08:34:27 -05:00
if not args . verific :
2022-11-21 16:21:31 -06:00
ys_params [ " VERILOG_FILES " ] = " " . join (
[ shlex . quote ( eachfile ) for eachfile in args . benchmark_files ]
)
2022-01-17 02:21:29 -06:00
if not " READ_VERILOG_OPTIONS " in ys_params :
ys_params [ " READ_VERILOG_OPTIONS " ] = " "
2021-10-29 08:34:27 -05:00
else :
if " ADD_INCLUDE_DIR " not in ys_params :
ys_params [ " ADD_INCLUDE_DIR " ] = " "
if " ADD_LIBRARY_DIR " not in ys_params :
ys_params [ " ADD_LIBRARY_DIR " ] = " "
if " ADD_BLACKBOX_MODULES " not in ys_params :
ys_params [ " ADD_BLACKBOX_MODULES " ] = " "
if " READ_HDL_FILE " not in ys_params :
ys_params [ " READ_HDL_FILE " ] = " "
if " READ_LIBRARY " not in ys_params :
ys_params [ " READ_LIBRARY " ] = " "
if " VERIFIC_VERILOG_STANDARD " not in ys_params :
ys_params [ " VERIFIC_VERILOG_STANDARD " ] = " -vlog2k "
if " VERIFIC_SYSTEMVERILOG_STANDARD " not in ys_params :
ys_params [ " VERIFIC_SYSTEMVERILOG_STANDARD " ] = " -sv "
if " VERIFIC_VHDL_STANDARD " not in ys_params :
ys_params [ " VERIFIC_VHDL_STANDARD " ] = " -vhdl "
ext_to_standard_map = {
2022-11-21 16:21:31 -06:00
" .v " : ys_params [ " VERIFIC_VERILOG_STANDARD " ] ,
" .vh " : ys_params [ " VERIFIC_VERILOG_STANDARD " ] ,
" .verilog " : ys_params [ " VERIFIC_VERILOG_STANDARD " ] ,
" .vlg " : ys_params [ " VERIFIC_VERILOG_STANDARD " ] ,
" .sv " : ys_params [ " VERIFIC_SYSTEMVERILOG_STANDARD " ] ,
" .svh " : ys_params [ " VERIFIC_SYSTEMVERILOG_STANDARD " ] ,
" .vhd " : ys_params [ " VERIFIC_VHDL_STANDARD " ] ,
" .vhdl " : ys_params [ " VERIFIC_VHDL_STANDARD " ] ,
}
2021-10-29 08:34:27 -05:00
lib_files = [ ]
include_dirs = set ( [ os . path . dirname ( eachfile ) for eachfile in args . benchmark_files ] )
if " VERIFIC_INCLUDE_DIR " in ys_params :
include_dirs . update ( ys_params [ " VERIFIC_INCLUDE_DIR " ] . split ( " , " ) )
if include_dirs and not ys_params [ " ADD_INCLUDE_DIR " ] :
2022-11-21 16:21:31 -06:00
ys_params [ " ADD_INCLUDE_DIR " ] = " \n " . join (
[ " verific -vlog-incdir " + shlex . quote ( eachdir ) for eachdir in include_dirs ]
)
2021-10-29 08:34:27 -05:00
if " VERIFIC_LIBRARY_DIR " in ys_params :
2022-11-21 16:21:31 -06:00
ys_params [ " ADD_LIBRARY_DIR " ] = " \n " . join (
[
" verific -vlog-libdir " + shlex . quote ( eachdir )
for eachdir in ys_params [ " VERIFIC_LIBRARY_DIR " ] . split ( " , " )
]
)
2021-10-29 08:34:27 -05:00
try :
2022-01-17 02:21:29 -06:00
for param , value in ys_params . items ( ) :
2022-01-17 08:42:40 -06:00
if param . startswith ( " VERIFIC_READ_LIB_NAME " ) :
2022-11-21 16:21:31 -06:00
index = param [ len ( " VERIFIC_READ_LIB_NAME " ) : ]
2022-01-17 08:42:40 -06:00
src_param = " VERIFIC_READ_LIB_SRC " + index
2022-01-17 02:21:29 -06:00
if src_param in ys_params :
src_files = [ ]
for name in ys_params [ src_param ] . split ( " , " ) :
for eachfile in args . benchmark_files :
if name . strip ( ) in eachfile :
src_files . append ( eachfile )
break
if not src_files :
clean_up_and_exit ( " Failed to locate verific library files " )
lib_files . extend ( src_files )
filename , file_extension = os . path . splitext ( src_files [ 0 ] )
2022-11-21 16:21:31 -06:00
ys_params [ " READ_LIBRARY " ] + = " " . join (
[ " verific -work " , ys_params [ param ] , ext_to_standard_map [ file_extension ] ]
+ [ shlex . quote ( eachfile ) for eachfile in src_files ]
+ [ " \n " ]
)
2022-01-17 02:21:29 -06:00
standard_to_sources = { }
2021-10-29 08:34:27 -05:00
for eachfile in args . benchmark_files :
if eachfile in lib_files :
continue
filename , file_extension = os . path . splitext ( eachfile )
2022-01-17 02:21:29 -06:00
if ext_to_standard_map [ file_extension ] in standard_to_sources :
standard_to_sources [ ext_to_standard_map [ file_extension ] ] . append ( eachfile )
else :
standard_to_sources [ ext_to_standard_map [ file_extension ] ] = [ eachfile ]
for standard , sources in standard_to_sources . items ( ) :
2022-11-21 16:21:31 -06:00
ys_params [ " READ_HDL_FILE " ] + = " " . join (
[
" verific " ,
" -L " + ys_params [ " VERIFIC_SEARCH_LIB " ]
if " VERIFIC_SEARCH_LIB " in ys_params
else " " ,
standard ,
" " . join ( [ shlex . quote ( src ) for src in sources ] ) ,
" \n " ,
]
)
2021-10-29 08:34:27 -05:00
except :
logger . exception ( " Failed to determine design file type " )
clean_up_and_exit ( " " )
if " YOSYS_CELL_SIM_VERILOG " in ys_params :
2022-11-21 16:21:31 -06:00
ys_params [ " READ_HDL_FILE " ] + = " " . join (
[
" verific " ,
ys_params [ " VERIFIC_VERILOG_STANDARD " ] ,
ys_params [ " YOSYS_CELL_SIM_VERILOG " ] ,
" \n " ,
]
)
2021-10-29 08:34:27 -05:00
if " YOSYS_CELL_SIM_SYSTEMVERILOG " in ys_params :
2022-11-21 16:21:31 -06:00
ys_params [ " READ_HDL_FILE " ] + = " " . join (
[
" verific " ,
ys_params [ " VERIFIC_SYSTEMVERILOG_STANDARD " ] ,
ys_params [ " YOSYS_CELL_SIM_SYSTEMVERILOG " ] ,
" \n " ,
]
)
2021-10-29 08:34:27 -05:00
if " YOSYS_CELL_SIM_VHDL " in ys_params :
2022-11-21 16:21:31 -06:00
ys_params [ " READ_HDL_FILE " ] + = " " . join (
[
" verific " ,
ys_params [ " VERIFIC_VHDL_STANDARD " ] ,
ys_params [ " YOSYS_CELL_SIM_VHDL " ] ,
" \n " ,
]
)
2021-10-29 08:34:27 -05:00
if " YOSYS_BLACKBOX_MODULES " in ys_params :
2022-11-21 16:21:31 -06:00
ys_params [ " ADD_BLACKBOX_MODULES " ] = " blackbox " + " " . join (
[ " \\ " + mod for mod in ys_params [ " YOSYS_BLACKBOX_MODULES " ] . split ( " , " ) ]
)
2021-10-29 08:34:27 -05:00
2021-03-16 17:45:57 -05:00
ys_params [ " TOP_MODULE " ] = args . top_module
ys_params [ " LUT_SIZE " ] = lut_size
2022-11-21 16:21:31 -06:00
ys_params [ " OUTPUT_BLIF " ] = args . top_module + " _yosys_out.blif "
ys_params [ " OUTPUT_VERILOG " ] = args . top_module + " _output_verilog.v "
2021-03-04 02:45:19 -06:00
2021-10-29 08:34:27 -05:00
return ys_params
def run_yosys_with_abc ( ) :
"""
Execute yosys with ABC and optional blackbox support
"""
ys_params = create_yosys_params ( )
2022-11-21 16:21:31 -06:00
yosys_template = (
args . yosys_tmpl
if args . yosys_tmpl
else os . path . join ( cad_tools [ " misc_dir " ] , " ys_tmpl_yosys_vpr_flow.ys " )
)
tmpl = Template ( open ( yosys_template , encoding = " utf-8 " ) . read ( ) )
with open ( " yosys.ys " , " w " ) as archfile :
2020-11-25 23:09:36 -06:00
archfile . write ( tmpl . safe_substitute ( ys_params ) )
2021-02-03 11:34:34 -06:00
2022-11-21 16:21:31 -06:00
run_command ( " Run yosys " , " yosys_output.log " , [ cad_tools [ " yosys_path " ] , " yosys.ys " ] )
2019-08-09 17:49:05 -05:00
def run_odin2 ( ) :
pass
def run_abc_vtr ( ) :
pass
def run_abc_for_standarad ( ) :
pass
def run_ace2 ( ) :
2019-08-15 15:39:58 -05:00
if args . black_box_ace :
2022-11-21 16:21:31 -06:00
with open ( args . top_module + " _yosys_out.blif " , " r " ) as fp :
2019-08-15 15:39:58 -05:00
blif_lines = fp . readlines ( )
2022-11-21 16:21:31 -06:00
with open ( args . top_module + " _bb.blif " , " w " ) as fp :
2019-08-15 15:39:58 -05:00
for eachline in blif_lines :
if " .names " in eachline :
input_nets = eachline . split ( ) [ 1 : ]
2022-11-21 16:21:31 -06:00
if len ( input_nets ) - 1 > args . K :
logger . error ( " One module in blif have more inputs " + " than K value " )
2019-08-15 15:39:58 -05:00
# Map CEll to each logic in blif
2022-11-21 16:21:31 -06:00
map_nets = ( input_nets [ : - 1 ] + [ " unconn " ] * args . K ) [ : args . K ]
map_nets = [
" I[ %d ]= %s " % ( indx , eachnet ) for indx , eachnet in enumerate ( map_nets )
]
2019-08-15 15:39:58 -05:00
map_nets + = [ " O[0]= %s \n " % input_nets [ - 1 ] ]
fp . write ( " .subckt CELL " )
fp . write ( " " . join ( map_nets ) )
else :
fp . write ( eachline )
declar_input = " " . join ( [ " I[ %d ] " % i for i in range ( args . K ) ] )
2022-11-21 16:21:31 -06:00
model_tmpl = (
" \n "
+ " .model CELL \n "
+ " .inputs "
+ declar_input
+ " \n "
+ " .outputs O[0] \n "
+ " .blackbox \n "
+ " .end \n "
)
2019-08-15 15:39:58 -05:00
fp . write ( model_tmpl )
# Prepare ACE run command
command = [
2022-11-21 16:21:31 -06:00
" -b " ,
args . top_module + ( " _bb.blif " if args . black_box_ace else " _yosys_out.blif " ) ,
" -o " ,
args . top_module + " _ace_out.act " ,
" -n " ,
args . top_module + " _ace_out.blif " ,
" -c " ,
" clk " ,
2019-08-15 15:39:58 -05:00
]
command + = [ " -d " , " %.4f " % args . ace_d ] if args . ace_d else [ " " ]
command + = [ " -p " , " %.4f " % args . ace_d ] if args . ace_p else [ " " ]
try :
2022-11-21 16:21:31 -06:00
filename = args . top_module + " _ace2_output.txt "
with open ( filename , " w+ " ) as output :
process = subprocess . run (
[ cad_tools [ " ace_path " ] ] + command ,
check = True ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
universal_newlines = True ,
)
2019-08-15 15:39:58 -05:00
output . write ( process . stdout )
if process . returncode :
2022-11-21 16:21:31 -06:00
logger . info ( " ACE2 failed with returncode %d " , process . returncode )
2019-09-05 11:23:35 -05:00
raise subprocess . CalledProcessError ( 0 , command )
2019-08-15 15:39:58 -05:00
except :
logger . exception ( " Failed to run ACE2 " )
clean_up_and_exit ( " " )
logger . info ( " ACE2 output is written in file %s " % filename )
2019-08-09 17:49:05 -05:00
2019-08-15 15:39:58 -05:00
def run_pro_blif_3arg ( ) :
command = [
2022-11-21 16:21:31 -06:00
" -i " ,
args . top_module + " _ace_out.blif " ,
" -o " ,
args . top_module + " .blif " ,
" -initial_blif " ,
args . top_module + " _yosys_out.blif " ,
2019-08-15 15:39:58 -05:00
]
try :
2022-11-21 16:21:31 -06:00
filename = args . top_module + " _blif_3args_output.txt "
with open ( filename , " w+ " ) as output :
process = subprocess . run (
[ " perl " , cad_tools [ " pro_blif_path " ] ] + command ,
check = True ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
universal_newlines = True ,
)
2019-08-15 15:39:58 -05:00
output . write ( process . stdout )
if process . returncode :
2022-11-21 16:21:31 -06:00
logger . info ( " blif_3args script failed with returncode %d " , process . returncode )
2019-08-15 15:39:58 -05:00
except :
logger . exception ( " Failed to run blif_3args " )
clean_up_and_exit ( " " )
logger . info ( " blif_3args output is written in file %s " % filename )
2019-08-09 17:49:05 -05:00
2019-08-22 18:01:38 -05:00
def collect_files_for_vpr ( ) :
2019-08-25 01:23:39 -05:00
# Sanitize provided Benchmark option
2019-08-22 18:01:38 -05:00
if len ( args . benchmark_files ) > 1 :
2020-10-06 14:09:22 -05:00
logger . error ( " Expecting Single Benchmark Blif file. " )
2019-08-25 01:23:39 -05:00
if not os . path . isfile ( args . benchmark_files [ 0 ] or " " ) :
clean_up_and_exit ( " Provided Blif file not found " )
2022-11-21 16:21:31 -06:00
shutil . copy ( args . benchmark_files [ 0 ] , args . top_module + " .blif " )
2019-08-25 01:23:39 -05:00
# Sanitize provided Activity file option
2022-08-01 19:02:28 -05:00
if args . power :
2022-11-21 16:21:31 -06:00
if not os . path . isfile ( args . activity_file or " " ) :
logger . error ( " Activity File - %s " % args . activity_file )
clean_up_and_exit ( " Provided activity file not found " )
shutil . copy ( args . activity_file , args . top_module + " _ace_out.act " )
2022-08-01 20:13:57 -05:00
else :
2022-11-21 16:21:31 -06:00
if os . path . isfile ( args . activity_file ) :
shutil . copy ( args . activity_file , args . top_module + " _ace_out.act " )
2019-08-25 01:23:39 -05:00
# Sanitize provided Benchmark option
if not os . path . isfile ( args . base_verilog or " " ) :
logger . error ( " Base Verilog File - %s " % args . base_verilog )
clean_up_and_exit ( " Provided base_verilog file not found " )
2022-11-21 16:21:31 -06:00
shutil . copy ( args . base_verilog , args . top_module + " _output_verilog.v " )
2019-08-22 18:01:38 -05:00
2020-04-06 01:34:36 -05:00
def run_openfpga_shell ( ) :
2020-04-08 22:28:14 -05:00
ExecTime [ " VPRStart " ] = time . time ( )
2020-04-06 01:34:36 -05:00
# bench_blif, fixed_chan_width, logfile, route_only=False
2022-11-21 16:21:31 -06:00
tmpl = Template ( open ( args . top_module + " _template.openfpga " , encoding = " utf-8 " ) . read ( ) )
2020-04-06 01:34:36 -05:00
path_variables = script_env_vars [ " PATH " ]
2022-08-01 19:02:28 -05:00
path_variables [ " TOP_MODULE " ] = args . top_module
2020-04-06 01:34:36 -05:00
path_variables [ " VPR_ARCH_FILE " ] = args . arch_file
path_variables [ " OPENFPGA_ARCH_FILE " ] = args . openfpga_arch_file
2022-11-21 16:21:31 -06:00
path_variables [ " VPR_TESTBENCH_BLIF " ] = args . top_module + " .blif "
path_variables [ " ACTIVITY_FILE " ] = args . top_module + " _ace_out.act "
path_variables [ " REFERENCE_VERILOG_TESTBENCH " ] = args . top_module + " _output_verilog.v "
2020-07-27 19:10:43 -05:00
for indx in range ( 0 , len ( OpenFPGAArgs ) , 2 ) :
tmpVar = OpenFPGAArgs [ indx ] [ 2 : ] . upper ( )
2022-11-21 16:21:31 -06:00
path_variables [ tmpVar ] = OpenFPGAArgs [ indx + 1 ]
2020-07-27 19:10:43 -05:00
2022-11-21 16:21:31 -06:00
with open ( args . top_module + " _run.openfpga " , " w " , encoding = " utf-8 " ) as archfile :
2020-11-25 23:09:36 -06:00
archfile . write ( tmpl . safe_substitute ( path_variables ) )
2022-11-21 16:21:31 -06:00
command = [ cad_tools [ " openfpga_shell_path " ] , " -batch " , " -f " , args . top_module + " _run.openfpga " ]
2020-04-06 01:34:36 -05:00
run_command ( " OpenFPGA Shell Run " , " openfpgashell.log " , command )
2020-04-08 22:28:14 -05:00
ExecTime [ " VPREnd " ] = time . time ( )
2022-09-20 15:46:30 -05:00
extract_vpr_stats ( " openfpgashell.log " )
2020-04-05 12:36:24 -05:00
2019-08-19 20:04:14 -05:00
def extract_vpr_stats ( logfile , r_filename = " vpr_stat " , parse_section = " vpr " ) :
2022-11-21 16:21:31 -06:00
section = (
" DEFAULT_PARSE_RESULT_POWER " if parse_section == " power " else " DEFAULT_PARSE_RESULT_VPR "
)
2019-08-15 15:39:58 -05:00
vpr_log = open ( logfile ) . read ( )
resultDict = { }
2019-08-19 20:04:14 -05:00
for name , value in config . items ( section ) :
reg_string , filt_function = value . split ( " , " )
2019-08-15 15:39:58 -05:00
match = re . search ( reg_string [ 1 : - 1 ] , vpr_log )
if match :
2019-08-19 20:04:14 -05:00
try :
if " lambda " in filt_function . strip ( ) :
2022-11-21 16:21:31 -06:00
eval ( " ParseFunction = " + filt_function . strip ( ) )
2019-08-19 20:04:14 -05:00
extract_val = ParseFunction ( * * match . groups ( ) )
elif filt_function . strip ( ) == " int " :
extract_val = int ( match . group ( 1 ) )
elif filt_function . strip ( ) == " float " :
extract_val = float ( match . group ( 1 ) )
elif filt_function . strip ( ) == " str " :
extract_val = str ( match . group ( 1 ) )
elif filt_function . strip ( ) == " scientific " :
try :
2022-11-21 16:21:31 -06:00
mult = {
" m " : 1e-3 ,
" u " : 1e-6 ,
" n " : 1e-9 ,
" K " : 1e-3 ,
" M " : 1e-6 ,
" G " : 1e-9 ,
} . get ( match . group ( 2 ) [ 0 ] , 1 )
2019-08-19 20:04:14 -05:00
except :
mult = 1
2022-11-21 16:21:31 -06:00
extract_val = float ( match . group ( 1 ) ) * mult
2019-08-19 20:04:14 -05:00
else :
2019-08-19 20:06:46 -05:00
extract_val = match . group ( 1 )
2019-08-19 20:04:14 -05:00
except :
logger . exception ( " Filter failed " )
2019-08-22 18:01:38 -05:00
extract_val = " Filter Failed "
2019-08-15 15:39:58 -05:00
resultDict [ name ] = extract_val
dummyparser = ConfigParser ( )
2019-08-16 11:59:44 -05:00
dummyparser . read_dict ( { " RESULTS " : resultDict } )
2019-08-15 15:39:58 -05:00
2022-11-21 16:21:31 -06:00
with open ( r_filename + " .result " , " w " ) as configfile :
2019-08-15 15:39:58 -05:00
dummyparser . write ( configfile )
2022-11-21 16:21:31 -06:00
logger . info ( " %s result extracted in file %s " % ( parse_section , r_filename + " .result " ) )
2019-08-15 15:39:58 -05:00
def run_rewrite_verilog ( ) :
# Rewrite the verilog after optimization
2021-03-08 22:08:55 -06:00
# If there is no template script provided, use a default template
# If there is a template script provided, replace parameters from configuration
2021-03-08 01:21:07 -06:00
if not args . ys_rewrite_tmpl :
script_cmd = [
2022-11-21 16:21:31 -06:00
" read_blif %s " % args . top_module + " .blif " ,
" write_verilog %s " % args . top_module + " _output_verilog.v " ,
2021-03-08 01:21:07 -06:00
]
command = [ cad_tools [ " yosys_path " ] , " -p " , " ; " . join ( script_cmd ) ]
2021-03-08 01:35:47 -06:00
run_command ( " Yosys " , " yosys_rewrite.log " , command )
2021-03-08 01:21:07 -06:00
else :
2021-03-08 22:08:55 -06:00
# Yosys script parameter mapping
2021-10-29 08:34:27 -05:00
ys_rewrite_params = create_yosys_params ( )
2021-03-10 15:10:35 -06:00
# Split a series of scripts by delim ';'
# And execute the scripts serially
for iteration_idx , curr_rewrite_tmpl in enumerate ( args . ys_rewrite_tmpl . split ( " ; " ) ) :
2022-11-21 16:21:31 -06:00
tmpl = Template ( open ( curr_rewrite_tmpl , encoding = " utf-8 " ) . read ( ) )
2021-03-10 15:10:35 -06:00
logger . info ( " Yosys rewrite iteration: " + str ( iteration_idx ) )
2022-11-21 16:21:31 -06:00
with open ( " yosys_rewrite_ " + str ( iteration_idx ) + " .ys " , " w " ) as archfile :
2021-03-10 15:10:35 -06:00
archfile . write ( tmpl . safe_substitute ( ys_rewrite_params ) )
2022-11-21 16:21:31 -06:00
run_command (
" Run yosys " ,
" yosys_rewrite_output_ " + str ( iteration_idx ) + " .log " ,
[ cad_tools [ " yosys_path " ] , " yosys_rewrite_ " + str ( iteration_idx ) + " .ys " ] ,
)
2019-08-15 15:39:58 -05:00
2019-10-31 10:56:57 -05:00
def run_netlists_verification ( exit_if_fail = True ) :
2019-08-22 18:01:38 -05:00
ExecTime [ " VerificationStart " ] = time . time ( )
2022-11-21 16:21:31 -06:00
compiled_file = " compiled_ " + args . top_module
2019-08-15 15:39:58 -05:00
# include_netlists = args.top_module+"_include_netlists.v"
2022-11-21 16:21:31 -06:00
tb_top_formal = args . top_module + " _top_formal_verification_random_tb "
tb_top_autochecked = args . top_module + " _autocheck_top_tb "
2019-08-15 15:39:58 -05:00
# netlists_path = args.vpr_fpga_verilog_dir_val+"/SRC/"
command = [ cad_tools [ " iverilog_path " ] ]
command + = [ " -o " , compiled_file ]
2020-04-15 13:24:51 -05:00
command + = [ " ./SRC/ %s _include_netlists.v " % args . top_module ]
2019-08-15 15:39:58 -05:00
command + = [ " -s " ]
if args . vpr_fpga_verilog_formal_verification_top_netlist :
command + = [ tb_top_formal ]
else :
command + = [ tb_top_autochecked ]
2022-02-01 15:55:25 -06:00
# TODO: This is NOT flexible!!! We should consider to make the include directory customizable through options
# Add source directory to the include dir
command + = [ " -I " , " ./SRC " ]
2019-08-15 15:39:58 -05:00
run_command ( " iverilog_verification " , " iverilog_output.txt " , command )
2019-09-18 13:14:26 -05:00
vvp_command = [ " vvp " , compiled_file ]
2019-08-19 20:06:46 -05:00
output = run_command ( " vvp_verification " , " vvp_sim_output.txt " , vvp_command )
if " Succeed " in output :
logger . info ( " VVP Simulation Successful " )
else :
2019-09-18 13:14:26 -05:00
logger . error ( str ( output ) . split ( " \n " ) [ - 1 ] )
if exit_if_fail :
clean_up_and_exit ( " Failed to run VVP verification " )
2019-08-22 18:01:38 -05:00
ExecTime [ " VerificationEnd " ] = time . time ( )
2019-08-15 15:39:58 -05:00
def run_command ( taskname , logfile , command , exit_if_fail = True ) :
2019-08-21 12:08:13 -05:00
logger . info ( " Launching %s " % taskname )
2022-11-21 16:21:31 -06:00
with open ( logfile , " w " ) as output :
2019-08-23 00:41:25 -05:00
try :
2022-11-21 16:21:31 -06:00
output . write ( " " . join ( command ) + " \n " )
process = subprocess . run (
command , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True
)
2019-08-15 15:39:58 -05:00
output . write ( process . stdout )
2021-02-03 11:34:34 -06:00
output . write ( process . stderr )
output . write ( str ( process . returncode ) )
if " openfpgashell " in logfile :
filter_openfpga_output ( process . stdout )
2019-08-15 15:39:58 -05:00
if process . returncode :
2022-11-21 16:21:31 -06:00
logger . error ( " %s run failed with returncode %d " % ( taskname , process . returncode ) )
2021-02-03 11:34:34 -06:00
logger . error ( " command %s " % " " . join ( command ) )
filter_failed_process_output ( process . stderr )
if exit_if_fail :
clean_up_and_exit ( " Failed to run %s task " % taskname )
except Exception :
logger . exception ( " %s failed to execute " % ( taskname ) )
traceback . print_exc ( file = output )
2019-08-23 00:41:25 -05:00
if exit_if_fail :
clean_up_and_exit ( " Failed to run %s task " % taskname )
2019-08-15 15:39:58 -05:00
logger . info ( " %s is written in file %s " % ( taskname , logfile ) )
2019-08-19 20:06:46 -05:00
return process . stdout
2019-08-15 15:39:58 -05:00
2021-02-03 11:34:34 -06:00
def filter_openfpga_output ( vpr_output ) :
stdout = iter ( vpr_output . split ( " \n " ) )
try :
for i in range ( 50 ) :
if " Version: " in next ( stdout ) :
2022-11-21 16:21:31 -06:00
logger . info ( " OpenFPGAShell %s %s " % ( next ( stdout ) , next ( stdout ) ) )
2021-02-03 11:34:34 -06:00
break
except StopIteration :
pass
2019-08-23 00:41:25 -05:00
def filter_failed_process_output ( vpr_output ) :
2019-08-16 14:36:39 -05:00
for line in vpr_output . split ( " \n " ) :
2021-10-18 05:45:35 -05:00
elements_to_log = [ " error " , " what() " ]
if any ( match in line . lower ( ) for match in elements_to_log ) :
2019-08-16 14:36:39 -05:00
logger . error ( " -->> " + line )
2019-08-17 17:22:52 -05:00
2019-08-09 17:49:05 -05:00
if __name__ == " __main__ " :
2019-08-22 18:01:38 -05:00
ExecTime [ " Start " ] = time . time ( )
2020-07-27 19:10:43 -05:00
# args = parser.parse_args()
args , OpenFPGAArgs = parser . parse_known_args ( )
2019-08-09 17:49:05 -05:00
main ( )