#!/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 os import sys import random import math from prjxray import util from prjxray.lut_maker import LutMaker from prjxray.db import Database random.seed(int(os.getenv("SEED"), 16)) def bram_count(): db = Database(util.get_db_root(), util.get_part()) grid = db.grid() count = 0 for tile_name in grid.tiles(): loc = grid.loc_of_tilename(tile_name) gridinfo = grid.gridinfo_at_loc(loc) for site_name, site_type in gridinfo.sites.items(): if site_type in ['RAMBFIFO36E1']: count += 1 return count def sdp_bram(name, width, address_bits): depth = 2**address_bits return ''' module {name}( // Write port input wrclk, input [{width}-1:0] di, input wren, input [{address_bits}-1:0] wraddr, // Read port input rdclk, input rden, input [{address_bits}-1:0] rdaddr, output reg [{width}-1:0] do); (* ram_style = "block" *) reg [{width}-1:0] ram[0:{depth}]; always @ (posedge wrclk) begin if(wren == 1) begin ram[wraddr] <= di; end end always @ (posedge rdclk) begin if(rden == 1) begin do <= ram[rdaddr]; end end endmodule '''.format( name=name, width=width, address_bits=address_bits, depth=depth, ) MAX_BRAM = 8 def emit_sdp_bram(luts, name, modules, lines, width, address_bits): modules.append(sdp_bram(name=name, width=width, address_bits=address_bits)) lines.append( ''' wire [{address_bits}-1:0] {name}_wraddr; wire [{address_bits}-1:0] {name}_rdaddr; '''.format( name=name, address_bits=address_bits, )) for bit in range(address_bits): lines.append( """ assign {name}_wraddr[{bit}] = {net};""".format( name=name, bit=bit, net=luts.get_next_output_net())) for bit in range(address_bits): lines.append( """ assign {name}_rdaddr[{bit}] = {net};""".format( name=name, bit=bit, net=luts.get_next_output_net())) lines.append( ''' (* KEEP, DONT_TOUCH *) {name} {name}_inst( .wraddr({name}_wraddr), .rdaddr({name}_rdaddr) ); '''.format(name=name)) return width, address_bits, math.ceil( float(width) / 72) * 72 * (2**address_bits) def max_address_bits(width): return math.floor(math.log(float(MAX_BRAM * 36 * 1024) / width, 2)) def random_sdp_bram(luts, name, modules, lines): sdp_choices = set() for width in (1, 2, 4, 8, 16, 18, 32, 36): sdp_choices.add((width, (1, max_address_bits(width)))) for nbram in range(2, MAX_BRAM + 1): sdp_choices.add((nbram * 32, (1, max_address_bits(nbram * 32)))) sdp_choices.add((nbram * 36, (1, max_address_bits(nbram * 36)))) sdp_choices.add((nbram * 16, (1, max_address_bits(nbram * 16)))) sdp_choices.add((nbram * 32, (1, max_address_bits(nbram * 32)))) # Bias some wide but shallow BRAMs to toggle the lower address bits # more. for address_bits in range(1, 4): sdp_choices.add((nbram * 16, (address_bits, address_bits))) sdp_choices = sorted(sdp_choices) width, address_bits_range = random.choice(sdp_choices) address_bits = random.randint(*address_bits_range) return emit_sdp_bram(luts, name, modules, lines, width, address_bits) def run(): luts = LutMaker() count = bram_count() max_bram_count = random.randint(1, 200) modules = [] lines = [] idx = 0 while count > MAX_BRAM: width, address_bits, bits = random_sdp_bram( luts, "ram{}".format(idx), modules, lines) brams = math.ceil(bits / float(36 * 1024)) count -= brams print(width, address_bits, bits, brams, count, file=sys.stderr) idx += 1 if idx >= max_bram_count: break for module in modules: print(module) print(''' module top(); ''') for lut in luts.create_wires_and_luts(): print(lut) for l in lines: print(l) print("endmodule") if __name__ == '__main__': run()