fuzzers: Add 046-clk-bufg-mixed-pips fuzzer

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
This commit is contained in:
Tomasz Michalak 2019-06-07 10:28:12 +02:00
parent 19ed8c5af8
commit 00c4672c12
10 changed files with 683 additions and 1 deletions

View File

@ -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

View File

@ -0,0 +1,3 @@
# BUFG interconnect fuzzer
Solves pips located within the BUFG switch box.

View File

@ -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

View File

@ -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=<N> -j<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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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))