| #!/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 io | |
| import os | |
| import random | |
| import re | |
| random.seed(int(os.getenv("SEED"), 16)) | |
| from prjxray import util | |
| from prjxray import lut_maker | |
| from prjxray import verilog | |
| from prjxray.db import Database | |
| 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) | |
| for site_name, site_type in gridinfo.sites.items(): | |
| if site_type in ['BSCAN', 'CAPTURE', 'ICAP', 'USR_ACCESS', | |
| 'STARTUP', 'FRAME_ECC', 'DCIRESET']: | |
| if site_name not in 'ICAP_X0Y0': | |
| yield site_name, site_type | |
| def write_csv_params(params): | |
| pinstr = 'tile,site,\n' | |
| for vals in params: | |
| pinstr += ','.join(map(str, vals)) + '\n' | |
| open('params.csv', 'w').write(pinstr) | |
| def generate_params(): | |
| bscan_already_on = False | |
| icap_already_on = False | |
| tile_params = [] | |
| for loci, (site, site_type) in enumerate(sorted(gen_sites())): | |
| p = {} | |
| if site_type in "ICAP" and not icap_already_on: | |
| p["ICAP_WIDTH"] = verilog.quote( | |
| random.choice(["X32", "X8", "X16"])) | |
| elif site_type in "BSCAN" and not bscan_already_on: | |
| p["JTAG_CHAIN"] = random.randint(1, 4) | |
| bscan_already_on = True | |
| elif site_type in "CAPTURE": | |
| p["ONESHOT"] = verilog.quote(random.choice(["TRUE", "FALSE"])) | |
| elif site_type in "STARTUP": | |
| p["PROG_USR"] = verilog.quote(random.choice(["TRUE", "FALSE"])) | |
| elif site_type in "FRAME_ECC": | |
| p["FARSRC"] = verilog.quote(random.choice(["FAR", "EFAR"])) | |
| elif site_type in [ | |
| "DCIRESET", "USR_ACCESS" | |
| ]: #The primitives from these sites have no parameters | |
| p["ENABLED"] = random.randint(0, 1) | |
| else: | |
| continue | |
| p["LOC"] = verilog.quote(site) | |
| tile_params.append( | |
| { | |
| "site": site, | |
| "site_type": site_type, | |
| "module": "mod_{}".format(site_type), | |
| "params": p | |
| }) | |
| return tile_params | |
| def generate_netlist(params): | |
| DUTN = len(params) | |
| DIN_N = DUTN * 32 | |
| DOUT_N = DUTN * 32 | |
| string_output = io.StringIO() | |
| any_bscan = False | |
| any_icap = False | |
| usr_access_on = False | |
| capture_on = False | |
| startup_on = False | |
| frame_ecc_on = False | |
| dcireset_on = False | |
| luts = lut_maker.LutMaker() | |
| verilog.top_harness(DIN_N, DOUT_N) | |
| print( | |
| ''' | |
| module roi(input clk, input [%d:0] din, output [%d:0] dout);''' % | |
| (DIN_N - 1, DOUT_N - 1)) | |
| for loci, param in enumerate(params): | |
| ports = { | |
| 'din': 'din[{} +: 8]'.format(8 * loci), | |
| 'dout': 'dout[{} +: 8]'.format(8 * loci), | |
| 'clk': 'clk' | |
| } | |
| if param["site_type"] in "BSCAN": | |
| ports = { | |
| 'din': | |
| '{{din[{} +: 7],{}}}'.format( | |
| 8 * loci + 1, luts.get_next_output_net()), | |
| 'dout': | |
| '{{dout[{} +: 7],{}}}'.format( | |
| 8 * loci + 1, luts.get_next_input_net()), | |
| 'clk': | |
| 'clk' | |
| } | |
| any_bscan = True | |
| elif param["site_type"] in ["ICAP"]: | |
| any_icap = True | |
| elif param["site_type"] in ["CAPTURE"]: | |
| capture_on = True | |
| elif param["site_type"] in ["STARTUP"]: | |
| startup_on = True | |
| elif param["site_type"] in ["FRAME_ECC"]: | |
| frame_ecc_on = True | |
| elif param["site_type"] in ["USR_ACCESS", "DCIRESET"]: | |
| if not param["params"]["ENABLED"]: | |
| continue | |
| if param["site_type"] in ["DCIRESET"]: | |
| dcireset_on = True | |
| else: | |
| usr_access_on = True | |
| else: | |
| continue | |
| verilog.instance( | |
| param["module"], | |
| "inst_{}".format(param["site"]), | |
| ports, | |
| param["params"], | |
| string_buffer=string_output) | |
| #Generate LUTs | |
| for l in luts.create_wires_and_luts(): | |
| print(l) | |
| print(string_output.getvalue()) | |
| print( | |
| ''' | |
| endmodule | |
| // ---------------------------------------------------------------------''') | |
| if any_icap: | |
| print( | |
| ''' | |
| module mod_ICAP (input [7:0] din, output [7:0] dout, input clk); | |
| parameter ICAP_WIDTH = "X32"; | |
| parameter LOC = "ICAP_X0Y0"; | |
| wire [23:0] icap_out; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| ICAPE2 #( | |
| .ICAP_WIDTH(ICAP_WIDTH), | |
| .SIM_CFG_FILE_NAME("NONE") | |
| ) | |
| ICAPE2_inst ( | |
| .O({icap_out, dout}), | |
| .CLK(clk), | |
| .CSIB(), | |
| .I({24'd0, din}), | |
| .RDWRB() | |
| ); | |
| endmodule | |
| ''') | |
| if capture_on: | |
| print( | |
| ''' | |
| module mod_CAPTURE (input [7:0] din, output [7:0] dout, input clk); | |
| parameter ONESHOT ="TRUE"; | |
| parameter LOC = "ICAP_X0Y0"; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| CAPTUREE2 #( | |
| .ONESHOT(ONESHOT) // Specifies the procedure for performing single readback per CAP trigger. | |
| ) | |
| CAPTUREE2_inst ( | |
| .CAP(1'b0), | |
| .CLK(clk) | |
| ); | |
| endmodule | |
| ''') | |
| if usr_access_on: | |
| print( | |
| ''' | |
| module mod_USR_ACCESS (input [7:0] din, output [7:0] dout, input clk); | |
| parameter ENABLED = 1; | |
| parameter LOC = "USR_ACCESS_X0Y0"; | |
| wire [23:0] usr_access_wire; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| USR_ACCESSE2 USR_ACCESSE2_inst ( | |
| .CFGCLK(), | |
| .DATA({usr_access_wire, dout}), | |
| .DATAVALID() | |
| ); | |
| endmodule | |
| ''') | |
| if any_bscan: | |
| print( | |
| ''' | |
| module mod_BSCAN (input [7:0] din, output [7:0] dout, input clk); | |
| parameter JTAG_CHAIN = 1; | |
| parameter LOC = "BSCAN_X0Y0"; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| BSCANE2 #( | |
| .JTAG_CHAIN(JTAG_CHAIN) | |
| ) | |
| dut ( | |
| .CAPTURE(), | |
| .DRCK(), | |
| .RESET(), | |
| .RUNTEST(), | |
| .SEL(), | |
| .SHIFT(), | |
| .TCK(), | |
| .TDI(dout[0]), | |
| .TMS(), | |
| .UPDATE(), | |
| .TDO(din[0]) | |
| ); | |
| endmodule | |
| ''') | |
| if startup_on: | |
| print( | |
| ''' | |
| module mod_STARTUP (input [7:0] din, output [7:0] dout, input clk); | |
| parameter LOC = "STARTUP_X0Y0"; | |
| parameter PROG_USR = "FALSE"; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| STARTUPE2 #( | |
| .PROG_USR(PROG_USR), // Activate program event security feature. Requires encrypted bitstreams. | |
| .SIM_CCLK_FREQ(0.0) // Set the Configuration Clock Frequency(ns) for simulation. | |
| ) | |
| STARTUPE2_inst ( | |
| .CFGCLK(), | |
| .CFGMCLK(), | |
| .EOS(), | |
| .PREQ(dout[0]), | |
| .CLK(clk), | |
| .GSR(), | |
| .GTS(), | |
| .KEYCLEARB(), | |
| .PACK(), | |
| .USRCCLKO(), | |
| .USRCCLKTS(), | |
| .USRDONEO(), | |
| .USRDONETS() | |
| ); | |
| endmodule | |
| ''') | |
| if frame_ecc_on: | |
| print( | |
| ''' | |
| module mod_FRAME_ECC (input [7:0] din, output [7:0] dout, input clk); | |
| parameter LOC = "FRAME_ECC_X0Y0"; | |
| parameter FARSRC = "EFAR"; | |
| wire [25:0] far_wire; | |
| assign dout[7:0] = far_wire[7:0]; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| FRAME_ECCE2 #( | |
| .FARSRC(FARSRC), | |
| .FRAME_RBT_IN_FILENAME("NONE") | |
| ) | |
| FRAME_ECCE2_inst ( | |
| .CRCERROR(), | |
| .ECCERROR(), | |
| .ECCERRORSINGLE(), | |
| .FAR(far_wire), | |
| .SYNBIT(), | |
| .SYNDROME(), | |
| .SYNDROMEVALID(), | |
| .SYNWORD() | |
| ); | |
| endmodule | |
| ''') | |
| if dcireset_on: | |
| print( | |
| ''' | |
| module mod_DCIRESET (input [7:0] din, output [7:0] dout, input clk); | |
| parameter LOC = "FRAME_ECC_X0Y0"; | |
| parameter ENABLED = 1; | |
| (* KEEP, DONT_TOUCH, LOC=LOC *) | |
| DCIRESET DCIRESET_inst ( | |
| .LOCKED(dout[0]), | |
| .RST(dout[1]) | |
| ); | |
| endmodule | |
| ''') | |
| def run(): | |
| params = generate_params() | |
| generate_netlist(params) | |
| with open('params.jl', 'w') as f: | |
| json.dump(params, f, indent=2) | |
| if __name__ == '__main__': | |
| run() |