From 6fd2cb4eec41ae3526598b4985940afa36eb0c7f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Sat, 9 Feb 2019 22:37:39 -0800 Subject: [PATCH] Initial working GCLK to HROW_CLK PIP fuzzer. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/041-clk-hrow-pips/Makefile | 26 +++ fuzzers/041-clk-hrow-pips/bits.dbf | 0 .../041-clk-hrow-pips/clk_hrow_pip_list.tcl | 21 ++ fuzzers/041-clk-hrow-pips/generate.py | 51 +++++ fuzzers/041-clk-hrow-pips/generate.tcl | 43 ++++ fuzzers/041-clk-hrow-pips/output_cmt.tcl | 11 + fuzzers/041-clk-hrow-pips/top.py | 190 ++++++++++++++++++ 7 files changed, 342 insertions(+) create mode 100644 fuzzers/041-clk-hrow-pips/Makefile create mode 100644 fuzzers/041-clk-hrow-pips/bits.dbf create mode 100644 fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl create mode 100644 fuzzers/041-clk-hrow-pips/generate.py create mode 100644 fuzzers/041-clk-hrow-pips/generate.tcl create mode 100644 fuzzers/041-clk-hrow-pips/output_cmt.tcl create mode 100644 fuzzers/041-clk-hrow-pips/top.py diff --git a/fuzzers/041-clk-hrow-pips/Makefile b/fuzzers/041-clk-hrow-pips/Makefile new file mode 100644 index 00000000..f532495c --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/Makefile @@ -0,0 +1,26 @@ +N ?= 50 + +include ../fuzzer.mk + +database: build/segbits_clk_hrow.db + +build/segbits_clk_hrow.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -o build/segbits_clk_hrow.rdb \ + $(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \ + $(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS)) + +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.db + ${XRAY_MASKMERGE} build/mask_clk_hrow.db \ + $(addsuffix /segdata_clk_hrow_top_r.txt,$(SPECIMENS)) \ + $(addsuffix /segdata_clk_hrow_bot_r.txt,$(SPECIMENS)) + +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 + +.PHONY: database pushdb diff --git a/fuzzers/041-clk-hrow-pips/bits.dbf b/fuzzers/041-clk-hrow-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl new file mode 100644 index 00000000..b21bec3a --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -0,0 +1,21 @@ +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_HROW_TOP_R clk_hrow_top_r.txt +print_tile_pips CLK_HROW_BOT_R clk_hrow_bot_r.txt +print_tile_pips CLK_BUFG_REBUF clk_bufg_rebuf.txt diff --git a/fuzzers/041-clk-hrow-pips/generate.py b/fuzzers/041-clk-hrow-pips/generate.py new file mode 100644 index 00000000..ff1fcb61 --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/generate.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import re + + +def main(): + segmk = Segmaker("design.bits") + + 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_HROW'): + continue + + pip_prefix, pip = pip.split(".") + tile_from_pip, tile_type = pip_prefix.split('/') + assert tile == tile_from_pip + _, src = src.split("/") + _, dst = dst.split("/") + + rows = set(range(8)) + columns = set(range(4)) + + m = re.match('^CLK_HROW_R_CK_GCLK([0-9]+)$', src) + if m: + gclk = int(m.group(1)) + row = gclk % 8 + column = int(gclk / 8) + + segmk.add_tile_tag(tile, '{}.GCLK_ENABLE_ROW{}'.format(dst, row), 1) + segmk.add_tile_tag(tile, '{}.GCLK_ENABLE_COLUMN{}'.format(dst, column), 1) + + rows.remove(row) + columns.remove(column) + + for row in rows: + segmk.add_tile_tag(tile, '{}.GCLK_ENABLE_ROW{}'.format(dst, row), 0) + + for column in columns: + segmk.add_tile_tag(tile, '{}.GCLK_ENABLE_COLUMN{}'.format(dst, column), 0) + + + segmk.compile() + segmk.write() + + +if __name__ == '__main__': + main() diff --git a/fuzzers/041-clk-hrow-pips/generate.tcl b/fuzzers/041-clk-hrow-pips/generate.tcl new file mode 100644 index 00000000..9932ddc7 --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/generate.tcl @@ -0,0 +1,43 @@ +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-161}] + 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/041-clk-hrow-pips/output_cmt.tcl b/fuzzers/041-clk-hrow-pips/output_cmt.tcl new file mode 100644 index 00000000..d1af528c --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/output_cmt.tcl @@ -0,0 +1,11 @@ +create_project -force -part $::env(XRAY_PART) design design +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +set fp [open "cmt_regions.csv" "w"] +foreach site_type {MMCME2_ADV PLLE2_ADV BUFHCE} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py new file mode 100644 index 00000000..44a153ff --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -0,0 +1,190 @@ +import os +import re +import random +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray.db import Database + +XY_RE = re.compile('^BUFHCE_X([0-9]+)Y([0-9]+)$') +BUFGCTRL_XY_RE = re.compile('^BUFGCTRL_X([0-9]+)Y([0-9]+)$') + +""" +BUFHCE's can be driven from: + +MMCME2_ADV +BUFHCE +PLLE2_ADV +BUFGCTRL +""" + +def get_xy(s): + m = BUFGCTRL_XY_RE.match(s) + x = int(m.group(1)) + y = int(m.group(2)) + return x, y + +def gen_sites(desired_site_type): + 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) + for site, site_type in gridinfo.sites.items(): + if site_type == desired_site_type: + yield site + + +def gen_bufhce_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 == 'BUFHCE': + sites.append(site) + + if sites: + yield tile_name, sorted(sites) + + +def read_site_to_cmt(): + 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) + +CMT_RE = re.compile('X([0-9]+)Y([0-9]+)') + +class ClockSources(object): + def __init__(self): + self.sources = {} + self.merged_sources = {} + + def add_clock_source(self, source, cmt): + if cmt not in self.sources: + self.sources[cmt] = [] + + self.sources[cmt].append(source) + + def get_random_source(self, cmt): + if cmt not in self.merged_sources: + choices = [] + choices.extend(self.sources['ANY']) + + if cmt in self.sources: + choices.extend(self.sources[cmt]) + + m = CMT_RE.match(cmt) + x = int(m.group(1)) + y = int(m.group(2)) + + 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 + + return random.choice(self.merged_sources[cmt]) + + +def other_sources(): + site_to_cmt = dict(read_site_to_cmt()) + + clock_sources = ClockSources() + clock_sources.add_clock_source('one', 'ANY') + clock_sources.add_clock_source('zero', 'ANY') + + print(""" + wire zero = 0; + wire one = 1;""") + + for idx in range(1): + wire_name = "lut_wire_{}".format(idx) + clock_sources.add_clock_source(wire_name, 'ANY') + print(""" + (* KEEP, DONT_TOUCH *) + wire {wire_name}; + LUT6 lut{idx} ( + .O({wire_name}) + );""".format( + idx=idx, + wire_name=wire_name, + )) + + for site in gen_sites('PLLE2_ADV'): + pll_clocks = ['pll_clock_{site}_{idx}'.format(site=site, idx=idx) for + idx in range(6)] + + for clk in pll_clocks[:2]: + clock_sources.add_clock_source(clk, site_to_cmt[site]) + + print(""" + wire {c0}, {c1}, {c2}, {c3}, {c4}, {c5}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + PLLE2_ADV pll_{site} ( + .CLKOUT0({c0}), + .CLKOUT1({c1}), + .CLKOUT2({c2}), + .CLKOUT3({c3}), + .CLKOUT4({c4}), + .CLKOUT5({c5}) + ); + """.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], + )) + + +def main(): + print(''' +module top(); + ''') + + gclks = [] + for site in sorted(gen_sites("BUFGCTRL"), key=get_xy): + wire_name = 'clk_{}'.format(site) + gclks.append(wire_name) + + print(""" + wire {wire_name}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFG bufg_{site} ( + .O({wire_name}) + ); + """.format( + site=site, + wire_name=wire_name, + )) + + bufhce_sites = list(gen_bufhce_sites()) + for tile_name, sites in bufhce_sites: + for site in sites: + print(""" + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFHCE buf_{site} ( + .I({wire_name}) + ); + """.format( + site=site, + wire_name=random.choice(gclks), + )) + + print("endmodule") + +if __name__ == '__main__': + main()