blob: 66f8a728fe6f94272f5849060f4b68e1ea51e337 [file] [log] [blame] [edit]
#!/usr/bin/env python3
"""
This script generates a verilog module which implements ROM memory. Content
of the memory is also generated. Different styles of ROM implementation are
available.
"""
import sys
import argparse
import math
import random
# =============================================================================
class Templates:
# =============================================================================
memory_inferred_bram = """
module rom #
(
parameter ROM_SIZE_BITS = {mem_size} // Size in 32-bit words
)
(
// Closk & reset
input wire CLK,
input wire RST,
// ROM interface
input wire I_STB,
input wire [ROM_SIZE_BITS-1:0] I_ADR,
output wire O_STB,
output wire [31:0] O_DAT
);
// ============================================================================
localparam ROM_SIZE = (1<<ROM_SIZE_BITS);
reg [31:0] rom [0:ROM_SIZE-1];
reg rom_stb;
reg [31:0] rom_dat;
always @(posedge CLK)
rom_dat <= rom[I_ADR];
always @(posedge CLK or posedge RST)
if (RST) rom_stb <= 1'd0;
else rom_stb <= I_STB;
assign O_STB = rom_stb;
assign O_DAT = rom_dat;
// ============================================================================
initial begin
{mem_data}
end
// ============================================================================
endmodule
"""
# =============================================================================
memory_explicit_dram64 = """
module rom #
(
parameter ROM_SIZE_BITS = {mem_size} // Size in 32-bit words
)
(
// Closk & reset
input wire CLK,
input wire RST,
// ROM interface
input wire I_STB,
input wire [ROM_SIZE_BITS-1:0] I_ADR,
output wire O_STB,
output wire [31:0] O_DAT
);
// ============================================================================
// DRAM aggregation logic
{dram_agg_code}
assign O_STB = rom_stb;
assign O_DAT = dram_data_0; // FIXME: Hard coded !
// ============================================================================
// DRAMs
{dram_code}
endmodule
"""
# =============================================================================
dram_row_reg = """
wire [{cols_minus_one}:0] {data_w};
reg [{cols_minus_one}:0] {data_r};
wire [{mem_size_bits_minus_one}:0] {addr};
always @(posedge CLK)
{data_r} <= {data_w};
assign {addr} = I_ADR; // FIXME: Hard coded !
"""
ram64x1d = """
RAM64X1D #
(
.INIT ({init})
)
dram_{row}_{col}
(
.WCLK (CLK),
.WE (1'b0), .D(1'b0),
.DPRA0 (1'b0), .DPRA1(1'b0), .DPRA2(1'b0),
.DPRA3 (1'b0), .DPRA4(1'b0), .DPRA5(1'b0),
.A0 ({addr}[0]), .A1 ({addr}[1]), .A2 ({addr}[2]),
.A3 ({addr}[3]), .A4 ({addr}[4]), .A5 ({addr}[5]),
.SPO ({data})
);
"""
# =============================================================================
def generate_inferred_bram(rom_data):
# Log2 memory size
mem_size_bits = int(math.ceil(math.log2(len(rom_data))))
# Case statements
case_statements = ""
for i, data_word in enumerate(rom_data):
case_statements += " rom['h%04X] <= 32'h%08X;\n" % (i, data_word)
return Templates.memory_inferred_bram.format(
mem_size=mem_size_bits, mem_data=case_statements
)
def generate_explicit_dram(rom_data, dram_size_bits=6):
# Log2 memory size
mem_size_bits = int(math.ceil(math.log2(len(rom_data))))
# DRAM size
dram_size = int(math.pow(2, dram_size_bits))
# Memory width is fixed to 32-bits. It is the number of lets say "horizontal"
# DRAMS that need to be used
mem_width = 32
# Memory height is the number of DRAMs required to store 1 bit of the
# whole data set. It has to be an integer multiply of the DRAM size.
mem_height = int(math.ceil(len(rom_data) / dram_size))
# FIXME: Only one row works -> 64 words. Need more time to code hierarchical
# muxes to join them.
assert (mem_height == 1)
sys.stderr.write("dram_size = %d\n" % dram_size)
sys.stderr.write("mem_height = %d\n" % mem_height)
# Generate "rows" of DRAMs
dram_code = ""
wire_code = ""
for row in range(mem_height):
# Row aggregation
wire_code += Templates.dram_row_reg.format(
cols_minus_one=mem_width - 1,
mem_size_bits_minus_one=dram_size_bits - 1,
data_r="dram_data_%d" % (row),
data_w="dram_data_%d_w" % (row),
addr="dram_addr_%d" % (row)
)
# Cut data range
i0 = row * dram_size
i1 = min(len(rom_data), i0 + dram_size)
sz = i1 - i0
data_chunk = [0] * dram_size
data_chunk[:sz] = rom_data[i0:i1]
# Generate "row" of DRAMS
for col in range(mem_width):
bit = col
init_data = [
bool(data_chunk[i] & (1 << bit)) for i in range(dram_size)
]
init_str = "".join(["%c" % "1" if b else "0" for b in init_data])
init_str = "%d'b" % dram_size + init_str[::-1]
code = Templates.ram64x1d.format(
init=init_str,
col=col,
row=row,
addr="dram_addr_%d" % (row),
data="dram_data_%d_w[%d]" % (row, col)
)
dram_code += code
# Add final wire bindings
wire_code += """
assign rom_dat = dram_data_0; // FIXME: Hard coded !
reg rom_stb;
always @(posedge CLK or posedge RST)
if (RST) rom_stb <= 1'd0;
else rom_stb <= I_STB;
"""
return Templates.memory_explicit_dram64.format(
mem_size=mem_size_bits,
dram_agg_code=wire_code,
dram_code=dram_code,
)
# =============================================================================
def generate_rom_data(word_count):
"""
Generates a list of 32-bit words that are to be put into ROM memory
"""
rom_data = []
random.seed(123456, version=2) # A fixed seed
for i in range(word_count):
# # Simple sequence of monotonically increasing numbers
# v0 = 2*i
# v1 = 2*i+1
# Pseudo-random numbers
v0 = int(random.random() * 65536.0)
v1 = int(random.random() * 65536.0)
# Pack as big endian
data_word = v0 << 16
data_word |= v1
rom_data.append(data_word)
return rom_data
# =============================================================================
def main():
# Argument parser
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--rom-style",
type=str,
default="bram",
help="ROM style (\"bram\",\"dram64\")"
)
args = parser.parse_args()
# Generate BRAM
if args.rom_style == "bram":
rom_data = generate_rom_data(512)
print(generate_inferred_bram(rom_data))
elif args.rom_style == "bram36":
rom_data = generate_rom_data(1024)
print(generate_inferred_bram(rom_data))
# Generate DRAM64
elif args.rom_style == "dram64":
rom_data = generate_rom_data(64)
print(generate_explicit_dram(rom_data))
# Error
else:
sys.stderr.write("Invalid ROM style '%s'" % args.rom_style)
exit(-1)
# =============================================================================
if __name__ == "__main__":
main()