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