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