005-tilegrid: Extract frames count information from part's json

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
diff --git a/fuzzers/005-tilegrid/add_tdb.py b/fuzzers/005-tilegrid/add_tdb.py
index 9e3ab41..c2f3c22 100644
--- a/fuzzers/005-tilegrid/add_tdb.py
+++ b/fuzzers/005-tilegrid/add_tdb.py
@@ -123,6 +123,7 @@
         ("pcie_int_interface", int_frames, int_words),
     ]
 
+    tile_frames_map = localutil.TileFrames()
     for (subdir, frames, words) in tdb_fns:
         tdb_fn = os.path.join(
             subdir, 'build_{}'.format(os.environ['XRAY_PART']),
@@ -134,7 +135,8 @@
         for (tile, frame, wordidx) in load_db(tdb_fn):
             tilej = database[tile]
             verbose and print("Add %s %08X_%03u" % (tile, frame, wordidx))
-            localutil.add_tile_bits(tile, tilej, frame, wordidx, frames, words)
+            localutil.add_tile_bits(
+                tile, tilej, frame, wordidx, frames, words, tile_frames_map)
 
     # Save
     xjson.pprint(open(fn_out, "w"), database)
diff --git a/fuzzers/005-tilegrid/generate_full.py b/fuzzers/005-tilegrid/generate_full.py
index 7492ea4..4022edc 100644
--- a/fuzzers/005-tilegrid/generate_full.py
+++ b/fuzzers/005-tilegrid/generate_full.py
@@ -49,7 +49,8 @@
     return tiles_by_grid
 
 
-def propagate_INT_lr_bits(database, tiles_by_grid, verbose=False):
+def propagate_INT_lr_bits(
+        database, tiles_by_grid, tile_frames_map, verbose=False):
     '''Populate segment base addresses: L/R along INT column'''
 
     int_frames, int_words, _ = localutil.get_entry('INT', 'CLB_IO_CLK')
@@ -92,10 +93,10 @@
 
         localutil.add_tile_bits(
             other_tile, database[other_tile], baseaddr, offset, int_frames,
-            int_words)
+            int_words, tile_frames_map)
 
 
-def propagate_INT_bits_in_column(database, tiles_by_grid):
+def propagate_INT_bits_in_column(database, tiles_by_grid, tile_frames_map):
     """ Propigate INT offsets up and down INT columns.
 
     INT columns appear to be fairly regular, where starting from offset 0,
@@ -146,7 +147,7 @@
                 offset -= int_words
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    int_frames, int_words)
+                    int_frames, int_words, tile_frames_map)
             elif tile['type'].startswith('INT_'):
                 # INT above HCLK
                 assert next_tile_type.startswith(
@@ -155,7 +156,7 @@
                 offset -= hclk_words
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    hclk_frames, hclk_words)
+                    hclk_frames, hclk_words, tile_frames_map)
             else:
                 # HCLK above INT
                 assert tile['type'].startswith(
@@ -164,7 +165,7 @@
                     offset -= int_words
                     localutil.add_tile_bits(
                         next_tile, database[next_tile], baseaddr, offset,
-                        int_frames, int_words)
+                        int_frames, int_words, tile_frames_map)
                 else:
                     # Handle special case column where the PCIE tile is present.
                     assert next_tile_type in ['PCIE_NULL'], next_tile_type
@@ -195,7 +196,7 @@
                 offset += int_words
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    int_frames, int_words)
+                    int_frames, int_words, tile_frames_map)
             elif tile['type'].startswith('INT_'):
                 # INT below HCLK
                 assert next_tile_type.startswith(
@@ -204,7 +205,7 @@
                 offset += int_words
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    hclk_frames, hclk_words)
+                    hclk_frames, hclk_words, tile_frames_map)
             else:
                 # HCLK below INT
                 assert tile['type'].startswith(
@@ -215,14 +216,14 @@
                 offset += hclk_words
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    int_frames, int_words)
+                    int_frames, int_words, tile_frames_map)
 
             tile_name = next_tile
             tile = database[tile_name]
 
 
 def propagate_INT_INTERFACE_bits_in_column(
-        database, tiles_by_grid, int_interface_name):
+        database, tiles_by_grid, int_interface_name, tile_frames_map):
     """ Propagate INT_INTERFACE column for a given INT_INTERFACE tile name.
 
     INT_INTERFACE tiles do not usually have any PIPs or baseaddresses,
@@ -280,7 +281,7 @@
                 offset -= (int_words + extra_offset)
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    int_frames, int_words)
+                    int_frames, int_words, tile_frames_map)
 
             down_tile_name = next_tile
             down_tile = database[down_tile_name]
@@ -312,7 +313,7 @@
                 offset += (int_words + extra_offset)
                 localutil.add_tile_bits(
                     next_tile, database[next_tile], baseaddr, offset,
-                    int_frames, int_words)
+                    int_frames, int_words, tile_frames_map)
 
             up_tile_name = next_tile
             up_tile = database[up_tile_name]
@@ -549,12 +550,14 @@
     database = json.load(open(json_in_fn, "r"))
     tiles_by_grid = make_tiles_by_grid(database)
 
-    propagate_INT_lr_bits(database, tiles_by_grid, verbose=verbose)
-    propagate_INT_bits_in_column(database, tiles_by_grid)
+    tile_frames_map = localutil.TileFrames()
+    propagate_INT_lr_bits(
+        database, tiles_by_grid, tile_frames_map, verbose=verbose)
+    propagate_INT_bits_in_column(database, tiles_by_grid, tile_frames_map)
     propagate_INT_INTERFACE_bits_in_column(
-        database, tiles_by_grid, "GTP_INT_INTERFACE")
+        database, tiles_by_grid, "GTP_INT_INTERFACE", tile_frames_map)
     propagate_INT_INTERFACE_bits_in_column(
-        database, tiles_by_grid, "PCIE_INT_INTERFACE")
+        database, tiles_by_grid, "PCIE_INT_INTERFACE", tile_frames_map)
     propagate_rebuf(database, tiles_by_grid)
     propagate_IOB_SING(database, tiles_by_grid)
     propagate_IOI_SING(database, tiles_by_grid)
diff --git a/fuzzers/005-tilegrid/util.py b/fuzzers/005-tilegrid/util.py
index 421f7b3..0f65e00 100644
--- a/fuzzers/005-tilegrid/util.py
+++ b/fuzzers/005-tilegrid/util.py
@@ -10,11 +10,51 @@
 # 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 {
@@ -35,7 +75,14 @@
 
 
 def add_tile_bits(
-        tile_name, tile_db, baseaddr, offset, frames, words, verbose=False):
+        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
@@ -45,6 +92,17 @@
     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 specified for the tile {} ({}) exceeds the maximum allowed value ({}). Falling back to the maximum value."
+            .format(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, (