#!/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 os import random random.seed(int(os.getenv("SEED"), 16)) from prjxray import util from prjxray import verilog from prjxray.db import Database from prjxray.lut_maker import LutMaker WRITE_MODES = ("WRITE_FIRST", "NO_CHANGE", "READ_FIRST") 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) if gridinfo.tile_type not in ['BRAM_L', 'BRAM_R']: continue sites = {} for site_name, site_type in gridinfo.sites.items(): sites[site_type] = site_name yield tile_name, sites def ramb18(tile_name, luts, lines, sites): """ RAMB18E1 in either top or bottom site. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = random.randint(0, 1) == 1 params['Y1_IN_USE'] = not params['Y0_IN_USE'] params['FIFO_Y0_IN_USE'] = False params['FIFO_Y1_IN_USE'] = False if params['Y0_IN_USE']: site = sites['FIFO18E1'] elif params['Y1_IN_USE']: site = sites['RAMB18E1'] else: assert False lines.append( ''' (* KEEP, DONT_TOUCH, LOC = "{site}" *) RAMB18E1 #( ) bram_{site} ( ); '''.format(site=site)) return params def ramb18_2x(tile_name, luts, lines, sites): """ RAMB18E1 in both top and bottom site. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = True params['Y1_IN_USE'] = True params['FIFO_Y0_IN_USE'] = False params['FIFO_Y1_IN_USE'] = False lines.append( ''' (* KEEP, DONT_TOUCH, LOC = "{top_site}" *) RAMB18E1 #( ) bram_{top_site} ( ); (* KEEP, DONT_TOUCH, LOC = "{bottom_site}" *) RAMB18E1 #( ) bram_{bottom_site} ( ); '''.format( top_site=sites['FIFO18E1'], bottom_site=sites['RAMB18E1'], )) return params def ramb36(tile_name, luts, lines, sites): """ RAMB36 consuming entire tile. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = True params['Y1_IN_USE'] = True params['FIFO_Y0_IN_USE'] = False params['FIFO_Y1_IN_USE'] = False site = sites['RAMBFIFO36E1'] lines.append( """ wire [7:0] webwe_{site}; wire [3:0] wea_{site}; wire regce_{site}; wire [15:0] rdaddr_{site}; wire [15:0] wraddr_{site}; """.format(site=site)) for bit in range(15): lines.append( 'assign rdaddr_{site}[{bit}] = {net};'.format( bit=bit, site=site, net=luts.get_next_output_net())) lines.append( 'assign wraddr_{site}[{bit}] = {net};'.format( bit=bit, site=site, net=luts.get_next_output_net())) for bit in range(8): lines.append( 'assign webwe_{site}[{bit}] = {net};'.format( bit=bit, site=site, net=luts.get_next_output_net())) for bit in range(4): lines.append( 'assign wea_{site}[{bit}] = {net};'.format( bit=bit, site=site, net=luts.get_next_output_net())) lines.append( 'assign regce_{site} = {net};'.format( bit=bit, site=site, net=luts.get_next_output_net())) do_reg = verilog.vrandbit() ram_mode = random.choice(('SDP', 'TDP')) READ_WIDTH_A = 0 READ_WIDTH_B = 0 if ram_mode == 'TDP': write_mode_a = random.choice(WRITE_MODES) write_mode_b = random.choice(WRITE_MODES) WRITE_WIDTH_A = 36 WRITE_WIDTH_B = 36 else: write_mode_a = 'WRITE_FIRST' write_mode_b = 'WRITE_FIRST' WRITE_WIDTH_A = 72 WRITE_WIDTH_B = 72 lines.append( ''' (* KEEP, DONT_TOUCH, LOC = "{site}" *) RAMB36E1 #( .DOA_REG({doa_reg}), .DOB_REG({dob_reg}), .WRITE_MODE_A({write_mode_a}), .WRITE_MODE_B({write_mode_b}), .READ_WIDTH_A({READ_WIDTH_A}), .READ_WIDTH_B({READ_WIDTH_B}), .WRITE_WIDTH_A({WRITE_WIDTH_A}), .WRITE_WIDTH_B({WRITE_WIDTH_B}), .INIT_A(36'hFF_FFFF_FFFF), .SRVAL_A(36'hFF_FFFF_FFFF), .INIT_B(36'hFF_FFFF_FFFF), .SRVAL_B(36'hFF_FFFF_FFFF), .RAM_MODE({ram_mode}) ) bram_{site} ( .ADDRARDADDR(rdaddr_{site}), .ADDRBWRADDR(wraddr_{site}), .REGCEAREGCE(regce_{site}), .REGCEB(regce_{site}), .WEBWE(webwe_{site}), .WEA(wea_{site}) ); '''.format( site=site, doa_reg=do_reg, dob_reg=do_reg, write_mode_a=verilog.quote(write_mode_a), write_mode_b=verilog.quote(write_mode_b), ram_mode=verilog.quote(ram_mode), READ_WIDTH_A=READ_WIDTH_A, READ_WIDTH_B=READ_WIDTH_B, WRITE_WIDTH_A=WRITE_WIDTH_A, WRITE_WIDTH_B=WRITE_WIDTH_B, )) return params def fifo18(tile_name, luts, lines, sites): """ FIFO18E1 without bottom RAMB site. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = True params['Y1_IN_USE'] = False params['FIFO_Y0_IN_USE'] = True params['FIFO_Y1_IN_USE'] = False lines.append( ''' wire fifo_rst_{site}; (* KEEP, DONT_TOUCH *) LUT6 fifo_lut_{site} ( .O(fifo_rst_{site}) ); (* KEEP, DONT_TOUCH, LOC = "{site}" *) FIFO18E1 #( .ALMOST_EMPTY_OFFSET(8), .ALMOST_FULL_OFFSET(8), .DATA_WIDTH({data_width}) ) fifo_{site} ( .RST(fifo_rst_{site}) ); '''.format( site=sites['FIFO18E1'], data_width=random.choice((4, 9)), )) return params def fifo18_ramb18(tile_name, luts, lines, sites): """ FIFO18E1 in top site and RAMB18E1 in bottom site. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = True params['Y1_IN_USE'] = True params['FIFO_Y0_IN_USE'] = True params['FIFO_Y1_IN_USE'] = False lines.append( ''' wire fifo_rst_{fifo_site}; (* KEEP, DONT_TOUCH *) LUT6 fifo_lut_{fifo_site} ( .O(fifo_rst_{fifo_site}) ); (* KEEP, DONT_TOUCH, LOC = "{fifo_site}" *) FIFO18E1 #( .ALMOST_EMPTY_OFFSET(5), .ALMOST_FULL_OFFSET(5) ) fifo_{fifo_site} ( .RST(fifo_rst_{fifo_site}) ); (* KEEP, DONT_TOUCH, LOC = "{ramb_site}" *) RAMB18E1 #( ) bram_{ramb_site} ( ); '''.format( fifo_site=sites['FIFO18E1'], ramb_site=sites['RAMB18E1'], )) return params def fifo36(tile_name, luts, lines, sites): """ FIFO36E1 consuming entire tile. """ params = {} params['tile'] = tile_name params['Y0_IN_USE'] = True params['Y1_IN_USE'] = True params['FIFO_Y0_IN_USE'] = True params['FIFO_Y1_IN_USE'] = True data_width = random.choice((4, 9)) if data_width == 4: ALMOST_EMPTY_OFFSET = 8184 ALMOST_FULL_OFFSET = 8184 else: ALMOST_EMPTY_OFFSET = 4087 ALMOST_FULL_OFFSET = 4087 lines.append( ''' wire fifo_rst_{site}; (* KEEP, DONT_TOUCH *) LUT6 fifo_lut_{site} ( .O(fifo_rst_{site}) ); (* KEEP, DONT_TOUCH, LOC = "{site}" *) FIFO36E1 #( .ALMOST_EMPTY_OFFSET({ALMOST_EMPTY_OFFSET}), .ALMOST_FULL_OFFSET({ALMOST_FULL_OFFSET}), .DATA_WIDTH({data_width}), .INIT(36'hFF_FFFF_FFFF), .SRVAL(36'hFF_FFFF_FFFF) ) fifo_{site} ( .RST(fifo_rst_{site}) ); '''.format( site=sites['RAMBFIFO36E1'], data_width=data_width, ALMOST_EMPTY_OFFSET=ALMOST_EMPTY_OFFSET, ALMOST_FULL_OFFSET=ALMOST_FULL_OFFSET)) return params def main(): print(''' module top(); ''') luts = LutMaker() lines = [] params_list = [] for tile_name, sites in gen_sites(): gen_fun = random.choice( (ramb18, ramb18_2x, ramb36, fifo18, fifo18_ramb18, fifo36)) params_list.append(gen_fun(tile_name, luts, lines, sites)) for lut in luts.create_wires_and_luts(): print(lut) for l in lines: print(l) print("endmodule") with open('params.json', 'w') as f: json.dump(params_list, f, indent=2) if __name__ == '__main__': main()