| #!/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() |