diff --git a/fuzzers/000-init-db/Makefile b/fuzzers/000-init-db/Makefile index ebef99a1..ee42445a 100644 --- a/fuzzers/000-init-db/Makefile +++ b/fuzzers/000-init-db/Makefile @@ -39,6 +39,10 @@ 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 BLOCK_RAM_EXTRA_FOR=\ mask_bram \ diff --git a/fuzzers/037-iob-pips/Makefile b/fuzzers/037-iob-pips/Makefile new file mode 100644 index 00000000..57f3d46b --- /dev/null +++ b/fuzzers/037-iob-pips/Makefile @@ -0,0 +1,50 @@ +export FUZDIR=$(shell pwd) +PIP_TYPE?=ioi3 +PIPLIST_TCL=$(FUZDIR)/ioi3_pip_list.tcl + +TODO_RE="[LR]IOI3\.(IOI_([IO]LOGIC[01]_CLK(DIV|B)?)|(IOI_OCLK_[01]))\..*" +EXCLUDE_RE=".*\..*\.(?=IOI_((PHASER)|(OCLK)|(IMUX22_1))).*" + +MAKETODO_FLAGS=--pip-type ${PIP_TYPE} --seg-type $(PIP_TYPE) --re $(TODO_RE) --sides "xr,xl" --exclude-re $(EXCLUDE_RE) +N = 40 + +A_PIPLIST=lioi3.txt + +SEGMATCH_FLAGS=-c -1 -m 20 -M 50 +SPECIMENS_DEPS=build/cmt_regions.csv + +include ../pip_loop.mk + +build/segbits_ioi3_x.rdb: $(SPECIMENS_OK) + ${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_ioi3_x.rdb \ + $(shell find build -name segdata_lioi3*.txt) $(shell find build -name segdata_rioi3*.txt) + +RDBS = build/segbits_ioi3_x.rdb + +database: ${RDBS} + ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ + --seg-fn-in build/segbits_ioi3_x.rdb \ + --seg-fn-out build/segbits_ioi3_x.db + + # Keep a copy to track iter progress + cp build/segbits_ioi3_x.rdb build/$(ITER)/segbits_ioi3_x.rdb + cp build/segbits_ioi3_x.db build/$(ITER)/segbits_ioi3_x.db + + # 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} lioi3 build/segbits_ioi3_x.db + XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} rioi3 build/segbits_ioi3_x.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} lioi3 build/segbits_ioi3_x.db + ${XRAY_MERGEDB} rioi3 build/segbits_ioi3_x.db + ${XRAY_MERGEDB} lioi3_tbytesrc build/segbits_ioi3_x.db + ${XRAY_MERGEDB} rioi3_tbytesrc build/segbits_ioi3_x.db + ${XRAY_MERGEDB} lioi3_tbyteterm build/segbits_ioi3_x.db + ${XRAY_MERGEDB} rioi3_tbyteterm build/segbits_ioi3_x.db + +.PHONY: database pushdb diff --git a/fuzzers/037-iob-pips/bits.dbf b/fuzzers/037-iob-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/037-iob-pips/generate.py b/fuzzers/037-iob-pips/generate.py new file mode 100644 index 00000000..4ee3c186 --- /dev/null +++ b/fuzzers/037-iob-pips/generate.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +from prjxray.segmaker import Segmaker +import os, re +import os.path + + +def bitfilter(frame, word): + if frame < 28: + return False + return True + + +def main(): + segmk = Segmaker("design.bits") + + tiledata = {} + pipdata = {} + ignpip = set() + + with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', + 'ioi3', 'lioi3.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', + 'ioi3', 'rioi3.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('LIOI3') and not tile.startswith('RIOI3'): + continue + + log = open("log.txt", "a") + print(line, file=log) + pip_prefix, _ = pip.split(".") + tile_from_pip, tile_type = pip_prefix.split('/') + + _, 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) + + if pnum == 1 or pdir == 0: + print("Ignoring pip: {}".format(pip), file=log) + ignpip.add((src, dst)) + + for tile, pips_srcs_dsts in tiledata.items(): + tile_type = pips_srcs_dsts["type"] + + if tile_type.startswith('LIOI3'): + tile_type = 'LIOI3' + elif tile_type.startswith('RIOI3'): + tile_type = 'RIOI3' + + pips = pips_srcs_dsts["pips"] + + for src, dst in pipdata[tile_type]: + if (src, dst) in ignpip: + pass + if re.match(r'.*PHASER.*', src) or re.match(r'.*CLKDIV[PFB].*', + dst): + pass + elif (src, dst) in tiledata[tile]["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) + + internal_feedback = False + + segmk.compile(bitfilter=bitfilter) + segmk.write() + + +if __name__ == "__main__": + main() diff --git a/fuzzers/037-iob-pips/generate.tcl b/fuzzers/037-iob-pips/generate.tcl new file mode 100644 index 00000000..39cdcf39 --- /dev/null +++ b/fuzzers/037-iob-pips/generate.tcl @@ -0,0 +1,55 @@ +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 {AVAL-74}] + set_property IS_ENABLED 0 [get_drc_checks {PDRC-26}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-4}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-5}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-13}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-98}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-99}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-115}] + set_property IS_ENABLED 0 [get_drc_checks {REQP-144}] + + set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets] + + place_design + write_checkpoint -force design_before_route.dcp + route_design + write_checkpoint -force design.dcp + + write_bitstream -force design.bit + write_pip_txtdata design.txt +} + +run diff --git a/fuzzers/037-iob-pips/ioi3_pip_list.tcl b/fuzzers/037-iob-pips/ioi3_pip_list.tcl new file mode 100644 index 00000000..d7c940af --- /dev/null +++ b/fuzzers/037-iob-pips/ioi3_pip_list.tcl @@ -0,0 +1,39 @@ +proc print_tile_pips {tile_type filename} { + set fp [open $filename w] + set pips [dict create] + foreach tile [get_tiles -filter "TYPE == $tile_type"] { + puts "Dumping PIPs for tile $tile ($tile_type) to $filename." + foreach pip [lsort [get_pips -of_objects $tile]] { + set src [get_wires -uphill -of_objects $pip] + set dst [get_wires -downhill -of_objects $pip] + + # Skip pips with disconnected nodes + set src_node [get_nodes -of_objects $src] + + if { $src_node == {} } { + continue + } + + set dst_node [get_nodes -of_objects $src] + if { $dst_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] { + puts $fp $pip_string + dict set pips $pip_string 1 + } + } + } + } + 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 LIOI3 lioi3.txt +print_tile_pips RIOI3 rioi3.txt diff --git a/fuzzers/037-iob-pips/output_cmt.tcl b/fuzzers/037-iob-pips/output_cmt.tcl new file mode 100644 index 00000000..663789a5 --- /dev/null +++ b/fuzzers/037-iob-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 BUFR BUFMRCE BUFIO ILOGICE3 OLOGICE3 IDELAYE2 IDELAYCTRL PLLE2_ADV} { + foreach site [get_sites -filter "SITE_TYPE == $site_type"] { + puts $fp "$site,[get_property CLOCK_REGION $site]" + } +} +close $fp diff --git a/fuzzers/037-iob-pips/top.py b/fuzzers/037-iob-pips/top.py new file mode 100644 index 00000000..e6e4e3f0 --- /dev/null +++ b/fuzzers/037-iob-pips/top.py @@ -0,0 +1,345 @@ +import os +import random +import math +random.seed(int(os.getenv("SEED"), 16)) +from prjxray import util +from prjxray import verilog +from prjxray import lut_maker +from prjxray.db import Database + +NOT_INCLUDED_TILES = ['LIOI3_SING', 'RIOI3_SING'] + +SITE_TYPES = ['OLOGICE3', 'ILOGICE3'] + + +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) + + +def gen_sites(): + ''' Return dict of ISERDES/OSERDES locations. ''' + db = Database(util.get_db_root()) + grid = db.grid() + + xy_fun = util.create_xy_fun('\S+') + + tiles = grid.tiles() + + for tile_name in sorted(tiles): + loc = grid.loc_of_tilename(tile_name) + gridinfo = grid.gridinfo_at_loc(loc) + tile_type = gridinfo.tile_type + + tile = {'tile': tile_name, 'tile_type': tile_type, 'ioi_sites': {}} + + for site_name, site_type in gridinfo.sites.items(): + if site_type in SITE_TYPES: + xy = xy_fun(site_name) + if xy not in tile['ioi_sites']: + tile['ioi_sites'][xy] = {} + + tile['ioi_sites'][xy][site_type] = site_name + + yield tile + + +class ClockSources(object): + def __init__(self): + self.site_to_cmt = dict(read_site_to_cmt()) + + self.leaf_gclks = {} + self.ioclks = {} + self.rclks = {} + self.selected_leaf_gclks = {} + self.lut_maker = lut_maker.LutMaker() + + for cmt in set(self.site_to_cmt.values()): + self.leaf_gclks[cmt] = [] + self.ioclks[cmt] = [] + self.rclks[cmt] = [] + + def init_clocks(self): + """ Initialize all IOI clock sources. """ + for site, cmt in self.site_to_cmt.items(): + clk = 'clk_' + site + if 'BUFHCE' in site: + print( + """ + wire {clk}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFH bufh_{site}( + .O({clk}) + ); + """.format( + clk=clk, + site=site, + )) + + self.leaf_gclks[cmt].append(clk) + + if 'BUFIO' in site: + print( + """ + wire {clk}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFIO bufio_{site}( + .O({clk}) + ); + """.format( + clk=clk, + site=site, + )) + + self.ioclks[cmt].append(clk) + + if 'BUFR' in site: + print( + """ + wire {clk}; + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + BUFR bufr_{site}( + .O({clk}) + ); + """.format( + clk=clk, + site=site, + )) + + self.rclks[cmt].append(clk) + + # Choose 6 leaf_gclks to be used in each CMT. + for cmt in self.leaf_gclks: + self.selected_leaf_gclks[cmt] = random.sample( + self.leaf_gclks[cmt], 6) + + def get_clock( + self, + site, + allow_ioclks, + allow_rclks, + allow_fabric=True, + allow_empty=True): + cmt = self.site_to_cmt[site] + choices = [] + if allow_fabric: + choices.append('lut') + + if allow_empty: + choices.append('') + + choices.extend(self.selected_leaf_gclks[cmt]) + if allow_ioclks: + choices.extend(self.ioclks[cmt]) + + if allow_rclks: + choices.extend(self.rclks[cmt]) + + clock = random.choice(choices) + is_lut = False + if clock == "lut": + clock = self.lut_maker.get_next_output_net() + is_lut = True + return clock, is_lut + + +def add_port(ports, port, signal): + ports.append('.{}({})'.format(port, signal)) + + +def run(): + print("module top();") + + clocks = ClockSources() + clocks.init_clocks() + """ + + ISERDESE2 clock sources: + + CLK/CLKB: + - Allows LEAF_GCLK, IOCLKS, RCLKS and fabric + - Dedicated pips + + CLKDIV: + - No dedicated pips, uses fabric clock in. + + CLKDIVP: + - Has pips, MIG only, PHASER or fabric. + + OCLK/OCLKB: + - Allows LEAF_GCLK, IOCLKS, RCLKS and fabric + - Must match OSERDESE2:CLK/CLKB + + OSERDESE2 clock sources: + + CLKDIV/CLKDIVB: + - Allows LEAF_GCLK and RCLKS and fabric + - Dedicated pips + + CLKDIVF/CLKDIVFB: + - Allows LEAF_GCLK and RCLKS and fabric + - No explicit port, follows CLKDIV/CLKDIVB? + """ + + output = [] + + for tile in gen_sites(): + if tile['tile_type'] in NOT_INCLUDED_TILES: + continue + + for xy in tile['ioi_sites']: + ilogic_site_type = random.choice([None, 'ISERDESE2', 'IDDR']) + use_oserdes = random.randint(0, 1) + + ilogic_site = tile['ioi_sites'][xy]['ILOGICE3'] + ologic_site = tile['ioi_sites'][xy]['OLOGICE3'] + + if use_oserdes: + oclk, _ = clocks.get_clock( + ologic_site, allow_ioclks=True, allow_rclks=True) + + oclkb = oclk + else: + oclk, is_lut = clocks.get_clock( + ilogic_site, allow_ioclks=True, allow_rclks=True) + + if random.randint(0, 1): + oclkb = oclk + else: + oclkb, _ = clocks.get_clock( + ilogic_site, + allow_ioclks=True, + allow_rclks=True, + allow_fabric=not is_lut) + + DATA_RATE = random.choice(['DDR', 'SDR']) + clk, is_lut = clocks.get_clock( + ilogic_site, + allow_ioclks=True, + allow_rclks=True, + allow_empty=DATA_RATE == 'SDR') + if False: + clkb = clk + else: + clkb = clk + while clkb == clk: + clkb, _ = clocks.get_clock( + ilogic_site, + allow_ioclks=True, + allow_rclks=True, + allow_empty=False) + + if ilogic_site_type is None: + pass + elif ilogic_site_type == 'ISERDESE2': + INTERFACE_TYPE = random.choice( + [ + 'MEMORY', + 'MEMORY_DDR3', + 'MEMORY_QDR', + 'NETWORKING', + 'OVERSAMPLE', + ]) + ports = [] + + add_port(ports, 'CLK', clk) + add_port(ports, 'CLKB', clkb) + add_port(ports, 'OCLK', oclk) + add_port(ports, 'OCLKB', oclkb) + + output.append( + """ + (* KEEP, DONT_TOUCH, LOC="{site}" *) + ISERDESE2 #( + .DATA_RATE({DATA_RATE}), + .INTERFACE_TYPE({INTERFACE_TYPE}), + .IS_CLK_INVERTED({IS_CLK_INVERTED}), + .IS_CLKB_INVERTED({IS_CLKB_INVERTED}), + .INIT_Q1({INIT_Q1}), + .INIT_Q2({INIT_Q2}), + .INIT_Q3({INIT_Q3}), + .INIT_Q4({INIT_Q4}), + .SRVAL_Q1({SRVAL_Q1}), + .SRVAL_Q2({SRVAL_Q2}), + .SRVAL_Q3({SRVAL_Q3}), + .SRVAL_Q4({SRVAL_Q4}) + ) iserdes_{site}( + {ports});""".format( + site=ilogic_site, + ports=',\n'.join(ports), + DATA_RATE=verilog.quote(DATA_RATE), + INTERFACE_TYPE=verilog.quote(INTERFACE_TYPE), + IS_CLK_INVERTED=random.randint(0, 1), + IS_CLKB_INVERTED=random.randint(0, 1), + INIT_Q1=random.randint(0, 1), + INIT_Q2=random.randint(0, 1), + INIT_Q3=random.randint(0, 1), + INIT_Q4=random.randint(0, 1), + SRVAL_Q1=random.randint(0, 1), + SRVAL_Q2=random.randint(0, 1), + SRVAL_Q3=random.randint(0, 1), + SRVAL_Q4=random.randint(0, 1), + )) + elif ilogic_site_type == 'IDDR': + ports = [] + add_port(ports, 'C', clk) + add_port(ports, 'CB', clkb) + + output.append( + """ + (* KEEP, DONT_TOUCH, LOC="{site}" *) + IDDR_2CLK #( + .INIT_Q1({INIT_Q1}), + .INIT_Q2({INIT_Q2}), + .SRTYPE({SRTYPE}) + ) iserdes_{site}( + {ports});""".format( + site=ilogic_site, + ports=',\n'.join(ports), + INIT_Q1=random.randint(0, 1), + INIT_Q2=random.randint(0, 1), + SRTYPE=verilog.quote(random.choice(['ASYNC', 'SYNC'])), + )) + else: + assert False, ilogic_site_type + + if use_oserdes: + ports = [] + + add_port( + ports, 'CLKDIV', + clocks.get_clock( + ologic_site, + allow_ioclks=False, + allow_rclks=True, + )[0]) + + add_port(ports, 'CLK', oclk) + + output.append( + """ + (* KEEP, DONT_TOUCH, LOC = "{site}" *) + OSERDESE2 #( + .DATA_RATE_OQ("SDR"), + .DATA_RATE_TQ("SDR") + ) oserdes_{site} ( + {ports});""".format( + site=ologic_site, + ports=',\n'.join(ports), + )) + + for s in clocks.lut_maker.create_wires_and_luts(): + print(s) + + for s in output: + print(s) + + print("endmodule") + + +if __name__ == '__main__': + run() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index c515cde3..532fa5d1 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -88,6 +88,7 @@ $(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid)) $(eval $(call fuzzer,035-iob-ilogic,005-tilegrid)) $(eval $(call fuzzer,035a-iob-idelay,005-tilegrid)) $(eval $(call fuzzer,036-iob-ologic,005-tilegrid)) +$(eval $(call fuzzer,037-iob-pips,005-tilegrid)) $(eval $(call fuzzer,038-cfg,005-tilegrid)) $(eval $(call fuzzer,040-clk-hrow-config,005-tilegrid)) $(eval $(call fuzzer,041-clk-hrow-pips,005-tilegrid)) diff --git a/fuzzers/int_maketodo.py b/fuzzers/int_maketodo.py index 4bef0ec9..df800e33 100644 --- a/fuzzers/int_maketodo.py +++ b/fuzzers/int_maketodo.py @@ -209,12 +209,22 @@ def run( if side == "r" and not r: continue - if side != "": - side = "_" + side + if side == "xl": + segfile = "l{}".format(seg_type) + pipfile = "l{}".format(pip_type) + elif side == "xr": + segfile = "r{}".format(seg_type) + pipfile = "r{}".format(pip_type) + elif side == "l" or side == "r": + segfile = "{}_{}".format(seg_type, side) + pipfile = "{}_{}".format(pip_type, side) + else: + segfile = "{}".format(seg_type) + pipfile = "{}".format(pip_type) maketodo( - "%s/%s%s.txt" % (pip_dir, pip_type, side), - "%s/segbits_%s%s.db" % (db_dir, seg_type, side), + "%s/%s.txt" % (pip_dir, pipfile), + "%s/segbits_%s.db" % (db_dir, segfile), intre, exclude_re=exclude_re, balance_wire_re=balance_wire_re,