Complete initial PLL fuzzer.

This solves for all unknown bits, but results in a large "IN_USE"
feature for apparently constant bits.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2019-07-02 18:22:34 -07:00
parent bc822f8337
commit 30648d554a
12 changed files with 660 additions and 53 deletions

View File

@ -79,7 +79,7 @@ def run(fn_in, fn_out, verbose=False):
("iob/build/segbits_tilegrid.tdb", 42, 4), ("iob/build/segbits_tilegrid.tdb", 42, 4),
("ioi/build/segbits_tilegrid.tdb", 42, 4), ("ioi/build/segbits_tilegrid.tdb", 42, 4),
("mmcm/build/segbits_tilegrid.tdb", 30, 101), ("mmcm/build/segbits_tilegrid.tdb", 30, 101),
("pll/build/segbits_tilegrid.tdb", 30, 101), ("pll/build/segbits_tilegrid.tdb", 30, 26),
("monitor/build/segbits_tilegrid.tdb", 30, 101), ("monitor/build/segbits_tilegrid.tdb", 30, 101),
("bram/build/segbits_tilegrid.tdb", 28, 10), ("bram/build/segbits_tilegrid.tdb", 28, 10),
("bram_block/build/segbits_tilegrid.tdb", 128, 10), ("bram_block/build/segbits_tilegrid.tdb", 128, 10),

View File

@ -1,3 +1,3 @@
N ?= 5 N ?= 5
GENERATE_ARGS?="--oneval 1 --design params.csv --dframe 1C --dword 98" GENERATE_ARGS?="--oneval 1 --design params.csv --dframe 1C --dword 23"
include ../fuzzaddr/common.mk include ../fuzzaddr/common.mk

View File

@ -1,12 +1,10 @@
# read/write width is relatively slow to resolve
# Even slower with multi bit masks...
N := 50 N := 50
include ../fuzzer.mk include ../fuzzer.mk
database: build/segbits_cmt_top_upper_t.db database: build/segbits_cmt_top_upper_t.db
build/segbits_cmt_top_upper_t.rdb: $(SPECIMENS_OK) build/segbits_cmt_top_upper_t.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -o build/segbits_cmt_top_upper_t.rdb \ ${XRAY_SEGMATCH} -c 150 -o build/segbits_cmt_top_upper_t.rdb \
$(addsuffix /segdata_cmt_top_r_upper_t.txt,$(SPECIMENS)) \ $(addsuffix /segdata_cmt_top_r_upper_t.txt,$(SPECIMENS)) \
$(addsuffix /segdata_cmt_top_l_upper_t.txt,$(SPECIMENS)) $(addsuffix /segdata_cmt_top_l_upper_t.txt,$(SPECIMENS))

View File

@ -7,6 +7,9 @@ from prjxray import verilog
def bitfilter(frame, word): def bitfilter(frame, word):
if frame < 28:
return False
if frame == 25 and word == 3121: if frame == 25 and word == 3121:
return False return False
@ -14,12 +17,14 @@ def bitfilter(frame, word):
def bus_tags(segmk, ps, site): def bus_tags(segmk, ps, site):
segmk.add_site_tag(site, 'IN_USE', ps['active'])
if not ps['active']:
return
for k in ps: for k in ps:
segmk.add_site_tag(site, 'param_' + k + '_' + str(ps[k]), 1) segmk.add_site_tag(site, 'param_' + k + '_' + str(ps[k]), 1)
segmk.add_site_tag(site, 'DWE_CONNECTED',
ps['dwe_conn'].startswith('dwe_') or ps['dwe_conn'].startswith('den_'))
for reg, invert in [ for reg, invert in [
('RST', 1), ('RST', 1),
('PWRDWN', 1), ('PWRDWN', 1),
@ -32,18 +37,72 @@ def bus_tags(segmk, ps, site):
else: else:
segmk.add_site_tag(site, 'INV_' + reg, ps[opt]) segmk.add_site_tag(site, 'INV_' + reg, ps[opt])
for opt in ['OPTIMIZED', 'HIGH', 'LOW']: for opt in ['OPTIMIZED', 'HIGH', 'LOW']:
if verilog.unquote(ps['BANDWIDTH']) == opt: if verilog.unquote(ps['BANDWIDTH']) == opt:
segmk.add_site_tag( segmk.add_site_tag(site, 'BANDWIDTH.' + opt, 1)
site, 'BANDWIDTH.' + opt,
1)
elif verilog.unquote(ps['BANDWIDTH']) == 'LOW': elif verilog.unquote(ps['BANDWIDTH']) == 'LOW':
segmk.add_site_tag( segmk.add_site_tag(site, 'BANDWIDTH.' + opt, 0)
site, 'BANDWIDTH.' + opt,
0)
for opt in ['ZHOLD', 'BUF_IN', 'EXTERNAL', 'INTERNAL']: for opt in ['ZHOLD', 'BUF_IN', 'EXTERNAL', 'INTERNAL']:
continue
opt_match = verilog.unquote(ps['COMPENSATION']) == opt
if ps['clkfbin_conn'] == '':
segmk.add_site_tag(site, 'COMP.NOFB_' + opt, opt_match)
segmk.add_site_tag(site, 'COMP.ZNOFB_' + opt, opt_match)
continue
for conn in ['clk', 'clkfbout_mult_BUFG_' + ps['site'],
'clkfbout_mult_' + ps['site']]:
conn_match = ps['clkfbin_conn'] == conn
segmk.add_site_tag(
site, 'COMP.' + opt + '_' + conn + '_' + ps['site'], opt_match
and conn_match)
segmk.add_site_tag(
site, 'COMP.Z' + opt + '_' + conn + '_' + ps['site'],
not opt_match and conn_match)
segmk.add_site_tag(
site, 'COMP.Z' + opt + '_Z' + conn + '_' + ps['site'],
not opt_match and not conn_match)
segmk.add_site_tag(
site, 'COMP.' + opt + '_Z' + conn + '_' + ps['site'], opt_match
and not conn_match)
match = verilog.unquote(ps['COMPENSATION']) in ['BUF_IN', 'EXTERNAL']
bufg_on_clkin = \
'BUFG' in ps['clkin1_conn'] or \
'BUFG' in ps['clkin2_conn']
if not match:
if verilog.unquote(ps['COMPENSATION']) == 'ZHOLD' and bufg_on_clkin:
match = True
segmk.add_site_tag(
site, 'COMPENSATION.BUF_IN_OR_EXTERNAL_OR_ZHOLD_CLKIN_BUF', match)
match = verilog.unquote(ps['COMPENSATION']) in ['ZHOLD']
segmk.add_site_tag(
site, 'COMPENSATION.Z_ZHOLD_OR_CLKIN_BUF', not match
or (match and bufg_on_clkin))
segmk.add_site_tag(
site, 'COMPENSATION.ZHOLD_NO_CLKIN_BUF', match and \
not bufg_on_clkin
)
segmk.add_site_tag(
site, 'COMPENSATION.ZHOLD_NO_CLKIN_BUF_NO_TOP', match and \
not bufg_on_clkin and \
site != "PLLE2_ADV_X0Y2"
)
segmk.add_site_tag(
site, 'COMP.ZHOLD_NO_CLKIN_BUF_TOP', match and \
not bufg_on_clkin and \
site == "PLLE2_ADV_X0Y2"
)
for opt in ['ZHOLD', 'BUF_IN', 'EXTERNAL', 'INTERNAL']:
if opt in ['BUF_IN', 'EXTERNAL']:
if ps['clkfbin_conn'] not in ['', 'clk']:
continue
if site == "PLLE2_ADV_X0Y2" and opt == 'ZHOLD': if site == "PLLE2_ADV_X0Y2" and opt == 'ZHOLD':
segmk.add_site_tag( segmk.add_site_tag(
site, 'TOP.COMPENSATION.' + opt, site, 'TOP.COMPENSATION.' + opt,
@ -56,14 +115,9 @@ def bus_tags(segmk, ps, site):
site, 'COMPENSATION.Z_' + opt, site, 'COMPENSATION.Z_' + opt,
verilog.unquote(ps['COMPENSATION']) != opt) verilog.unquote(ps['COMPENSATION']) != opt)
match = "TRUE" == verilog.unquote(ps['STARTUP_WAIT']) and \
opt == verilog.unquote(ps['COMPENSATION'])
segmk.add_site_tag(site, "STARTUP_WAIT_AND_" + opt,
match)
segmk.add_site_tag( segmk.add_site_tag(
site, 'COMPENSATION.BUF_IN_OR_EXTERNAL', site, 'COMPENSATION.INTERNAL',
verilog.unquote(ps['COMPENSATION']) in ['BUF_IN', 'EXTERNAL']) verilog.unquote(ps['COMPENSATION']) in ['INTERNAL'])
for param in ['CLKFBOUT_MULT']: for param in ['CLKFBOUT_MULT']:
paramadj = int(ps[param]) paramadj = int(ps[param])

View File

@ -29,27 +29,43 @@ def main():
params = { params = {
"site": "site":
site, site,
"dclk_conn": random.choice(( 'active':
random.random() > .2,
"clkin1_conn":
random.choice((
"clkfbout_mult_BUFG_" + site,
"clk",
)),
"clkin2_conn":
random.choice((
"clkfbout_mult_BUFG_" + site,
"clk",
)),
"dclk_conn":
random.choice((
"0", "0",
"clk", "clk",
)), )),
"dwe_conn": random.choice(( "dwe_conn":
random.choice((
"", "",
"1", "1",
"0", "0",
"dwe_" + site, "dwe_" + site,
"den_" + site, "den_" + site,
)), )),
"den_conn": random.choice(( "den_conn":
random.choice((
"", "",
"1", "1",
"0", "0",
"den_" + site, "den_" + site,
)), )),
"daddr4_conn": random.choice(( "daddr4_conn":
random.choice((
"0", "0",
"dwe_" + site, "dwe_" + site,
)), )),
"IS_RST_INVERTED": "IS_RST_INVERTED":
random.randint(0, 1), random.randint(0, 1),
"IS_PWRDWN_INVERTED": "IS_PWRDWN_INVERTED":
@ -85,15 +101,34 @@ def main():
'INTERNAL', 'INTERNAL',
))), ))),
"BANDWIDTH": "BANDWIDTH":
verilog.quote( verilog.quote(random.choice((
random.choice(( 'OPTIMIZED',
'OPTIMIZED', 'HIGH',
'HIGH', 'LOW',
'LOW', ))),
))),
} }
if verilog.unquote(params['COMPENSATION']) == 'ZHOLD':
params['clkfbin_conn'] = random.choice(
(
"",
"clkfbout_mult_BUFG_" + site,
))
elif verilog.unquote(params['COMPENSATION']) == 'INTERNAL':
params['clkfbin_conn'] = random.choice(
(
"",
"clkfbout_mult_" + site,
))
else:
params['clkfbin_conn'] = random.choice(
("", "clk", "clkfbout_mult_BUFG_" + site))
f.write('%s\n' % (json.dumps(params))) f.write('%s\n' % (json.dumps(params)))
if not params['active']:
continue
print( print(
""" """
@ -109,6 +144,7 @@ def main():
); );
wire clkfbout_mult_{site}; wire clkfbout_mult_{site};
wire clkfbout_mult_BUFG_{site};
wire clkout0_{site}; wire clkout0_{site};
wire clkout1_{site}; wire clkout1_{site};
wire clkout2_{site}; wire clkout2_{site};
@ -131,7 +167,9 @@ def main():
.STARTUP_WAIT({STARTUP_WAIT}), .STARTUP_WAIT({STARTUP_WAIT}),
.CLKOUT0_DUTY_CYCLE({CLKOUT0_DUTY_CYCLE}), .CLKOUT0_DUTY_CYCLE({CLKOUT0_DUTY_CYCLE}),
.COMPENSATION({COMPENSATION}), .COMPENSATION({COMPENSATION}),
.BANDWIDTH({BANDWIDTH}) .BANDWIDTH({BANDWIDTH}),
.CLKIN1_PERIOD(10.0),
.CLKIN2_PERIOD(10.0)
) pll_{site} ( ) pll_{site} (
.CLKFBOUT(clkfbout_mult_{site}), .CLKFBOUT(clkfbout_mult_{site}),
.CLKOUT0(clkout0_{site}), .CLKOUT0(clkout0_{site}),
@ -143,9 +181,9 @@ def main():
.DRDY(), .DRDY(),
.LOCKED(), .LOCKED(),
.DO(), .DO(),
.CLKFBIN(), .CLKFBIN({clkfbin_conn}),
.CLKIN1(clk), .CLKIN1({clkin1_conn}),
.CLKIN2(), .CLKIN2({clkin2_conn}),
.CLKINSEL(), .CLKINSEL(),
.DCLK({dclk_conn}), .DCLK({dclk_conn}),
.DEN({den_conn}), .DEN({den_conn}),
@ -155,6 +193,12 @@ def main():
.DI(), .DI(),
.DADDR({{7{{ {daddr4_conn} }} }})); .DADDR({{7{{ {daddr4_conn} }} }}));
(* KEEP, DONT_TOUCH *)
BUFG bufg_{site} (
.I(clkfbout_mult_{site}),
.O(clkfbout_mult_BUFG_{site})
);
(* KEEP, DONT_TOUCH *) (* KEEP, DONT_TOUCH *)
FDRE reg_clkfbout_mult_{site} ( FDRE reg_clkfbout_mult_{site} (
.C(clkfbout_mult_{site}) .C(clkfbout_mult_{site})

View File

@ -4,9 +4,7 @@ REGISTER_LAYOUT = {
'CLKOUT1': [ 'CLKOUT1': [
('LOW_TIME', 6), ('LOW_TIME', 6),
('HIGH_TIME', 6), ('HIGH_TIME', 6),
# This bit is the output enable bit, which is being detected as a pip ('OUTPUT_ENABLE', 1),
# bit, which is roughly correct. Leave this bit as a pip bit.
(None, 1),
('PHASE_MUX', 3), ('PHASE_MUX', 3),
], ],
'CLKOUT2': [ 'CLKOUT2': [
@ -60,11 +58,20 @@ REGISTER_LAYOUT = {
], ],
'POWER_REG': [ 'POWER_REG': [
('POWER_REG', 16), ('POWER_REG', 16),
] ],
} }
BASE_OFFSET = 0x00
REGISTER_MAP = [] REGISTER_MAP = []
REGISTER_MAP.append(None)
REGISTER_MAP.append(None)
for idx in range(3):
REGISTER_MAP.append(None)
REGISTER_MAP.append(None)
# 0x06 - 0x15 # 0x06 - 0x15
for output in ['CLKOUT5', 'CLKOUT0', 'CLKOUT1', 'CLKOUT2', 'CLKOUT3', for output in ['CLKOUT5', 'CLKOUT0', 'CLKOUT1', 'CLKOUT2', 'CLKOUT3',
'CLKOUT4', None, 'CLKFBOUT']: 'CLKOUT4', None, 'CLKFBOUT']:
@ -96,17 +103,24 @@ for _ in range(0x4E - 0x28 - 1):
REGISTER_MAP.append(('FILTREG1', 'FILTREG1')) REGISTER_MAP.append(('FILTREG1', 'FILTREG1'))
REGISTER_MAP.append(('FILTREG2', 'FILTREG2')) REGISTER_MAP.append(('FILTREG2', 'FILTREG2'))
for _ in range(0x20):
REGISTER_MAP.append(None)
class RegisterAddress(object): class RegisterAddress(object):
def __init__(self, frame_offsets, bit_offset): def __init__(self, frame_offsets, bit_offset):
self.frame_index = 0 self.frame_index = 0
self.frame_offsets = frame_offsets self.frame_offsets = frame_offsets
self.bit_offset = bit_offset self.bit_offset = bit_offset
self.bits_used = set()
def next_bit(self): def next_bit(self, used=True):
output = '{}_{}'.format( output = '{}_{}'.format(
self.frame_offsets[self.frame_index], self.bit_offset) self.frame_offsets[self.frame_index], self.bit_offset)
if used:
self.bits_used.add(output)
self.frame_index += 1 self.frame_index += 1
if self.frame_index >= len(self.frame_offsets): if self.frame_index >= len(self.frame_offsets):
self.frame_index = 0 self.frame_index = 0
@ -130,6 +144,7 @@ def passthrough_non_register_segbits(seg_in):
base_offset_register = 'CMT_UPPER_T.PLLE2.CLKOUT5_DIVIDE[1]' base_offset_register = 'CMT_UPPER_T.PLLE2.CLKOUT5_DIVIDE[1]'
bit_offset = None bit_offset = None
in_use = None
with open(seg_in, 'r') as f: with open(seg_in, 'r') as f:
for l in f: for l in f:
if l.startswith(base_offset_register): if l.startswith(base_offset_register):
@ -140,10 +155,15 @@ def passthrough_non_register_segbits(seg_in):
assert frame_offset == 28 assert frame_offset == 28
assert bit_index > 3 assert bit_index > 3
bit_offset = bit_index - 3 bit_offset = bit_index - 3 - 16 * 3
continue continue
if 'IN_USE' in l:
assert in_use is None
in_use = l.strip()
continue
parts = l.split() parts = l.split()
feature_parts = parts[0].split('.') feature_parts = parts[0].split('.')
@ -177,10 +197,11 @@ def passthrough_non_register_segbits(seg_in):
print(l.strip()) print(l.strip())
assert bit_offset is not None assert bit_offset is not None
return bit_offset assert in_use is not None
return bit_offset, in_use
def output_registers(bit_offset): def output_registers(bit_offset, in_use):
""" Output segbits for the known PLL register space. """ Output segbits for the known PLL register space.
The first bit offset in the register space is required to generate this The first bit offset in the register space is required to generate this
@ -192,7 +213,7 @@ def output_registers(bit_offset):
for idx, register in enumerate(REGISTER_MAP): for idx, register in enumerate(REGISTER_MAP):
if register is None: if register is None:
for _ in range(16): for _ in range(16):
reg.next_bit() reg.next_bit(used=False)
continue continue
layout, register_name = register layout, register_name = register
@ -209,7 +230,7 @@ def output_registers(bit_offset):
bit_count += 1 bit_count += 1
if field is None: if field is None:
reg.next_bit() reg.next_bit(used=False)
continue continue
print( print(
@ -222,7 +243,7 @@ def output_registers(bit_offset):
bit_count += 1 bit_count += 1
if field is None: if field is None:
reg.next_bit() reg.next_bit(used=False)
continue continue
print( print(
@ -241,6 +262,11 @@ def output_registers(bit_offset):
'CMT_UPPER_T.PLLE2.{}[{}] {}'.format( 'CMT_UPPER_T.PLLE2.{}[{}] {}'.format(
register_name, bit, reg.next_bit())) register_name, bit, reg.next_bit()))
parts = in_use.split()
feature = parts[0]
bits = [p for p in parts[1:] if p not in reg.bits_used]
print('{} {}'.format(feature, ' '.join(bits)))
def main(): def main():
parser = argparse.ArgumentParser(description="") parser = argparse.ArgumentParser(description="")
@ -249,9 +275,9 @@ def main():
args = parser.parse_args() args = parser.parse_args()
bit_offset = passthrough_non_register_segbits(args.seg_in) bit_offset, in_use = passthrough_non_register_segbits(args.seg_in)
output_registers(bit_offset) output_registers(bit_offset, in_use)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -0,0 +1,51 @@
export FUZDIR=$(shell pwd)
PIP_TYPE?=cmt_top
PIPLIST_TCL=$(FUZDIR)/cmt_top_upper_t.tcl
TODO_RE=".*"
MAKETODO_FLAGS=--sides "r_upper_t,l_upper_t" --pip-type ${PIP_TYPE} --seg-type cmt_top --re $(TODO_RE)
N = 50
A_PIPLIST=cmt_top_l_upper_t.txt
include ../pip_loop.mk
build/segbits_cmt_top_l_upper_t.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_cmt_top_l_upper_t.rdb \
$(shell find build -name segdata_cmt_top_l_upper_t.txt)
build/segbits_cmt_top_r_upper_t.rdb: $(SPECIMENS_OK)
${XRAY_SEGMATCH} ${SEGMATCH_FLAGS} -o build/segbits_cmt_top_r_upper_t.rdb \
$(shell find build -name segdata_cmt_top_r_upper_t.txt)
database: build/segbits_cmt_top_l_upper_t.rdb build/segbits_cmt_top_r_upper_t.rdb
${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
${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
# Keep a copy to track iter progress
cp build/segbits_cmt_top_l_upper_t.rdb build/$(ITER)/segbits_cmt_top_l_upper_t.rdb
cp build/segbits_cmt_top_l_upper_t.db build/$(ITER)/segbits_cmt_top_l_upper_t.db
cp build/segbits_cmt_top_r_upper_t.rdb build/$(ITER)/segbits_cmt_top_r_upper_t.rdb
cp build/segbits_cmt_top_r_upper_t.db build/$(ITER)/segbits_cmt_top_r_upper_t.db
${XRAY_MASKMERGE} build/mask_cmt_top_l_upper_t.db \
$(shell find build -name segdata_cmt_top_l_upper_t.txt)
${XRAY_MASKMERGE} build/mask_cmt_top_r_upper_t.db \
$(shell find build -name segdata_cmt_top_r_upper_t.txt)
# 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} cmt_top_l_upper_t build/segbits_cmt_top_l_upper_t.db
XRAY_DATABASE_DIR=${FUZDIR}/build/database ${XRAY_MERGEDB} cmt_top_r_upper_t build/segbits_cmt_top_r_upper_t.db
pushdb: database
${XRAY_MERGEDB} cmt_top_l_upper_t build/segbits_cmt_top_l_upper_t.db
${XRAY_MERGEDB} cmt_top_r_upper_t build/segbits_cmt_top_r_upper_t.db
.PHONY: database pushdb

View File

View File

@ -0,0 +1,29 @@
proc print_tile_pips {tile_type filename} {
set tile [lindex [get_tiles -filter "TYPE == $tile_type"] 0]
puts "Dumping PIPs for tile $tile ($tile_type) to $filename."
set fp [open $filename w]
foreach pip [lsort [get_pips -of_objects [get_tiles $tile]]] {
set src [get_wires -uphill -of_objects $pip]
set dst [get_wires -downhill -of_objects $pip]
if {[llength [get_nodes -uphill -of_objects [get_nodes -of_objects $dst]]] == 1} {
set src_node [get_nodes -of $src]
set dst_node [get_nodes -of $dst]
if { [string first INT_INTERFACE [get_wires -of $src_node]] != -1 } {
continue
}
if { [string first INT_INTERFACE [get_wires -of $dst_node]] != -1 } {
continue
}
}
puts $fp "$tile_type.[regsub {.*/} $dst ""].[regsub {.*/} $src ""]"
}
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 CMT_TOP_L_UPPER_T cmt_top_l_upper_t.txt
print_tile_pips CMT_TOP_R_UPPER_T cmt_top_r_upper_t.txt

View File

@ -0,0 +1,106 @@
#!/usr/bin/env python3
from prjxray.segmaker import Segmaker
import os
import os.path
def bitfilter(frame, word):
if frame <= 1:
return False
return True
def main():
segmk = Segmaker("design.bits")
tiledata = {}
pipdata = {}
ignpip = set()
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'cmt_top', 'cmt_top_l_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))
with open(os.path.join(os.getenv('FUZDIR'), '..', 'piplist', 'build',
'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))
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('CMT_TOP'):
continue
if 'UPPER_B' in tile:
continue
pip_prefix, _ = pip.split(".")
tile_from_pip, tile_type = pip_prefix.split('/')
assert tile == tile_from_pip
_, 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 dst.startswith('CMT_TOP_R_UPPER_T_CLK') or \
dst.startswith('CMT_TOP_L_UPPER_T_CLK'):
ignpip.add((src, dst))
for tile, pips_srcs_dsts in tiledata.items():
tile_type = pips_srcs_dsts["type"]
pips = pips_srcs_dsts["pips"]
for src, dst in pipdata[tile_type]:
if (src, dst) in ignpip:
pass
elif (src, dst) in pips:
segmk.add_tile_tag(tile, "%s.%s" % (dst, src), 1)
elif (src, dst) not in tiledata[tile]["pips"]:
segmk.add_tile_tag(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
segmk.add_tile_tag(tile, "EXTERNAL_FEEDBACK", not internal_feedback)
segmk.compile(bitfilter=bitfilter)
segmk.write()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,57 @@
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]
# Disable MMCM frequency etc sanity checks
set_property IS_ENABLED 0 [get_drc_checks {PDRC-29}]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-30}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-50}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-53}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-126}]
# PLL
set_property IS_ENABLED 0 [get_drc_checks {PDRC-43}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-161}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-78}]
set_property IS_ENABLED 0 [get_drc_checks {AVAL-81}]
set_property IS_ENABLED 0 [get_drc_checks {PDRC-38}]
set_property IS_ENABLED 0 [get_drc_checks {REQP-13}]
place_design
route_design
write_checkpoint -force design.dcp
write_bitstream -force design.bit
write_pip_txtdata design.txt
}
run

View File

@ -0,0 +1,242 @@
""" """
import os
import random
random.seed(int(os.getenv("SEED"), 16))
from prjxray import util
from prjxray.db import Database
def find_phasers_for_pll(grid, loc):
gridinfo = grid.gridinfo_at_loc((loc[0], loc[1] + 13))
phasers = {
'IN': [],
'OUT': [],
}
for site_name, site_type in gridinfo.sites.items():
if site_type == 'PHASER_IN_PHY':
phasers['IN'].append(site_name)
elif site_type == 'PHASER_OUT_PHY':
phasers['OUT'].append(site_name)
assert len(phasers['IN']) > 0
assert len(phasers['OUT']) > 0
phasers['IN'].sort()
phasers['OUT'].sort()
return phasers
def gen_sites():
db = Database(util.get_db_root())
grid = db.grid()
for tile_name in sorted(grid.tiles()):
loc = grid.loc_of_tilename(tile_name)
gridinfo = grid.gridinfo_at_loc(loc)
for site_name, site_type in gridinfo.sites.items():
if site_type in ['PLLE2_ADV']:
phasers = find_phasers_for_pll(grid, loc)
yield site_name, phasers
def main():
print(
'''
module top();
(* KEEP, DONT_TOUCH *)
LUT6 dummy();
''')
bufg_count = 0
for site, phasers in sorted(gen_sites(), key=lambda x: x[0]):
drive_feedback = random.randint(0, 1)
clkfbin_src = random.choice(('BUFH', '0', '1', None))
if drive_feedback:
COMPENSATION = "INTERNAL"
else:
if clkfbin_src in ['0', '1']:
COMPENSATION = 'EXTERNAL'
else:
COMPENSATION = "ZHOLD"
print(
"""
wire clkfbin_{site};
wire clkin1_{site};
wire clkin2_{site};
wire clkfbout_mult_{site};
wire clkout0_{site};
wire clkout1_{site};
wire clkout2_{site};
wire clkout3_{site};
wire clkout4_{site};
wire clkout5_{site};
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
PLLE2_ADV #(
.COMPENSATION("{COMPENSATION}")
) pll_{site} (
.CLKFBOUT(clkfbout_mult_{site}),
.CLKOUT0(clkout0_{site}),
.CLKOUT1(clkout1_{site}),
.CLKOUT2(clkout2_{site}),
.CLKOUT3(clkout3_{site}),
.CLKOUT4(clkout4_{site}),
.CLKOUT5(clkout5_{site}),
.DRDY(),
.LOCKED(),
.DO(),
.CLKFBIN(clkfbin_{site}),
.CLKIN1(clkin1_{site}),
.CLKIN2(clkin2_{site}),
.CLKINSEL(),
.DCLK(),
.DEN(),
.DWE(),
.PWRDWN(),
.RST(),
.DI(),
.DADDR());
""".format(site=site, COMPENSATION=COMPENSATION))
for clkout in range(4, 6):
# CLKOUT4 and CLKOUT5 can only drive one signal type
if random.randint(0, 1) and bufg_count < 16:
bufg_count += 1
print(
"""
(* KEEP, DONT_TOUCH *)
BUFG (
.I(clkout{idx}_{site})
);""".format(idx=clkout, site=site))
any_phaser = False
for clkout in range(4):
# CLKOUT0-CLKOUT3 can drive:
# - 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)
if drive_bufg:
bufg_count += 1
print(
"""
(* KEEP, DONT_TOUCH *)
BUFG (
.I(clkout{idx}_{site})
);""".format(idx=clkout, site=site))
if drive_phaser and not any_phaser and False:
any_phaser = True
print(
"""
(* KEEP, DONT_TOUCH, LOC="{phaser_loc}" *)
PHASER_OUT phaser_{site}(
.FREQREFCLK(clkout{idx}_{site})
);""".format(idx=clkout, site=site, phaser_loc=phasers['OUT'][0]))
drive_bufg = random.randint(0, 1) and bufg_count < 16
if drive_bufg and clkfbin_src not in ['BUFH', 'BUFR']:
bufg_count += 1
print(
"""
(* KEEP, DONT_TOUCH *)
BUFG (
.I(clkfbout_mult_{site})
);""".format(site=site))
if drive_feedback:
print(
"""
assign clkfbin_{site} = clkfbout_mult_{site};
""".format(site=site))
else:
# If CLKFBIN is not using CLKFBOUT feedback, can be connected to:
# - BUFHCE/BUFR using dedicated path
# - Switch box clock port
if clkfbin_src is None:
pass
elif clkfbin_src == 'BUFH':
print(
"""
(* KEEP, DONT_TOUCH *)
BUFH (
.I(clkfbout_mult_{site}),
.O(clkfbin_{site})
);""".format(site=site))
elif clkfbin_src == 'BUFR':
print(
"""
(* KEEP, DONT_TOUCH *)
BUFR (
.I(clkfbout_mult_{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))
else:
assert False, clkfbin_src
clkin_is_none = False
for clkin in range(2):
clkin_src = random.choice((
'BUFH',
'BUFR',
'0',
'1',
None,
))
if clkin == 1 and clkin_is_none and clkin_src is None:
clkin_src = 'BUFH'
if clkin_src is None:
pass
elif clkin_src == 'BUFH':
print(
"""
(* KEEP, DONT_TOUCH *)
BUFH (
.O(clkin{idx}_{site})
);""".format(idx=clkin + 1, 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))
else:
assert False, clkfbin_src
print("endmodule")
if __name__ == '__main__':
main()