1
0
Fork 0
rocket-chip/fsim/fpga_mem_gen

196 lines
5.9 KiB
Python
Executable File

#! /usr/bin/env python
# See LICENSE for license details.
# This is based off of reference-chip/vlsi/src/vlsi_mem_gen
import sys
import math
use_latches = False
module_template = '''module %s(
%s
);
%s
%s
always @(posedge CLK) begin
%s
end
%s
endmodule
'''
mask_assert_template = '''
`ifndef SYNTHESIS
integer i;
integer j;
always @(posedge CLK) begin%s
end
`endif
'''
assert_template = '''
for (i=0; i<%d; i=i+%d) begin
for (j=1; j<%d; j=j+1) begin
if (%sM[i] != %sM[i+j]) begin
$fwrite(32'h80000002, "ASSERTION FAILED: write mask granularity\\n");
$finish;
end
end
end'''
def parse_line(line):
name = ''
width = 0
depth = 0
ports = ''
mask_gran = 1
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])
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, ports, mask_gran)
def gen_range(mask_index, mask_gran, max_width):
return '%d:%d' % (min(mask_gran*(mask_index+1),max_width)-1,
min(mask_gran*(mask_index),max_width))
def gen_mem(name, width, depth, ports, mask_gran):
addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
mask_width = int(math.ceil(float(width) / mask_gran))
port_spec = ['input CLK', 'input RST', 'input init']
readports = []
writeports = []
latchports = []
rwports = []
decl = []
combinational = []
sequential = []
maskedports = {}
mask_asserts = ''
for pid in range(len(ports)):
ptype = ports[pid]
if ptype[0:1] == 'm':
ptype = ptype[1:]
maskedports[pid] = pid
if ptype == 'read':
port_spec += ['input [%d:0] R%dA' % (addr_width-1, pid)]
port_spec += ['input R%dE' % pid]
port_spec += ['output [%d:0] R%dO' % (width-1, pid)]
readports += [pid]
elif ptype == 'write':
port_spec += ['input [%d:0] W%dA' % (addr_width-1, pid)]
port_spec += ['input W%dE' % pid]
port_spec += ['input [%d:0] W%dI' % (width-1, pid)]
if pid in maskedports:
port_spec += ['input [%d:0] W%dM' % (width-1, pid)]
if not use_latches or pid in maskedports:
writeports += [pid]
else:
latchports += [pid]
elif ptype == 'rw':
port_spec += ['input [%d:0] RW%dA' % (addr_width-1, pid)]
port_spec += ['input RW%dE' % pid]
port_spec += ['input RW%dW' % pid]
if pid in maskedports:
port_spec += ['input [%d:0] RW%dM' % (width-1, pid)]
port_spec += ['input [%d:0] RW%dI' % (width-1, pid)]
port_spec += ['output [%d:0] RW%dO' % (width-1, pid)]
rwports += [pid]
else:
sys.exit('%s: unknown port type %s' % (sys.argv[0], ptype))
decl += ['reg [%d:0] ram [%d:0];' % (width-1, depth-1)]
decl += ['`ifndef SYNTHESIS']
decl += [' integer initvar;']
decl += [' initial begin']
decl += [' #0.002;']
decl += [' for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth]
decl += [' ram[initvar] = {%d {$random}};' % ((width-1)/32+1)]
decl += [' end']
decl += ['`endif']
for pid in readports:
decl += ['reg [%d:0] reg_R%dA;' % (addr_width-1, pid)]
sequential += ['if (R%dE) reg_R%dA <= R%dA;' % (pid, pid, pid)]
combinational += ['assign R%dO = ram[reg_R%dA];' % (pid, pid)]
for pid in rwports:
decl += ['reg [%d:0] reg_RW%dA;' % (addr_width-1, pid)]
sequential += ['if (RW%dE && !RW%dW) reg_RW%dA <= RW%dA;' % (pid, pid, pid, pid)]
combinational += ['assign RW%dO = ram[reg_RW%dA];' % (pid, pid)]
for pid in latchports:
decl += ['reg [%d:0] latch_W%dA;' % (addr_width-1, pid)]
decl += ['reg [%d:0] latch_W%dI;' % (width-1, pid)]
decl += ['reg latch_W%dE;' % (pid)]
combinational += ['always @(*) begin']
combinational += [' if (!CLK && W%dE) latch_W%dA <= W%dA;' % (pid, pid, pid)]
combinational += [' if (!CLK && W%dE) latch_W%dI <= W%dI;' % (pid, pid, pid)]
combinational += [' if (!CLK) latch_W%dE <= W%dE;' % (pid, pid)]
combinational += ['end']
combinational += ['always @(*)']
combinational += [' if (CLK && latch_W%dE)' % (pid)]
combinational += [' ram[latch_W%dA] <= latch_W%dI;' % (pid, pid)]
for pid in writeports:
if pid not in maskedports:
sequential += ['if (W%dE) ram[W%dA] <= W%dI;' % (pid, pid, pid)]
else:
for mask_index in range(mask_width):
rs = gen_range(mask_index, mask_gran, width)
sequential += ['if (W%dE && W%dM[%d]) ram[W%dA][%s] <= W%dI[%s];' %
(pid, pid, mask_index*mask_gran, pid, rs, pid, rs)]
mask_asserts += assert_template % (mask_width, mask_gran, mask_gran, 'W'+str(pid), 'W'+str(pid))
for pid in rwports:
if pid not in maskedports:
sequential += ['if (RW%dE && RW%dW) ram[RW%dA] <= RW%dI;' % (pid, pid, pid, pid)]
else:
for mask_index in range(mask_width):
rs = gen_range(mask_index, mask_gran, width)
sequential += ['if (RW%dE && RW%dW && RW%dM[%d]) ram[RW%dA][%s] <= RW%dI[%s];' %
(pid, pid, pid, mask_index*mask_gran, pid, rs, pid, rs)]
mask_asserts += assert_template % (mask_width, mask_gran, mask_gran, 'RW'+str(pid), 'RW'+str(pid))
check_masks = '' if len(maskedports) == 0 else mask_assert_template % mask_asserts
return module_template % (name,
',\n '.join(port_spec),
check_masks,
'\n '.join(decl),
'\n '.join(sequential),
'\n '.join(combinational))
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()