############################################## # This is the "Match Resource to Pin" utility (aka MR2P) # # It takes two files as inputs: # # (1) an input net list file # containing (some) net to resource assignment lines, .e.g. # NET 'P12_21' U1- # comment lines and nets already assigned to pins are ok # # (2) and an input "resource to pin dictionary" file # containing resource location lines, e.g. # r2p_dict["IO_L01N_0"] = "B4" # some optional comment # # and creates two files as outputs: # # (1) an output net list file # which will receive all input lines, # some of which will have been translated, e.g. # NET 'P12_21' U1-B4 # some optional comment IO_L01N_0 # comment lines and nets already assigned are simply copied # # (2) and an output (section of a) User Constraint file. # For any input net line that was translated, # this output file will receive a line, e.g. # NET "P12_21" LOC = "B4"; # # messages are printed to the screen # and copied to a logfile ############################################## # Version 0.1 14-Sep-2012: Initial version with input and output files hardcoded # Version 1.0 05-Nov-2012: Add command line arguments to specify names of input and output files # Version 2.0 12-Apr-2012: Copy any existing comment at end of 'NET' lines of N2R input file to N2P output file ############################################## app_title = "Match_Resource_to_Pin" app_version = "2.0" log_file_name = "match_res2pin.log" ############################################## ############################################## # Until we make MR2P parse command line arguments # we need to manually hardcode the input and output file names ############################################# # input net list file name inp_net2res_filename = "to_assign_n2r.txt" # input "resource to pin dictionary" file name r2p_dict = dict() # will needs to be filled via the file named below inp_res2pin_dict = "dictionary_r2p.txt" # output net list file name out_net_filename = "assigned_n2p.txt" # output (section of) UCF file name out_ucf_filename = "assigned_ucf.txt" ############################################## ############################################## char_res_delim_start = "<" char_res_delim_end = ">" char_net_delim = "'" char_comment_delim = "#" ############################################## import string import time import sys ################################################################### def show_exc_info ( logfile = None, stop_on_except = 0 ) : #---------------------------- exception_info = sys.exc_info() # retrieve exception info exception_type = exception_info[0] # exception type exception_value = exception_info[1] # exception value exception_at_line = exception_info[2].tb_lineno # traceback item print ' *** exception_type :', exception_type print ' *** exception_value :', exception_value print ' *** exception_at_line :', exception_at_line if ( logfile != None ): logfile.flush ( ) logfile.write ( ' *** exception_type :' + str(exception_type) + '\n' ) logfile.flush ( ) logfile.write ( ' *** exception_value :' + str(exception_value) + '\n' ) logfile.flush ( ) logfile.write ( ' *** exception_at_line :' + str(exception_at_line) + '\n' ) logfile.flush ( ) # del statement is executed left to right # We need to drop reference to traceback # This must be done explicitely (as below) when directly inside except clause # but it would be done implictely when returning from a function like here del [ exception_at_line, exception_value, exception_type, exception_info ] if stop_on_except : raise # stop and get a trace ################################################################### #say hello #-------------------------------- print ' --------------------------' print ' %s V%s' % ( app_title, app_version ) print ' --------------------------' #open a logfile #-------------------------------- app_logfile = open ( log_file_name, 'a' ) current_time = time.asctime ( time.localtime( time.time() ) ) app_logfile.write ( '\n\n Starting %s \n' % app_title ) app_logfile.write ( ' V%s -- %s\n' % ( app_version, current_time ) ) app_logfile.write ( '\n' ) # read and parse command line arguments #-------------------------------- command_line_argument = sys.argv[1:] cmdarg_tot = len ( command_line_argument ) cmdarg_num = 0 while ( cmdarg_num < cmdarg_tot ) : # check for known argument switch and that there will always be a filename after the switch if ( ( command_line_argument[cmdarg_num] not in ( "-i", "-d", "-o", "-u" ) ) or ( cmdarg_num+1 >= cmdarg_tot ) ) : status = "Command line error at argument <%s>" % command_line_argument[cmdarg_num] print status app_logfile.write ( "\n%s\n" % status ) print "Argument Usage: [-i input_net_to_resource_filename] \n" \ + " [-d input_resource_dictionary_filename] \n" \ + " [-o output_net_to_pin_filename] \n" \ + " [-u output_ucf_filename] \n" sys.exit( 1 ) # input net list file name elif ( command_line_argument[cmdarg_num] == "-i" ) : inp_net2res_filename = command_line_argument[cmdarg_num+1] # input "resource to pin dictionary" file name elif ( command_line_argument[cmdarg_num] == "-d" ) : inp_res2pin_dict = command_line_argument[cmdarg_num+1] # output net list file name elif ( command_line_argument[cmdarg_num] == "-o" ) : out_net_filename = command_line_argument[cmdarg_num+1] # output (section of) UCF file name elif ( command_line_argument[cmdarg_num] == "-u" ) : out_ucf_filename = command_line_argument[cmdarg_num+1] cmdarg_num = cmdarg_num + 2 # ingest the resource dictionary #-------------------------------- try: status = "Reading Resource to Pin dictionary from <%s>" % inp_res2pin_dict print status app_logfile.write ( "\n%s\n" % status ) execfile ( inp_res2pin_dict ) status = "Found %d Resource Names in dictionary" % len(r2p_dict) print status app_logfile.write ( "\n%s\n" % status ) except: status = "Error reading Resource to Pin dictionary" print status app_logfile.write ( "%s\n" % status ) show_exc_info ( app_logfile, stop_on_except = 1 ) # prepare a second dictionary to keep track of entry usage r2p_usage = dict() for r2p_dict_entry in r2p_dict : r2p_usage [ r2p_dict_entry ] = 0 # open input file #-------------------------------- status = "Opening Input Net to Resource file <%s>" % inp_net2res_filename print status app_logfile.write ( "\n%s\n" % status ) inp_netlist = open ( inp_net2res_filename, "r" ) # open output files and write header comment #-------------------------------- status = "Opening Output Net to Pin File <%s>" % out_net_filename print status app_logfile.write ( "\n%s\n" % status ) out_netlist = open ( out_net_filename, "w" ) out_netlist.write ( "#\n# File created by %s V%s at %s\n" % ( app_title, app_version, current_time ) ) out_netlist.write ( "# derived from input Netlist file <%s>\n" % inp_net2res_filename ) out_netlist.write ( "# and Resource to Pin dictionary <%s>\n#\n\n" % inp_res2pin_dict ) status = "Opening Output User Constraint File <%s>" % out_ucf_filename print status app_logfile.write ( "\n%s\n" % status ) out_ucf = open ( out_ucf_filename, "w" ) out_ucf.write ( "//\n// File created by %s V%s at %s\n" % ( app_title, app_version, current_time ) ) out_ucf.write ( "// derived from input Netlist file <%s>\n" % inp_net2res_filename ) out_ucf.write ( "// and Resource to Pin dictionary <%s>\n//\n\n" % inp_res2pin_dict ) # read input file #-------------------------------- status = "Processing Net to Resource File and Matching Pins" print status app_logfile.write ( "\n%s\n" % status ) line_num = 0 for inp_net_line in inp_netlist.readlines() : line_num += 1 out_net_line = inp_net_line # copying the input line is the default if no change is needed # We only filter NET lines if ( inp_net_line[:3] == "NET" ) : # There might be a comment at the end of the input line # look for it now, as we will also check that it doesn't start too early loc_comment = string.find ( inp_net_line, char_comment_delim ) # might as well grab the comment now if ( loc_comment > 0 ) : # we remember the comment, without the comment flag, and without the end of line cmt_string = inp_net_line [ loc_comment+1 : -1 ] else : cmt_string = "" # see if there is something to translate, i.e. string within <> # appearing before any comment flag loc_res_start = string.find ( inp_net_line, char_res_delim_start) loc_res_end = string.find ( inp_net_line, char_res_delim_end ) if ( ( loc_res_start > 0 ) # there is a resource starting character and ( loc_res_end > loc_res_start ) # there is a resource ending character after the starting character and ( ( loc_comment < 0 ) # there is no comment... or ( loc_res_end < loc_comment ) ) ) : # ...or the comment starts after the resource field # now we have the fpga signal name that was on the line res_string = inp_net_line [ loc_res_start+1 : loc_res_end ] # We also need the net name to write the UCF file loc_net_start = string.find ( inp_net_line, char_net_delim ) loc_net_end = string.find ( inp_net_line[loc_net_start+1:], char_net_delim ) + loc_net_start+1 if ( ( loc_net_start > 0 ) and ( loc_net_end > loc_net_start) ) : # now we have the net name net_string = inp_net_line [ loc_net_start+1 : loc_net_end ] #print "INFO: found net <%s> using resource <%s> at line #%d" % ( net_string , # res_string, # line_num ) else : net_string = "" out_net_line = "%s *** Error *** \n" % ( inp_net_line[:-1] ) status = "ERROR: no net name found at line #%d" % line_num print status app_logfile.write ( "%s\n" % status ) status = ".....: %s " % inp_net_line print status app_logfile.write ( "%s\n" % status ) # check if we have a match for that resource name and retrieve the pin ID if ( r2p_dict.has_key( res_string ) ) : pin_string = r2p_dict [ res_string ] # remember that we used this entry r2p_usage [ res_string ] += 1 else : pin_string = "" out_net_line = "%s *** Error *** \n" % ( inp_net_line[:-1] ) status = "ERROR: resource <%s> not in dictionary at line #%d " % ( res_string, line_num ) print status app_logfile.write ( "%s\n" % status ) status = ".....: %s " % inp_net_line print status app_logfile.write ( "%s\n" % status ) # if we have a net name and resource name, # we are now ready to generate the output lines if ( ( len(net_string) > 0 ) and ( len(pin_string) > 0 ) ) : pad_string = ( 12 - len(pin_string) ) * " " # the output net line will be writen outside of the IF out_net_line = "%s%s%s #%s %s\n" % ( inp_net_line[:loc_res_start], pin_string, pad_string, cmt_string, res_string ) # the output UCF line needs to be written now out_ucf_lines = '// %s \n NET "%s" LOC = "%s";\n\n' % ( res_string, net_string, pin_string ) out_ucf.write ( out_ucf_lines ) #else : # there was a problem either finding a net name or a resource name, # it was flagged and we do not change the input line #else: # this was a NET line but there was nothing to translate #else : # the line did not start with NET, no change # write the input line to the output file, whether it was edited or not out_netlist.write ( out_net_line ) # done with input and output files #-------------------------------- inp_netlist.close() out_netlist.close() out_ucf.close() # now look for any dictionary entry # that was left unused, or used multiple times #-------------------------------- status = "Starting Resource Usage Consistency Check" print status app_logfile.write ( "\n%s\n" % status ) ok_tot = 0 unused_tot = 0 unused_str = "" multip_tot = 0 multip_str = "" # scan all usage entries for r2p_dict_entry in r2p_dict : if ( r2p_usage [ r2p_dict_entry ] == 0 ) : unused_tot += 1 unused_str = "%s (%d time) %s \n" % (unused_str, r2p_usage [ r2p_dict_entry ], r2p_dict_entry ) if ( r2p_usage [ r2p_dict_entry ] == 1 ) : ok_tot += 1 if ( r2p_usage [ r2p_dict_entry ] > 1 ) : multip_tot += 1 multip_str = "%s (%d time) %s \n" % (multip_str, r2p_usage [ r2p_dict_entry ], r2p_dict_entry ) # Now report result status = "Matched %d Resources to Pins" % ok_tot print status app_logfile.write ( "%s\n" % status ) if ( multip_tot == 0 ) : status = "No Resource dictionary item was used multiple times" print status app_logfile.write ( "%s\n" % status ) else : status = "%d Resource dictionary items were ***used multiple times***:" % multip_tot print status print "-->Check <%s> for list of multiply used resources" % log_file_name app_logfile.write ( "%s\n" % status ) app_logfile.write ( "%s\n" % multip_str ) if ( unused_tot == 0 ) : status = "No Resource dictionary item was left unused" print status app_logfile.write ( "%s\n" % status ) else : status = "%d Resource dictionary items were left unused:" % unused_tot print status print "-->Check <%s> for list of unused resources" % log_file_name app_logfile.write ( "%s\n" % status ) app_logfile.write ( "%s\n" % unused_str ) # Done #-------------------------------- status = "Done\n" print status app_logfile.write ( "\n%s\n" % status )