diff --git a/fuzzers/005-tilegrid/Makefile b/fuzzers/005-tilegrid/Makefile index e6cffaad..fc2b3c5d 100644 --- a/fuzzers/005-tilegrid/Makefile +++ b/fuzzers/005-tilegrid/Makefile @@ -15,6 +15,7 @@ TILEGRID_TDB_DEPENDENCIES += cfg_int/build/segbits_tilegrid.tdb TILEGRID_TDB_DEPENDENCIES += monitor_int/build/segbits_tilegrid.tdb TILEGRID_TDB_DEPENDENCIES += clk_hrow/build/segbits_tilegrid.tdb TILEGRID_TDB_DEPENDENCIES += clk_bufg/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += hclk_cmt/build/segbits_tilegrid.tdb GENERATE_FULL_ARGS= ifeq (${XRAY_DATABASE}, zynq7) @@ -104,6 +105,9 @@ clk_hrow/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json clk_bufg/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json cd clk_bufg && $(MAKE) +hclk_cmt/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd hclk_cmt && $(MAKE) + build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES) python3 add_tdb.py \ --fn-in build/basicdb/tilegrid.json \ @@ -139,6 +143,7 @@ clean: cd orphan_int_column && $(MAKE) clean cd clk_hrow && $(MAKE) clean cd clk_bufg && $(MAKE) clean + cd hclk_cmt && $(MAKE) clean .PHONY: database pushdb clean run diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py index 3dc7eae3..f5b32147 100644 --- a/fuzzers/005-tilegrid/add_tdb.py +++ b/fuzzers/005-tilegrid/add_tdb.py @@ -86,6 +86,7 @@ def run(fn_in, fn_out, verbose=False): ("dsp/build/segbits_tilegrid.tdb", 28, 10), ("clk_hrow/build/segbits_tilegrid.tdb", 30, 18), ("clk_bufg/build/segbits_tilegrid.tdb", 30, 8), + ("hclk_cmt/build/segbits_tilegrid.tdb", 30, 10), ("clb_int/build/segbits_tilegrid.tdb", int_frames, int_words), ("iob_int/build/segbits_tilegrid.tdb", int_frames, int_words), ("bram_int/build/segbits_tilegrid.tdb", int_frames, int_words), diff --git a/fuzzers/005-tilegrid/hclk_cmt/Makefile b/fuzzers/005-tilegrid/hclk_cmt/Makefile new file mode 100644 index 00000000..c6172fe8 --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_cmt/Makefile @@ -0,0 +1,4 @@ +N ?= 5 +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 5 --dframe 1C" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/hclk_cmt/generate.tcl b/fuzzers/005-tilegrid/hclk_cmt/generate.tcl new file mode 100644 index 00000000..5a69791f --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_cmt/generate.tcl @@ -0,0 +1,3 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +generate_top diff --git a/fuzzers/005-tilegrid/hclk_cmt/top.py b/fuzzers/005-tilegrid/hclk_cmt/top.py new file mode 100644 index 00000000..3fd68bc0 --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_cmt/top.py @@ -0,0 +1,66 @@ +import os +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + + +def gen_sites(): + db = Database(util.get_db_root()) + grid = db.grid() + for tile_name in sorted(grid.tiles()): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + sites = [] + for site, site_type in gridinfo.sites.items(): + if site_type == 'BUFMRCE': + sites.append(site) + + if sites: + yield tile_name, sorted(sites) + + +def write_params(params): + pinstr = 'tile,val,site\n' + for tile, (site, val) in sorted(params.items()): + pinstr += '%s,%s,%s\n' % (tile, val, site) + open('params.csv', 'w').write(pinstr) + + +def run(): + print(''' +module top(); + ''') + + params = {} + + sites = list(gen_sites()) + for (tile_name, sites), isone in zip(sites, + util.gen_fuzz_states(len(sites))): + site_name = sites[0] + params[tile_name] = (site_name, isone) + + print( + ''' + wire clk_{site}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFMRCE #( + .INIT_OUT({isone}) + ) buf_{site} ( + .O(clk_{site}) + ); + + BUFR bufr_{site} ( + .I(clk_{site}) + ); +'''.format( + site=site_name, + isone=isone, + )) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/045-hclk-cmt-pips/Makefile b/fuzzers/045-hclk-cmt-pips/Makefile new file mode 100644 index 00000000..06e27822 --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/Makefile @@ -0,0 +1,65 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=hclk_cmt +PIPLIST_TCL=$(FUZDIR)/hclk_cmt_pip_list.tcl +TODO_RE=".*" +# Skipped pips: +# - LEAF wires are disconnected +# - FREQ_REF is only used by interconnect clocks, so low likelyhood of usage. +# A BUFR can be used to clock divide if needed +# - PHSR PIPs are connected to PHASER sites, which are undocumented, so avoid +# for now. +EXCLUDE_RE="(^.*LEAF)|(HCLK_CMT_L\.[^.]+\.HCLK_CMT_MUX_CLK_[0-9]+)|(HCLK_CMT\.[^.]+\.HCLK_CMT_CK_IN[0-9]+)|(^.*BUFMR)|(^.*FREQ_REF)|(^.*PHSR)|(^.*CLK_PLL7)|(^.*CLK_MMCM13)" + +MAKETODO_FLAGS=--sides ",l" --pip-type ${PIP_TYPE} --seg-type ${PIP_TYPE} --re $(TODO_RE) --exclude-re $(EXCLUDE_RE) +N = 50 + +# These PIPs all appear to be either a 1 bit solutions. +SEGMATCH_FLAGS=-c 2 +SPECIMENS_DEPS=build/cmt_regions.csv +A_PIPLIST=hclk_cmt.txt + +include ../pip_loop.mk + +build/segbits_hclk_cmt.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_cmt.rdb \ + $(shell find build -name segdata_hclk_cmt.txt) + +build/segbits_hclk_cmt_l.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_hclk_cmt_l.rdb \ + $(shell find build -name segdata_hclk_cmt_l.txt) + +database: build/segbits_hclk_cmt.rdb build/segbits_hclk_cmt_l.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_hclk_cmt.rdb \ + --seg-fn-out build/segbits_hclk_cmt.db + + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_hclk_cmt_l.rdb \ + --seg-fn-out build/segbits_hclk_cmt_l.db + + # Keep a copy to track iter progress + cp build/segbits_hclk_cmt.rdb build/$(ITER)/segbits_hclk_cmt.rdb + cp build/segbits_hclk_cmt_l.rdb build/$(ITER)/segbits_hclk_cmt_l.rdb + + + ${XRAY_MASKMERGE} build/mask_hclk_cmt.db \ + $(shell find build -name segdata_hclk_cmt.txt) + ${XRAY_MASKMERGE} build/mask_hclk_cmt_l.db \ + $(shell find build -name segdata_hclk_cmt_l.txt) + + # 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_cmt build/segbits_hclk_cmt.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} hclk_cmt_l build/segbits_hclk_cmt_l.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_cmt build/segbits_hclk_cmt.db + ${XRAY_MERGEDB} hclk_cmt_l build/segbits_hclk_cmt_l.db + ${XRAY_MERGEDB} mask_hclk_cmt build/mask_hclk_cmt.db + ${XRAY_MERGEDB} mask_hclk_cmt_l build/mask_hclk_cmt_l.db + +.PHONY: database pushdb diff --git a/fuzzers/045-hclk-cmt-pips/bits.dbf b/fuzzers/045-hclk-cmt-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/045-hclk-cmt-pips/generate.py b/fuzzers/045-hclk-cmt-pips/generate.py new file mode 100644 index 00000000..492e3f28 --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/generate.py @@ -0,0 +1,105 @@ +#!/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_cmt', 'hclk_cmt.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) + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'hclk_cmt', 'hclk_cmt_l.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_CMT'): + 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) + + for port in tile_ports[tile_type]: + if port in tiledata[tile]["dsts"] or port in tiledata[tile]["srcs"]: + segmk.add_tile_tag(tile, "{}_ACTIVE".format(port), 1) + else: + segmk.add_tile_tag(tile, "{}_ACTIVE".format(port), 0) + + segmk.compile(bitfilter=bitfilter) + segmk.write() + + +if __name__ == "__main__": + main() diff --git a/fuzzers/045-hclk-cmt-pips/generate.tcl b/fuzzers/045-hclk-cmt-pips/generate.tcl new file mode 100644 index 00000000..fce56c46 --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/generate.tcl @@ -0,0 +1,233 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc write_pip_txtdata {filename} { + puts "FUZ([pwd]): Writing $filename." + set fp [open $filename w] + set nets [get_nets -hierarchical] + set nnets [llength $nets] + set neti 0 + foreach net $nets { + incr neti + if {($neti % 100) == 0 } { + puts "FUZ([pwd]): Dumping pips from net $net ($neti / $nnets)" + } + foreach pip [get_pips -of_objects $net] { + set tile [get_tiles -of_objects $pip] + set src_wire [get_wires -uphill -of_objects $pip] + set dst_wire [get_wires -downhill -of_objects $pip] + set num_pips [llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst_wire]]] + set dir_prop [get_property IS_DIRECTIONAL $pip] + puts $fp "$tile $pip $src_wire $dst_wire $num_pips $dir_prop" + } + } + close $fp +} + +proc load_todo {} { + 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 .] + dict lappend todo_map [lindex $parts 2] [list [lindex $parts 0] [lindex $parts 1]] + } + close $fp + return $todo_map +} + +proc route_todo {} { + puts "Checking TODO's" + set todo_map [load_todo] + + set nets [get_nets] + + set todo_nets [dict create] + set used_destinations [dict create] + + foreach net $nets { + # Check to see if this net is one we are interested in + set wires [get_wires -of_objects $net -filter {TILE_NAME =~ *HCLK_CMT*}] + + set is_gclk_net 0 + foreach wire $wires { + if [regexp "HCLK_CMT_MUX_CLK_\[0-9\]+" $wire] { + set is_gclk_net 1 + break + } + if [regexp "HCLK_CMT_CK_IN\[0-9\]+" $wire] { + set is_gclk_net 1 + break + } + } + + if {$is_gclk_net == 0} { + puts "$net not going to a HCLK port, skipping." + continue + } + + foreach wire $wires { + 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 dsts [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 dst $dsts { + set dst_tile_type [lindex $dst 0] + + if {$dst_tile_type != $tile_type} { + continue + } + + set dst_wire [lindex $dst 1] + + if { $other_wire == $dst } { + set found_target 1 + puts "Interesting net $net already going from $wire to $other_wire." + set_property IS_ROUTE_FIXED 1 $net + dict set used_destinations "$tile/$dst_wire" 1 + break + } + } + } + + if { $found_target == 1 } { + # Net has an interesting + continue + } + + dict set todo_nets $net [list $tile $wire] + puts "Interesting net $net (including $wire) is being rerouted." + } + } + + dict for {net tile_wire} $todo_nets { + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set dsts [dict get $todo_map $wire] + + puts "Rerouting net $net at $tile / $wire (type $tile_type)" + + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + + set todos {} + 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_CMT_MUX_CLK_\[0-9\]+" $dst_wire] { + set is_gclk_net 1 + } + if [regexp "HCLK_CMT_CK_IN\[0-9\]+" $dst_wire] { + set is_gclk_net 1 + } + + if {$is_gclk_net == 0} { + continue + } + + lappend todos $dst_wire + } + + puts "All todos for $tile_type / $wire" + foreach dst_wire $todos { + puts " - $dst_wire" + } + + 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 + } + + puts "Attempting to route to $dst_wire for net $net." + + 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_nets [get_nets -of_objects $target_node] + + if { $old_nets != {} } { + route_design -unroute -nets $old_nets + } + + set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + set new_route [find_routing_path -to $target_node -from $origin_node] + puts "Origin node: $origin_node" + puts "Target wire: $target_wire" + puts "Target node: $target_node" + + # Only need to set route to one of the destinations. + # Router will handle the rest. + set_property FIXED_ROUTE $new_route $net + + dict set used_destinations "$tile/$dst_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/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl b/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl new file mode 100644 index 00000000..e3ff9cdf --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl @@ -0,0 +1,20 @@ +proc print_tile_pips {tile_type filename} { + set tile [lindex [get_tiles -filter "TYPE == $tile_type"] 0] + puts "Dumping PIPs for tile $tile ($tile_type) to $filename." + set fp [open $filename w] + foreach pip [lsort [get_pips -of_objects [get_tiles $tile]]] { + set src [get_wires -uphill -of_objects $pip] + set dst [get_wires -downhill -of_objects $pip] + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { + puts $fp "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" + } + } + 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_CMT_L hclk_cmt_l.txt +print_tile_pips HCLK_CMT hclk_cmt.txt diff --git a/fuzzers/045-hclk-cmt-pips/output_cmt.tcl b/fuzzers/045-hclk-cmt-pips/output_cmt.tcl new file mode 100644 index 00000000..f4d00aff --- /dev/null +++ b/fuzzers/045-hclk-cmt-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 BUFMRCE BUFHCE IOB33M BUFR} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/045-hclk-cmt-pips/top.py b/fuzzers/045-hclk-cmt-pips/top.py new file mode 100644 index 00000000..d623b9c1 --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/top.py @@ -0,0 +1,446 @@ +""" 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. + + Some clock sources can be routed to any CMT, for these, cmt='ANY'. + For clock sources that belong to a CMT, cmt should be set to the CMT of + the source. + + """ + + def __init__(self): + self.sources = {} + self.source_to_cmt = {} + self.used_sources_from_cmt = {} + + 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, uses_left_right_routing=False, 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]) + + if uses_left_right_routing: + x, y = CMT_XY_FUN(cmt) + + if x % 2 == 0: + x += 1 + else: + x -= 1 + + paired_cmt = 'X{}Y{}'.format(x, y) + + if paired_cmt in self.sources: + for source in self.sources[paired_cmt]: + if 'BUFHCE' not in source: + choices.append(source) + + random.shuffle(choices) + + if not uses_left_right_routing: + return choices[0] + + 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]) >= 14: + continue + + self.used_sources_from_cmt[source_cmt].add(source) + + return source + + return None + + +def get_paired_iobs(db, grid, tile_name): + """ The two IOB33M's above and below the HCLK row have dedicate clock lines. + """ + + gridinfo = grid.gridinfo_at_tilename(tile_name) + loc = grid.loc_of_tilename(tile_name) + + if gridinfo.tile_type.endswith('_L'): + inc = 1 + else: + inc = -1 + + idx = 1 + while True: + gridinfo = grid.gridinfo_at_loc((loc.grid_x + inc * idx, loc.grid_y)) + + if gridinfo.tile_type == 'HCLK_IOI3': + break + + idx += 1 + + # Move from HCLK_IOI column to IOB column + idx += 1 + + for dy in [-1, -3, 2, 4]: + iob_loc = (loc.grid_x + inc * idx, loc.grid_y + dy) + gridinfo = grid.gridinfo_at_loc(iob_loc) + tile_name = grid.tilename_at_loc(iob_loc) + + assert gridinfo.tile_type.endswith('IOB33') + + for site, site_type in gridinfo.sites.items(): + if site_type == 'IOB33M': + yield tile_name, site + + +def check_allowed(mmcm_pll_dir, cmt): + """ Check whether the CMT specified is in the allowed direction. + + This function is designed to bias sources to either the left or right + input lines. + + """ + if mmcm_pll_dir == 'BOTH': + return True + elif mmcm_pll_dir == 'ODD': + x, y = CMT_XY_FUN(cmt) + return (x & 1) == 1 + elif mmcm_pll_dir == 'EVEN': + x, y = CMT_XY_FUN(cmt) + return (x & 1) == 0 + else: + assert False, mmcm_pll_dir + + +def main(): + """ + HCLK_CMT switch box has the follow inputs: + + 4 IOBs above and below + 14 MMCM outputs + 8 PLL outputs + 4 PHASER_IN outputs + 2 INT connections + + and the following outputs: + + 3 PLLE2 inputs + 2 BUFMR inputs + 3 MMCM inputs + ~2 MMCM -> BUFR??? + """ + + clock_sources = ClockSources() + adv_clock_sources = ClockSources() + site_to_cmt = dict(read_site_to_cmt()) + + 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 + + hclk_cmts = set() + ins = [] + iobs = StringIO() + + hclk_cmt_tiles = set() + for tile_name, site in gen_sites('BUFMRCE'): + cmt = site_to_cmt[site] + hclk_cmts.add(cmt) + hclk_cmt_tiles.add(tile_name) + + mmcm_pll_only = random.randint(0, 1) + mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH')) + + print( + '// mmcm_pll_only {} mmcm_pll_dir {}'.format( + mmcm_pll_only, mmcm_pll_dir)) + + for tile_name in sorted(hclk_cmt_tiles): + for _, site in get_paired_iobs(db, grid, tile_name): + + ins.append('input clk_{site}'.format(site=site)) + if check_allowed(mmcm_pll_dir, site_to_cmt[site]): + clock_sources.add_clock_source( + 'clock_IBUF_{site}'.format(site=site), site_to_cmt[site]) + adv_clock_sources.add_clock_source( + 'clock_IBUF_{site}'.format(site=site), site_to_cmt[site]) + + print( + """ + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + wire clock_IBUF_{site}; + IBUF #( .IOSTANDARD("LVCMOS33") ) ibuf_{site} ( + .I(clk_{site}), + .O(clock_IBUF_{site}) + ); + """.format(site=site), + file=iobs) + + print( + ''' +module top({inputs}); + (* KEEP, DONT_TOUCH *) + LUT6 dummy(); + '''.format(inputs=', '.join(ins))) + + print(iobs.getvalue()) + + luts = LutMaker() + wires = StringIO() + bufhs = StringIO() + + for _, site in gen_sites('MMCME2_ADV'): + mmcm_clocks = [ + 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(13) + ] + + if check_allowed(mmcm_pll_dir, site_to_cmt[site]): + for clk in mmcm_clocks: + 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({c1}), + .CLKOUT1({c2}), + .CLKOUT1B({c3}), + .CLKOUT2({c4}), + .CLKOUT2B({c5}), + .CLKOUT3({c6}), + .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) + ] + + if check_allowed(mmcm_pll_dir, site_to_cmt[site]): + for clk in pll_clocks: + 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=bufhs) + + if site_to_cmt[site] in hclk_cmts: + if not mmcm_pll_only: + clock_sources.add_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site]) + adv_clock_sources.add_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site]) + + hclks_used_by_cmt = {} + for cmt in site_to_cmt.values(): + hclks_used_by_cmt[cmt] = set() + + def check_hclk_src(src, src_cmt): + if len(hclks_used_by_cmt[src_cmt] + ) >= 12 and src not in hclks_used_by_cmt[src_cmt]: + return None + else: + hclks_used_by_cmt[src_cmt].add(src) + return src + + if random.random() > .10: + for tile_name, site in gen_sites('BUFHCE'): + wire_name = clock_sources.get_random_source( + site_to_cmt[site], + uses_left_right_routing=True, + no_repeats=mmcm_pll_only) + + if wire_name is not None and 'BUFHCE' in wire_name: + # Looping a BUFHCE to a BUFHCE requires using a hclk in the + # CMT of the source + src_cmt = clock_sources.source_to_cmt[wire_name] + + wire_name = check_hclk_src(wire_name, src_cmt) + + if wire_name is None: + continue + + print( + """ + assign I_{site} = {wire_name};""".format( + site=site, + wire_name=wire_name, + ), + file=bufhs) + + for tile_name, site in gen_sites('BUFMRCE'): + pass + + for l in luts.create_wires_and_luts(): + print(l) + + print(wires.getvalue()) + print(bufhs.getvalue()) + + for _, site in gen_sites('BUFR'): + adv_clock_sources.add_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site]) + print( + """ + wire O_{site}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR bufr_{site} ( + .O(O_{site}) + );""".format(site=site)) + + for _, site in gen_sites('PLLE2_ADV'): + for cin in ('cin1', 'cin2', 'clkfbin'): + if random.random() > .2: + src = adv_clock_sources.get_random_source(site_to_cmt[site]) + + src_cmt = adv_clock_sources.source_to_cmt[src] + + if 'IBUF' not in src and 'BUFR' not in src: + # Clocks from input pins do not require HCLK's, all other + # sources route from a global row clock. + src = check_hclk_src(src, src_cmt) + + if src is None: + continue + + print( + """ + assign {cin}_{site} = {csrc}; + """.format(cin=cin, site=site, csrc=src)) + + for _, site in gen_sites('MMCME2_ADV'): + for cin in ('cin1', 'cin2', 'clkfbin'): + if random.random() > .2: + src = adv_clock_sources.get_random_source(site_to_cmt[site]) + + src_cmt = adv_clock_sources.source_to_cmt[src] + if 'IBUF' not in src and 'BUFR' not in src: + # Clocks from input pins do not require HCLK's, all other + # sources route from a global row clock. + src = check_hclk_src(src, src_cmt) + + if src is None: + continue + + print( + """ + assign {cin}_{site} = {csrc}; + """.format(cin=cin, site=site, csrc=src)) + + print("endmodule") + + +if __name__ == '__main__': + main() diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index cc43a861..a2a70f54 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -123,9 +123,12 @@ def run( if side == "r" and not r: continue + if side != "": + side = "_" + side + maketodo( - "%s/%s_%s.txt" % (pip_dir, pip_type, side), - "%s/segbits_%s_%s.db" % (db_dir, seg_type, side), + "%s/%s%s.txt" % (pip_dir, pip_type, side), + "%s/segbits_%s%s.db" % (db_dir, seg_type, side), intre, exclude_re=exclude_re, not_endswith=not_endswith, diff --git a/utils/mergedb.sh b/utils/mergedb.sh index 3ec63507..78025412 100755 --- a/utils/mergedb.sh +++ b/utils/mergedb.sh @@ -100,6 +100,11 @@ case "$1" in clk_bufg_top_r) sed < "$2" > "$tmp1" -e 's/^CLK_BUFG\./CLK_BUFG_TOP_R./' ;; + hclk_cmt) + cp "$2" "$tmp1" ;; + hclk_cmt_l) + sed < "$2" > "$tmp1" -e 's/^HCLK_CMT\./HCLK_CMT_L./' ;; + clk_bufg_rebuf) cp "$2" "$tmp1" ;;