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