mirror of https://github.com/openXC7/prjxray.git
341 lines
8.9 KiB
Python
341 lines
8.9 KiB
Python
#!/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()
|