| #!/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 |
| |
| import json |
| import os |
| import random |
| from collections import namedtuple |
| |
| random.seed(int(os.getenv("SEED"), 16)) |
| from prjxray import util |
| from prjxray import verilog |
| from prjxray.lut_maker import LutMaker |
| from prjxray.db import Database |
| |
| INT = "INT" |
| BIN = "BIN" |
| |
| |
| def gen_sites(tile, site, filter_cmt=None): |
| 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) |
| |
| if tile not in gridinfo.tile_type: |
| continue |
| else: |
| tile_type = gridinfo.tile_type |
| |
| for site_name, site_type in gridinfo.sites.items(): |
| if site_type != site: |
| continue |
| |
| cmt = gridinfo.clock_region |
| |
| if filter_cmt is not None and cmt != filter_cmt: |
| continue |
| |
| yield tile_name, tile_type, site_name, cmt |
| |
| |
| def main(): |
| print( |
| ''' |
| module top( |
| input wire in, |
| output wire out |
| ); |
| |
| assign out = in; |
| ''') |
| |
| luts = LutMaker() |
| |
| params_dict = {"tile_type": None} |
| params_list = list() |
| |
| clkswing_cfg_tiles = dict() |
| ibufds_out_wires = dict() |
| for tile_name, _, site_name, _ in gen_sites("GTX_COMMON", "IBUFDS_GTE2"): |
| # Both the IBUFDS_GTE2 in the same tile need to have |
| # the same CLKSWING_CFG parameter |
| if tile_name not in clkswing_cfg_tiles: |
| clkswing_cfg = random.randint(0, 3) |
| clkswing_cfg_tiles[tile_name] = clkswing_cfg |
| else: |
| clkswing_cfg = clkswing_cfg_tiles[tile_name] |
| |
| in_use = bool(random.randint(0, 9)) |
| params = { |
| "site": |
| site_name, |
| "tile": |
| tile_name, |
| "IN_USE": |
| in_use, |
| "CLKRCV_TRST": |
| verilog.quote("TRUE" if random.randint(0, 1) else "FALSE"), |
| "CLKCM_CFG": |
| verilog.quote("TRUE" if random.randint(0, 1) else "FALSE"), |
| "CLKSWING_CFG": |
| clkswing_cfg, |
| } |
| |
| if in_use: |
| ibufds_out_wire = "{}_O".format(site_name) |
| |
| if tile_name not in ibufds_out_wires: |
| ibufds_out_wires[tile_name] = list() |
| |
| ibufds_out_wires[tile_name].append( |
| (ibufds_out_wire, int(site_name[-1]) % 2)) |
| |
| print("wire {};".format(ibufds_out_wire)) |
| print("(* KEEP, DONT_TOUCH, LOC=\"{}\" *)".format(site_name)) |
| print( |
| """ |
| IBUFDS_GTE2 #( |
| .CLKRCV_TRST({CLKRCV_TRST}), |
| .CLKCM_CFG({CLKCM_CFG}), |
| .CLKSWING_CFG({CLKSWING_CFG}) |
| ) {site} ( |
| .O({out}) |
| );""".format(**params, out=ibufds_out_wire)) |
| |
| params_list.append(params) |
| |
| DRP_PORTS = [ |
| ("DRPCLK", "clk"), ("DRPEN", "in"), ("DRPWE", "in"), ("DRPRDY", "out") |
| ] |
| |
| for tile_name, tile_type, site_name, cmt in gen_sites("GTX_COMMON", |
| "GTXE2_COMMON"): |
| |
| params_dict["tile_type"] = tile_type |
| |
| params = dict() |
| params['site'] = site_name |
| params['tile'] = tile_name |
| |
| verilog_attr = "" |
| |
| verilog_attr = "#(" |
| |
| fuz_dir = os.getenv("FUZDIR", None) |
| assert fuz_dir |
| with open(os.path.join(fuz_dir, "attrs.json"), "r") as attrs_file: |
| attrs = json.load(attrs_file) |
| |
| in_use = bool(random.randint(0, 9)) |
| params["IN_USE"] = in_use |
| |
| if in_use: |
| for param, param_info in attrs.items(): |
| param_type = param_info["type"] |
| param_values = param_info["values"] |
| param_digits = param_info["digits"] |
| |
| if param_type == INT: |
| value = random.choice(param_values) |
| value_str = value |
| else: |
| assert param_type == BIN |
| value = random.randint(0, param_values[0]) |
| value_str = "{digits}'b{value:0{digits}b}".format( |
| value=value, digits=param_digits) |
| |
| params[param] = value |
| |
| verilog_attr += """ |
| .{}({}),""".format(param, value_str) |
| |
| verilog_ports = "" |
| |
| for param in ["QPLLLOCKDETCLK", "DRPCLK"]: |
| is_inverted = random.randint(0, 1) |
| |
| params[param] = is_inverted |
| |
| verilog_attr += """ |
| .IS_{}_INVERTED({}),""".format(param, is_inverted) |
| verilog_ports += """ |
| .{}({}),""".format(param, luts.get_next_output_net()) |
| |
| verilog_attr = verilog_attr.rstrip(",") |
| verilog_attr += "\n)" |
| |
| for param in ["GTREFCLK0_USED", "GTREFCLK1_USED", |
| "BOTH_GTREFCLK_USED"]: |
| params[param] = 0 |
| |
| if tile_name in ibufds_out_wires: |
| gtrefclk_ports_used = 0 |
| |
| for wire, location in ibufds_out_wires[tile_name]: |
| if random.random() < 0.5: |
| continue |
| |
| verilog_ports += """ |
| .GTREFCLK{}({}),""".format(location, wire) |
| |
| gtrefclk_ports_used += 1 |
| params["GTREFCLK{}_USED".format(location)] = 1 |
| |
| if gtrefclk_ports_used == 2: |
| params["BOTH_GTREFCLK_USED"] = 1 |
| |
| enable_drp = random.randint(0, 1) |
| params["ENABLE_DRP"] = enable_drp |
| |
| for _, _, channel_site_name, _ in gen_sites("GTX_CHANNEL", |
| "GTXE2_CHANNEL", cmt): |
| |
| if not enable_drp: |
| break |
| |
| verilog_ports_channel = "" |
| for port, direction in DRP_PORTS: |
| if direction == "in": |
| verilog_ports_channel += """ |
| .{}({}),""".format(port, luts.get_next_output_net()) |
| |
| elif direction == "clk": |
| # DRPCLK needs to come from a clock source |
| print( |
| """ |
| wire clk_bufg_{site}; |
| |
| (* KEEP, DONT_TOUCH *) |
| BUFG bufg_{site} (.O(clk_bufg_{site}));""".format(site=channel_site_name)) |
| |
| verilog_ports_channel += """ |
| .{}(clk_bufg_{}),""".format(port, channel_site_name) |
| |
| elif direction == "out": |
| verilog_ports_channel += """ |
| .{}({}),""".format(port, luts.get_next_input_net()) |
| |
| print( |
| """ |
| (* KEEP, DONT_TOUCH, LOC=\"{site}\" *) |
| GTXE2_CHANNEL {site} ( |
| {ports} |
| );""".format(ports=verilog_ports_channel.rstrip(","), site=channel_site_name)) |
| |
| print( |
| """ |
| (* KEEP, DONT_TOUCH, LOC=\"{site}\" *) |
| GTXE2_COMMON {attrs} {site} ( |
| {ports} |
| );""".format( |
| attrs=verilog_attr, |
| ports=verilog_ports.rstrip(","), |
| site=site_name)) |
| |
| params_list.append(params) |
| |
| for l in luts.create_wires_and_luts(): |
| print(l) |
| |
| print("endmodule") |
| |
| params_dict["params"] = params_list |
| with open('params.json', 'w') as f: |
| json.dump(params_dict, f, indent=2) |
| |
| |
| if __name__ == '__main__': |
| main() |