From 19ed8c5af8abe3ae6dddc5c5e270248afe9d3b1b Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Fri, 7 Jun 2019 10:18:51 +0200 Subject: [PATCH 1/2] 044-clk-bufg-pips: Exclude CK_BUFG_(BOT|TOP)_R_CK_MUXED from todo list Signed-off-by: Tomasz Michalak --- fuzzers/044-clk-bufg-pips/Makefile | 2 +- fuzzers/044-clk-bufg-pips/generate.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fuzzers/044-clk-bufg-pips/Makefile b/fuzzers/044-clk-bufg-pips/Makefile index 0821b3f1..3d0f42de 100644 --- a/fuzzers/044-clk-bufg-pips/Makefile +++ b/fuzzers/044-clk-bufg-pips/Makefile @@ -3,7 +3,7 @@ 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) +MAKETODO_FLAGS=--sides "bot_r,top_r" --pip-type ${PIP_TYPE} --seg-type clk_bufg --re $(TODO_RE) --exclude-re ".*\.CLK_BUFG_(BOT|TOP)_R_CK_MUXED[0-9]+" N = 50 # These PIPs all appear to be either a 1 bit solutions. diff --git a/fuzzers/044-clk-bufg-pips/generate.py b/fuzzers/044-clk-bufg-pips/generate.py index 58b895a2..0be965f5 100644 --- a/fuzzers/044-clk-bufg-pips/generate.py +++ b/fuzzers/044-clk-bufg-pips/generate.py @@ -3,6 +3,7 @@ from prjxray.segmaker import Segmaker import os import os.path +import re def bitfilter(frame, word): @@ -72,7 +73,11 @@ def main(): tiledata[tile]["srcs"].add(dst) tiledata[tile]["dsts"].add(src) - if pnum == 1 or pdir == 0: + muxed_src = re.match( + '^CLK_BUFG_(TOP|BOT)_R_CK_MUXED', src) is not None + + if pnum == 1 or pdir == 0 or \ + muxed_src: ignpip.add((src, dst)) for tile, pips_srcs_dsts in tiledata.items(): From 00c4672c12f971124f76b93987a0fed1274881f3 Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Fri, 7 Jun 2019 10:28:12 +0200 Subject: [PATCH 2/2] fuzzers: Add 046-clk-bufg-mixed-pips fuzzer Signed-off-by: Tomasz Michalak --- fuzzers/046-clk-bufg-muxed-pips/Makefile | 61 ++++ fuzzers/046-clk-bufg-muxed-pips/README.md | 3 + fuzzers/046-clk-bufg-muxed-pips/bits.dbf | 33 ++ fuzzers/046-clk-bufg-muxed-pips/build_zdb.py | 71 ++++ .../clk_bufg_pip_list.tcl | 20 ++ fuzzers/046-clk-bufg-muxed-pips/generate.py | 99 +++++ fuzzers/046-clk-bufg-muxed-pips/generate.tcl | 46 +++ .../046-clk-bufg-muxed-pips/output_cmt.tcl | 11 + fuzzers/046-clk-bufg-muxed-pips/top.py | 337 ++++++++++++++++++ fuzzers/Makefile | 3 +- 10 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 fuzzers/046-clk-bufg-muxed-pips/Makefile create mode 100644 fuzzers/046-clk-bufg-muxed-pips/README.md create mode 100644 fuzzers/046-clk-bufg-muxed-pips/bits.dbf create mode 100644 fuzzers/046-clk-bufg-muxed-pips/build_zdb.py create mode 100644 fuzzers/046-clk-bufg-muxed-pips/clk_bufg_pip_list.tcl create mode 100644 fuzzers/046-clk-bufg-muxed-pips/generate.py create mode 100644 fuzzers/046-clk-bufg-muxed-pips/generate.tcl create mode 100644 fuzzers/046-clk-bufg-muxed-pips/output_cmt.tcl create mode 100644 fuzzers/046-clk-bufg-muxed-pips/top.py diff --git a/fuzzers/046-clk-bufg-muxed-pips/Makefile b/fuzzers/046-clk-bufg-muxed-pips/Makefile new file mode 100644 index 00000000..41ba1580 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/Makefile @@ -0,0 +1,61 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=clk_bufg +PIPLIST_TCL=$(FUZDIR)/clk_bufg_pip_list.tcl +TODO_RE=".*\.CLK_BUFG_(BOT|TOP)_R_CK_MUXED[0-9]+" + +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 1 +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/046-clk-bufg-muxed-pips/README.md b/fuzzers/046-clk-bufg-muxed-pips/README.md new file mode 100644 index 00000000..e07b7d31 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/README.md @@ -0,0 +1,3 @@ +# BUFG interconnect fuzzer + +Solves pips located within the BUFG switch box. diff --git a/fuzzers/046-clk-bufg-muxed-pips/bits.dbf b/fuzzers/046-clk-bufg-muxed-pips/bits.dbf new file mode 100644 index 00000000..3ba9bed1 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/bits.dbf @@ -0,0 +1,33 @@ +# 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 +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/046-clk-bufg-muxed-pips/build_zdb.py b/fuzzers/046-clk-bufg-muxed-pips/build_zdb.py new file mode 100644 index 00000000..8f8d8fe6 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/build_zdb.py @@ -0,0 +1,71 @@ +""" 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 +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') + + 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 + + print('# Generated from build_zdb.py') + + 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/046-clk-bufg-muxed-pips/clk_bufg_pip_list.tcl b/fuzzers/046-clk-bufg-muxed-pips/clk_bufg_pip_list.tcl new file mode 100644 index 00000000..c870f353 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-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/046-clk-bufg-muxed-pips/generate.py b/fuzzers/046-clk-bufg-muxed-pips/generate.py new file mode 100644 index 00000000..7f431b3f --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/generate.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import os +import os.path +import re + + +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) + + muxed_src = re.match( + '^CLK_BUFG_(TOP|BOT)_R_CK_MUXED', src) is not None + if pnum == 1 or pdir == 0 or \ + not muxed_src: + 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/046-clk-bufg-muxed-pips/generate.tcl b/fuzzers/046-clk-bufg-muxed-pips/generate.tcl new file mode 100644 index 00000000..f3bbef42 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-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/046-clk-bufg-muxed-pips/output_cmt.tcl b/fuzzers/046-clk-bufg-muxed-pips/output_cmt.tcl new file mode 100644 index 00000000..540c8143 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-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/046-clk-bufg-muxed-pips/top.py b/fuzzers/046-clk-bufg-muxed-pips/top.py new file mode 100644 index 00000000..5f1a38c1 --- /dev/null +++ b/fuzzers/046-clk-bufg-muxed-pips/top.py @@ -0,0 +1,337 @@ +""" 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() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index 5d683049..c2886520 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -89,8 +89,9 @@ $(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,044-clk-bufg-pips,046-clk-bufg-muxed-pips)) $(eval $(call fuzzer,045-hclk-cmt-pips,005-tilegrid)) +$(eval $(call fuzzer,046-clk-bufg-muxed-pips,005-tilegrid)) $(eval $(call fuzzer,048-int-piplist,005-tilegrid)) $(eval $(call fuzzer,049-int-imux-gfan,048-int-piplist)) $(eval $(call fuzzer,050-pip-seed,048-int-piplist))