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