Make MMCM pip fuzzer more robust.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2020-10-13 13:09:22 -07:00
parent af6700a692
commit 4e4bcae418
4 changed files with 163 additions and 108 deletions

View File

@ -220,9 +220,6 @@ def main():
tags_to_remove = set()
for tag, bits in segbits.items():
if len(bits) == 0:
tags_to_remove.add(tag)
if 'REBUF' in tag and 'ACTIVE' not in tag:
# FIXME: Removing REBUF pips for now.
tags_to_remove.add(tag)
@ -232,15 +229,14 @@ def main():
for tag in segbits.keys():
if tag.endswith("_ACTIVE") and 'FREQ_BB' in tag:
if 'FREQ_BB_REBUF' in tag:
m = re.search('FREQ_BB_REBUF([0-9])', tag)
else:
m = re.search('FREQ_BB_NS([0-9])', tag)
assert m is not None, tag
prefix = '.CMT_R_LOWER_B_CLK_FREQ_BB{}'.format(m.group(1))
tags_to_mask = [t for t in segbits.keys() if t.endswith(prefix)]
mask_out_bits(segbits, segbits[tag], tags_to_mask)
for idx in range(4):
prefix1 = '.CMT_L_LOWER_B_CLK_FREQ_BB{}'.format(idx)
prefix2 = '.CMT_R_LOWER_B_CLK_FREQ_BB{}'.format(idx)
tags_to_mask = [
t for t in segbits.keys()
if t.endswith(prefix1) or t.endswith(prefix2)
]
mask_out_bits(segbits, segbits[tag], tags_to_mask)
# Find common bits
bit_groups = find_common_bits_for_tag_groups(segbits, tag_groups)

View File

@ -47,6 +47,116 @@ proc write_used_wires {filename} {
close $fp
}
proc load_route {line} {
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..."
return
}
set source_pin [get_pins -of $net -filter "DIRECTION == OUT"]
if { [llength $source_pin] == 0 } {
error "Failed to find source pin of net $net"
}
set source_site_pins [get_site_pins -of $source_pin]
puts "MANROUTE: Possible site pins for net $net: $source_site_pins"
# Fixed part read from file
set route_list {}
if { [string first / $wires] != -1 } {
# Route list is just intermediate node and final node, fill it in
if { [llength $wires] != 2} {
error "Expected only 2 wires, found [llength $wires]"
}
set intermediate_node [get_nodes [lindex $wires 0]]
set dest_node [get_nodes -of_objects [get_wires -of_objects $tile "*/[lindex $wires 1]"]]
if [catch {find_routing_path -from $intermediate_node -to $dest_node} route_list] {
puts "MANROUTE: Failed to find routing path from $intermediate_node to $dest_node for net $net\nError: $route_list"
return
}
if { [llength $route_list] == 0 } {
puts "MANROUTE: Failed to find routing path from $intermediate_node to $dest_node for net $net"
return
}
} else {
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"
return
}
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"
return
}
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
if [catch {set_property FIXED_ROUTE $route $net} result] {
puts "MANROUTE: Net $net failed to set FIXED_ROUTE, ripping up...\nError: $result"
set_property FIXED_ROUTE "" $net
set_property IS_ROUTE_FIXED 0 $net
route_design -unroute -nets $net
}
# Route the single net. Needed to detect conflicts when evaluating
# other ones
puts "Running route design"
route_design -quiet -directive Quick -nets $net
puts "Done running route design"
# 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"
}
}
proc load_routes {filename} {
puts "MANROUTE: Loading routes from $filename"
@ -56,86 +166,7 @@ proc load_routes {filename} {
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
if [catch {set_property FIXED_ROUTE $route $net} ] {
puts "MANROUTE: Net $net failed to set FIXED_ROUTE, ripping up..."
set_property FIXED_ROUTE "" $net
set_property IS_ROUTE_FIXED 0 $net
route_design -unroute -nets $net
}
# Route the single net. Needed to detect conflicts when evaluating
# other ones
puts "Running route design"
route_design -quiet -directive Quick -nets $net
puts "Done running route design"
# 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"
}
load_route $line
}
close $fp

View File

@ -0,0 +1,11 @@
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_IN3_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_L_LOWER_B_CLK_IN3_INT
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_IN1_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_L_LOWER_B_CLK_IN1_INT
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_IN2_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_L_LOWER_B_CLK_IN2_INT
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_IN3_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKFBIN.CMT_R_LOWER_B_CLK_IN3_INT
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_IN1_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN1.CMT_R_LOWER_B_CLK_IN1_INT
CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_FREQ_BB0 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_FREQ_BB1 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_FREQ_BB2 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_FREQ_BB3 CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_IN2_HCLK CMT_LOWER_B.CMT_LR_LOWER_B_MMCM_CLKIN2.CMT_R_LOWER_B_CLK_IN2_INT

View File

@ -84,6 +84,20 @@ def find_phasers_for_mmcm(grid, loc):
return phasers
def find_hclk_ref_wires_for_mmcm(grid, loc):
tilename = grid.tilename_at_loc((loc[0], loc[1] - 17))
gridinfo = grid.gridinfo_at_tilename(tilename)
assert gridinfo.tile_type in ['HCLK_CMT_L', 'HCLK_CMT']
# HCLK_CMT_MUX_OUT_FREQ_REF[0-3]
wires = []
for idx in range(4):
wires.append('{}/HCLK_CMT_MUX_OUT_FREQ_REF{}'.format(tilename, idx))
return wires
def gen_sites():
db = Database(util.get_db_root(), util.get_part())
grid = db.grid()
@ -94,11 +108,12 @@ def gen_sites():
for site_name, site_type in gridinfo.sites.items():
if site_type in ['MMCME2_ADV']:
phasers = find_phasers_for_mmcm(grid, loc)
yield tile_name, site_name, phasers
hclk_wires = find_hclk_ref_wires_for_mmcm(grid, loc)
yield tile_name, site_name, phasers, hclk_wires
def get_random_route_from_site_pin(
pip_list, tile_name, site_pin, direction, occupied_wires):
pip_list, tile_name, site_pin, direction, occupied_wires, hclk_wires):
# A map of MMCM site pins to wires they are connected to.
pin_to_wire = {
@ -138,6 +153,9 @@ def get_random_route_from_site_pin(
# The first wire
wire = pin_to_wire[tile_type][site_pin]
if site_pin in ["CLKIN1", "CLKIN2", "CLKFBIN"] and random.random() < .2:
return [random.choice(hclk_wires), wire]
# Walk randomly.
route = []
while True:
@ -199,7 +217,7 @@ module top(
count = 0
mmcms = sorted(gen_sites(), key=lambda x: x[0])
random.shuffle(mmcms)
for tile, site, phasers in mmcms:
for tile, site, phasers, hclk_wires in mmcms:
in_use = random.randint(0, 2) > 0
count += 1
@ -219,20 +237,20 @@ module top(
# Sometimes manually randomized route for CLKOUTx conflicts with
# the verilog design.
('CLKOUT0', 'down'),
('CLKOUT1', 'down'),
('CLKOUT2', 'down'),
('CLKOUT3', 'down'),
('CLKOUT4', 'down'),
('CLKOUT5', 'down'),
('CLKOUT6', 'down'),
#('CLKOUT0', 'down'),
#('CLKOUT1', 'down'),
#('CLKOUT2', 'down'),
#('CLKOUT3', 'down'),
#('CLKOUT4', 'down'),
#('CLKOUT5', 'down'),
#('CLKOUT6', 'down'),
]
occupied_wires = set()
for pin, dir in pins:
route = get_random_route_from_site_pin(
pip_list, tile, pin, dir, occupied_wires)
pip_list, tile, pin, dir, occupied_wires, hclk_wires)
if route is None:
endpoints[pin] = ""
continue
@ -248,11 +266,10 @@ module top(
# Store them in a random order so the TCL script will try to route
# them also in the random order.
lines = []
for pin, (
route,
dir,
) in routes.items():
pins = sorted(routes.keys())
random.shuffle(pins)
for pin in pins:
(route, dir) = routes[pin]
route_str = " ".join(route)
lines.append(
'{} {} {} {} {}\n'.format(tile, site, pin, dir, route_str))