xref: /XiangShan/scripts/vlsi_mem_gen (revision 66314a3840e5ebe6cc81ca4725bde95942f67489)
1#! /usr/bin/env python
2
3# See LICENSE.SiFive for license details.
4# See LICENSE.Berkeley for license details.
5
6import sys
7import math
8
9use_latches = 0
10blackbox = 0
11
12def parse_line(line):
13  name = ''
14  width = 0
15  depth = 0
16  ports = ''
17  mask_gran = 0
18  tokens = line.split()
19  i = 0
20  for i in range(0,len(tokens),2):
21    s = tokens[i]
22    if s == 'name':
23      name = tokens[i+1]
24    elif s == 'width':
25      width = int(tokens[i+1])
26      mask_gran = width # default setting
27    elif s == 'depth':
28      depth = int(tokens[i+1])
29    elif s == 'ports':
30      ports = tokens[i+1].split(',')
31    elif s == 'mask_gran':
32      mask_gran = int(tokens[i+1])
33    else:
34      sys.exit('%s: unknown argument %s' % (sys.argv[0], a))
35  return (name, width, depth, mask_gran, width//mask_gran, ports)
36
37def gen_mem(name, width, depth, mask_gran, mask_seg, ports):
38  addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
39  port_spec = []
40  readports = []
41  writeports = []
42  latchports = []
43  rwports = []
44  decl = []
45  combinational = []
46  sequential = []
47  maskedports = {}
48  for pid in range(len(ports)):
49    ptype = ports[pid]
50    if ptype[0:1] == 'm':
51      ptype = ptype[1:]
52      maskedports[pid] = pid
53
54    if ptype == 'read':
55      prefix = 'R%d_' % len(readports)
56      port_spec.append('input %sclk' % prefix)
57      port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
58      port_spec.append('input %sen' % prefix)
59      port_spec.append('output [%d:0] %sdata' % (width-1, prefix))
60      readports.append(pid)
61    elif ptype == 'write':
62      prefix = 'W%d_' % len(writeports)
63      port_spec.append('input %sclk' % prefix)
64      port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
65      port_spec.append('input %sen' % prefix)
66      port_spec.append('input [%d:0] %sdata' % (width-1, prefix))
67      if pid in maskedports:
68        port_spec.append('input [%d:0] %smask' % (mask_seg-1, prefix))
69      if not use_latches or pid in maskedports:
70        writeports.append(pid)
71      else:
72        latchports.append(pid)
73    elif ptype == 'rw':
74      prefix = 'RW%d_' % len(rwports)
75      port_spec.append('input %sclk' % prefix)
76      port_spec.append('input [%d:0] %saddr' % (addr_width-1, prefix))
77      port_spec.append('input %sen' % prefix)
78      port_spec.append('input %swmode' % prefix)
79      if pid in maskedports:
80        port_spec.append('input [%d:0] %swmask' % (mask_seg-1, prefix))
81      port_spec.append('input [%d:0] %swdata' % (width-1, prefix))
82      port_spec.append('output [%d:0] %srdata' % (width-1, prefix))
83      rwports.append(pid)
84    else:
85      sys.exit('%s: unknown port type %s' % (sys.argv[0], ptype))
86
87  nr = len(readports)
88  nw = len(writeports)
89  nrw = len(rwports)
90  masked = len(maskedports)>0
91  tup = (depth, width, nr, nw, nrw, masked)
92
93  def emit_read(idx, rw):
94    prefix = ('RW%d_' if rw else 'R%d_') % idx
95    data = ('%srdata' if rw else '%sdata') % prefix
96    en = ('%sen && !%swmode' % (prefix, prefix)) if rw else ('%sen' % prefix)
97    decl.append('reg reg_%sren;' % prefix)
98    decl.append('reg [%d:0] reg_%saddr;' % (addr_width-1, prefix))
99    sequential.append('always @(posedge %sclk)' % prefix)
100    sequential.append('  reg_%sren <= %s;' % (prefix, en))
101    sequential.append('always @(posedge %sclk)' % prefix)
102    sequential.append('  if (%s) reg_%saddr <= %saddr;' % (en, prefix, prefix))
103    combinational.append('`ifdef RANDOMIZE_GARBAGE_ASSIGN')
104    combinational.append('reg [%d:0] %srandom;' % (((width-1)//32+1)*32-1, prefix))
105    combinational.append('`ifdef RANDOMIZE_MEM_INIT')
106    combinational.append('  initial begin')
107    combinational.append('    #`RANDOMIZE_DELAY begin end')
108    combinational.append('    %srandom = {%s};' % (prefix, ', '.join(['$random'] * ((width-1)//32+1))))
109    combinational.append('    reg_%sren = %srandom[0];' % (prefix, prefix))
110    combinational.append('  end')
111    combinational.append('`endif')
112    combinational.append('always @(posedge %sclk) %srandom <= {%s};' % (prefix, prefix, ', '.join(['$random'] * ((width-1)//32+1))))
113    combinational.append('assign %s = reg_%sren ? ram[reg_%saddr] : %srandom[%d:0];' % (data, prefix, prefix, prefix, width-1))
114    combinational.append('`else')
115    combinational.append('assign %s = ram[reg_%saddr];' % (data, prefix))
116    combinational.append('`endif')
117
118  for idx in range(nr):
119    emit_read(idx, False)
120
121  for idx in range(nrw):
122    emit_read(idx, True)
123
124  for idx in range(len(latchports)):
125    prefix = 'W%d_' % idx
126    decl.append('reg [%d:0] latch_%saddr;' % (addr_width-1, prefix))
127    decl.append('reg [%d:0] latch_%sdata;' % (width-1, prefix))
128    decl.append('reg latch_%sen;' % (prefix))
129    combinational.append('always @(*) begin')
130    combinational.append('  if (!%sclk && %sen) latch_%saddr <= %saddr;' % (prefix, prefix, prefix, prefix))
131    combinational.append('  if (!%sclk && %sen) latch_%sdata <= %sdata;' % (prefix, prefix, prefix, prefix))
132    combinational.append('  if (!%sclk) latch_%sen <= %sen;' % (prefix, prefix, prefix))
133    combinational.append('end')
134    combinational.append('always @(*)')
135    combinational.append('  if (%sclk && latch_%sen)' % (prefix, prefix))
136    combinational.append('    ram[latch_%saddr] <= latch_%sdata;' % (prefix, prefix))
137
138  decl.append('reg [%d:0] ram [%d:0];' % (width-1, depth-1))
139  decl.append('`ifdef RANDOMIZE_MEM_INIT')
140  decl.append('  integer initvar;')
141  decl.append('  initial begin')
142  decl.append('    #`RANDOMIZE_DELAY begin end')
143  decl.append('    for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth)
144  decl.append('      ram[initvar] = {%d {$random}};' % ((width-1)//32+1))
145  for idx in range(nr):
146    prefix = 'R%d_' % idx
147    decl.append('    reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
148  for idx in range(nrw):
149    prefix = 'RW%d_' % idx
150    decl.append('    reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
151  decl.append('  end')
152  decl.append('`endif')
153
154  decl.append("integer i;")
155  for idx in range(nw):
156    prefix = 'W%d_' % idx
157    pid = writeports[idx]
158    sequential.append('always @(posedge %sclk)' % prefix)
159    sequential.append("  if (%sen) begin" % prefix)
160    for i in range(mask_seg):
161      mask = ('if (%smask[%d]) ' % (prefix, i)) if pid in maskedports else ''
162      ram_range = '%d:%d' % ((i+1)*mask_gran-1, i*mask_gran)
163      sequential.append("    %sram[%saddr][%s] <= %sdata[%s];" % (mask, prefix, ram_range, prefix, ram_range))
164    sequential.append("  end")
165  for idx in range(nrw):
166    pid = rwports[idx]
167    prefix = 'RW%d_' % idx
168    sequential.append('always @(posedge %sclk)' % prefix)
169    sequential.append("  if (%sen && %swmode) begin" % (prefix, prefix))
170    if mask_seg > 0:
171      sequential.append("    for(i=0;i<%d;i=i+1) begin" % mask_seg)
172      if pid in maskedports:
173        sequential.append("      if(%swmask[i]) begin" % prefix)
174        sequential.append("        ram[%saddr][i*%d +: %d] <= %swdata[i*%d +: %d];" %(prefix, mask_gran, mask_gran, prefix, mask_gran, mask_gran))
175        sequential.append("      end")
176      else:
177        sequential.append("      ram[%saddr][i*%d +: %d] <= %swdata[i*%d +: %d];" %(prefix, mask_gran, mask_gran, prefix, mask_gran, mask_gran))
178      sequential.append("    end")
179    sequential.append("  end")
180  body = "\
181  %s\n\
182  %s\n\
183  %s\n" % ('\n  '.join(decl), '\n  '.join(sequential), '\n  '.join(combinational))
184
185  s = "\nmodule %s(\n\
186  %s\n\
187);\n\
188\n\
189%s\
190\n\
191endmodule" % (name, ',\n  '.join(port_spec), body if not blackbox else "")
192  return s
193
194def main(args):
195  f = open(args.output_file, "w") if (args.output_file) else None
196  conf_file = args.conf
197  for line in open(conf_file):
198    parsed_line = gen_mem(*parse_line(line))
199    if f is not None:
200        f.write(parsed_line)
201    else:
202        print(parsed_line)
203
204if __name__ == '__main__':
205  import argparse
206  parser = argparse.ArgumentParser(description='Memory generator for Rocket Chip')
207  parser.add_argument('conf', metavar='.conf file')
208  parser.add_argument('--blackbox', '-b', action='store_true', help='set to disable output of module body')
209  #parser.add_argument('--use_latches', '-l', action='store_true', help='set to enable use of latches')
210  parser.add_argument('--output_file', '-o', help='name of output file, default is stdout')
211  args = parser.parse_args()
212  blackbox = args.blackbox
213  #use_latches = args.use_latches
214  main(args)
215