diff --git a/fuzzers/047-hclk-ioi-pips/Makefile b/fuzzers/047-hclk-ioi-pips/Makefile new file mode 100644 index 00000000..29d68354 --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/Makefile @@ -0,0 +1,46 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=hclk_ioi3 +PIPLIST_TCL=$(FUZDIR)/hclk_ioi3_pip_list.tcl +TODO_RE=".*" +# FIXME Modify fuzzer to solve PIPs that drive the BUFIO and BUFR from ILOGIC clock or through the IOI tile. +EXCLUDE_RE=".*\.HCLK_IOI_((RCLK_IMUX[0-3])|(I2IOCLK))" + +MAKETODO_FLAGS= --sides "" --pip-type ${PIP_TYPE} --seg-type ${PIP_TYPE} --re $(TODO_RE) --exclude-re $(EXCLUDE_RE) +N = 50 + +SEGMATCH_FLAGS=-c 3 -m 15 -M 45 +SPECIMENS_DEPS=build/cmt_regions.csv +A_PIPLIST=hclk_ioi3.txt + +include ../pip_loop.mk + +build/segbits_hclk_ioi3.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_ioi3.rdb \ + $(shell find build -name segdata_hclk_ioi3.txt) + +build/segbits_hclk_ioi3.db: build/segbits_hclk_ioi3.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_hclk_ioi3.rdb \ + --seg-fn-out build/segbits_hclk_ioi3.db + + # Keep a copy to track iter progress + cp build/segbits_hclk_ioi3.rdb build/$(ITER)/segbits_hclk_ioi3.rdb + + + ${XRAY_MASKMERGE} build/mask_hclk_ioi3.db \ + $(shell find build -name segdata_hclk_ioi3.txt) + +database: build/segbits_hclk_ioi3.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} hclk_ioi3 build/segbits_hclk_ioi3.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} hclk_ioi3 build/segbits_hclk_ioi3.db + ${XRAY_MERGEDB} mask_hclk_ioi build/mask_hclk_ioi3.db + +.PHONY: database pushdb diff --git a/fuzzers/047-hclk-ioi-pips/README.md b/fuzzers/047-hclk-ioi-pips/README.md new file mode 100644 index 00000000..8f1c36a5 --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/README.md @@ -0,0 +1,3 @@ +# HCLK_IOI interconnect fuzzer + +Solves pips located within the HCLK_IOI switch box. diff --git a/fuzzers/047-hclk-ioi-pips/bits.dbf b/fuzzers/047-hclk-ioi-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/047-hclk-ioi-pips/generate.py b/fuzzers/047-hclk-ioi-pips/generate.py new file mode 100644 index 00000000..cd87f62a --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/generate.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import os +import os.path + + +def bitfilter(frame, word): + if frame < 26: + return False + return True + + +def main(): + segmk = Segmaker("design.bits") + + tiledata = {} + pipdata = {} + ignpip = set() + tile_ports = {} + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'hclk_ioi3', 'hclk_ioi3.txt')) 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) + + 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('HCLK_IOI3'): + 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) + + if pnum == 1 or pdir == 0: + ignpip.add((src, dst)) + + for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + pips = pips_srcs_dsts["pips"] + + 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) + 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/047-hclk-ioi-pips/generate.tcl b/fuzzers/047-hclk-ioi-pips/generate.tcl new file mode 100644 index 00000000..c680e900 --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/generate.tcl @@ -0,0 +1,324 @@ +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 +} + +# 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] + puts $todo_map + 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 =~ "*HCLK_IOI*" } -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 HCLK port, 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 route_todo {} { + set used_destinations [dict create] + set todo_map [load_todo "dsts"] + set serdes_nets [get_nets_with_todo_pip_wires "dsts" "serdes_clk_ILOGIC" "HCLK_IOI_CK_IGCLK" $used_destinations] + puts "Serdes nets: $serdes_nets" + dict for {net tile_wire} $serdes_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_target_wire [get_wires -of_objects $net -filter {TILE_NAME =~ "*HCLK_IOI*" && NAME =~ "*HCLK_IOI_LEAF_GCLK_*"}] + if {$old_target_wire == {}} { + continue + } + if {[dict exists $used_destinations $old_target_wire]} { + puts "Not routing to $old_target_wire, in use." + continue + } + puts "Rerouting net $net at $tile / $wire (type $tile_type)" + puts "Previous target wire: $old_target_wire" + set old_target_node [get_nodes -of_objects $old_target_wire] + if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $old_target_wire match group] { + set old_target_side $group + } + foreach dst $dsts { + set dst_tile_type [lindex $dst 0] + if {$dst_tile_type != $tile_type} { + continue + } + + set dst_wire [lindex $dst 1] + + set is_gclk_net 0 + if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $dst_wire match group] { + set is_gclk_net 1 + set dst_side $group + } + + if {$is_gclk_net == 0 || $dst_side != $old_target_side} { + continue + } + + lappend todos $dst_wire + } + + puts "All todos for $tile_type / $wire" + foreach dst_wire $todos { + puts " - $dst_wire" + } + set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + puts "Origin node: $origin_node" + route_design -unroute -nets $net + + # Find an input in the todo list that this can 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 target_wire [get_wires "$tile/$dst_wire"] + set target_node [get_nodes -of_objects $target_wire] + if {[llength $target_node] == 0} { + error "Failed to find node for $tile/$dst_wire." + } + + set old_net [get_nets -of_objects $target_node -quiet] + if {$old_net == {}} { + continue + } + puts "Unrouting the old net: $old_net" + route_design -unroute -nets $old_net + set old_origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $old_net]] + + # Route the net through the desired node + puts "Attempting to route to $target_node for net $net." + route_via $net [list $target_node] + + puts "Attempting to route to $old_target_node for net $old_net." + # Route the old net through the old target node + route_via $old_net [list $old_target_node ] + + puts "Origin node: $origin_node, Old origin node: $old_origin_node" + puts "Target wire: $target_wire, Old target wire: $old_target_wire" + puts "Target node: $target_node, Old target node: $old_target_node" + + dict set used_destinations "$target_wire" 1 + dict set used_destinations "$old_target_wire" 1 + + break + } + } + + set todo_map [load_todo "srcs"] + set idelayctrl_nets [get_nets_with_todo_pip_wires "srcs" "IDELAYCTRL" "HCLK_IOI_IDELAYCTRL_REFCLK" $used_destinations] + puts "Idelayctrl nets: $idelayctrl_nets" + dict for {net tile_wire} $idelayctrl_nets { + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set srcs [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 =~ "*HCLK_IOI*" && NAME =~ "*HCLK_IOI_LEAF_GCLK_*"}] + 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] + if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $old_origin_wire match group] { + set old_target_side $group + } + foreach src $srcs { + set src_tile_type [lindex $src 0] + if {$src_tile_type != $tile_type} { + continue + } + + set src_wire [lindex $src 1] + + set is_gclk_net 0 + if [regexp "HCLK_IOI_LEAF_GCLK_\(\(TOP\)|\(BOT\)\).*" $src_wire match group] { + set is_gclk_net 1 + } + + if {$is_gclk_net == 0} { + continue + } + + lappend todos $src_wire + } + + puts "All todos for $tile_type / $wire" + foreach src_wire $todos { + puts " - $src_wire" + } + 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 src_wire $todos { + if { [dict exists $used_destinations "$tile/$src_wire"] } { + puts "Not routing to $tile / $src_wire, in use." + continue + } + + set origin_wire [get_wires "$tile/$src_wire"] + set origin_node [get_nodes -of_objects $origin_wire] + if {[llength $origin_node] == 0} { + error "Failed to find node for $tile/$src_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 $src_wire for net $net." + route_via $net [list $origin_node] + + 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 + } + } +} + +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-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-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 CLOCK_DEDICATED_ROUTE FALSE [get_nets] + + place_design + route_design + route_todo + route_design + + + write_checkpoint -force design.dcp + write_bitstream -force design.bit + write_pip_txtdata design.txt +} + +run diff --git a/fuzzers/047-hclk-ioi-pips/hclk_ioi3_pip_list.tcl b/fuzzers/047-hclk-ioi-pips/hclk_ioi3_pip_list.tcl new file mode 100644 index 00000000..afcb74d7 --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/hclk_ioi3_pip_list.tcl @@ -0,0 +1,39 @@ +proc print_tile_pips {tile_type filename} { + set fp [open $filename w] + set pips [dict create] + foreach tile [get_tiles -filter "TYPE == $tile_type"] { + puts "Dumping PIPs for tile $tile ($tile_type) to $filename." + 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 + } + + if {[llength [get_nodes -uphill -of_objects $dst_node]] > 1} { + 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 + } + } else { + puts "Ignoring PIP: $pip" + } + } + } + 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 HCLK_IOI3 hclk_ioi3.txt diff --git a/fuzzers/047-hclk-ioi-pips/output_cmt.tcl b/fuzzers/047-hclk-ioi-pips/output_cmt.tcl new file mode 100644 index 00000000..30bbd3e1 --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/output_cmt.tcl @@ -0,0 +1,11 @@ +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 PLLE2_ADV BUFHCE IOB33M BUFR BUFMRCE BUFIO ILOGICE3 IDELAYCTRL} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/047-hclk-ioi-pips/top.py b/fuzzers/047-hclk-ioi-pips/top.py new file mode 100644 index 00000000..7d7da1eb --- /dev/null +++ b/fuzzers/047-hclk-ioi-pips/top.py @@ -0,0 +1,457 @@ +""" Emits top.v's for various BUFHCE routing inputs. """ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.lut_maker import LutMaker +from prjxray.db import Database +from io import StringIO + +CMT_XY_FUN = util.create_xy_fun(prefix='') + + +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. + + cmt='ANY' indicates that this source can be routed to any CMT. + """ + if cmt not in self.sources: + self.sources[cmt] = [] + + self.sources[cmt].append(source) + self.source_to_cmt[source] = cmt + + def get_random_source(self, cmt, no_repeats=False): + """ 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 main(): + """ + HCLK_IOI has the following inputs: + + 12 (east) BUFH from the right side of the HROW + 12 (west) Bounce PIPs from one BUFH to any of 6 GCLK_BOT and 6 GCLK_TOP + 4 (east) PHSR_PERFCLK (IOCLK_PLL) from HCLK_CLB to input of BUFIO + 8 (4 north and 4 south) BUFR CLR and CE + 2 (south) I2IOCLK to input of BUFR + 2 (north) I2IOCLK to input of BUFR + 2 RCLK IMUX (IMUX0 and IMUX1) choosing input of BUFR + + outputs: + 4 (east) BUFRCLK - from BUFR to HROW + 4 (north) BUFR2IO - from BUFR + 4 (north) IOCLK from BUFIO + + """ + + global_clock_sources = ClockSources() + cmt_clock_sources = ClockSources() + cmt_fast_clock_sources = ClockSources(4) + bufr_clock_sources = ClockSources() + bufio_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()) + 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 + + def serdes_relative_location(tile, site): + (serdes_loc_x, serdes_loc_y) = grid.loc_of_tilename(tile) + serdes_clk_reg = site_to_cmt[site] + for tile_name in sorted(grid.tiles()): + if 'HCLK_IOI3' in tile_name: + (hclk_tile_loc_x, + hclk_tile_loc_y) = grid.loc_of_tilename(tile_name) + if hclk_tile_loc_x == serdes_loc_x: + gridinfo = grid.gridinfo_at_loc( + (hclk_tile_loc_x, hclk_tile_loc_y)) + random_site = next(iter(gridinfo.sites.keys())) + hclk_clk_reg = site_to_cmt[random_site] + if hclk_clk_reg == serdes_clk_reg: + if serdes_loc_y < hclk_tile_loc_y: + return "TOP" + elif serdes_loc_y > hclk_tile_loc_y: + return "BOTTOM" + else: + assert False + + 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 + + print( + ''' +module top(); + (* KEEP, DONT_TOUCH *) + LUT6 dummy(); + ''') + + luts = LutMaker() + bufs = StringIO() + + for _, site in gen_sites('MMCME2_ADV'): + mmcm_clocks = [ + 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(13) + ] + + for idx, clk in enumerate(mmcm_clocks): + if idx < 4: + cmt_fast_clock_sources.add_clock_source(clk, site_to_cmt[site]) + else: + 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}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + MMCME2_ADV pll_{site} ( + .CLKIN1(cin1_{site}), + .CLKIN2(cin2_{site}), + .CLKFBIN(clkfbin_{site}), + .CLKOUT0({c0}), + .CLKOUT0B({c4}), + .CLKOUT1({c1}), + .CLKOUT1B({c5}), + .CLKOUT2({c2}), + .CLKOUT2B({c6}), + .CLKOUT3({c3}), + .CLKOUT3B({c7}), + .CLKOUT4({c8}), + .CLKOUT5({c9}), + .CLKOUT6({c10}), + .CLKFBOUT({c11}), + .CLKFBOUTB({c12}) + ); + """.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], + c7=mmcm_clocks[7], + c8=mmcm_clocks[8], + c9=mmcm_clocks[9], + c10=mmcm_clocks[10], + c11=mmcm_clocks[11], + c12=mmcm_clocks[12], + )) + + for _, site in gen_sites('PLLE2_ADV'): + 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_name, site in gen_sites('BUFHCE'): + print( + """ + wire I_{site}; + wire O_{site}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFHCE buf_{site} ( + .I(I_{site}), + .O(O_{site}) + );""".format(site=site), + file=bufs) + global_clock_sources.add_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site]) + + hclks_used_by_clock_region = {} + for cmt in site_to_cmt.values(): + hclks_used_by_clock_region[cmt] = set() + + def check_hclk_src(src, src_cmt): + if len(hclks_used_by_clock_region[src_cmt] + ) >= 12 and src not in hclks_used_by_clock_region[src_cmt]: + return None + else: + hclks_used_by_clock_region[src_cmt].add(src) + return src + + cmt_clks_used_by_clock_region = {} + for cmt in site_to_cmt.values(): + cmt_clks_used_by_clock_region[cmt] = list() + + def check_cmt_clk_src(src, src_clock_region): + print( + "//src: {}, clk_reg: {}, len {}".format( + src, src_clock_region, + len(cmt_clks_used_by_clock_region[src_clock_region]))) + if len(cmt_clks_used_by_clock_region[src_clock_region]) >= 4: + return None + else: + cmt_clks_used_by_clock_region[src_clock_region].append(src) + return src + + #Add IDELAYCTRL + idelayctrl_in_clock_region = {} + for cmt in site_to_cmt.values(): + idelayctrl_in_clock_region[cmt] = False + for _, site in gen_sites('IDELAYCTRL'): + if random.random() < 0.5: + wire_name = global_clock_sources.get_random_source( + site_to_cmt[site], no_repeats=False) + if wire_name is None: + continue + src_cmt = global_clock_sources.source_to_cmt[wire_name] + wire_name = check_hclk_src(wire_name, src_cmt) + + if wire_name is None: + continue + idelayctrl_in_clock_region[src_cmt] = True + print( + """ + assign I_{site} = {clock_source}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + IDELAYCTRL idelay_ctrl_{site} ( + .RDY(), + .REFCLK(I_{site}), + .RST() + );""".format(site=site, clock_source=wire_name)) + + # Add SERDES driven by BUFH or MMCM + for tile, site in gen_sites('ILOGICE3'): + wire_name = None + clock_region = site_to_cmt[site] + if clock_region not in clock_region_limit: + # Select serdes limit and relative location per clock region + serdes_location = random.choice(["TOP", "BOTTOM", "ANY"]) + if serdes_location in "ANY": + #We want TOP and BOTTOM IGCLK PIPs occupied but leave one slot for IDELAYCTRL + if idelayctrl_in_clock_region[clock_region]: + clock_region_limit[clock_region] = 0 if random.random( + ) < 0.2 else 11 + else: + clock_region_limit[clock_region] = 0 if random.random( + ) < 0.2 else 12 + else: + if idelayctrl_in_clock_region[clock_region]: + clock_region_limit[clock_region] = 0 if random.random( + ) < 0.2 else 5 + else: + clock_region_limit[clock_region] = 0 if random.random( + ) < 0.2 else 6 + + clock_region_serdes_location[clock_region] = serdes_location + + # We reached the limit of hclks in this clock region + if clock_region_limit[clock_region] == 0: + continue + + # Add a serdes if it's located at the correct side from the HCLK_IOI tile + if clock_region_serdes_location[clock_region] not in "ANY" and \ + serdes_relative_location(tile, site) != clock_region_serdes_location[clock_region]: + continue + if random.random() > 0.3: + wire_name = global_clock_sources.get_random_source( + site_to_cmt[site], no_repeats=True) + if wire_name is None: + continue + src_cmt = global_clock_sources.source_to_cmt[wire_name] + wire_name = check_hclk_src(wire_name, src_cmt) + if wire_name is None: + print("//wire is None") + continue + clock_region_limit[clock_region] -= 1 + print( + """ + assign serdes_clk_{site} = {clock_source};""".format( + site=site, clock_source=wire_name)) + else: + wire_name = cmt_fast_clock_sources.get_random_source( + site_to_cmt[site], no_repeats=False) + if wire_name is None: + continue + src_cmt = cmt_fast_clock_sources.source_to_cmt[wire_name] + wire_name = check_cmt_clk_src(wire_name, src_cmt) + if wire_name is None: + continue + bufio_site = get_clock_region_site("BUFIO", clock_region) + if bufio_site is None: + continue + print( + """ + assign serdes_clk_{serdes_loc} = O_{site}; + assign I_{site} = {clock_source}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFIO bufio_{site} ( + .O(O_{site}), + .I(I_{site}) + );""".format(site=bufio_site, clock_source=wire_name, serdes_loc=site)) + + print( + "// clock_region: {} {}".format( + clock_region, clock_region_serdes_location[clock_region])) + print( + """ + (* KEEP, DONT_TOUCH, LOC = "{loc}" *) + ISERDESE2 #( + .DATA_RATE("SDR"), + .DATA_WIDTH(4), + .DYN_CLKDIV_INV_EN("FALSE"), + .DYN_CLK_INV_EN("FALSE"), + .INIT_Q1(1'b0), + .INIT_Q2(1'b0), + .INIT_Q3(1'b0), + .INIT_Q4(1'b0), + .INTERFACE_TYPE("OVERSAMPLE"), + .IOBDELAY("NONE"), + .NUM_CE(2), + .OFB_USED("FALSE"), + .SERDES_MODE("MASTER"), + .SRVAL_Q1(1'b0), + .SRVAL_Q2(1'b0), + .SRVAL_Q3(1'b0), + .SRVAL_Q4(1'b0) + ) + ISERDESE2_inst_{loc} ( + .CLK(serdes_clk_{loc}), + .CLKB(), + .CLKDIV(), + .D(1'b0), + .DDLY(), + .OFB(), + .OCLKB(), + .RST(), + .SHIFTIN1(), + .SHIFTIN2() + ); + """.format(loc=site, clock_source=wire_name)) + + # BUFRs + for _, site in gen_sites('BUFR'): + if random.random() < 0.5: + wire_name = cmt_fast_clock_sources.get_random_source( + site_to_cmt[site], no_repeats=False) + if wire_name is None: + continue + src_cmt = cmt_fast_clock_sources.source_to_cmt[wire_name] + wire_name = check_cmt_clk_src(wire_name, src_cmt) + if wire_name is None: + continue + bufr_clock_sources.add_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site]) + print( + """ + assign I_{site} = {clock_source}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR bufr_{site} ( + .O(O_{site}), + .I(I_{site}) + );""".format(site=site, clock_source=wire_name), + file=bufs) + + for _, site in gen_sites('MMCME2_ADV'): + wire_name = bufr_clock_sources.get_random_source( + site_to_cmt[site], no_repeats=True) + + if wire_name is None: + continue + print( + """ + assign cin1_{site} = {wire_name};""".format( + site=site, wire_name=wire_name)) + + print(bufs.getvalue()) + + print("endmodule") + + +if __name__ == '__main__': + main() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index b0662990..ae5ff042 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -95,6 +95,7 @@ $(eval $(call fuzzer,043-clk-rebuf-pips,005-tilegrid)) $(eval $(call fuzzer,044-clk-bufg-pips,046-clk-bufg-muxed-pips)) $(eval $(call fuzzer,045-hclk-cmt-pips,005-tilegrid)) $(eval $(call fuzzer,046-clk-bufg-muxed-pips,005-tilegrid)) +$(eval $(call fuzzer,047-hclk-ioi-pips,005-tilegrid)) $(eval $(call fuzzer,048-int-piplist,005-tilegrid)) $(eval $(call fuzzer,049-int-imux-gfan,048-int-piplist)) $(eval $(call fuzzer,050-pip-seed,048-int-piplist)) diff --git a/utils/mergedb.sh b/utils/mergedb.sh index f47548c3..553ea3b5 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -123,6 +123,9 @@ case "$1" in cfg_center_mid) cp "$2" "$tmp1" ;; + hclk_ioi3) + cp "$2" "$tmp1" ;; + mask_*) db=$XRAY_DATABASE_DIR/$XRAY_DATABASE/$1.db ismask=true