|  | #!/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, random | 
|  | random.seed(int(os.getenv("SEED"), 16)) | 
|  |  | 
|  | import json | 
|  |  | 
|  | from prjxray import util | 
|  | from prjxray import verilog | 
|  | 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 "IOB33" not in tile_name or "SING" in tile_name: | 
|  | continue | 
|  | tile_list.append(tile_name) | 
|  |  | 
|  | get_xy = util.create_xy_fun('[LR]IOB33_') | 
|  | 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)) | 
|  |  | 
|  | iob33s = [k for k, v in iob_gridinfo.sites.items() if v == "IOB33S"][0] | 
|  | iob33m = [k for k, v in iob_gridinfo.sites.items() if v == "IOB33M"][0] | 
|  |  | 
|  | top_sites = { | 
|  | "IOB": iob33m, | 
|  | "ILOGIC": iob33m.replace("IOB", "ILOGIC"), | 
|  | "IDELAY": iob33m.replace("IOB", "IDELAY"), | 
|  | } | 
|  |  | 
|  | bot_sites = { | 
|  | "IOB": iob33s, | 
|  | "ILOGIC": iob33s.replace("IOB", "ILOGIC"), | 
|  | "IDELAY": iob33s.replace("IOB", "IDELAY"), | 
|  | } | 
|  |  | 
|  | yield iob_tile_name, top_sites, bot_sites | 
|  |  | 
|  |  | 
|  | def gen_iserdes(loc): | 
|  |  | 
|  | # Site params | 
|  | params = { | 
|  | "SITE_LOC": verilog.quote(loc), | 
|  | "USE_IDELAY": random.randint(0, 1), | 
|  | "BEL_TYPE": verilog.quote("ISERDESE2"), | 
|  | "INIT_Q1": random.randint(0, 1), | 
|  | "INIT_Q2": random.randint(0, 1), | 
|  | "INIT_Q3": random.randint(0, 1), | 
|  | "INIT_Q4": random.randint(0, 1), | 
|  | "SRVAL_Q1": random.randint(0, 1), | 
|  | "SRVAL_Q2": random.randint(0, 1), | 
|  | "SRVAL_Q3": random.randint(0, 1), | 
|  | "SRVAL_Q4": random.randint(0, 1), | 
|  | "NUM_CE": random.randint(1, 2), | 
|  |  | 
|  | # The following one shows negative correlation (0 - not inverted) | 
|  | "IS_D_INVERTED": random.randint(0, 1), | 
|  |  | 
|  | # No bits were found for parameters below | 
|  | "IS_OCLKB_INVERTED": random.randint(0, 1), | 
|  | "IS_OCLK_INVERTED": random.randint(0, 1), | 
|  | "IS_CLKDIVP_INVERTED": random.randint(0, 1), | 
|  | "IS_CLKDIV_INVERTED": random.randint(0, 1), | 
|  | "IS_CLKB_INVERTED": random.randint(0, 1), | 
|  | "IS_CLK_INVERTED": random.randint(0, 1), | 
|  | "DYN_CLKDIV_INV_EN": verilog.quote(random.choice(["TRUE", "FALSE"])), | 
|  | "DYN_CLK_INV_EN": verilog.quote(random.choice(["TRUE", "FALSE"])), | 
|  | "IOBDELAY": verilog.quote( | 
|  | random.choice(["NONE", "IBUF", "IFD", "BOTH"])), | 
|  | "OFB_USED": verilog.quote( | 
|  | random.choice(["TRUE"] + ["FALSE"] * 9)),  # Force more FALSEs | 
|  | } | 
|  |  | 
|  | iface_type = random.choice( | 
|  | ["NETWORKING", "OVERSAMPLE", "MEMORY", "MEMORY_DDR3", "MEMORY_QDR"]) | 
|  | data_rate = random.choice(["SDR", "DDR"]) | 
|  | serdes_mode = random.choice(["MASTER", "SLAVE"]) | 
|  |  | 
|  | params["INTERFACE_TYPE"] = verilog.quote(iface_type) | 
|  | params["DATA_RATE"] = verilog.quote(data_rate) | 
|  | params["SERDES_MODE"] = verilog.quote(serdes_mode) | 
|  |  | 
|  | # Networking mode | 
|  | if iface_type == "NETWORKING": | 
|  | data_widths = { | 
|  | "SDR": [2, 3, 4, 5, 6, 7, 8], | 
|  | "DDR": [4, 6, 8, 10, 14], | 
|  | } | 
|  | params["DATA_WIDTH"] = random.choice(data_widths[data_rate]) | 
|  |  | 
|  | # Others | 
|  | else: | 
|  | params["DATA_WIDTH"] = 4 | 
|  |  | 
|  | if verilog.unquote(params["OFB_USED"]) == "TRUE": | 
|  | params["IOBDELAY"] = verilog.quote("NONE") | 
|  |  | 
|  | return params | 
|  |  | 
|  |  | 
|  | def gen_iddr(loc): | 
|  |  | 
|  | # Site params | 
|  | params = { | 
|  | "SITE_LOC": | 
|  | verilog.quote(loc), | 
|  | "USE_IDELAY": | 
|  | random.randint(0, 1), | 
|  | "BEL_TYPE": | 
|  | verilog.quote(random.choice(["IDDR", "IDDR_NO_CLK"])), | 
|  | "INIT_Q1": | 
|  | random.randint(0, 1), | 
|  | "INIT_Q2": | 
|  | random.randint(0, 1), | 
|  | "SRTYPE": | 
|  | verilog.quote(random.choice(["ASYNC", "SYNC"])), | 
|  | "DDR_CLK_EDGE": | 
|  | verilog.quote( | 
|  | random.choice( | 
|  | ["OPPOSITE_EDGE", "SAME_EDGE", "SAME_EDGE_PIPELINED"])), | 
|  | "CE1USED": | 
|  | random.randint(0, 1), | 
|  | "SR_MODE": | 
|  | verilog.quote(random.choice(["NONE", "SET", "RST"])), | 
|  | "IS_C_INVERTED": | 
|  | random.randint(0, 1), | 
|  | "IS_D_INVERTED": | 
|  | random.randint(0, 1), | 
|  | } | 
|  |  | 
|  | if params["USE_IDELAY"]: | 
|  | params["IDELMUX"] = random.randint(0, 1) | 
|  | params["IFFDELMUX"] = random.randint(0, 1) | 
|  | else: | 
|  | params["IDELMUX"] = 0 | 
|  | params["IFFDELMUX"] = 0 | 
|  |  | 
|  | return params | 
|  |  | 
|  |  | 
|  | def run(): | 
|  |  | 
|  | # Get all [LR]IOI3 tiles | 
|  | tiles = list(gen_sites()) | 
|  |  | 
|  | # Header | 
|  | print("// Tile count: %d" % len(tiles)) | 
|  | print("// Seed: '%s'" % os.getenv("SEED")) | 
|  | print( | 
|  | ''' | 
|  | module top ( | 
|  | (* CLOCK_BUFFER_TYPE = "NONE" *) | 
|  | input  wire clk1, | 
|  | (* CLOCK_BUFFER_TYPE = "NONE" *) | 
|  | input  wire clk2, | 
|  | input  wire ce, | 
|  | input  wire rst, | 
|  | input  wire [{N}:0] di, | 
|  | output wire [{N}:0] do | 
|  | ); | 
|  |  | 
|  | wire [{N}:0] di_buf; | 
|  | wire [{N}:0] do_buf; | 
|  |  | 
|  | // IDELAYCTRL | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | IDELAYCTRL idelayctrl(); | 
|  | '''.format(**{"N": len(tiles) - 1})) | 
|  |  | 
|  | # LOCes IOBs | 
|  | data = [] | 
|  | for i, sites in enumerate(tiles): | 
|  | tile_name = sites[0] | 
|  |  | 
|  | # Use site | 
|  | if random.randint(0, 19) > 0:  # Use more often | 
|  |  | 
|  | # Top sites | 
|  | if random.randint(0, 1): | 
|  | this_sites = sites[1] | 
|  | other_sites = sites[2] | 
|  | # Bottom sites | 
|  | else: | 
|  | this_sites = sites[2] | 
|  | other_sites = sites[1] | 
|  |  | 
|  | # Generate cell | 
|  | bel_types = ["IDDR", "ISERDESE2"] | 
|  | bel_type = bel_types[int( | 
|  | random.randint(0, 2) > 0)]  # ISERDES more often | 
|  | if bel_type == "ISERDESE2": | 
|  | params = gen_iserdes(this_sites["ILOGIC"]) | 
|  | if bel_type == "IDDR": | 
|  | params = gen_iddr(this_sites["ILOGIC"]) | 
|  |  | 
|  | params["IDELAY_LOC"] = verilog.quote(this_sites["IDELAY"]) | 
|  | params["IS_USED"] = 1 | 
|  |  | 
|  | # Instantiate the cell | 
|  | print('') | 
|  | print('// This : ' + " ".join(this_sites.values())) | 
|  | print('// Other: ' + " ".join(other_sites.values())) | 
|  | print('(* LOC="%s", KEEP, DONT_TOUCH *)' % this_sites["IOB"]) | 
|  | print('IBUF ibuf_%03d (.I(di[%3d]), .O(di_buf[%3d]));' % (i, i, i)) | 
|  | print('(* LOC="%s", KEEP, DONT_TOUCH *)' % other_sites["IOB"]) | 
|  | print('OBUF obuf_%03d (.I(do_buf[%3d]), .O(do[%3d]));' % (i, i, i)) | 
|  |  | 
|  | clk1_conn = random.choice(["clk1", ""]) | 
|  |  | 
|  | param_str = ",".join(".%s(%s)" % (k, v) for k, v in params.items()) | 
|  | print( | 
|  | 'ilogic_single #(%s) ilogic_%03d (.clk1(%s), .clk2(clk2), .ce(ce), .rst(rst), .I(di_buf[%3d]), .O(do_buf[%3d]));' | 
|  | % (param_str, i, clk1_conn, i, i)) | 
|  |  | 
|  | params["CHAINED"] = 0 | 
|  | params["TILE_NAME"] = tile_name | 
|  |  | 
|  | # Params for the second site | 
|  | other_params = { | 
|  | "TILE_NAME": tile_name, | 
|  | "SITE_LOC": verilog.quote(other_sites["ILOGIC"]), | 
|  | "IDELAY_LOC": verilog.quote(other_sites["IDELAY"]), | 
|  | "IS_USED": 0, | 
|  | } | 
|  |  | 
|  | # Append to data list | 
|  | data.append([params, other_params]) | 
|  |  | 
|  | # Don't use sites | 
|  | else: | 
|  |  | 
|  | params_list = [ | 
|  | { | 
|  | "TILE_NAME": tile_name, | 
|  | "SITE_LOC": verilog.quote(sites[1]["ILOGIC"]), | 
|  | "IDELAY_LOC": verilog.quote(sites[1]["IDELAY"]), | 
|  | "IS_USED": 0, | 
|  | }, | 
|  | { | 
|  | "TILE_NAME": tile_name, | 
|  | "SITE_LOC": verilog.quote(sites[2]["ILOGIC"]), | 
|  | "IDELAY_LOC": verilog.quote(sites[2]["IDELAY"]), | 
|  | "IS_USED": 0, | 
|  | } | 
|  | ] | 
|  |  | 
|  | data.append(params_list) | 
|  |  | 
|  | # Store params | 
|  | with open("params.json", "w") as fp: | 
|  | json.dump(data, fp, sort_keys=True, indent=1) | 
|  |  | 
|  | print( | 
|  | ''' | 
|  | endmodule | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | module ilogic_single( | 
|  | input  wire clk1, | 
|  | input  wire clk2, | 
|  | input  wire ce, | 
|  | input  wire rst, | 
|  | input  wire I, | 
|  | output wire O, | 
|  | input  wire [1:0] shiftin, | 
|  | output wire [1:0] shiftout | 
|  | ); | 
|  |  | 
|  | parameter SITE_LOC = ""; | 
|  | parameter IS_USED = 1; | 
|  | parameter BEL_TYPE = "ISERDESE2"; | 
|  | parameter IDELAY_LOC = ""; | 
|  | parameter USE_IDELAY = 0; | 
|  | parameter IDELMUX = 0; | 
|  | parameter IFFDELMUX = 0; | 
|  | parameter INTERFACE_TYPE = "NETWORKING"; | 
|  | parameter DATA_RATE = "DDR"; | 
|  | parameter DATA_WIDTH = 4; | 
|  | parameter SERDES_MODE = "MASTER"; | 
|  | parameter NUM_CE = 2; | 
|  | parameter INIT_Q1 = 0; | 
|  | parameter INIT_Q2 = 0; | 
|  | parameter INIT_Q3 = 0; | 
|  | parameter INIT_Q4 = 0; | 
|  | parameter SRVAL_Q1 = 0; | 
|  | parameter SRVAL_Q2 = 0; | 
|  | parameter SRVAL_Q3 = 0; | 
|  | parameter SRVAL_Q4 = 0; | 
|  | parameter IS_D_INVERTED = 0; | 
|  | parameter IS_OCLK_INVERTED = 0; | 
|  | parameter IS_OCLKB_INVERTED = 0; | 
|  | parameter IS_CLK_INVERTED = 0; | 
|  | parameter IS_CLKB_INVERTED = 0; | 
|  | parameter IS_CLKDIV_INVERTED = 0; | 
|  | parameter IS_CLKDIVP_INVERTED = 0; | 
|  | parameter DYN_CLKDIV_INV_EN = "FALSE"; | 
|  | parameter DYN_CLK_INV_EN = "FALSE"; | 
|  | parameter IOBDELAY = "NONE"; | 
|  | parameter OFB_USED = "FALSE"; | 
|  | parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; | 
|  | parameter SRTYPE = "ASYNC"; | 
|  | parameter CE1USED = 0; | 
|  | parameter SR_MODE = "NONE"; | 
|  | parameter IS_C_INVERTED = 0; | 
|  |  | 
|  | wire [8:0] x; | 
|  | wire ddly; | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | generate if (IS_USED && USE_IDELAY) begin | 
|  |  | 
|  | // IDELAY | 
|  | (* LOC=IDELAY_LOC, KEEP, DONT_TOUCH *) | 
|  | IDELAYE2 idelay | 
|  | ( | 
|  | .C(clk), | 
|  | .REGRST(), | 
|  | .LD(), | 
|  | .CE(), | 
|  | .INC(), | 
|  | .CINVCTRL(), | 
|  | .CNTVALUEIN(), | 
|  | .IDATAIN(I), | 
|  | .DATAIN(), | 
|  | .LDPIPEEN(), | 
|  | .DATAOUT(ddly), | 
|  | .CNTVALUEOUT() | 
|  | ); | 
|  |  | 
|  | end else begin | 
|  |  | 
|  | assign ddly = 0; | 
|  |  | 
|  | end endgenerate | 
|  |  | 
|  | (* KEEP, DONT_TOUCH *) | 
|  | generate if (IS_USED && BEL_TYPE == "ISERDESE2") begin | 
|  |  | 
|  | // ISERDES | 
|  | (* LOC=SITE_LOC, KEEP, DONT_TOUCH *) | 
|  | ISERDESE2 # | 
|  | ( | 
|  | .INTERFACE_TYPE(INTERFACE_TYPE), | 
|  | .DATA_RATE(DATA_RATE), | 
|  | .DATA_WIDTH(DATA_WIDTH), | 
|  | .SERDES_MODE(SERDES_MODE), | 
|  | .NUM_CE(NUM_CE), | 
|  | .IS_D_INVERTED(IS_D_INVERTED), | 
|  | .IS_OCLK_INVERTED(IS_OCLK_INVERTED), | 
|  | .IS_OCLKB_INVERTED(IS_OCLKB_INVERTED), | 
|  | .IS_CLK_INVERTED(IS_CLK_INVERTED), | 
|  | .IS_CLKB_INVERTED(IS_CLKB_INVERTED), | 
|  | .IS_CLKDIV_INVERTED(IS_CLKDIV_INVERTED), | 
|  | .IS_CLKDIVP_INVERTED(IS_CLKDIVP_INVERTED), | 
|  | .INIT_Q1(INIT_Q1), | 
|  | .INIT_Q2(INIT_Q2), | 
|  | .INIT_Q3(INIT_Q3), | 
|  | .INIT_Q4(INIT_Q4), | 
|  | .SRVAL_Q1(SRVAL_Q1), | 
|  | .SRVAL_Q2(SRVAL_Q2), | 
|  | .SRVAL_Q3(SRVAL_Q3), | 
|  | .SRVAL_Q4(SRVAL_Q4), | 
|  | .DYN_CLKDIV_INV_EN(DYN_CLKDIV_INV_EN), | 
|  | .DYN_CLK_INV_EN(DYN_CLK_INV_EN), | 
|  | .IOBDELAY(IOBDELAY), | 
|  | .OFB_USED(OFB_USED) | 
|  | ) | 
|  | isedres | 
|  | ( | 
|  | .D(I), | 
|  | .DDLY(), | 
|  | .OFB(), | 
|  | //.TFB(), | 
|  | .CE1(), | 
|  | .CE2(), | 
|  | .DYNCLKSEL(), | 
|  | .CLK(clk1), | 
|  | .CLKB(clk2), | 
|  | .OCLK(), | 
|  | .OCLKB(), | 
|  | .DYNCLKDIVSEL(), | 
|  | .CLKDIV(), | 
|  | .CLKDIVP(), | 
|  | .RST(), | 
|  | .BITSLIP(), | 
|  | .O(x[8]), | 
|  | .Q1(x[0]), | 
|  | .Q2(x[1]), | 
|  | .Q3(x[2]), | 
|  | .Q4(x[3]), | 
|  | .Q5(x[4]), | 
|  | .Q6(x[5]), | 
|  | .Q7(x[6]), | 
|  | .Q8(x[7]), | 
|  | .SHIFTIN1(shiftin[0]), | 
|  | .SHIFTIN2(shiftin[1]), | 
|  | .SHIFTOUT1(shiftout[0]), | 
|  | .SHIFTOUT2(shiftout[1]) | 
|  | ); | 
|  |  | 
|  | end else if (IS_USED && BEL_TYPE == "IDDR") begin | 
|  |  | 
|  | // IDDR | 
|  | (* LOC=SITE_LOC, KEEP, DONT_TOUCH *) | 
|  | IDDR # | 
|  | ( | 
|  | .IS_C_INVERTED(IS_C_INVERTED), | 
|  | .IS_D_INVERTED(IS_D_INVERTED), | 
|  | .DDR_CLK_EDGE(DDR_CLK_EDGE), | 
|  | .INIT_Q1(INIT_Q1), | 
|  | .INIT_Q2(INIT_Q2), | 
|  | .SRTYPE(SRTYPE) | 
|  | ) | 
|  | iddr | 
|  | ( | 
|  | .C(clk1), | 
|  | .CE( (CE1USED) ? ce : 1'hx ), | 
|  | .D( (IFFDELMUX) ? ddly : I  ), | 
|  | .S( (SR_MODE == "SET") ? rst : 1'd0 ), | 
|  | .R( (SR_MODE == "RST") ? rst : 1'd0 ), | 
|  | .Q1(x[0]), | 
|  | .Q2(x[1]) | 
|  | ); | 
|  |  | 
|  | assign x[8] = (IDELMUX) ? ddly : I; | 
|  | assign x[7:2] = 0; | 
|  |  | 
|  | end else if (IS_USED && BEL_TYPE == "IDDR_NO_CLK") begin | 
|  |  | 
|  | // IDDR | 
|  | (* LOC=SITE_LOC, KEEP, DONT_TOUCH *) | 
|  | IDDR # | 
|  | ( | 
|  | .IS_C_INVERTED(IS_C_INVERTED), | 
|  | .IS_D_INVERTED(IS_D_INVERTED), | 
|  | .DDR_CLK_EDGE(DDR_CLK_EDGE), | 
|  | .INIT_Q1(INIT_Q1), | 
|  | .INIT_Q2(INIT_Q2), | 
|  | .SRTYPE(SRTYPE) | 
|  | ) | 
|  | iddr | 
|  | ( | 
|  | .C(), | 
|  | .CE( (CE1USED) ? ce : 1'hx ), | 
|  | .D( (IFFDELMUX) ? ddly : I  ), | 
|  | .S( (SR_MODE == "SET") ? rst : 1'd0 ), | 
|  | .R( (SR_MODE == "RST") ? rst : 1'd0 ), | 
|  | .Q1(x[0]), | 
|  | .Q2(x[1]) | 
|  | ); | 
|  |  | 
|  | assign x[8] = (IDELMUX) ? ddly : I; | 
|  | assign x[7:2] = 0; | 
|  |  | 
|  | end else begin | 
|  |  | 
|  | assign x[0] = I; | 
|  | assign x[1] = I; | 
|  | assign x[2] = I; | 
|  | assign x[3] = I; | 
|  | assign x[4] = I; | 
|  | assign x[5] = I; | 
|  | assign x[6] = I; | 
|  | assign x[7] = I; | 
|  | assign x[8] = I; | 
|  |  | 
|  | end endgenerate | 
|  |  | 
|  | // Output | 
|  | assign O = |x; | 
|  |  | 
|  | endmodule | 
|  |  | 
|  | ''') | 
|  |  | 
|  |  | 
|  | run() |