From 4a6930694f39fd314cf2219cfca5ae05edf1d939 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 11 Oct 2019 15:42:26 +0200 Subject: [PATCH] Reworked fuzzer, added README.md Signed-off-by: Maciej Kurc --- fuzzers/034-cmt-pll-pips/Makefile | 16 +- fuzzers/034-cmt-pll-pips/README.md | 20 ++ fuzzers/034-cmt-pll-pips/bits.dbf | 9 - fuzzers/034-cmt-pll-pips/fixup_and_group.py | 222 ++++++++++++++++++++ fuzzers/034-cmt-pll-pips/generate.py | 98 ++++----- fuzzers/034-cmt-pll-pips/generate.tcl | 6 +- fuzzers/034-cmt-pll-pips/tag_groups.txt | 13 ++ fuzzers/034-cmt-pll-pips/top.py | 116 +++++----- minitests/plle2_adv/basys3_plle2_adv.v | 7 +- minitests/plle2_adv/src/plle2_test.v | 14 +- minitests/plle2_adv/tcl/par.tcl | 2 +- 11 files changed, 378 insertions(+), 145 deletions(-) create mode 100644 fuzzers/034-cmt-pll-pips/README.md delete mode 100644 fuzzers/034-cmt-pll-pips/bits.dbf create mode 100755 fuzzers/034-cmt-pll-pips/fixup_and_group.py create mode 100644 fuzzers/034-cmt-pll-pips/tag_groups.txt diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile index 75ec003e..5efba883 100644 --- a/fuzzers/034-cmt-pll-pips/Makefile +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -8,7 +8,9 @@ MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type c else MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE) endif -N = 100 + +N = 80 +SEGMATCH_FLAGS=-m 10 -M 20 -c 170 A_PIPLIST=cmt_top_l_upper_t.txt @@ -30,14 +32,14 @@ RDBS += build/segbits_cmt_top_r_upper_t.rdb endif database: ${RDBS} - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_cmt_top_l_upper_t.rdb \ - --seg-fn-out build/segbits_cmt_top_l_upper_t.db + python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \ + -i build/segbits_cmt_top_l_upper_t.rdb \ + -o build/segbits_cmt_top_l_upper_t.db ifneq (${XRAY_DATABASE}, zynq7) - ${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \ - --seg-fn-in build/segbits_cmt_top_r_upper_t.rdb \ - --seg-fn-out build/segbits_cmt_top_r_upper_t.db + python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \ + -i build/segbits_cmt_top_r_upper_t.rdb \ + -o build/segbits_cmt_top_r_upper_t.db endif # Keep a copy to track iter progress diff --git a/fuzzers/034-cmt-pll-pips/README.md b/fuzzers/034-cmt-pll-pips/README.md new file mode 100644 index 00000000..50ffdee0 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/README.md @@ -0,0 +1,20 @@ +# Fuzzer for the PIPs of CMT_TOP_[LR]_UPPER_T tiles. + +The fuzzer instantiates a PLL in each available site with 2/3 probability of using it. Once used it is connected randomly to various clock and logic resources. + +For some nets a randomized "manual" route is chosen to cover as many routing scenarios as possible. + +The information whether a PLL is used or not is stored in a file (`"design.txt"`) along with the randomized route (`route.txt`) + +After the design synthesis the `generate.py` sets fixed routes on some nets which is read from the `route.txt` file. The rest of the design is routed in the regular way. The script also dumps all used PIPs (as reported by Vivado) to the `design_pips.txt`. + +The tag generation is done in the following way: + +- If a PLL site is occupied then tags for all active PIPs are emitted as 1s. No tags are emitted for inactive PIPs. +- When a PLL site is not occupied (IN_USE=0) then tags for all PIPs for the CMT tile are emitted as 0s. +- The IN_USE tag is emitted directly. + +The raw solution of tag bits is postprocessed via the custom script `fixup_and_group.py`. The script does two things: + +- Clears all bits found for the IN_USE tag in all other tags. Those bits are common to all of them. +- Groups tags according to the group definitions read from the `tag_groups.txt` file. Bits that are common to the group are set as 0 in each tag that belongs to it (tags within a group are exclusive). \ No newline at end of file diff --git a/fuzzers/034-cmt-pll-pips/bits.dbf b/fuzzers/034-cmt-pll-pips/bits.dbf deleted file mode 100644 index 42dfeb37..00000000 --- a/fuzzers/034-cmt-pll-pips/bits.dbf +++ /dev/null @@ -1,9 +0,0 @@ -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_CLKIN1 -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_CLKIN2 -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN - -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN1_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_CLKIN1 -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN2_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_CLKIN2 -CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT ^ CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN - -28_43 29_42 29_43 28_44 diff --git a/fuzzers/034-cmt-pll-pips/fixup_and_group.py b/fuzzers/034-cmt-pll-pips/fixup_and_group.py new file mode 100755 index 00000000..b005b05a --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/fixup_and_group.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python3 +""" +This is a db fixup script that does two things: + +1. Clears (removes) all bits found in "IN_USE" tag(s) and removes the IN_USE + tag itself + +2. Reads tag group definition from a file and applies the tag grouping. First + a set of common bits for each group is found (logical OR among all tags + belonging to the group). Then in each tag belonging to the group those + bits are set to 0 but only if they are not already present there. + +The resulting data is written into a segbits file. +""" +import argparse +import re +import itertools + +# ============================================================================= + + +def load_tag_groups(file_name): + """ + Loads tag groups from a text file. + + A tag group is defined by specifying a space separated list of tags within + a single line. Lines that are empty or start with '#' are ignored. + """ + tag_groups = [] + + # Load tag group specifications + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + + if len(line) == 0 or line.startswith("#"): + continue + + group = set(line.split()) + if len(group): + tag_groups.append(group) + + # Check if all tag groups are exclusive + for tag_group_a, tag_group_b in itertools.combinations(tag_groups, 2): + + tags = tag_group_a & tag_group_b + if len(tags): + raise RuntimeError( + "Tag(s) {} are present in multiple groups".format( + " ".join(tags))) + + return tag_groups + + +# ============================================================================= + + +def parse_bit(bit): + """ + Decodes string describing a bit. Returns a tuple (frame, bit, value) + """ + match = re.match("^(!?)([0-9]+)_([0-9]+)$", bit) + assert match != None, bit + + val = int(match.group(1) != "!") + frm = int(match.group(2)) + bit = int(match.group(3)) + + return frm, bit, val + + +def bit_to_str(bit): + """ + Converts a tuple (frame, bit, value) to its string representation. + """ + s = "!" if not bit[2] else "" + return "{}{}_{}".format(s, bit[0], bit[1]) + + +def load_segbits(file_name): + """ + Loads a segbits file. + """ + + segbits = {} + + with open(file_name, "r") as fp: + for line in fp: + line = line.strip() + fields = line.split() + + if len(fields) < 2: + raise RuntimeError("Malformed line: '%s'" % line) + + tag = fields[0] + + if "<" in line or ">" in line: + segbits[tag] = set() + + else: + bits = set([parse_bit(bit) for bit in fields[1:]]) + segbits[tag] = bits + + return segbits + + +def save_segbits(file_name, segbits): + """ + Save segbits to a .db or .rdb file + """ + + with open(file_name, "w") as fp: + for tag, bits in segbits.items(): + if not len(bits): + continue + + line = tag + " " + line += " ".join([bit_to_str(bit) for bit in sorted(list(bits))]) + fp.write(line + "\n") + + +# ============================================================================= + + +def mask_out_bits(segbits, mask, tags_to_mask=None): + """ + Given a set of bits and a list of tags to affect (optional) removes all + the bits from each tag that are present (and equal) in the masking set. + """ + + if tags_to_mask is None: + tags_to_mask = segbits.keys() + + # Mask out matching bits + for tag in tags_to_mask: + bits = segbits[tag] + + bits = set(bits) - set(mask) + segbits[tag] = bits + + return segbits + + +def find_common_bits_for_tag_groups(segbits, tag_groups): + """ + For each tag group finds a common set of bits that have value of one. + """ + + bit_groups = [] + + for tag_group in tag_groups: + bit_group = set() + + for tag, bits in segbits.items(): + if tag in tag_group: + ones = set([b for b in bits if b[2]]) + bit_group |= ones + + bit_groups.append(bit_group) + + return bit_groups + + +def group_tags(segbits, tag_groups, bit_groups): + """ + Implements tag grouping. If a tag belongs to a group then the common bits + of that group are added to is as zeros. + """ + + for tag_group, bit_group in zip(tag_groups, bit_groups): + zeros = set([(b[0], b[1], 0) for b in bit_group]) + for tag in tag_group: + + # Insert zero bits + if tag in segbits.keys(): + bits = segbits[tag] + for z in zeros: + if not (z[0], z[1], 1) in bits: + bits.add(z) + + return segbits + + +# ============================================================================= + + +def main(): + + # Parse arguments + parser = argparse.ArgumentParser() + + parser.add_argument("-i", required=True, type=str, help="Input .rdb file") + parser.add_argument( + "-g", required=True, type=str, help="Input tag group definition file") + parser.add_argument("-o", required=True, type=str, help="Output .rdb file") + + args = parser.parse_args() + + # Load tag groups + tag_groups = load_tag_groups(args.g) + + # Load raw database file + segbits = load_segbits(args.i) + + # Mask out bits present in "IN_USE" tag(s) as they are common to other tags + for tag in segbits.keys(): + if tag.endswith("IN_USE"): + prefix = tag[:tag.index("IN_USE")] + tags_to_mask = [t for t in segbits.keys() if t.startswith(prefix)] + mask_out_bits(segbits, segbits[tag], tags_to_mask) + + # Find common bits + bit_groups = find_common_bits_for_tag_groups(segbits, tag_groups) + # Apply tag grouping + segbits = group_tags(segbits, tag_groups, bit_groups) + + # Save fixed database file + save_segbits(args.o, segbits) + + +if __name__ == "__main__": + main() diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py index fd93cfd3..5bfe2ec0 100644 --- a/fuzzers/034-cmt-pll-pips/generate.py +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -4,11 +4,10 @@ from prjxray.segmaker import Segmaker import os import os.path import itertools -import random def bitfilter(frame, word): - if frame <= 1: + if frame < 28 or frame > 29: return False return True @@ -17,12 +16,14 @@ def bitfilter(frame, word): def main(): segmk = Segmaker("design.bits") + designdata = {} tiledata = {} pipdata = {} ppipdata = {} ignpip = set() # Load PIP lists + print("Loading PIP lists...") piplists = ['cmt_top_l_upper_t.txt', 'cmt_top_r_upper_t.txt'] for piplist in piplists: with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build', @@ -35,6 +36,7 @@ def main(): pipdata[tile_type].append((src, dst)) # Load PPIP lists (to exclude them) + print("Loading PPIP lists...") ppiplists = ['ppips_cmt_top_l_upper_t.db', 'ppips_cmt_top_r_upper_t.db'] for ppiplist in ppiplists: fname = os.path.join( @@ -43,7 +45,6 @@ def main(): for l in f: pip_data, pip_type = l.strip().split() - print(pip_data, pip_type) if pip_type != 'always': continue @@ -53,8 +54,14 @@ def main(): ppipdata[tile_type].append((src, dst)) - print("Loading tags from design.txt.") + # Load desgin data + print("Loading design data...") with open("design.txt", "r") as f: + for line in f: + fields = line.strip().split(",") + designdata[fields[0]] = fields[1:] + + with open("design_pips.txt", "r") as f: for line in f: tile, pip, src, dst, pnum, pdir = line.split() @@ -94,63 +101,50 @@ def main(): dst.startswith('CMT_TOP_L_UPPER_T_CLK'): ignpip.add((src, dst)) - # Ignore pseudo pips - for ppip in ppipdata[tile_type]: - if ppip == (src, dst): - ignpip.add(( - src, - dst, - )) - tags = {} - for tile, pips_srcs_dsts in tiledata.items(): - tile_type = pips_srcs_dsts["type"] - pips = pips_srcs_dsts["pips"] + # Populate IN_USE tags + for tile, (site, in_use) in designdata.items(): if tile not in tags: tags[tile] = {} - for src, dst in pipdata[tile_type]: - if (src, dst) in ignpip: - pass - elif (src, dst) in pips: - tags[tile]["%s.%s" % (dst, src)] = 1 - elif (src, dst) not in tiledata[tile]["pips"]: - tags[tile]["%s.%s" % (dst, src)] = 0 - - internal_feedback = False - for src, dst in [ - ('CMT_TOP_L_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ('CMT_TOP_R_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), - ]: - if (src, dst) in pips: - internal_feedback = True - - tags[tile]["EXTERNAL_FEEDBACK"] = int(not internal_feedback) - - # Those tags are exclusive. This is due to the fact that Vivado sometimes - # report routes that does not correspond to underlying bit configuration. - xored_tags = [ - ( - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT" - ), - ( - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN", - "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT" - ), - ] + tags[tile]["IN_USE"] = int(in_use) + # Populate PIPs for tile in tags.keys(): - for pair in xored_tags: - for tag_a, tag_b in itertools.permutations(pair, 2): + tile_type = tile.rsplit("_", maxsplit=1)[0] - if tag_a in tags[tile] and tag_b in tags[tile]: - if tags[tile][tag_a] == tags[tile][tag_b]: - d = tags[tile] - del d[tag_a] - del d[tag_b] + in_use = tags[tile]["IN_USE"] + internal_feedback = False + if not in_use: + active_pips = [] + else: + active_pips = tiledata[tile]["pips"] + + for src, dst in pipdata[tile_type]: + + if (src, dst) in ignpip: + continue + if (src, dst) in ppipdata[tile_type]: + continue + + tag = "{}.{}".format(dst, src) + val = in_use if (src, dst) in active_pips else False + + if not (in_use and not val): + tags[tile][tag] = int(val) + + for s, d in [ + ('CMT_TOP_L_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), + ('CMT_TOP_R_CLKFBOUT2IN', 'CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN'), + ]: + if (s, d) in active_pips: + internal_feedback = in_use + + tags[tile]["INTERNAL_FEEDBACK"] = int(internal_feedback) + + # Output tags for tile, tile_tags in tags.items(): for t, v in tile_tags.items(): segmk.add_tile_tag(tile, t, v) diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl index f58587df..744cf8a0 100644 --- a/fuzzers/034-cmt-pll-pips/generate.tcl +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -92,7 +92,7 @@ proc load_routes {filename} { # Route the single net. Needed to detect conflicts when evaluating # other ones - route_design -quiet -nets $net + route_design -quiet -directive Quick -nets $net # Check for conflicts. set status [get_property ROUTE_STATUS $net] @@ -138,11 +138,11 @@ proc run {} { load_routes routes.txt write_checkpoint -force design_pre_route.dcp - route_design -preserve + route_design -directive Quick -preserve write_checkpoint -force design.dcp write_bitstream -force design.bit - write_pip_txtdata design.txt + write_pip_txtdata design_pips.txt } run diff --git a/fuzzers/034-cmt-pll-pips/tag_groups.txt b/fuzzers/034-cmt-pll-pips/tag_groups.txt new file mode 100644 index 00000000..afa81e6a --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/tag_groups.txt @@ -0,0 +1,13 @@ +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_CLKFBOUT2IN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_CLKFBIN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_L_UPPER_T_PLLE2_CLK_FB_INT + +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_CLKIN1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN1_INT + +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_L_UPPER_T_PLLE2_CLK_IN2_INT + +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_CLKFBOUT2IN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_CLKFBIN CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN.CMT_TOP_R_UPPER_T_PLLE2_CLK_FB_INT + +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_CLKIN1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_FREQ_BB3 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT + +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_CLKIN2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB0 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB1 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB2 CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_FREQ_BB3 +CMT_UPPER_T.CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT + diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py index d562a3be..55a12571 100644 --- a/fuzzers/034-cmt-pll-pips/top.py +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -51,8 +51,9 @@ def get_random_route_from_site_pin( site_type = tile["sites"][site_name] tile = db.get_tile_type(tile_type) - site = [s for s in tile.get_sites() if s.type == site_type - ][0] # FIXME: find correct site by vivado loc + + # Assumption: there is only one PLL per tile. + site = [s for s in tile.get_sites() if s.type == site_type][0] # Find site wire wire = None @@ -62,7 +63,7 @@ def get_random_route_from_site_pin( break assert wire is not None - # Walk randomly over not occupied wires. + # Walk randomly. route = [] while True: route.append(wire) @@ -94,40 +95,47 @@ def get_random_route_from_site_pin( def main(): + + # 8 inputs per clock region + # 5 clock regions for device + max_clk_inputs = 8 * 5 + clkin_idx = 0 + print( ''' -module top(); +module top( + input wire [{nclkin}:0] clkin +); + (* KEEP, DONT_TOUCH *) LUT6 dummy(); - ''') + '''.format(nclkin=max_clk_inputs - 1)) db = Database(util.get_db_root()) bufg_count = 0 + design_file = open('design.txt', 'w') routes_file = open('routes.txt', 'w') for tile, site, phasers in sorted(gen_sites(), key=lambda x: x[0]): + in_use = random.randint(0, 2) > 0 + + design_file.write("{},{},{}\n".format(tile, site, int(in_use))) + + if not in_use: + continue # Generate random routes to/from some pins routes = {} endpoints = {} pins = [ - # Enabling random manual routing for CLKINx breaks solution for - # tags: - # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN1.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN1_INT - # - CMT_TOP_R_UPPER_T_PLLE2_CLKIN2.CMT_TOP_R_UPPER_T_PLLE2_CLK_IN2_INT - - #('CLKIN1', 'up'), - #('CLKIN2', 'up'), - - # This works: + ('CLKIN1', 'up'), + ('CLKIN2', 'up'), ('CLKFBIN', 'up'), - ('CLKFBOUT', 'down'), # Sometimes manually randomized route for CLKOUTx conflicts with - # the verilog design. Need to fix that in the future. - + # the verilog design. #('CLKOUT0', 'down'), #('CLKOUT1', 'down'), #('CLKOUT2', 'down'), @@ -149,12 +157,10 @@ module top(); ) endpoints[pin] = route[-1] if dir == 'down' else route[0] - internal_feedback = endpoints['CLKFBOUT'].endswith('CLKFBIN') - if internal_feedback: - del routes['CLKFBIN'] + internal_feedback = endpoints['CLKFBIN'].endswith('CLKFBOUT') - # Store them in random order so the TCL script will try to route - # in random order. + # Store them in a random order so the TCL script will try to route + # them also in the random order. lines = [] for pin, ( route, @@ -168,7 +174,6 @@ module top(); random.shuffle(lines) routes_file.writelines(lines) - #clkfbin_src = random.choice(('BUFH', '0', '1', 'logic', None)) clkfbin_src = random.choice(('BUFH', 'logic')) if internal_feedback: @@ -236,7 +241,7 @@ module top(); # - Global drivers (e.g. BUFG) # - PHASER_[IN|OUT]_[CA|DB]_FREQREFCLK via BB_[0-3] drive_bufg = random.randint(0, 1) and bufg_count < 16 - drive_phaser = random.randint(0, 1) + drive_phaser = 0 #random.randint(0, 1) if drive_bufg: bufg_count += 1 @@ -270,18 +275,6 @@ module top(); .I(clkfbout_mult_{site}), .O(clkfbin_{site}) );""".format(site=site)) - elif clkfbin_src == '0': - print( - """ - assign clkfbin_{site} = 1'b0; - """.format(site=site)) - elif clkfbin_src == '1': - print( - """ - assign clkfbin_{site} = 1'b1; - """.format(site=site)) - elif clkfbin_src is None: - pass elif clkfbin_src == 'logic': print( """ @@ -292,59 +285,46 @@ module top(); .O(clkfbin_{site}) ); """.format(site=site)) - - clkin_is_none = False + else: + assert False, clkfb_src for clkin in range(2): - clkin_src = random.choice( - ( - 'BUFH', - 'BUFR', - # '0', - # '1', - 'logic', - # None, - )) - if clkin == 1 and clkin_is_none and clkin_src is None: - clkin_src = 'BUFH' + clkin_src = random.choice(( + 'BUFH', + 'BUFR', + 'logic', + )) - if clkin_src is None: - pass - elif clkin_src == 'BUFH': + if clkin_src == 'BUFH': print( """ (* KEEP, DONT_TOUCH *) BUFH ( - .O(clkin{idx}_{site}) - );""".format(idx=clkin + 1, site=site)) + .O(clkin{idx}_{site}), + .I(clkin{idx2}) + );""".format(idx=clkin + 1, idx2=clkin_idx, site=site)) elif clkin_src == 'BUFR': print( """ (* KEEP, DONT_TOUCH *) BUFR ( - .O(clkin{idx}_{site}) - );""".format(idx=clkin + 1, site=site)) - elif clkin_src == '0': - print( - """ - assign clkin{idx}_{site} = 0; - """.format(idx=clkin + 1, site=site)) - elif clkin_src == '1': - print( - """ - assign clkin{idx}_{site} = 1; - """.format(idx=clkin + 1, site=site)) + .O(clkin{idx}_{site}), + .I(clkin{idx2}) + );""".format(idx=clkin + 1, idx2=clkin_idx, site=site)) elif clkin_src == 'logic': print( """ (* KEEP, DONT_TOUCH *) LUT6 # (.INIT(64'h5555555555555555)) clkin{idx}_logic_{site} ( + .I0(clkin{idx2}), .O(clkin{idx}_{site}) ); - """.format(idx=clkin + 1, site=site)) + """.format(idx=clkin + 1, idx2=clkin_idx, site=site)) else: - assert False, clkin_src + assert False, (clkin, clkin_src) + + clkin_idx += 1 print("endmodule") diff --git a/minitests/plle2_adv/basys3_plle2_adv.v b/minitests/plle2_adv/basys3_plle2_adv.v index aace7c85..ddbf279d 100644 --- a/minitests/plle2_adv/basys3_plle2_adv.v +++ b/minitests/plle2_adv/basys3_plle2_adv.v @@ -15,6 +15,10 @@ input wire [15:0] sw, output wire [15:0] led ); +// ============================================================================ + +assign tx = rx; + // ============================================================================ // Clock & reset reg [3:0] rst_sr; @@ -44,7 +48,8 @@ plle2_test plle2_test .O_CNT (led[5:0]) ); -assign led [14:6] = 0; +assign led [14] = |sw; +assign led [13:6] = 0; endmodule diff --git a/minitests/plle2_adv/src/plle2_test.v b/minitests/plle2_adv/src/plle2_test.v index dd73b2eb..9348c2d2 100644 --- a/minitests/plle2_adv/src/plle2_test.v +++ b/minitests/plle2_adv/src/plle2_test.v @@ -22,12 +22,16 @@ always @(posedge clk100) // ============================================================================ // The PLL -wire clk_fb; +wire clk_fb_o; +wire clk_fb_i; wire [5:0] clk; PLLE2_ADV # ( +.BANDWIDTH ("HIGH"), +.COMPENSATION ("BUF_IN"), + .CLKIN1_PERIOD (20.0), // 50MHz .CLKIN2_PERIOD (10.0), // 100MHz @@ -35,7 +39,7 @@ PLLE2_ADV # .CLKFBOUT_PHASE (0.0), .CLKOUT0_DIVIDE (16), -.CLKOUT0_DUTY_CYCLE (0.5), +.CLKOUT0_DUTY_CYCLE (0.53125), .CLKOUT0_PHASE (45.0), .CLKOUT1_DIVIDE (32), @@ -69,8 +73,8 @@ pll .RST (RST), .LOCKED (O_LOCKED), -.CLKFBIN (clk_fb), -.CLKFBOUT (clk_fb), +.CLKFBIN (clk_fb_i), +.CLKFBOUT (clk_fb_o), .CLKOUT0 (clk[0]), .CLKOUT1 (clk[1]), @@ -80,6 +84,8 @@ pll .CLKOUT5 (clk[5]) ); +BUFG clk_fb_buf (.I(clk_fb_o), .O(clk_fb_i)); + // ============================================================================ // Counters diff --git a/minitests/plle2_adv/tcl/par.tcl b/minitests/plle2_adv/tcl/par.tcl index 60d66e80..7f9dcdcc 100644 --- a/minitests/plle2_adv/tcl/par.tcl +++ b/minitests/plle2_adv/tcl/par.tcl @@ -13,4 +13,4 @@ route_design write_checkpoint -force ../$env(PROJECT_NAME).dcp -write_bitstream -force ../$env(PROJECT_NAME).bit +write_bitstream -force -logic_location_file ../$env(PROJECT_NAME).bit