Reworked fuzzer, added README.md

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2019-10-11 15:42:26 +02:00
parent 73c8652858
commit 4a6930694f
11 changed files with 378 additions and 145 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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