From 30648d554ac0edf61308f1eabc89538182bd701f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 2 Jul 2019 18:22:34 -0700 Subject: [PATCH] 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> --- fuzzers/005-tilegrid/add_tdb.py | 2 +- fuzzers/005-tilegrid/pll/Makefile | 2 +- fuzzers/032-cmt-pll/Makefile | 4 +- fuzzers/032-cmt-pll/generate.py | 88 +++++-- fuzzers/032-cmt-pll/top.py | 80 ++++-- fuzzers/032-cmt-pll/write_pll_reg.py | 52 +++- fuzzers/034-cmt-pll-pips/Makefile | 51 ++++ fuzzers/034-cmt-pll-pips/bits.dbf | 0 fuzzers/034-cmt-pll-pips/cmt_top_upper_t.tcl | 29 +++ fuzzers/034-cmt-pll-pips/generate.py | 106 ++++++++ fuzzers/034-cmt-pll-pips/generate.tcl | 57 +++++ fuzzers/034-cmt-pll-pips/top.py | 242 +++++++++++++++++++ 12 files changed, 660 insertions(+), 53 deletions(-) create mode 100644 fuzzers/034-cmt-pll-pips/Makefile create mode 100644 fuzzers/034-cmt-pll-pips/bits.dbf create mode 100644 fuzzers/034-cmt-pll-pips/cmt_top_upper_t.tcl create mode 100644 fuzzers/034-cmt-pll-pips/generate.py create mode 100644 fuzzers/034-cmt-pll-pips/generate.tcl create mode 100644 fuzzers/034-cmt-pll-pips/top.py diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py index b893bd30..97566508 100644 --- a/fuzzers/005-tilegrid/add_tdb.py +++ b/fuzzers/005-tilegrid/add_tdb.py @@ -79,7 +79,7 @@ def run(fn_in, fn_out, verbose=False): ("iob/build/segbits_tilegrid.tdb", 42, 4), ("ioi/build/segbits_tilegrid.tdb", 42, 4), ("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), ("bram/build/segbits_tilegrid.tdb", 28, 10), ("bram_block/build/segbits_tilegrid.tdb", 128, 10), diff --git a/fuzzers/005-tilegrid/pll/Makefile b/fuzzers/005-tilegrid/pll/Makefile index 004495bc..0d8e4d19 100644 --- a/fuzzers/005-tilegrid/pll/Makefile +++ b/fuzzers/005-tilegrid/pll/Makefile @@ -1,3 +1,3 @@ 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 diff --git a/fuzzers/032-cmt-pll/Makefile b/fuzzers/032-cmt-pll/Makefile index 46345118..726d9f34 100644 --- a/fuzzers/032-cmt-pll/Makefile +++ b/fuzzers/032-cmt-pll/Makefile @@ -1,12 +1,10 @@ -# read/write width is relatively slow to resolve -# Even slower with multi bit masks... N := 50 include ../fuzzer.mk database: build/segbits_cmt_top_upper_t.db 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_l_upper_t.txt,$(SPECIMENS)) diff --git a/fuzzers/032-cmt-pll/generate.py b/fuzzers/032-cmt-pll/generate.py index 8490180a..c358070a 100644 --- a/fuzzers/032-cmt-pll/generate.py +++ b/fuzzers/032-cmt-pll/generate.py @@ -7,6 +7,9 @@ from prjxray import verilog def bitfilter(frame, word): + if frame < 28: + return False + if frame == 25 and word == 3121: return False @@ -14,12 +17,14 @@ def bitfilter(frame, word): def bus_tags(segmk, ps, site): + segmk.add_site_tag(site, 'IN_USE', ps['active']) + + if not ps['active']: + return + for k in ps: 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 [ ('RST', 1), ('PWRDWN', 1), @@ -32,18 +37,72 @@ def bus_tags(segmk, ps, site): else: segmk.add_site_tag(site, 'INV_' + reg, ps[opt]) - for opt in ['OPTIMIZED', 'HIGH', 'LOW']: if verilog.unquote(ps['BANDWIDTH']) == opt: - segmk.add_site_tag( - site, 'BANDWIDTH.' + opt, - 1) + segmk.add_site_tag(site, 'BANDWIDTH.' + opt, 1) elif verilog.unquote(ps['BANDWIDTH']) == 'LOW': - segmk.add_site_tag( - site, 'BANDWIDTH.' + opt, - 0) + segmk.add_site_tag(site, 'BANDWIDTH.' + opt, 0) 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': segmk.add_site_tag( site, 'TOP.COMPENSATION.' + opt, @@ -56,14 +115,9 @@ def bus_tags(segmk, ps, site): site, 'COMPENSATION.Z_' + 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( - site, 'COMPENSATION.BUF_IN_OR_EXTERNAL', - verilog.unquote(ps['COMPENSATION']) in ['BUF_IN', 'EXTERNAL']) + site, 'COMPENSATION.INTERNAL', + verilog.unquote(ps['COMPENSATION']) in ['INTERNAL']) for param in ['CLKFBOUT_MULT']: paramadj = int(ps[param]) diff --git a/fuzzers/032-cmt-pll/top.py b/fuzzers/032-cmt-pll/top.py index 657e8fbb..096bde34 100644 --- a/fuzzers/032-cmt-pll/top.py +++ b/fuzzers/032-cmt-pll/top.py @@ -29,27 +29,43 @@ def main(): params = { "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", "clk", - )), - "dwe_conn": random.choice(( + )), + "dwe_conn": + random.choice(( "", "1", "0", "dwe_" + site, "den_" + site, - )), - "den_conn": random.choice(( + )), + "den_conn": + random.choice(( "", "1", "0", "den_" + site, - )), - "daddr4_conn": random.choice(( + )), + "daddr4_conn": + random.choice(( "0", "dwe_" + site, - )), + )), "IS_RST_INVERTED": random.randint(0, 1), "IS_PWRDWN_INVERTED": @@ -85,15 +101,34 @@ def main(): 'INTERNAL', ))), "BANDWIDTH": - verilog.quote( - random.choice(( - 'OPTIMIZED', - 'HIGH', - 'LOW', - ))), + verilog.quote(random.choice(( + 'OPTIMIZED', + 'HIGH', + '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))) + if not params['active']: + continue + print( """ @@ -109,6 +144,7 @@ def main(): ); wire clkfbout_mult_{site}; + wire clkfbout_mult_BUFG_{site}; wire clkout0_{site}; wire clkout1_{site}; wire clkout2_{site}; @@ -131,7 +167,9 @@ def main(): .STARTUP_WAIT({STARTUP_WAIT}), .CLKOUT0_DUTY_CYCLE({CLKOUT0_DUTY_CYCLE}), .COMPENSATION({COMPENSATION}), - .BANDWIDTH({BANDWIDTH}) + .BANDWIDTH({BANDWIDTH}), + .CLKIN1_PERIOD(10.0), + .CLKIN2_PERIOD(10.0) ) pll_{site} ( .CLKFBOUT(clkfbout_mult_{site}), .CLKOUT0(clkout0_{site}), @@ -143,9 +181,9 @@ def main(): .DRDY(), .LOCKED(), .DO(), - .CLKFBIN(), - .CLKIN1(clk), - .CLKIN2(), + .CLKFBIN({clkfbin_conn}), + .CLKIN1({clkin1_conn}), + .CLKIN2({clkin2_conn}), .CLKINSEL(), .DCLK({dclk_conn}), .DEN({den_conn}), @@ -155,6 +193,12 @@ def main(): .DI(), .DADDR({{7{{ {daddr4_conn} }} }})); + (* KEEP, DONT_TOUCH *) + BUFG bufg_{site} ( + .I(clkfbout_mult_{site}), + .O(clkfbout_mult_BUFG_{site}) + ); + (* KEEP, DONT_TOUCH *) FDRE reg_clkfbout_mult_{site} ( .C(clkfbout_mult_{site}) diff --git a/fuzzers/032-cmt-pll/write_pll_reg.py b/fuzzers/032-cmt-pll/write_pll_reg.py index 49fdab5c..439e2931 100644 --- a/fuzzers/032-cmt-pll/write_pll_reg.py +++ b/fuzzers/032-cmt-pll/write_pll_reg.py @@ -4,9 +4,7 @@ REGISTER_LAYOUT = { 'CLKOUT1': [ ('LOW_TIME', 6), ('HIGH_TIME', 6), - # This bit is the output enable bit, which is being detected as a pip - # bit, which is roughly correct. Leave this bit as a pip bit. - (None, 1), + ('OUTPUT_ENABLE', 1), ('PHASE_MUX', 3), ], 'CLKOUT2': [ @@ -60,11 +58,20 @@ REGISTER_LAYOUT = { ], 'POWER_REG': [ ('POWER_REG', 16), - ] + ], } +BASE_OFFSET = 0x00 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 for output in ['CLKOUT5', 'CLKOUT0', 'CLKOUT1', 'CLKOUT2', 'CLKOUT3', 'CLKOUT4', None, 'CLKFBOUT']: @@ -96,17 +103,24 @@ for _ in range(0x4E - 0x28 - 1): REGISTER_MAP.append(('FILTREG1', 'FILTREG1')) REGISTER_MAP.append(('FILTREG2', 'FILTREG2')) +for _ in range(0x20): + REGISTER_MAP.append(None) + class RegisterAddress(object): def __init__(self, frame_offsets, bit_offset): self.frame_index = 0 self.frame_offsets = frame_offsets self.bit_offset = bit_offset + self.bits_used = set() - def next_bit(self): + def next_bit(self, used=True): output = '{}_{}'.format( self.frame_offsets[self.frame_index], self.bit_offset) + if used: + self.bits_used.add(output) + self.frame_index += 1 if self.frame_index >= len(self.frame_offsets): 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]' bit_offset = None + in_use = None with open(seg_in, 'r') as f: for l in f: if l.startswith(base_offset_register): @@ -140,10 +155,15 @@ def passthrough_non_register_segbits(seg_in): assert frame_offset == 28 assert bit_index > 3 - bit_offset = bit_index - 3 + bit_offset = bit_index - 3 - 16 * 3 continue + if 'IN_USE' in l: + assert in_use is None + in_use = l.strip() + continue + parts = l.split() feature_parts = parts[0].split('.') @@ -177,10 +197,11 @@ def passthrough_non_register_segbits(seg_in): print(l.strip()) 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. 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): if register is None: for _ in range(16): - reg.next_bit() + reg.next_bit(used=False) continue layout, register_name = register @@ -209,7 +230,7 @@ def output_registers(bit_offset): bit_count += 1 if field is None: - reg.next_bit() + reg.next_bit(used=False) continue print( @@ -222,7 +243,7 @@ def output_registers(bit_offset): bit_count += 1 if field is None: - reg.next_bit() + reg.next_bit(used=False) continue print( @@ -241,6 +262,11 @@ def output_registers(bit_offset): 'CMT_UPPER_T.PLLE2.{}[{}] {}'.format( 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(): parser = argparse.ArgumentParser(description="") @@ -249,9 +275,9 @@ def main(): 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__": diff --git a/fuzzers/034-cmt-pll-pips/Makefile b/fuzzers/034-cmt-pll-pips/Makefile new file mode 100644 index 00000000..0d8fd30b --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/Makefile @@ -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 diff --git a/fuzzers/034-cmt-pll-pips/bits.dbf b/fuzzers/034-cmt-pll-pips/bits.dbf new file mode 100644 index 00000000..e69de29b diff --git a/fuzzers/034-cmt-pll-pips/cmt_top_upper_t.tcl b/fuzzers/034-cmt-pll-pips/cmt_top_upper_t.tcl new file mode 100644 index 00000000..26a4d368 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/cmt_top_upper_t.tcl @@ -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 diff --git a/fuzzers/034-cmt-pll-pips/generate.py b/fuzzers/034-cmt-pll-pips/generate.py new file mode 100644 index 00000000..0b6243f3 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/generate.py @@ -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() diff --git a/fuzzers/034-cmt-pll-pips/generate.tcl b/fuzzers/034-cmt-pll-pips/generate.tcl new file mode 100644 index 00000000..502a0ec2 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/generate.tcl @@ -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 diff --git a/fuzzers/034-cmt-pll-pips/top.py b/fuzzers/034-cmt-pll-pips/top.py new file mode 100644 index 00000000..c26cba32 --- /dev/null +++ b/fuzzers/034-cmt-pll-pips/top.py @@ -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()