|  | #!/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 os | 
|  | import random | 
|  | random.seed(int(os.getenv("SEED"), 16)) | 
|  | from prjxray import util | 
|  | from prjxray import verilog | 
|  | from prjxray.db import Database | 
|  | import json | 
|  |  | 
|  |  | 
|  | def find_hclk_ref_wires_for_mmcm(grid, loc): | 
|  | tilename = grid.tilename_at_loc((loc[0], loc[1] - 17)) | 
|  | gridinfo = grid.gridinfo_at_tilename(tilename) | 
|  |  | 
|  | assert gridinfo.tile_type in ['HCLK_CMT_L', 'HCLK_CMT'] | 
|  |  | 
|  | # HCLK_CMT_MUX_OUT_FREQ_REF[0-3] | 
|  | wires = [] | 
|  | for idx in range(4): | 
|  | wires.append('{}/HCLK_CMT_MUX_OUT_FREQ_REF{}'.format(tilename, idx)) | 
|  |  | 
|  | return wires | 
|  |  | 
|  |  | 
|  | def gen_sites(): | 
|  | 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) | 
|  |  | 
|  | tile_type = tile_name.rsplit("_", 1)[0] | 
|  |  | 
|  | for site_name, site_type in gridinfo.sites.items(): | 
|  | if site_type in ['MMCME2_ADV']: | 
|  | hclk_wires = find_hclk_ref_wires_for_mmcm(grid, loc) | 
|  | yield tile_name, tile_type, site_name, hclk_wires | 
|  |  | 
|  |  | 
|  | def gen_true_false(p): | 
|  | if random.random() <= p: | 
|  | return verilog.quote("TRUE") | 
|  | else: | 
|  | return verilog.quote("FALSE") | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | sites = sorted(list(gen_sites())) | 
|  | max_sites = len(sites) | 
|  |  | 
|  | f = open('params.jl', 'w') | 
|  | f.write('module,loc,params\n') | 
|  |  | 
|  | routes_file = open('routes.txt', 'w') | 
|  |  | 
|  | print( | 
|  | """ | 
|  | module top( | 
|  | input [{N}:0] clkin1, | 
|  | input [{N}:0] clkin2, | 
|  | input [{N}:0] clkfb, | 
|  | input [{N}:0] dclk | 
|  | ); | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | LUT1 dummy(); | 
|  | """.format(N=max_sites - 1)) | 
|  |  | 
|  | for i, (tile_name, tile_type, site, | 
|  | hclk_wires) in enumerate(sorted(gen_sites())): | 
|  | params = { | 
|  | "site": | 
|  | site, | 
|  | 'active': | 
|  | random.random() > .2, | 
|  | "clkin1_conn": | 
|  | random.choice( | 
|  | ("clkfbout_mult_BUFG_" + site, "clkin1[{}]".format(i), "")), | 
|  | "clkin2_conn": | 
|  | random.choice( | 
|  | ("clkfbout_mult_BUFG_" + site, "clkin2[{}]".format(i), "")), | 
|  | "dclk_conn": | 
|  | random.choice(( | 
|  | "0", | 
|  | "dclk[{}]".format(i), | 
|  | )), | 
|  | "dwe_conn": | 
|  | random.choice(( | 
|  | "", | 
|  | "1", | 
|  | "0", | 
|  | "dwe_" + site, | 
|  | "den_" + site, | 
|  | )), | 
|  | "den_conn": | 
|  | random.choice(( | 
|  | "", | 
|  | "1", | 
|  | "0", | 
|  | "den_" + site, | 
|  | )), | 
|  | "daddr4_conn": | 
|  | random.choice(( | 
|  | "0", | 
|  | "dwe_" + site, | 
|  | )), | 
|  | "IS_RST_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_PWRDWN_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_CLKINSEL_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_PSEN_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_PSINCDEC_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "CLKFBOUT_MULT_F": | 
|  | random.randint(2, 4), | 
|  | "CLKOUT0_DIVIDE_F": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT1_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT2_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT3_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT4_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT5_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "CLKOUT6_DIVIDE": | 
|  | random.randint(1, 128), | 
|  | "DIVCLK_DIVIDE": | 
|  | random.randint(1, 5), | 
|  | "CLKOUT0_DUTY_CYCLE": | 
|  | "0.500", | 
|  | "STARTUP_WAIT": | 
|  | verilog.quote('TRUE' if random.randint(0, 1) else 'FALSE'), | 
|  | "COMPENSATION": | 
|  | verilog.quote( | 
|  | random.choice(( | 
|  | 'ZHOLD', | 
|  | 'BUF_IN', | 
|  | 'EXTERNAL', | 
|  | 'INTERNAL', | 
|  | ))), | 
|  | "BANDWIDTH": | 
|  | verilog.quote(random.choice(( | 
|  | 'OPTIMIZED', | 
|  | 'HIGH', | 
|  | 'LOW', | 
|  | ))), | 
|  | "SS_EN": | 
|  | gen_true_false(0.15), | 
|  | } | 
|  |  | 
|  | # SS_EN requires BANDWIDTH to be LOW | 
|  | if verilog.unquote(params["SS_EN"]) == "TRUE": | 
|  | params["BANDWIDTH"] = verilog.quote("LOW") | 
|  |  | 
|  | if verilog.unquote(params['COMPENSATION']) == 'ZHOLD': | 
|  | params['clkfbin_conn'] = random.choice( | 
|  | ( | 
|  | "", | 
|  | "clkfbout_mult_BUFG_" + site, | 
|  | )) | 
|  | elif verilog.unquote(params['COMPENSATION']) == 'INTERNAL': | 
|  | params['clkfbin_conn'] = random.choice( | 
|  | ( | 
|  | "", | 
|  | "clkfbout_mult_" + site, | 
|  | )) | 
|  | else: | 
|  | params['clkfbin_conn'] = random.choice( | 
|  | ("", "clkfb[{}]".format(i), "clkfbout_mult_BUFG_" + site)) | 
|  |  | 
|  | def get_clkin_wires(idx): | 
|  | wires = [ | 
|  | "{tile}_CLKIN{idx}", "{tile}_FREQ_BB0", "{tile}_FREQ_BB1", | 
|  | "{tile}_FREQ_BB2", "{tile}_FREQ_BB3", "{tile}_CLK_IN{idx}_INT" | 
|  | "{tile}_CLK_IN{idx}_HCLK" | 
|  | ] | 
|  | return [ | 
|  | tile_name + "/" + w.format(tile=tile_type, idx=idx) | 
|  | for w in wires | 
|  | ] | 
|  |  | 
|  | params['clkin1_route'] = random.choice(get_clkin_wires(1) + hclk_wires) | 
|  | params['clkin2_route'] = random.choice(get_clkin_wires(2) + hclk_wires) | 
|  |  | 
|  | params['clkfbin_route'] = random.choice( | 
|  | ( | 
|  | "{}_CLKFBOUT2IN", | 
|  | "{}_FREQ_BB0", | 
|  | "{}_FREQ_BB1", | 
|  | "{}_FREQ_BB2", | 
|  | "{}_FREQ_BB3", | 
|  | "{}_CLK_IN3_INT", | 
|  | "{}_CLK_IN3_HCLK", | 
|  | )).format(tile_type) | 
|  |  | 
|  | f.write('%s\n' % (json.dumps(params))) | 
|  |  | 
|  | def make_ibuf_net(net): | 
|  | p = net.find('[') | 
|  | return net[:p] + '_IBUF' + net[p:] | 
|  |  | 
|  | if params['clkin1_conn'] != "": | 
|  | net = params['clkin1_conn'] | 
|  | if "[" in net and "]" in net: | 
|  | net = make_ibuf_net(net) | 
|  | wire = params['clkin1_route'] | 
|  | routes_file.write('{} {}\n'.format(net, wire)) | 
|  |  | 
|  | if params['clkin2_conn'] != "": | 
|  | net = params['clkin2_conn'] | 
|  | if "[" in net and "]" in net: | 
|  | net = make_ibuf_net(net) | 
|  | wire = params['clkin2_route'] | 
|  | routes_file.write('{} {}\n'.format(net, wire)) | 
|  |  | 
|  | if params['clkfbin_conn'] != "" and\ | 
|  | params['clkfbin_conn'] != ("clkfbout_mult_BUFG_" + site): | 
|  | net = params['clkfbin_conn'] | 
|  | if "[" in net and "]" in net: | 
|  | net = make_ibuf_net(net) | 
|  | wire = '{}/{}'.format(tile_name, params['clkfbin_route']) | 
|  | routes_file.write('{} {}\n'.format(net, wire)) | 
|  |  | 
|  | if not params['active']: | 
|  | continue | 
|  |  | 
|  | print( | 
|  | """ | 
|  |  | 
|  | wire den_{site}; | 
|  | wire dwe_{site}; | 
|  |  | 
|  | LUT1 den_lut_{site} ( | 
|  | .O(den_{site}) | 
|  | ); | 
|  |  | 
|  | LUT1 dwe_lut_{site} ( | 
|  | .O(dwe_{site}) | 
|  | ); | 
|  |  | 
|  | wire clkfbout_mult_{site}; | 
|  | wire clkfbout_mult_BUFG_{site}; | 
|  | wire clkout0_{site}; | 
|  | wire clkout1_{site}; | 
|  | wire clkout2_{site}; | 
|  | wire clkout3_{site}; | 
|  | wire clkout4_{site}; | 
|  | wire clkout5_{site}; | 
|  | wire clkout6_{site}; | 
|  | (* KEEP, DONT_TOUCH, LOC = "{site}" *) | 
|  | MMCME2_ADV #( | 
|  | .IS_RST_INVERTED({IS_RST_INVERTED}), | 
|  | .IS_PWRDWN_INVERTED({IS_PWRDWN_INVERTED}), | 
|  | .IS_CLKINSEL_INVERTED({IS_CLKINSEL_INVERTED}), | 
|  | .IS_PSEN_INVERTED({IS_PSEN_INVERTED}), | 
|  | .IS_PSINCDEC_INVERTED({IS_PSINCDEC_INVERTED}), | 
|  | .CLKOUT0_DIVIDE_F({CLKOUT0_DIVIDE_F}), | 
|  | .CLKOUT1_DIVIDE({CLKOUT1_DIVIDE}), | 
|  | .CLKOUT2_DIVIDE({CLKOUT2_DIVIDE}), | 
|  | .CLKOUT3_DIVIDE({CLKOUT3_DIVIDE}), | 
|  | .CLKOUT4_DIVIDE({CLKOUT4_DIVIDE}), | 
|  | .CLKOUT5_DIVIDE({CLKOUT5_DIVIDE}), | 
|  | .CLKOUT6_DIVIDE({CLKOUT6_DIVIDE}), | 
|  | .CLKFBOUT_MULT_F({CLKFBOUT_MULT_F}), | 
|  | .DIVCLK_DIVIDE({DIVCLK_DIVIDE}), | 
|  | .STARTUP_WAIT({STARTUP_WAIT}), | 
|  | .CLKOUT0_DUTY_CYCLE({CLKOUT0_DUTY_CYCLE}), | 
|  | .COMPENSATION({COMPENSATION}), | 
|  | .BANDWIDTH({BANDWIDTH}), | 
|  | .SS_EN({SS_EN}), | 
|  | .CLKIN1_PERIOD(10.0), | 
|  | .CLKIN2_PERIOD(10.0) | 
|  | ) pll_{site} ( | 
|  | .CLKFBOUT(clkfbout_mult_{site}), | 
|  | .CLKOUT0(clkout0_{site}), | 
|  | .CLKOUT1(clkout1_{site}), | 
|  | .CLKOUT2(clkout2_{site}), | 
|  | .CLKOUT3(clkout3_{site}), | 
|  | .CLKOUT4(clkout4_{site}), | 
|  | .CLKOUT5(clkout5_{site}), | 
|  | .CLKOUT6(clkout6_{site}), | 
|  | .DRDY(), | 
|  | .LOCKED(), | 
|  | .DO(), | 
|  | .CLKFBIN({clkfbin_conn}), | 
|  | .CLKIN1({clkin1_conn}), | 
|  | .CLKIN2({clkin2_conn}), | 
|  | .CLKINSEL(), | 
|  | .DCLK({dclk_conn}), | 
|  | .DEN({den_conn}), | 
|  | .DWE({dwe_conn}), | 
|  | .PWRDWN(), | 
|  | .RST(), | 
|  | .DI(), | 
|  | .DADDR({{7{{ {daddr4_conn} }} }})); | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | BUFG bufg_{site} ( | 
|  | .I(clkfbout_mult_{site}), | 
|  | .O(clkfbout_mult_BUFG_{site}) | 
|  | ); | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | FDRE reg_clkfbout_mult_{site} ( | 
|  | .C(clkfbout_mult_{site}) | 
|  | ); | 
|  | """.format(**params)) | 
|  |  | 
|  | disabled_clkout = random.randint(0, 7) | 
|  | for clk in range(0, 7): | 
|  | if clk == disabled_clkout: | 
|  | continue | 
|  |  | 
|  | print( | 
|  | """ | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | FDRE reg_clkout{clk}_{site} ( | 
|  | .C(clkout{clk}_{site}) | 
|  | ); | 
|  | """.format(clk=clk, site=params['site'])) | 
|  |  | 
|  | print('endmodule') | 
|  |  | 
|  | f.close() | 
|  |  | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | main() |