tilelink: add mask rom
This commit is contained in:
178
scripts/vlsi_mem_gen
Executable file
178
scripts/vlsi_mem_gen
Executable file
@ -0,0 +1,178 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# See LICENSE.SiFive for license details.
|
||||
# See LICENSE.Berkeley for license details.
|
||||
|
||||
import sys
|
||||
import math
|
||||
|
||||
use_latches = 0
|
||||
|
||||
def parse_line(line):
|
||||
name = ''
|
||||
width = 0
|
||||
depth = 0
|
||||
ports = ''
|
||||
mask_gran = 0
|
||||
tokens = line.split()
|
||||
i = 0
|
||||
for i in range(0,len(tokens),2):
|
||||
s = tokens[i]
|
||||
if s == 'name':
|
||||
name = tokens[i+1]
|
||||
elif s == 'width':
|
||||
width = int(tokens[i+1])
|
||||
mask_gran = width # default setting
|
||||
elif s == 'depth':
|
||||
depth = int(tokens[i+1])
|
||||
elif s == 'ports':
|
||||
ports = tokens[i+1].split(',')
|
||||
elif s == 'mask_gran':
|
||||
mask_gran = int(tokens[i+1])
|
||||
else:
|
||||
sys.exit('%s: unknown argument %s' % (sys.argv[0], a))
|
||||
return (name, width, depth, mask_gran, width//mask_gran, ports)
|
||||
|
||||
def gen_mem(name, width, depth, mask_gran, mask_seg, ports):
|
||||
addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
|
||||
port_spec = []
|
||||
readports = []
|
||||
writeports = []
|
||||
latchports = []
|
||||
rwports = []
|
||||
decl = []
|
||||
combinational = []
|
||||
sequential = []
|
||||
maskedports = {}
|
||||
for pid in range(len(ports)):
|
||||
ptype = ports[pid]
|
||||
if ptype[0:1] == 'm':
|
||||
ptype = ptype[1:]
|
||||
maskedports[pid] = pid
|
||||
|
||||
if ptype == 'read':
|
||||
prefix = 'R%d_' % len(readports)
|
||||
port_spec.append('input %sclk' % prefix)
|
||||
port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
|
||||
port_spec.append('input %sen' % prefix)
|
||||
port_spec.append('output [%d:0] %sdata' % (width-1, prefix))
|
||||
readports.append(pid)
|
||||
elif ptype == 'write':
|
||||
prefix = 'W%d_' % len(writeports)
|
||||
port_spec.append('input %sclk' % prefix)
|
||||
port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
|
||||
port_spec.append('input %sen' % prefix)
|
||||
port_spec.append('input [%d:0] %sdata' % (width-1, prefix))
|
||||
if pid in maskedports:
|
||||
port_spec.append('input [%d:0] %smask' % (mask_seg-1, prefix))
|
||||
if not use_latches or pid in maskedports:
|
||||
writeports.append(pid)
|
||||
else:
|
||||
latchports.append(pid)
|
||||
elif ptype == 'rw':
|
||||
prefix = 'RW%d_' % len(rwports)
|
||||
port_spec.append('input %sclk' % prefix)
|
||||
port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
|
||||
port_spec.append('input %sen' % prefix)
|
||||
port_spec.append('input %swmode' % prefix)
|
||||
if pid in maskedports:
|
||||
port_spec.append('input [%d:0] %swmask' % (mask_seg-1, prefix))
|
||||
port_spec.append('input [%d:0] %swdata' % (width-1, prefix))
|
||||
port_spec.append('output [%d:0] %srdata' % (width-1, prefix))
|
||||
rwports.append(pid)
|
||||
else:
|
||||
sys.exit('%s: unknown port type %s' % (sys.argv[0], ptype))
|
||||
|
||||
nr = len(readports)
|
||||
nw = len(writeports)
|
||||
nrw = len(rwports)
|
||||
masked = len(maskedports)>0
|
||||
tup = (depth, width, nr, nw, nrw, masked)
|
||||
|
||||
for idx in range(nr):
|
||||
prefix = 'R%d_' % idx
|
||||
decl.append('reg [%d:0] reg_%saddr;' % (addr_width-1, prefix))
|
||||
sequential.append('always @(posedge %sclk)' % prefix)
|
||||
sequential.append(' if (%sen) reg_%saddr <= %saddr;' % (prefix, prefix, prefix))
|
||||
combinational.append('assign %sdata = ram[reg_%saddr];' % (prefix, prefix))
|
||||
|
||||
for idx in range(nrw):
|
||||
prefix = 'RW%d_' % idx
|
||||
decl.append('reg [%d:0] reg_%saddr;' % (addr_width-1, prefix))
|
||||
sequential.append('always @(posedge %sclk)' % prefix)
|
||||
sequential.append(' if (%sen && !%swmode) reg_%saddr <= %saddr;' % (prefix, prefix, prefix, prefix))
|
||||
combinational.append('assign %srdata = ram[reg_%saddr];' % (prefix, prefix))
|
||||
|
||||
for idx in range(len(latchports)):
|
||||
prefix = 'W%d_' % idx
|
||||
decl.append('reg [%d:0] latch_%saddr;' % (addr_width-1, prefix))
|
||||
decl.append('reg [%d:0] latch_%sdata;' % (width-1, prefix))
|
||||
decl.append('reg latch_%sen;' % (prefix))
|
||||
combinational.append('always @(*) begin')
|
||||
combinational.append(' if (!%sclk && %sen) latch_%saddr <= %saddr;' % (prefix, prefix, prefix, prefix))
|
||||
combinational.append(' if (!%sclk && %sen) latch_%sdata <= %sdata;' % (prefix, prefix, prefix, prefix))
|
||||
combinational.append(' if (!%sclk) latch_%sen <= %sen;' % (prefix, prefix, prefix))
|
||||
combinational.append('end')
|
||||
combinational.append('always @(*)')
|
||||
combinational.append(' if (%sclk && latch_%sen)' % (prefix, prefix))
|
||||
combinational.append(' ram[latch_%saddr] <= latch_%sdata;' % (prefix, prefix))
|
||||
|
||||
decl.append('reg [%d:0] ram [%d:0];' % (width-1, depth-1))
|
||||
decl.append('`ifdef RANDOMIZE_MEM_INIT')
|
||||
decl.append(' integer initvar;')
|
||||
decl.append(' initial begin')
|
||||
decl.append(' #0.002 begin end')
|
||||
decl.append(' for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth)
|
||||
decl.append(' ram[initvar] = {%d {$random}};' % ((width-1)/32+1))
|
||||
for idx in range(nr):
|
||||
prefix = 'R%d_' % idx
|
||||
decl.append(' reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)/32+1)))
|
||||
for idx in range(nrw):
|
||||
prefix = 'RW%d_' % idx
|
||||
decl.append(' reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)/32+1)))
|
||||
decl.append(' end')
|
||||
decl.append('`endif')
|
||||
|
||||
decl.append("integer i;")
|
||||
for idx in range(nw):
|
||||
prefix = 'W%d_' % idx
|
||||
pid = writeports[idx]
|
||||
sequential.append('always @(posedge %sclk)' % prefix)
|
||||
sequential.append(" if (%sen) begin" % prefix)
|
||||
for i in range(mask_seg):
|
||||
mask = ('if (%smask[%d]) ' % (prefix, i)) if pid in maskedports else ''
|
||||
ram_range = '%d:%d' % ((i+1)*mask_gran-1, i*mask_gran)
|
||||
sequential.append(" %sram[%saddr][%s] <= %sdata[%s];" % (mask, prefix, ram_range, prefix, ram_range))
|
||||
sequential.append(" end")
|
||||
for idx in range(nrw):
|
||||
pid = rwports[idx]
|
||||
prefix = 'RW%d_' % idx
|
||||
sequential.append('always @(posedge %sclk)' % prefix)
|
||||
sequential.append(" if (%sen && %swmode) begin" % (prefix, prefix))
|
||||
for i in range(mask_seg):
|
||||
mask = ('if (%swmask[%d]) ' % (prefix, i)) if pid in maskedports else ''
|
||||
ram_range = '%d:%d' % ((i+1)*mask_gran-1, i*mask_gran)
|
||||
sequential.append(" %sram[%saddr][%s] <= %swdata[%s];" % (mask, prefix, ram_range, prefix, ram_range))
|
||||
sequential.append(" end")
|
||||
body = "\
|
||||
%s\n\
|
||||
%s\n\
|
||||
%s\n" % ('\n '.join(decl), '\n '.join(sequential), '\n '.join(combinational))
|
||||
|
||||
s = "\nmodule %s(\n\
|
||||
%s\n\
|
||||
);\n\
|
||||
\n\
|
||||
%s\
|
||||
\n\
|
||||
endmodule" % (name, ',\n '.join(port_spec), body)
|
||||
return s
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit('Please give a .conf file as input')
|
||||
for line in open(sys.argv[1]):
|
||||
print(gen_mem(*parse_line(line)))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
138
scripts/vlsi_rom_gen
Executable file
138
scripts/vlsi_rom_gen
Executable file
@ -0,0 +1,138 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# See LICENSE.SiFive for license details.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import doctest
|
||||
import sys
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
|
||||
verilog_template = """
|
||||
module {name}(
|
||||
input clock,
|
||||
input oe,
|
||||
input me,
|
||||
input [{address_bits_minus_1}:0] address,
|
||||
output [{output_width_minus_1}:0] q
|
||||
);
|
||||
reg [{output_width_minus_1}:0] out;
|
||||
reg [{output_width_minus_1}:0] rom [0:{depth_minus_1}];
|
||||
|
||||
|
||||
// 1024 is the maximum length of $readmemh filename supported by Cadence Incisive
|
||||
reg [1024 * 8 - 1:0] path;
|
||||
|
||||
integer i;
|
||||
initial begin
|
||||
`ifdef RANDOMIZE
|
||||
`ifdef RANDOMIZE_MEM_INIT
|
||||
for (i = 0; i < {depth}; i++) begin
|
||||
rom[i] = {{{num_random_blocks}{{$random}}}};
|
||||
end
|
||||
`endif
|
||||
`endif
|
||||
if (!$value$plusargs("maskromhex=%s", path)) begin
|
||||
path = "{rom_hex_file}";
|
||||
end
|
||||
$readmemh(path, rom);
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clock) begin
|
||||
if (me) begin
|
||||
out <= rom[address];
|
||||
end
|
||||
end
|
||||
|
||||
assign q = oe ? out : {output_width}'bZ;
|
||||
|
||||
endmodule
|
||||
"""
|
||||
|
||||
|
||||
def gen_rom(name, width, depth, rom_hex_file):
|
||||
variables = {
|
||||
'name': name,
|
||||
'address_bits_minus_1': (depth - 1).bit_length() - 1,
|
||||
'depth': depth,
|
||||
'depth_minus_1': depth - 1,
|
||||
'output_width': width,
|
||||
'output_width_minus_1': width - 1,
|
||||
# $random in verilog returns 32 bits; compute how many times to repeat
|
||||
# $random in order to fill the width
|
||||
'num_random_blocks': (width - 1) // 32 + 1,
|
||||
'rom_hex_file': rom_hex_file,
|
||||
}
|
||||
return verilog_template.format(**variables)
|
||||
|
||||
|
||||
def iterate_by_n(it, n):
|
||||
"""Iterate over items in it, yielding n-tuples of successive items.
|
||||
|
||||
>>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=2))
|
||||
[(1, 2), (3, 4), (5, 6)]
|
||||
>>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=3))
|
||||
[(1, 2, 3), (4, 5, 6)]
|
||||
>>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=4))
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Iterable length not evenly divisible by 4
|
||||
"""
|
||||
it = iter(it)
|
||||
while True:
|
||||
batch = ()
|
||||
for i in range(n):
|
||||
try:
|
||||
batch += (next(it),)
|
||||
except StopIteration:
|
||||
if batch: # If this is not the first iteration
|
||||
raise ValueError(
|
||||
'Iterable length not evenly divisible by {}'.format(n)
|
||||
)
|
||||
else:
|
||||
raise
|
||||
yield batch
|
||||
|
||||
|
||||
def try_cast_int(x):
|
||||
try:
|
||||
return int(x)
|
||||
except ValueError:
|
||||
return x
|
||||
|
||||
|
||||
ROMParameters = namedtuple('ROMParameters', ['name', 'depth', 'width'])
|
||||
default_rom_parameters = ROMParameters(name='', depth=0, width=0)
|
||||
|
||||
|
||||
def parse_line(line):
|
||||
kwargs = {key: try_cast_int(val)
|
||||
for key, val in iterate_by_n(line.split(), 2)}
|
||||
rom_parameters = default_rom_parameters._replace(**kwargs)
|
||||
return rom_parameters._asdict()
|
||||
|
||||
|
||||
def main():
|
||||
if '--run-tests' in sys.argv:
|
||||
(failures, total) = doctest.testmod(verbose=True)
|
||||
sys.exit(1 if failures else 0)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit('Please give a .conf file as input')
|
||||
|
||||
print('// This file created by ' + __file__)
|
||||
with open(sys.argv[1]) as fp:
|
||||
lines = fp.readlines()
|
||||
if len(lines) > 1:
|
||||
warnings.warn('vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.')
|
||||
for line in lines:
|
||||
verilog = gen_rom(rom_hex_file=sys.argv[2],
|
||||
**parse_line(line))
|
||||
print(verilog)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user