From 6e957480684a1e6d8f5513541370c1652969fa9d Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Fri, 22 Jan 2021 14:44:20 +0100 Subject: [PATCH 1/6] 065-gtp-common-pips: add fuzzer to document GTP_COMMON_MID pips Problems found: - for some PIPs configurations, no bit is generated. For instance if there are only connections with RX/TX from the GTP channel - some missing PIPs with one bit only - re-routing now correctly runs for every PIP Signed-off-by: Alessandro Comodi --- fuzzers/065-gtp-common-pips/Makefile | 56 +++ fuzzers/065-gtp-common-pips/bits.dbf | 0 fuzzers/065-gtp-common-pips/generate.py | 102 +++++ fuzzers/065-gtp-common-pips/generate.tcl | 396 ++++++++++++++++++ .../gtp_common_pip_list.tcl | 49 +++ fuzzers/065-gtp-common-pips/output_cmt.tcl | 18 + fuzzers/065-gtp-common-pips/top.py | 315 ++++++++++++++ prjxray/segmaker.py | 2 + utils/mergedb.sh | 4 +- 9 files changed, 940 insertions(+), 2 deletions(-) create mode 100644 fuzzers/065-gtp-common-pips/Makefile create mode 100644 fuzzers/065-gtp-common-pips/bits.dbf create mode 100644 fuzzers/065-gtp-common-pips/generate.py create mode 100644 fuzzers/065-gtp-common-pips/generate.tcl create mode 100644 fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl create mode 100644 fuzzers/065-gtp-common-pips/output_cmt.tcl create mode 100644 fuzzers/065-gtp-common-pips/top.py diff --git a/fuzzers/065-gtp-common-pips/Makefile b/fuzzers/065-gtp-common-pips/Makefile new file mode 100644 index 00000000..838d7354 --- /dev/null +++ b/fuzzers/065-gtp-common-pips/Makefile @@ -0,0 +1,56 @@ +# Copyright (C) 2017-2020 The Project X-Ray Authors. +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC +export FUZDIR=$(shell pwd) +PIP_TYPE?=gtp_common +PIPLIST_TCL=$(FUZDIR)/gtp_common_pip_list.tcl + + +TODO_RE=".*" + +MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(PIP_TYPE) --re $(TODO_RE) --sides "" +N = 20 + +SEGMATCH_FLAGS=-c 2 +SPECIMENS_DEPS=build/cmt_regions.csv +A_PIPLIST=gtp_common.txt + +include ../pip_loop.mk + +build/segbits_gtp_common.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_gtp_common.rdb \ + $(shell find build -name segdata_gtp_common*.txt) + +RDBS = build/segbits_gtp_common.rdb + +database: ${RDBS} + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_gtp_common.rdb \ + --seg-fn-out build/segbits_gtp_common.db + + # Keep a copy to track iter progress + cp build/segbits_gtp_common.rdb build/$(ITER)/segbits_gtp_common.rdb + cp build/segbits_gtp_common.db build/$(ITER)/segbits_gtp_common.db + + # Clobber existing .db to eliminate potential conflicts + cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} gtp_common build/segbits_gtp_common.db + +build/cmt_regions.csv: output_cmt.tcl + mkdir -p build + cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + +pushdb: database + ${XRAY_MERGEDB} gtp_common_mid_left build/segbits_gtp_common.db + ${XRAY_MERGEDB} gtp_common_mid_right build/segbits_gtp_common.db + +run: + $(MAKE) clean + +$(FUZDIR)/../int_loop.sh --check-args "--zero-entries --timeout-iters 10" + touch run.${XRAY_PART}.ok + +.PHONY: database pushdb run diff --git a/fuzzers/065-gtp-common-pips/bits.dbf b/fuzzers/065-gtp-common-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/065-gtp-common-pips/generate.py b/fuzzers/065-gtp-common-pips/generate.py new file mode 100644 index 00000000..0c8feb88 --- /dev/null +++ b/fuzzers/065-gtp-common-pips/generate.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (C) 2017-2020 The Project X-Ray Authors. +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC + +from prjxray.segmaker import Segmaker +import os +import os.path + + +def bitfilter(frame, word): + word = int(word / 32) + + if frame not in [0, 1, 2, 3, 4, 5, 6, 7]: + return False + + if word != 50: + return False + + return True + + +def read_pip_data(pipfile, pipdata, tile_ports): + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'gtp_common', pipfile)) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] + tile_ports[tile_type] = set() + + pipdata[tile_type].append((src, dst)) + tile_ports[tile_type].add(src) + tile_ports[tile_type].add(dst) + + +def main(): + segmk = Segmaker("design.bits") + + tiledata = {} + pipdata = {} + ignpip = set() + tile_ports = {} + + read_pip_data('gtp_common.txt', pipdata, tile_ports) + + print("Loading tags from design.txt.") + with open("design.txt", "r") as f: + for line in f: + tile, pip, src, dst, pnum, pdir = line.split() + + if not tile.startswith('GTP_COMMON_MID'): + continue + + pip_prefix, _ = pip.split(".") + tile_from_pip, tile_type = pip_prefix.split('/') + assert tile == tile_from_pip + _, src = src.split("/") + _, dst = dst.split("/") + pnum = int(pnum) + pdir = int(pdir) + + if tile not in tiledata: + tiledata[tile] = { + "type": tile_type, + "pips": set(), + "srcs": set(), + "dsts": set() + } + + tiledata[tile]["pips"].add((src, dst)) + tiledata[tile]["srcs"].add(src) + tiledata[tile]["dsts"].add(dst) + + if pdir == 0: + tiledata[tile]["srcs"].add(dst) + tiledata[tile]["dsts"].add(src) + + for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + pips = pips_srcs_dsts["pips"] + + for src, dst in pipdata["GTP_COMMON_MID_LEFT"]: + if (src, dst) in ignpip: + pass + elif (src, dst) in pips: + segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1) + elif dst not in tiledata[tile]["dsts"]: + segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0) + + segmk.compile(bitfilter=bitfilter) + segmk.write() + + +if __name__ == "__main__": + main() diff --git a/fuzzers/065-gtp-common-pips/generate.tcl b/fuzzers/065-gtp-common-pips/generate.tcl new file mode 100644 index 00000000..8b8ee17d --- /dev/null +++ b/fuzzers/065-gtp-common-pips/generate.tcl @@ -0,0 +1,396 @@ +# Copyright (C) 2017-2020 The Project X-Ray Authors +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc load_todo {{dir "dst"}} { + set fp [open "../../todo_all.txt" r] + + # Create map of pip source to remaining destinations for that pip + set todo_map [dict create] + for {gets $fp line} {$line != ""} {gets $fp line} { + set parts [split $line .] + if {$dir == "dsts"} { + dict lappend todo_map [lindex $parts 2] [list [lindex $parts 0] [lindex $parts 1]] + } elseif {$dir == "srcs"} { + dict lappend todo_map [lindex $parts 1] [list [lindex $parts 0] [lindex $parts 2]] + } else { + error "Incorrect argument. Available options: src, dst" + } + } + close $fp + return $todo_map +} + +proc shuffle_list {list} { + set l [llength $list] + for {set i 0} {$i<=$l} {incr i} { + set x [lindex $list [set p [expr {int(rand()*$l)}]]] + set list [lreplace $list $p $p] + set list [linsert $list [expr {int(rand()*$l)}] $x] + } + + return $list +} + +# Get the dictionary of nets with one corresponding source wire +# of a PIP from the todo list +proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destinations {verbose false}} { + set todo_map [load_todo $direction] + set nets [get_nets] + set todo_nets [dict create] + + foreach net $nets { + if {![regexp $net_regexp $net]} { + continue + } + # Check to see if this net is one we are interested in* + set wires [get_wires -of_objects $net -filter {TILE_NAME =~ "*GTP_COMMON_MID*" && (NAME =~ "*CK_IN*" || NAME =~ "*MUX*")} -quiet] + + set wire_found 0 + foreach wire $wires { + if [regexp $wire_regexp $wire] { + set wire_found 1 + break + } + } + + if {$wire_found == 0} { + if {$verbose} { + puts "$net not going to a GTP common wire, skipping." + } + continue + } + + set tile [lindex [split $wire /] 0] + set wire [lindex [split $wire /] 1] + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + + + if { ![dict exists $todo_map $wire] } { + continue + } + + set candidates [dict get $todo_map $wire] + + # This net is interesting, see if it is already going somewhere we + # want. + set found_target 0 + foreach other_wire $wires { + if { $found_target == 1 } { + break + } + + set other_wire [lindex [split $other_wire /] 1] + + if { $wire == $other_wire } { + continue + } + + foreach candidate $candidates { + set candidate_tile_type [lindex $candidate 0] + + if {$candidate_tile_type != $tile_type} { + continue + } + + set candidate_wire [lindex $candidate 1] + + if { $other_wire == $candidate } { + set found_target 1 + if {$verbose} { + puts "Interesting net $net already going from $wire to $other_wire." + } + set_property IS_ROUTE_FIXED 1 $net + dict set used_destinations "$tile/$candidate_wire" 1 + break + } + } + } + + if { $found_target == 1 } { + # Net already has an interesting feature - don't reroute. + continue + } + + dict set todo_nets $net [list $tile $wire] + if {$verbose} { + puts "Interesting net $net (including $wire) is being rerouted." + } + } + return $todo_nets +} + +proc remove_net_randomly {wire_regexp} { + # Randomly removes a net containing a given wire + set nets [get_nets] + set net_to_remove "" + + foreach net $nets { + set wires [get_wires -of_objects $net] + + foreach wire $wires { + if [regexp $wire_regexp $wire] { + set net_to_remove $net + break + } + } + } + + if { $net_to_remove != "" && rand() <= 0.1 } { + puts "Removing net: $net_to_remove" + remove_net $net_to_remove + } +} + +proc route_todo {} { + + # It is very common to have nets passing through the + # HCLK_GTP_CK_IN[01] wires, resulting in results. + # This step removes the net containing the problematic + # wire with a 10% probability + remove_net_randomly "HCLK_GTP_CK_IN0" + remove_net_randomly "HCLK_GTP_CK_IN1" + + set used_destinations [dict create] + set todo_map [load_todo "dsts"] + set gtp_channel_nets [get_nets_with_todo_pip_wires "dsts" "gtp_channel_clock" "GTPE2_COMMON_\[TR\]XOUTCLK_MUX_\[0123\]" $used_destinations true] + set ibufds_nets [get_nets_with_todo_pip_wires "dsts" "ibufds_clock" "IBUFDS_GTPE2_\[01\]_MGTCLKOUT_MUX" $used_destinations true] + set gtp_nets [dict merge $gtp_channel_nets $ibufds_nets] + puts "GTP nets: $gtp_nets" + dict for {net tile_wire} $gtp_nets { + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set dsts [dict get $todo_map $wire] + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + set todos {} + + set old_origin_wire [get_wires -of_objects $net -filter {TILE_NAME =~ "*GTP_COMMON_MID_LEFT*" && NAME =~ "*HCLK_GTP_CK_IN*"}] + if {$old_origin_wire == {}} { + continue + } + + puts "Rerouting net $net at $tile / $wire (type $tile_type)" + puts "Previous target wire: $old_origin_wire" + + set old_origin_node [get_nodes -of_objects $old_origin_wire] + foreach dst $dsts { + set dst_wire [lindex $dst 1] + + lappend todos $dst_wire + } + + set todos_length [llength $todos] + if {$todos_length == 0} { + continue + } + + puts "All todos for $tile_type / $wire" + foreach dst_wire $todos { + puts " - $dst_wire" + } + + set todos [shuffle_list $todos] + + set target_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] + puts "Target node: $target_node" + route_design -unroute -nets $net + + # Find an output in the todo list that can drive. + foreach dst_wire $todos { + if { [dict exists $used_destinations "$tile/$dst_wire"] } { + puts "Not routing to $tile / $dst_wire, in use." + continue + } + + set origin_wire [get_wires "$tile/$dst_wire"] + set origin_node [get_nodes -of_objects $origin_wire] + if {[llength $origin_node] == 0} { + error "Failed to find node for $tile/$dst_wire." + } + + set old_net [get_nets -of_objects $origin_node -quiet] + if {$old_net != {}} { + puts "Unrouting the old net: $old_net" + route_design -unroute -nets $old_net + } + + # Route the net through the desired node + puts "Attempting to route to $dst_wire for net $net." + set route_status [route_via $net [list $origin_node] 0] + + if {$route_status == 0} { + puts "WARNING: route failed, continue with next todo" + continue + } + + puts "Target node: $target_node" + puts "Origin wire: $origin_wire, Old origin wire: $old_origin_wire" + puts "Origin node: $origin_node, Old origin node: $old_origin_node" + + dict set used_destinations "$origin_wire" 1 + + break + } + } + + set todo_map [load_todo "srcs"] + set pll_nets [get_nets_with_todo_pip_wires "srcs" "pll_clock" "HCLK_GTP_CK_IN" $used_destinations true] + set mmcm_nets [get_nets_with_todo_pip_wires "srcs" "mmcm_clock" "HCLK_GTP_CK_IN" $used_destinations true] + set cmt_nets [dict merge $pll_nets $mmcm_nets] + puts "CMT nets: $cmt_nets" + dict for {net tile_wire} $cmt_nets { + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set dsts [dict keys $todo_map] + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + set todos {} + + set old_origin_dst_wire [get_wires -of_objects $net -filter {TILE_NAME =~ "*GTP_COMMON_MID*"}] + if {$old_origin_dst_wire == {}} { + continue + } + + puts "Rerouting net $net at $tile / $wire (type $tile_type)" + puts "Previous target wire: $old_origin_dst_wire" + + set old_origin_node [get_nodes -of_objects $old_origin_dst_wire] + if [regexp "HCLK_GTP_CK_IN.*" $old_origin_dst_wire match group] { + set old_target_side $group + } + foreach dst $dsts { + set srcs [dict get $todo_map $dst] + foreach src $srcs { + + set src_wire [lindex $src 1] + + set is_gtp_net 1 + if [regexp "HCLK_GTP_CK_MUX.*" $src_wire match group] { + set is_gtp_net 0 + } + + if {$is_gtp_net == 1} { + continue + } + + set wire_pairs [list $src_wire $dst] + lappend todos $wire_pairs + } + } + + set todos_length [llength $todos] + if {$todos_length == 0} { + continue + } + + puts "All todos for $tile_type / $wire" + foreach src_wire $todos { + puts " - $src_wire" + } + + set todos [shuffle_list $todos] + + set target_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] + puts "Target node: $target_node" + route_design -unroute -nets $net + + # Find an output in the todo list that can drive. + foreach wire_pair $todos { + + set src_wire [lindex $wire_pair 0] + set dst_wire [lindex $wire_pair 1] + + if { [dict exists $used_destinations "$tile/$dst_wire"] } { + puts "Not routing to $tile / $dst_wire, in use." + continue + } + + if { [dict exists $used_destinations "$tile/$src_wire"] } { + puts "Not routing to $tile / $src_wire, in use." + continue + } + + set origin_src_wire [get_wires "$tile/$src_wire"] + set origin_src_node [get_nodes -of_objects $origin_src_wire] + if {[llength $origin_src_node] == 0} { + error "Failed to find node for $tile/$src_wire." + } + + set origin_dst_wire [get_wires "$tile/$dst_wire"] + set origin_dst_node [get_nodes -of_objects $origin_dst_wire] + if {[llength $origin_dst_node] == 0} { + error "Failed to find node for $tile/$dst_wire." + } + + set old_src_net [get_nets -of_objects $origin_src_node -quiet] + if {$old_src_net != {}} { + puts "Unrouting the old net: $old_src_net" + route_design -unroute -nets $old_src_net + } + + set old_dst_net [get_nets -of_objects $origin_dst_node -quiet] + if {$old_dst_net != {}} { + puts "Unrouting the old net: $old_dst_net" + route_design -unroute -nets $old_dst_net + } + + # Route the net through the desired node + puts "Attempting to route to $src_wire and $dst_wire for net $net." + set route_status [route_via $net [list $origin_src_node $origin_dst_node]] + + puts "Target node: $target_node" + puts "Origin src wire: $origin_src_wire" + puts "Origin src node: $origin_src_node" + puts "Origin dst wire: $origin_dst_wire" + puts "Origin dst node: $origin_dst_node" + + dict set used_destinations "$origin_dst_wire" 1 + dict set used_destinations "$origin_src_wire" 1 + + break + } + } +} + +proc run {} { + create_project -force -part $::env(XRAY_PART) design design + read_verilog top.v + synth_design -top top + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + set_property IS_ENABLED 0 [get_drc_checks {PDRC-29}] + set_property IS_ENABLED 0 [get_drc_checks {PDRC-38}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-13}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-47}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-123}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-161}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-1575}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-1619}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-1684}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-1712}] + set_property IS_ENABLED 0 [get_drc_checks {AVAL-50}] + set_property IS_ENABLED 0 [get_drc_checks {AVAL-78}] + set_property IS_ENABLED 0 [get_drc_checks {AVAL-81}] + set_property IS_ENABLED 0 [get_drc_checks {PDIL-1}] + + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] + + place_design -directive Quick + route_design -directive Quick + route_todo + route_design + + + write_checkpoint -force design.dcp + write_bitstream -force design.bit + write_pip_txtdata design.txt +} + +run diff --git a/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl new file mode 100644 index 00000000..d5149f50 --- /dev/null +++ b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl @@ -0,0 +1,49 @@ +# Copyright (C) 2017-2020 The Project X-Ray Authors +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC +proc print_tile_pips {tile_type filename} { + set fp [open $filename w] + set pips [dict create] + foreach tile [get_tiles -filter "TYPE == $tile_type"] { + foreach pip [lsort [get_pips -of_objects $tile]] { + set src [get_wires -uphill -of_objects $pip] + set dst [get_wires -downhill -of_objects $pip] + + # Skip pips with disconnected nodes + set src_node [get_nodes -of_objects $src] + + if { $src_node == {} } { + continue + } + + set dst_node [get_nodes -of_objects $dst] + if { $dst_node == {} } { + continue + } + + set dst_wire [regsub {.*/} $dst ""] + set dst_hclk_match [regexp {HCLK_GTP_CK_IN[0-9]+} $dst_wire] + set dst_ibufds_mux_match [regexp {IBUFDS_GTPE2_[01]_MGTCLKOUT_MUX} $dst_wire] + set dst_gtp_mux_match [regexp {GTPE2_COMMON_[RT]XOUTCLK_MUX_[0123]} $dst_wire] + + if { $dst_hclk_match || $dst_ibufds_mux_match || $dst_gtp_mux_match } { + set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" + if ![dict exists $pips $pip_string] { + puts $fp $pip_string + dict set pips $pip_string 1 + } + } + } + } + close $fp +} + +create_project -force -part $::env(XRAY_PART) design design +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +print_tile_pips GTP_COMMON_MID_LEFT gtp_common.txt diff --git a/fuzzers/065-gtp-common-pips/output_cmt.tcl b/fuzzers/065-gtp-common-pips/output_cmt.tcl new file mode 100644 index 00000000..9e449188 --- /dev/null +++ b/fuzzers/065-gtp-common-pips/output_cmt.tcl @@ -0,0 +1,18 @@ +# Copyright (C) 2017-2020 The Project X-Ray Authors +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC +create_project -force -part $::env(XRAY_PART) design design +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +set fp [open "cmt_regions.csv" "w"] +foreach site_type {MMCME2_ADV IBUFDS_GTE2 GTPE2_CHANNEL GTPE2_COMMON PLLE2_ADV BUFHCE} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/065-gtp-common-pips/top.py b/fuzzers/065-gtp-common-pips/top.py new file mode 100644 index 00000000..6f4c18cd --- /dev/null +++ b/fuzzers/065-gtp-common-pips/top.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (C) 2017-2020 The Project X-Ray Authors. +# +# Use of this source code is governed by a ISC-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/ISC +# +# SPDX-License-Identifier: ISC +import os +import random +import math +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray import verilog +from prjxray import lut_maker +from prjxray.db import Database + + +def read_site_to_cmt(): + """ Yields clock sources and which CMT they route within. """ + with open(os.path.join(os.getenv('FUZDIR'), 'build', + 'cmt_regions.csv')) as f: + for l in f: + site, cmt = l.strip().split(',') + yield (site, cmt) + + +class ClockSources(object): + """ Class for tracking clock sources. + """ + + def __init__(self, limit=14): + self.sources = {} + self.source_to_cmt = {} + self.used_sources_from_cmt = {} + self.limit = limit + + def add_clock_source(self, source, cmt): + """ Adds a source from a specific CMT. + + """ + if cmt not in self.sources: + self.sources[cmt] = [] + + self.sources[cmt].append(source) + self.source_to_cmt[source] = cmt + + def sources_depleted(self, cmt): + if cmt in self.sources: + if cmt not in self.used_sources_from_cmt: + return False + + return self.sources[cmt] == self.used_sources_from_cmt[cmt] + + return True + + def get_random_source(self, cmt, no_repeats=True): + """ Get a random source that is routable to the specific CMT. + + get_random_source will return a source that is either cmt='ANY', + cmt equal to the input CMT, or the adjecent CMT. + + """ + + choices = [] + + if cmt in self.sources: + choices.extend(self.sources[cmt]) + + random.shuffle(choices) + for source in choices: + + source_cmt = self.source_to_cmt[source] + + if source_cmt not in self.used_sources_from_cmt: + self.used_sources_from_cmt[source_cmt] = set() + + if no_repeats and source in self.used_sources_from_cmt[source_cmt]: + continue + + if len(self.used_sources_from_cmt[source_cmt]) >= self.limit: + continue + + self.used_sources_from_cmt[source_cmt].add(source) + return source + + return None + + +def print_bufhce(name, net): + print( + """ +(* KEEP, DONT_TOUCH, LOC="{site}" *) +BUFHCE {site} ( +.I({clock}) +);""".format(site=name, clock=net)) + + +def main(): + """ + GTP_COMMON_MID has clock pips from: + + 2 IBUFDS_GTE2 sites (within the GTP_CMMON tile) + 4 GTP_CHANNEL sites within the same column. Each GTP_CHANNEL can provide 2 clocks + 14 clocks lines from the HROW spine + """ + + cmt_clock_sources = ClockSources() + gtp_channel_clock_sources = ClockSources() + ibufds_clock_sources = ClockSources() + site_to_cmt = dict(read_site_to_cmt()) + clock_region_limit = dict() + clock_region_serdes_location = dict() + + db = Database(util.get_db_root(), util.get_part()) + grid = db.grid() + + def gen_sites(desired_site_type): + for tile_name in sorted(grid.tiles()): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + for site, site_type in gridinfo.sites.items(): + if site_type == desired_site_type: + yield tile_name, site + + clock_region_sites = set() + + def get_clock_region_site(site_type, clk_reg): + for site_name, reg in site_to_cmt.items(): + if site_name.startswith(site_type) and reg in clk_reg: + if site_name not in clock_region_sites: + clock_region_sites.add(site_name) + return site_name + + cmt_with_gtp = set() + for tile_name, site in gen_sites('GTPE2_COMMON'): + cmt_with_gtp.add(site_to_cmt[site]) + + ibufds_inputs = dict() + input_wires = list() + for _, site in gen_sites('IBUFDS_GTE2'): + if site_to_cmt[site] not in cmt_with_gtp: + continue + + ibufds_i = "{}_ibufds_i".format(site) + ibufds_ib = "{}_ibufds_ib".format(site) + ibufds_inputs[site] = [ibufds_i, ibufds_ib] + + input_wires.append("input wire {}".format(ibufds_i)) + input_wires.append("input wire {}".format(ibufds_ib)) + + print( + ''' +module top( + {} +); + (* KEEP, DONT_TOUCH *) + LUT6 dummy(); + '''.format(",\n\t".join(input_wires))) + + for _, site in gen_sites('MMCME2_ADV'): + if site_to_cmt[site] not in cmt_with_gtp: + continue + + mmcm_clocks = [ + 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(7) + ] + + for clk in mmcm_clocks: + cmt_clock_sources.add_clock_source(clk, site_to_cmt[site]) + + print( + """ + wire cin1_{site}, cin2_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + MMCME2_ADV pll_{site} ( + .CLKIN1(cin1_{site}), + .CLKIN2(cin2_{site}), + .CLKOUT0({c0}), + .CLKOUT1({c1}), + .CLKOUT2({c2}), + .CLKOUT3({c3}), + .CLKOUT4({c4}), + .CLKOUT5({c5}), + .CLKOUT6({c6}) + );""".format( + site=site, + c0=mmcm_clocks[0], + c1=mmcm_clocks[1], + c2=mmcm_clocks[2], + c3=mmcm_clocks[3], + c4=mmcm_clocks[4], + c5=mmcm_clocks[5], + c6=mmcm_clocks[6])) + + for _, site in gen_sites('PLLE2_ADV'): + if site_to_cmt[site] not in cmt_with_gtp: + continue + + pll_clocks = [ + 'pll_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(7) + ] + + for clk in pll_clocks: + cmt_clock_sources.add_clock_source(clk, site_to_cmt[site]) + + print( + """ + wire cin1_{site}, cin2_{site}, clkfbin_{site}, {c0}, {c1}, {c2}, {c3}, {c4}, {c5}, {c6}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + PLLE2_ADV pll_{site} ( + .CLKIN1(cin1_{site}), + .CLKIN2(cin2_{site}), + .CLKFBIN(clkfbin_{site}), + .CLKOUT0({c0}), + .CLKOUT1({c1}), + .CLKOUT2({c2}), + .CLKOUT3({c3}), + .CLKOUT4({c4}), + .CLKOUT5({c5}), + .CLKFBOUT({c6}) + );""".format( + site=site, + c0=pll_clocks[0], + c1=pll_clocks[1], + c2=pll_clocks[2], + c3=pll_clocks[3], + c4=pll_clocks[4], + c5=pll_clocks[5], + c6=pll_clocks[6], + )) + + for tile, site in gen_sites('IBUFDS_GTE2'): + if site_to_cmt[site] not in cmt_with_gtp: + continue + + ibufds_clock = 'ibufds_clock_{site}'.format(site=site) + + ibufds_clock_sources.add_clock_source(ibufds_clock, site_to_cmt[site]) + + out_port = "O" if random.random() < 0.5 else "ODIV2" + i_port = ibufds_inputs[site][0] + ib_port = ibufds_inputs[site][1] + + print( + """ + wire {o}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + IBUFDS_GTE2 ibufds_{site} ( + .I({i}), + .IB({ib}), + .{out_port}({o}) + );""".format( + site=site, + i=i_port, + ib=ib_port, + o=ibufds_clock, + out_port=out_port)) + + for _, site in gen_sites('GTPE2_CHANNEL'): + if site_to_cmt[site] not in cmt_with_gtp: + continue + + gtp_channel_clock_rx = 'gtp_channel_clock_{site}_rxclkout'.format( + site=site) + gtp_channel_clock_tx = 'gtp_channel_clock_{site}_txclkout'.format( + site=site) + + gtp_channel_clock_sources.add_clock_source( + gtp_channel_clock_rx, site_to_cmt[site]) + gtp_channel_clock_sources.add_clock_source( + gtp_channel_clock_tx, site_to_cmt[site]) + + print( + """ + wire {rx}, {tx}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + GTPE2_CHANNEL gtp_channel_{site} ( + .RXOUTCLK({rx}), + .TXOUTCLK({tx}) + );""".format(site=site, rx=gtp_channel_clock_rx, tx=gtp_channel_clock_tx)) + + for cmt in cmt_with_gtp: + cmt_clock_used = 0 + + for _, bufhce in gen_sites('BUFHCE'): + if site_to_cmt[bufhce] != cmt: + continue + + chance = random.random() + + if chance < 0.2 or cmt_clock_used < 3: + cmt_clock_used += 1 + clock_name = cmt_clock_sources.get_random_source(cmt) + elif chance > 0.2 and chance < 0.4: + clock_name = ibufds_clock_sources.get_random_source(cmt) + elif chance < 0.6: + clock_name = gtp_channel_clock_sources.get_random_source(cmt) + else: + continue + + if clock_name is None: + continue + + print_bufhce("{}".format(bufhce), clock_name) + + print('endmodule') + + +if __name__ == "__main__": + main() diff --git a/prjxray/segmaker.py b/prjxray/segmaker.py index 69397761..a6503351 100644 --- a/prjxray/segmaker.py +++ b/prjxray/segmaker.py @@ -377,6 +377,8 @@ class Segmaker: tile_type_norm = 'CMT_LOWER_B' if 'GTP_CHANNEL' in tile_type_norm: tile_type_norm = 'GTP_CHANNEL' + if 'GTP_COMMON' in tile_type_norm: + tile_type_norm = 'GTP_COMMON' # ignore dummy tiles (ex: VBRK) if len(tiledata['bits']) == 0: diff --git a/utils/mergedb.sh b/utils/mergedb.sh index 3ea1ac5b..85a3193c 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -164,10 +164,10 @@ case "$1" in cp "$2" "$tmp1" ;; gtp_common_mid_left) - sed < "$2" > "$tmp1" -e 's/^GTP_COMMON_MID_RIGHT\./GTP_COMMON_MID_LEFT./' ;; + sed < "$2" > "$tmp1" -e 's/^GTP_COMMON\./GTP_COMMON_MID_LEFT./' ;; gtp_common_mid_right) - cp "$2" "$tmp1" ;; + sed < "$2" > "$tmp1" -e 's/^GTP_COMMON\./GTP_COMMON_MID_RIGHT./' ;; gtp_channel_0) sed < "$2" > "$tmp1" -e 's/^GTP_CHANNEL\./GTP_CHANNEL_0./' ;; From 913a6ece4051d8773d992a84547a2efc435a5afc Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Thu, 28 Jan 2021 16:08:55 +0100 Subject: [PATCH 2/6] pip fuzzers: enable part specific builds Signed-off-by: Alessandro Comodi --- fuzzers/int_loop.sh | 7 ++++--- fuzzers/pip_loop.mk | 43 +++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/fuzzers/int_loop.sh b/fuzzers/int_loop.sh index c6616704..0dfb9a04 100755 --- a/fuzzers/int_loop.sh +++ b/fuzzers/int_loop.sh @@ -47,17 +47,18 @@ set -ex MAKE=${MAKE:-make} echo $MAKE i=1 +BUILD_DIR=${BUILD_DIR:-build} while true; do ${MAKE} ITER=$i cleaniter - ${MAKE} ITER=$i build/todo.txt - if [ ! -s build/todo.txt -a $i -eq 1 ]; then + ${MAKE} ITER=$i $BUILD_DIR/todo.txt + if [ ! -s $BUILD_DIR/todo.txt -a $i -eq 1 ]; then echo "Empty TODO file, assuming all the ints were already solved!" exit 0 fi if python3 ${XRAY_DIR}/fuzzers/int_loop_check.py $check_args ; then break fi - if [ -f build/todo/timeout ] ; then + if [ -f $BUILD_DIR/todo/timeout ] ; then echo "ERROR: timeout" exit 1 fi diff --git a/fuzzers/pip_loop.mk b/fuzzers/pip_loop.mk index 43b6e1c1..4b5e87f9 100644 --- a/fuzzers/pip_loop.mk +++ b/fuzzers/pip_loop.mk @@ -15,10 +15,13 @@ ITER ?= 1 MAKETODO_FLAGS ?=--pip-type pips_int --seg-type int SPECIMENS_DEPS ?= +BUILD_DIR ?= ${FUZDIR}/build +RUN_OK ?= run.ok + # See int_loop_check.py # rempips took 35 iters once, so set 50 as a good start point CHECK_ARGS ?= --zero-entries --timeout-iters 50 -SPECIMENS := $(addprefix build/$(ITER)/specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS := $(addprefix $(BUILD_DIR)/$(ITER)/specimen_,$(shell seq -f '%03.0f' $(N))) SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) # Individual fuzzer directory, such as ~/prjxray/fuzzers/010-lutinit export FUZDIR=$(shell pwd) @@ -29,8 +32,8 @@ all: database SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) include $(SELF_DIR)/pip_list.mk -$(SPECIMENS_OK): build/todo.txt $(SPECIMENS_DEPS) - mkdir -p build/$(ITER) +$(SPECIMENS_OK): $(BUILD_DIR)/todo.txt $(SPECIMENS_DEPS) + mkdir -p $(BUILD_DIR)/$(ITER) +if [ -f ${FUZDIR}/generate.sh ] ; then \ bash ${FUZDIR}/generate.sh $(subst /OK,,$@) ; \ else \ @@ -39,37 +42,37 @@ $(SPECIMENS_OK): build/todo.txt $(SPECIMENS_DEPS) touch $@ # Used 1) to see if we are done 2) pips to try in generate.tcl -build/todo.txt: piplist $(XRAY_DIR)/fuzzers/int_maketodo.py build/database/seeded - XRAY_DATABASE_DIR=${FUZDIR}/build/database \ +$(BUILD_DIR)/todo.txt: piplist $(XRAY_DIR)/fuzzers/int_maketodo.py $(BUILD_DIR)/database/seeded + XRAY_DATABASE_DIR=$(BUILD_DIR)/database \ python3 $(XRAY_DIR)/fuzzers/int_maketodo.py \ - $(MAKETODO_FLAGS) |sort >build/todo_all.txt - cat build/todo_all.txt | sort -R | head -n$(TODO_N) > build/todo.txt.tmp - mv build/todo.txt.tmp build/todo.txt + $(MAKETODO_FLAGS) |sort >$(BUILD_DIR)/todo_all.txt + cat $(BUILD_DIR)/todo_all.txt | sort -R | head -n$(TODO_N) > $(BUILD_DIR)/todo.txt.tmp + mv $(BUILD_DIR)/todo.txt.tmp $(BUILD_DIR)/todo.txt # Per iter files - mkdir -p build/$(ITER) - cp build/todo_all.txt build/todo.txt build/$(ITER)/ + mkdir -p $(BUILD_DIR)/$(ITER) + cp $(BUILD_DIR)/todo_all.txt $(BUILD_DIR)/todo.txt $(BUILD_DIR)/$(ITER)/ # All in one dir for easier trending - mkdir -p build/todo - cp build/todo_all.txt build/todo/$(ITER)_all.txt + mkdir -p $(BUILD_DIR)/todo + cp $(BUILD_DIR)/todo_all.txt $(BUILD_DIR)/todo/$(ITER)_all.txt # Initial copy for first todo.txt # Subsequent are based on updated db -build/database/seeded: - mkdir -p build/database/${XRAY_DATABASE} - cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} - touch build/database/seeded +$(BUILD_DIR)/database/seeded: + mkdir -p $(BUILD_DIR)/database/${XRAY_DATABASE} + cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db $(BUILD_DIR)/database/${XRAY_DATABASE} + touch $(BUILD_DIR)/database/seeded # FIXME: consider moving to script run: $(MAKE) clean - +$(XRAY_DIR)/fuzzers/int_loop.sh --check-args "$(CHECK_ARGS)" - touch run.ok + +env BUILD_DIR=$(BUILD_DIR) $(XRAY_DIR)/fuzzers/int_loop.sh --check-args "$(CHECK_ARGS)" + touch $(RUN_OK) clean: - rm -rf build run.ok todo + rm -rf $(BUILD_DIR) $(RUN_OK) todo # Remove iteration specific files, but keep piplist.tcl output cleaniter: - rm -rf build/$(ITER) build/todo.txt + rm -rf $(BUILD_DIR)/$(ITER) $(BUILD_DIR)/todo.txt .PHONY: all database pushdb run clean cleaniter From 618e170875bee4b711c8c97357e7738daad11017 Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Thu, 28 Jan 2021 16:09:44 +0100 Subject: [PATCH 3/6] 065-gtp-common-pips: enable fuzzer in makefile Signed-off-by: Alessandro Comodi --- fuzzers/065-gtp-common-pips/Makefile | 56 ++++++++++--------- fuzzers/065-gtp-common-pips/generate.py | 6 +- .../gtp_common_pip_list.tcl | 2 +- fuzzers/065-gtp-common-pips/top.py | 5 +- fuzzers/Makefile | 1 + 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/fuzzers/065-gtp-common-pips/Makefile b/fuzzers/065-gtp-common-pips/Makefile index 838d7354..79c0c0b1 100644 --- a/fuzzers/065-gtp-common-pips/Makefile +++ b/fuzzers/065-gtp-common-pips/Makefile @@ -6,51 +6,53 @@ # # SPDX-License-Identifier: ISC export FUZDIR=$(shell pwd) -PIP_TYPE?=gtp_common +PIP_TYPE?=gtp_common_${XRAY_PART} +SEG_TYPE?=gtp_common PIPLIST_TCL=$(FUZDIR)/gtp_common_pip_list.tcl +BUILD_DIR = ${FUZDIR}/build_${XRAY_PART} +RUN_OK = run.${XRAY_PART}.ok TODO_RE=".*" -MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(PIP_TYPE) --re $(TODO_RE) --sides "" -N = 20 +MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(SEG_TYPE) --re $(TODO_RE) --sides "" +N = 60 SEGMATCH_FLAGS=-c 2 -SPECIMENS_DEPS=build/cmt_regions.csv -A_PIPLIST=gtp_common.txt +SPECIMENS_DEPS=$(BUILD_DIR)/cmt_regions.csv +A_PIPLIST=gtp_common_${XRAY_PART}.txt include ../pip_loop.mk -build/segbits_gtp_common.rdb: $(SPECIMENS_OK) - ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_gtp_common.rdb \ - $(shell find build -name segdata_gtp_common*.txt) +$(BUILD_DIR)/segbits_gtp_common.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o $(BUILD_DIR)/segbits_gtp_common.rdb \ + $(shell find $(BUILD_DIR) -name segdata_gtp_common*.txt) -RDBS = build/segbits_gtp_common.rdb +RDBS = $(BUILD_DIR)/segbits_gtp_common.rdb database: ${RDBS} - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_gtp_common.rdb \ - --seg-fn-out build/segbits_gtp_common.db + ${XRAY_DBFIXUP} --db-root $(BUILD_DIR) --zero-db bits.dbf \ + --seg-fn-in $(BUILD_DIR)/segbits_gtp_common.rdb \ + --seg-fn-out $(BUILD_DIR)/segbits_gtp_common.db # Keep a copy to track iter progress - cp build/segbits_gtp_common.rdb build/$(ITER)/segbits_gtp_common.rdb - cp build/segbits_gtp_common.db build/$(ITER)/segbits_gtp_common.db + cp $(BUILD_DIR)/segbits_gtp_common.rdb $(BUILD_DIR)/$(ITER)/segbits_gtp_common.rdb + cp $(BUILD_DIR)/segbits_gtp_common.db $(BUILD_DIR)/$(ITER)/segbits_gtp_common.db # Clobber existing .db to eliminate potential conflicts - cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} - XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} gtp_common build/segbits_gtp_common.db + cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db $(BUILD_DIR)/database/${XRAY_DATABASE} + XRAY_DATABASE_DIR=$(BUILD_DIR)/database ${XRAY_MERGEDB} gtp_common_mid_left $(BUILD_DIR)/segbits_gtp_common.db + XRAY_DATABASE_DIR=$(BUILD_DIR)/database ${XRAY_MERGEDB} gtp_common_mid_right $(BUILD_DIR)/segbits_gtp_common.db -build/cmt_regions.csv: output_cmt.tcl - mkdir -p build - cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl +$(BUILD_DIR)/cmt_regions.csv: output_cmt.tcl + mkdir -p $(BUILD_DIR) + cd $(BUILD_DIR)/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + +clean_all: + rm -rf build_* run.*.ok pushdb: database - ${XRAY_MERGEDB} gtp_common_mid_left build/segbits_gtp_common.db - ${XRAY_MERGEDB} gtp_common_mid_right build/segbits_gtp_common.db + ${XRAY_MERGEDB} gtp_common_mid_left $(BUILD_DIR)/segbits_gtp_common.db + ${XRAY_MERGEDB} gtp_common_mid_right $(BUILD_DIR)/segbits_gtp_common.db -run: - $(MAKE) clean - +$(FUZDIR)/../int_loop.sh --check-args "--zero-entries --timeout-iters 10" - touch run.${XRAY_PART}.ok - -.PHONY: database pushdb run +.PHONY: database pushdb run clean diff --git a/fuzzers/065-gtp-common-pips/generate.py b/fuzzers/065-gtp-common-pips/generate.py index 0c8feb88..ba60b252 100644 --- a/fuzzers/065-gtp-common-pips/generate.py +++ b/fuzzers/065-gtp-common-pips/generate.py @@ -27,8 +27,9 @@ def bitfilter(frame, word): def read_pip_data(pipfile, pipdata, tile_ports): + part = os.getenv('XRAY_PART') with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', - 'gtp_common', pipfile)) as f: + 'gtp_common_{}'.format(part), pipfile)) as f: for l in f: tile_type, dst, src = l.strip().split('.') if tile_type not in pipdata: @@ -48,7 +49,8 @@ def main(): ignpip = set() tile_ports = {} - read_pip_data('gtp_common.txt', pipdata, tile_ports) + part = os.getenv('XRAY_PART') + read_pip_data('gtp_common_{}.txt'.format(part), pipdata, tile_ports) print("Loading tags from design.txt.") with open("design.txt", "r") as f: diff --git a/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl index d5149f50..a2856474 100644 --- a/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl +++ b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl @@ -46,4 +46,4 @@ create_project -force -part $::env(XRAY_PART) design design set_property design_mode PinPlanning [current_fileset] open_io_design -name io_1 -print_tile_pips GTP_COMMON_MID_LEFT gtp_common.txt +print_tile_pips GTP_COMMON_MID_LEFT gtp_common_$::env(XRAY_PART).txt diff --git a/fuzzers/065-gtp-common-pips/top.py b/fuzzers/065-gtp-common-pips/top.py index 6f4c18cd..4cae8350 100644 --- a/fuzzers/065-gtp-common-pips/top.py +++ b/fuzzers/065-gtp-common-pips/top.py @@ -20,7 +20,10 @@ from prjxray.db import Database def read_site_to_cmt(): """ Yields clock sources and which CMT they route within. """ - with open(os.path.join(os.getenv('FUZDIR'), 'build', + fuzdir = os.getenv('FUZDIR') + part = os.getenv('XRAY_PART') + + with open(os.path.join(fuzdir, 'build_{}'.format(part), 'cmt_regions.csv')) as f: for l in f: site, cmt = l.strip().split(',') diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 4e96d661..e00fde32 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -160,6 +160,7 @@ ifeq ($(XRAY_DATABASE),artix7) $(eval $(call fuzzer,061-pcie-conf,005-tilegrid,all)) $(eval $(call fuzzer,063-gtp-common-conf,005-tilegrid,part)) $(eval $(call fuzzer,064-gtp-channel-conf,005-tilegrid,part)) +$(eval $(call fuzzer,065-gtp-common-pips,005-tilegrid,part)) endif endif endif From 9d89c64913e6e0c952698993c1f993f96827276c Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Fri, 29 Jan 2021 17:26:08 +0100 Subject: [PATCH 4/6] 065-gtp-common-pips: assorted fixes to correctly solve all the PIPs Signed-off-by: Alessandro Comodi --- fuzzers/065-gtp-common-pips/Makefile | 4 +- fuzzers/065-gtp-common-pips/generate.py | 2 +- fuzzers/065-gtp-common-pips/generate.tcl | 51 +++++-------------- .../gtp_common_pip_list.tcl | 2 +- fuzzers/065-gtp-common-pips/top.py | 36 +++++++++++-- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/fuzzers/065-gtp-common-pips/Makefile b/fuzzers/065-gtp-common-pips/Makefile index 79c0c0b1..68a8f0e5 100644 --- a/fuzzers/065-gtp-common-pips/Makefile +++ b/fuzzers/065-gtp-common-pips/Makefile @@ -7,7 +7,7 @@ # SPDX-License-Identifier: ISC export FUZDIR=$(shell pwd) PIP_TYPE?=gtp_common_${XRAY_PART} -SEG_TYPE?=gtp_common +SEG_TYPE?=gtp_common_mid_left PIPLIST_TCL=$(FUZDIR)/gtp_common_pip_list.tcl BUILD_DIR = ${FUZDIR}/build_${XRAY_PART} @@ -22,6 +22,8 @@ SEGMATCH_FLAGS=-c 2 SPECIMENS_DEPS=$(BUILD_DIR)/cmt_regions.csv A_PIPLIST=gtp_common_${XRAY_PART}.txt +CHECK_ARGS= --zero-entries --timeout-iters 5 --todo-dir $(BUILD_DIR)/todo + include ../pip_loop.mk $(BUILD_DIR)/segbits_gtp_common.rdb: $(SPECIMENS_OK) diff --git a/fuzzers/065-gtp-common-pips/generate.py b/fuzzers/065-gtp-common-pips/generate.py index ba60b252..52e4db33 100644 --- a/fuzzers/065-gtp-common-pips/generate.py +++ b/fuzzers/065-gtp-common-pips/generate.py @@ -88,7 +88,7 @@ def main(): tile_type = pips_srcs_dsts["type"] pips = pips_srcs_dsts["pips"] - for src, dst in pipdata["GTP_COMMON_MID_LEFT"]: + for src, dst in pipdata["GTP_COMMON"]: if (src, dst) in ignpip: pass elif (src, dst) in pips: diff --git a/fuzzers/065-gtp-common-pips/generate.tcl b/fuzzers/065-gtp-common-pips/generate.tcl index 8b8ee17d..111f8acb 100644 --- a/fuzzers/065-gtp-common-pips/generate.tcl +++ b/fuzzers/065-gtp-common-pips/generate.tcl @@ -39,7 +39,7 @@ proc shuffle_list {list} { # Get the dictionary of nets with one corresponding source wire # of a PIP from the todo list -proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destinations {verbose false}} { +proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destinations {verbose false} {cmt_net false}} { set todo_map [load_todo $direction] set nets [get_nets] set todo_nets [dict create] @@ -70,6 +70,10 @@ proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destina set wire [lindex [split $wire /] 1] set tile_type [get_property TILE_TYPE [get_tiles $tile]] + if { $cmt_net } { + dict set todo_nets $net [list $tile $wire] + continue + } if { ![dict exists $todo_map $wire] } { continue @@ -122,40 +126,11 @@ proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destina puts "Interesting net $net (including $wire) is being rerouted." } } + return $todo_nets } -proc remove_net_randomly {wire_regexp} { - # Randomly removes a net containing a given wire - set nets [get_nets] - set net_to_remove "" - - foreach net $nets { - set wires [get_wires -of_objects $net] - - foreach wire $wires { - if [regexp $wire_regexp $wire] { - set net_to_remove $net - break - } - } - } - - if { $net_to_remove != "" && rand() <= 0.1 } { - puts "Removing net: $net_to_remove" - remove_net $net_to_remove - } -} - proc route_todo {} { - - # It is very common to have nets passing through the - # HCLK_GTP_CK_IN[01] wires, resulting in results. - # This step removes the net containing the problematic - # wire with a 10% probability - remove_net_randomly "HCLK_GTP_CK_IN0" - remove_net_randomly "HCLK_GTP_CK_IN1" - set used_destinations [dict create] set todo_map [load_todo "dsts"] set gtp_channel_nets [get_nets_with_todo_pip_wires "dsts" "gtp_channel_clock" "GTPE2_COMMON_\[TR\]XOUTCLK_MUX_\[0123\]" $used_destinations true] @@ -239,8 +214,8 @@ proc route_todo {} { } set todo_map [load_todo "srcs"] - set pll_nets [get_nets_with_todo_pip_wires "srcs" "pll_clock" "HCLK_GTP_CK_IN" $used_destinations true] - set mmcm_nets [get_nets_with_todo_pip_wires "srcs" "mmcm_clock" "HCLK_GTP_CK_IN" $used_destinations true] + set pll_nets [get_nets_with_todo_pip_wires "srcs" "pll_clock" "HCLK_GTP_CK_IN" $used_destinations true true] + set mmcm_nets [get_nets_with_todo_pip_wires "srcs" "mmcm_clock" "HCLK_GTP_CK_IN" $used_destinations true true] set cmt_nets [dict merge $pll_nets $mmcm_nets] puts "CMT nets: $cmt_nets" dict for {net tile_wire} $cmt_nets { @@ -304,13 +279,11 @@ proc route_todo {} { set src_wire [lindex $wire_pair 0] set dst_wire [lindex $wire_pair 1] - if { [dict exists $used_destinations "$tile/$dst_wire"] } { - puts "Not routing to $tile / $dst_wire, in use." - continue - } + set used_dst_wire [dict exists $used_destinations "$tile/$dst_wire"] + set used_src_wire [dict exists $used_destinations "$tile/$src_wire"] - if { [dict exists $used_destinations "$tile/$src_wire"] } { - puts "Not routing to $tile / $src_wire, in use." + if { $used_dst_wire || $used_src_wire } { + puts "Not routing to $tile / $src_wire or $dst_wire, in use." continue } diff --git a/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl index a2856474..fad8b60b 100644 --- a/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl +++ b/fuzzers/065-gtp-common-pips/gtp_common_pip_list.tcl @@ -31,7 +31,7 @@ proc print_tile_pips {tile_type filename} { set dst_gtp_mux_match [regexp {GTPE2_COMMON_[RT]XOUTCLK_MUX_[0123]} $dst_wire] if { $dst_hclk_match || $dst_ibufds_mux_match || $dst_gtp_mux_match } { - set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" + set pip_string "GTP_COMMON.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" if ![dict exists $pips $pip_string] { puts $fp $pip_string dict set pips $pip_string 1 diff --git a/fuzzers/065-gtp-common-pips/top.py b/fuzzers/065-gtp-common-pips/top.py index 4cae8350..8e990c1b 100644 --- a/fuzzers/065-gtp-common-pips/top.py +++ b/fuzzers/065-gtp-common-pips/top.py @@ -30,6 +30,28 @@ def read_site_to_cmt(): yield (site, cmt) +def todo_pips(): + """ Returns a boolean tuple corresponding to the presence or not + of a type of PIP in the todo list.""" + + is_gtp_channel_left = False + is_ibufds_left = False + is_cmt_left = False + + with open("../../todo_all.txt", "r") as todo_file: + for line in todo_file: + fields = line.split(".") + + if "HCLK_GTP_CK_IN" not in fields[1]: + continue + + is_gtp_channel_left |= fields[2].startswith("GTPE2_COMMON") + is_ibufds_left |= fields[2].startswith("IBUFDS") + is_cmt_left |= fields[2].startswith("HCLK") + + return (is_gtp_channel_left, is_ibufds_left, is_cmt_left) + + class ClockSources(object): """ Class for tracking clock sources. """ @@ -288,7 +310,7 @@ module top( );""".format(site=site, rx=gtp_channel_clock_rx, tx=gtp_channel_clock_tx)) for cmt in cmt_with_gtp: - cmt_clock_used = 0 + cmt_clock_used = False for _, bufhce in gen_sites('BUFHCE'): if site_to_cmt[bufhce] != cmt: @@ -296,12 +318,16 @@ module top( chance = random.random() - if chance < 0.2 or cmt_clock_used < 3: - cmt_clock_used += 1 + use_gtp_channel, use_ibufds, use_cmt = todo_pips() + + if (chance < 0.3 and use_cmt) or not cmt_clock_used: + # There must always be at least one CMT clock used + # to trigger the bits for the GTP_COMMON and IBUFDS pips + cmt_clock_used = True clock_name = cmt_clock_sources.get_random_source(cmt) - elif chance > 0.2 and chance < 0.4: + elif chance > 0.3 and chance < 0.4 and use_ibufds: clock_name = ibufds_clock_sources.get_random_source(cmt) - elif chance < 0.6: + elif chance < 0.7 and use_gtp_channel: clock_name = gtp_channel_clock_sources.get_random_source(cmt) else: continue From f48608dd1c84aca6fa346901bdd13f5c0f6eb309 Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Fri, 29 Jan 2021 17:50:44 +0100 Subject: [PATCH 5/6] 064-gtp-channel-conf: fix pushdb race condition issue Signed-off-by: Alessandro Comodi --- fuzzers/064-gtp-channel-conf/pushdb.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/064-gtp-channel-conf/pushdb.sh b/fuzzers/064-gtp-channel-conf/pushdb.sh index f976e51b..ed1e9e40 100644 --- a/fuzzers/064-gtp-channel-conf/pushdb.sh +++ b/fuzzers/064-gtp-channel-conf/pushdb.sh @@ -7,7 +7,7 @@ # # SPDX-License-Identifier: ISC -if ! test $(find . -name "segdata_gtp_channel_[0123]_mid_*.txt" | wc -c) -eq 0 +if ! test $(find ${BUILD_DIR} -name "segdata_gtp_channel_[0123]_mid_*.txt" | wc -c) -eq 0 then ${XRAY_MERGEDB} gtp_channel_0_mid_left ${BUILD_DIR}/segbits_gtp_channelx.db ${XRAY_MERGEDB} gtp_channel_1_mid_left ${BUILD_DIR}/segbits_gtp_channelx.db @@ -27,7 +27,7 @@ then ${XRAY_MERGEDB} mask_gtp_channel_3_mid_right ${BUILD_DIR}/mask_gtp_channelx.db fi -if ! test $(find . -name "segdata_gtp_channel_[0123].txt" | wc -c) -eq 0 +if ! test $(find ${BUILD_DIR} -name "segdata_gtp_channel_[0123].txt" | wc -c) -eq 0 then ${XRAY_MERGEDB} gtp_channel_0 ${BUILD_DIR}/segbits_gtp_channelx.db ${XRAY_MERGEDB} gtp_channel_1 ${BUILD_DIR}/segbits_gtp_channelx.db From 6ad64bc4faffac61f36cd8f84a49f0baac44b2c5 Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Tue, 2 Feb 2021 19:34:52 +0100 Subject: [PATCH 6/6] 065-gtp-common-pips: add comments Signed-off-by: Alessandro Comodi --- fuzzers/065-gtp-common-pips/generate.py | 4 ++++ fuzzers/065-gtp-common-pips/generate.tcl | 30 +++++++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/fuzzers/065-gtp-common-pips/generate.py b/fuzzers/065-gtp-common-pips/generate.py index 52e4db33..621e78ed 100644 --- a/fuzzers/065-gtp-common-pips/generate.py +++ b/fuzzers/065-gtp-common-pips/generate.py @@ -17,9 +17,13 @@ import os.path def bitfilter(frame, word): word = int(word / 32) + # Clock-related PIPs in the GTP_COMMON_MID_[LEFT|RIGHT] have bits + # from frame 0 to 7, hence, all the other frames are skipped. if frame not in [0, 1, 2, 3, 4, 5, 6, 7]: return False + # All the Clock-related PIPs have bits at word 50 in the GTP_COMMON tile. + # Filter out all bits not belonging to word 50. if word != 50: return False diff --git a/fuzzers/065-gtp-common-pips/generate.tcl b/fuzzers/065-gtp-common-pips/generate.tcl index 111f8acb..abfb0c76 100644 --- a/fuzzers/065-gtp-common-pips/generate.tcl +++ b/fuzzers/065-gtp-common-pips/generate.tcl @@ -131,10 +131,14 @@ proc get_nets_with_todo_pip_wires {direction net_regexp wire_regexp used_destina } proc route_todo {} { + set verbose false + set used_destinations [dict create] + + # Re-route GTP-related nets, which are originated from the GTPE2_CHANNEL and/or IBUFDS_GTE2 primitives. set todo_map [load_todo "dsts"] - set gtp_channel_nets [get_nets_with_todo_pip_wires "dsts" "gtp_channel_clock" "GTPE2_COMMON_\[TR\]XOUTCLK_MUX_\[0123\]" $used_destinations true] - set ibufds_nets [get_nets_with_todo_pip_wires "dsts" "ibufds_clock" "IBUFDS_GTPE2_\[01\]_MGTCLKOUT_MUX" $used_destinations true] + set gtp_channel_nets [get_nets_with_todo_pip_wires "dsts" "gtp_channel_clock" "GTPE2_COMMON_\[TR\]XOUTCLK_MUX_\[0123\]" $used_destinations $verbose] + set ibufds_nets [get_nets_with_todo_pip_wires "dsts" "ibufds_clock" "IBUFDS_GTPE2_\[01\]_MGTCLKOUT_MUX" $used_destinations $verbose] set gtp_nets [dict merge $gtp_channel_nets $ibufds_nets] puts "GTP nets: $gtp_nets" dict for {net tile_wire} $gtp_nets { @@ -213,9 +217,10 @@ proc route_todo {} { } } + # Re-route CMT-related nets, which are originated from the fabric's PLL/MMCM primitives set todo_map [load_todo "srcs"] - set pll_nets [get_nets_with_todo_pip_wires "srcs" "pll_clock" "HCLK_GTP_CK_IN" $used_destinations true true] - set mmcm_nets [get_nets_with_todo_pip_wires "srcs" "mmcm_clock" "HCLK_GTP_CK_IN" $used_destinations true true] + set pll_nets [get_nets_with_todo_pip_wires "srcs" "pll_clock" "HCLK_GTP_CK_IN" $used_destinations $verbose true] + set mmcm_nets [get_nets_with_todo_pip_wires "srcs" "mmcm_clock" "HCLK_GTP_CK_IN" $used_destinations $verbose true] set cmt_nets [dict merge $pll_nets $mmcm_nets] puts "CMT nets: $cmt_nets" dict for {net tile_wire} $cmt_nets { @@ -230,19 +235,25 @@ proc route_todo {} { continue } + # All clock nets which have a source belonging to a PLL/MMCM tile can be routed to any + # HCLK_GTP_CK_MUX --> HCLK_GTP_CK_IN wire pair, hence we build a list of all the remaining + # PIPs to choose from. puts "Rerouting net $net at $tile / $wire (type $tile_type)" puts "Previous target wire: $old_origin_dst_wire" - set old_origin_node [get_nodes -of_objects $old_origin_dst_wire] - if [regexp "HCLK_GTP_CK_IN.*" $old_origin_dst_wire match group] { - set old_target_side $group - } foreach dst $dsts { set srcs [dict get $todo_map $dst] foreach src $srcs { - + # For each HCLK_GTP_CK_IN wire, get the source node (HCLK_GTP_CK_MUX) from the todo_map + # that still needs to be documented. + # + # Each HCLK_GTP_CK_IN has two possible HCLK_GTP_CK_MUX sources to be paired with. set src_wire [lindex $src 1] + # There are PIPs that do connect HCLK_GTP_CK_IN wires to GTP_CHANNEL- and IBUFDS-related wires. + # + # These kinds of PIPs are solved at a previous stage of this process, hence, the todo PIP list should + # not contain these src/dst pairs at this stage, but only PIPs to the fabric (PLL/MMCM nets). set is_gtp_net 1 if [regexp "HCLK_GTP_CK_MUX.*" $src_wire match group] { set is_gtp_net 0 @@ -282,6 +293,7 @@ proc route_todo {} { set used_dst_wire [dict exists $used_destinations "$tile/$dst_wire"] set used_src_wire [dict exists $used_destinations "$tile/$src_wire"] + # If one between MUX or IN wire pairs is already used, skip this todo if { $used_dst_wire || $used_src_wire } { puts "Not routing to $tile / $src_wire or $dst_wire, in use." continue