From c0b8aef3a96b36565fc9cc3ab062304a5aec4b83 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Mon, 14 Oct 2019 16:38:02 -0700 Subject: [PATCH] Add pin functions to tilegrid. - Add support to emit PUDC_B pullup if unused (for A7 and Z7 fabrics). Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fuzzers/005-tilegrid/Makefile | 1 + fuzzers/005-tilegrid/generate.py | 35 ++++++++++-- fuzzers/005-tilegrid/generate_tiles.tcl | 7 +++ prjxray/fasm_assembler.py | 7 +++ prjxray/grid.py | 1 + prjxray/grid_types.py | 2 +- utils/fasm2frames.py | 76 ++++++++++++++++++++++++- 7 files changed, 121 insertions(+), 8 deletions(-) diff --git a/fuzzers/005-tilegrid/Makefile b/fuzzers/005-tilegrid/Makefile index 6dace887..0e4a9717 100644 --- a/fuzzers/005-tilegrid/Makefile +++ b/fuzzers/005-tilegrid/Makefile @@ -49,6 +49,7 @@ build/basicdb/tilegrid.json: generate.py build/tiles/tiles.txt mkdir -p build/basicdb cd build && python3 ${FUZDIR}/generate.py \ --tiles $(FUZDIR)/build/tiles/tiles.txt \ + --pin_func $(FUZDIR)/build/tiles/pin_func.txt \ --out ${BUILD_DIR}/basicdb/tilegrid.json clb/build/segbits_tilegrid.tdb: build/basicdb/tilegrid.json diff --git a/fuzzers/005-tilegrid/generate.py b/fuzzers/005-tilegrid/generate.py index 86704caa..430c26cb 100644 --- a/fuzzers/005-tilegrid/generate.py +++ b/fuzzers/005-tilegrid/generate.py @@ -32,7 +32,19 @@ def load_tiles(tiles_fn): return tiles -def make_database(tiles): +def load_pin_functions(pin_func_fn): + pin_functions = {} + + with open(pin_func_fn) as f: + for line in f: + site, pin_func = line.split() + assert site not in pin_functions, site + pin_functions[site] = pin_func + + return pin_functions + + +def make_database(tiles, pin_func): # tile database with X, Y, and list of sites # tile name as keys database = dict() @@ -44,17 +56,25 @@ def make_database(tiles): "grid_x": tile["grid_x"], "grid_y": tile["grid_y"], "bits": {}, + "pin_functions": {}, } + for site in database[tile["name"]]["sites"]: + if site in pin_func: + database[tile["name"]]["pin_functions"][site] = pin_func[site] + return database -def run(tiles_fn, json_fn, verbose=False): +def run(tiles_fn, pin_func_fn, json_fn, verbose=False): # Load input files tiles = load_tiles(tiles_fn) + # Read site map + pin_func = load_pin_functions(pin_func_fn) + # Index input - database = make_database(tiles) + database = make_database(tiles, pin_func) # Save xjson.pprint(open(json_fn, 'w'), database) @@ -69,10 +89,15 @@ def main(): parser.add_argument('--verbose', action='store_true', help='') parser.add_argument('--out', default='/dev/stdout', help='Output JSON') parser.add_argument( - '--tiles', default='tiles.txt', help='Input tiles.txt tcl output') + '--tiles', + default='tiles.txt', + help='Input tiles.txt tcl output', + required=True) + parser.add_argument( + '--pin_func', help='List of sites with pin functions', required=True) args = parser.parse_args() - run(args.tiles, args.out, verbose=args.verbose) + run(args.tiles, args.pin_func, args.out, verbose=args.verbose) if __name__ == '__main__': diff --git a/fuzzers/005-tilegrid/generate_tiles.tcl b/fuzzers/005-tilegrid/generate_tiles.tcl index 9e2f9baf..6ab62f76 100644 --- a/fuzzers/005-tilegrid/generate_tiles.tcl +++ b/fuzzers/005-tilegrid/generate_tiles.tcl @@ -6,6 +6,7 @@ proc write_tiles_txt {} { # Write tiles.txt with site metadata set fp [open "tiles.txt" w] + set fp_pin [open "pin_func.txt" w] foreach tile $tiles { set type [get_property TYPE $tile] set grid_x [get_property GRID_POINT_X $tile] @@ -17,11 +18,17 @@ proc write_tiles_txt {} { set site_types [get_property SITE_TYPE $sites] foreach t $site_types s $sites { lappend typed_sites $t $s + + set package_pin [get_package_pins -of $s -quiet] + if [llength $package_pin] { + puts $fp_pin "$s [get_property PIN_FUNC $package_pin]" + } } } puts $fp "$type $tile $grid_x $grid_y $typed_sites" } + close $fp_pin close $fp } diff --git a/prjxray/fasm_assembler.py b/prjxray/fasm_assembler.py index 4b55fca6..5980ebb4 100644 --- a/prjxray/fasm_assembler.py +++ b/prjxray/fasm_assembler.py @@ -27,6 +27,11 @@ class FasmAssembler(object): self.frames = {} self.frames_line = {} + self.feature_callback = lambda feature: None + + def set_feature_callback(self, feature_callback): + self.feature_callback = feature_callback + def get_frames(self, sparse=False): if not sparse: frames = self.frames_init() @@ -138,6 +143,8 @@ class FasmAssembler(object): if not line.set_feature: return + self.feature_callback(line.set_feature) + line_strs = tuple(fasm.fasm_line_to_string(line)) assert len(line_strs) == 1 line_str = line_strs[0] diff --git a/prjxray/grid.py b/prjxray/grid.py index b7246713..a751e966 100644 --- a/prjxray/grid.py +++ b/prjxray/grid.py @@ -50,6 +50,7 @@ class Grid(object): bits=bits, sites=tileinfo['sites'], tile_type=tileinfo['type'], + pin_functions=tileinfo.get('pin_functions', {}), ) x, y = zip(*self.loc.keys()) diff --git a/prjxray/grid_types.py b/prjxray/grid_types.py index 92062596..04c9beb8 100644 --- a/prjxray/grid_types.py +++ b/prjxray/grid_types.py @@ -11,7 +11,7 @@ class BlockType(enum.Enum): GridLoc = namedtuple('GridLoc', 'grid_x grid_y') -GridInfo = namedtuple('GridInfo', 'bits sites tile_type') +GridInfo = namedtuple('GridInfo', 'bits sites tile_type pin_functions') BitAlias = namedtuple('BitAlias', 'tile_type start_offset sites') Bits = namedtuple('Bits', 'base_address frames offset words alias') BitsInfo = namedtuple('BitsInfo', 'block_type tile bits') diff --git a/utils/fasm2frames.py b/utils/fasm2frames.py index f94060f1..c36fbc13 100755 --- a/utils/fasm2frames.py +++ b/utils/fasm2frames.py @@ -54,10 +54,56 @@ def dump_frm(f, frames): '0x%08X ' % addr + ','.join(['0x%08X' % w for w in words]) + '\n') -def run(db_root, filename_in, f_out, sparse=False, roi=None, debug=False): +def find_pudc_b(db): + """ Find PUDC_B pin func in grid, and return the tile and site prefix. + + The PUDC_B pin is a special 7-series pin that controls unused pin pullup. + + If the PUDC_B is unused, it is configured as an input with a PULLUP. + + """ + grid = db.grid() + + pudc_b_tile_site = None + for tile in grid.tiles(): + gridinfo = grid.gridinfo_at_tilename(tile) + + for site, pin_function in gridinfo.pin_functions.items(): + if 'PUDC_B' in pin_function: + assert pudc_b_tile_site == None, ( + pudc_b_tile_site, (tile, site)) + iob_y = int(site[-1]) % 2 + + pudc_b_tile_site = (tile, 'IOB_Y{}'.format(iob_y)) + + return pudc_b_tile_site + + +def run( + db_root, + filename_in, + f_out, + sparse=False, + roi=None, + debug=False, + emit_pudc_b_pullup=False): db = Database(db_root) assembler = fasm_assembler.FasmAssembler(db) + if emit_pudc_b_pullup: + pudc_b_in_use = False + pudc_b_tile_site = find_pudc_b(db) + + def check_for_pudc_b(set_feature): + parts = set_feature.feature.split('.') + + if parts[0] == pudc_b_tile_site[0] and parts[ + 1] == pudc_b_tile_site[1]: + nonlocal pudc_b_in_use + pudc_b_in_use = True + + assembler.set_feature_callback(check_for_pudc_b) + extra_features = [] if roi: with open(roi) as f: @@ -74,6 +120,27 @@ def run(db_root, filename_in, f_out, sparse=False, roi=None, debug=False): '\n'.join(roi_j['required_features'])) assembler.parse_fasm_filename(filename_in, extra_features=extra_features) + + if emit_pudc_b_pullup and not pudc_b_in_use: + # Enable IN-only and PULLUP on PUDC_B IOB. + # + # TODO: The following FASM string only works on Artix 50T and Zynq 10 + # fabrics. It is known to be wrong for the K70T fabric, but it is + # unclear how to know which IOSTANDARD to use. + missing_features = [] + for line in fasm.parse_fasm_string(""" +{tile}.{site}.LVCMOS12_LVCMOS15_LVCMOS18_LVCMOS25_LVCMOS33_LVTTL_SSTL135.IN_ONLY +{tile}.{site}.LVCMOS25_LVCMOS33_LVTTL.IN +{tile}.{site}.PULLTYPE.PULLUP +""".format( + tile=pudc_b_tile_site[0], + site=pudc_b_tile_site[1], + )): + assembler.add_fasm_line(line, missing_features) + + if missing_features: + raise fasm_assembler.FasmLookupError('\n'.join(missing_features)) + frames = assembler.get_frames(sparse=sparse) if debug: @@ -103,6 +170,10 @@ def main(): parser.add_argument( '--roi', help="ROI design.json file defining which tiles are within the ROI.") + parser.add_argument( + '--emit_pudc_b_pullup', + help="Emit an IBUF and PULLUP on the PUDC_B pin if unused", + action='store_true') parser.add_argument( '--debug', action='store_true', help="Print debug dump") parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file') @@ -119,7 +190,8 @@ def main(): f_out=open(args.fn_out, 'w'), sparse=args.sparse, roi=args.roi, - debug=args.debug) + debug=args.debug, + emit_pudc_b_pullup=args.emit_pudc_b_pullup) if __name__ == '__main__':