From 89abe7ad471b2de7fb12d03f87d850377bc2fb37 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Mon, 30 Sep 2019 16:56:49 +0200 Subject: [PATCH 01/14] 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)) From 205bc5c1df6480b8d1efde4dfa6c498390026d39 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 1 Oct 2019 17:42:12 +0200 Subject: [PATCH 02/14] Code formatting. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/generate.py | 11 ++-- fuzzers/034-cmt-pll-pips/generate.tcl | 2 +- fuzzers/034-cmt-pll-pips/top.py | 72 ++++++++++++++++----------- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index d6118dc0..3e37c246 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -23,7 +23,8 @@ def main(): # 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: + 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: @@ -34,7 +35,8 @@ def main(): # 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) + 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() @@ -93,7 +95,10 @@ def main(): # Ignore pseudo pips for ppip in ppipdata[tile_type]: if ppip == (src, dst): - ignpip.add((src, dst, )) + ignpip.add(( + src, + dst, + )) for tile, pips_srcs_dsts in tiledata.items(): tile_type = pips_srcs_dsts["type"] diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl index c28e7492..f58587df 100644 --- a/fuzzers/034-cmt-pll-pips/generate.tcl +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -100,7 +100,7 @@ proc load_routes {filename} { # Ripup and discard the fixed route. set_property FIXED_ROUTE "" $net route_design -unroute -nets $net - puts "MANROUTE: Net $net status $status, ripping up..." + puts "MANROUTE: Net $net status $status, ripping up..." } else { set_property IS_ROUTE_FIXED 1 $net puts "MANROUTE: Successful manual route for $net" diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index 159bee37..d58b492d 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -42,7 +42,8 @@ def gen_sites(): yield tile_name, site_name, phasers -def get_random_route_from_site_pin(db, tile_name, site_name, site_pin, direction, occupied_wires): +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] @@ -50,7 +51,8 @@ def get_random_route_from_site_pin(db, tile_name, site_name, site_pin, direction 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 + 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 @@ -76,11 +78,11 @@ def get_random_route_from_site_pin(db, tile_name, site_name, site_pin, direction continue if next_wire not in occupied_wires: - wires.append(next_wire) + wires.append(next_wire) if len(wires) == 0: break - + wire = random.choice(wires) occupied_wires.add(wire) @@ -111,38 +113,46 @@ module top(); endpoints = {} pins = [ -# ('CLKIN1', 'up'), -# ('CLKIN2', 'up'), + # ('CLKIN1', 'up'), + # ('CLKIN2', 'up'), ('CLKFBIN', 'up'), ('CLKFBOUT', 'down'), -# ('CLKOUT0', 'down'), -# ('CLKOUT1', 'down'), -# ('CLKOUT2', 'down'), -# ('CLKOUT3', '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) + 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,) + routes[pin] = ( + route, + dir, + ) endpoints[pin] = route[-1] if dir == 'down' else route[0] internal_feedback = endpoints['CLKFBOUT'].endswith('CLKFBIN') - if internal_feedback: + 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(): + for pin, ( + route, + dir, + ) in routes.items(): route_str = " ".join(route) - lines.append('{} {} {} {} {}\n'.format(tile, site, pin, dir, route_str)) + lines.append( + '{} {} {} {} {}\n'.format(tile, site, pin, dir, route_str)) random.shuffle(lines) routes_file.writelines(lines) @@ -236,7 +246,8 @@ module top(); );""".format(idx=clkout, site=site, phaser_loc=phasers['OUT'][0])) if internal_feedback: - print(""" + print( + """ assign clkfbin_{site} = clkfbout_mult_{site}; """.format(site=site)) else: @@ -249,17 +260,20 @@ module top(); .O(clkfbin_{site}) );""".format(site=site)) elif clkfbin_src == '0': - print(""" + print( + """ assign clkfbin_{site} = 1'b0; """.format(site=site)) elif clkfbin_src == '1': - print(""" + print( + """ assign clkfbin_{site} = 1'b1; """.format(site=site)) elif clkfbin_src is None: pass elif clkfbin_src == 'logic': - print(""" + print( + """ (* KEEP, DONT_TOUCH *) LUT6 # (.INIT(64'h5555555555555555)) clkfbin_logic_{site} ( @@ -271,14 +285,15 @@ module top(); clkin_is_none = False for clkin in range(2): - clkin_src = random.choice(( - 'BUFH', - 'BUFR', -# '0', -# '1', - 'logic', -# None, - )) + clkin_src = random.choice( + ( + 'BUFH', + 'BUFR', + # '0', + # '1', + 'logic', + # None, + )) if clkin == 1 and clkin_is_none and clkin_src is None: clkin_src = 'BUFH' @@ -309,7 +324,8 @@ module top(); assign clkin{idx}_{site} = 1; """.format(idx=clkin + 1, site=site)) elif clkin_src == 'logic': - print(""" + print( + """ (* KEEP, DONT_TOUCH *) LUT6 # (.INIT(64'h5555555555555555)) clkin{idx}_logic_{site} ( From a4250c14872bdd32664e7a838ab04a4ffe7ed9c8 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Wed, 2 Oct 2019 09:20:32 +0200 Subject: [PATCH 03/14] Comments. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/top.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index d58b492d..d562a3be 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -113,14 +113,25 @@ module top(); endpoints = {} pins = [ - # ('CLKIN1', 'up'), - # ('CLKIN2', 'up'), + # Enabling random manual routing for CLKINx breaks solution for + # tags: + # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT + # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT + + #('CLKIN1', 'up'), + #('CLKIN2', 'up'), + + # This works: ('CLKFBIN', 'up'), ('CLKFBOUT', 'down'), - # ('CLKOUT0', 'down'), - # ('CLKOUT1', 'down'), - # ('CLKOUT2', 'down'), - # ('CLKOUT3', 'down'), + + # Sometimes manually randomized route for CLKOUTx conflicts with + # the verilog design. Need to fix that in the future. + + #('CLKOUT0', 'down'), + #('CLKOUT1', 'down'), + #('CLKOUT2', 'down'), + #('CLKOUT3', 'down'), ] occupied_wires = set() From f88a1d54b8543f242dd46da43d1adc01d18bfcdd Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Wed, 2 Oct 2019 14:16:42 +0200 Subject: [PATCH 04/14] Fixed makefile Signed-off-by: Maciej Kurc --- fuzzers/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 3b13875b..72921655 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,071-ppips)) +$(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)) From 56258694aa31b1f9c54aee240c951674d9649700 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 10 Oct 2019 13:18:07 +0200 Subject: [PATCH 05/14] Added rejection of conflicting features. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/Makefile | 2 +- fuzzers/034-cmt-pll-pips/bits.dbf | 3 ++- fuzzers/034-cmt-pll-pips/generate.py | 37 +++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile index 03771b89..75ec003e 100644 --- a/fuzzers/034-cmt-pll-pips/Makefile +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -8,7 +8,7 @@ MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type c else MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE) endif -N = 50 +N = 100 A_PIPLIST=cmt_top_l_upper_t.txt diff --git a/fuzzers/034-cmt-pll-pips/bits.dbf b/fuzzers/034-cmt-pll-pips/bits.dbf index 277920bb..42dfeb37 100644 --- a/fuzzers/034-cmt-pll-pips/bits.dbf +++ b/fuzzers/034-cmt-pll-pips/bits.dbf @@ -1,8 +1,9 @@ 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_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_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 +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN 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 3e37c246..8ae86c41 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -3,7 +3,8 @@ from prjxray.segmaker import Segmaker import os import os.path - +import itertools +import random def bitfilter(frame, word): if frame <= 1: @@ -100,17 +101,21 @@ def main(): dst, )) + tags = {} for tile, pips_srcs_dsts in tiledata.items(): tile_type = pips_srcs_dsts["type"] pips = pips_srcs_dsts["pips"] + if tile not in tags: + tags[tile] = {} + for src, dst in pipdata[tile_type]: if (src, dst) in ignpip: pass elif (src, dst) in pips: - segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1) + tags[tile]["%s.%s" % (dst, src)] = 1 elif (src, dst) not in tiledata[tile]["pips"]: - segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0) + tags[tile]["%s.%s" % (dst, src)] = 0 internal_feedback = False for src, dst in [ @@ -120,7 +125,31 @@ def main(): if (src, dst) in pips: internal_feedback = True - segmk.add_tile_tag(tile, "EXTERNAL_FEEDBACK", not internal_feedback) + tags[tile]["EXTERNAL_FEEDBACK"] = int(not internal_feedback) + + + # Those tags are exclusive. This is due to the fact that Vivado sometimes + # report routes that does not correspond to underlying bit configuration. + xored_tags = [ + ("CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN", + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT"), + ("CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN", + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT"), + ] + + for tile in tags.keys(): + for pair in xored_tags: + for tag_a, tag_b in itertools.permutations(pair, 2): + + if tag_a in tags[tile] and tag_b in tags[tile]: + if tags[tile][tag_a] == tags[tile][tag_b]: + d = tags[tile] + del d[tag_a] + del d[tag_b] + + for tile, tile_tags in tags.items(): + for t, v in tile_tags.items(): + segmk.add_tile_tag(tile, t, v) segmk.compile(bitfilter=bitfilter) segmk.write() From 73c8652858e86b4c389268ac846c78fe3c0e2479 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 10 Oct 2019 13:31:15 +0200 Subject: [PATCH 06/14] Ran make format_py Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/generate.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index 8ae86c41..fd93cfd3 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -6,6 +6,7 @@ import os.path import itertools import random + def bitfilter(frame, word): if frame <= 1: return False @@ -127,14 +128,17 @@ def main(): tags[tile]["EXTERNAL_FEEDBACK"] = int(not internal_feedback) - # Those tags are exclusive. This is due to the fact that Vivado sometimes # report routes that does not correspond to underlying bit configuration. xored_tags = [ - ("CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT"), - ("CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT"), + ( + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN", + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT" + ), + ( + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN", + "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT" + ), ] for tile in tags.keys(): From 4a6930694f39fd314cf2219cfca5ae05edf1d939 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 11 Oct 2019 15:42:26 +0200 Subject: [PATCH 07/14] Reworked fuzzer, added README.md Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/Makefile | 16 +- fuzzers/034-cmt-pll-pips/README.md | 20 ++ fuzzers/034-cmt-pll-pips/bits.dbf | 9 - fuzzers/034-cmt-pll-pips/fixup_and_group.py | 222 ++++++++++++++++++++ fuzzers/034-cmt-pll-pips/generate.py | 98 ++++----- fuzzers/034-cmt-pll-pips/generate.tcl | 6 +- fuzzers/034-cmt-pll-pips/tag_groups.txt | 13 ++ fuzzers/034-cmt-pll-pips/top.py | 116 +++++----- minitests/plle2_adv/basys3_plle2_adv.v | 7 +- minitests/plle2_adv/src/plle2_test.v | 14 +- minitests/plle2_adv/tcl/par.tcl | 2 +- 11 files changed, 378 insertions(+), 145 deletions(-) create mode 100644 fuzzers/034-cmt-pll-pips/README.md delete mode 100644 fuzzers/034-cmt-pll-pips/bits.dbf create mode 100755 fuzzers/034-cmt-pll-pips/fixup_and_group.py create mode 100644 fuzzers/034-cmt-pll-pips/tag_groups.txt diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile index 75ec003e..5efba883 100644 --- a/fuzzers/034-cmt-pll-pips/Makefile +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -8,7 +8,9 @@ MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type c else MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE) endif -N = 100 + +N = 80 +SEGMATCH_FLAGS=-m 10 -M 20 -c 170 A_PIPLIST=cmt_top_l_upper_t.txt @@ -30,14 +32,14 @@ RDBS += build/segbits_cmt_top_r_upper_t.rdb endif database: ${RDBS} - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_cmt_top_l_upper_t.rdb \ - --seg-fn-out build/segbits_cmt_top_l_upper_t.db + python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \ + -i build/segbits_cmt_top_l_upper_t.rdb \ + -o build/segbits_cmt_top_l_upper_t.db ifneq (${XRAY_DATABASE}, zynq7) - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_cmt_top_r_upper_t.rdb \ - --seg-fn-out build/segbits_cmt_top_r_upper_t.db + python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \ + -i build/segbits_cmt_top_r_upper_t.rdb \ + -o build/segbits_cmt_top_r_upper_t.db endif # Keep a copy to track iter progress diff --git a/fuzzers/034-cmt-pll-pips/README.md b/fuzzers/034-cmt-pll-pips/README.md new file mode 100644 index 00000000..50ffdee0 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/README.md @@ -0,0 +1,20 @@ +# Fuzzer for the PIPs of CMT_TOP_[LR]_UPPER_T tiles. + +The fuzzer instantiates a PLL in each available site with 2/3 probability of using it. Once used it is connected randomly to various clock and logic resources. + +For some nets a randomized "manual" route is chosen to cover as many routing scenarios as possible. + +The information whether a PLL is used or not is stored in a file (`"design.txt"`) along with the randomized route (`route.txt`) + +After the design synthesis the `generate.py` sets fixed routes on some nets which is read from the `route.txt` file. The rest of the design is routed in the regular way. The script also dumps all used PIPs (as reported by Vivado) to the `design_pips.txt`. + +The tag generation is done in the following way: + +- If a PLL site is occupied then tags for all active PIPs are emitted as 1s. No tags are emitted for inactive PIPs. +- When a PLL site is not occupied (IN_USE=0) then tags for all PIPs for the CMT tile are emitted as 0s. +- The IN_USE tag is emitted directly. + +The raw solution of tag bits is postprocessed via the custom script `fixup_and_group.py`. The script does two things: + +- Clears all bits found for the IN_USE tag in all other tags. Those bits are common to all of them. +- Groups tags according to the group definitions read from the `tag_groups.txt` file. Bits that are common to the group are set as 0 in each tag that belongs to it (tags within a group are exclusive). \ No newline at end of file diff --git a/fuzzers/034-cmt-pll-pips/bits.dbf b/fuzzers/034-cmt-pll-pips/bits.dbf deleted file mode 100644 index 42dfeb37..00000000 --- a/fuzzers/034-cmt-pll-pips/bits.dbf +++ /dev/null @@ -1,9 +0,0 @@ -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_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_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 -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN - -28_43 29_42 29_43 28_44 diff --git a/fuzzers/034-cmt-pll-pips/fixup_and_group.py b/fuzzers/034-cmt-pll-pips/fixup_and_group.py new file mode 100755 index 00000000..b005b05a --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/fixup_and_group.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +""" +This is a db fixup script that does two things: + +1. Clears (removes) all bits found in "IN_USE" tag(s) and removes the IN_USE + tag itself + +2. Reads tag group definition from a file and applies the tag grouping. First + a set of common bits for each group is found (logical OR among all tags + belonging to the group). Then in each tag belonging to the group those + bits are set to 0 but only if they are not already present there. + +The resulting data is written into a segbits file. +""" +import argparse +import re +import itertools + +# ============================================================================= + + +def load_tag_groups(file_name): + """ + Loads tag groups from a text file. + + A tag group is defined by specifying a space separated list of tags within + a single line. Lines that are empty or start with '#' are ignored. + """ + tag_groups = [] + + # Load tag group specifications + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + + if len(line) == 0 or line.startswith("#"): + continue + + group = set(line.split()) + if len(group): + tag_groups.append(group) + + # Check if all tag groups are exclusive + for tag_group_a, tag_group_b in itertools.combinations(tag_groups, 2): + + tags = tag_group_a & tag_group_b + if len(tags): + raise RuntimeError( + "Tag(s) {} are present in multiple groups".format( + " ".join(tags))) + + return tag_groups + + +# ============================================================================= + + +def parse_bit(bit): + """ + Decodes string describing a bit. Returns a tuple (frame, bit, value) + """ + match = re.match("^(!?)([0-9]+)_([0-9]+)$", bit) + assert match != None, bit + + val = int(match.group(1) != "!") + frm = int(match.group(2)) + bit = int(match.group(3)) + + return frm, bit, val + + +def bit_to_str(bit): + """ + Converts a tuple (frame, bit, value) to its string representation. + """ + s = "!" if not bit[2] else "" + return "{}{}_{}".format(s, bit[0], bit[1]) + + +def load_segbits(file_name): + """ + Loads a segbits file. + """ + + segbits = {} + + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + fields = line.split() + + if len(fields) < 2: + raise RuntimeError("Malformed line: '%s'" % line) + + tag = fields[0] + + if "<" in line or ">" in line: + segbits[tag] = set() + + else: + bits = set([parse_bit(bit) for bit in fields[1:]]) + segbits[tag] = bits + + return segbits + + +def save_segbits(file_name, segbits): + """ + Save segbits to a .db or .rdb file + """ + + with open(file_name, "w") as fp: + for tag, bits in segbits.items(): + if not len(bits): + continue + + line = tag + " " + line += " ".join([bit_to_str(bit) for bit in sorted(list(bits))]) + fp.write(line + "\n") + + +# ============================================================================= + + +def mask_out_bits(segbits, mask, tags_to_mask=None): + """ + Given a set of bits and a list of tags to affect (optional) removes all + the bits from each tag that are present (and equal) in the masking set. + """ + + if tags_to_mask is None: + tags_to_mask = segbits.keys() + + # Mask out matching bits + for tag in tags_to_mask: + bits = segbits[tag] + + bits = set(bits) - set(mask) + segbits[tag] = bits + + return segbits + + +def find_common_bits_for_tag_groups(segbits, tag_groups): + """ + For each tag group finds a common set of bits that have value of one. + """ + + bit_groups = [] + + for tag_group in tag_groups: + bit_group = set() + + for tag, bits in segbits.items(): + if tag in tag_group: + ones = set([b for b in bits if b[2]]) + bit_group |= ones + + bit_groups.append(bit_group) + + return bit_groups + + +def group_tags(segbits, tag_groups, bit_groups): + """ + Implements tag grouping. If a tag belongs to a group then the common bits + of that group are added to is as zeros. + """ + + for tag_group, bit_group in zip(tag_groups, bit_groups): + zeros = set([(b[0], b[1], 0) for b in bit_group]) + for tag in tag_group: + + # Insert zero bits + if tag in segbits.keys(): + bits = segbits[tag] + for z in zeros: + if not (z[0], z[1], 1) in bits: + bits.add(z) + + return segbits + + +# ============================================================================= + + +def main(): + + # Parse arguments + parser = argparse.ArgumentParser() + + parser.add_argument("-i", required=True, type=str, help="Input .rdb file") + parser.add_argument( + "-g", required=True, type=str, help="Input tag group definition file") + parser.add_argument("-o", required=True, type=str, help="Output .rdb file") + + args = parser.parse_args() + + # Load tag groups + tag_groups = load_tag_groups(args.g) + + # Load raw database file + segbits = load_segbits(args.i) + + # Mask out bits present in "IN_USE" tag(s) as they are common to other tags + for tag in segbits.keys(): + if tag.endswith("IN_USE"): + prefix = tag[:tag.index("IN_USE")] + tags_to_mask = [t for t in segbits.keys() if t.startswith(prefix)] + mask_out_bits(segbits, segbits[tag], tags_to_mask) + + # Find common bits + bit_groups = find_common_bits_for_tag_groups(segbits, tag_groups) + # Apply tag grouping + segbits = group_tags(segbits, tag_groups, bit_groups) + + # Save fixed database file + save_segbits(args.o, segbits) + + +if __name__ == "__main__": + main() diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index fd93cfd3..5bfe2ec0 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -4,11 +4,10 @@ from prjxray.segmaker import Segmaker import os import os.path import itertools -import random def bitfilter(frame, word): - if frame <= 1: + if frame < 28 or frame > 29: return False return True @@ -17,12 +16,14 @@ def bitfilter(frame, word): def main(): segmk = Segmaker("design.bits") + designdata = {} tiledata = {} pipdata = {} ppipdata = {} ignpip = set() # Load PIP lists + print("Loading 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', @@ -35,6 +36,7 @@ def main(): pipdata[tile_type].append((src, dst)) # Load PPIP lists (to exclude them) + print("Loading PPIP lists...") ppiplists = ['ppips_cmt_top_l_upper_t.db', 'ppips_cmt_top_r_upper_t.db'] for ppiplist in ppiplists: fname = os.path.join( @@ -43,7 +45,6 @@ def main(): for l in f: pip_data, pip_type = l.strip().split() - print(pip_data, pip_type) if pip_type != 'always': continue @@ -53,8 +54,14 @@ def main(): ppipdata[tile_type].append((src, dst)) - print("Loading tags from design.txt.") + # Load desgin data + print("Loading design data...") with open("design.txt", "r") as f: + for line in f: + fields = line.strip().split(",") + designdata[fields[0]] = fields[1:] + + with open("design_pips.txt", "r") as f: for line in f: tile, pip, src, dst, pnum, pdir = line.split() @@ -94,63 +101,50 @@ 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, - )) - tags = {} - for tile, pips_srcs_dsts in tiledata.items(): - tile_type = pips_srcs_dsts["type"] - pips = pips_srcs_dsts["pips"] + # Populate IN_USE tags + for tile, (site, in_use) in designdata.items(): if tile not in tags: tags[tile] = {} - for src, dst in pipdata[tile_type]: - if (src, dst) in ignpip: - pass - elif (src, dst) in pips: - tags[tile]["%s.%s" % (dst, src)] = 1 - elif (src, dst) not in tiledata[tile]["pips"]: - tags[tile]["%s.%s" % (dst, src)] = 0 - - internal_feedback = False - for src, dst in [ - ('CMT_TOP_L_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ('CMT_TOP_R_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ]: - if (src, dst) in pips: - internal_feedback = True - - tags[tile]["EXTERNAL_FEEDBACK"] = int(not internal_feedback) - - # Those tags are exclusive. This is due to the fact that Vivado sometimes - # report routes that does not correspond to underlying bit configuration. - xored_tags = [ - ( - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT" - ), - ( - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT" - ), - ] + tags[tile]["IN_USE"] = int(in_use) + # Populate PIPs for tile in tags.keys(): - for pair in xored_tags: - for tag_a, tag_b in itertools.permutations(pair, 2): + tile_type = tile.rsplit("_", maxsplit=1)[0] - if tag_a in tags[tile] and tag_b in tags[tile]: - if tags[tile][tag_a] == tags[tile][tag_b]: - d = tags[tile] - del d[tag_a] - del d[tag_b] + in_use = tags[tile]["IN_USE"] + internal_feedback = False + if not in_use: + active_pips = [] + else: + active_pips = tiledata[tile]["pips"] + + for src, dst in pipdata[tile_type]: + + if (src, dst) in ignpip: + continue + if (src, dst) in ppipdata[tile_type]: + continue + + tag = "{}.{}".format(dst, src) + val = in_use if (src, dst) in active_pips else False + + if not (in_use and not val): + tags[tile][tag] = int(val) + + for s, d in [ + ('CMT_TOP_L_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), + ('CMT_TOP_R_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), + ]: + if (s, d) in active_pips: + internal_feedback = in_use + + tags[tile]["INTERNAL_FEEDBACK"] = int(internal_feedback) + + # Output tags for tile, tile_tags in tags.items(): for t, v in tile_tags.items(): segmk.add_tile_tag(tile, t, v) diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl index f58587df..744cf8a0 100644 --- a/fuzzers/034-cmt-pll-pips/generate.tcl +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -92,7 +92,7 @@ proc load_routes {filename} { # Route the single net. Needed to detect conflicts when evaluating # other ones - route_design -quiet -nets $net + route_design -quiet -directive Quick -nets $net # Check for conflicts. set status [get_property ROUTE_STATUS $net] @@ -138,11 +138,11 @@ proc run {} { load_routes routes.txt write_checkpoint -force design_pre_route.dcp - route_design -preserve + route_design -directive Quick -preserve write_checkpoint -force design.dcp write_bitstream -force design.bit - write_pip_txtdata design.txt + write_pip_txtdata design_pips.txt } run diff --git a/fuzzers/034-cmt-pll-pips/tag_groups.txt b/fuzzers/034-cmt-pll-pips/tag_groups.txt new file mode 100644 index 00000000..afa81e6a --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/tag_groups.txt @@ -0,0 +1,13 @@ +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_CLKFBOUT2IN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_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_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB3 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_CLKIN2.CMT_TOP_L_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB3 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_CLKFBIN.CMT_TOP_R_CLKFBOUT2IN 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_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB3 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_CLKIN1.CMT_TOP_R_UPPER_T_CLKIN1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB3 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_CLKIN2.CMT_TOP_R_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB3 +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT + diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index d562a3be..55a12571 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -51,8 +51,9 @@ def get_random_route_from_site_pin( 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 + + # Assumption: there is only one PLL per tile. + site = [s for s in tile.get_sites() if s.type == site_type][0] # Find site wire wire = None @@ -62,7 +63,7 @@ def get_random_route_from_site_pin( break assert wire is not None - # Walk randomly over not occupied wires. + # Walk randomly. route = [] while True: route.append(wire) @@ -94,40 +95,47 @@ def get_random_route_from_site_pin( def main(): + + # 8 inputs per clock region + # 5 clock regions for device + max_clk_inputs = 8 * 5 + clkin_idx = 0 + print( ''' -module top(); +module top( + input wire [{nclkin}:0] clkin +); + (* KEEP, DONT_TOUCH *) LUT6 dummy(); - ''') + '''.format(nclkin=max_clk_inputs - 1)) db = Database(util.get_db_root()) bufg_count = 0 + design_file = open('design.txt', 'w') routes_file = open('routes.txt', 'w') for tile, site, phasers in sorted(gen_sites(), key=lambda x: x[0]): + in_use = random.randint(0, 2) > 0 + + design_file.write("{},{},{}\n".format(tile, site, int(in_use))) + + if not in_use: + continue # Generate random routes to/from some pins routes = {} endpoints = {} pins = [ - # Enabling random manual routing for CLKINx breaks solution for - # tags: - # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT - # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT - - #('CLKIN1', 'up'), - #('CLKIN2', 'up'), - - # This works: + ('CLKIN1', 'up'), + ('CLKIN2', 'up'), ('CLKFBIN', 'up'), - ('CLKFBOUT', 'down'), # Sometimes manually randomized route for CLKOUTx conflicts with - # the verilog design. Need to fix that in the future. - + # the verilog design. #('CLKOUT0', 'down'), #('CLKOUT1', 'down'), #('CLKOUT2', 'down'), @@ -149,12 +157,10 @@ module top(); ) endpoints[pin] = route[-1] if dir == 'down' else route[0] - internal_feedback = endpoints['CLKFBOUT'].endswith('CLKFBIN') - if internal_feedback: - del routes['CLKFBIN'] + internal_feedback = endpoints['CLKFBIN'].endswith('CLKFBOUT') - # Store them in random order so the TCL script will try to route - # in random order. + # Store them in a random order so the TCL script will try to route + # them also in the random order. lines = [] for pin, ( route, @@ -168,7 +174,6 @@ module top(); 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: @@ -236,7 +241,7 @@ module top(); # - Global drivers (e.g. BUFG) # - PHASER_[IN|OUT]_[CA|DB]_FREQREFCLK via BB_[0-3] drive_bufg = random.randint(0, 1) and bufg_count < 16 - drive_phaser = random.randint(0, 1) + drive_phaser = 0 #random.randint(0, 1) if drive_bufg: bufg_count += 1 @@ -270,18 +275,6 @@ module top(); .I(clkfbout_mult_{site}), .O(clkfbin_{site}) );""".format(site=site)) - elif clkfbin_src == '0': - print( - """ - assign clkfbin_{site} = 1'b0; - """.format(site=site)) - elif clkfbin_src == '1': - print( - """ - assign clkfbin_{site} = 1'b1; - """.format(site=site)) - elif clkfbin_src is None: - pass elif clkfbin_src == 'logic': print( """ @@ -292,59 +285,46 @@ module top(); .O(clkfbin_{site}) ); """.format(site=site)) - - clkin_is_none = False + else: + assert False, clkfb_src for clkin in range(2): - clkin_src = random.choice( - ( - 'BUFH', - 'BUFR', - # '0', - # '1', - 'logic', - # None, - )) - if clkin == 1 and clkin_is_none and clkin_src is None: - clkin_src = 'BUFH' + clkin_src = random.choice(( + 'BUFH', + 'BUFR', + 'logic', + )) - if clkin_src is None: - pass - elif clkin_src == 'BUFH': + if clkin_src == 'BUFH': print( """ (* KEEP, DONT_TOUCH *) BUFH ( - .O(clkin{idx}_{site}) - );""".format(idx=clkin + 1, site=site)) + .O(clkin{idx}_{site}), + .I(clkin{idx2}) + );""".format(idx=clkin + 1, idx2=clkin_idx, site=site)) elif clkin_src == 'BUFR': print( """ (* KEEP, DONT_TOUCH *) BUFR ( - .O(clkin{idx}_{site}) - );""".format(idx=clkin + 1, site=site)) - elif clkin_src == '0': - print( - """ - assign clkin{idx}_{site} = 0; - """.format(idx=clkin + 1, site=site)) - elif clkin_src == '1': - print( - """ - assign clkin{idx}_{site} = 1; - """.format(idx=clkin + 1, site=site)) + .O(clkin{idx}_{site}), + .I(clkin{idx2}) + );""".format(idx=clkin + 1, idx2=clkin_idx, site=site)) elif clkin_src == 'logic': print( """ (* KEEP, DONT_TOUCH *) LUT6 # (.INIT(64'h5555555555555555)) clkin{idx}_logic_{site} ( + .I0(clkin{idx2}), .O(clkin{idx}_{site}) ); - """.format(idx=clkin + 1, site=site)) + """.format(idx=clkin + 1, idx2=clkin_idx, site=site)) else: - assert False, clkin_src + assert False, (clkin, clkin_src) + + clkin_idx += 1 print("endmodule") diff --git a/minitests/plle2_adv/basys3_plle2_adv.v b/minitests/plle2_adv/basys3_plle2_adv.v index aace7c85..ddbf279d 100644 --- a/minitests/plle2_adv/basys3_plle2_adv.v +++ b/minitests/plle2_adv/basys3_plle2_adv.v @@ -15,6 +15,10 @@ input wire [15:0] sw, output wire [15:0] led ); +// ============================================================================ + +assign tx = rx; + // ============================================================================ // Clock & reset reg [3:0] rst_sr; @@ -44,7 +48,8 @@ plle2_test plle2_test .O_CNT (led[5:0]) ); -assign led [14:6] = 0; +assign led [14] = |sw; +assign led [13:6] = 0; endmodule diff --git a/minitests/plle2_adv/src/plle2_test.v b/minitests/plle2_adv/src/plle2_test.v index dd73b2eb..9348c2d2 100644 --- a/minitests/plle2_adv/src/plle2_test.v +++ b/minitests/plle2_adv/src/plle2_test.v @@ -22,12 +22,16 @@ always @(posedge clk100) // ============================================================================ // The PLL -wire clk_fb; +wire clk_fb_o; +wire clk_fb_i; wire [5:0] clk; PLLE2_ADV # ( +.BANDWIDTH ("HIGH"), +.COMPENSATION ("BUF_IN"), + .CLKIN1_PERIOD (20.0), // 50MHz .CLKIN2_PERIOD (10.0), // 100MHz @@ -35,7 +39,7 @@ PLLE2_ADV # .CLKFBOUT_PHASE (0.0), .CLKOUT0_DIVIDE (16), -.CLKOUT0_DUTY_CYCLE (0.5), +.CLKOUT0_DUTY_CYCLE (0.53125), .CLKOUT0_PHASE (45.0), .CLKOUT1_DIVIDE (32), @@ -69,8 +73,8 @@ pll .RST (RST), .LOCKED (O_LOCKED), -.CLKFBIN (clk_fb), -.CLKFBOUT (clk_fb), +.CLKFBIN (clk_fb_i), +.CLKFBOUT (clk_fb_o), .CLKOUT0 (clk[0]), .CLKOUT1 (clk[1]), @@ -80,6 +84,8 @@ pll .CLKOUT5 (clk[5]) ); +BUFG clk_fb_buf (.I(clk_fb_o), .O(clk_fb_i)); + // ============================================================================ // Counters diff --git a/minitests/plle2_adv/tcl/par.tcl b/minitests/plle2_adv/tcl/par.tcl index 60d66e80..7f9dcdcc 100644 --- a/minitests/plle2_adv/tcl/par.tcl +++ b/minitests/plle2_adv/tcl/par.tcl @@ -13,4 +13,4 @@ route_design write_checkpoint -force ../$env(PROJECT_NAME).dcp -write_bitstream -force ../$env(PROJECT_NAME).bit +write_bitstream -force -logic_location_file ../$env(PROJECT_NAME).bit From 355a571400bf6886dda518c2b31fb73d980eb660 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 25 Oct 2019 09:34:49 +0200 Subject: [PATCH 08/14] Removed the INTERNAL_FEEDBACK tag as it is the same as the PLLE2.COMPENSATION.INTENAL Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/generate.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index 5bfe2ec0..1e39831d 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -135,15 +135,6 @@ def main(): if not (in_use and not val): tags[tile][tag] = int(val) - for s, d in [ - ('CMT_TOP_L_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ('CMT_TOP_R_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ]: - if (s, d) in active_pips: - internal_feedback = in_use - - tags[tile]["INTERNAL_FEEDBACK"] = int(internal_feedback) - # Output tags for tile, tile_tags in tags.items(): for t, v in tile_tags.items(): From 5ab90a604d27fd9bda4ff33abc7d3996fcb7547e Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 25 Oct 2019 14:50:23 +0200 Subject: [PATCH 09/14] Inceased N Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile index 5efba883..03b26da9 100644 --- a/fuzzers/034-cmt-pll-pips/Makefile +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -9,7 +9,7 @@ else MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE) endif -N = 80 +N = 100 SEGMATCH_FLAGS=-m 10 -M 20 -c 170 A_PIPLIST=cmt_top_l_upper_t.txt From 8267bcdaebb8696e3cc5e6a15a1a7f915e333d3d Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Mon, 28 Oct 2019 15:56:24 +0100 Subject: [PATCH 10/14] Updated regex for PIP todo list. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile index 03b26da9..013ee3d0 100644 --- a/fuzzers/034-cmt-pll-pips/Makefile +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -1,7 +1,7 @@ export FUZDIR=$(shell pwd) PIP_TYPE?=cmt_top PIPLIST_TCL=$(FUZDIR)/cmt_top_upper_t.tcl -TODO_RE=".*\.CMT_TOP_[LR]_UPPER_T_PLLE2_CLK_[^_]+_INT" +TODO_RE=".*CMT_TOP_[LR]_UPPER_T_PLLE2_CLK(IN1|IN2|FBIN)\.CMT_TOP_[LR]" ifneq (${XRAY_DATABASE}, zynq7) MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE) From bf380f2bdde8ca704b74e9d7638fc24e4dc81ddf Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 29 Oct 2019 11:50:40 +0100 Subject: [PATCH 11/14] PIPs and PPIPs are now not read from the db. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/top.py | 93 +++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index 55a12571..1727d4bc 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -6,6 +6,49 @@ from prjxray import util from prjxray.db import Database +class PipList(object): + def __init__(self): + self.piplist = {} + self.ppiplist = {} + + def get_pip_and_ppip_list_for_tile_type(self, tile_type): + + # Load PIP list for the tile type if not already loaded + if tile_type not in self.piplist: + self.piplist[tile_type] = [] + + fname = os.path.join( + os.getenv('FUZDIR'), '..', 'piplist', 'build', 'cmt_top', + tile_type.lower() + '.txt') + + with open(fname, "r") as f: + for l in f: + tile, dst, src = l.strip().split('.') + if tile_type == tile: + self.piplist[tile_type].append((src, dst)) + + # Load PPIP list for the tile type if not already loaded + if tile_type not in self.ppiplist: + self.ppiplist[tile_type] = [] + + fname = os.path.join( + os.getenv('FUZDIR'), '..', '071-ppips', 'build', + 'ppips_' + tile_type.lower() + '.db') + + with open(fname, "r") as f: + for l in f: + pip_data, pip_type = l.strip().split() + + if pip_type != 'always': + continue + + tile, dst, src = pip_data.strip().split('.') + if tile_type == tile: + self.ppiplist[tile_type].append((src, dst)) + + return self.piplist[tile_type], self.ppiplist[tile_type] + + def find_phasers_for_pll(grid, loc): gridinfo = grid.gridinfo_at_loc((loc[0], loc[1] + 13)) @@ -43,25 +86,31 @@ def gen_sites(): def get_random_route_from_site_pin( - db, tile_name, site_name, site_pin, direction, occupied_wires): + pip_list, tile_name, site_pin, direction, occupied_wires): - grid = db.grid() - tile = db.tilegrid[tile_name] - tile_type = tile["type"] - site_type = tile["sites"][site_name] + # A map of PLL site pins to wires they are connected to. + pin_to_wire = { + "CMT_TOP_L_UPPER_T": { + "CLKIN1": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN1", + "CLKIN2": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN2", + "CLKFBIN": "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN", + }, + "CMT_TOP_R_UPPER_T": { + "CLKIN1": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN1", + "CLKIN2": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN2", + "CLKFBIN": "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN", + }, + } - tile = db.get_tile_type(tile_type) + # Get tile type + tile_type = tile_name.rsplit("_", maxsplit=1)[0] - # Assumption: there is only one PLL per tile. - site = [s for s in tile.get_sites() if s.type == site_type][0] + # Get all PIPs (PIPs + PPIPs) + pips, ppips = pip_list.get_pip_and_ppip_list_for_tile_type(tile_type) + all_pips = pips + ppips - # 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 + # The first wire + wire = pin_to_wire[tile_type][site_pin] # Walk randomly. route = [] @@ -70,11 +119,11 @@ def get_random_route_from_site_pin( 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 + for src, dst in all_pips: + if direction == "down" and src == wire: + next_wire = dst + elif direction == "up" and dst == wire: + next_wire = src else: continue @@ -111,7 +160,7 @@ module top( LUT6 dummy(); '''.format(nclkin=max_clk_inputs - 1)) - db = Database(util.get_db_root()) + pip_list = PipList() bufg_count = 0 design_file = open('design.txt', 'w') @@ -146,7 +195,7 @@ module top( for pin, dir in pins: route = get_random_route_from_site_pin( - db, tile, site, pin, dir, occupied_wires) + pip_list, tile, pin, dir, occupied_wires) if route is None: endpoints[pin] = "" continue From 573ee1a38d39d4382bc3bada158745499f1a00e7 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 29 Oct 2019 11:55:03 +0100 Subject: [PATCH 12/14] Fixed bug in tag_groups.txt Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/tag_groups.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/tag_groups.txt b/fuzzers/034-cmt-pll-pips/tag_groups.txt index afa81e6a..239d2e84 100644 --- a/fuzzers/034-cmt-pll-pips/tag_groups.txt +++ b/fuzzers/034-cmt-pll-pips/tag_groups.txt @@ -8,6 +8,5 @@ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_CLKFBOUT2IN CMT_UPPER_T.CM 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_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB3 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_CLKIN2.CMT_TOP_R_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB3 -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_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT From 0377b5fb4c046a310252943d8dc77a666bde9edb Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 29 Oct 2019 16:36:40 +0100 Subject: [PATCH 13/14] Disabled reading PIPs and PPIPs for "R" version of CMT tiles for Zynq7. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/generate.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index 1e39831d..d1bb9bd3 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -22,9 +22,18 @@ def main(): ppipdata = {} ignpip = set() + # Zynq7 do not have R CMTs + if os.getenv("XRAY_DATABASE") == "zynq7": + piplists = ['cmt_top_l_upper_t.txt'] + ppiplists = ['ppips_cmt_top_l_upper_t.db'] + else: + piplists = ['cmt_top_l_upper_t.txt', 'cmt_top_r_upper_t.txt'] + ppiplists = [ + 'ppips_cmt_top_l_upper_t.db', 'ppips_cmt_top_r_upper_t.db' + ] + # Load PIP lists print("Loading 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: @@ -37,7 +46,6 @@ def main(): # Load PPIP lists (to exclude them) print("Loading PPIP lists...") - 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) From b99bd85fa41df6792a43ed274f9ef16f6ba4db7f Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 29 Oct 2019 18:20:50 +0100 Subject: [PATCH 14/14] Added handling of routing failure in the TCL script. Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/generate.tcl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl index 744cf8a0..19be7bd4 100644 --- a/fuzzers/034-cmt-pll-pips/generate.tcl +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -140,6 +140,18 @@ proc run {} { route_design -directive Quick -preserve + if {[llength [get_nets -filter {ROUTE_STATUS!="ROUTED"}]] ne 0} { + set nets [get_nets -filter {IS_ROUTE_FIXED==1}] + puts "MANROUTE: Got unrouted nets: $nets" + puts "MANROUTE: Ripping up and starting again with no fixed routes" + + route_design -unroute + set_property FIXED_ROUTE "" $nets + set_property IS_ROUTE_FIXED 0 $nets + + route_design -directive Quick + } + write_checkpoint -force design.dcp write_bitstream -force design.bit write_pip_txtdata design_pips.txt