| #!/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 |
| ''' |
| Generate a primitive to place at every I/O |
| Unlike CLB tests, the LFSR for this is inside the ROI, not driving it |
| ''' |
| |
| import os |
| import random |
| random.seed(int(os.getenv("SEED"), 16)) |
| from prjxray import util |
| from prjxray.db import Database |
| import re |
| |
| |
| def gen_sites(): |
| ''' |
| IOB18S: main IOB of a diff pair |
| IOB18M: secondary IOB of a diff pair |
| IOB18: not a diff pair. Relatively rare (at least in ROI...2 of them?) |
| Focus on IOB18S to start |
| ''' |
| db = Database(util.get_db_root(), util.get_part()) |
| grid = db.grid() |
| for tile_name in sorted(grid.tiles()): |
| loc = grid.loc_of_tilename(tile_name) |
| gridinfo = grid.gridinfo_at_loc(loc) |
| |
| sites = [] |
| for site_name, site_type in gridinfo.sites.items(): |
| if site_type == 'IDELAYE2_FINEDELAY': |
| sites.append(site_name) |
| |
| if len(sites) == 0: |
| continue |
| |
| sites_y = [ |
| int(re.match('IDELAY_X[0-9]+Y([0-9]+)', site).group(1)) |
| for site in sites |
| ] |
| |
| sites, _ = zip(*sorted(zip(sites, sites_y), key=lambda x: x[1])) |
| |
| if gridinfo.tile_type[0] == 'L': |
| int_grid_x = loc.grid_x + 3 |
| pad_grid_x = loc.grid_x - 1 |
| int_tile_type = 'INT_L' |
| else: |
| int_grid_x = loc.grid_x - 3 |
| pad_grid_x = loc.grid_x + 1 |
| int_tile_type = 'INT_R' |
| |
| int_tile_locs = [ |
| (int_grid_x, loc.grid_y), |
| ] |
| |
| pad_gridinfo = grid.gridinfo_at_loc((pad_grid_x, loc.grid_y)) |
| |
| pad_sites = pad_gridinfo.sites.keys() |
| pad_sites_y = [ |
| int(re.match('IOB_X[0-9]+Y([0-9]+)', site).group(1)) |
| for site in pad_sites |
| ] |
| pad_sites, _ = zip( |
| *sorted(zip(pad_sites, pad_sites_y), key=lambda x: x[1])) |
| |
| if not gridinfo.tile_type.endswith("_SING"): |
| int_tile_locs.append((int_grid_x, loc.grid_y - 1)) |
| |
| assert len(sites) == len(int_tile_locs), ( |
| tile_name, sites, int_tile_locs) |
| assert len(sites) == len(pad_sites), (sites, pad_sites) |
| |
| for site_name, pad_site, int_tile_loc in zip(sites, pad_sites, |
| int_tile_locs): |
| int_tile_name = grid.tilename_at_loc(int_tile_loc) |
| assert int_tile_name.startswith(int_tile_type), ( |
| int_tile_name, site_name, int_tile_loc) |
| yield int_tile_name, site_name, pad_site |
| |
| |
| def write_params(params): |
| pinstr = '' |
| for tile, (site, val, pad_site_name, pin) in sorted(params.items()): |
| pinstr += '%s,%s,%s,%s,%s\n' % (tile, val, site, pad_site_name, pin) |
| open('params.csv', 'w').write(pinstr) |
| |
| |
| def run(): |
| sites = list(gen_sites()) |
| print( |
| ''' |
| `define N_DI {} |
| |
| module top(input wire [`N_DI-1:0] di); |
| wire [`N_DI-1:0] di_buf; |
| |
| (* KEEP, DONT_TOUCH, IODELAY_GROUP = "iodelays" *) |
| IDELAYCTRL idelayctrl ( |
| .REFCLK() |
| ); |
| '''.format(len(sites))) |
| |
| params = {} |
| |
| for idx, ((tile_name, site_name, pad_site_name), isone) in enumerate(zip( |
| sites, util.gen_fuzz_states(len(sites)))): |
| params[tile_name] = (site_name, isone, pad_site_name, "di[%u]" % idx) |
| |
| # Force HARD0 -> GFAN1 with CNTVALUEIN4 = 0 |
| # Toggle 1 pip with CNTVALUEIN3 = ? |
| print( |
| ''' |
| |
| // Solving for {3} |
| (* KEEP, DONT_TOUCH *) |
| IBUF ibuf_{0}(.I(di[{2}]), .O(di_buf[{2}])); |
| |
| (* KEEP, DONT_TOUCH, LOC = "{0}", IODELAY_GROUP = "iodelays" *) |
| IDELAYE2 idelay_{0} ( |
| .CNTVALUEIN(5'b0{1}111), |
| .IDATAIN(di_buf[{2}]) |
| ); |
| '''.format(site_name, isone, idx, tile_name)) |
| |
| print("endmodule") |
| write_params(params) |
| |
| |
| if __name__ == '__main__': |
| run() |