blob: 2226d40ef2577d669cb39fb40ee9b64f0a467ce2 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
from utils import xjson
def load_tiles(tiles_fn):
'''
"$type $tile $grid_x $grid_y $skip_tile $clock_region $typed_sites"
typed_sites: foreach t $site_types s $sites
'''
tiles = list()
with open(tiles_fn) as f:
for line in f:
# CLBLM_L CLBLM_L_X10Y98 30 106 SLICEL SLICE_X13Y98 SLICEM SLICE_X12Y98
record = line.split()
tile_type, tile_name, grid_x, grid_y, skip_tile = record[0:5]
grid_x, grid_y = int(grid_x), int(grid_y)
skip_tile = int(skip_tile) != 0
sites = {}
# prohibits is the list of sites that the Vivado placer will not
# place at.
#
# Speculation: These sites are prohibited not because the hardware
# doesn't work, but because the interconnect around these sites is
# extremely narrow due to the hardblocks to the left and right of
# tiles. As a result, these sites should be avoided because
# congestion and delays when using these sites might be very very
# high.
prohibits = []
clock_region = None
if len(record) >= 6:
clock_region = record[5]
if clock_region == "NA":
clock_region = None
for i in range(6, len(record), 3):
site_type, site_name, prohibited = record[i:i + 3]
sites[site_name] = site_type
if int(prohibited):
prohibits.append(site_name)
if not skip_tile:
tile = {
'type': tile_type,
'name': tile_name,
'grid_x': grid_x,
'grid_y': grid_y,
'sites': sites,
'prohibited_sites': sorted(prohibits),
'clock_region': clock_region,
}
else:
# Replace tiles within the exclude_roi with NULL tiles to
# ensure no gaps in the tilegrid.
#
# The name will reflect the original tile.
tile = {
'type': 'NULL',
'name': tile_name,
'grid_x': grid_x,
'grid_y': grid_y,
'sites': {},
'prohibited_sites': [],
'clock_region': clock_region,
}
tiles.append(tile)
return 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()
for tile in tiles:
database[tile["name"]] = {
"type": tile["type"],
"sites": tile["sites"],
"grid_x": tile["grid_x"],
"grid_y": tile["grid_y"],
"bits": {},
"pin_functions": {},
"prohibited_sites": tile['prohibited_sites'],
}
if tile["clock_region"]:
database[tile["name"]]["clock_region"] = tile["clock_region"]
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, 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, pin_func)
# Save
xjson.pprint(open(json_fn, 'w'), database)
def main():
import argparse
parser = argparse.ArgumentParser(
description='Generate tilegrid.json from bitstream deltas')
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',
required=True)
parser.add_argument(
'--pin_func', help='List of sites with pin functions', required=True)
args = parser.parse_args()
run(args.tiles, args.pin_func, args.out, verbose=args.verbose)
if __name__ == '__main__':
main()