##################################################################### # Python script to convert pre-PnR Verilog testbench # to post-PnR Verilog testbench # This script will # - Add ports required by post-PnR Verilog module # - Scan-chain head and tail ports # - Add signal stimuli for the scan-chain head and tails # - Rename fpga_top to fpga_core when instanciate Design Under Test (DUT) ##################################################################### import os from os.path import dirname, abspath, isfile import shutil import re import argparse import logging ##################################################################### # Initialize logger ##################################################################### logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) ##################################################################### # Parse the options ##################################################################### parser = argparse.ArgumentParser(description='Converter for post-PnR Verilog testbench') parser.add_argument('--pre_pnr_testbench', required=True, help='Specify the file path for the pre-PnR Verilog testbench as input') parser.add_argument('--post_pnr_testbench', required=True, help='Specify the file path for the post-PnR Verilog testbench to be outputted') args = parser.parse_args() ##################################################################### # Check options: # - Input file must be valid # Otherwise, error out # - Remove any output file if already exist # TODO: give a warning when remove files ##################################################################### if not isfile(args.pre_pnr_testbench): logging.error("Invalid pre-PnR testbench: " + args.pre_pnr_testbench + "\nFile does not exist!\n") exit(1) if isfile(args.post_pnr_testbench): logging.warn("Remove existing post-PnR testbench: " + args.post_pnr_testbench + "!\n") os.remove(args.post_pnr_testbench) ##################################################################### # Open the post-pnr Verilog testbench and start modification ##################################################################### logging.info("Converting pre-PnR testbench:"+ args.pre_pnr_testbench) logging.info(" To post-PnR testbench:"+ args.post_pnr_testbench) # Create output file handler tb_file = open(args.post_pnr_testbench, "w") # Read line by line from pre-PnR testbench with open(args.pre_pnr_testbench, "r") as wp: template_netlist = wp.readlines() for line_num, curr_line in enumerate(template_netlist): # If the current line satisfy the following conditions # It should be modified and outputted to post-PnR Verilog testbenches # Other lines can be directly copied to post-PnR Verilog testbenches line2output = curr_line \ # Condition A: # Add post_pnr to top-level module name if (curr_line.startswith("module")): line2output = re.sub("autocheck_top_tb;$", "post_pnr_autocheck_top_tb;", curr_line) # Add sc_head and sc_tail wire definition after ccff tail definition # Condition B: # Add sc_head and sc_tail wire definition after ccff tail definition if (curr_line == "wire [0:0] ccff_tail;\n"): line2output = line2output \ + "// ---- Scan-chain head ----\n" \ + "wire [0:0] sc_head;\n" \ + "// ---- Scan-chain tail ----\n" \ + "wire [0:0] sc_tail;\n" # Condition C: # Assign an initial value to sc_head after other ports elif (curr_line == "\tassign IO_ISOL_N[0] = 1'b1;\n"): line2output = line2output \ + "\tassign sc_head[0] = 1'b0;\n" # Condition D: # Replace fpga_top with fpga_core in DUT instanciation elif (curr_line == "\tfpga_top FPGA_DUT (\n"): line2output = "\tfpga_core FPGA_DUT (\n" # Condition E: # Add sc_head and sc_tail to the port mapping of FPGA core instance elif (curr_line == "\t\t.ccff_tail(ccff_tail[0]));\n"): line2output = "\t\t.ccff_tail(ccff_tail[0]),\n" \ + "\t\t.sc_head(sc_head[0]),\n" \ + "\t\t.sc_tail(sc_tail[0])\n" \ + "\t\t);\n" tb_file.write(line2output) tb_file.close() logging.info("Done")