diff --git a/fuzzers/005-tilegrid/Makefile b/fuzzers/005-tilegrid/Makefile index 79ebb70f..6dace887 100644 --- a/fuzzers/005-tilegrid/Makefile +++ b/fuzzers/005-tilegrid/Makefile @@ -19,6 +19,7 @@ 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 TILEGRID_TDB_DEPENDENCIES += pll/build/segbits_tilegrid.tdb +TILEGRID_TDB_DEPENDENCIES += hclk_ioi/build/segbits_tilegrid.tdb GENERATE_FULL_ARGS= ifeq (${XRAY_DATABASE}, zynq7) @@ -116,6 +117,9 @@ clk_bufg/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json hclk_cmt/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json cd hclk_cmt && $(MAKE) +hclk_ioi/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json + cd hclk_ioi && $(MAKE) + build/tilegrid_tdb.json: add_tdb.py $(TILEGRID_TDB_DEPENDENCIES) python3 add_tdb.py \ --fn-in build/basicdb/tilegrid.json \ @@ -154,6 +158,7 @@ clean: cd clk_hrow && $(MAKE) clean cd clk_bufg && $(MAKE) clean cd hclk_cmt && $(MAKE) clean + cd hclk_ioi && $(MAKE) clean .PHONY: database pushdb clean run diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py index 97566508..432ed475 100644 --- a/fuzzers/005-tilegrid/add_tdb.py +++ b/fuzzers/005-tilegrid/add_tdb.py @@ -89,6 +89,7 @@ def run(fn_in, fn_out, verbose=False): ("clk_hrow/build/segbits_tilegrid.tdb", 30, 18), ("clk_bufg/build/segbits_tilegrid.tdb", 30, 8), ("hclk_cmt/build/segbits_tilegrid.tdb", 30, 10), + ("hclk_ioi/build/segbits_tilegrid.tdb", 42, 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/generate_full.py b/fuzzers/005-tilegrid/generate_full.py index ee8d1d78..1afa3bec 100644 --- a/fuzzers/005-tilegrid/generate_full.py +++ b/fuzzers/005-tilegrid/generate_full.py @@ -356,12 +356,17 @@ def propagate_IOI_SING(database, tiles_by_grid): break if 'CLB_IO_CLK' in database[tile]['bits']: - assert bits['baseaddr'] == database[tile]['bits'][ - 'CLB_IO_CLK']['baseaddr'] - assert bits['frames'] == database[tile]['bits']['CLB_IO_CLK'][ - 'frames'] - assert bits['words'] == database[tile]['bits']['CLB_IO_CLK'][ - 'words'] + if tile.startswith("LIOI") or tile.startswith("RIOI"): + assert bits['baseaddr'] == database[tile]['bits'][ + 'CLB_IO_CLK']['baseaddr'] + assert bits['frames'] == database[tile]['bits'][ + 'CLB_IO_CLK']['frames'], "{}:{} == {}".format( + tile, bits['frames'], + database[tile]['bits']['CLB_IO_CLK']['frames']) + assert bits['words'] == database[tile]['bits'][ + 'CLB_IO_CLK']['words'], "{}: {} != {}".format( + tile, bits['words'], + database[tile]['bits']['CLB_IO_CLK']['words']) top_tile = tile diff --git a/fuzzers/005-tilegrid/hclk_ioi/Makefile b/fuzzers/005-tilegrid/hclk_ioi/Makefile new file mode 100644 index 00000000..f37874d8 --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_ioi/Makefile @@ -0,0 +1,4 @@ +N ?= 5 +GENERATE_ARGS?="--oneval 1 --design params.csv --dword 5 --dframe 21" +include ../fuzzaddr/common.mk + diff --git a/fuzzers/005-tilegrid/hclk_ioi/generate.tcl b/fuzzers/005-tilegrid/hclk_ioi/generate.tcl new file mode 100644 index 00000000..5a69791f --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_ioi/generate.tcl @@ -0,0 +1,3 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +generate_top diff --git a/fuzzers/005-tilegrid/hclk_ioi/top.py b/fuzzers/005-tilegrid/hclk_ioi/top.py new file mode 100644 index 00000000..9d60542c --- /dev/null +++ b/fuzzers/005-tilegrid/hclk_ioi/top.py @@ -0,0 +1,63 @@ +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 == 'BUFR': + 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}; + BUFMRCE buf_{site} ( + .O(clk_{site}) + ); + + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR #( + .BUFR_DIVIDE("{divide}") + ) bufr_{site} ( + .I(clk_{site}) + ); +'''.format(site=site_name, divide="2" if isone else "1")) + + print("endmodule") + write_params(params) + + +if __name__ == '__main__': + run() diff --git a/fuzzers/007-timing/.gitignore b/fuzzers/007-timing/.gitignore new file mode 100644 index 00000000..759ac773 --- /dev/null +++ b/fuzzers/007-timing/.gitignore @@ -0,0 +1,2 @@ +*.json +sdfs diff --git a/fuzzers/007-timing/Makefile b/fuzzers/007-timing/Makefile index 52202107..c164609e 100644 --- a/fuzzers/007-timing/Makefile +++ b/fuzzers/007-timing/Makefile @@ -1,10 +1,30 @@ +SLICEL_SDFS = bel/build/CLBLL_L.sdf bel/build/CLBLL_R.sdf bel/build/CLBLM_L.sdf bel/build/CLBLM_R.sdf routing-bels/build/slicel.sdf +SLICEM_SDFS = bel/build/CLBLL_L.sdf bel/build/CLBLL_R.sdf bel/build/CLBLM_L.sdf bel/build/CLBLM_R.sdf routing-bels/build/slicem.sdf + run: all -all: bel/build/sdf - touch run.ok +all: pushdb clean: cd bel && $(MAKE) clean + cd routing-bels && $(MAKE) clean -bel/build/sdf: +bel/build/sdf.ok: cd bel && $(MAKE) +routing-bels/build/sdf: + cd routing-bels && $(MAKE) + +mergesdfs: bel/build/sdf.ok routing-bels/build/sdf + mkdir -p sdfs + python3 ${XRAY_UTILS_DIR}/sdfmerge.py --sdfs $(SLICEM_SDFS) --site SLICEM --out sdfs/slicem.sdf + python3 ${XRAY_UTILS_DIR}/sdfmerge.py --sdfs $(SLICEL_SDFS) --site SLICEL --out sdfs/slicel.sdf --json debu.json + cp bel/build/*.sdf sdfs + +pushdb: mergesdfs + mkdir -p ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings + cp sdfs/*.sdf ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings + touch run.ok + +cleandb: + rm -rf ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings + diff --git a/fuzzers/007-timing/bel/Makefile b/fuzzers/007-timing/bel/Makefile index eda5433d..7267b8d6 100644 --- a/fuzzers/007-timing/bel/Makefile +++ b/fuzzers/007-timing/bel/Makefile @@ -1,12 +1,12 @@ -all: pushdb +all: build/sdf.ok clean: rm -rf build -build/bel_timings.txt: +build/run.ok: bash runme.sh -build/fixup_timings: build/bel_timings.txt +build/fixup_timings: build/run.ok python3 fixup_timings_txt.py --txtin build/bel_timings.txt --txtout build/bel_timings.txt --site RAMBFIFO36E1 --slice BRAM_L --type timings python3 fixup_timings_txt.py --txtin build/bel_timings.txt --txtout build/bel_timings.txt --site RAMBFIFO36E1 --slice BRAM_R --type timings python3 fixup_timings_txt.py --txtin build/bel_pins.txt --txtout build/bel_pins.txt --site RAMBFIFO36E1 --slice BRAM_L --type pins @@ -17,17 +17,7 @@ build/fixup_timings: build/bel_timings.txt build/bel_timings.json: build/fixup_timings python3 tim2json.py --timings=build/bel_timings.txt --json=build/bel_timings.json --properties=build/bel_properties.txt --propertiesmap=properties_map.json --pinaliasmap=pin_alias_map.json --belpins=build/bel_pins.txt --sitepins=build/tile_pins.txt --debug true -build/sdf: build/bel_timings.json +build/sdf.ok: build/bel_timings.json python3 ${XRAY_UTILS_DIR}/makesdf.py --json=${PWD}/build/bel_timings.json --sdf=${PWD}/build + touch build/sdf.ok -cleandb: - rm -rf ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings - -mergesdfs: build/sdf - python3 ${XRAY_UTILS_DIR}/sdfmerge.py --sdfs build/CLBLL_L.sdf build/CLBLL_R.sdf build/CLBLM_L.sdf build/CLBLM_R.sdf --site SLICEM --out build/slicem.sdf - python3 ${XRAY_UTILS_DIR}/sdfmerge.py --sdfs build/CLBLL_L.sdf build/CLBLL_R.sdf build/CLBLM_L.sdf build/CLBLM_R.sdf --site SLICEL --out build/slicel.sdf - -pushdb: mergesdfs - mkdir -p ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings - cp build/*sdf ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings - touch run.ok diff --git a/fuzzers/007-timing/bel/pin_alias_map.json b/fuzzers/007-timing/bel/pin_alias_map.json index d984d6c4..5406a619 100644 --- a/fuzzers/007-timing/bel/pin_alias_map.json +++ b/fuzzers/007-timing/bel/pin_alias_map.json @@ -12,6 +12,22 @@ } }, "rambfifo36e1" : { + "REGCEAREGCEL" : { + "names" : ["regceal"], + "is_property_related" : false + }, + "REGCEAREGCEU" : { + "names" : ["regceau"], + "is_property_related" : false + }, + "RSTREGARSTREGL" : { + "names" : ["rstregal"], + "is_property_related" : false + }, + "RSTREGARSTREGU" : { + "names" : ["rstregau"], + "is_property_related" : false + }, "RSTRAMARSTRAMLRST" : { "names" : ["rstramarstl"], "is_property_related" : false @@ -55,6 +71,22 @@ "DOPBDOP0" : { "names" : ["dopbdopl", "dopbdopu"], "is_property_related" : false + }, + "DIADI0" : { + "names" : ["diadil", "diadiu"], + "is_property_related" : false + }, + "DIBDI0" : { + "names" : ["dibdil", "dibdiu"], + "is_property_related" : false + }, + "DIPADIP0" : { + "names" : ["dipadipl", "dipadipu"], + "is_property_related" : false + }, + "DIPBDIP0" : { + "names" : ["dipbdipl", "dipbdipu"], + "is_property_related" : false } } } diff --git a/fuzzers/007-timing/routing-bels/.gitignore b/fuzzers/007-timing/routing-bels/.gitignore new file mode 100644 index 00000000..8d080e88 --- /dev/null +++ b/fuzzers/007-timing/routing-bels/.gitignore @@ -0,0 +1 @@ +*json diff --git a/fuzzers/007-timing/routing-bels/Makefile b/fuzzers/007-timing/routing-bels/Makefile new file mode 100644 index 00000000..ed041a1a --- /dev/null +++ b/fuzzers/007-timing/routing-bels/Makefile @@ -0,0 +1,17 @@ +all: build/slicel.sdf build/slicem.sdf + +clean: + rm -rf build + +build/slicel.sdf: build/run.ok + python3 tim2sdf.py --timings build/slicel.txt --site SLICEL --sdf build/slicel.sdf + +build/slicem.sdf: build/run.ok + python3 tim2sdf.py --timings build/slicem.txt --site SLICEM --sdf build/slicem.sdf + +build/run.ok: + bash runme.sh + +cleandb: + rm -rf ${XRAY_DATABASE_DIR}/${XRAY_DATABASE}/timings + diff --git a/fuzzers/007-timing/routing-bels/runme.sh b/fuzzers/007-timing/routing-bels/runme.sh new file mode 100644 index 00000000..00f88914 --- /dev/null +++ b/fuzzers/007-timing/routing-bels/runme.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ex + +# Create build dir +export SRC_DIR=$PWD +export BUILD_DIR=build + +mkdir -p $BUILD_DIR +cd $BUILD_DIR + +${XRAY_VIVADO} -mode batch -source $SRC_DIR/runme.tcl +test -z "$(fgrep CRITICAL vivado.log)" && touch run.ok diff --git a/fuzzers/007-timing/routing-bels/runme.tcl b/fuzzers/007-timing/routing-bels/runme.tcl new file mode 100644 index 00000000..8dd33e21 --- /dev/null +++ b/fuzzers/007-timing/routing-bels/runme.tcl @@ -0,0 +1,62 @@ +source "$::env(XRAY_DIR)/utils/utils.tcl" + +proc create_design {} { + + create_project -force -part $::env(XRAY_PART) design design + read_verilog $::env(SRC_DIR)/top.v + synth_design -top top -flatten_hierarchy none + + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_00) IOSTANDARD LVCMOS33" [get_ports di] + set_property -dict "PACKAGE_PIN $::env(XRAY_PIN_01) IOSTANDARD LVCMOS33" [get_ports do] + + set_property CFGBVS VCCO [current_design] + set_property CONFIG_VOLTAGE 3.3 [current_design] + set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] +} + +proc place_and_route_design {} { + + place_design + route_design + + write_checkpoint -force design.dcp +} + +proc dump_model_timings {timing_fp models} { + + set properties [list "DELAY" "FAST_MAX" "FAST_MIN" "SLOW_MAX" "SLOW_MIN"] + + foreach model $models { + set timing_line {} + lappend timing_line "$model" + foreach property $properties { + set value [get_property $property [get_speed_models -patterns $model]] + lappend timing_line "$property:$value" + } + + puts $timing_fp $timing_line + } +} + +proc dump {} { + + set slicel_fp [open "slicel.txt" w] + set slicem_fp [open "slicem.txt" w] + set slicel_speed_models [get_speed_models -patterns *_sl_*] + set slicem_speed_models [get_speed_models -patterns *_sm_*] + + dump_model_timings $slicel_fp $slicel_speed_models + dump_model_timings $slicem_fp $slicem_speed_models + + close $slicel_fp + close $slicem_fp +} + +proc run {} { + create_design + place_and_route_design + dump + write_bitstream -force design.bit +} + +run diff --git a/fuzzers/007-timing/routing-bels/tim2sdf.py b/fuzzers/007-timing/routing-bels/tim2sdf.py new file mode 100644 index 00000000..dd9e3f19 --- /dev/null +++ b/fuzzers/007-timing/routing-bels/tim2sdf.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +import argparse +import json +from sdf_timing import sdfparse +from sdf_timing import utils + + +def generate_sdf(timings, sdffile): + + sdf_data = sdfparse.emit(timings, timescale='1ns') + with open(sdffile, 'w') as fp: + fp.write(sdf_data) + + +def add_timing_paths_entry(paths, type, values): + paths[type] = dict() + paths[type]['min'] = values[0] + paths[type]['avg'] = values[1] + paths[type]['max'] = values[2] + return paths + + +def read_raw_timings(fin, site): + + timings = dict() + timings['cells'] = dict() + with open(fin, "r") as f: + for line in f: + + raw_data = line.split() + speed_model = raw_data[0] + + if speed_model.startswith('bel_d_'): + speed_model = speed_model[6:] + + speed_model_split = speed_model.split('_') + interconn_input = "_".join(speed_model_split[1:-1]) + interconn_output = speed_model_split[-1] + celltype = "routing_bel" + + if celltype not in timings['cells']: + timings['cells'][celltype] = dict() + + cellsite = site + '/' + interconn_output.upper() + + if cellsite not in timings['cells'][celltype]: + timings['cells'][celltype][cellsite] = dict() + + if speed_model not in timings['cells'][celltype][cellsite]: + timings['cells'][celltype][cellsite][speed_model] = dict() + + delays = dict() + # each timing entry reports 5 delays + for d in range(0, 5): + (t, v) = raw_data[d + 1].split(':') + delays[t] = v + + # create entry for sdf writer + iport = dict() + iport['port'] = interconn_input + iport['port_edge'] = None + oport = dict() + oport['port'] = interconn_output + oport['port_edge'] = None + paths = dict() + paths = add_timing_paths_entry( + paths, 'slow', [delays['SLOW_MIN'], None, delays['SLOW_MAX']]) + paths = add_timing_paths_entry( + paths, 'fast', [delays['FAST_MIN'], None, delays['FAST_MAX']]) + + if speed_model.endswith('diff'): + iport['port'] = "_".join(speed_model_split[1:]) + iport['port_edge'] = None + timings['cells'][celltype][cellsite][ + speed_model] = utils.add_device(iport, paths) + else: + timings['cells'][celltype][cellsite][ + speed_model] = utils.add_interconnect(iport, oport, paths) + timings['cells'][celltype][cellsite][speed_model][ + 'is_absolute'] = True + + return timings + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--timings', type=str, help='Raw timing input file') + parser.add_argument('--sdf', type=str, help='output sdf file') + parser.add_argument( + '--site', type=str, help='Site of the processed timings') + parser.add_argument( + '--debug', type=bool, default=False, help='Enable debug json dumps') + args = parser.parse_args() + + timings = read_raw_timings(args.timings, args.site) + if args.debug: + with open("debug" + args.site + ".json", 'w') as fp: + json.dump(timings, fp, indent=4, sort_keys=True) + + generate_sdf(timings, args.sdf) + + +if __name__ == '__main__': + main() diff --git a/fuzzers/007-timing/routing-bels/top.v b/fuzzers/007-timing/routing-bels/top.v new file mode 100644 index 00000000..a234addd --- /dev/null +++ b/fuzzers/007-timing/routing-bels/top.v @@ -0,0 +1,5 @@ +module top(input di, output do); + + assign do = di; + +endmodule 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(): 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 ec724cd6..411e733d 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -91,8 +91,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)) diff --git a/fuzzers/int_generate.py b/fuzzers/int_generate.py index b19c3ec4..67e1bb4c 100644 --- a/fuzzers/int_generate.py +++ b/fuzzers/int_generate.py @@ -54,10 +54,11 @@ with open(args.design, "r") as f: if tile not in tiledata: tiledata[tile] = {"pips": set(), "srcs": set(), "dsts": set()} - if pip in pipdata: - assert pipdata[pip] == (src, dst) + tile_lr = ("_".join(tile.split("_")[0:2])) + if (tile_lr, pip) in pipdata: + assert pipdata[(tile_lr, pip)] == (src, dst) else: - pipdata[pip] = (src, dst) + pipdata[(tile_lr, pip)] = (src, dst) tiledata[tile]["pips"].add(pip) tiledata[tile]["srcs"].add(src) @@ -67,23 +68,23 @@ with open(args.design, "r") as f: tiledata[tile]["srcs"].add(dst) tiledata[tile]["dsts"].add(src) + t = ("_".join(tile.split("_")[0:2]), dst, src) if pnum == 1 or pdir == 0: verbose and print('ignore pnum == 1 or pdir == 0: ', pip) - ignpip.add(pip) + ignpip.add(t) - t = ("_".join(tile.split("_")[0:2]), dst, src) if t not in todo: verbose and print('ignore not todo: ', t) - ignpip.add(pip) + ignpip.add(t) for tile, pips_srcs_dsts in tiledata.items(): pips = pips_srcs_dsts["pips"] srcs = pips_srcs_dsts["srcs"] dsts = pips_srcs_dsts["dsts"] - - for pip, src_dst in pipdata.items(): + for (tile_lr, pip), src_dst in pipdata.items(): src, dst = src_dst - if pip in ignpip: + t = (tile_lr, dst, src) + if t in ignpip: pass elif pip in pips: segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1) diff --git a/minitests/roi_harness/roi_base_div2.v b/minitests/roi_harness/roi_base_div2.v new file mode 100644 index 00000000..9dc808e8 --- /dev/null +++ b/minitests/roi_harness/roi_base_div2.v @@ -0,0 +1,65 @@ +//See README and tcl for more info + +`include "defines.v" + +module roi(input clk, + input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + wire div_clk; + wire clk_IBUF_BUFG; + BUFR #( + .BUFR_DIVIDE(2) + ) clock_divider ( + .I(clk), + .O(div_clk), + .CE(1), + .CLR(0) + ); + + BUFG clock_buffer ( + .I(div_clk), + .O(clk_IBUF_BUFG) + ); + + genvar i; + generate + //CLK + (* KEEP, DONT_TOUCH *) + reg clk_reg; + always @(posedge clk_IBUF_BUFG) begin + clk_reg <= clk_reg; + end + + //DIN + for (i = 0; i < DIN_N; i = i+1) begin:ins + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(din[i]), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O()); + end + + //DOUT + for (i = 0; i < DOUT_N; i = i+1) begin:outs + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(1'b0), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O(dout[i])); + end + endgenerate +endmodule diff --git a/third_party/python-sdf-timing b/third_party/python-sdf-timing index 95010bce..679152c9 160000 --- a/third_party/python-sdf-timing +++ b/third_party/python-sdf-timing @@ -1 +1 @@ -Subproject commit 95010bcea451ad8a5bf7308a80001d16012ae116 +Subproject commit 679152c9e6b92627cffba186618ab98ac29b627b diff --git a/utils/sdfmerge.py b/utils/sdfmerge.py index b63cca27..2c7081fe 100644 --- a/utils/sdfmerge.py +++ b/utils/sdfmerge.py @@ -55,7 +55,7 @@ def main(): timings_list.append(timing) merged_sdf = merge(timings_list, args.site) - open(args.out, 'w').write(sdfparse.emit(merged_sdf)) + open(args.out, 'w').write(sdfparse.emit(merged_sdf, timescale='1ns')) if args.json is not None: with open(args.json, 'w') as fp: