|  | #!/usr/bin/env python3 | 
|  | # -*- coding: utf-8 -*- | 
|  | # | 
|  | # Copyright (C) 2017-2023  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 | 
|  |  | 
|  | import os, random | 
|  | random.seed(int(os.getenv("SEED"), 16)) | 
|  |  | 
|  | import sys | 
|  | import json | 
|  |  | 
|  | from prjxray import util | 
|  | from prjxray.db import Database | 
|  |  | 
|  | # ============================================================================= | 
|  |  | 
|  |  | 
|  | def gen_sites(): | 
|  | db = Database(util.get_db_root(), util.get_part()) | 
|  | grid = db.grid() | 
|  |  | 
|  | tile_list = [] | 
|  | for tile_name in sorted(grid.tiles()): | 
|  | if "IOB18" not in tile_name or "SING" in tile_name: | 
|  | continue | 
|  | tile_list.append(tile_name) | 
|  |  | 
|  | get_xy = util.create_xy_fun('RIOB18_') | 
|  | tile_list.sort(key=get_xy) | 
|  |  | 
|  | for iob_tile_name in tile_list: | 
|  | iob_gridinfo = grid.gridinfo_at_loc( | 
|  | grid.loc_of_tilename(iob_tile_name)) | 
|  |  | 
|  | # Find IOI tile adjacent to IOB | 
|  | for suffix in ["IOI", "IOI_TBYTESRC", "IOI_TBYTETERM"]: | 
|  | try: | 
|  | ioi_tile_name = iob_tile_name.replace("IOB18", suffix) | 
|  | ioi_gridinfo = grid.gridinfo_at_loc( | 
|  | grid.loc_of_tilename(ioi_tile_name)) | 
|  | break | 
|  | except KeyError: | 
|  | pass | 
|  |  | 
|  | iob18s = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18S"][0] | 
|  | iob18m = [k for k, v in iob_gridinfo.sites.items() if v == "IOB18M"][0] | 
|  | odelay_s = iob18s.replace("IOB", "ODELAY") | 
|  | odelay_m = iob18m.replace("IOB", "ODELAY") | 
|  |  | 
|  | yield iob18m, odelay_m, iob18s, odelay_s | 
|  |  | 
|  |  | 
|  | def run(): | 
|  |  | 
|  | # Get all [LR]IOI3 tiles | 
|  | tiles = list(gen_sites()) | 
|  |  | 
|  | # Header | 
|  | print("// Tile count: %d" % len(tiles)) | 
|  | print("// Seed: '%s'" % os.getenv("SEED")) | 
|  |  | 
|  | ninputs = 0 | 
|  | do_idx = [] | 
|  | for i, sites in enumerate(tiles): | 
|  | if random.randint(0, 1): | 
|  | do_idx.append(ninputs) | 
|  | ninputs += 1 | 
|  | else: | 
|  | do_idx.append(None) | 
|  |  | 
|  | print( | 
|  | ''' | 
|  | module top ( | 
|  | (* CLOCK_BUFFER_TYPE = "NONE" *) | 
|  | input  wire clk, | 
|  | output wire [{N}:0] do | 
|  | ); | 
|  |  | 
|  | wire clk_buf = clk; | 
|  |  | 
|  | wire [{N}:0] do_buf; | 
|  | '''.format(N=ninputs - 1)) | 
|  |  | 
|  | # LOCes IOBs | 
|  | data = [] | 
|  | for i, (sites, obuf_idx) in enumerate(zip(tiles, do_idx)): | 
|  |  | 
|  | if random.randint(0, 1): | 
|  | iob_inuse     = sites[0] | 
|  | iob_other     = sites[2] | 
|  | odelay_inuse  = sites[1] | 
|  | odelay_other  = sites[3] | 
|  | else: | 
|  | iob_inuse     = sites[2] | 
|  | iob_other     = sites[0] | 
|  | odelay_inuse  = sites[3] | 
|  | odelay_other  = sites[1] | 
|  |  | 
|  | use_obuf = obuf_idx is not None | 
|  |  | 
|  | if not use_obuf: | 
|  | continue | 
|  |  | 
|  | params = { | 
|  | "LOC": | 
|  | "\"" + odelay_inuse + "\"", | 
|  | "ODELAY_TYPE": | 
|  | "\"" + random.choice( | 
|  | ["FIXED", "VARIABLE", "VAR_LOAD"]) + "\"", | 
|  | "ODELAY_VALUE": | 
|  | random.randint(0, 31), | 
|  | "HIGH_PERFORMANCE_MODE": | 
|  | "\"" + random.choice(["TRUE", "FALSE"]) + "\"", | 
|  | "CINVCTRL_SEL": | 
|  | "\"" + random.choice(["TRUE", "FALSE"]) + "\"", | 
|  | "PIPE_SEL": | 
|  | "\"" + random.choice(["TRUE", "FALSE"]) + "\"", | 
|  | "IS_C_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_ODATAIN_INVERTED": | 
|  | random.randint(0, 1), | 
|  | } | 
|  |  | 
|  | if params["ODELAY_TYPE"] != "\"VAR_LOAD_PIPE\"": | 
|  | params["PIPE_SEL"] = "\"FALSE\"" | 
|  |  | 
|  | # The datasheet says that for these two modes the delay is set to 0 | 
|  | if params["ODELAY_TYPE"] == "\"VAR_LOAD\"": | 
|  | params["ODELAY_VALUE"] = 0 | 
|  | if params["ODELAY_TYPE"] == "\"VAR_LOAD_PIPE\"": | 
|  | params["ODELAY_VALUE"] = 0 | 
|  |  | 
|  | if params["ODELAY_TYPE"] == "\"FIXED\"": | 
|  | params["IS_C_INVERTED"] = 0 | 
|  |  | 
|  | param_str = ",".join(".%s(%s)" % (k, v) for k, v in params.items()) | 
|  |  | 
|  | if random.randint(0, 5) == 0: | 
|  | print('') | 
|  | print('(* LOC="%s", KEEP, DONT_TOUCH *)' % iob_inuse) | 
|  | print( | 
|  | 'OBUF obuf_%03d (.I(%d), .O(do[%3d]));' % | 
|  | (obuf_idx, random.randint(0, 1), obuf_idx)) | 
|  | params['ODELAY_BYPASS'] = True | 
|  | params["ODELAY_NOT_IN_USE"] = odelay_inuse + " " + odelay_other | 
|  | else: | 
|  | print('') | 
|  | print('(* LOC="%s", KEEP, DONT_TOUCH *)' % iob_inuse) | 
|  | print( | 
|  | 'OBUF obuf_%03d (.I(do_buf[%3d]), .O(do[%3d]));' % | 
|  | (obuf_idx, obuf_idx, obuf_idx)) | 
|  | print( | 
|  | 'mod #(%s) mod_%03d (.clk(clk_buf), .O(do_buf[%3d]));' % | 
|  | (param_str, i, obuf_idx)) | 
|  | params['ODELAY_BYPASS'] = False | 
|  | params["ODELAY_IN_USE"] = odelay_inuse | 
|  | params["ODELAY_NOT_IN_USE"] = odelay_other | 
|  |  | 
|  | data.append(params) | 
|  |  | 
|  | # Store params | 
|  | with open("params.json", "w") as fp: | 
|  | json.dump(data, fp, sort_keys=True, indent=1) | 
|  |  | 
|  | print( | 
|  | ''' | 
|  | // IDELAYCTRL | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | IDELAYCTRL idelayctrl(); | 
|  |  | 
|  | endmodule | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | module mod( | 
|  | input  wire clk, | 
|  | output  wire O | 
|  | ); | 
|  |  | 
|  | parameter LOC = ""; | 
|  | parameter ODELAY_TYPE = "FIXED"; | 
|  | parameter ODELAY_VALUE = 0; | 
|  | parameter DELAY_SRC = "ODATAIN"; | 
|  | parameter HIGH_PERFORMANCE_MODE = "TRUE"; | 
|  | parameter SIGNAL_PATTERN = "DATA"; | 
|  | parameter CINVCTRL_SEL = "FALSE"; | 
|  | parameter PIPE_SEL = "FALSE"; | 
|  | parameter IS_C_INVERTED = 0; | 
|  | parameter IS_ODATAIN_INVERTED = 0; | 
|  |  | 
|  | wire x; | 
|  | wire lut; | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | LUT2 l( .O(lut) ); | 
|  |  | 
|  | // ODELAY | 
|  | (* LOC=LOC, KEEP, DONT_TOUCH *) | 
|  | ODELAYE2 #( | 
|  | .ODELAY_TYPE(ODELAY_TYPE), | 
|  | .ODELAY_VALUE(ODELAY_VALUE), | 
|  | .DELAY_SRC(DELAY_SRC), | 
|  | .HIGH_PERFORMANCE_MODE(HIGH_PERFORMANCE_MODE), | 
|  | .SIGNAL_PATTERN(SIGNAL_PATTERN), | 
|  | .CINVCTRL_SEL(CINVCTRL_SEL), | 
|  | .PIPE_SEL(PIPE_SEL), | 
|  | .IS_C_INVERTED(IS_C_INVERTED), | 
|  | .IS_ODATAIN_INVERTED(IS_ODATAIN_INVERTED) | 
|  | ) | 
|  | odelay | 
|  | ( | 
|  | .C(clk), | 
|  | .REGRST(), | 
|  | .LD(), | 
|  | .CE(), | 
|  | .INC(), | 
|  | .CINVCTRL(), | 
|  | .CNTVALUEIN(), | 
|  | .ODATAIN(lut), | 
|  | .LDPIPEEN(), | 
|  | .DATAOUT(O), | 
|  | .CNTVALUEOUT() | 
|  | ); | 
|  |  | 
|  | endmodule | 
|  | ''') | 
|  |  | 
|  |  | 
|  | run() |