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