mirror of https://github.com/openXC7/prjxray.git
commit
a8f635c003
|
|
@ -1,14 +1,16 @@
|
||||||
export FUZDIR=$(shell pwd)
|
export FUZDIR=$(shell pwd)
|
||||||
PIP_TYPE?=cmt_top
|
PIP_TYPE?=cmt_top
|
||||||
PIPLIST_TCL=$(FUZDIR)/cmt_top_upper_t.tcl
|
PIPLIST_TCL=$(FUZDIR)/cmt_top_upper_t.tcl
|
||||||
TODO_RE=".*\.CMT_TOP_[LR]_UPPER_T_PLLE2_CLK_[^_]+_INT"
|
TODO_RE=".*CMT_TOP_[LR]_UPPER_T_PLLE2_CLK(IN1|IN2|FBIN)\.CMT_TOP_[LR]"
|
||||||
|
|
||||||
ifneq (${XRAY_DATABASE}, zynq7)
|
ifneq (${XRAY_DATABASE}, zynq7)
|
||||||
MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE)
|
MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE)
|
||||||
else
|
else
|
||||||
MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE)
|
MAKETODO_FLAGS=--sides "l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE)
|
||||||
endif
|
endif
|
||||||
N = 50
|
|
||||||
|
N = 100
|
||||||
|
SEGMATCH_FLAGS=-m 10 -M 20 -c 170
|
||||||
|
|
||||||
A_PIPLIST=cmt_top_l_upper_t.txt
|
A_PIPLIST=cmt_top_l_upper_t.txt
|
||||||
|
|
||||||
|
|
@ -30,14 +32,14 @@ RDBS += build/segbits_cmt_top_r_upper_t.rdb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
database: ${RDBS}
|
database: ${RDBS}
|
||||||
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
|
python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \
|
||||||
--seg-fn-in build/segbits_cmt_top_l_upper_t.rdb \
|
-i build/segbits_cmt_top_l_upper_t.rdb \
|
||||||
--seg-fn-out build/segbits_cmt_top_l_upper_t.db
|
-o build/segbits_cmt_top_l_upper_t.db
|
||||||
|
|
||||||
ifneq (${XRAY_DATABASE}, zynq7)
|
ifneq (${XRAY_DATABASE}, zynq7)
|
||||||
${XRAY_DBFIXUP} --db-root build --zero-db bits.dbf \
|
python3 ${FUZDIR}/fixup_and_group.py -g tag_groups.txt \
|
||||||
--seg-fn-in build/segbits_cmt_top_r_upper_t.rdb \
|
-i build/segbits_cmt_top_r_upper_t.rdb \
|
||||||
--seg-fn-out build/segbits_cmt_top_r_upper_t.db
|
-o build/segbits_cmt_top_r_upper_t.db
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Keep a copy to track iter progress
|
# Keep a copy to track iter progress
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
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_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_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
|
|
||||||
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
from prjxray.segmaker import Segmaker
|
from prjxray.segmaker import Segmaker
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
def bitfilter(frame, word):
|
def bitfilter(frame, word):
|
||||||
if frame <= 1:
|
if frame < 28 or frame > 29:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
@ -15,30 +16,60 @@ def bitfilter(frame, word):
|
||||||
def main():
|
def main():
|
||||||
segmk = Segmaker("design.bits")
|
segmk = Segmaker("design.bits")
|
||||||
|
|
||||||
|
designdata = {}
|
||||||
tiledata = {}
|
tiledata = {}
|
||||||
pipdata = {}
|
pipdata = {}
|
||||||
|
ppipdata = {}
|
||||||
ignpip = set()
|
ignpip = set()
|
||||||
|
|
||||||
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
|
# Zynq7 do not have R CMTs
|
||||||
'cmt_top', 'cmt_top_l_upper_t.txt')) as f:
|
if os.getenv("XRAY_DATABASE") == "zynq7":
|
||||||
for l in f:
|
piplists = ['cmt_top_l_upper_t.txt']
|
||||||
tile_type, dst, src = l.strip().split('.')
|
ppiplists = ['ppips_cmt_top_l_upper_t.db']
|
||||||
if tile_type not in pipdata:
|
else:
|
||||||
pipdata[tile_type] = []
|
piplists = ['cmt_top_l_upper_t.txt', 'cmt_top_r_upper_t.txt']
|
||||||
|
ppiplists = [
|
||||||
|
'ppips_cmt_top_l_upper_t.db', 'ppips_cmt_top_r_upper_t.db'
|
||||||
|
]
|
||||||
|
|
||||||
pipdata[tile_type].append((src, dst))
|
# Load PIP lists
|
||||||
|
print("Loading PIP lists...")
|
||||||
|
for piplist in piplists:
|
||||||
|
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
|
||||||
|
'cmt_top', piplist)) as f:
|
||||||
|
for l in f:
|
||||||
|
tile_type, dst, src = l.strip().split('.')
|
||||||
|
if tile_type not in pipdata:
|
||||||
|
pipdata[tile_type] = []
|
||||||
|
|
||||||
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
|
pipdata[tile_type].append((src, dst))
|
||||||
'cmt_top', 'cmt_top_r_upper_t.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))
|
# Load PPIP lists (to exclude them)
|
||||||
|
print("Loading PPIP lists...")
|
||||||
|
for ppiplist in ppiplists:
|
||||||
|
fname = os.path.join(
|
||||||
|
os.getenv('FUZDIR'), '..', '071-ppips', 'build', ppiplist)
|
||||||
|
with open(fname, 'r') as f:
|
||||||
|
for l in f:
|
||||||
|
pip_data, pip_type = l.strip().split()
|
||||||
|
|
||||||
print("Loading tags from design.txt.")
|
if pip_type != 'always':
|
||||||
|
continue
|
||||||
|
|
||||||
|
tile_type, dst, src = pip_data.split('.')
|
||||||
|
if tile_type not in ppipdata:
|
||||||
|
ppipdata[tile_type] = []
|
||||||
|
|
||||||
|
ppipdata[tile_type].append((src, dst))
|
||||||
|
|
||||||
|
# Load desgin data
|
||||||
|
print("Loading design data...")
|
||||||
with open("design.txt", "r") as f:
|
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:
|
for line in f:
|
||||||
tile, pip, src, dst, pnum, pdir = line.split()
|
tile, pip, src, dst, pnum, pdir = line.split()
|
||||||
|
|
||||||
|
|
@ -47,6 +78,8 @@ def main():
|
||||||
|
|
||||||
if 'UPPER_B' in tile:
|
if 'UPPER_B' in tile:
|
||||||
continue
|
continue
|
||||||
|
if 'LOWER_T' in tile:
|
||||||
|
continue
|
||||||
|
|
||||||
pip_prefix, _ = pip.split(".")
|
pip_prefix, _ = pip.split(".")
|
||||||
tile_from_pip, tile_type = pip_prefix.split('/')
|
tile_from_pip, tile_type = pip_prefix.split('/')
|
||||||
|
|
@ -76,27 +109,44 @@ def main():
|
||||||
dst.startswith('CMT_TOP_L_UPPER_T_CLK'):
|
dst.startswith('CMT_TOP_L_UPPER_T_CLK'):
|
||||||
ignpip.add((src, dst))
|
ignpip.add((src, dst))
|
||||||
|
|
||||||
for tile, pips_srcs_dsts in tiledata.items():
|
tags = {}
|
||||||
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] = {}
|
||||||
|
|
||||||
|
tags[tile]["IN_USE"] = int(in_use)
|
||||||
|
|
||||||
|
# Populate PIPs
|
||||||
|
for tile in tags.keys():
|
||||||
|
tile_type = tile.rsplit("_", maxsplit=1)[0]
|
||||||
|
|
||||||
|
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]:
|
for src, dst in pipdata[tile_type]:
|
||||||
|
|
||||||
if (src, dst) in ignpip:
|
if (src, dst) in ignpip:
|
||||||
pass
|
continue
|
||||||
elif (src, dst) in pips:
|
if (src, dst) in ppipdata[tile_type]:
|
||||||
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
|
continue
|
||||||
elif (src, dst) not in tiledata[tile]["pips"]:
|
|
||||||
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 0)
|
|
||||||
|
|
||||||
internal_feedback = False
|
tag = "{}.{}".format(dst, src)
|
||||||
for src, dst in [
|
val = in_use if (src, dst) in active_pips else False
|
||||||
('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
|
|
||||||
|
|
||||||
segmk.add_tile_tag(tile, "EXTERNAL_FEEDBACK", not internal_feedback)
|
if not (in_use and not val):
|
||||||
|
tags[tile][tag] = int(val)
|
||||||
|
|
||||||
|
# Output tags
|
||||||
|
for tile, tile_tags in tags.items():
|
||||||
|
for t, v in tile_tags.items():
|
||||||
|
segmk.add_tile_tag(tile, t, v)
|
||||||
|
|
||||||
segmk.compile(bitfilter=bitfilter)
|
segmk.compile(bitfilter=bitfilter)
|
||||||
segmk.write()
|
segmk.write()
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,93 @@ proc write_pip_txtdata {filename} {
|
||||||
close $fp
|
close $fp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc load_routes {filename} {
|
||||||
|
puts "MANROUTE: Loading routes from $filename"
|
||||||
|
|
||||||
|
set fp [open $filename r]
|
||||||
|
foreach line [split [read $fp] "\n"] {
|
||||||
|
if {$line eq ""} {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
puts "MANROUTE: Line: $line"
|
||||||
|
|
||||||
|
# Parse the line
|
||||||
|
set fields [split $line " "]
|
||||||
|
set tile_name [lindex $fields 0]
|
||||||
|
set site_name [lindex $fields 1]
|
||||||
|
set pin_name [lindex $fields 2]
|
||||||
|
set route_dir [lindex $fields 3]
|
||||||
|
set wires [lrange $fields 4 end]
|
||||||
|
|
||||||
|
# Get net
|
||||||
|
set tile [get_tiles $tile_name]
|
||||||
|
set site [get_sites -of_objects $tile $site_name]
|
||||||
|
set pin [get_site_pins -of_objects $site "*/$pin_name"]
|
||||||
|
set net [get_nets -quiet -of_objects $pin]
|
||||||
|
|
||||||
|
if {$net eq "" } {
|
||||||
|
puts "MANROUTE: No net for pin $pin_name found! Skipping..."
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fixed part read from file
|
||||||
|
set route_list {}
|
||||||
|
foreach wire $wires {
|
||||||
|
lappend route_list [get_nodes -of_objects [get_wires -of_objects $tile "*/$wire"]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Complete the route
|
||||||
|
if {$route_dir eq "up"} {
|
||||||
|
set node_to [lindex $route_list 0]
|
||||||
|
set node_from [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]]
|
||||||
|
|
||||||
|
set rpart [find_routing_path -from $node_from -to $node_to]
|
||||||
|
if {$rpart eq ""} {
|
||||||
|
puts "MANROUTE: No possible route continuation for net $net"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
set route_list [concat [lrange $rpart 0 end-1] $route_list]
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$route_dir eq "down"} {
|
||||||
|
set node_from [lindex $route_list e]
|
||||||
|
set node_to [get_nodes -of_objects [get_site_pins -filter {DIRECTION == IN} -of_objects $net]]
|
||||||
|
|
||||||
|
set rpart [find_routing_path -from $node_from -to $node_to]
|
||||||
|
if {$rpart eq ""} {
|
||||||
|
puts "MANROUTE: No possible route continuation for net $net"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set route_list [concat $route_list [lrange $rpart 1 end]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the fixed route
|
||||||
|
puts "MANROUTE: Net: $net, Route: $route_list. routing..."
|
||||||
|
regsub -all {{}} $route_list "" route
|
||||||
|
set_property FIXED_ROUTE $route $net
|
||||||
|
|
||||||
|
# Route the single net. Needed to detect conflicts when evaluating
|
||||||
|
# other ones
|
||||||
|
route_design -quiet -directive Quick -nets $net
|
||||||
|
|
||||||
|
# Check for conflicts.
|
||||||
|
set status [get_property ROUTE_STATUS $net]
|
||||||
|
if {$status ne "ROUTED"} {
|
||||||
|
# Ripup and discard the fixed route.
|
||||||
|
set_property FIXED_ROUTE "" $net
|
||||||
|
route_design -unroute -nets $net
|
||||||
|
puts "MANROUTE: Net $net status $status, ripping up..."
|
||||||
|
} else {
|
||||||
|
set_property IS_ROUTE_FIXED 1 $net
|
||||||
|
puts "MANROUTE: Successful manual route for $net"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close $fp
|
||||||
|
}
|
||||||
|
|
||||||
proc run {} {
|
proc run {} {
|
||||||
create_project -force -part $::env(XRAY_PART) design design
|
create_project -force -part $::env(XRAY_PART) design design
|
||||||
read_verilog top.v
|
read_verilog top.v
|
||||||
|
|
@ -47,11 +134,27 @@ proc run {} {
|
||||||
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
|
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
|
||||||
|
|
||||||
place_design
|
place_design
|
||||||
route_design
|
|
||||||
|
load_routes routes.txt
|
||||||
|
write_checkpoint -force design_pre_route.dcp
|
||||||
|
|
||||||
|
route_design -directive Quick -preserve
|
||||||
|
|
||||||
|
if {[llength [get_nets -filter {ROUTE_STATUS!="ROUTED"}]] ne 0} {
|
||||||
|
set nets [get_nets -filter {IS_ROUTE_FIXED==1}]
|
||||||
|
puts "MANROUTE: Got unrouted nets: $nets"
|
||||||
|
puts "MANROUTE: Ripping up and starting again with no fixed routes"
|
||||||
|
|
||||||
|
route_design -unroute
|
||||||
|
set_property FIXED_ROUTE "" $nets
|
||||||
|
set_property IS_ROUTE_FIXED 0 $nets
|
||||||
|
|
||||||
|
route_design -directive Quick
|
||||||
|
}
|
||||||
|
|
||||||
write_checkpoint -force design.dcp
|
write_checkpoint -force design.dcp
|
||||||
write_bitstream -force design.bit
|
write_bitstream -force design.bit
|
||||||
write_pip_txtdata design.txt
|
write_pip_txtdata design_pips.txt
|
||||||
}
|
}
|
||||||
|
|
||||||
run
|
run
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
|
@ -6,6 +6,49 @@ from prjxray import util
|
||||||
from prjxray.db import Database
|
from prjxray.db import Database
|
||||||
|
|
||||||
|
|
||||||
|
class PipList(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.piplist = {}
|
||||||
|
self.ppiplist = {}
|
||||||
|
|
||||||
|
def get_pip_and_ppip_list_for_tile_type(self, tile_type):
|
||||||
|
|
||||||
|
# Load PIP list for the tile type if not already loaded
|
||||||
|
if tile_type not in self.piplist:
|
||||||
|
self.piplist[tile_type] = []
|
||||||
|
|
||||||
|
fname = os.path.join(
|
||||||
|
os.getenv('FUZDIR'), '..', 'piplist', 'build', 'cmt_top',
|
||||||
|
tile_type.lower() + '.txt')
|
||||||
|
|
||||||
|
with open(fname, "r") as f:
|
||||||
|
for l in f:
|
||||||
|
tile, dst, src = l.strip().split('.')
|
||||||
|
if tile_type == tile:
|
||||||
|
self.piplist[tile_type].append((src, dst))
|
||||||
|
|
||||||
|
# Load PPIP list for the tile type if not already loaded
|
||||||
|
if tile_type not in self.ppiplist:
|
||||||
|
self.ppiplist[tile_type] = []
|
||||||
|
|
||||||
|
fname = os.path.join(
|
||||||
|
os.getenv('FUZDIR'), '..', '071-ppips', 'build',
|
||||||
|
'ppips_' + tile_type.lower() + '.db')
|
||||||
|
|
||||||
|
with open(fname, "r") as f:
|
||||||
|
for l in f:
|
||||||
|
pip_data, pip_type = l.strip().split()
|
||||||
|
|
||||||
|
if pip_type != 'always':
|
||||||
|
continue
|
||||||
|
|
||||||
|
tile, dst, src = pip_data.strip().split('.')
|
||||||
|
if tile_type == tile:
|
||||||
|
self.ppiplist[tile_type].append((src, dst))
|
||||||
|
|
||||||
|
return self.piplist[tile_type], self.ppiplist[tile_type]
|
||||||
|
|
||||||
|
|
||||||
def find_phasers_for_pll(grid, loc):
|
def find_phasers_for_pll(grid, loc):
|
||||||
gridinfo = grid.gridinfo_at_loc((loc[0], loc[1] + 13))
|
gridinfo = grid.gridinfo_at_loc((loc[0], loc[1] + 13))
|
||||||
|
|
||||||
|
|
@ -39,27 +82,153 @@ def gen_sites():
|
||||||
for site_name, site_type in gridinfo.sites.items():
|
for site_name, site_type in gridinfo.sites.items():
|
||||||
if site_type in ['PLLE2_ADV']:
|
if site_type in ['PLLE2_ADV']:
|
||||||
phasers = find_phasers_for_pll(grid, loc)
|
phasers = find_phasers_for_pll(grid, loc)
|
||||||
yield site_name, phasers
|
yield tile_name, site_name, phasers
|
||||||
|
|
||||||
|
|
||||||
|
def get_random_route_from_site_pin(
|
||||||
|
pip_list, tile_name, site_pin, direction, occupied_wires):
|
||||||
|
|
||||||
|
# A map of PLL site pins to wires they are connected to.
|
||||||
|
pin_to_wire = {
|
||||||
|
"CMT_TOP_L_UPPER_T": {
|
||||||
|
"CLKIN1": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN1",
|
||||||
|
"CLKIN2": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN2",
|
||||||
|
"CLKFBIN": "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN",
|
||||||
|
},
|
||||||
|
"CMT_TOP_R_UPPER_T": {
|
||||||
|
"CLKIN1": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN1",
|
||||||
|
"CLKIN2": "CMT_TOP_R_UPPER_T_PLLE2_CLKIN2",
|
||||||
|
"CLKFBIN": "CMT_TOP_R_UPPER_T_PLLE2_CLKFBIN",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get tile type
|
||||||
|
tile_type = tile_name.rsplit("_", maxsplit=1)[0]
|
||||||
|
|
||||||
|
# Get all PIPs (PIPs + PPIPs)
|
||||||
|
pips, ppips = pip_list.get_pip_and_ppip_list_for_tile_type(tile_type)
|
||||||
|
all_pips = pips + ppips
|
||||||
|
|
||||||
|
# The first wire
|
||||||
|
wire = pin_to_wire[tile_type][site_pin]
|
||||||
|
|
||||||
|
# Walk randomly.
|
||||||
|
route = []
|
||||||
|
while True:
|
||||||
|
route.append(wire)
|
||||||
|
|
||||||
|
wires = []
|
||||||
|
|
||||||
|
for src, dst in all_pips:
|
||||||
|
if direction == "down" and src == wire:
|
||||||
|
next_wire = dst
|
||||||
|
elif direction == "up" and dst == wire:
|
||||||
|
next_wire = src
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if next_wire not in occupied_wires:
|
||||||
|
wires.append(next_wire)
|
||||||
|
|
||||||
|
if len(wires) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
wire = random.choice(wires)
|
||||||
|
occupied_wires.add(wire)
|
||||||
|
|
||||||
|
# For "up" direction reverse the route.
|
||||||
|
if direction == "down":
|
||||||
|
return route
|
||||||
|
if direction == "up":
|
||||||
|
return route[::-1]
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
|
# 8 inputs per clock region
|
||||||
|
# 5 clock regions for device
|
||||||
|
max_clk_inputs = 8 * 5
|
||||||
|
clkin_idx = 0
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'''
|
'''
|
||||||
module top();
|
module top(
|
||||||
|
input wire [{nclkin}:0] clkin
|
||||||
|
);
|
||||||
|
|
||||||
(* KEEP, DONT_TOUCH *)
|
(* KEEP, DONT_TOUCH *)
|
||||||
LUT6 dummy();
|
LUT6 dummy();
|
||||||
''')
|
'''.format(nclkin=max_clk_inputs - 1))
|
||||||
|
|
||||||
|
pip_list = PipList()
|
||||||
bufg_count = 0
|
bufg_count = 0
|
||||||
|
|
||||||
for site, phasers in sorted(gen_sites(), key=lambda x: x[0]):
|
design_file = open('design.txt', 'w')
|
||||||
drive_feedback = random.randint(0, 1)
|
routes_file = open('routes.txt', 'w')
|
||||||
clkfbin_src = random.choice(('BUFH', '0', '1', None))
|
|
||||||
|
|
||||||
if drive_feedback:
|
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 = [
|
||||||
|
('CLKIN1', 'up'),
|
||||||
|
('CLKIN2', 'up'),
|
||||||
|
('CLKFBIN', 'up'),
|
||||||
|
|
||||||
|
# Sometimes manually randomized route for CLKOUTx conflicts with
|
||||||
|
# the verilog design.
|
||||||
|
#('CLKOUT0', 'down'),
|
||||||
|
#('CLKOUT1', 'down'),
|
||||||
|
#('CLKOUT2', 'down'),
|
||||||
|
#('CLKOUT3', 'down'),
|
||||||
|
]
|
||||||
|
|
||||||
|
occupied_wires = set()
|
||||||
|
for pin, dir in pins:
|
||||||
|
|
||||||
|
route = get_random_route_from_site_pin(
|
||||||
|
pip_list, tile, pin, dir, occupied_wires)
|
||||||
|
if route is None:
|
||||||
|
endpoints[pin] = ""
|
||||||
|
continue
|
||||||
|
|
||||||
|
routes[pin] = (
|
||||||
|
route,
|
||||||
|
dir,
|
||||||
|
)
|
||||||
|
endpoints[pin] = route[-1] if dir == 'down' else route[0]
|
||||||
|
|
||||||
|
internal_feedback = endpoints['CLKFBIN'].endswith('CLKFBOUT')
|
||||||
|
|
||||||
|
# Store them in a random order so the TCL script will try to route
|
||||||
|
# them also in the random order.
|
||||||
|
lines = []
|
||||||
|
for pin, (
|
||||||
|
route,
|
||||||
|
dir,
|
||||||
|
) in routes.items():
|
||||||
|
|
||||||
|
route_str = " ".join(route)
|
||||||
|
lines.append(
|
||||||
|
'{} {} {} {} {}\n'.format(tile, site, pin, dir, route_str))
|
||||||
|
|
||||||
|
random.shuffle(lines)
|
||||||
|
routes_file.writelines(lines)
|
||||||
|
|
||||||
|
clkfbin_src = random.choice(('BUFH', 'logic'))
|
||||||
|
|
||||||
|
if internal_feedback:
|
||||||
COMPENSATION = "INTERNAL"
|
COMPENSATION = "INTERNAL"
|
||||||
else:
|
else:
|
||||||
if clkfbin_src in ['0', '1']:
|
if clkfbin_src == 'logic':
|
||||||
COMPENSATION = 'EXTERNAL'
|
COMPENSATION = 'EXTERNAL'
|
||||||
else:
|
else:
|
||||||
COMPENSATION = "ZHOLD"
|
COMPENSATION = "ZHOLD"
|
||||||
|
|
@ -121,7 +290,7 @@ module top();
|
||||||
# - Global drivers (e.g. BUFG)
|
# - Global drivers (e.g. BUFG)
|
||||||
# - PHASER_[IN|OUT]_[CA|DB]_FREQREFCLK via BB_[0-3]
|
# - PHASER_[IN|OUT]_[CA|DB]_FREQREFCLK via BB_[0-3]
|
||||||
drive_bufg = random.randint(0, 1) and bufg_count < 16
|
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:
|
if drive_bufg:
|
||||||
bufg_count += 1
|
bufg_count += 1
|
||||||
|
|
@ -141,30 +310,13 @@ module top();
|
||||||
.FREQREFCLK(clkout{idx}_{site})
|
.FREQREFCLK(clkout{idx}_{site})
|
||||||
);""".format(idx=clkout, site=site, phaser_loc=phasers['OUT'][0]))
|
);""".format(idx=clkout, site=site, phaser_loc=phasers['OUT'][0]))
|
||||||
|
|
||||||
drive_bufg = random.randint(0, 1) and bufg_count < 16
|
if internal_feedback:
|
||||||
|
|
||||||
if drive_bufg and clkfbin_src not in ['BUFH', 'BUFR']:
|
|
||||||
bufg_count += 1
|
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
(* KEEP, DONT_TOUCH *)
|
assign clkfbin_{site} = clkfbout_mult_{site};
|
||||||
BUFG (
|
""".format(site=site))
|
||||||
.I(clkfbout_mult_{site})
|
|
||||||
);""".format(site=site))
|
|
||||||
|
|
||||||
if drive_feedback:
|
|
||||||
print(
|
|
||||||
"""
|
|
||||||
assign clkfbin_{site} = clkfbout_mult_{site};
|
|
||||||
""".format(site=site))
|
|
||||||
else:
|
else:
|
||||||
# If CLKFBIN is not using CLKFBOUT feedback, can be connected to:
|
if clkfbin_src == 'BUFH':
|
||||||
# - BUFHCE/BUFR using dedicated path
|
|
||||||
# - Switch box clock port
|
|
||||||
|
|
||||||
if clkfbin_src is None:
|
|
||||||
pass
|
|
||||||
elif clkfbin_src == 'BUFH':
|
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
(* KEEP, DONT_TOUCH *)
|
(* KEEP, DONT_TOUCH *)
|
||||||
|
|
@ -172,68 +324,56 @@ module top();
|
||||||
.I(clkfbout_mult_{site}),
|
.I(clkfbout_mult_{site}),
|
||||||
.O(clkfbin_{site})
|
.O(clkfbin_{site})
|
||||||
);""".format(site=site))
|
);""".format(site=site))
|
||||||
elif clkfbin_src == 'BUFR':
|
elif clkfbin_src == 'logic':
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
(* KEEP, DONT_TOUCH *)
|
(* KEEP, DONT_TOUCH *)
|
||||||
BUFR (
|
LUT6 # (.INIT(64'h5555555555555555))
|
||||||
.I(clkfbout_mult_{site}),
|
clkfbin_logic_{site} (
|
||||||
|
.I0(clkfbout_mult_{site}),
|
||||||
.O(clkfbin_{site})
|
.O(clkfbin_{site})
|
||||||
);""".format(site=site))
|
);
|
||||||
elif clkfbin_src == '0':
|
|
||||||
print(
|
|
||||||
"""
|
|
||||||
assign clkfbin_{site} = 0;
|
|
||||||
""".format(site=site))
|
|
||||||
elif clkfbin_src == '1':
|
|
||||||
print(
|
|
||||||
"""
|
|
||||||
assign clkfbin_{site} = 1;
|
|
||||||
""".format(site=site))
|
""".format(site=site))
|
||||||
else:
|
else:
|
||||||
assert False, clkfbin_src
|
assert False, clkfb_src
|
||||||
|
|
||||||
clkin_is_none = False
|
|
||||||
|
|
||||||
for clkin in range(2):
|
for clkin in range(2):
|
||||||
clkin_src = random.choice((
|
clkin_src = random.choice((
|
||||||
'BUFH',
|
'BUFH',
|
||||||
'BUFR',
|
'BUFR',
|
||||||
'0',
|
'logic',
|
||||||
'1',
|
|
||||||
None,
|
|
||||||
))
|
))
|
||||||
if clkin == 1 and clkin_is_none and clkin_src is None:
|
|
||||||
clkin_src = 'BUFH'
|
|
||||||
|
|
||||||
if clkin_src is None:
|
if clkin_src == 'BUFH':
|
||||||
pass
|
|
||||||
elif clkin_src == 'BUFH':
|
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
(* KEEP, DONT_TOUCH *)
|
(* KEEP, DONT_TOUCH *)
|
||||||
BUFH (
|
BUFH (
|
||||||
.O(clkin{idx}_{site})
|
.O(clkin{idx}_{site}),
|
||||||
);""".format(idx=clkin + 1, site=site))
|
.I(clkin{idx2})
|
||||||
|
);""".format(idx=clkin + 1, idx2=clkin_idx, site=site))
|
||||||
elif clkin_src == 'BUFR':
|
elif clkin_src == 'BUFR':
|
||||||
print(
|
print(
|
||||||
"""
|
"""
|
||||||
(* KEEP, DONT_TOUCH *)
|
(* KEEP, DONT_TOUCH *)
|
||||||
BUFR (
|
BUFR (
|
||||||
|
.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})
|
.O(clkin{idx}_{site})
|
||||||
);""".format(idx=clkin + 1, site=site))
|
);
|
||||||
elif clkin_src == '0':
|
""".format(idx=clkin + 1, idx2=clkin_idx, site=site))
|
||||||
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))
|
|
||||||
else:
|
else:
|
||||||
assert False, clkfbin_src
|
assert False, (clkin, clkin_src)
|
||||||
|
|
||||||
|
clkin_idx += 1
|
||||||
|
|
||||||
print("endmodule")
|
print("endmodule")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ $(eval $(call fuzzer,028-fifo-config,005-tilegrid))
|
||||||
$(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid))
|
$(eval $(call fuzzer,029-bram-fifo-config,005-tilegrid))
|
||||||
$(eval $(call fuzzer,030-iob,005-tilegrid))
|
$(eval $(call fuzzer,030-iob,005-tilegrid))
|
||||||
$(eval $(call fuzzer,032-cmt-pll,005-tilegrid))
|
$(eval $(call fuzzer,032-cmt-pll,005-tilegrid))
|
||||||
$(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid))
|
$(eval $(call fuzzer,034-cmt-pll-pips,005-tilegrid 071-ppips))
|
||||||
$(eval $(call fuzzer,035-iob-ilogic,005-tilegrid))
|
$(eval $(call fuzzer,035-iob-ilogic,005-tilegrid))
|
||||||
$(eval $(call fuzzer,035a-iob-idelay,005-tilegrid))
|
$(eval $(call fuzzer,035a-iob-idelay,005-tilegrid))
|
||||||
$(eval $(call fuzzer,036-iob-ologic,005-tilegrid))
|
$(eval $(call fuzzer,036-iob-ologic,005-tilegrid))
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ input wire [15:0] sw,
|
||||||
output wire [15:0] led
|
output wire [15:0] led
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
assign tx = rx;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Clock & reset
|
// Clock & reset
|
||||||
reg [3:0] rst_sr;
|
reg [3:0] rst_sr;
|
||||||
|
|
@ -44,7 +48,8 @@ plle2_test plle2_test
|
||||||
.O_CNT (led[5:0])
|
.O_CNT (led[5:0])
|
||||||
);
|
);
|
||||||
|
|
||||||
assign led [14:6] = 0;
|
assign led [14] = |sw;
|
||||||
|
assign led [13:6] = 0;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,16 @@ always @(posedge clk100)
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// The PLL
|
// The PLL
|
||||||
wire clk_fb;
|
wire clk_fb_o;
|
||||||
|
wire clk_fb_i;
|
||||||
|
|
||||||
wire [5:0] clk;
|
wire [5:0] clk;
|
||||||
|
|
||||||
PLLE2_ADV #
|
PLLE2_ADV #
|
||||||
(
|
(
|
||||||
|
.BANDWIDTH ("HIGH"),
|
||||||
|
.COMPENSATION ("BUF_IN"),
|
||||||
|
|
||||||
.CLKIN1_PERIOD (20.0), // 50MHz
|
.CLKIN1_PERIOD (20.0), // 50MHz
|
||||||
.CLKIN2_PERIOD (10.0), // 100MHz
|
.CLKIN2_PERIOD (10.0), // 100MHz
|
||||||
|
|
||||||
|
|
@ -35,7 +39,7 @@ PLLE2_ADV #
|
||||||
.CLKFBOUT_PHASE (0.0),
|
.CLKFBOUT_PHASE (0.0),
|
||||||
|
|
||||||
.CLKOUT0_DIVIDE (16),
|
.CLKOUT0_DIVIDE (16),
|
||||||
.CLKOUT0_DUTY_CYCLE (0.5),
|
.CLKOUT0_DUTY_CYCLE (0.53125),
|
||||||
.CLKOUT0_PHASE (45.0),
|
.CLKOUT0_PHASE (45.0),
|
||||||
|
|
||||||
.CLKOUT1_DIVIDE (32),
|
.CLKOUT1_DIVIDE (32),
|
||||||
|
|
@ -69,8 +73,8 @@ pll
|
||||||
.RST (RST),
|
.RST (RST),
|
||||||
.LOCKED (O_LOCKED),
|
.LOCKED (O_LOCKED),
|
||||||
|
|
||||||
.CLKFBIN (clk_fb),
|
.CLKFBIN (clk_fb_i),
|
||||||
.CLKFBOUT (clk_fb),
|
.CLKFBOUT (clk_fb_o),
|
||||||
|
|
||||||
.CLKOUT0 (clk[0]),
|
.CLKOUT0 (clk[0]),
|
||||||
.CLKOUT1 (clk[1]),
|
.CLKOUT1 (clk[1]),
|
||||||
|
|
@ -80,6 +84,8 @@ pll
|
||||||
.CLKOUT5 (clk[5])
|
.CLKOUT5 (clk[5])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BUFG clk_fb_buf (.I(clk_fb_o), .O(clk_fb_i));
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Counters
|
// Counters
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,4 @@ route_design
|
||||||
|
|
||||||
write_checkpoint -force ../$env(PROJECT_NAME).dcp
|
write_checkpoint -force ../$env(PROJECT_NAME).dcp
|
||||||
|
|
||||||
write_bitstream -force ../$env(PROJECT_NAME).bit
|
write_bitstream -force -logic_location_file ../$env(PROJECT_NAME).bit
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue