diff --git a/fuzzers/000-init-db/Makefile b/fuzzers/000-init-db/Makefile index d1eec21c..60975cb2 100644 --- a/fuzzers/000-init-db/Makefile +++ b/fuzzers/000-init-db/Makefile @@ -39,12 +39,14 @@ DB_SIMPLE=\ $(addsuffix _r, $(DB_SIMPLE_LR) $(DB_SIMPLE_R)) \ segbits_cmt_top_l_upper_t \ segbits_cmt_top_r_upper_t \ - segbits_lioi3 \ segbits_rioi3 \ - segbits_liob33 \ segbits_riob33 \ segbits_hclk_ioi3 \ +ifneq (${XRAY_DATABASE}, zynq7) +DB_SIMPLE += segbits_lioi3 segbits_liob33 +endif + BLOCK_RAM_EXTRA_FOR=\ mask_bram \ segbits_bram diff --git a/fuzzers/041-clk-hrow-pips/Makefile b/fuzzers/041-clk-hrow-pips/Makefile index 5a370e1b..8612c58a 100644 --- a/fuzzers/041-clk-hrow-pips/Makefile +++ b/fuzzers/041-clk-hrow-pips/Makefile @@ -9,7 +9,7 @@ N = 50 # These PIPs all appear to be either a 2 bit solutions. SEGMATCH_FLAGS=-c 2 -SPECIMENS_DEPS=build/cmt_regions.csv +SPECIMENS_DEPS=build/dump.ok A_PIPLIST=clk_hrow_bot_r.txt include ../pip_loop.mk @@ -37,9 +37,18 @@ database: build/segbits_clk_hrow_bot_r.rdb build/segbits_clk_hrow_top_r.rdb XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_bot_r build/segbits_clk_hrow_bot_r.db XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} clk_hrow_top_r build/segbits_clk_hrow_top_r.db -build/cmt_regions.csv: output_cmt.tcl +ifeq (${XRAY_DATABASE}, zynq7) +build/dump.ok: output_cmt.tcl output_pss_clocks.tcl mkdir -p build cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_pss_clocks.tcl + touch build/dump.ok +else +build/dump.ok: output_cmt.tcl + mkdir -p build + cd build/ && ${XRAY_VIVADO} -mode batch -source ${FUZDIR}/output_cmt.tcl + touch build/dump.ok +endif generate: $(SPECIMENS_OK) diff --git a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl index 597872ad..791a369d 100644 --- a/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl +++ b/fuzzers/041-clk-hrow-pips/clk_hrow_pip_list.tcl @@ -28,11 +28,6 @@ proc print_tile_pips {tile_type filename} { continue } - # TODO: Support CLK sources from PS7 hardblock - if [string match *PSS_HCLK* $src_node] { - continue - } - if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] != 1} { set pip_string "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]" if ![dict exists $pips $pip_string] { diff --git a/fuzzers/041-clk-hrow-pips/generate.tcl b/fuzzers/041-clk-hrow-pips/generate.tcl index 5f9277e1..3b040dfa 100644 --- a/fuzzers/041-clk-hrow-pips/generate.tcl +++ b/fuzzers/041-clk-hrow-pips/generate.tcl @@ -246,9 +246,9 @@ proc run {} { set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] place_design - route_design + route_design -directive Quick route_todo - route_design + route_design -directive Quick write_checkpoint -force design.dcp write_bitstream -force design.bit diff --git a/fuzzers/041-clk-hrow-pips/output_pss_clocks.tcl b/fuzzers/041-clk-hrow-pips/output_pss_clocks.tcl new file mode 100644 index 00000000..8aacf2d9 --- /dev/null +++ b/fuzzers/041-clk-hrow-pips/output_pss_clocks.tcl @@ -0,0 +1,41 @@ +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 "pss_clocks.csv" "w"] +puts $fp "pin,wire,tile,clock_regions" + +# List all PSS_HCLK wires +set pss_clk_wires [get_wires *PSS_HCLK* -of_objects [get_tiles PSS*]] +foreach wire $pss_clk_wires { + + # Get PIPs that mention the wire inside a CLK_HROW tile. Take the first one. + set pips [get_pips CLK_HROW_* -of_objects [get_nodes -of_objects $wire]] + set pip [lindex $pips 0] + + # Get the CLK_HROW tile. + set tile [get_tiles -of_objects $pip] + + # Get the name of the input wire of the CLK_HROW tile. This is different + # than the name of the PSS clock wire. Do it by parsing the PIP name + set cmt_wire [lindex [split [lindex [split $pip "-"] 0] "."] 1] + + # Get clock regions of the tile. CLK_HROW tiles span two regions. + set regions [dict create] + foreach site [get_sites -of_objects $tile] { + set region [get_property CLOCK_REGION $site] + dict incr regions $region + } + + set regions [dict keys $regions] + + # Get uphill PIP, parse its name to get the PS7 wire name. This will be + # actually the wire of the PSS tile but the important part of the name + # is the same. + set pip [get_pips -uphill -of_objects $wire] + set pin [lindex [split [lindex [split $pip "."] 1] "-"] 0] + + puts $fp "$pin,$cmt_wire,$tile,$regions" +} + +close $fp diff --git a/fuzzers/041-clk-hrow-pips/top.py b/fuzzers/041-clk-hrow-pips/top.py index 472eacd8..3993fd03 100644 --- a/fuzzers/041-clk-hrow-pips/top.py +++ b/fuzzers/041-clk-hrow-pips/top.py @@ -5,15 +5,22 @@ import re random.seed(int(os.getenv("SEED"), 16)) from prjxray import util from prjxray import verilog +from prjxray.grid_types import GridLoc from prjxray.db import Database from prjxray.lut_maker import LutMaker from io import StringIO +import csv +import sys CMT_XY_FUN = util.create_xy_fun(prefix='') BUFGCTRL_XY_FUN = util.create_xy_fun('BUFGCTRL_') BUFHCE_XY_FUN = util.create_xy_fun('BUFHCE_') +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + def gen_sites(desired_site_type): db = Database(util.get_db_root()) grid = db.grid() @@ -42,6 +49,12 @@ def gen_bufhce_sites(): yield tile_name, sorted(sites) +def get_cmt_loc(cmt_tile_name): + db = Database(util.get_db_root()) + grid = db.grid() + return grid.loc_of_tilename(cmt_tile_name) + + def read_site_to_cmt(): """ Yields clock sources and which CMT they route within. """ with open(os.path.join(os.getenv('FUZDIR'), 'build', @@ -51,6 +64,13 @@ def read_site_to_cmt(): yield (site, cmt) +def read_pss_clocks(): + with open(os.path.join(os.getenv('FUZDIR'), 'build', + 'pss_clocks.csv')) as f: + for l in csv.DictReader(f): + yield l + + class ClockSources(object): """ Class for tracking clock sources. @@ -305,16 +325,21 @@ def main(): PLLE2_ADV BUFGCTRL Local INT connect - + PS7 (Zynq) """ print(''' +// SEED={} module top(); - ''') + '''.format(os.getenv('SEED'))) + + is_zynq = os.getenv('XRAY_DATABASE') == 'zynq7' + clock_sources = ClockSources() site_to_cmt = dict(read_site_to_cmt()) - clock_sources = ClockSources() + if is_zynq: + pss_clocks = list(read_pss_clocks()) # To ensure that all left or right sources are used, sometimes only MMCM/PLL # sources are allowed. The force of ODD/EVEN/BOTH further biases the @@ -426,6 +451,57 @@ module top(); .O(O_{site}) );""".format(site=site)) + if is_zynq: + + # FCLK clocks. Those are generated by the PS and go directly to one of + # the CLK_HROW tile. + clocks = [ + "PSS_FCLKCLK0", + "PSS_FCLKCLK1", + "PSS_FCLKCLK2", + "PSS_FCLKCLK3", + ] + + loc, _, site = next(gen_sites('PS7')) + + print("") + + # Add clock sources and generate wires + for wire in clocks: + clock_info = [d for d in pss_clocks if d["pin"] == wire][0] + + # CMT tile + cmt_tile = clock_info["tile"] + cmt_loc = get_cmt_loc(cmt_tile) + + # Add only if the input wire is in the todo list + dsts = [k for k, v in todos.items() if clock_info["wire"] in v] + if len(dsts) > 0: + + # Wire source clock region. The PS7 is always left of the + # CLK_HROW tile, but it does not matter here. + regions = clock_info["clock_regions"].split() + regions = sorted([(int(r[1]), int(r[3])) for r in regions]) + + # Add the clock source + cmt = "X{}Y{}".format(regions[0][0], regions[0][1]) + clock_sources.add_clock_source(wire, cmt, cmt_loc) + + print(" wire {};".format(wire)) + + print( + """ + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + PS7 ps7_{site} ( + .FCLKCLK({{{fclk3}, {fclk2}, {fclk1}, {fclk0}}}) + ); + """.format( + site=site, + fclk0=clocks[0], + fclk1=clocks[1], + fclk2=clocks[2], + fclk3=clocks[3])) + luts = LutMaker() bufhs = StringIO() bufgs = StringIO()