From 9187df2c958a7801a0720cfa99d9afbb207799dc Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:03:51 -0700 Subject: [PATCH 01/21] Initial BUFG PIP fuzzer. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/044-clk-bufg-pips/Makefile | 61 ++++ fuzzers/044-clk-bufg-pips/bits.dbf | 32 ++ fuzzers/044-clk-bufg-pips/build_zdb.py | 49 +++ .../044-clk-bufg-pips/clk_bufg_pip_list.tcl | 20 ++ fuzzers/044-clk-bufg-pips/generate.py | 90 +++++ fuzzers/044-clk-bufg-pips/generate.tcl | 46 +++ fuzzers/044-clk-bufg-pips/output_cmt.tcl | 11 + fuzzers/044-clk-bufg-pips/top.py | 326 ++++++++++++++++++ 8 files changed, 635 insertions(+) create mode 100644 fuzzers/044-clk-bufg-pips/Makefile create mode 100644 fuzzers/044-clk-bufg-pips/bits.dbf create mode 100644 fuzzers/044-clk-bufg-pips/build_zdb.py create mode 100644 fuzzers/044-clk-bufg-pips/clk_bufg_pip_list.tcl create mode 100644 fuzzers/044-clk-bufg-pips/generate.py create mode 100644 fuzzers/044-clk-bufg-pips/generate.tcl create mode 100644 fuzzers/044-clk-bufg-pips/output_cmt.tcl create mode 100644 fuzzers/044-clk-bufg-pips/top.py diff --git a/fuzzers/044-clk-bufg-pips/Makefile b/fuzzers/044-clk-bufg-pips/Makefile new file mode 100644 index 00000000..0821b3f1 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/Makefile @@ -0,0 +1,61 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=clk_bufg +PIPLIST_TCL=$(FUZDIR)/clk_bufg_pip_list.tcl +TODO_RE=".*" + +MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_bufg --re $(TODO_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=clk_bufg_bot_r.txt + +include ../pip_loop.mk + +build/segbits_clk_bufg_top_r.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_bufg_top_r.rdb \ + $(shell find build -name segdata_clk_bufg_top_r.txt) + +build/segbits_clk_bufg_bot_r.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_bufg_bot_r.rdb \ + $(shell find build -name segdata_clk_bufg_bot_r.txt) + + +database: build/segbits_clk_bufg_top_r.rdb build/segbits_clk_bufg_bot_r.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_clk_bufg_bot_r.rdb \ + --seg-fn-out build/segbits_clk_bufg_bot_r.db + + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_clk_bufg_top_r.rdb \ + --seg-fn-out build/segbits_clk_bufg_top_r.db + + # Keep a copy to track iter progress + cp build/segbits_clk_bufg_top_r.rdb build/$(ITER)/segbits_clk_bufg_top_r.rdb + cp build/segbits_clk_bufg_top_r.db build/$(ITER)/segbits_clk_bufg_top_r.db + cp build/segbits_clk_bufg_bot_r.rdb build/$(ITER)/segbits_clk_bufg_bot_r.rdb + cp build/segbits_clk_bufg_bot_r.db build/$(ITER)/segbits_clk_bufg_bot_r.db + + + ${XRAY_MASKMERGE} build/mask_clk_bufg_top_r.db \ + $(shell find build -name segdata_clk_bufg_top_r.txt) + ${XRAY_MASKMERGE} build/mask_clk_bufg_bot_r.db \ + $(shell find build -name segdata_clk_bufg_bot_r.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} clk_bufg_top_r build/segbits_clk_bufg_top_r.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_bufg_bot_r build/segbits_clk_bufg_bot_r.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} clk_bufg_bot_r build/segbits_clk_bufg_bot_r.db + ${XRAY_MERGEDB} clk_bufg_top_r build/segbits_clk_bufg_top_r.db + ${XRAY_MERGEDB} mask_clk_bufg_bot_r build/mask_clk_bufg_bot_r.db + ${XRAY_MERGEDB} mask_clk_bufg_top_r build/mask_clk_bufg_top_r.db + +.PHONY: database pushdb diff --git a/fuzzers/044-clk-bufg-pips/bits.dbf b/fuzzers/044-clk-bufg-pips/bits.dbf new file mode 100644 index 00000000..1fb02ee4 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/bits.dbf @@ -0,0 +1,32 @@ +26_07 26_08 27_06,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I0.CLK_BUFG_IMUX28_0 +26_04 26_05 27_05,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I1.CLK_BUFG_IMUX28_0 +26_167 26_168 27_166,CLK_BUFG.CLK_BUFG_BUFGCTRL10_I0.CLK_BUFG_IMUX30_2 +26_164 26_165 27_165,CLK_BUFG.CLK_BUFG_BUFGCTRL10_I1.CLK_BUFG_IMUX30_2 +26_183 26_184 27_182,CLK_BUFG.CLK_BUFG_BUFGCTRL11_I0.CLK_BUFG_IMUX31_2 +26_180 26_181 27_181,CLK_BUFG.CLK_BUFG_BUFGCTRL11_I1.CLK_BUFG_IMUX31_2 +26_199 26_200 27_198,CLK_BUFG.CLK_BUFG_BUFGCTRL12_I0.CLK_BUFG_IMUX28_3 +26_196 26_197 27_197,CLK_BUFG.CLK_BUFG_BUFGCTRL12_I1.CLK_BUFG_IMUX28_3 +26_215 26_216 27_214,CLK_BUFG.CLK_BUFG_BUFGCTRL13_I0.CLK_BUFG_IMUX29_3 +26_212 26_213 27_213,CLK_BUFG.CLK_BUFG_BUFGCTRL13_I1.CLK_BUFG_IMUX29_3 +26_231 26_232 27_230,CLK_BUFG.CLK_BUFG_BUFGCTRL14_I0.CLK_BUFG_IMUX30_3 +26_228 26_229 27_229,CLK_BUFG.CLK_BUFG_BUFGCTRL14_I1.CLK_BUFG_IMUX30_3 +26_247 26_248 27_246,CLK_BUFG.CLK_BUFG_BUFGCTRL15_I0.CLK_BUFG_IMUX31_3 +26_244 26_245 27_245,CLK_BUFG.CLK_BUFG_BUFGCTRL15_I1.CLK_BUFG_IMUX31_3 +26_23 26_24 27_22,CLK_BUFG.CLK_BUFG_BUFGCTRL1_I0.CLK_BUFG_IMUX29_0 +26_20 26_21 27_21,CLK_BUFG.CLK_BUFG_BUFGCTRL1_I1.CLK_BUFG_IMUX29_0 +26_39 26_40 27_38,CLK_BUFG.CLK_BUFG_BUFGCTRL2_I0.CLK_BUFG_IMUX30_0 +26_36 26_37 27_37,CLK_BUFG.CLK_BUFG_BUFGCTRL2_I1.CLK_BUFG_IMUX30_0 +26_55 26_56 27_54,CLK_BUFG.CLK_BUFG_BUFGCTRL3_I0.CLK_BUFG_IMUX31_0 +26_52 26_53 27_53,CLK_BUFG.CLK_BUFG_BUFGCTRL3_I1.CLK_BUFG_IMUX31_0 +26_71 26_72 27_70,CLK_BUFG.CLK_BUFG_BUFGCTRL4_I0.CLK_BUFG_IMUX28_1 +26_68 26_69 27_69,CLK_BUFG.CLK_BUFG_BUFGCTRL4_I1.CLK_BUFG_IMUX28_1 +26_87 26_88 27_86,CLK_BUFG.CLK_BUFG_BUFGCTRL5_I0.CLK_BUFG_IMUX29_1 +26_84 26_85 27_85,CLK_BUFG.CLK_BUFG_BUFGCTRL5_I1.CLK_BUFG_IMUX29_1 +26_103 26_104 27_102,CLK_BUFG.CLK_BUFG_BUFGCTRL6_I0.CLK_BUFG_IMUX30_1 +26_100 26_101 27_101,CLK_BUFG.CLK_BUFG_BUFGCTRL6_I1.CLK_BUFG_IMUX30_1 +26_119 26_120 27_118,CLK_BUFG.CLK_BUFG_BUFGCTRL7_I0.CLK_BUFG_IMUX31_1 +26_116 26_117 27_117,CLK_BUFG.CLK_BUFG_BUFGCTRL7_I1.CLK_BUFG_IMUX31_1 +26_135 26_136 27_134,CLK_BUFG.CLK_BUFG_BUFGCTRL8_I0.CLK_BUFG_IMUX28_2 +26_132 26_133 27_133,CLK_BUFG.CLK_BUFG_BUFGCTRL8_I1.CLK_BUFG_IMUX28_2 +26_151 26_152 27_150,CLK_BUFG.CLK_BUFG_BUFGCTRL9_I0.CLK_BUFG_IMUX29_2 +26_148 26_149 27_149,CLK_BUFG.CLK_BUFG_BUFGCTRL9_I1.CLK_BUFG_IMUX29_2 diff --git a/fuzzers/044-clk-bufg-pips/build_zdb.py b/fuzzers/044-clk-bufg-pips/build_zdb.py new file mode 100644 index 00000000..0cca8773 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/build_zdb.py @@ -0,0 +1,49 @@ +import argparse + +def main(): + parser = argparse.ArgumentParser("Form ZDB groups for BUFG.") + + parser.add_argument('bot_r') + parser.add_argument('top_r') + + args = parser.parse_args() + + groups = {} + + with open(args.bot_r) as f: + for l in f: + parts = l.strip().split(' ') + feature = parts[0] + bits = parts[1:] + tile_type, dst, src = feature.split('.') + + assert tile_type == "CLK_BUFG" + + if dst not in groups: + groups[dst] = {} + + groups[dst][src] = bits + + for dst in groups: + if len(groups[dst]) == 1: + continue + + bits = set() + zero_feature = None + for src in groups[dst]: + if groups[dst][src][0] == '<0': + assert zero_feature is None + zero_feature = src + else: + bits |= set(groups[dst][src]) + + assert zero_feature is not None, dst + + print('{bits},{type}.{dst}.{src}'.format( + bits=' '.join(sorted(bits)), + type='CLK_BUFG', + dst=dst, + src=zero_feature)) + +if __name__ == "__main__": + main() diff --git a/fuzzers/044-clk-bufg-pips/clk_bufg_pip_list.tcl b/fuzzers/044-clk-bufg-pips/clk_bufg_pip_list.tcl new file mode 100644 index 00000000..c870f353 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/clk_bufg_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 CLK_BUFG_TOP_R clk_bufg_top_r.txt +print_tile_pips CLK_BUFG_BOT_R clk_bufg_bot_r.txt diff --git a/fuzzers/044-clk-bufg-pips/generate.py b/fuzzers/044-clk-bufg-pips/generate.py new file mode 100644 index 00000000..ce1dbde1 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/generate.py @@ -0,0 +1,90 @@ +#!/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() + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', 'clk_bufg', 'clk_bufg_bot_r.txt')) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] + + pipdata[tile_type].append((src, dst)) + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', 'clk_bufg', 'clk_bufg_top_r.txt')) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] + + pipdata[tile_type].append((src, dst)) + + 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('CLK_BUFG'): + continue + + if tile.startswith('CLK_BUFG_REBUF'): + 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/044-clk-bufg-pips/generate.tcl b/fuzzers/044-clk-bufg-pips/generate.tcl new file mode 100644 index 00000000..f3bbef42 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/generate.tcl @@ -0,0 +1,46 @@ +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 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 {REQP-123}] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit + write_pip_txtdata design.txt +} + +run diff --git a/fuzzers/044-clk-bufg-pips/output_cmt.tcl b/fuzzers/044-clk-bufg-pips/output_cmt.tcl new file mode 100644 index 00000000..540c8143 --- /dev/null +++ b/fuzzers/044-clk-bufg-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 BUFHCE} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/044-clk-bufg-pips/top.py b/fuzzers/044-clk-bufg-pips/top.py new file mode 100644 index 00000000..7b88238a --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/top.py @@ -0,0 +1,326 @@ +""" 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='') +BUFGCTRL_XY_FUN = util.create_xy_fun('BUFGCTRL_') + + +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.merged_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) + assert source not in self.source_to_cmt or self.source_to_cmt[ + source] == cmt, source + self.source_to_cmt[source] = cmt + + def get_random_source(self, cmt): + """ 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. + + """ + if cmt not in self.merged_sources: + choices = [] + if 'ANY' in self.sources: + choices.extend(self.sources['ANY']) + + if cmt in self.sources: + choices.extend(self.sources[cmt]) + + 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: + choices.extend(self.sources[paired_cmt]) + + self.merged_sources[cmt] = choices + + if self.merged_sources[cmt]: + source = random.choice(self.merged_sources[cmt]) + + 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() + + self.used_sources_from_cmt[source_cmt].add(source) + + if source_cmt != 'ANY' and len( + self.used_sources_from_cmt[source_cmt]) > 14: + print('//', self.used_sources_from_cmt) + self.used_sources_from_cmt[source_cmt].remove(source) + return None + else: + return source + + + +def main(): + """ + BUFG's can be driven from: + + Interconnect + HROW cascade + + """ + + print(''' +module top(); + (* KEEP, DONT_TOUCH *) + LUT6 dummy(); + ''') + + site_to_cmt = dict(read_site_to_cmt()) + luts = LutMaker() + wires = StringIO() + bufgs = StringIO() + + clock_sources = ClockSources() + + 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 + + + for _, site in gen_sites('MMCME2_ADV'): + mmcm_clocks = [ + 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) + for idx in range(13) + ] + + for clk in mmcm_clocks: + clock_sources.add_clock_source(clk, site_to_cmt[site]) + + print( + """ + wire {c0}, {c1}, {c2}, {c3}, {c4}, {c5}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + MMCME2_ADV pll_{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 sorted(gen_sites("BUFGCTRL"), + key=lambda x: BUFGCTRL_XY_FUN(x[1])): + print( + """ + wire O_{site}; + wire S1_{site}; + wire S0_{site}; + wire IGNORE1_{site}; + wire IGNORE0_{site}; + wire I1_{site}; + wire I0_{site}; + wire CE1_{site}; + wire CE0_{site}; + """.format(site=site), file=wires) + + print(""" + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFGCTRL bufg_{site} ( + .O(O_{site}), + .S1(S1_{site}), + .S0(S0_{site}), + .IGNORE1(IGNORE1_{site}), + .IGNORE0(IGNORE0_{site}), + .I1(I1_{site}), + .I0(I0_{site}), + .CE1(CE1_{site}), + .CE0(CE0_{site}) + ); + """.format(site=site), file=bufgs) + + """ BUFG clock sources: + + 2 from interconnect + Output of BUFG +/- 1 + Cascade in (e.g. PLL, MMCM) + + """ + + CLOCK_CHOICES = ( + 'LUT', + 'BUFG_+1', + 'BUFG_-1', + 'CASCADE', + ) + + def find_bufg_cmt(tile): + if '_BOT_' in tile: + inc = 1 + else: + inc = -1 + + loc = grid.loc_of_tilename(tile) + + offset = 1 + + while True: + gridinfo = grid.gridinfo_at_loc((loc.grid_x, loc.grid_y+offset*inc)) + if gridinfo.tile_type.startswith('CLK_HROW_'): + return site_to_cmt[list(gridinfo.sites.keys())[0]] + + offset += 1 + + def get_clock_net(tile, site, source_type): + if source_type == 'LUT': + return luts.get_next_output_net() + elif source_type == 'BUFG_+1': + x, y = BUFGCTRL_XY_FUN(site) + + target_y = y + 1 + max_y = ((y // 16) + 1)*16 + + if target_y >= max_y: + target_y -= 16 + + return 'O_BUFGCTRL_X{x}Y{y}'.format(x=x, y=target_y) + elif source_type == 'BUFG_-1': + x, y = BUFGCTRL_XY_FUN(site) + + target_y = y - 1 + min_y = (y // 16)*16 + + if target_y < min_y: + target_y += 16 + + return 'O_BUFGCTRL_X{x}Y{y}'.format(x=x, y=target_y) + elif source_type == 'CASCADE': + cmt = find_bufg_cmt(tile) + return clock_sources.get_random_source(cmt) + else: + assert False, source_type + + for tile, site in sorted(gen_sites("BUFGCTRL"), + key=lambda x: BUFGCTRL_XY_FUN(x[1])): + if random.randint(0, 1): + print(""" + assign I0_{site} = {i0_net};""".format( + site=site, + i0_net=get_clock_net(tile, site, random.choice(CLOCK_CHOICES))), file=bufgs) + + if random.randint(0, 1): + print(""" + assign I1_{site} = {i1_net};""".format( + site=site, + i1_net = get_clock_net(tile, site, random.choice(CLOCK_CHOICES))), file=bufgs) + + print(""" + assign S0_{site} = {s0_net}; + assign S1_{site} = {s1_net}; + assign IGNORE0_{site} = {ignore0_net}; + assign IGNORE1_{site} = {ignore1_net}; + assign CE0_{site} = {ce0_net}; + assign CE1_{site} = {ce1_net}; + """.format( + site=site, + s0_net=luts.get_next_output_net(), + s1_net=luts.get_next_output_net(), + ignore0_net=luts.get_next_output_net(), + ignore1_net=luts.get_next_output_net(), + ce0_net=luts.get_next_output_net(), + ce1_net=luts.get_next_output_net(), + ), file=bufgs) + + for l in luts.create_wires_and_luts(): + print(l) + + print(wires.getvalue()) + print(bufgs.getvalue()) + + itr = iter(gen_sites('BUFHCE')) + + for tile, site in sorted(gen_sites("BUFGCTRL"), + key=lambda x: BUFGCTRL_XY_FUN(x[1])): + if random.randint(0, 1): + _, bufhce_site = next(itr) + + print(""" + (* KEEP, DONT_TOUCH, LOC = "{bufhce_site}" *) + BUFHCE bufhce_{bufhce_site} ( + .I(O_{site}) + );""".format( + site=site, + bufhce_site=bufhce_site, + )) + + print("endmodule") + + +if __name__ == '__main__': + main() From 6ca687ad5f7976df5802becaf1291bd31d13c91a Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:07:37 -0700 Subject: [PATCH 02/21] Add comment to build_zdb. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/044-clk-bufg-pips/build_zdb.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/fuzzers/044-clk-bufg-pips/build_zdb.py b/fuzzers/044-clk-bufg-pips/build_zdb.py index 0cca8773..a558d89f 100644 --- a/fuzzers/044-clk-bufg-pips/build_zdb.py +++ b/fuzzers/044-clk-bufg-pips/build_zdb.py @@ -1,8 +1,25 @@ +""" Tool for building ZDB for BUFG pips. + +This requires that the rdb files be good enough to identify all the 0 candidate +features, which may take multiple manual iterations. Manual iterations can +be running like: + +make ITER= -j database + +And then invoking: +python3 build_zdb.py build/segbits_clk_bufg_bot_r.rdb build/segbits_clk_bufg_top_r.rdb > bits.dbf + +will successed if and only if the rdb is complete enough. + +bits.dbf is committed, so this utility should only be needed to document the +process. + +""" import argparse def main(): parser = argparse.ArgumentParser("Form ZDB groups for BUFG.") - + parser.add_argument('bot_r') parser.add_argument('top_r') From 3d70606d7991e803c19a6c92eba5df661647ca0f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:07:56 -0700 Subject: [PATCH 03/21] Add explicit l/r flag. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/int_maketodo.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index 55e37aa8..a1729a10 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -89,6 +89,7 @@ def run( db_dir, pip_dir, intre, + sides, l, r, pip_type, @@ -105,18 +106,16 @@ def run( assert intre, "RE is required" - if l: - maketodo( - "%s/%s_l.txt" % (pip_dir, pip_type), - "%s/segbits_%s_l.db" % (db_dir, seg_type), - intre, - not_endswith, - verbose=verbose) + for side in sides: + if side == "l" and not l: + continue + + if side == "r" and not r: + continue - if r: maketodo( - "%s/%s_r.txt" % (pip_dir, pip_type), - "%s/segbits_%s_r.db" % (db_dir, seg_type), + "%s/%s_%s.txt" % (pip_dir, pip_type, side), + "%s/segbits_%s_%s.db" % (db_dir, seg_type, side), intre, not_endswith, verbose=verbose) @@ -135,6 +134,7 @@ def main(): parser.add_argument('--re', required=True, help='') parser.add_argument('--pip-type', default="pips_int", help='') parser.add_argument('--seg-type', default="int", help='') + parser.add_argument('--sides', default="l,r", help='') util.add_bool_arg(parser, '--l', default=True, help='') util.add_bool_arg(parser, '--r', default=True, help='') parser.add_argument( @@ -146,6 +146,7 @@ def main(): db_dir=args.db_dir, pip_dir=args.pip_dir, intre=args.re, + sides=args.sides.split(','), l=args.l, r=args.r, pip_type=args.pip_type, From 3232ae3edc1af7ce170dffdbe868ea67f516b7d4 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:10:25 -0700 Subject: [PATCH 04/21] Run make format. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/044-clk-bufg-pips/build_zdb.py | 13 ++-- fuzzers/044-clk-bufg-pips/generate.py | 9 ++- fuzzers/044-clk-bufg-pips/top.py | 85 +++++++++++++++----------- 3 files changed, 63 insertions(+), 44 deletions(-) diff --git a/fuzzers/044-clk-bufg-pips/build_zdb.py b/fuzzers/044-clk-bufg-pips/build_zdb.py index a558d89f..b3d2fe34 100644 --- a/fuzzers/044-clk-bufg-pips/build_zdb.py +++ b/fuzzers/044-clk-bufg-pips/build_zdb.py @@ -17,6 +17,7 @@ process. """ import argparse + def main(): parser = argparse.ArgumentParser("Form ZDB groups for BUFG.") @@ -56,11 +57,13 @@ def main(): assert zero_feature is not None, dst - print('{bits},{type}.{dst}.{src}'.format( - bits=' '.join(sorted(bits)), - type='CLK_BUFG', - dst=dst, - src=zero_feature)) + print( + '{bits},{type}.{dst}.{src}'.format( + bits=' '.join(sorted(bits)), + type='CLK_BUFG', + dst=dst, + src=zero_feature)) + if __name__ == "__main__": main() diff --git a/fuzzers/044-clk-bufg-pips/generate.py b/fuzzers/044-clk-bufg-pips/generate.py index ce1dbde1..58b895a2 100644 --- a/fuzzers/044-clk-bufg-pips/generate.py +++ b/fuzzers/044-clk-bufg-pips/generate.py @@ -4,12 +4,14 @@ 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") @@ -17,7 +19,8 @@ def main(): pipdata = {} ignpip = set() - with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', 'clk_bufg', 'clk_bufg_bot_r.txt')) as f: + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'clk_bufg', 'clk_bufg_bot_r.txt')) as f: for l in f: tile_type, dst, src = l.strip().split('.') if tile_type not in pipdata: @@ -25,7 +28,8 @@ def main(): pipdata[tile_type].append((src, dst)) - with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', 'clk_bufg', 'clk_bufg_top_r.txt')) as f: + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'clk_bufg', 'clk_bufg_top_r.txt')) as f: for l in f: tile_type, dst, src = l.strip().split('.') if tile_type not in pipdata: @@ -86,5 +90,6 @@ def main(): segmk.compile(bitfilter=bitfilter) segmk.write() + if __name__ == "__main__": main() diff --git a/fuzzers/044-clk-bufg-pips/top.py b/fuzzers/044-clk-bufg-pips/top.py index 7b88238a..5f1a38c1 100644 --- a/fuzzers/044-clk-bufg-pips/top.py +++ b/fuzzers/044-clk-bufg-pips/top.py @@ -95,7 +95,6 @@ class ClockSources(object): return source - def main(): """ BUFG's can be driven from: @@ -105,7 +104,8 @@ def main(): """ - print(''' + print( + ''' module top(); (* KEEP, DONT_TOUCH *) LUT6 dummy(); @@ -129,7 +129,6 @@ module top(); if site_type == desired_site_type: yield tile_name, site - for _, site in gen_sites('MMCME2_ADV'): mmcm_clocks = [ 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) @@ -176,7 +175,7 @@ module top(); )) for _, site in sorted(gen_sites("BUFGCTRL"), - key=lambda x: BUFGCTRL_XY_FUN(x[1])): + key=lambda x: BUFGCTRL_XY_FUN(x[1])): print( """ wire O_{site}; @@ -188,9 +187,11 @@ module top(); wire I0_{site}; wire CE1_{site}; wire CE0_{site}; - """.format(site=site), file=wires) + """.format(site=site), + file=wires) - print(""" + print( + """ (* KEEP, DONT_TOUCH, LOC = "{site}" *) BUFGCTRL bufg_{site} ( .O(O_{site}), @@ -203,8 +204,8 @@ module top(); .CE1(CE1_{site}), .CE0(CE0_{site}) ); - """.format(site=site), file=bufgs) - + """.format(site=site), + file=bufgs) """ BUFG clock sources: 2 from interconnect @@ -214,11 +215,11 @@ module top(); """ CLOCK_CHOICES = ( - 'LUT', - 'BUFG_+1', - 'BUFG_-1', - 'CASCADE', - ) + 'LUT', + 'BUFG_+1', + 'BUFG_-1', + 'CASCADE', + ) def find_bufg_cmt(tile): if '_BOT_' in tile: @@ -231,7 +232,8 @@ module top(); offset = 1 while True: - gridinfo = grid.gridinfo_at_loc((loc.grid_x, loc.grid_y+offset*inc)) + gridinfo = grid.gridinfo_at_loc( + (loc.grid_x, loc.grid_y + offset * inc)) if gridinfo.tile_type.startswith('CLK_HROW_'): return site_to_cmt[list(gridinfo.sites.keys())[0]] @@ -244,7 +246,7 @@ module top(); x, y = BUFGCTRL_XY_FUN(site) target_y = y + 1 - max_y = ((y // 16) + 1)*16 + max_y = ((y // 16) + 1) * 16 if target_y >= max_y: target_y -= 16 @@ -254,7 +256,7 @@ module top(); x, y = BUFGCTRL_XY_FUN(site) target_y = y - 1 - min_y = (y // 16)*16 + min_y = (y // 16) * 16 if target_y < min_y: target_y += 16 @@ -267,20 +269,27 @@ module top(); assert False, source_type for tile, site in sorted(gen_sites("BUFGCTRL"), - key=lambda x: BUFGCTRL_XY_FUN(x[1])): + key=lambda x: BUFGCTRL_XY_FUN(x[1])): if random.randint(0, 1): - print(""" + print( + """ assign I0_{site} = {i0_net};""".format( - site=site, - i0_net=get_clock_net(tile, site, random.choice(CLOCK_CHOICES))), file=bufgs) + site=site, + i0_net=get_clock_net( + tile, site, random.choice(CLOCK_CHOICES))), + file=bufgs) if random.randint(0, 1): - print(""" + print( + """ assign I1_{site} = {i1_net};""".format( - site=site, - i1_net = get_clock_net(tile, site, random.choice(CLOCK_CHOICES))), file=bufgs) + site=site, + i1_net=get_clock_net( + tile, site, random.choice(CLOCK_CHOICES))), + file=bufgs) - print(""" + print( + """ assign S0_{site} = {s0_net}; assign S1_{site} = {s1_net}; assign IGNORE0_{site} = {ignore0_net}; @@ -288,14 +297,15 @@ module top(); assign CE0_{site} = {ce0_net}; assign CE1_{site} = {ce1_net}; """.format( - site=site, - s0_net=luts.get_next_output_net(), - s1_net=luts.get_next_output_net(), - ignore0_net=luts.get_next_output_net(), - ignore1_net=luts.get_next_output_net(), - ce0_net=luts.get_next_output_net(), - ce1_net=luts.get_next_output_net(), - ), file=bufgs) + site=site, + s0_net=luts.get_next_output_net(), + s1_net=luts.get_next_output_net(), + ignore0_net=luts.get_next_output_net(), + ignore1_net=luts.get_next_output_net(), + ce0_net=luts.get_next_output_net(), + ce1_net=luts.get_next_output_net(), + ), + file=bufgs) for l in luts.create_wires_and_luts(): print(l) @@ -306,18 +316,19 @@ module top(); itr = iter(gen_sites('BUFHCE')) for tile, site in sorted(gen_sites("BUFGCTRL"), - key=lambda x: BUFGCTRL_XY_FUN(x[1])): + key=lambda x: BUFGCTRL_XY_FUN(x[1])): if random.randint(0, 1): _, bufhce_site = next(itr) - print(""" + print( + """ (* KEEP, DONT_TOUCH, LOC = "{bufhce_site}" *) BUFHCE bufhce_{bufhce_site} ( .I(O_{site}) );""".format( - site=site, - bufhce_site=bufhce_site, - )) + site=site, + bufhce_site=bufhce_site, + )) print("endmodule") From 5091d0a59e130adc5836a8cbecb2df44735d737c Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 16:11:15 -0700 Subject: [PATCH 05/21] Add 044 to fuzzer Makefile. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 39293c13..a943cd54 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -83,6 +83,7 @@ $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) $(eval $(call fuzzer,042-clk-bufg-config,005-tilegrid)) $(eval $(call fuzzer,043-clk-rebuf-pips,005-tilegrid)) +$(eval $(call fuzzer,044-clk-bufg-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)) From 023cd55bb1f6909d129265e64e52712208558c8f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 12 Mar 2019 18:23:47 -0700 Subject: [PATCH 06/21] Refactor 041 fuzzer to avoid requiring insight into mux structure. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/Makefile | 23 ++-- fuzzers/041-clk-hrow-pips/clk_table.py | 34 ----- fuzzers/041-clk-hrow-pips/generate.py | 117 ++++++++++++------ .../041-clk-hrow-pips/merge_clk_entries.py | 89 ------------- fuzzers/041-clk-hrow-pips/top.py | 24 ++-- 5 files changed, 107 insertions(+), 180 deletions(-) delete mode 100644 fuzzers/041-clk-hrow-pips/clk_table.py delete mode 100644 fuzzers/041-clk-hrow-pips/merge_clk_entries.py diff --git a/fuzzers/041-clk-hrow-pips/Makefile b/fuzzers/041-clk-hrow-pips/Makefile index f3677cf7..98c03ac9 100644 --- a/fuzzers/041-clk-hrow-pips/Makefile +++ b/fuzzers/041-clk-hrow-pips/Makefile @@ -1,5 +1,5 @@ export FUZDIR=$(shell pwd) -PIP_TYPE?=clk_hrow_bot +PIP_TYPE?=clk_hrow PIPLIST_TCL=$(FUZDIR)/clk_hrow_pip_list.tcl ifeq (${XRAY_PART}, xc7z010clg400-1) @@ -7,14 +7,14 @@ ifeq (${XRAY_PART}, xc7z010clg400-1) # be documented. TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_[LR][0-9]+\.CLK_HROW_.*[KR_][0-9]+" else -TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_" +TODO_RE=".*" endif -MAKETODO_FLAGS=--no-l --pip-type ${PIP_TYPE} --seg-type clk_hrow_bot --re $(TODO_RE) +MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE) N = 50 -# These PIPs all appear to be either a 1 bit solutions. -SEGMATCH_FLAGS=-c 1 +# These PIPs all appear to be either a 2 bit solutions. +SEGMATCH_FLAGS=-c 2 SPECIMENS_DEPS=build/cmt_regions.csv A_PIPLIST=clk_hrow_bot_r.txt @@ -31,27 +31,20 @@ build/segbits_clk_hrow.rdb: $(SPECIMENS_OK) $(shell find build -name segdata_clk_hrow_top_r.txt) \ $(shell find build -name segdata_clk_hrow_bot_r.txt) -build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb piplist +build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ --seg-fn-in build/segbits_clk_hrow.rdb \ - --seg-fn-out build/segbits_clk_hrow_rc.db - - # Convert row/column into PIP definition. - python3 merge_clk_entries.py \ - build/segbits_clk_hrow_rc.db \ - $(XRAY_FUZZERS_DIR)/piplist/build/${PIP_TYPE}/clk_hrow_bot_r.txt \ - build/segbits_clk_hrow.db + --seg-fn-out build/segbits_clk_hrow.db # Keep a copy to track iter progress cp build/segbits_clk_hrow.rdb build/$(ITER)/segbits_clk_hrow.rdb - cp build/segbits_clk_hrow_rc.db build/$(ITER)/segbits_clk_hrow_rc.db - ${XRAY_MASKMERGE} build/mask_clk_hrow.db \ $(shell find build -name segdata_clk_hrow_top_r.txt) \ $(shell find build -name segdata_clk_hrow_bot_r.txt) # Clobber existing .db to eliminate potential conflicts + rm -f build/database/${XRAY_DATABASE}/* cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db diff --git a/fuzzers/041-clk-hrow-pips/clk_table.py b/fuzzers/041-clk-hrow-pips/clk_table.py deleted file mode 100644 index 9b3ccdfd..00000000 --- a/fuzzers/041-clk-hrow-pips/clk_table.py +++ /dev/null @@ -1,34 +0,0 @@ -HCLKS = 24 -GCLKS = 32 -SIDE_CLK_INPUTS = 14 - -CLK_TABLE_NUM_ROWS = 8 -CLK_TABLE_NUM_COLS = 8 - - -def get_clk_table(): - clk_table = {} - for gclk in range(GCLKS): - gclk_name = 'CLK_HROW_R_CK_GCLK{}'.format(gclk) - row = gclk % CLK_TABLE_NUM_ROWS - column = int(gclk / CLK_TABLE_NUM_ROWS) - clk_table[gclk_name] = (row, column) - - for row in range(8): - clk_table['CLK_HROW_CK_IN_L{}'.format(row)] = (row, 4) - for row in range(6): - clk_table['CLK_HROW_CK_IN_L{}'.format(row + 8)] = (row, 5) - - for row in range(8): - clk_table['CLK_HROW_CK_IN_R{}'.format(row)] = (row, 6) - for row in range(6): - clk_table['CLK_HROW_CK_IN_R{}'.format(row + 8)] = (row, 7) - - # HROW_CK_INT__, Y == Y share the same bits, and only X = 0 or X = 1 - # are present on a particular HROW. - for y in range(2): - for x in range(2): - int_clk_name = 'CLK_HROW_CK_INT_{}_{}'.format(x, y) - clk_table[int_clk_name] = (y + 6, 7) - - return clk_table diff --git a/fuzzers/041-clk-hrow-pips/generate.py b/fuzzers/041-clk-hrow-pips/generate.py index f9b20ba2..de28cde3 100644 --- a/fuzzers/041-clk-hrow-pips/generate.py +++ b/fuzzers/041-clk-hrow-pips/generate.py @@ -1,17 +1,46 @@ #!/usr/bin/env python3 +import os +import os.path from prjxray.segmaker import Segmaker -import clk_table +import pprint def main(): segmk = Segmaker("design.bits") - table = clk_table.get_clk_table() + + tiledata = {} + pipdata = {} + clk_list = {} + ignpip = set() + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'clk_hrow', 'clk_hrow_bot_r.txt')) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] + clk_list[tile_type] = set() + + pipdata[tile_type].append((src, dst)) + + if dst.startswith('CLK_HROW_CK_MUX_OUT_'): + clk_list[tile_type].add(src) + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'clk_hrow', 'clk_hrow_top_r.txt')) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + if tile_type not in pipdata: + pipdata[tile_type] = [] + clk_list[tile_type] = set() + + pipdata[tile_type].append((src, dst)) + + if dst.startswith('CLK_HROW_CK_MUX_OUT_'): + clk_list[tile_type].add(src) print("Loading tags from design.txt.") - - active_gclks = {} - active_clks = {} with open("design.txt", "r") as f: for line in f: tile, pip, src, dst, pnum, pdir = line.split() @@ -19,36 +48,46 @@ def main(): if not tile.startswith('CLK_HROW'): continue - pip_prefix, pip = pip.split(".") + 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) - rows = set(range(clk_table.CLK_TABLE_NUM_ROWS)) - columns = set(range(clk_table.CLK_TABLE_NUM_COLS)) + if tile not in tiledata: + tiledata[tile] = { + "type": tile_type, + "pips": set(), + "srcs": set(), + "dsts": set() + } - if src in table: - row, column = table[src] + tiledata[tile]["pips"].add((src, dst)) + tiledata[tile]["srcs"].add(src) + tiledata[tile]["dsts"].add(dst) - segmk.add_tile_tag( - tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 1) - segmk.add_tile_tag( - tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 1) + if pdir == 0: + tiledata[tile]["srcs"].add(dst) + tiledata[tile]["dsts"].add(src) - rows.remove(row) - columns.remove(column) + if pnum == 1 or pdir == 0: + ignpip.add((src, dst)) - for row in rows: - segmk.add_tile_tag( - tile, '{}.HCLK_ENABLE_ROW{}'.format(dst, row), 0) + active_gclks = {} + active_clks = {} - for column in columns: - segmk.add_tile_tag( - tile, '{}.HCLK_ENABLE_COLUMN{}'.format(dst, column), 0) - if tile not in active_clks: - active_clks[tile] = set() + for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + pips = pips_srcs_dsts["pips"] + + if tile not in active_clks: + active_clks[tile] = set() + + for src, dst in pips_srcs_dsts["pips"]: + if dst.startswith('CLK_HROW_CK_MUX_OUT_'): active_clks[tile].add(src) @@ -58,18 +97,26 @@ def main(): active_gclks[src].add(tile) - tiles = sorted(active_clks.keys()) + 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 tile_type, srcs in clk_list.items(): + for tile, pips_srcs_dsts in tiledata.items(): + for src in srcs: + if 'GCLK' not in src: + active = src in active_clks[tile] + segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), active) + else: + if src not in active_gclks: + segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 0) + elif tile in active_gclks[src]: + segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 1) - for tile in active_clks: - for src in table: - if 'GCLK' not in src: - active = src in active_clks[tile] - segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), active) - else: - if src not in active_gclks: - segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 0) - elif tile in active_gclks[src]: - segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 1) segmk.compile() segmk.write() diff --git a/fuzzers/041-clk-hrow-pips/merge_clk_entries.py b/fuzzers/041-clk-hrow-pips/merge_clk_entries.py deleted file mode 100644 index 1ddd2ebe..00000000 --- a/fuzzers/041-clk-hrow-pips/merge_clk_entries.py +++ /dev/null @@ -1,89 +0,0 @@ -import argparse -import clk_table - - -def main(): - parser = argparse.ArgumentParser( - description="Convert HCLK ROW/COLUMN definitions into HCLK pips.") - parser.add_argument('in_segbit') - parser.add_argument('piplist') - parser.add_argument('out_segbit') - - args = parser.parse_args() - - output_features = [] - hrow_outs = {} - tile = None - with open(args.in_segbit) as f: - for l in f: - parts = l.strip().split(' ') - feature = parts[0] - bits = ' '.join(parts[1:]) - - # No post-processing on _ACTIVE bits. - if feature.endswith('_ACTIVE'): - output_features.append(l.strip()) - continue - - tile1, dst, src = feature.split('.') - if tile is None: - tile = tile1 - else: - assert tile == tile1 - - n = int(src[-1]) - - if dst not in hrow_outs: - hrow_outs[dst] = { - 'rows': {}, - 'columns': {}, - } - - if src[-4:-1] == 'ROW': - hrow_outs[dst]['rows'][n] = bits - else: - assert src[-7:-1] == 'COLUMN', src - hrow_outs[dst]['columns'][n] = bits - - piplists = {} - with open(args.piplist) as f: - for l in f: - tile, dst, src = l.strip().split('.') - assert tile == 'CLK_HROW_BOT_R', tile - - if dst not in piplists: - piplists[dst] = [] - - piplists[dst].append(src) - - table = clk_table.get_clk_table() - - with open(args.out_segbit, 'w') as f: - for l in output_features: - print(l, file=f) - - for dst in sorted(hrow_outs): - for src in sorted(piplists[dst]): - if src not in table: - continue - - row, column = table[src] - - if row not in hrow_outs[dst]['rows']: - continue - - if column not in hrow_outs[dst]['columns']: - continue - - print( - 'CLK_HROW.{dst}.{inclk} {row_bits} {column_bits}'.format( - dst=dst, - inclk=src, - row_bits=hrow_outs[dst]['rows'][row], - column_bits=hrow_outs[dst]['columns'][column], - ), - file=f) - - -if __name__ == "__main__": - main() diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 74c8d2de..819f3a61 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -135,6 +135,8 @@ def check_allowed(mmcm_pll_dir, cmt): elif mmcm_pll_dir == 'EVEN': x, y = CMT_XY_FUN(cmt) return (x & 1) == 0 + elif mmcm_pll_dir == 'NONE': + return False else: assert False, mmcm_pll_dir @@ -162,7 +164,7 @@ module top(); # sources are allowed. The force of ODD/EVEN/BOTH further biases the # clock sources to the left or right column inputs. mmcm_pll_only = random.randint(0, 1) - mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH')) + mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH', 'NONE')) if not mmcm_pll_only: for _ in range(2): @@ -279,22 +281,30 @@ module top(); any_bufhce = False for tile_name, sites in gen_bufhce_sites(): for site in sites: - wire_name = clock_sources.get_random_source(site_to_cmt[site]) - if wire_name is None: - continue - any_bufhce = True print( """ + wire I_{site}; (* KEEP, DONT_TOUCH, LOC = "{site}" *) BUFHCE buf_{site} ( - .I({wire_name}) + .I(I_{site}) ); """.format( site=site, - wire_name=wire_name, )) + if random.random() > .05: + wire_name = clock_sources.get_random_source(site_to_cmt[site]) + if wire_name is None: + continue + + print(""" + assign I_{site} = {wire_name};""".format( + site=site, + wire_name=wire_name, + )) + + if not any_bufhce: for tile_name, sites in gen_bufhce_sites(): for site in sites: From c2df5c97eb27011ffe57a7acb22fff270266f225 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 14 Mar 2019 20:05:27 -0700 Subject: [PATCH 07/21] Working complete HROW pip fuzzer. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/005-tilegrid/add_tdb.py | 2 +- fuzzers/005-tilegrid/clk_hrow/Makefile | 2 +- fuzzers/005-tilegrid/generate_full.py | 2 +- fuzzers/041-clk-hrow-pips/Makefile | 63 +++--- fuzzers/041-clk-hrow-pips/generate.py | 23 +- fuzzers/041-clk-hrow-pips/generate.tcl | 3 +- fuzzers/041-clk-hrow-pips/output_cmt.tcl | 2 +- fuzzers/041-clk-hrow-pips/top.py | 261 ++++++++++++++++++++--- fuzzers/int_maketodo.py | 19 +- 9 files changed, 306 insertions(+), 71 deletions(-) diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py index 793b2a3f..3dc7eae3 100644 --- a/fuzzers/005-tilegrid/add_tdb.py +++ b/fuzzers/005-tilegrid/add_tdb.py @@ -84,7 +84,7 @@ def run(fn_in, fn_out, verbose=False): ("bram_block/build/segbits_tilegrid.tdb", 128, 10), ("clb/build/segbits_tilegrid.tdb", 36, 2), ("dsp/build/segbits_tilegrid.tdb", 28, 10), - ("clk_hrow/build/segbits_tilegrid.tdb", 30, 7), + ("clk_hrow/build/segbits_tilegrid.tdb", 30, 18), ("clk_bufg/build/segbits_tilegrid.tdb", 30, 8), ("clb_int/build/segbits_tilegrid.tdb", int_frames, int_words), ("iob_int/build/segbits_tilegrid.tdb", int_frames, int_words), diff --git a/fuzzers/005-tilegrid/clk_hrow/Makefile b/fuzzers/005-tilegrid/clk_hrow/Makefile index 17297e84..1934a3f7 100644 --- a/fuzzers/005-tilegrid/clk_hrow/Makefile +++ b/fuzzers/005-tilegrid/clk_hrow/Makefile @@ -1,4 +1,4 @@ N ?= 5 -GENERATE_ARGS?="--oneval 1 --design params.csv --dword 1 --dframe 1A" +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 6 --dframe 1A" include ../fuzzaddr/common.mk diff --git a/fuzzers/005-tilegrid/generate_full.py b/fuzzers/005-tilegrid/generate_full.py index 476c9221..11aabfa6 100644 --- a/fuzzers/005-tilegrid/generate_full.py +++ b/fuzzers/005-tilegrid/generate_full.py @@ -233,7 +233,7 @@ def propagate_rebuf(database, tiles_by_grid): rebuf_below]['type'] assert database[tile_name]['bits']['CLB_IO_CLK'][ - 'offset'] == 47, database[tile_name]['bits']['CLB_IO_CLK'] + 'offset'] == 42, database[tile_name]['bits']['CLB_IO_CLK'] database[rebuf_below]['bits'] = copy.deepcopy( database[tile_name]['bits']) database[rebuf_below]['bits']['CLB_IO_CLK']['offset'] = 73 diff --git a/fuzzers/041-clk-hrow-pips/Makefile b/fuzzers/041-clk-hrow-pips/Makefile index 98c03ac9..df0a7b87 100644 --- a/fuzzers/041-clk-hrow-pips/Makefile +++ b/fuzzers/041-clk-hrow-pips/Makefile @@ -5,12 +5,15 @@ PIPLIST_TCL=$(FUZDIR)/clk_hrow_pip_list.tcl ifeq (${XRAY_PART}, xc7z010clg400-1) # xc7z010clg400-1 is missing some side clock connections, so these bits cannot # be documented. +# FIXME: Use EXCLUDE_RE rather than complicated include RE. TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_[LR][0-9]+\.CLK_HROW_.*[KR_][0-9]+" +TODO_EXCLUDE_RE="^CLK_HROW_BOT_R.*CASCIN[0-9]+$$" else TODO_RE=".*" +TODO_EXCLUDE_RE="^CLK_HROW_BOT_R.*CASCIN[0-9]+$$" endif -MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE) +MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE) --exclude-re $(TODO_EXCLUDE_RE) N = 50 # These PIPs all appear to be either a 2 bit solutions. @@ -20,39 +23,49 @@ A_PIPLIST=clk_hrow_bot_r.txt include ../pip_loop.mk -database: build/segbits_clk_hrow.db - -build/cmt_regions.csv: output_cmt.tcl - mkdir -p build - cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl - -build/segbits_clk_hrow.rdb: $(SPECIMENS_OK) - ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow.rdb \ - $(shell find build -name segdata_clk_hrow_top_r.txt) \ - $(shell find build -name segdata_clk_hrow_bot_r.txt) - -build/segbits_clk_hrow.db: build/segbits_clk_hrow.rdb +database: build/segbits_clk_hrow_bot_r.rdb build/segbits_clk_hrow_top_r.rdb ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_clk_hrow.rdb \ - --seg-fn-out build/segbits_clk_hrow.db + --seg-fn-in build/segbits_clk_hrow_top_r.rdb \ + --seg-fn-out build/segbits_clk_hrow_top_r.db + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_clk_hrow_bot_r.rdb \ + --seg-fn-out build/segbits_clk_hrow_bot_r.db # Keep a copy to track iter progress - cp build/segbits_clk_hrow.rdb build/$(ITER)/segbits_clk_hrow.rdb + cp build/segbits_clk_hrow_top_r.rdb build/$(ITER)/segbits_clk_hrow_top_r.rdb + cp build/segbits_clk_hrow_bot_r.rdb build/$(ITER)/segbits_clk_hrow_bot_r.rdb - ${XRAY_MASKMERGE} build/mask_clk_hrow.db \ - $(shell find build -name segdata_clk_hrow_top_r.txt) \ + ${XRAY_MASKMERGE} build/mask_clk_hrow_top_r.db \ + $(shell find build -name segdata_clk_hrow_top_r.txt) + ${XRAY_MASKMERGE} build/mask_clk_hrow_bot_r.db \ $(shell find build -name segdata_clk_hrow_bot_r.txt) # Clobber existing .db to eliminate potential conflicts rm -f build/database/${XRAY_DATABASE}/* cp ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/segbits*.db build/database/${XRAY_DATABASE} - XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db - XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow_bot_r.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow_top_r.db + +build/cmt_regions.csv: output_cmt.tcl + mkdir -p build + cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + +generate: $(SPECIMENS_OK) + +build/segbits_clk_hrow_top_r.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow_top_r.rdb \ + $(shell find build -name segdata_clk_hrow_top_r.txt) + +build/segbits_clk_hrow_bot_r.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_clk_hrow_bot_r.rdb \ + $(shell find build -name segdata_clk_hrow_bot_r.txt) + +build/segbits_clk_hrow.db: build/segbits_clk_hrow_top_.rdb pushdb: database - ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow.db - ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow.db - ${XRAY_MERGEDB} mask_clk_hrow_bot_r build/mask_clk_hrow.db - ${XRAY_MERGEDB} mask_clk_hrow_top_r build/mask_clk_hrow.db + ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow_bot_r.db + ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow_top_r.db + ${XRAY_MERGEDB} mask_clk_hrow_bot_r build/mask_clk_hrow_bot_r.db + ${XRAY_MERGEDB} mask_clk_hrow_top_r build/mask_clk_hrow_top_r.db -.PHONY: database pushdb +.PHONY: database pushdb generate diff --git a/fuzzers/041-clk-hrow-pips/generate.py b/fuzzers/041-clk-hrow-pips/generate.py index de28cde3..98be0a87 100644 --- a/fuzzers/041-clk-hrow-pips/generate.py +++ b/fuzzers/041-clk-hrow-pips/generate.py @@ -3,7 +3,6 @@ import os import os.path from prjxray.segmaker import Segmaker -import pprint def main(): @@ -12,6 +11,7 @@ def main(): tiledata = {} pipdata = {} clk_list = {} + casco_list = {} ignpip = set() with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', @@ -21,9 +21,13 @@ def main(): if tile_type not in pipdata: pipdata[tile_type] = [] clk_list[tile_type] = set() + casco_list[tile_type] = set() pipdata[tile_type].append((src, dst)) + if 'CASCO' in dst: + casco_list[tile_type].add(dst) + if dst.startswith('CLK_HROW_CK_MUX_OUT_'): clk_list[tile_type].add(src) @@ -34,9 +38,13 @@ def main(): if tile_type not in pipdata: pipdata[tile_type] = [] clk_list[tile_type] = set() + casco_list[tile_type] = set() pipdata[tile_type].append((src, dst)) + if 'CASCO' in dst: + casco_list[tile_type].add(dst) + if dst.startswith('CLK_HROW_CK_MUX_OUT_'): clk_list[tile_type].add(src) @@ -78,7 +86,6 @@ def main(): active_gclks = {} active_clks = {} - for tile, pips_srcs_dsts in tiledata.items(): tile_type = pips_srcs_dsts["type"] pips = pips_srcs_dsts["pips"] @@ -87,15 +94,13 @@ def main(): active_clks[tile] = set() for src, dst in pips_srcs_dsts["pips"]: - if dst.startswith('CLK_HROW_CK_MUX_OUT_'): + active_clks[tile].add(src) - active_clks[tile].add(src) + if 'GCLK' in src: + if src not in active_gclks: + active_gclks[src] = set() - if 'GCLK' in src: - if src not in active_gclks: - active_gclks[src] = set() - - active_gclks[src].add(tile) + active_gclks[src].add(tile) for src, dst in pipdata[tile_type]: if (src, dst) in ignpip: diff --git a/fuzzers/041-clk-hrow-pips/generate.tcl b/fuzzers/041-clk-hrow-pips/generate.tcl index e9f672b4..09bcabd9 100644 --- a/fuzzers/041-clk-hrow-pips/generate.tcl +++ b/fuzzers/041-clk-hrow-pips/generate.tcl @@ -121,7 +121,7 @@ proc route_todo {} { } set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] - set destination_nodes [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] + set destination_nodes [filter [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] {NAME =~ *CLK_HROW*}] route_design -unroute -nets $net set new_route [find_routing_path -to $target_node -from $origin_node] puts "Origin node: $origin_node" @@ -151,6 +151,7 @@ proc run {} { set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] set_property IS_ENABLED 0 [get_drc_checks {REQP-161}] set_property IS_ENABLED 0 [get_drc_checks {REQP-123}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-13}] set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] diff --git a/fuzzers/041-clk-hrow-pips/output_cmt.tcl b/fuzzers/041-clk-hrow-pips/output_cmt.tcl index d1af528c..06aba163 100644 --- a/fuzzers/041-clk-hrow-pips/output_cmt.tcl +++ b/fuzzers/041-clk-hrow-pips/output_cmt.tcl @@ -3,7 +3,7 @@ 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} { +foreach site_type {MMCME2_ADV PLLE2_ADV BUFHCE BUFR} { foreach site [get_sites -filter "SITE_TYPE == $site_type"] { puts $fp "$site,[get_property CLOCK_REGION $site]" } diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 819f3a61..8712ee68 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -1,11 +1,17 @@ """ Emits top.v's for various BUFHCE routing inputs. """ import os import random +import re random.seed(int(os.getenv("SEED"), 16)) from prjxray import util +from prjxray import verilog from prjxray.db import Database +from prjxray.lut_maker import LutMaker +from io import StringIO CMT_XY_FUN = util.create_xy_fun(prefix='') +BUFGCTRL_XY_FUN = util.create_xy_fun('BUFGCTRL_') +BUFHCE_XY_FUN = util.create_xy_fun('BUFHCE_') def gen_sites(desired_site_type): @@ -17,7 +23,7 @@ def gen_sites(desired_site_type): gridinfo = grid.gridinfo_at_loc(loc) for site, site_type in gridinfo.sites.items(): if site_type == desired_site_type: - yield site + yield loc, gridinfo.tile_type, site def gen_bufhce_sites(): @@ -59,8 +65,10 @@ class ClockSources(object): self.merged_sources = {} self.source_to_cmt = {} self.used_sources_from_cmt = {} + self.sources_by_loc = {} + self.active_cmt_ports = {} - def add_clock_source(self, source, cmt): + def add_clock_source(self, source, cmt, loc=None): """ Adds a source from a specific CMT. cmt='ANY' indicates that this source can be routed to any CMT. @@ -73,6 +81,14 @@ class ClockSources(object): source] == cmt, source self.source_to_cmt[source] = cmt + self.add_bufg_clock_source(source, cmt, loc) + + def add_bufg_clock_source(self, source, cmt, loc): + if loc not in self.sources_by_loc: + self.sources_by_loc[loc] = [] + + self.sources_by_loc[loc].append((cmt, source)) + def get_random_source(self, cmt): """ Get a random source that is routable to the specific CMT. @@ -113,12 +129,91 @@ class ClockSources(object): if source_cmt != 'ANY' and len( self.used_sources_from_cmt[source_cmt]) > 14: - print('//', self.used_sources_from_cmt) self.used_sources_from_cmt[source_cmt].remove(source) return None else: return source + def get_bufg_source(self, loc, tile_type, site, todos, i_wire, used_only): + bufg_sources = [] + + top = '_TOP_' in tile_type + bottom = '_BOT_' in tile_type + + assert top ^ bottom, tile_type + + if top: + for src_loc, cmt_sources in self.sources_by_loc.items(): + if src_loc is None: + continue + if src_loc.grid_y <= loc.grid_y: + bufg_sources.extend(cmt_sources) + elif bottom: + for src_loc, cmt_sources in self.sources_by_loc.items(): + if src_loc is None: + continue + if src_loc.grid_y > loc.grid_y: + bufg_sources.extend(cmt_sources) + + # CLK_HROW_TOP_R_CK_BUFG_CASCO0 -> CLK_BUFG_BUFGCTRL0_I0 + # CLK_HROW_TOP_R_CK_BUFG_CASCO22 -> CLK_BUFG_BUFGCTRL11_I0 + # CLK_HROW_TOP_R_CK_BUFG_CASCO23 -> CLK_BUFG_BUFGCTRL11_I1 + # CLK_HROW_BOT_R_CK_BUFG_CASCO27 -> CLK_BUFG_BUFGCTRL13_I1 + + x, y = BUFGCTRL_XY_FUN(site) + assert x == 0 + y = y % 16 + + + assert i_wire in [0, 1], i_wire + + casco_wire = '{tile_type}_CK_BUFG_CASCO{casco_idx}'.format( + tile_type=tile_type.replace('BUFG', 'HROW'), + casco_idx=(y*2+i_wire)) + + if casco_wire not in todos: + return None + + target_wires = [] + + need_bufr = False + for src_wire in todos[casco_wire]: + if 'BUFRCLK' in src_wire: + need_bufr = True + break + + for cmt, wire in bufg_sources: + if 'BUFR' in wire: + if need_bufr: + target_wires.append((cmt, wire)) + else: + target_wires.append((cmt, wire)) + + random.shuffle(target_wires) + for cmt, source in target_wires: + if cmt == 'ANY': + return source + else: + # Make sure to not try to import move than 14 sources from + # the CMT, there is limited routing. + if cmt not in self.used_sources_from_cmt: + self.used_sources_from_cmt[cmt] = set() + + if source in self.used_sources_from_cmt[cmt]: + return source + elif used_only: + continue + + if len(self.used_sources_from_cmt[cmt]) < 14: + self.used_sources_from_cmt[cmt].add(source) + return source + else: + continue + + return None + + + def check_allowed(mmcm_pll_dir, cmt): """ Check whether the CMT specified is in the allowed direction. @@ -140,6 +235,45 @@ def check_allowed(mmcm_pll_dir, cmt): else: assert False, mmcm_pll_dir +def read_todo(): + dsts = {} + + with open(os.path.join('..', 'todo_all.txt')) as f: + for l in f: + tile_type, dst, src = l.strip().split('.') + + if dst not in dsts: + dsts[dst] = set() + + dsts[dst].add(src) + + return dsts + +def need_int_connections(todos): + for srcs in todos.values(): + for src in srcs: + if re.search('INT_._.', src): + return True + + return False + +def bufhce_in_todo(todos, site): + if 'BUFHCE' in site: + # CLK_HROW_CK_MUX_OUT_R9 -> X1Y9 + # CLK_HROW_CK_MUX_OUT_L11 -> X0Y35 + x, y = BUFHCE_XY_FUN(site) + y = y % 12 + + if x == 0: + lr = 'L' + elif x == 1: + lr = 'R' + else: + assert False, x + + return 'CLK_HROW_CK_MUX_OUT_{lr}{y}'.format(lr=lr, y=y) in todos + else: + return True def main(): """ @@ -166,26 +300,27 @@ module top(); mmcm_pll_only = random.randint(0, 1) mmcm_pll_dir = random.choice(('ODD', 'EVEN', 'BOTH', 'NONE')) + todos = read_todo() + if not mmcm_pll_only: - for _ in range(2): - clock_sources.add_clock_source('one', 'ANY') - clock_sources.add_clock_source('zero', 'ANY') + if need_int_connections(todos): + for _ in range(10): + clock_sources.add_clock_source('one', 'ANY') + clock_sources.add_clock_source('zero', 'ANY') print(""" wire zero = 0; wire one = 1;""") - for site in gen_sites('MMCME2_ADV'): + for loc, _, site in gen_sites('MMCME2_ADV'): mmcm_clocks = [ 'mmcm_clock_{site}_{idx}'.format(site=site, idx=idx) for idx in range(13) ] - if not check_allowed(mmcm_pll_dir, site_to_cmt[site]): - continue - - for clk in mmcm_clocks: - clock_sources.add_clock_source(clk, site_to_cmt[site]) + 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], loc) print( """ @@ -223,17 +358,15 @@ module top(); c12=mmcm_clocks[12], )) - for site in gen_sites('PLLE2_ADV'): + for loc, _, site in gen_sites('PLLE2_ADV'): pll_clocks = [ 'pll_clock_{site}_{idx}'.format(site=site, idx=idx) for idx in range(6) ] - if not check_allowed(mmcm_pll_dir, site_to_cmt[site]): - continue - - for clk in pll_clocks: - clock_sources.add_clock_source(clk, site_to_cmt[site]) + 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], loc) print( """ @@ -257,30 +390,65 @@ module top(); c5=pll_clocks[5], )) + for loc, _, site in gen_sites('BUFR'): + clock_sources.add_bufg_clock_source('O_{site}'.format(site=site), site_to_cmt[site], loc) + print(""" + wire O_{site}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR bufr_{site} ( + .O(O_{site}) + );""".format(site=site)) + + luts = LutMaker() + bufhs = StringIO() + bufgs = StringIO() + gclks = [] - for site in sorted(gen_sites("BUFGCTRL"), - key=util.create_xy_fun('BUFGCTRL_')): - wire_name = 'clk_{}'.format(site) + for _, _, site in sorted(gen_sites("BUFGCTRL"), + key=lambda x: BUFGCTRL_XY_FUN(x[2])): + wire_name = 'gclk_{}'.format(site) gclks.append(wire_name) if not mmcm_pll_only: clock_sources.add_clock_source(wire_name, 'ANY') + print(""" + wire {wire_name}; + """.format(wire_name=wire_name)) print( """ - wire {wire_name}; + wire I1_{site}; + wire I0_{site}; (* KEEP, DONT_TOUCH, LOC = "{site}" *) - BUFG bufg_{site} ( - .O({wire_name}) + BUFGCTRL bufg_{site} ( + .O({wire_name}), + .S1({s1net}), + .S0({s0net}), + .IGNORE1({ignore1net}), + .IGNORE0({ignore0net}), + .I1(I1_{site}), + .I0(I0_{site}), + .CE1({ce1net}), + .CE0({ce0net}) ); """.format( site=site, wire_name=wire_name, - )) + s1net=luts.get_next_output_net(), + s0net=luts.get_next_output_net(), + ignore1net=luts.get_next_output_net(), + ignore0net=luts.get_next_output_net(), + ce1net=luts.get_next_output_net(), + ce0net=luts.get_next_output_net(), + ), file=bufgs) + any_bufhce = False for tile_name, sites in gen_bufhce_sites(): for site in sites: + if not bufhce_in_todo(todos, site): + continue + any_bufhce = True print( """ @@ -291,10 +459,11 @@ module top(); ); """.format( site=site, - )) + ), file=bufhs) if random.random() > .05: wire_name = clock_sources.get_random_source(site_to_cmt[site]) + if wire_name is None: continue @@ -302,7 +471,7 @@ module top(); assign I_{site} = {wire_name};""".format( site=site, wire_name=wire_name, - )) + ), file=bufhs) if not any_bufhce: @@ -311,16 +480,52 @@ module top(); print( """ (* KEEP, DONT_TOUCH, LOC = "{site}" *) - BUFHCE buf_{site} ( + BUFHCE #( + .INIT_OUT({INIT_OUT}), + .CE_TYPE({CE_TYPE}), + .IS_CE_INVERTED({IS_CE_INVERTED}) + ) buf_{site} ( .I({wire_name}) ); """.format( + INIT_OUT=random.randint(0, 1), + CE_TYPE=verilog.quote( + random.choice(('SYNC', 'ASYNC'))), + IS_CE_INVERTED = random.randint(0, 1), site=site, wire_name=gclks[0], )) break break + for l in luts.create_wires_and_luts(): + print(l) + + print(bufhs.getvalue()) + print(bufgs.getvalue()) + + used_only = random.random() < .25 + + for loc, tile_type, site in sorted(gen_sites("BUFGCTRL"), + key=lambda x: BUFGCTRL_XY_FUN(x[2])): + if random.randint(0, 1): + wire_name = clock_sources.get_bufg_source(loc, tile_type, site, todos, 1, used_only) + if wire_name is not None: + print(""" + assign I1_{site} = {wire_name};""".format( + site=site, + wire_name=wire_name, + )) + + if random.randint(0, 1): + wire_name = clock_sources.get_bufg_source(loc, tile_type, site, todos, 0, used_only) + if wire_name is not None: + print(""" + assign I0_{site} = {wire_name};""".format( + site=site, + wire_name=wire_name, + )) + print("endmodule") diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index a1729a10..970d8d07 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -33,7 +33,7 @@ def load_pipfile(pipfile, verbose=False): return todos, tile_type -def maketodo(pipfile, dbfile, intre, not_endswith=None, verbose=False): +def maketodo(pipfile, dbfile, intre, exclude_re=None, not_endswith=None, verbose=False): ''' db files start with INT., but pipfile lines start with INT_L Normalize by removing before the first dot @@ -75,8 +75,15 @@ def maketodo(pipfile, dbfile, intre, not_endswith=None, verbose=False): drops = 0 lines = 0 for line in todos: - if re.match(intre, line) and (not_endswith is None - or not line.endswith(not_endswith)): + include = re.match(intre, line) is not None + + if include and not_endswith is not None: + include = not line.endswith(not_endswith) + + if include and exclude_re is not None: + include = re.match(exclude_re, line) is None + + if include: print(line) else: drops += 1 @@ -94,6 +101,7 @@ def run( r, pip_type, seg_type, + exclude_re=None, not_endswith=None, verbose=False): if db_dir is None: @@ -117,7 +125,8 @@ def run( "%s/%s_%s.txt" % (pip_dir, pip_type, side), "%s/segbits_%s_%s.db" % (db_dir, seg_type, side), intre, - not_endswith, + exclude_re=exclude_re, + not_endswith=not_endswith, verbose=verbose) @@ -132,6 +141,7 @@ def main(): parser.add_argument('--db-dir', default=None, help='') parser.add_argument('--pip-dir', default=None, help='') parser.add_argument('--re', required=True, help='') + parser.add_argument('--exclude-re', required=False, default=None, help='') parser.add_argument('--pip-type', default="pips_int", help='') parser.add_argument('--seg-type', default="int", help='') parser.add_argument('--sides', default="l,r", help='') @@ -146,6 +156,7 @@ def main(): db_dir=args.db_dir, pip_dir=args.pip_dir, intre=args.re, + exclude_re=args.exclude_re, sides=args.sides.split(','), l=args.l, r=args.r, From 953d64a7b937f11e7ece8eba2f71c8519806bf8c Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 15 Mar 2019 18:42:40 -0700 Subject: [PATCH 08/21] Run make format. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/generate.py | 1 - fuzzers/041-clk-hrow-pips/top.py | 69 +++++++++++++++------------ fuzzers/int_maketodo.py | 4 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/fuzzers/041-clk-hrow-pips/generate.py b/fuzzers/041-clk-hrow-pips/generate.py index 98be0a87..30f24eed 100644 --- a/fuzzers/041-clk-hrow-pips/generate.py +++ b/fuzzers/041-clk-hrow-pips/generate.py @@ -122,7 +122,6 @@ def main(): elif tile in active_gclks[src]: segmk.add_tile_tag(tile, '{}_ACTIVE'.format(src), 1) - segmk.compile() segmk.write() diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 8712ee68..34badcff 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -164,12 +164,11 @@ class ClockSources(object): assert x == 0 y = y % 16 - assert i_wire in [0, 1], i_wire casco_wire = '{tile_type}_CK_BUFG_CASCO{casco_idx}'.format( - tile_type=tile_type.replace('BUFG', 'HROW'), - casco_idx=(y*2+i_wire)) + tile_type=tile_type.replace('BUFG', 'HROW'), + casco_idx=(y * 2 + i_wire)) if casco_wire not in todos: return None @@ -213,8 +212,6 @@ class ClockSources(object): return None - - def check_allowed(mmcm_pll_dir, cmt): """ Check whether the CMT specified is in the allowed direction. @@ -235,6 +232,7 @@ def check_allowed(mmcm_pll_dir, cmt): else: assert False, mmcm_pll_dir + def read_todo(): dsts = {} @@ -249,6 +247,7 @@ def read_todo(): return dsts + def need_int_connections(todos): for srcs in todos.values(): for src in srcs: @@ -257,6 +256,7 @@ def need_int_connections(todos): return False + def bufhce_in_todo(todos, site): if 'BUFHCE' in site: # CLK_HROW_CK_MUX_OUT_R9 -> X1Y9 @@ -275,6 +275,7 @@ def bufhce_in_todo(todos, site): else: return True + def main(): """ BUFHCE's can be driven from: @@ -366,7 +367,7 @@ module top(); 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], loc) + clock_sources.add_clock_source(clk, site_to_cmt[site], loc) print( """ @@ -391,8 +392,10 @@ module top(); )) for loc, _, site in gen_sites('BUFR'): - clock_sources.add_bufg_clock_source('O_{site}'.format(site=site), site_to_cmt[site], loc) - print(""" + clock_sources.add_bufg_clock_source( + 'O_{site}'.format(site=site), site_to_cmt[site], loc) + print( + """ wire O_{site}; (* KEEP, DONT_TOUCH, LOC = "{site}" *) BUFR bufr_{site} ( @@ -405,7 +408,7 @@ module top(); gclks = [] for _, _, site in sorted(gen_sites("BUFGCTRL"), - key=lambda x: BUFGCTRL_XY_FUN(x[2])): + key=lambda x: BUFGCTRL_XY_FUN(x[2])): wire_name = 'gclk_{}'.format(site) gclks.append(wire_name) @@ -440,8 +443,8 @@ module top(); ignore0net=luts.get_next_output_net(), ce1net=luts.get_next_output_net(), ce0net=luts.get_next_output_net(), - ), file=bufgs) - + ), + file=bufgs) any_bufhce = False for tile_name, sites in gen_bufhce_sites(): @@ -457,9 +460,8 @@ module top(); BUFHCE buf_{site} ( .I(I_{site}) ); - """.format( - site=site, - ), file=bufhs) + """.format(site=site, ), + file=bufhs) if random.random() > .05: wire_name = clock_sources.get_random_source(site_to_cmt[site]) @@ -467,12 +469,13 @@ module top(); if wire_name is None: continue - print(""" + print( + """ assign I_{site} = {wire_name};""".format( - site=site, - wire_name=wire_name, - ), file=bufhs) - + site=site, + wire_name=wire_name, + ), + file=bufhs) if not any_bufhce: for tile_name, sites in gen_bufhce_sites(): @@ -491,7 +494,7 @@ module top(); INIT_OUT=random.randint(0, 1), CE_TYPE=verilog.quote( random.choice(('SYNC', 'ASYNC'))), - IS_CE_INVERTED = random.randint(0, 1), + IS_CE_INVERTED=random.randint(0, 1), site=site, wire_name=gclks[0], )) @@ -507,24 +510,28 @@ module top(); used_only = random.random() < .25 for loc, tile_type, site in sorted(gen_sites("BUFGCTRL"), - key=lambda x: BUFGCTRL_XY_FUN(x[2])): + key=lambda x: BUFGCTRL_XY_FUN(x[2])): if random.randint(0, 1): - wire_name = clock_sources.get_bufg_source(loc, tile_type, site, todos, 1, used_only) + wire_name = clock_sources.get_bufg_source( + loc, tile_type, site, todos, 1, used_only) if wire_name is not None: - print(""" + print( + """ assign I1_{site} = {wire_name};""".format( - site=site, - wire_name=wire_name, - )) + site=site, + wire_name=wire_name, + )) if random.randint(0, 1): - wire_name = clock_sources.get_bufg_source(loc, tile_type, site, todos, 0, used_only) + wire_name = clock_sources.get_bufg_source( + loc, tile_type, site, todos, 0, used_only) if wire_name is not None: - print(""" + print( + """ assign I0_{site} = {wire_name};""".format( - site=site, - wire_name=wire_name, - )) + site=site, + wire_name=wire_name, + )) print("endmodule") diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index 970d8d07..cc43a861 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -33,7 +33,9 @@ def load_pipfile(pipfile, verbose=False): return todos, tile_type -def maketodo(pipfile, dbfile, intre, exclude_re=None, not_endswith=None, verbose=False): +def maketodo( + pipfile, dbfile, intre, exclude_re=None, not_endswith=None, + verbose=False): ''' db files start with INT., but pipfile lines start with INT_L Normalize by removing before the first dot From 66c7c4c3ab4e9bb2f2372c8363e372e3626c8edb Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 15 Mar 2019 06:47:46 -0700 Subject: [PATCH 09/21] Add fuzzers for HCLK_CMT tiles. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/005-tilegrid/Makefile | 5 + fuzzers/005-tilegrid/add_tdb.py | 1 + fuzzers/005-tilegrid/hclk_cmt/Makefile | 4 + fuzzers/005-tilegrid/hclk_cmt/generate.tcl | 3 + fuzzers/005-tilegrid/hclk_cmt/top.py | 66 +++ fuzzers/045-hclk-cmt-pips/Makefile | 65 +++ fuzzers/045-hclk-cmt-pips/bits.dbf | 0 fuzzers/045-hclk-cmt-pips/generate.py | 105 +++++ fuzzers/045-hclk-cmt-pips/generate.tcl | 233 +++++++++ .../045-hclk-cmt-pips/hclk_cmt_pip_list.tcl | 20 + fuzzers/045-hclk-cmt-pips/output_cmt.tcl | 11 + fuzzers/045-hclk-cmt-pips/top.py | 446 ++++++++++++++++++ fuzzers/int_maketodo.py | 7 +- utils/mergedb.sh | 5 + 14 files changed, 969 insertions(+), 2 deletions(-) create mode 100644 fuzzers/005-tilegrid/hclk_cmt/Makefile create mode 100644 fuzzers/005-tilegrid/hclk_cmt/generate.tcl create mode 100644 fuzzers/005-tilegrid/hclk_cmt/top.py create mode 100644 fuzzers/045-hclk-cmt-pips/Makefile create mode 100644 fuzzers/045-hclk-cmt-pips/bits.dbf create mode 100644 fuzzers/045-hclk-cmt-pips/generate.py create mode 100644 fuzzers/045-hclk-cmt-pips/generate.tcl create mode 100644 fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl create mode 100644 fuzzers/045-hclk-cmt-pips/output_cmt.tcl create mode 100644 fuzzers/045-hclk-cmt-pips/top.py 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" ;; From 4c0f36b755d83419611b14f175bc33ceb3bee21f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 15 Mar 2019 18:46:09 -0700 Subject: [PATCH 10/21] Add new fuzzer to root Makefile. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/fuzzers/Makefile b/fuzzers/Makefile index a943cd54..01ceaf73 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -84,6 +84,7 @@ $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) $(eval $(call fuzzer,042-clk-bufg-config,005-tilegrid)) $(eval $(call fuzzer,043-clk-rebuf-pips,005-tilegrid)) $(eval $(call fuzzer,044-clk-bufg-pips,005-tilegrid)) +$(eval $(call fuzzer,045-hclk-cmt-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)) From a5b086bfcf6d47141c9dd49c9d8e4eadec679ce2 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 15 Mar 2019 19:37:23 -0700 Subject: [PATCH 11/21] Clearify ZDB and how it was generated. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/044-clk-bufg-pips/bits.dbf | 1 + fuzzers/044-clk-bufg-pips/build_zdb.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fuzzers/044-clk-bufg-pips/bits.dbf b/fuzzers/044-clk-bufg-pips/bits.dbf index 1fb02ee4..3ba9bed1 100644 --- a/fuzzers/044-clk-bufg-pips/bits.dbf +++ b/fuzzers/044-clk-bufg-pips/bits.dbf @@ -1,3 +1,4 @@ +# Generated from build_zdb.py 26_07 26_08 27_06,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I0.CLK_BUFG_IMUX28_0 26_04 26_05 27_05,CLK_BUFG.CLK_BUFG_BUFGCTRL0_I1.CLK_BUFG_IMUX28_0 26_167 26_168 27_166,CLK_BUFG.CLK_BUFG_BUFGCTRL10_I0.CLK_BUFG_IMUX30_2 diff --git a/fuzzers/044-clk-bufg-pips/build_zdb.py b/fuzzers/044-clk-bufg-pips/build_zdb.py index b3d2fe34..8f8d8fe6 100644 --- a/fuzzers/044-clk-bufg-pips/build_zdb.py +++ b/fuzzers/044-clk-bufg-pips/build_zdb.py @@ -1,4 +1,4 @@ -""" Tool for building ZDB for BUFG pips. +""" Tool for building zero db file for BUFG pips. This requires that the rdb files be good enough to identify all the 0 candidate features, which may take multiple manual iterations. Manual iterations can @@ -42,6 +42,8 @@ def main(): groups[dst][src] = bits + print('# Generated from build_zdb.py') + for dst in groups: if len(groups[dst]) == 1: continue From e6727e6c6077d2a9c07cbdb857c4a28640a407a4 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 15 Mar 2019 19:43:10 -0700 Subject: [PATCH 12/21] Add README's Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/044-clk-bufg-pips/README.md | 4 ++++ fuzzers/045-hclk-cmt-pips/README.md | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 fuzzers/044-clk-bufg-pips/README.md create mode 100644 fuzzers/045-hclk-cmt-pips/README.md diff --git a/fuzzers/044-clk-bufg-pips/README.md b/fuzzers/044-clk-bufg-pips/README.md new file mode 100644 index 00000000..3073e716 --- /dev/null +++ b/fuzzers/044-clk-bufg-pips/README.md @@ -0,0 +1,4 @@ +BUFG interconnect fuzzer +======================== + +Solves pips located within the BUFG switch box. diff --git a/fuzzers/045-hclk-cmt-pips/README.md b/fuzzers/045-hclk-cmt-pips/README.md new file mode 100644 index 00000000..941e0636 --- /dev/null +++ b/fuzzers/045-hclk-cmt-pips/README.md @@ -0,0 +1,4 @@ +HCLK\_CMT interconnect fuzzer +============================= + +Solves pips located within the HCLK\_CMT switch box. From 90715ab3e4e48d77d9cec93eb3f41dd72c1d5413 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 18 Mar 2019 15:59:54 -0700 Subject: [PATCH 13/21] Attempt to fix flaky 041 fuzzer. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/Makefile | 11 +- .../041-clk-hrow-pips/clk_hrow_pip_list.tcl | 32 ++- fuzzers/041-clk-hrow-pips/generate.tcl | 258 ++++++++++++------ fuzzers/041-clk-hrow-pips/top.py | 22 ++ fuzzers/045-hclk-cmt-pips/Makefile | 3 +- .../045-hclk-cmt-pips/hclk_cmt_pip_list.tcl | 32 ++- 6 files changed, 248 insertions(+), 110 deletions(-) diff --git a/fuzzers/041-clk-hrow-pips/Makefile b/fuzzers/041-clk-hrow-pips/Makefile index df0a7b87..9bd3afc1 100644 --- a/fuzzers/041-clk-hrow-pips/Makefile +++ b/fuzzers/041-clk-hrow-pips/Makefile @@ -2,18 +2,9 @@ export FUZDIR=$(shell pwd) PIP_TYPE?=clk_hrow PIPLIST_TCL=$(FUZDIR)/clk_hrow_pip_list.tcl -ifeq (${XRAY_PART}, xc7z010clg400-1) -# xc7z010clg400-1 is missing some side clock connections, so these bits cannot -# be documented. -# FIXME: Use EXCLUDE_RE rather than complicated include RE. -TODO_RE="[^\.]+\.CLK_HROW_CK_MUX_OUT_[LR][0-9]+\.CLK_HROW_.*[KR_][0-9]+" -TODO_EXCLUDE_RE="^CLK_HROW_BOT_R.*CASCIN[0-9]+$$" -else TODO_RE=".*" -TODO_EXCLUDE_RE="^CLK_HROW_BOT_R.*CASCIN[0-9]+$$" -endif -MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE) --exclude-re $(TODO_EXCLUDE_RE) +MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_hrow --re $(TODO_RE) N = 50 # These PIPs all appear to be either a 2 bit solutions. diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl index 83872c61..692ad20d 100644 --- a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -1,12 +1,30 @@ 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 ""]" + 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 $src] + if { $dst_node == {} } { + continue + } + + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 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 + } + } } } close $fp diff --git a/fuzzers/041-clk-hrow-pips/generate.tcl b/fuzzers/041-clk-hrow-pips/generate.tcl index 09bcabd9..5f9277e1 100644 --- a/fuzzers/041-clk-hrow-pips/generate.tcl +++ b/fuzzers/041-clk-hrow-pips/generate.tcl @@ -24,119 +24,209 @@ proc write_pip_txtdata {filename} { } proc load_todo {} { - set fp [open "../../todo.txt" r] - set todo_lines {} + set fp [open "../../todo_all.txt" r] + + # Create map of pip destinations to remaining sources for that pip + set todo_map [dict create] for {gets $fp line} {$line != ""} {gets $fp line} { - lappend todo_lines [split $line .] + set parts [split $line .] + if ![string match "*CLK_HROW_CK_IN_*" [lindex $parts 2]] { + continue + } + dict lappend todo_map [lindex $parts 1] [list [lindex $parts 0] [lindex $parts 2]] } close $fp - return $todo_lines + return $todo_map } proc route_todo {} { puts "Checking TODO's" - set todo_lines [load_todo] - set srcs {} - foreach todo $todo_lines { - set src [lindex $todo 2] + set todo_map [load_todo] - if [string match "*CLK_HROW_CK_IN_*" $src] { - lappend srcs $src - } - } + set nets [get_nets] - set srcs [lsort -unique $srcs] + set todo_nets [dict create] + set used_destinations [dict create] - set nets [get_nets -hierarchical "*clock*"] - set found_wires {} - set remaining_nets {} foreach net $nets { - set wires [get_wires -of_objects $net] + # Check to see if this net is one we are interested in + set wires [get_wires -of_objects $net -filter {TILE_NAME =~ *CLK_HROW*}] + set is_gclk_net 0 foreach wire $wires { - if [regexp "CLK_HROW_CK_IN_\[LR\]\[0-9\]+" $wire] { - # Route already going where we want it, continue - puts "Checking wire $wire." - set wire [lindex [split $wire "/"] 1] - if {[lsearch -regexp $srcs "$wire$"] != -1} { - puts "Found in TODO list, removing from list." - lappend found_wires $wire - # Fix route that is using target net. - set_property is_route_fixed 1 $net - } else { - puts "Wire not in TODO list, adding to reroute list." - lappend remaining_nets $net - } - break - } - } - } - - set found_wires [lsort -unique $found_wires] - foreach wire $found_wires { - puts "Removing $wire" - set srcs [lsearch -regexp -all -inline -not $srcs "$wire$"] - } - - puts "Remaining TODOs:" - foreach src $srcs { - puts $src - } - - set remaining_nets [lsort -unique $remaining_nets] - set completed_todos {} - - foreach net $remaining_nets { - set wires [get_wires -of_objects $net] - - set clk_in_wire "" - foreach wire $wires { - if [regexp "CLK_HROW_CK_IN_(\[LR\])\[0-9\]+" $wire match lr] { - set clk_in_wire $wire + puts "Check wire $wire in $net" + if [string match "*CLK_HROW_CK_IN_*" $wire] { + set gclk_tile [lindex [split $wire /] 0] + set gclk_wire [lindex [split $wire /] 1] + set is_gclk_net 1 break } } - if {$clk_in_wire == ""} { - error "$net does not appear to be correct net for rerouting?" + if {$is_gclk_net == 0} { + puts "$net not going to a HCLK port, skipping." + continue } - puts "" - puts "Rerouting net $net at $clk_in_wire ($lr)" + puts "Net $net wires:" + foreach wire [get_wires -of_objects $net] { + puts " - $wire" + } - # Find an input in the todo list that this can can drive. - foreach src $srcs { - if {[lsearch -exact $completed_todos $src] != -1} { + foreach wire $wires { + set tile [lindex [split $wire /] 0] + set wire [lindex [split $wire /] 1] + if { $tile != $gclk_tile } { continue } - if [regexp "CLK_HROW_CK_IN_$lr\[0-9\]+" $src] { - puts "Found target pip $src for net $net." - set tile [get_tiles -of_objects $clk_in_wire] + set tile_type [get_property TILE_TYPE [get_tiles $tile]] - set target_wire [get_wires "$tile/$src"] - set target_node [get_nodes -of_objects $target_wire] - if {[llength $target_node] == 0} { - error "Failed to find node for $tile/$src." + if { ![dict exists $todo_map $wire] } { + continue + } + + set srcs [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 origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] - set destination_nodes [filter [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]] {NAME =~ *CLK_HROW*}] - route_design -unroute -nets $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" - puts "Destination nodes: $destination_nodes" + set other_wire [lindex [split $other_wire /] 1] - # Only need to set route to one of the destinations. - # Router will handle the rest. - set_property FIXED_ROUTE [concat $new_route [lindex $destination_nodes 0]] $net + if { $wire == $other_wire } { + continue + } - # Remove wire, as we've found a clock to set - lappend completed_todos $src - break + foreach src $srcs { + set src_tile_type [lindex $src 0] + + if {$src_tile_type != $tile_type} { + continue + } + + set src_wire [lindex $src 1] + + if { $other_wire == $src_wire } { + 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/$src_wire" 1 + break + } + } } + + if { $found_target == 1 } { + # Net has an interesting + continue + } + + dict set todo_nets $net [list $tile $wire $gclk_wire] + puts "Interesting net $net (including $wire and $gclk_wire) is being rerouted." + } + } + + set routed_sources [dict create] + + dict for {net tile_wire} $todo_nets { + + if { [get_property IS_ROUTE_FIXED $net] == 1 } { + puts "Net $net is already routed, skipping." + continue + } + + set tile [lindex $tile_wire 0] + set wire [lindex $tile_wire 1] + set gclk_wire [lindex $tile_wire 2] + set srcs [dict get $todo_map $wire] + + puts "" + puts "Rerouting net $net at $tile / $gclk_wire (type $tile_type)" + + set tile_type [get_property TILE_TYPE [get_tiles $tile]] + regexp "CLK_HROW_CK_IN_(\[LR\])\[0-9\]+" $gclk_wire match lr + + set todos {} + foreach src $srcs { + set src_tile_type [lindex $src 0] + if {$src_tile_type != $tile_type} { + continue + } + + set src_wire [lindex $src 1] + + if [regexp "CLK_HROW_CK_IN_$lr\[0-9\]+" $src_wire] { + lappend todos $src_wire + } + } + + if {[llength $todos] == 0} { + puts "No inputs for net $net." + dict set used_destinations "$tile/$gclk_wire" 1 + continue + } + + puts "All todos for $tile_type / $wire" + foreach src_wire $todos { + puts " - $src_wire" + } + + + # Find an input in the todo list that this can can drive. + set set_new_route 0 + foreach src_wire $todos { + if { [dict exists $used_destinations "$tile/$src_wire"] } { + puts "Not routing to $tile / $src_wire, in use." + continue + } + + puts "Attempting to route to $src_wire for net $net." + + set target_wire [get_wires "$tile/$src_wire"] + set target_node [get_nodes -of_objects $target_wire] + if {[llength $target_node] == 0} { + continue + } + + set origin_node [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + + if [dict exists $routed_sources $origin_node] { + puts "Skip net $net, already routed." + continue + } + + route_design -unroute -nets $net + + set old_nets [get_nets -of_objects $target_node] + if { $old_nets != {} } { + puts "Unrouting $old_nets" + route_design -unroute -nets $old_nets + } + + set old_nets [get_nets -of_objects $origin_node] + if { $old_nets != {} } { + puts "Unrouting $old_nets" + route_design -unroute -nets $old_nets + } + + 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/$src_wire" 1 + dict set routed_sources "$origin_node" 1 + set set_new_route 1 + break } } } diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 34badcff..c4ec2dc4 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -275,6 +275,25 @@ def bufhce_in_todo(todos, site): else: return True +def need_gclk_connection(todos, site): + x, y = BUFGCTRL_XY_FUN(site) + assert x == 0 + + src_wire = 'CLK_HROW_R_CK_GCLK{}'.format(y) + for srcs in todos.values(): + if src_wire in srcs: + return True + + return False + +def only_gclk_left(todos): + for srcs in todos.values(): + for src in srcs: + if 'GCLK' not in src: + return False + + return True + def main(): """ @@ -303,6 +322,9 @@ module top(); todos = read_todo() + if only_gclk_left(todos): + mmcm_pll_dir = 'NONE' + if not mmcm_pll_only: if need_int_connections(todos): for _ in range(10): diff --git a/fuzzers/045-hclk-cmt-pips/Makefile b/fuzzers/045-hclk-cmt-pips/Makefile index 06e27822..d0a9df82 100644 --- a/fuzzers/045-hclk-cmt-pips/Makefile +++ b/fuzzers/045-hclk-cmt-pips/Makefile @@ -3,12 +3,11 @@ 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)" +EXCLUDE_RE="(^.*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 diff --git a/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl b/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl index e3ff9cdf..a41b692b 100644 --- a/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl +++ b/fuzzers/045-hclk-cmt-pips/hclk_cmt_pip_list.tcl @@ -1,12 +1,30 @@ 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 ""]" + 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 $src] + if { $dst_node == {} } { + continue + } + + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 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 + } + } } } close $fp From ef18f0ff783b2ff716f0c92fd139026536e4163c Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 18 Mar 2019 17:09:07 -0700 Subject: [PATCH 14/21] Put back LEAF filter. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/045-hclk-cmt-pips/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/045-hclk-cmt-pips/Makefile b/fuzzers/045-hclk-cmt-pips/Makefile index d0a9df82..0406aa5a 100644 --- a/fuzzers/045-hclk-cmt-pips/Makefile +++ b/fuzzers/045-hclk-cmt-pips/Makefile @@ -7,7 +7,7 @@ TODO_RE=".*" # 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="(^.*BUFMR)|(^.*FREQ_REF)|(^.*PHSR)|(^.*CLK_PLL7)|(^.*CLK_MMCM13)" +EXCLUDE_RE="(^.*LEAF)|(^.*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 From a1b24f3a24b4f7bef00f66f14e74203b959939b2 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 18 Mar 2019 17:36:27 -0700 Subject: [PATCH 15/21] Run make format. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/top.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index c4ec2dc4..5ac8692d 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -275,6 +275,7 @@ def bufhce_in_todo(todos, site): else: return True + def need_gclk_connection(todos, site): x, y = BUFGCTRL_XY_FUN(site) assert x == 0 @@ -286,6 +287,7 @@ def need_gclk_connection(todos, site): return False + def only_gclk_left(todos): for srcs in todos.values(): for src in srcs: From 59a4c27f2ea3c45c17c77e1c06aa6b80ecd43384 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Wed, 20 Mar 2019 09:26:19 -0700 Subject: [PATCH 16/21] Attempt make 041 and 045 work on K7 and Z7. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl | 5 +++++ fuzzers/045-hclk-cmt-pips/top.py | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl index 692ad20d..2679bd36 100644 --- a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -18,6 +18,11 @@ proc print_tile_pips {tile_type filename} { continue } + # TODO: Support CLK sources from GTX hardblocks. + if [string match *GTX* $src_node] { + continue + } + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" if ![dict exists $pips $pip_string] { diff --git a/fuzzers/045-hclk-cmt-pips/top.py b/fuzzers/045-hclk-cmt-pips/top.py index d623b9c1..0c740d01 100644 --- a/fuzzers/045-hclk-cmt-pips/top.py +++ b/fuzzers/045-hclk-cmt-pips/top.py @@ -107,14 +107,16 @@ def get_paired_iobs(db, grid, tile_name): if gridinfo.tile_type.endswith('_L'): inc = 1 + lr = 'R' else: inc = -1 + lr = 'L' idx = 1 while True: gridinfo = grid.gridinfo_at_loc((loc.grid_x + inc * idx, loc.grid_y)) - if gridinfo.tile_type == 'HCLK_IOI3': + if gridinfo.tile_type.startswith('HCLK_IOI'): break idx += 1 @@ -127,7 +129,8 @@ def get_paired_iobs(db, grid, tile_name): gridinfo = grid.gridinfo_at_loc(iob_loc) tile_name = grid.tilename_at_loc(iob_loc) - assert gridinfo.tile_type.endswith('IOB33') + assert gridinfo.tile_type.startswith(lr + 'IOB'), ( + gridinfo, lr + 'IOB') for site, site_type in gridinfo.sites.items(): if site_type == 'IOB33M': From 57b897a670eca11293fcf84c183274c9a0d84de5 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Wed, 20 Mar 2019 10:19:56 -0700 Subject: [PATCH 17/21] Fix IOB18M's not being used. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/045-hclk-cmt-pips/output_cmt.tcl | 2 +- fuzzers/045-hclk-cmt-pips/top.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fuzzers/045-hclk-cmt-pips/output_cmt.tcl b/fuzzers/045-hclk-cmt-pips/output_cmt.tcl index f4d00aff..1ad5c1a0 100644 --- a/fuzzers/045-hclk-cmt-pips/output_cmt.tcl +++ b/fuzzers/045-hclk-cmt-pips/output_cmt.tcl @@ -3,7 +3,7 @@ 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_type {MMCME2_ADV PLLE2_ADV BUFMRCE BUFHCE IOB33M IOB18M BUFR} { foreach site [get_sites -filter "SITE_TYPE == $site_type"] { puts $fp "$site,[get_property CLOCK_REGION $site]" } diff --git a/fuzzers/045-hclk-cmt-pips/top.py b/fuzzers/045-hclk-cmt-pips/top.py index 0c740d01..5e67b0a2 100644 --- a/fuzzers/045-hclk-cmt-pips/top.py +++ b/fuzzers/045-hclk-cmt-pips/top.py @@ -133,8 +133,8 @@ def get_paired_iobs(db, grid, tile_name): gridinfo, lr + 'IOB') for site, site_type in gridinfo.sites.items(): - if site_type == 'IOB33M': - yield tile_name, site + if site_type in ['IOB33M', 'IOB18M']: + yield tile_name, site, site_type[-3:-1] def check_allowed(mmcm_pll_dir, cmt): @@ -207,7 +207,7 @@ def main(): mmcm_pll_only, mmcm_pll_dir)) for tile_name in sorted(hclk_cmt_tiles): - for _, site in get_paired_iobs(db, grid, tile_name): + for _, site, volt 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]): @@ -220,11 +220,11 @@ def main(): """ (* KEEP, DONT_TOUCH, LOC = "{site}" *) wire clock_IBUF_{site}; - IBUF #( .IOSTANDARD("LVCMOS33") ) ibuf_{site} ( + IBUF #( .IOSTANDARD("LVCMOS{volt}") ) ibuf_{site} ( .I(clk_{site}), .O(clock_IBUF_{site}) ); - """.format(site=site), + """.format(volt=volt, site=site), file=iobs) print( From 63579139273bb9f24504dccc94b4c0a938f34c64 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 21 Mar 2019 09:45:13 -0700 Subject: [PATCH 18/21] Remove TESTPLL nodes from piplist. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl index 2679bd36..791a369d 100644 --- a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -23,6 +23,11 @@ proc print_tile_pips {tile_type filename} { continue } + # Some ports appear to be just test signals, ignore these. + if [string match *TESTPLL* $src_node] { + continue + } + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" if ![dict exists $pips $pip_string] { From 7a5f3a43c7aa88bfa45086db597d61cfdc89e404 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 21 Mar 2019 10:50:25 -0700 Subject: [PATCH 19/21] Also exclude PS CLKs for now. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl index 791a369d..597872ad 100644 --- a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -28,6 +28,11 @@ proc print_tile_pips {tile_type filename} { continue } + # TODO: Support CLK sources from PS7 hardblock + if [string match *PSS_HCLK* $src_node] { + continue + } + if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" if ![dict exists $pips $pip_string] { From 3e851a6256a4b51b67aa4e4f716a74d160e08dd6 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 21 Mar 2019 13:41:36 -0700 Subject: [PATCH 20/21] Reduce number of active GCLKs in final iterations. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/top.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 5ac8692d..da45a805 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -436,7 +436,14 @@ module top(); wire_name = 'gclk_{}'.format(site) gclks.append(wire_name) - if not mmcm_pll_only: + + include_source = True + if mmcm_pll_only: + include_source = False + elif only_gclk_left(todos): + include_source = need_gclk_connection(todos, site) + + if include_source: clock_sources.add_clock_source(wire_name, 'ANY') print(""" From c0b8c2bd0d25a5ae98542588835db07b209f3fbb Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Thu, 21 Mar 2019 14:19:41 -0700 Subject: [PATCH 21/21] Run make format. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/top.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index da45a805..472eacd8 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -436,7 +436,6 @@ module top(); wire_name = 'gclk_{}'.format(site) gclks.append(wire_name) - include_source = True if mmcm_pll_only: include_source = False