From 89abe7ad471b2de7fb12d03f87d850377bc2fb37 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Mon, 30 Sep 2019 16:56:49 +0200 Subject: [PATCH] Modified 034 to manually force routing through specific PIPs and exclude PPIPs from segdata. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/bits.dbf | 3 +- fuzzers/034-cmt-pll-pips/generate.py | 47 +++++-- fuzzers/034-cmt-pll-pips/generate.tcl | 93 ++++++++++++- fuzzers/034-cmt-pll-pips/top.py | 182 +++++++++++++++++++------- fuzzers/Makefile | 2 +- 5 files changed, 261 insertions(+), 66 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/bits.dbf b/fuzzers/034-cmt-pll-pips/bits.dbf index ad502de5..277920bb 100644 --- a/fuzzers/034-cmt-pll-pips/bits.dbf +++ b/fuzzers/034-cmt-pll-pips/bits.dbf @@ -1,7 +1,8 @@ -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_CLKIN1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN1_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_CLKIN1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN2_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_CLKIN2 +28_43 29_42 29_43 28_44 + diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index 0b6243f3..d6118dc0 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -17,25 +17,37 @@ def main(): tiledata = {} pipdata = {} + ppipdata = {} ignpip = set() - with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', - 'cmt_top', 'cmt_top_l_upper_t.txt')) as f: - for l in f: - tile_type, dst, src = l.strip().split('.') - if tile_type not in pipdata: - pipdata[tile_type] = [] + # Load PIP lists + piplists = ['cmt_top_l_upper_t.txt', 'cmt_top_r_upper_t.txt'] + for piplist in piplists: + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', 'cmt_top', piplist)) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] - pipdata[tile_type].append((src, dst)) + pipdata[tile_type].append((src, dst)) - with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', - 'cmt_top', 'cmt_top_r_upper_t.txt')) as f: - for l in f: - tile_type, dst, src = l.strip().split('.') - if tile_type not in pipdata: - pipdata[tile_type] = [] + # Load PPIP lists (to exclude them) + ppiplists = ['ppips_cmt_top_l_upper_t.db', 'ppips_cmt_top_r_upper_t.db'] + for ppiplist in ppiplists: + fname = os.path.join(os.getenv('FUZDIR'), '..', '071-ppips', 'build', ppiplist) + with open(fname, 'r') as f: + for l in f: + pip_data, pip_type = l.strip().split() - pipdata[tile_type].append((src, dst)) + print(pip_data, pip_type) + if pip_type != 'always': + continue + + tile_type, dst, src = pip_data.split('.') + if tile_type not in ppipdata: + ppipdata[tile_type] = [] + + ppipdata[tile_type].append((src, dst)) print("Loading tags from design.txt.") with open("design.txt", "r") as f: @@ -47,6 +59,8 @@ def main(): if 'UPPER_B' in tile: continue + if 'LOWER_T' in tile: + continue pip_prefix, _ = pip.split(".") tile_from_pip, tile_type = pip_prefix.split('/') @@ -76,6 +90,11 @@ def main(): dst.startswith('CMT_TOP_L_UPPER_T_CLK'): ignpip.add((src, dst)) + # Ignore pseudo pips + for ppip in ppipdata[tile_type]: + if ppip == (src, dst): + ignpip.add((src, dst, )) + for tile, pips_srcs_dsts in tiledata.items(): tile_type = pips_srcs_dsts["type"] pips = pips_srcs_dsts["pips"] diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl index 502a0ec2..c28e7492 100644 --- a/fuzzers/034-cmt-pll-pips/generate.tcl +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -23,6 +23,93 @@ proc write_pip_txtdata {filename} { close $fp } +proc load_routes {filename} { + puts "MANROUTE: Loading routes from $filename" + + set fp [open $filename r] + foreach line [split [read $fp] "\n"] { + if {$line eq ""} { + continue + } + + puts "MANROUTE: Line: $line" + + # Parse the line + set fields [split $line " "] + set tile_name [lindex $fields 0] + set site_name [lindex $fields 1] + set pin_name [lindex $fields 2] + set route_dir [lindex $fields 3] + set wires [lrange $fields 4 end] + + # Get net + set tile [get_tiles $tile_name] + set site [get_sites -of_objects $tile $site_name] + set pin [get_site_pins -of_objects $site "*/$pin_name"] + set net [get_nets -quiet -of_objects $pin] + + if {$net eq "" } { + puts "MANROUTE: No net for pin $pin_name found! Skipping..." + continue + } + + # Fixed part read from file + set route_list {} + foreach wire $wires { + lappend route_list [get_nodes -of_objects [get_wires -of_objects $tile "*/$wire"]] + } + + # Complete the route + if {$route_dir eq "up"} { + set node_to [lindex $route_list 0] + set node_from [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + + set rpart [find_routing_path -from $node_from -to $node_to] + if {$rpart eq ""} { + puts "MANROUTE: No possible route continuation for net $net" + continue + } + + set route_list [concat [lrange $rpart 0 end-1] $route_list] + } + + if {$route_dir eq "down"} { + set node_from [lindex $route_list e] + set node_to [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] + + set rpart [find_routing_path -from $node_from -to $node_to] + if {$rpart eq ""} { + puts "MANROUTE: No possible route continuation for net $net" + continue + } + set route_list [concat $route_list [lrange $rpart 1 end]] + } + + # Set the fixed route + puts "MANROUTE: Net: $net, Route: $route_list. routing..." + regsub -all {{}} $route_list "" route + set_property FIXED_ROUTE $route $net + + # Route the single net. Needed to detect conflicts when evaluating + # other ones + route_design -quiet -nets $net + + # Check for conflicts. + set status [get_property ROUTE_STATUS $net] + if {$status ne "ROUTED"} { + # Ripup and discard the fixed route. + set_property FIXED_ROUTE "" $net + route_design -unroute -nets $net + puts "MANROUTE: Net $net status $status, ripping up..." + } else { + set_property IS_ROUTE_FIXED 1 $net + puts "MANROUTE: Successful manual route for $net" + } + } + + close $fp +} + proc run {} { create_project -force -part $::env(XRAY_PART) design design read_verilog top.v @@ -47,7 +134,11 @@ proc run {} { set_property IS_ENABLED 0 [get_drc_checks {REQP-13}] place_design - route_design + + load_routes routes.txt + write_checkpoint -force design_pre_route.dcp + + route_design -preserve write_checkpoint -force design.dcp write_bitstream -force design.bit diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index c26cba32..159bee37 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -39,7 +39,56 @@ def gen_sites(): for site_name, site_type in gridinfo.sites.items(): if site_type in ['PLLE2_ADV']: phasers = find_phasers_for_pll(grid, loc) - yield site_name, phasers + yield tile_name, site_name, phasers + + +def get_random_route_from_site_pin(db, tile_name, site_name, site_pin, direction, occupied_wires): + + grid = db.grid() + tile = db.tilegrid[tile_name] + tile_type = tile["type"] + site_type = tile["sites"][site_name] + + tile = db.get_tile_type(tile_type) + site = [s for s in tile.get_sites() if s.type == site_type][0] # FIXME: find correct site by vivado loc + + # Find site wire + wire = None + for pin in site.site_pins: + if pin.name == site_pin: + wire = pin.wire + break + assert wire is not None + + # Walk randomly over not occupied wires. + route = [] + while True: + route.append(wire) + + wires = [] + + for pip in tile.pips: + if direction == "down" and pip.net_from == wire: + next_wire = pip.net_to + elif direction == "up" and pip.net_to == wire: + next_wire = pip.net_from + else: + continue + + if next_wire not in occupied_wires: + wires.append(next_wire) + + if len(wires) == 0: + break + + wire = random.choice(wires) + occupied_wires.add(wire) + + # For "up" direction reverse the route. + if direction == "down": + return route + if direction == "up": + return route[::-1] def main(): @@ -50,16 +99,61 @@ module top(); LUT6 dummy(); ''') + db = Database(util.get_db_root()) bufg_count = 0 - for site, phasers in sorted(gen_sites(), key=lambda x: x[0]): - drive_feedback = random.randint(0, 1) - clkfbin_src = random.choice(('BUFH', '0', '1', None)) + routes_file = open('routes.txt', 'w') - if drive_feedback: + for tile, site, phasers in sorted(gen_sites(), key=lambda x: x[0]): + + # Generate random routes to/from some pins + routes = {} + endpoints = {} + + pins = [ +# ('CLKIN1', 'up'), +# ('CLKIN2', 'up'), + ('CLKFBIN', 'up'), + ('CLKFBOUT', 'down'), +# ('CLKOUT0', 'down'), +# ('CLKOUT1', 'down'), +# ('CLKOUT2', 'down'), +# ('CLKOUT3', 'down'), + ] + + occupied_wires = set() + for pin, dir in pins: + + route = get_random_route_from_site_pin(db, tile, site, pin, dir, occupied_wires) + if route is None: + endpoints[pin] = "" + continue + + routes[pin] = (route, dir,) + endpoints[pin] = route[-1] if dir == 'down' else route[0] + + internal_feedback = endpoints['CLKFBOUT'].endswith('CLKFBIN') + if internal_feedback: + del routes['CLKFBIN'] + + # Store them in random order so the TCL script will try to route + # in random order. + lines = [] + for pin, (route, dir,) in routes.items(): + + route_str = " ".join(route) + lines.append('{} {} {} {} {}\n'.format(tile, site, pin, dir, route_str)) + + random.shuffle(lines) + routes_file.writelines(lines) + + #clkfbin_src = random.choice(('BUFH', '0', '1', 'logic', None)) + clkfbin_src = random.choice(('BUFH', 'logic')) + + if internal_feedback: COMPENSATION = "INTERNAL" else: - if clkfbin_src in ['0', '1']: + if clkfbin_src == 'logic': COMPENSATION = 'EXTERNAL' else: COMPENSATION = "ZHOLD" @@ -141,30 +235,12 @@ module top(); .FREQREFCLK(clkout{idx}_{site}) );""".format(idx=clkout, site=site, phaser_loc=phasers['OUT'][0])) - drive_bufg = random.randint(0, 1) and bufg_count < 16 - - if drive_bufg and clkfbin_src not in ['BUFH', 'BUFR']: - bufg_count += 1 - print( - """ - (* KEEP, DONT_TOUCH *) - BUFG ( - .I(clkfbout_mult_{site}) - );""".format(site=site)) - - if drive_feedback: - print( - """ - assign clkfbin_{site} = clkfbout_mult_{site}; - """.format(site=site)) + if internal_feedback: + print(""" + assign clkfbin_{site} = clkfbout_mult_{site}; + """.format(site=site)) else: - # If CLKFBIN is not using CLKFBOUT feedback, can be connected to: - # - BUFHCE/BUFR using dedicated path - # - Switch box clock port - - if clkfbin_src is None: - pass - elif clkfbin_src == 'BUFH': + if clkfbin_src == 'BUFH': print( """ (* KEEP, DONT_TOUCH *) @@ -172,26 +248,25 @@ module top(); .I(clkfbout_mult_{site}), .O(clkfbin_{site}) );""".format(site=site)) - elif clkfbin_src == 'BUFR': - print( - """ - (* KEEP, DONT_TOUCH *) - BUFR ( - .I(clkfbout_mult_{site}), - .O(clkfbin_{site}) - );""".format(site=site)) elif clkfbin_src == '0': - print( - """ - assign clkfbin_{site} = 0; + print(""" + assign clkfbin_{site} = 1'b0; """.format(site=site)) elif clkfbin_src == '1': - print( - """ - assign clkfbin_{site} = 1; + print(""" + assign clkfbin_{site} = 1'b1; + """.format(site=site)) + elif clkfbin_src is None: + pass + elif clkfbin_src == 'logic': + print(""" + (* KEEP, DONT_TOUCH *) + LUT6 # (.INIT(64'h5555555555555555)) + clkfbin_logic_{site} ( + .I0(clkfbout_mult_{site}), + .O(clkfbin_{site}) + ); """.format(site=site)) - else: - assert False, clkfbin_src clkin_is_none = False @@ -199,9 +274,10 @@ module top(); clkin_src = random.choice(( 'BUFH', 'BUFR', - '0', - '1', - None, +# '0', +# '1', + 'logic', +# None, )) if clkin == 1 and clkin_is_none and clkin_src is None: clkin_src = 'BUFH' @@ -232,8 +308,16 @@ module top(); """ assign clkin{idx}_{site} = 1; """.format(idx=clkin + 1, site=site)) + elif clkin_src == 'logic': + print(""" + (* KEEP, DONT_TOUCH *) + LUT6 # (.INIT(64'h5555555555555555)) + clkin{idx}_logic_{site} ( + .O(clkin{idx}_{site}) + ); + """.format(idx=clkin + 1, site=site)) else: - assert False, clkfbin_src + assert False, clkin_src print("endmodule") diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 29c98e8e..3b13875b 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -84,7 +84,7 @@ $(eval $(call fuzzer,028-fifo-config,005-tilegrid)) $(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid)) $(eval $(call fuzzer,030-iob,005-tilegrid)) $(eval $(call fuzzer,032-cmt-pll,005-tilegrid)) -$(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid)) +$(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid,071-ppips)) $(eval $(call fuzzer,035-iob-ilogic,005-tilegrid)) $(eval $(call fuzzer,035a-iob-idelay,005-tilegrid)) $(eval $(call fuzzer,036-iob-ologic,005-tilegrid))