Merge branch 'master' into add_pll_interconnect_fuzzer

This commit is contained in:
Keith Rothman 2019-07-08 11:22:49 -07:00
commit f92fb52576
32 changed files with 1119 additions and 38 deletions

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
N ?= 5
GENERATE_ARGS?="--oneval 1 --design params.csv --dword 5 --dframe 21"
include ../fuzzaddr/common.mk

View File

@ -0,0 +1,3 @@
source "$::env(XRAY_DIR)/utils/utils.tcl"
generate_top

View File

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

2
fuzzers/007-timing/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.json
sdfs

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
*json

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
module top(input di, output do);
assign do = di;
endmodule

View File

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

View File

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

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

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

View File

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

View File

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

@ -1 +1 @@
Subproject commit 95010bcea451ad8a5bf7308a80001d16012ae116
Subproject commit 679152c9e6b92627cffba186618ab98ac29b627b

View File

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