blob: 5f3dfd900cfa26c39d423fd1cdf8179d0cd6ef81 [file] [log] [blame]
#!/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()