| #!/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.segmaker import Segmaker |
| from prjxray.db import Database |
| from prjxray.util import get_db_root, get_part |
| import re |
| |
| REBUF_GCLK = re.compile('^CLK_BUFG_REBUF_R_CK_GCLK([0-9]+)_BOT$') |
| |
| GCLKS = 32 |
| |
| |
| def gclk_of_wire(wire): |
| m = REBUF_GCLK.match(wire) |
| assert m, wire |
| return int(m.group(1)) |
| |
| |
| class ClockColumn(object): |
| def __init__(self, db_root, part): |
| db = Database(db_root, part) |
| grid = db.grid() |
| |
| tiles_in_gclk_columns = [] |
| self.gclk_columns = {} |
| |
| for tile in grid.tiles(): |
| gridinfo = grid.gridinfo_at_tilename(tile) |
| |
| if gridinfo.tile_type != 'CLK_BUFG_REBUF': |
| continue |
| |
| loc = grid.loc_of_tilename(tile) |
| |
| tiles_in_gclk_columns.append((loc.grid_y, tile)) |
| |
| _, self.tiles_in_gclk_columns = zip( |
| *sorted(tiles_in_gclk_columns, key=lambda x: x[0])) |
| |
| # Initially all GCLK lines are idle. GCLK lines only exist between |
| #CLK_BUFG_REBUF tiles, hence len-1. |
| for gclk in range(GCLKS): |
| self.gclk_columns[gclk] = [ |
| False for _ in range(len(self.tiles_in_gclk_columns) - 1) |
| ] |
| |
| def enable_rebuf(self, tile, wire): |
| # Find which REBUF is being activated. |
| rebuf_idx = self.tiles_in_gclk_columns.index(tile) |
| assert rebuf_idx != -1, tile |
| |
| gclk = gclk_of_wire(wire) |
| |
| self.gclk_columns[gclk][rebuf_idx] = True |
| self.gclk_columns[gclk][rebuf_idx - 1] = True |
| |
| def yield_rebuf_state(self): |
| """ Yields tile_name, gclk, bool if active above tile, bool if active below tile """ |
| for idx, tile in enumerate(self.tiles_in_gclk_columns): |
| for gclk in range(GCLKS): |
| active_below = False |
| active_above = False |
| |
| if idx > 0: |
| active_below = self.gclk_columns[gclk][idx - 1] |
| |
| if idx < len(self.gclk_columns[gclk]): |
| active_above = self.gclk_columns[gclk][idx] |
| |
| yield tile, gclk, active_below, active_above |
| |
| |
| def main(): |
| db_root = get_db_root() |
| part = get_part() |
| |
| clock_column = ClockColumn(db_root, part) |
| |
| segmk = Segmaker("design.bits") |
| |
| print("Loading tags from design.txt.") |
| |
| with open("route.txt", "r") as f: |
| for line in f: |
| if 'CLK_BUFG_REBUF' not in line: |
| continue |
| |
| parts = line.replace('{', '').replace('}', '').strip().replace( |
| '\t', ' ').split(' ') |
| dst = parts[0] |
| pip = parts[3] |
| |
| tile_from_pip, pip = pip.split('/') |
| |
| if 'CLK_BUFG_REBUF' not in tile_from_pip: |
| continue |
| |
| tile_type, pip = pip.split('.') |
| assert tile_type == 'CLK_BUFG_REBUF' |
| |
| wire_a, wire_b = pip.split('<<->>') |
| |
| tile_from_wire, dst = dst.split('/') |
| |
| assert dst == wire_a |
| |
| if tile_from_wire == tile_from_pip: |
| b_to_a = wire_a == dst |
| a_to_b = not b_to_a |
| else: |
| b_to_a = wire_a != dst |
| a_to_b = not b_to_a |
| |
| segmk.add_tile_tag( |
| tile_from_pip, '{}.{}'.format(wire_a, wire_b), b_to_a) |
| segmk.add_tile_tag( |
| tile_from_pip, '{}.{}'.format(wire_b, wire_a), a_to_b) |
| |
| clock_column.enable_rebuf(tile_from_pip, wire_a) |
| |
| for tile, gclk, active_below, active_above in clock_column.yield_rebuf_state( |
| ): |
| segmk.add_tile_tag( |
| tile, 'GCLK{}_ENABLE_ABOVE'.format(gclk), active_above) |
| segmk.add_tile_tag( |
| tile, 'GCLK{}_ENABLE_BELOW'.format(gclk), active_below) |
| |
| segmk.compile() |
| segmk.write(allow_empty=True) |
| |
| |
| if __name__ == '__main__': |
| main() |