mirror of https://github.com/openXC7/prjxray.git
211 lines
6.2 KiB
Python
211 lines
6.2 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 math
|
|
import os
|
|
import functools
|
|
import random
|
|
random.seed(int(os.getenv("SEED"), 16))
|
|
from prjxray import util
|
|
from prjxray import verilog
|
|
from prjxray.verilog import vrandbits
|
|
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)
|
|
|
|
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
|
|
|
|
|
|
@functools.lru_cache(maxsize=None)
|
|
def prepare_rand_int_choices(minval, maxval):
|
|
""" Creates list ints between minval and maxval to allow fuzzer to uniquely identify all bits."""
|
|
assert minval >= 0
|
|
assert maxval >= minval
|
|
|
|
min_p2 = math.floor(math.log(max(minval, 1), 2))
|
|
max_p2 = math.ceil(math.log(maxval + 1, 2))
|
|
|
|
if 2**max_p2 > maxval:
|
|
max_search_p2 = max_p2 - 1
|
|
else:
|
|
max_search_p2 = max_p2
|
|
|
|
choices = set(
|
|
[minval, maxval, 2**(min_p2 + 1) - 1, 2**(max_search_p2) - 1])
|
|
|
|
lb = min_p2
|
|
ub = max_search_p2
|
|
|
|
while lb < ub:
|
|
ub = int(round(ub / 2.))
|
|
|
|
val = 2**ub - 1
|
|
|
|
lowval = val
|
|
if lowval < minval:
|
|
lowval |= (1 << max_search_p2)
|
|
assert lowval >= minval, (val, ub)
|
|
choices.add(lowval)
|
|
|
|
highval = val << (max_search_p2 - ub)
|
|
if highval > minval:
|
|
assert highval <= maxval, (val, ub)
|
|
choices.add(highval)
|
|
|
|
for bit in range(max_search_p2):
|
|
if 2**bit > minval:
|
|
choices.add(2**bit)
|
|
else:
|
|
choices.add(2**bit | 2**max_search_p2)
|
|
choices.add(2**bit | 2**(max_search_p2 - 1))
|
|
|
|
zeros = set()
|
|
ones = set()
|
|
|
|
for choice in choices:
|
|
assert choice >= minval, choice
|
|
assert choice <= maxval, choice
|
|
|
|
for bit in range(max_p2):
|
|
if (1 << bit) & choice:
|
|
ones.add(bit)
|
|
else:
|
|
zeros.add(bit)
|
|
|
|
assert len(ones) == max_p2
|
|
assert len(zeros) == max_p2
|
|
|
|
return tuple(sorted(choices))
|
|
|
|
|
|
def rand_int(minval, maxval):
|
|
return random.choice(prepare_rand_int_choices(minval, maxval))
|
|
|
|
|
|
def main():
|
|
print('''
|
|
module top();
|
|
''')
|
|
|
|
params_list = []
|
|
for tile_name, sites in gen_sites():
|
|
params = {}
|
|
params['tile'] = tile_name
|
|
params['site'] = sites['RAMBFIFO36E1']
|
|
|
|
params['DATA_WIDTH'] = random.choice([4, 9, 18, 36, 72])
|
|
params['EN_SYN'] = random.randint(0, 1)
|
|
params['DO_REG'] = 1
|
|
if params['EN_SYN']:
|
|
params['FIRST_WORD_FALL_THROUGH'] = 0
|
|
else:
|
|
params['FIRST_WORD_FALL_THROUGH'] = random.randint(0, 1)
|
|
|
|
if params['EN_SYN']:
|
|
MIN_ALMOST_FULL_OFFSET = 1
|
|
if params['DATA_WIDTH'] == 4:
|
|
MAX_ALMOST_FULL_OFFSET = 8190
|
|
elif params['DATA_WIDTH'] == 9:
|
|
MAX_ALMOST_FULL_OFFSET = 4094
|
|
elif params['DATA_WIDTH'] == 18:
|
|
MAX_ALMOST_FULL_OFFSET = 2046
|
|
elif params['DATA_WIDTH'] == 36:
|
|
MAX_ALMOST_FULL_OFFSET = 1022
|
|
elif params['DATA_WIDTH'] == 72:
|
|
MAX_ALMOST_FULL_OFFSET = 510
|
|
else:
|
|
assert False
|
|
|
|
MIN_ALMOST_EMPTY_OFFSET = MIN_ALMOST_FULL_OFFSET
|
|
MAX_ALMOST_EMPTY_OFFSET = MAX_ALMOST_FULL_OFFSET
|
|
else:
|
|
MIN_ALMOST_FULL_OFFSET = 4
|
|
if params['DATA_WIDTH'] == 4:
|
|
MAX_ALMOST_FULL_OFFSET = 8185
|
|
elif params['DATA_WIDTH'] == 9:
|
|
MAX_ALMOST_FULL_OFFSET = 4089
|
|
elif params['DATA_WIDTH'] == 18:
|
|
MAX_ALMOST_FULL_OFFSET = 2041
|
|
elif params['DATA_WIDTH'] == 36:
|
|
MAX_ALMOST_FULL_OFFSET = 1017
|
|
elif params['DATA_WIDTH'] == 72:
|
|
MAX_ALMOST_FULL_OFFSET = 505
|
|
else:
|
|
assert False
|
|
|
|
if params['FIRST_WORD_FALL_THROUGH']:
|
|
MIN_ALMOST_EMPTY_OFFSET = MIN_ALMOST_FULL_OFFSET + 2
|
|
MAX_ALMOST_EMPTY_OFFSET = MAX_ALMOST_FULL_OFFSET + 2
|
|
else:
|
|
MIN_ALMOST_EMPTY_OFFSET = MIN_ALMOST_FULL_OFFSET + 1
|
|
MAX_ALMOST_EMPTY_OFFSET = MAX_ALMOST_FULL_OFFSET + 1
|
|
|
|
ALMOST_EMPTY_OFFSET = rand_int(
|
|
MIN_ALMOST_EMPTY_OFFSET, MAX_ALMOST_EMPTY_OFFSET)
|
|
ALMOST_FULL_OFFSET = rand_int(
|
|
MIN_ALMOST_FULL_OFFSET, MAX_ALMOST_FULL_OFFSET)
|
|
params['ALMOST_EMPTY_OFFSET'] = "13'b{:013b}".format(
|
|
ALMOST_EMPTY_OFFSET)
|
|
params['ALMOST_FULL_OFFSET'] = "13'b{:013b}".format(ALMOST_FULL_OFFSET)
|
|
|
|
if params['DATA_WIDTH'] == 36:
|
|
params['FIFO_MODE'] = verilog.quote('FIFO36_72')
|
|
else:
|
|
params['FIFO_MODE'] = verilog.quote(
|
|
'FIFO36_72'
|
|
) #verilog.quote('FIFO18') #verilog.quote(random.choice(('FIFO18', 'FIFO18_36')))
|
|
|
|
params['INIT'] = '0' #vrandbits(36)
|
|
params['SRVAL'] = '0' #vrandbits(36)
|
|
|
|
print(
|
|
'''
|
|
(* KEEP, DONT_TOUCH, LOC = "{site}" *)
|
|
FIFO36E1 #(
|
|
.ALMOST_EMPTY_OFFSET({ALMOST_EMPTY_OFFSET}),
|
|
.ALMOST_FULL_OFFSET({ALMOST_FULL_OFFSET}),
|
|
.DATA_WIDTH({DATA_WIDTH}),
|
|
.DO_REG({DO_REG}),
|
|
.EN_SYN({EN_SYN}),
|
|
.FIFO_MODE({FIFO_MODE}),
|
|
.FIRST_WORD_FALL_THROUGH({FIRST_WORD_FALL_THROUGH}),
|
|
.INIT({INIT}),
|
|
.SRVAL({SRVAL})
|
|
) fifo_{site} (
|
|
);
|
|
'''.format(**params, ))
|
|
|
|
params['FIFO_MODE'] = verilog.unquote(params['FIFO_MODE'])
|
|
|
|
params_list.append(params)
|
|
|
|
print("endmodule")
|
|
|
|
with open('params.json', 'w') as f:
|
|
json.dump(params_list, f, indent=2)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|