| #!/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 random |
| random.seed(int(os.getenv("SEED"), 16)) |
| from prjxray import util |
| from prjxray import verilog |
| from prjxray.verilog import vrandbit, vrandbits |
| import json |
| |
| |
| def gen_bram18(): |
| ''' |
| sample: |
| "sites": { |
| "RAMB18_X0Y50": "FIFO18E1", |
| "RAMB18_X0Y51": "RAMB18E1", |
| "RAMB36_X0Y25": "RAMBFIFO36E1" |
| }, |
| ''' |
| for _tile_name, site_name, _site_type in sorted(util.get_roi().gen_sites( |
| ['RAMB18E1', 'FIFO18E1'])): |
| yield site_name |
| |
| |
| def gen_bram36(): |
| for _tile_name, site_name, _site_type in util.get_roi().gen_sites( |
| ['RAMBFIFO36E1']): |
| yield site_name |
| |
| |
| def gen_brams(): |
| ''' |
| Correctly assign a site to either bram36 or 2x bram18 |
| ''' |
| # XXX: mix 18 and 36? |
| for site in gen_bram18(): |
| yield ('RAMB18E1', site) |
| |
| |
| def place_bram18(site, loci): |
| ports = { |
| 'clk': 'clk', |
| 'din': 'din[ %d +: 8]' % (8 * loci, ), |
| 'dout': 'dout[ %d +: 8]' % (8 * loci, ), |
| } |
| |
| write_modes = ["WRITE_FIRST", "READ_FIRST", "NO_CHANGE"] |
| collisions = ["DELAYED_WRITE", "PERFORMANCE"] |
| priorities = ["RSTREG", "REGCE"] |
| |
| # Datasheet says 72 is legal in some cases, but think its a copy paste error from BRAM36 |
| # also 0 and 36 aren't real sizes |
| # Bias choice to 18 as its needed to solve certain bits quickly |
| widths = [1, 2, 4, 9, 18, 18, 36] |
| mode = '"TDP"' |
| |
| read_width_a = random.choice(widths) |
| write_width_b = random.choice(widths) |
| if read_width_a >= 36 or write_width_b >= 36: |
| read_width_b = 0 |
| write_width_a = 0 |
| mode = '"SDP"' |
| doa_reg = vrandbit() |
| dob_reg = doa_reg |
| write_modes = ["WRITE_FIRST", "READ_FIRST"] |
| rstreg_priority_a = verilog.quote(random.choice(priorities)) |
| rstreg_priority_b = rstreg_priority_a |
| else: |
| read_width_b = random.choice(widths) |
| write_width_a = random.choice(widths) |
| doa_reg = vrandbit() |
| dob_reg = vrandbit() |
| rstreg_priority_a = verilog.quote(random.choice(priorities)) |
| rstreg_priority_b = verilog.quote(random.choice(priorities)) |
| |
| params = { |
| 'LOC': verilog.quote(site), |
| 'IS_CLKARDCLK_INVERTED': vrandbit(), |
| 'IS_CLKBWRCLK_INVERTED': vrandbit(), |
| 'IS_ENARDEN_INVERTED': vrandbit(), |
| 'IS_ENBWREN_INVERTED': vrandbit(), |
| 'IS_RSTRAMARSTRAM_INVERTED': vrandbit(), |
| 'IS_RSTRAMB_INVERTED': vrandbit(), |
| 'IS_RSTREGARSTREG_INVERTED': vrandbit(), |
| 'IS_RSTREGB_INVERTED': vrandbit(), |
| 'RAM_MODE': mode, |
| 'WRITE_MODE_A': verilog.quote(random.choice(write_modes)), |
| 'WRITE_MODE_B': verilog.quote(random.choice(write_modes)), |
| "DOA_REG": doa_reg, |
| "DOB_REG": dob_reg, |
| "SRVAL_A": vrandbits(18), |
| "SRVAL_B": vrandbits(18), |
| "INIT_A": vrandbits(18), |
| "INIT_B": vrandbits(18), |
| "READ_WIDTH_A": read_width_a, |
| "READ_WIDTH_B": read_width_b, |
| "WRITE_WIDTH_A": write_width_a, |
| "WRITE_WIDTH_B": write_width_b, |
| "RDADDR_COLLISION_HWCONFIG": verilog.quote(random.choice(collisions)), |
| "RSTREG_PRIORITY_A": rstreg_priority_a, |
| "RSTREG_PRIORITY_B": rstreg_priority_b, |
| } |
| |
| return ('my_RAMB18E1', ports, params) |
| |
| |
| def main(): |
| brams = list(gen_brams()) |
| DUTN = len(brams) |
| DIN_N = DUTN * 8 |
| DOUT_N = DUTN * 8 |
| |
| verilog.top_harness(DIN_N, DOUT_N) |
| |
| f = open('params.jl', 'w') |
| f.write('module,loc,params\n') |
| print( |
| 'module roi(input clk, input [%d:0] din, output [%d:0] dout);' % |
| (DIN_N - 1, DOUT_N - 1)) |
| |
| for loci, (site_type, site) in enumerate(brams): |
| modname, ports, params = { |
| 'RAMB18E1': place_bram18, |
| #'RAMBFIFO36E1': place_bram36, |
| }[site_type](site, loci) |
| |
| verilog.instance(modname, 'inst_%u' % loci, ports, params=params) |
| |
| j = {'module': modname, 'i': loci, 'params': params} |
| f.write('%s\n' % (json.dumps(j))) |
| print('') |
| |
| f.close() |
| print( |
| '''endmodule |
| |
| // --------------------------------------------------------------------- |
| |
| ''') |
| |
| # RAMB18E1 |
| print( |
| ''' |
| module my_RAMB18E1 (input clk, input [7:0] din, output [7:0] dout); |
| parameter LOC = ""; |
| parameter IS_CLKARDCLK_INVERTED = 1'b0; |
| parameter IS_CLKBWRCLK_INVERTED = 1'b0; |
| parameter IS_ENARDEN_INVERTED = 1'b0; |
| parameter IS_ENBWREN_INVERTED = 1'b0; |
| parameter IS_RSTRAMARSTRAM_INVERTED = 1'b0; |
| parameter IS_RSTRAMB_INVERTED = 1'b0; |
| parameter IS_RSTREGARSTREG_INVERTED = 1'b0; |
| parameter IS_RSTREGB_INVERTED = 1'b0; |
| parameter RAM_MODE = "TDP"; |
| parameter WRITE_MODE_A = "WRITE_FIRST"; |
| parameter WRITE_MODE_B = "WRITE_FIRST"; |
| parameter RDADDR_COLLISION_HWCONFIG = "DELAYED_WRITE"; |
| parameter RSTREG_PRIORITY_A = "RSTREG"; |
| parameter RSTREG_PRIORITY_B = "RSTREG"; |
| |
| parameter DOA_REG = 1'b0; |
| parameter DOB_REG = 1'b0; |
| parameter SRVAL_A = 18'b0; |
| parameter SRVAL_B = 18'b0; |
| parameter INIT_A = 18'b0; |
| parameter INIT_B = 18'b0; |
| |
| parameter READ_WIDTH_A = 0; |
| parameter READ_WIDTH_B = 0; |
| parameter WRITE_WIDTH_A = 0; |
| parameter WRITE_WIDTH_B = 0; |
| ''') |
| print('''\ |
| (* LOC=LOC *) |
| RAMB18E1 #(''') |
| for i in range(8): |
| print(" .INITP_%02X(256'b0)," % (i, )) |
| print('') |
| for i in range(0x40): |
| print(" .INIT_%02X(256'b0)," % (i, )) |
| print('') |
| print( |
| ''' |
| .IS_CLKARDCLK_INVERTED(IS_CLKARDCLK_INVERTED), |
| .IS_CLKBWRCLK_INVERTED(IS_CLKBWRCLK_INVERTED), |
| .IS_ENARDEN_INVERTED(IS_ENARDEN_INVERTED), |
| .IS_ENBWREN_INVERTED(IS_ENBWREN_INVERTED), |
| .IS_RSTRAMARSTRAM_INVERTED(IS_RSTRAMARSTRAM_INVERTED), |
| .IS_RSTRAMB_INVERTED(IS_RSTRAMB_INVERTED), |
| .IS_RSTREGARSTREG_INVERTED(IS_RSTREGARSTREG_INVERTED), |
| .IS_RSTREGB_INVERTED(IS_RSTREGB_INVERTED), |
| .RAM_MODE(RAM_MODE), |
| .WRITE_MODE_A(WRITE_MODE_A), |
| .WRITE_MODE_B(WRITE_MODE_B), |
| |
| .DOA_REG(DOA_REG), |
| .DOB_REG(DOB_REG), |
| .SRVAL_A(SRVAL_A), |
| .SRVAL_B(SRVAL_B), |
| .INIT_A(INIT_A), |
| .INIT_B(INIT_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), |
| |
| .RDADDR_COLLISION_HWCONFIG(RDADDR_COLLISION_HWCONFIG), |
| |
| .RSTREG_PRIORITY_A(RSTREG_PRIORITY_A), |
| .RSTREG_PRIORITY_B(RSTREG_PRIORITY_B) |
| ) ram ( |
| .CLKARDCLK(din[0]), |
| .CLKBWRCLK(din[1]), |
| .ENARDEN(din[2]), |
| .ENBWREN(din[3]), |
| .REGCEAREGCE(din[4]), |
| .REGCEB(din[5]), |
| .RSTRAMARSTRAM(din[6]), |
| .RSTRAMB(din[7]), |
| .RSTREGARSTREG(din[0]), |
| .RSTREGB(din[1]), |
| .ADDRARDADDR(din[2]), |
| .ADDRBWRADDR(din[3]), |
| .DIADI(din[4]), |
| .DIBDI(din[5]), |
| .DIPADIP(din[6]), |
| .DIPBDIP(din[7]), |
| .WEA(1'b0), |
| .WEBWE(din[1]), |
| .DOADO(dout[0]), |
| .DOBDO(dout[1]), |
| .DOPADOP(dout[2]), |
| .DOPBDOP(dout[3])); |
| endmodule |
| ''') |
| |
| |
| if __name__ == "__main__": |
| main() |