2014-09-12 19:15:04 +02:00
|
|
|
#! /usr/bin/env python
|
|
|
|
|
2017-08-01 06:12:45 +02:00
|
|
|
# See LICENSE.SiFive for license details.
|
|
|
|
# See LICENSE.Berkeley for license details.
|
2014-09-12 19:15:04 +02:00
|
|
|
|
2014-09-01 05:26:55 +02:00
|
|
|
import sys
|
|
|
|
import math
|
|
|
|
|
|
|
|
use_latches = 0
|
|
|
|
|
2014-09-08 09:21:57 +02:00
|
|
|
def parse_line(line):
|
|
|
|
name = ''
|
|
|
|
width = 0
|
|
|
|
depth = 0
|
|
|
|
ports = ''
|
2016-09-06 23:48:28 +02:00
|
|
|
mask_gran = 0
|
2014-09-08 09:21:57 +02:00
|
|
|
tokens = line.split()
|
|
|
|
i = 0
|
2015-06-25 21:48:31 +02:00
|
|
|
for i in range(0,len(tokens),2):
|
2014-09-08 09:21:57 +02:00
|
|
|
s = tokens[i]
|
|
|
|
if s == 'name':
|
|
|
|
name = tokens[i+1]
|
|
|
|
elif s == 'width':
|
|
|
|
width = int(tokens[i+1])
|
2016-09-06 23:48:28 +02:00
|
|
|
mask_gran = width # default setting
|
2014-09-08 09:21:57 +02:00
|
|
|
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))
|
2017-01-14 01:40:02 +01:00
|
|
|
return (name, width, depth, mask_gran, width//mask_gran, ports)
|
2014-09-08 09:21:57 +02:00
|
|
|
|
2016-09-06 23:48:28 +02:00
|
|
|
def gen_mem(name, width, depth, mask_gran, mask_seg, ports):
|
2014-09-01 05:26:55 +02:00
|
|
|
addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
|
2016-09-06 23:48:28 +02:00
|
|
|
port_spec = []
|
2014-09-01 05:26:55 +02:00
|
|
|
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':
|
2016-09-06 23:48:28 +02:00
|
|
|
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))
|
2014-09-01 05:26:55 +02:00
|
|
|
readports.append(pid)
|
|
|
|
elif ptype == 'write':
|
2016-09-06 23:48:28 +02:00
|
|
|
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))
|
2014-09-01 05:26:55 +02:00
|
|
|
if pid in maskedports:
|
2016-09-06 23:48:28 +02:00
|
|
|
port_spec.append('input [%d:0] %smask' % (mask_seg-1, prefix))
|
2014-09-01 05:26:55 +02:00
|
|
|
if not use_latches or pid in maskedports:
|
|
|
|
writeports.append(pid)
|
|
|
|
else:
|
|
|
|
latchports.append(pid)
|
|
|
|
elif ptype == 'rw':
|
2016-09-06 23:48:28 +02:00
|
|
|
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)
|
2014-09-01 05:26:55 +02:00
|
|
|
if pid in maskedports:
|
2016-09-06 23:48:28 +02:00
|
|
|
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))
|
2014-09-01 05:26:55 +02:00
|
|
|
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)
|
|
|
|
|
2017-08-08 05:35:40 +02:00
|
|
|
def emit_read(idx, rw):
|
|
|
|
prefix = ('RW%d_' if rw else 'R%d_') % idx
|
|
|
|
data = ('%srdata' if rw else '%sdata') % prefix
|
|
|
|
en = ('%sen && !%swmode' % (prefix, prefix)) if rw else ('%sen' % prefix)
|
|
|
|
decl.append('reg reg_%sren;' % prefix)
|
2016-09-06 23:48:28 +02:00
|
|
|
decl.append('reg [%d:0] reg_%saddr;' % (addr_width-1, prefix))
|
|
|
|
sequential.append('always @(posedge %sclk)' % prefix)
|
2017-08-08 05:35:40 +02:00
|
|
|
sequential.append(' reg_%sren <= %s;' % (prefix, en))
|
|
|
|
sequential.append('always @(posedge %sclk)' % prefix)
|
|
|
|
sequential.append(' if (%s) reg_%saddr <= %saddr;' % (en, prefix, prefix))
|
|
|
|
combinational.append('`ifdef RANDOMIZE_GARBAGE_ASSIGN')
|
|
|
|
combinational.append('reg [%d:0] %srandom;' % (((width-1)//32+1)*32-1, prefix))
|
|
|
|
combinational.append('always @(posedge %sclk) %srandom <= {%s};' % (prefix, prefix, ', '.join(['$random'] * ((width-1)//32+1))))
|
|
|
|
combinational.append('assign %s = reg_%sren ? ram[reg_%saddr] : %srandom[%d:0];' % (data, prefix, prefix, prefix, width-1))
|
|
|
|
combinational.append('`else')
|
|
|
|
combinational.append('assign %s = ram[reg_%saddr];' % (data, prefix))
|
|
|
|
combinational.append('`endif')
|
|
|
|
|
|
|
|
for idx in range(nr):
|
|
|
|
emit_read(idx, False)
|
2014-09-01 05:26:55 +02:00
|
|
|
|
2016-09-06 23:48:28 +02:00
|
|
|
for idx in range(nrw):
|
2017-08-08 05:35:40 +02:00
|
|
|
emit_read(idx, True)
|
2014-09-01 05:26:55 +02:00
|
|
|
|
2016-09-06 23:48:28 +02:00
|
|
|
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))
|
2014-09-01 05:26:55 +02:00
|
|
|
combinational.append('always @(*) begin')
|
2016-09-06 23:48:28 +02:00
|
|
|
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))
|
2014-09-01 05:26:55 +02:00
|
|
|
combinational.append('end')
|
|
|
|
combinational.append('always @(*)')
|
2016-09-06 23:48:28 +02:00
|
|
|
combinational.append(' if (%sclk && latch_%sen)' % (prefix, prefix))
|
|
|
|
combinational.append(' ram[latch_%saddr] <= latch_%sdata;' % (prefix, prefix))
|
2014-09-01 05:26:55 +02:00
|
|
|
|
2015-06-26 08:17:35 +02:00
|
|
|
decl.append('reg [%d:0] ram [%d:0];' % (width-1, depth-1))
|
2017-03-07 10:56:15 +01:00
|
|
|
decl.append('`ifdef RANDOMIZE_MEM_INIT')
|
2015-06-26 08:17:35 +02:00
|
|
|
decl.append(' integer initvar;')
|
|
|
|
decl.append(' initial begin')
|
2016-09-07 20:04:36 +02:00
|
|
|
decl.append(' #0.002 begin end')
|
2015-06-26 08:17:35 +02:00
|
|
|
decl.append(' for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth)
|
2017-08-08 05:35:40 +02:00
|
|
|
decl.append(' ram[initvar] = {%d {$random}};' % ((width-1)//32+1))
|
2016-09-06 23:48:28 +02:00
|
|
|
for idx in range(nr):
|
|
|
|
prefix = 'R%d_' % idx
|
2017-08-08 05:35:40 +02:00
|
|
|
decl.append(' reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
|
2016-09-06 23:48:28 +02:00
|
|
|
for idx in range(nrw):
|
|
|
|
prefix = 'RW%d_' % idx
|
2017-08-08 05:35:40 +02:00
|
|
|
decl.append(' reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
|
2015-06-26 08:17:35 +02:00
|
|
|
decl.append(' end')
|
|
|
|
decl.append('`endif')
|
|
|
|
|
2014-09-01 05:26:55 +02:00
|
|
|
decl.append("integer i;")
|
2016-09-06 23:48:28 +02:00
|
|
|
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")
|
2014-09-01 05:26:55 +02:00
|
|
|
body = "\
|
|
|
|
%s\n\
|
2016-09-06 23:48:28 +02:00
|
|
|
%s\n\
|
|
|
|
%s\n" % ('\n '.join(decl), '\n '.join(sequential), '\n '.join(combinational))
|
2015-06-25 21:48:31 +02:00
|
|
|
|
2016-09-06 23:48:28 +02:00
|
|
|
s = "\nmodule %s(\n\
|
2014-09-01 05:26:55 +02:00
|
|
|
%s\n\
|
|
|
|
);\n\
|
|
|
|
\n\
|
|
|
|
%s\
|
|
|
|
\n\
|
2016-09-06 23:48:28 +02:00
|
|
|
endmodule" % (name, ',\n '.join(port_spec), body)
|
2014-09-01 05:26:55 +02:00
|
|
|
return s
|
|
|
|
|
2014-09-08 09:21:57 +02:00
|
|
|
def main():
|
|
|
|
if len(sys.argv) < 2:
|
|
|
|
sys.exit('Please give a .conf file as input')
|
|
|
|
for line in open(sys.argv[1]):
|
2015-06-25 21:48:31 +02:00
|
|
|
print(gen_mem(*parse_line(line)))
|
2014-09-01 05:26:55 +02:00
|
|
|
|
2014-09-08 09:21:57 +02:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|