====== PrimeTime Min Delay (Hold Violation) Fix ====== To using this script, we should using script [[vlsi:pt:report]] to generate reports. #! /tools/cfr/bin/python import os import sys import re import time from collections import defaultdict def get_all_hold_rpt(): modes = 'func mbist bisr scan merged'.split(' ') corners = 'max maxlt min minht maxrc minrc'.split(' ') content = "" print "\nReading hold timing reports:" for mode in modes: for corner in corners: ddir = "postlayout_%s_%s" % (mode, corner) file_name = "hfbi_%s_%s_hold.rpt" % (mode, corner) file_name = "zgdh_timing_hold_reg2reg_startend.rpt" vio_file = os.path.join(ddir, file_name) if os.path.exists(vio_file): print " Reading File: %s" % vio_file content += open(os.path.join(ddir, file_name)).read() #break #break return content def get_all_violators(): modes = 'func mbist bisr scan merged'.split(' ') corners = 'max maxlt min minht maxrc minrc'.split(' ') content = "" for mode in modes: for corner in corners: ddir = "postlayout_%s_%s" % (mode, corner) file_name = "uld_eti_%s_%s_all_violators.rpt" % (mode, corner) content += open(os.path.join(ddir, file_name)).read() return content def get_hold_vio_dict(all_violators): patt = """min_delay/hold \('reg2reg' group\)\s+Endpoint.*?\n\n""" all_hold_vio = re.findall(patt, all_violators, re.DOTALL) hold_endpoints_slack_dic = defaultdict(list) for line in "\n".join(all_hold_vio).split("\n"): line = line.strip() if line.find("(VIOLATED") >= 0: fields = re.split("\s+", line) endpoint = fields[0] hold_endpoints_slack_dic[endpoint].append(fields[1]) return hold_endpoints_slack_dic def get_slack_from_path(timing_path): patt="""slack \(VIOLATED\)\s+(-?[\d\.]+)""" slacks = re.findall(patt, timing_path, re.DOTALL) slack = None if slacks: slack = float(slacks[0]) return slack def remove_hier_net_pin(timing_rpt): new_rpt = "" lines = timing_rpt.split("\n") for line in lines: line_tmp = line.strip() if line_tmp.endswith("(net)"): # remove hier nets continue else: fields = line_tmp.split() if len(fields) == 7 and fields[2] == '0.00000' and fields[3] == '0.00000': # remove hier pins #print fields continue new_rpt += "%s\n" % line return new_rpt def get_hold_fix_pin(timing_path): point_patt = """(\S+) \((\S+)\)\s+([\d\.]+)""" data_arrival_index = timing_path.find('data arrival time') data_path = timing_path[:data_arrival_index] all_points = re.findall(point_patt, data_path, re.DOTALL) all_points.reverse() hold_fix_pin = "" for index, point_type_fanout in enumerate(all_points): #print point_type_fanout point, type, fanout = point_type_fanout if type == 'net': if fanout.find('.') == -1: if int(fanout) > 1: hold_fix_pin = all_points[index-1][0] break elif int(fanout) == 1: hold_fix_pin = all_points[index-1][0] #print hold_fix_pin return hold_fix_pin def get_hold_fix_pin_slacks(timing_path_rpt): patt = """Startpoint.*?-+\n\s+clock.*?slack \(VIOLATED\)\s+-[\d\.]+""" timing_paths = re.findall(patt, timing_path_rpt, re.DOTALL) count = 0; path_num = len(timing_paths) hold_fix_pin_slacks = defaultdict(list) print "Total %d timing paths to fix." % path_num for timing_path in timing_paths: hold_fix_pin = get_hold_fix_pin(timing_path) hold_slack = get_slack_from_path(timing_path) #print '\n',hold_fix_pin, hold_slack hold_fix_pin_slacks[hold_fix_pin].append( hold_slack ) count += 1 if count % 500 == 0: print "Process timing path %d in %d, %s" % ( count, path_num, time.strftime("%a, %d %b %Y %H:%M:%S") ) #print "Process timing path %d " % ( count) #break return hold_fix_pin_slacks def gen_hold_fix_cmd (hold_fix_pin_slacks): #buf_030 = "g65lxp/BUFM3LXP" #buf_050 = "g65xpipo/HDEL100XP" #buf_120 = "g65xpipo/HDEL200XP" hold_fix_cmd = """ # lib file: # /lsi/soft/lsi/fs/5.0/lsi_fs_5.0/lib3p/liberty/g65/ccs/g65lxp_lsiB_105V_125C.lib # /lsi/soft/lsi/fs/5.0/lsi_fs_5.0/lib3p/liberty/g65/ccs/g65xpipo_lsiB_105V_125C.lib set buf_030 {g65lxp/BUFM3LXP} ;# 0.0475800, 0.0445400 set buf_070 {g65xpipo/HDEL100XP} ;# 0.0731400, 0.0748000 set buf_170 {g65xpipo/HDEL200XP} ;# 0.176280, 0.182230 ####;initial list set hold_fix_pin_0 {}; # ~ 0.01 set hold_fix_pin_03 {}; # 0.01 ~ 0.03 set hold_fix_pin_05 {}; # 0.03 ~ 0.05 set hold_fix_pin_07 {}; # 0.05 ~ 0.07 set hold_fix_pin_09 {}; # 0.07 ~ 0.09 set hold_fix_pin_12 {}; # 0.09 ~ 0.12 set hold_fix_pin_14 {}; # 0.12 ~ 0.14 set hold_fix_pin_17 {}; # 0.14 ~ 0.18 set hold_fix_pin_20 {}; # > 0.18 set hold_fix_pin_9 {}; # """ for pin, slacks in hold_fix_pin_slacks.items(): slacks.sort() wslack = -slacks[0] if wslack < 0.01: #hold_fix_cmd += "# lappend hold_fix_pin_0 %s\n" % pin pass elif wslack < 0.03: hold_fix_cmd += "lappend hold_fix_pin_03 %s\n" % pin elif wslack < 0.05: hold_fix_cmd += "lappend hold_fix_pin_05 %s\n" % pin elif wslack < 0.07: hold_fix_cmd += "lappend hold_fix_pin_07 %s\n" % pin elif wslack < 0.09: hold_fix_cmd += "lappend hold_fix_pin_09 %s\n" % pin elif wslack < 0.12: hold_fix_cmd += "lappend hold_fix_pin_12 %s\n" % pin elif wslack < 0.14: hold_fix_cmd += "lappend hold_fix_pin_14 %s\n" % pin elif wslack < 0.17: hold_fix_cmd += "lappend hold_fix_pin_17 %s\n" % pin else: # hold_fix_cmd += "lappend hold_fix_pin_20 %s\n" % pin #print slacks[0], slacks[-1], len(slacks), pin hold_fix_cmd += "\n\n\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_03 $buf_030\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_05 $buf_070\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_07 $buf_070\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_09 $buf_170\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_12 $buf_170\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_14 $buf_170\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_17 $buf_170\n" hold_fix_cmd += "insert_buffer $hold_fix_pin_20 $buf_170\n" return hold_fix_cmd if __name__ == "__main__": all_hold_rpt_file = "all_hold_timing_path.rpt" if len(sys.argv) == 2: all_hold_rpt = open(sys.argv[1]).read() elif len(sys.argv) == 1: all_hold_rpt = get_all_hold_rpt() print "\nSave all hold timing report to file: %s" % all_hold_rpt_file open(all_hold_rpt_file, 'w').write(all_hold_rpt) print "Remove hier nets & pins in timing report" all_hold_rpt = remove_hier_net_pin(all_hold_rpt) #print "Save refined timing report" #open(all_hold_rpt_file+'.refine', 'w').write(all_hold_rpt) print "Get hold fix pins and slacks in timing rpt" hold_fix_pin_slacks = get_hold_fix_pin_slacks(all_hold_rpt) print "Write hold slacks & fix pin data" contents = [] for pin, slacks in hold_fix_pin_slacks.items(): slacks.sort() line = "%.5f, %2d, %s" % (slacks[0], len(slacks), pin) contents.append(line) contents.sort() contents[0:0] = ["hold-slack, path-number, pin"] open('all_hold_fix_pins.rpt','w').write("\n".join(contents)) fix_cmd = gen_hold_fix_cmd(hold_fix_pin_slacks) open('hold_fix.tcl','w').write(fix_cmd)