#!/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 prjxray import util import os import json ''' Local utils script to hold shared code of the 005-tilegrid fuzzer scripts ''' class TileFrames: """ Class for getting the number of frames used for configuring a tile with the specified baseaddress using the information from the part's json file """ def __init__(self): self.tile_address_to_frames = dict() def get_baseaddress(self, region, bus, row, column): assert bus == 'BLOCK_RAM' or bus == 'CLB_IO_CLK', 'Incorrect block type' address = (row << 17) + (column << 7) + ( (1 << 22) if region == 'bottom' else 0) + ( (1 << 23) if bus == 'BLOCK_RAM' else 0) return address def initialize_address_to_frames(self): with open(os.path.join(os.getenv('XRAY_FAMILY_DIR'), os.getenv('XRAY_PART'), 'part.json')) as pf: part_json = json.load(pf) for clock_region, rows in part_json['global_clock_regions'].items(): for row, buses in rows['rows'].items(): for bus, columns in buses['configuration_buses'].items(): for column, frames in columns[ 'configuration_columns'].items(): address = self.get_baseaddress( clock_region, bus, int(row), int(column)) assert address not in self.tile_address_to_frames self.tile_address_to_frames[address] = frames[ 'frame_count'] def get_tile_frames(self, baseaddress): if len(self.tile_address_to_frames) == 0: self.initialize_address_to_frames() assert baseaddress in self.tile_address_to_frames, "Base address not found in the part's json file" return self.tile_address_to_frames[baseaddress] def get_entry(tile_type, block_type): """ Get frames and words for a given tile_type (e.g. CLBLL) and block_type (CLB_IO_CLK, BLOCK_RAM, etc). """ return { # (tile_type, block_type): (frames, words, height) ("CLBLL", "CLB_IO_CLK"): (36, 2, None), ("CLBLM", "CLB_IO_CLK"): (36, 2, None), ("HCLK", "CLB_IO_CLK"): (26, 1, None), ("INT", "CLB_IO_CLK"): (28, 2, None), ("BRAM", "CLB_IO_CLK"): (28, 10, None), ("BRAM", "BLOCK_RAM"): (128, 10, None), ("DSP", "CLB_IO_CLK"): (28, 2, None), }.get((tile_type, block_type), None) def get_int_params(): int_frames, int_words, _ = get_entry('INT', 'CLB_IO_CLK') return int_frames, int_words def add_tile_bits( tile_name, tile_db, baseaddr, offset, frames, words, tile_frames, verbose=False): ''' Record data structure geometry for the given tile baseaddr For most tiles there is only one baseaddr, but some like BRAM have multiple Notes on multiple block types: https://github.com/SymbiFlow/prjxray/issues/145 ''' bits = tile_db['bits'] block_type = util.addr2btype(baseaddr) # Extract the information about the maximal number of frames from the part's json max_frames = tile_frames.get_tile_frames(baseaddr) if frames > max_frames: print( "Warning: The number of frames for base address {} specified for the tile {} ({}) exceeds the maximum allowed value ({}). Falling back to the maximum value." .format(hex(baseaddr), tile_name, frames, max_frames)) frames = max_frames # If frames count is None then use the maximum if frames is None: frames = max_frames assert offset <= 100, (tile_name, offset) # Few rare cases at X=0 for double width tiles split in half => small negative offset assert offset >= 0 or "IOB" in tile_name, ( tile_name, hex(baseaddr), offset) assert 1 <= words <= 101, words assert offset + words <= 101, ( tile_name, offset + words, offset, words, block_type) is_xc7k480t = 'xc7k480t' in os.environ['XRAY_PART'] baseaddr_str = '0x%08X' % baseaddr block = bits.get(block_type, None) if block is not None: done = True verbose and print( "%s: existing defintion for %s" % (tile_name, block_type)) assert block["baseaddr"] == baseaddr_str assert block["frames"] == frames, (block, frames) # TODO: HACK: some of the offsets of the K480T seem to be messed up # using the maximum offset below seems to make most sense when looking # at the preceding blocks if is_xc7k480t: if not block["offset"] == offset: print("XXX Hack: %s; orig offset %s, new %s" % (tile_name, block["offset"], offset)) offset = max(block['offset'], offset) print("XXX Hack: using offset {offset}") done = False else: assert block["offset"] == offset, "%s; orig offset %s, new %s" % ( - tile_name, block["offset"], offset) assert block["words"] == words if done: return block = bits.setdefault(block_type, {}) # FDRI address block["baseaddr"] = baseaddr_str # Number of frames this entry is sretched across # that is the following FDRI addresses are used: range(baseaddr, baseaddr + frames) block["frames"] = frames # Index of first word used within each frame block["offset"] = offset # Number of words used by tile. block["words"] = words