diff --git a/fuzzers/005-tilegrid/generate_full.py b/fuzzers/005-tilegrid/generate_full.py index dbb02a2b..1203d6d3 100644 --- a/fuzzers/005-tilegrid/generate_full.py +++ b/fuzzers/005-tilegrid/generate_full.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import copy import json from utils import xjson ''' @@ -209,6 +210,34 @@ def propagate_INT_bits_in_column(database, tiles_by_grid): tile_name = next_tile tile = database[tile_name] +def propagate_rebuf(database, tiles_by_grid): + """ Writing a fuzzer for the CLK_BUFG_REBUF tiles is hard, so propigate from CLK_HROW tiles. + + In the clock column, there is a CLK_BUFG_REBUF above and below the CLK_HROW + tile. Each clock column appears to use the same offsets, so propigdate + the base address and frame count, and update the offset and word count. + + """ + for tile_name in sorted(database.keys()): + tile = database[tile_name] + + if tile['type'] not in ['CLK_HROW_BOT_R', 'CLK_HROW_TOP_R']: + continue + + rebuf_below = tiles_by_grid[(tile['grid_x'], tile['grid_y'] - 12)] + assert database[rebuf_below]['type'] == 'CLK_BUFG_REBUF', database[rebuf_below]['type'] + rebuf_above = tiles_by_grid[(tile['grid_x'], tile['grid_y'] + 13)] + assert database[rebuf_above]['type'] == 'CLK_BUFG_REBUF', database[rebuf_below]['type'] + + assert database[tile_name]['bits']['CLB_IO_CLK']['offset'] == 47, 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'] = 71 + database[rebuf_below]['bits']['CLB_IO_CLK']['words'] = 10 + + database[rebuf_above]['bits'] = copy.deepcopy(database[tile_name]['bits']) + database[rebuf_above]['bits']['CLB_IO_CLK']['offset'] = 22 + database[rebuf_above]['bits']['CLB_IO_CLK']['words'] = 10 + def run(json_in_fn, json_out_fn, verbose=False): # Load input files @@ -217,6 +246,7 @@ def run(json_in_fn, json_out_fn, verbose=False): propagate_INT_lr_bits(database, tiles_by_grid, verbose=verbose) propagate_INT_bits_in_column(database, tiles_by_grid) + propagate_rebuf(database, tiles_by_grid) # Save xjson.pprint(open(json_out_fn, "w"), database) diff --git a/fuzzers/043-clk-rebuf-pips/Makefile b/fuzzers/043-clk-rebuf-pips/Makefile new file mode 100644 index 00000000..ff3d9fa7 --- /dev/null +++ b/fuzzers/043-clk-rebuf-pips/Makefile @@ -0,0 +1,22 @@ +N ?= 50 + +include ../fuzzer.mk + +database: build/segbits_clk_bufg_rebuf.db + +build/segbits_clk_bufg_rebuf.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} -o build/segbits_clk_bufg_rebuf.rdb \ + $(addsuffix /segdata_clk_bufg_rebuf.txt,$(SPECIMENS)) + +build/segbits_clk_bufg_rebuf.db: build/segbits_clk_bufg_rebuf.rdb + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_clk_bufg_rebuf.rdb \ + --seg-fn-out build/segbits_clk_bufg_rebuf.db + ${XRAY_MASKMERGE} build/mask_clk_bufg_rebuf.db \ + $(addsuffix /segdata_clk_bufg_rebuf.txt,$(SPECIMENS)) + +pushdb: database + ${XRAY_MERGEDB} clk_bufg_rebuf build/segbits_clk_bufg_rebuf.db + ${XRAY_MERGEDB} mask_clk_bufg_rebuf build/mask_clk_bufg_rebuf.db + +.PHONY: database pushdb diff --git a/fuzzers/043-clk-rebuf-pips/bits.dbf b/fuzzers/043-clk-rebuf-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/043-clk-rebuf-pips/generate.py b/fuzzers/043-clk-rebuf-pips/generate.py new file mode 100644 index 00000000..4204aaa8 --- /dev/null +++ b/fuzzers/043-clk-rebuf-pips/generate.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import re + +REBUF_GCLK = re.compile('^CLK_BUFG_REBUF_R_CK_GCLK([0-9]+)_BOT$') +def main(): + segmk = Segmaker("design.bits") + + print("Loading tags from design.txt.") + + gclks_in_use = {} + with open("design.txt", "r") as f: + for line in f: + if 'CLK_BUFG_REBUF' not in line: + continue + + parts = line.replace('{', '').replace('}','').strip().replace('\t', ' ').split(' ') + dst = parts[0] + pip = parts[3] + + tile_from_pip, pip = pip.split('/') + + if 'CLK_BUFG_REBUF' not in tile_from_pip: + continue + + tile_type, pip = pip.split('.') + assert tile_type == 'CLK_BUFG_REBUF' + + wire_a, wire_b = pip.split('<<->>') + + tile_from_wire, dst = dst.split('/') + + assert dst == wire_a + + m = REBUF_GCLK.match(dst) + assert m, dst + gclk = int(m.group(1)) + + if tile_from_pip not in gclks_in_use: + gclks_in_use[tile_from_pip] = set() + gclks_in_use[tile_from_pip].add(gclk) + + if tile_from_wire == tile_from_pip: + segmk.add_tile_tag(tile_from_pip, '{}.{}'.format(wire_a, wire_b), wire_a == dst) + segmk.add_tile_tag(tile_from_pip, '{}.{}'.format(wire_b, wire_a), wire_a != dst) + else: + segmk.add_tile_tag(tile_from_pip, '{}.{}'.format(wire_a, wire_b), wire_a != dst) + segmk.add_tile_tag(tile_from_pip, '{}.{}'.format(wire_b, wire_a), wire_a == dst) + + for tile, gclks in gclks_in_use.items(): + for gclk in range(2): + segmk.add_tile_tag(tile, 'GCLK{}_ENABLED'.format(gclk), gclk in gclks) + + segmk.compile() + segmk.write(allow_empty=True) + + +if __name__ == '__main__': + main() diff --git a/fuzzers/043-clk-rebuf-pips/generate.tcl b/fuzzers/043-clk-rebuf-pips/generate.tcl new file mode 100644 index 00000000..c83cf947 --- /dev/null +++ b/fuzzers/043-clk-rebuf-pips/generate.tcl @@ -0,0 +1,30 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc write_route_data {filename} { + set fp [open $filename w] + foreach net [get_nets -hierarchical] { + puts $fp "Net $net route:" + puts $fp [report_route_status -of_objects $net -return_string] + puts $fp "" + } + 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] + + place_design + route_design + + write_checkpoint -force design.dcp + write_bitstream -force design.bit + write_route_data design.txt +} + +run diff --git a/fuzzers/043-clk-rebuf-pips/top.py b/fuzzers/043-clk-rebuf-pips/top.py new file mode 100644 index 00000000..b56fa135 --- /dev/null +++ b/fuzzers/043-clk-rebuf-pips/top.py @@ -0,0 +1,105 @@ +import os +import itertools +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, set(sites) + +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()) + + opts = [] + for count in range(len(bufhce_sites)): + for opt in itertools.combinations(bufhce_sites, count+1): + opts.append(opt) + + for gclk in gclks[:2]: + #if random.random() < .2: + # continue + + for tile_name, sites in random.choice(opts): + for site in sorted(sites): + print(""" + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFHCE buf_{site} ( + .I({wire_name}) + );""".format( + site=site, + wire_name=gclk, + )) + sites.remove(site) + break + + print("endmodule") + + +if __name__ == '__main__': + main()