xref: /XiangShan/scripts/vlsi_mem_gen (revision 7ee2486883a66b728f83fb2db97c266345e9d2db)
14f24fc9aSDan Tang#! /usr/bin/env python3
2885733f1SZihao Yu
3885733f1SZihao Yu# See LICENSE.SiFive for license details.
4885733f1SZihao Yu# See LICENSE.Berkeley for license details.
5885733f1SZihao Yu
6885733f1SZihao Yuimport sys
7885733f1SZihao Yuimport math
8885733f1SZihao Yu
9885733f1SZihao Yuuse_latches = 0
10885733f1SZihao Yu
114f24fc9aSDan Tangclass VerilogModuleGenerator(object):
124f24fc9aSDan Tang  def __init__(self, name):
134f24fc9aSDan Tang    self.name = name
144f24fc9aSDan Tang    self.port_spec = []
154f24fc9aSDan Tang    self.decl = []
164f24fc9aSDan Tang    self.combinational = []
174f24fc9aSDan Tang    self.sequential = []
184f24fc9aSDan Tang
194f24fc9aSDan Tang  def __format_width(self, width):
204f24fc9aSDan Tang    return "[{}:0] ".format(width-1) if width > 1 else ""
214f24fc9aSDan Tang
224f24fc9aSDan Tang  def __format_depth(self, depth):
234f24fc9aSDan Tang    return " [{}:0]".format(depth-1) if depth > 1 else ""
244f24fc9aSDan Tang
254f24fc9aSDan Tang  def add_io(self, io_type, width, name):
264f24fc9aSDan Tang    width_str = self.__format_width(width)
274f24fc9aSDan Tang    # print(io_type, width_str, name)
284f24fc9aSDan Tang    self.port_spec.append(f'{io_type} {width_str}{name}')
294f24fc9aSDan Tang
304f24fc9aSDan Tang  def add_input(self, width, name):
314f24fc9aSDan Tang    self.add_io("input", width, name)
324f24fc9aSDan Tang
334f24fc9aSDan Tang  def add_output(self, width, name):
344f24fc9aSDan Tang    self.add_io("output", width, name)
354f24fc9aSDan Tang
364f24fc9aSDan Tang  def add_decl(self, decl_type, width, name, depth=1):
374f24fc9aSDan Tang    width_str = self.__format_width(width)
384f24fc9aSDan Tang    depth_str = self.__format_depth(depth)
394f24fc9aSDan Tang    self.decl.append(f"{decl_type} {width_str}{name}{depth_str};")
404f24fc9aSDan Tang
414f24fc9aSDan Tang  def add_decl_reg(self, width, name, depth=1):
424f24fc9aSDan Tang    self.add_decl("reg", width, name, depth)
434f24fc9aSDan Tang
4451e45dbbSTang Haojin  def add_decl_ram(self, width, name, depth=1):
4551e45dbbSTang Haojin    width_str = self.__format_width(width)
4651e45dbbSTang Haojin    depth_str = " [{}:0]".format(depth-1)
4751e45dbbSTang Haojin    self.decl.append(f"reg {width_str}{name}{depth_str};")
4851e45dbbSTang Haojin
494f24fc9aSDan Tang  def add_decl_wire(self, width, name, depth=1):
504f24fc9aSDan Tang    self.add_decl("wire", width, name, depth)
514f24fc9aSDan Tang
524f24fc9aSDan Tang  def add_decl_line(self, line):
534f24fc9aSDan Tang    self.decl.append(line)
544f24fc9aSDan Tang
554f24fc9aSDan Tang  def add_sequential(self, line):
564f24fc9aSDan Tang    self.sequential.append(line)
574f24fc9aSDan Tang
584f24fc9aSDan Tang  def add_combinational(self, line):
594f24fc9aSDan Tang    self.combinational.append(line)
604f24fc9aSDan Tang
614f24fc9aSDan Tang  def generate(self, blackbox):
624f24fc9aSDan Tang    body = "\
634f24fc9aSDan Tang  %s\n\
644f24fc9aSDan Tang  %s\n\
654f24fc9aSDan Tang  %s\n" % ('\n  '.join(self.decl), '\n  '.join(self.sequential), '\n  '.join(self.combinational))
664f24fc9aSDan Tang
674f24fc9aSDan Tang    s = "\nmodule %s(\n\
684f24fc9aSDan Tang  %s\n\
694f24fc9aSDan Tang);\n\
704f24fc9aSDan Tang\n\
714f24fc9aSDan Tang%s\
724f24fc9aSDan Tang\n\
734f24fc9aSDan Tangendmodule" % (self.name, ',\n  '.join(self.port_spec), body if not blackbox else blackbox)
744f24fc9aSDan Tang    return s
754f24fc9aSDan Tang
764f24fc9aSDan Tang
774f24fc9aSDan Tangclass Reshaper(object):
784f24fc9aSDan Tang  def __init__(self, before, after):
794f24fc9aSDan Tang    # print(before, after)
804f24fc9aSDan Tang    self.conf = before
814f24fc9aSDan Tang    self.new_conf = after
824f24fc9aSDan Tang    assert(self.conf[-1] == ['write', 'read'])
834f24fc9aSDan Tang    assert(self.new_conf[-1] == ['mwrite', 'read'])
844f24fc9aSDan Tang
854f24fc9aSDan Tang  def generate(self, mem):
864f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, _) = self.conf
874f24fc9aSDan Tang    (new_name, new_width, new_depth, new_mask_gran, new_mask_seg, _) = self.new_conf
884f24fc9aSDan Tang    addr_bits = math.log2(depth)
894f24fc9aSDan Tang    ways = new_width // width
904f24fc9aSDan Tang    ways_bits = int(math.log2(ways))
914f24fc9aSDan Tang    mem.add_decl_wire(new_width, "data_read")
924f24fc9aSDan Tang    mem.add_decl_wire(new_width, "data_write")
934f24fc9aSDan Tang    mem.add_combinational(f"assign data_write = ")
944f24fc9aSDan Tang    sels = [f"{f'(write_way_index == {w}) ?' if w != ways-1 else ''} ({{{new_width-width}'h0, W0_data}} << {width*w})" for w in range(ways)]
954f24fc9aSDan Tang    mem.add_combinational(":\n    ".join(sels) + ";")
964f24fc9aSDan Tang    mem.add_decl_wire(ways_bits, "read_way_index")
974f24fc9aSDan Tang    mem.add_combinational(f"assign read_way_index = R0_addr[{ways_bits-1}:0];")
984f24fc9aSDan Tang    mem.add_decl_wire(ways_bits, "write_way_index")
994f24fc9aSDan Tang    mem.add_combinational(f"assign write_way_index = W0_addr[{ways_bits-1}:0];")
1004f24fc9aSDan Tang    mem.add_combinational(f"{new_name} array (")
1014f24fc9aSDan Tang    mem.add_combinational(f"  .W0_clk(W0_clk),")
1024f24fc9aSDan Tang    mem.add_combinational(f"  .W0_addr(W0_addr[{new_width-1}:{ways_bits}]),")
1034f24fc9aSDan Tang    mem.add_combinational(f"  .W0_en(W0_en),")
1044f24fc9aSDan Tang    mem.add_combinational(f"  .W0_data(data_write),")
1054f24fc9aSDan Tang    mem.add_combinational(f"  .W0_mask({ways}'h1 << write_way_index),")
1064f24fc9aSDan Tang    mem.add_combinational(f"  .R0_clk(R0_clk),")
1074f24fc9aSDan Tang    mem.add_combinational(f"  .R0_addr(R0_addr[{new_width-1}:{ways_bits}]),")
1084f24fc9aSDan Tang    mem.add_combinational(f"  .R0_en(R0_en),")
1094f24fc9aSDan Tang    mem.add_combinational(f"  .R0_data(data_read)")
1104f24fc9aSDan Tang    mem.add_combinational(f");")
1114f24fc9aSDan Tang    mem.add_combinational(f"assign R0_data = ")
1124f24fc9aSDan Tang    sels = [f"{f'(read_way_index == {w}) ?' if w != ways-1 else ''} data_read[{width*(w+1)-1}:{width*w}]" for w in range(ways)]
1134f24fc9aSDan Tang    mem.add_combinational(":\n    ".join(sels) + ";")
1144f24fc9aSDan Tang
1154f24fc9aSDan Tang
1164f24fc9aSDan Tangclass Spliter(object):
1174f24fc9aSDan Tang  def __init__(self, before, after):
1184f24fc9aSDan Tang    # print(before, after)
1194f24fc9aSDan Tang    self.conf = before
1204f24fc9aSDan Tang    self.new_conf = after
1214f24fc9aSDan Tang    assert(self.conf[-1] == ['mrw'])
1224f24fc9aSDan Tang    assert(self.new_conf[-1] == ['rw'])
1234f24fc9aSDan Tang
1244f24fc9aSDan Tang  def generate(self, mem):
1254f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, _) = self.conf
1264f24fc9aSDan Tang    (new_name, new_width, new_depth, new_mask_gran, new_mask_seg, _) = self.new_conf
1274f24fc9aSDan Tang    assert(depth == new_depth)
1284f24fc9aSDan Tang    ways = width // new_width
1294f24fc9aSDan Tang    for i in range(ways):
1304f24fc9aSDan Tang      data_slice = f"[{new_width*(i+1)-1}:{new_width*i}]"
1314f24fc9aSDan Tang      mem.add_combinational(f"{new_name} array_{i} (")
1324f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_clk(RW0_clk),")
1334f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_addr(RW0_addr),")
1344f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_en(RW0_en),")
1354f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_wmode(RW0_wmode && RW0_wmask[{i}]),")
1364f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_wdata(RW0_wdata{data_slice}),")
1374f24fc9aSDan Tang      mem.add_combinational(f"  .RW0_rdata(RW0_rdata{data_slice})")
1384f24fc9aSDan Tang      mem.add_combinational(f");")
1394f24fc9aSDan Tang
1404f24fc9aSDan Tangclass SRAM(object):
1414f24fc9aSDan Tang  def __init__(self, line):
1424f24fc9aSDan Tang    self.parse_line(line)
1434f24fc9aSDan Tang    self.prepare_module()
1444f24fc9aSDan Tang
1454f24fc9aSDan Tang  def parse_line(self, line):
146885733f1SZihao Yu    name = ''
147885733f1SZihao Yu    width = 0
148885733f1SZihao Yu    depth = 0
149885733f1SZihao Yu    ports = ''
150885733f1SZihao Yu    mask_gran = 0
151885733f1SZihao Yu    tokens = line.split()
152885733f1SZihao Yu    i = 0
153885733f1SZihao Yu    for i in range(0, len(tokens), 2):
154885733f1SZihao Yu      s = tokens[i]
155885733f1SZihao Yu      if s == 'name':
156885733f1SZihao Yu        name = tokens[i+1]
157885733f1SZihao Yu      elif s == 'width':
158885733f1SZihao Yu        width = int(tokens[i+1])
159885733f1SZihao Yu        mask_gran = width # default setting
160885733f1SZihao Yu      elif s == 'depth':
161885733f1SZihao Yu        depth = int(tokens[i+1])
162885733f1SZihao Yu      elif s == 'ports':
163885733f1SZihao Yu        ports = tokens[i+1].split(',')
164885733f1SZihao Yu      elif s == 'mask_gran':
165885733f1SZihao Yu        mask_gran = int(tokens[i+1])
166885733f1SZihao Yu      else:
1674f24fc9aSDan Tang        sys.exit('%s: unknown argument %s' % (sys.argv[0], i))
1684f24fc9aSDan Tang    self.conf = (name, width, depth, mask_gran, width//mask_gran, ports)
1694f24fc9aSDan Tang  # return (name, width, depth, mask_gran, width//mask_gran, ports)
170885733f1SZihao Yu
1714f24fc9aSDan Tang  def prepare_module(self):
1724f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, ports) = self.conf
173885733f1SZihao Yu    addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
1744f24fc9aSDan Tang
1754f24fc9aSDan Tang    mem = VerilogModuleGenerator(name)
176885733f1SZihao Yu    readports = []
177885733f1SZihao Yu    writeports = []
178885733f1SZihao Yu    latchports = []
179885733f1SZihao Yu    rwports = []
180885733f1SZihao Yu    maskedports = {}
1814f24fc9aSDan Tang
1824f24fc9aSDan Tang    for pid, ptype in enumerate(ports):
183885733f1SZihao Yu      if ptype[0:1] == 'm':
184885733f1SZihao Yu        ptype = ptype[1:]
185885733f1SZihao Yu        maskedports[pid] = pid
186885733f1SZihao Yu
187885733f1SZihao Yu      if ptype == 'read':
188885733f1SZihao Yu        prefix = 'R%d_' % len(readports)
1894f24fc9aSDan Tang        mem.add_input(1, prefix + "clk")
1904f24fc9aSDan Tang        mem.add_input(addr_width, prefix + "addr")
1914f24fc9aSDan Tang        mem.add_input(1, prefix + "en")
1924f24fc9aSDan Tang        mem.add_output(width, prefix + "data")
193885733f1SZihao Yu        readports.append(pid)
194885733f1SZihao Yu      elif ptype == 'write':
195885733f1SZihao Yu        prefix = 'W%d_' % len(writeports)
1964f24fc9aSDan Tang        mem.add_input(1, prefix + "clk")
1974f24fc9aSDan Tang        mem.add_input(addr_width, prefix + "addr")
1984f24fc9aSDan Tang        mem.add_input(1, prefix + "en")
1994f24fc9aSDan Tang        mem.add_input(width, prefix + "data")
200885733f1SZihao Yu        if pid in maskedports:
2014f24fc9aSDan Tang          mem.add_input(mask_seg, prefix + "mask")
202885733f1SZihao Yu        if not use_latches or pid in maskedports:
203885733f1SZihao Yu          writeports.append(pid)
204885733f1SZihao Yu        else:
205885733f1SZihao Yu          latchports.append(pid)
206885733f1SZihao Yu      elif ptype == 'rw':
207885733f1SZihao Yu        prefix = 'RW%d_' % len(rwports)
2084f24fc9aSDan Tang        mem.add_input(1, prefix + "clk")
2094f24fc9aSDan Tang        mem.add_input(addr_width, prefix + "addr")
2104f24fc9aSDan Tang        mem.add_input(1, prefix + "en")
2114f24fc9aSDan Tang        mem.add_input(1, prefix + "wmode")
212885733f1SZihao Yu        if pid in maskedports:
2134f24fc9aSDan Tang          mem.add_input(mask_seg, prefix + "wmask")
2144f24fc9aSDan Tang        mem.add_input(width, prefix + "wdata")
2154f24fc9aSDan Tang        mem.add_output(width, prefix + "rdata")
216885733f1SZihao Yu        rwports.append(pid)
217885733f1SZihao Yu      else:
218885733f1SZihao Yu        sys.exit('%s: unknown port type %s' % (sys.argv[0], ptype))
2194f24fc9aSDan Tang    self.mem = mem
2204f24fc9aSDan Tang    self.ports_conf = (readports, writeports, latchports, rwports, maskedports)
2214f24fc9aSDan Tang
2224f24fc9aSDan Tang  def generate(self, blackbox):
2234f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, ports) = self.conf
2244f24fc9aSDan Tang    addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
2254f24fc9aSDan Tang    mem, (readports, writeports, latchports, rwports, maskedports) = self.mem, self.ports_conf
226885733f1SZihao Yu
227885733f1SZihao Yu    nr = len(readports)
228885733f1SZihao Yu    nw = len(writeports)
229885733f1SZihao Yu    nrw = len(rwports)
230885733f1SZihao Yu
231885733f1SZihao Yu    def emit_read(idx, rw):
232885733f1SZihao Yu      prefix = ('RW%d_' if rw else 'R%d_') % idx
233885733f1SZihao Yu      data = ('%srdata' if rw else '%sdata') % prefix
234885733f1SZihao Yu      en = ('%sen && !%swmode' % (prefix, prefix)) if rw else ('%sen' % prefix)
2354f24fc9aSDan Tang      mem.add_decl_reg(1, f"reg_{prefix}ren")
2364f24fc9aSDan Tang      mem.add_decl_reg(addr_width, f"reg_{prefix}addr")
2374f24fc9aSDan Tang      mem.add_sequential(f"always @(posedge {prefix}clk)")
2384f24fc9aSDan Tang      mem.add_sequential(f"  reg_{prefix}ren <= {en};")
2394f24fc9aSDan Tang      mem.add_sequential(f"always @(posedge {prefix}clk)")
2404f24fc9aSDan Tang      mem.add_sequential(f"  if ({en}) reg_{prefix}addr <= {prefix}addr;")
2414f24fc9aSDan Tang      mem.add_combinational("`ifdef RANDOMIZE_GARBAGE_ASSIGN")
2424f24fc9aSDan Tang      mem.add_combinational(f"reg [{((width-1)//32+1)*32-1}:0] {prefix}random;")
2434f24fc9aSDan Tang      mem.add_combinational(f"`ifdef RANDOMIZE_MEM_INIT")
2444f24fc9aSDan Tang      mem.add_combinational(f"  initial begin")
2454f24fc9aSDan Tang      mem.add_combinational(f"    #`RANDOMIZE_DELAY begin end")
2464f24fc9aSDan Tang      mem.add_combinational('    %srandom = {%s};' % (prefix, ', '.join(['$random'] * ((width-1)//32+1))))
2474f24fc9aSDan Tang      mem.add_combinational('    reg_%sren = %srandom[0];' % (prefix, prefix))
2484f24fc9aSDan Tang      mem.add_combinational('  end')
2494f24fc9aSDan Tang      mem.add_combinational('`endif')
2504f24fc9aSDan Tang      mem.add_combinational('always @(posedge %sclk) %srandom <= {%s};' % (prefix, prefix, ', '.join(['$random'] * ((width-1)//32+1))))
2514f24fc9aSDan Tang      mem.add_combinational('assign %s = reg_%sren ? ram[reg_%saddr] : %srandom[%d:0];' % (data, prefix, prefix, prefix, width-1))
2524f24fc9aSDan Tang      mem.add_combinational('`else')
2534f24fc9aSDan Tang      mem.add_combinational('assign %s = ram[reg_%saddr];' % (data, prefix))
2544f24fc9aSDan Tang      mem.add_combinational('`endif')
255885733f1SZihao Yu
256885733f1SZihao Yu    for idx in range(nr):
257885733f1SZihao Yu      emit_read(idx, False)
258885733f1SZihao Yu
259885733f1SZihao Yu    for idx in range(nrw):
260885733f1SZihao Yu      emit_read(idx, True)
261885733f1SZihao Yu
262885733f1SZihao Yu    for idx in range(len(latchports)):
263885733f1SZihao Yu      prefix = 'W%d_' % idx
2644f24fc9aSDan Tang      mem.add_decl_reg(addr_width, f"latch_{prefix}addr")
2654f24fc9aSDan Tang      mem.add_decl_reg(width, f"latch_{prefix}data")
2664f24fc9aSDan Tang      mem.add_decl_reg(1, f"latch_{prefix}en")
2674f24fc9aSDan Tang      mem.add_combinational('always @(*) begin')
2684f24fc9aSDan Tang      mem.add_combinational('  if (!%sclk && %sen) latch_%saddr <= %saddr;' % (prefix, prefix, prefix, prefix))
2694f24fc9aSDan Tang      mem.add_combinational('  if (!%sclk && %sen) latch_%sdata <= %sdata;' % (prefix, prefix, prefix, prefix))
2704f24fc9aSDan Tang      mem.add_combinational('  if (!%sclk) latch_%sen <= %sen;' % (prefix, prefix, prefix))
2714f24fc9aSDan Tang      mem.add_combinational('end')
2724f24fc9aSDan Tang      mem.add_combinational('always @(*)')
2734f24fc9aSDan Tang      mem.add_combinational('  if (%sclk && latch_%sen)' % (prefix, prefix))
2744f24fc9aSDan Tang      mem.add_combinational('    ram[latch_%saddr] <= latch_%sdata;' % (prefix, prefix))
275885733f1SZihao Yu
27651e45dbbSTang Haojin    mem.add_decl_ram(width, "ram", depth)
2774f24fc9aSDan Tang    mem.add_decl_line('`ifdef RANDOMIZE_MEM_INIT')
2784f24fc9aSDan Tang    mem.add_decl_line('  integer initvar;')
2794f24fc9aSDan Tang    mem.add_decl_line('  initial begin')
2804f24fc9aSDan Tang    mem.add_decl_line('    #`RANDOMIZE_DELAY begin end')
2814f24fc9aSDan Tang    mem.add_decl_line('    for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth)
2824f24fc9aSDan Tang    mem.add_decl_line('      ram[initvar] = {%d {$random}};' % ((width-1)//32+1))
283885733f1SZihao Yu    for idx in range(nr):
284885733f1SZihao Yu      prefix = 'R%d_' % idx
2854f24fc9aSDan Tang      mem.add_decl_line('    reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
286885733f1SZihao Yu    for idx in range(nrw):
287885733f1SZihao Yu      prefix = 'RW%d_' % idx
2884f24fc9aSDan Tang      mem.add_decl_line('    reg_%saddr = {%d {$random}};' % (prefix, ((addr_width-1)//32+1)))
2894f24fc9aSDan Tang    mem.add_decl_line('  end')
2904f24fc9aSDan Tang    mem.add_decl_line('`endif')
291885733f1SZihao Yu
2924f24fc9aSDan Tang    mem.add_decl_line("integer i;")
293885733f1SZihao Yu    for idx in range(nw):
294885733f1SZihao Yu      prefix = 'W%d_' % idx
295885733f1SZihao Yu      pid = writeports[idx]
2964f24fc9aSDan Tang      mem.add_sequential('always @(posedge %sclk)' % prefix)
2974f24fc9aSDan Tang      mem.add_sequential("  if (%sen) begin" % prefix)
298885733f1SZihao Yu      for i in range(mask_seg):
299885733f1SZihao Yu        mask = ('if (%smask[%d]) ' % (prefix, i)) if pid in maskedports else ''
300885733f1SZihao Yu        ram_range = '%d:%d' % ((i+1)*mask_gran-1, i*mask_gran)
3014f24fc9aSDan Tang        mem.add_sequential("    %sram[%saddr][%s] <= %sdata[%s];" % (mask, prefix, ram_range, prefix, ram_range))
3024f24fc9aSDan Tang      mem.add_sequential("  end")
303885733f1SZihao Yu    for idx in range(nrw):
304885733f1SZihao Yu      pid = rwports[idx]
305885733f1SZihao Yu      prefix = 'RW%d_' % idx
3064f24fc9aSDan Tang      mem.add_sequential('always @(posedge %sclk)' % prefix)
3074f24fc9aSDan Tang      mem.add_sequential("  if (%sen && %swmode) begin" % (prefix, prefix))
308885733f1SZihao Yu      if mask_seg > 0:
309ac271a23SEaston Man        if mask_gran == 1: # If 1 bit mask, use & instead
310ac271a23SEaston Man          if pid in maskedports:
311*7ee24868SEaston Man            mem.add_sequential("      ram[%saddr] <= (%swmask & %swdata) | (~%swmask & ram[%saddr]);" %(prefix, prefix, prefix, prefix, prefix))
312ac271a23SEaston Man          else:
313ac271a23SEaston Man            mem.add_sequential("      ram[%saddr] <= %swdata;" %(prefix, prefix))
314ac271a23SEaston Man        else:
3154f24fc9aSDan Tang          mem.add_sequential("    for (i=0;i<%d;i=i+1) begin" % mask_seg)
316885733f1SZihao Yu          if pid in maskedports:
3174f24fc9aSDan Tang            mem.add_sequential("      if (%swmask[i]) begin" % prefix)
3184f24fc9aSDan Tang            mem.add_sequential("        ram[%saddr][i*%d +: %d] <= %swdata[i*%d +: %d];" %(prefix, mask_gran, mask_gran, prefix, mask_gran, mask_gran))
3194f24fc9aSDan Tang            mem.add_sequential("      end")
320885733f1SZihao Yu          else:
3214f24fc9aSDan Tang            mem.add_sequential("      ram[%saddr][i*%d +: %d] <= %swdata[i*%d +: %d];" %(prefix, mask_gran, mask_gran, prefix, mask_gran, mask_gran))
3224f24fc9aSDan Tang          mem.add_sequential("    end")
3234f24fc9aSDan Tang      mem.add_sequential("  end")
3244f24fc9aSDan Tang    return mem.generate(blackbox)
325885733f1SZihao Yu
3264f24fc9aSDan Tang
3274f24fc9aSDan Tangclass SRAM_TSMC28(SRAM):
3284f24fc9aSDan Tang  def __init__(self, line):
3294f24fc9aSDan Tang    super().__init__(line)
3304f24fc9aSDan Tang    self.sub_srams = []
3314f24fc9aSDan Tang    if self.__check_subsrams():
3324f24fc9aSDan Tang      print(line.strip())
3334f24fc9aSDan Tang
3344f24fc9aSDan Tang  def __check_subsrams(self):
3354f24fc9aSDan Tang    need_split = self.__split()
3364f24fc9aSDan Tang    need_reshape  = self.__reshape()
3374f24fc9aSDan Tang    assert(not (need_split and need_reshape))
3384f24fc9aSDan Tang    return not need_split and not need_reshape
3394f24fc9aSDan Tang
3404f24fc9aSDan Tang  def __split(self):
3414f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, ports) = self.conf
342eae78b10SYinan Xu    '''if ports == ["mrw"] and mask_gran >= 32:
3434f24fc9aSDan Tang      new_conf = (name + "_sub", str(depth), str(mask_gran), "rw")
3444f24fc9aSDan Tang      line_field = ("name", "depth", "width", "ports")
3454f24fc9aSDan Tang      new_line = " ".join(map(lambda x: " ".join(x), zip(line_field, new_conf)))
3464f24fc9aSDan Tang      new_sram = SRAM_TSMC28(new_line)
3474f24fc9aSDan Tang      self.sub_srams.append(new_sram)
3484f24fc9aSDan Tang      reshaper = Spliter(self.conf, new_sram.conf)
3494f24fc9aSDan Tang      reshaper.generate(self.mem)
350eae78b10SYinan Xu      return True'''
3514f24fc9aSDan Tang    return False
3524f24fc9aSDan Tang
3534f24fc9aSDan Tang  def __reshape(self):
3544f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, ports) = self.conf
3554f24fc9aSDan Tang    if width == 2 and depth == 256:
3564f24fc9aSDan Tang      new_conf = (name + "_sub", "64", "8", "mwrite,read", "2")
3574f24fc9aSDan Tang      line_field = ("name", "depth", "width", "ports", "mask_gran")
3584f24fc9aSDan Tang      new_line = " ".join(map(lambda x: " ".join(x), zip(line_field, new_conf)))
3594f24fc9aSDan Tang      new_sram = SRAM_TSMC28(new_line)
3604f24fc9aSDan Tang      self.sub_srams.append(new_sram)
3614f24fc9aSDan Tang      reshaper = Reshaper(self.conf, new_sram.conf)
3624f24fc9aSDan Tang      reshaper.generate(self.mem)
3634f24fc9aSDan Tang      return True
3644f24fc9aSDan Tang    return False
3654f24fc9aSDan Tang
3664f24fc9aSDan Tang  def __get_tsmc_lib(self):
3674f24fc9aSDan Tang    mem, (readports, writeports, latchports, rwports, maskedports) = self.mem, self.ports_conf
3684f24fc9aSDan Tang    blackbox = "// tsmc lib here\n"
3694f24fc9aSDan Tang    (name, width, depth, mask_gran, mask_seg, _) = self.conf
3704f24fc9aSDan Tang    nports = (len(readports), len(writeports), len(rwports))
3714f24fc9aSDan Tang    addr_width = max(math.ceil(math.log(depth)/math.log(2)),1)
3724f24fc9aSDan Tang    masked = len(maskedports) > 0
3734f24fc9aSDan Tang    # from tsmc28_sram import gen_tsmc_ram_1pw, gen_tsmc_ram_1pnw, gen_tsmc_ram_2pw, gen_tsmc_ram_2pnw
3744f24fc9aSDan Tang    # if nports == (1, 1, 0):
3754f24fc9aSDan Tang    #   if masked:
3764f24fc9aSDan Tang    #     blackbox = gen_tsmc_ram_2pw("TS6N28HPCPLVTA64X8M2F", width, mask_gran)
3774f24fc9aSDan Tang    #   else:
3784f24fc9aSDan Tang    #     blackbox = gen_tsmc_ram_2pnw("TS6N28HPCPLVTA64X14M2F")
3794f24fc9aSDan Tang    # elif nports == (0, 0, 1):
3804f24fc9aSDan Tang    #   if masked:
3814f24fc9aSDan Tang    #     blackbox = gen_tsmc_ram_1pw('TS1N28HPCPLVTB8192X64M8SW', width, mask_gran, addr_width)
3824f24fc9aSDan Tang    #   else:
3834f24fc9aSDan Tang    #     blackbox = gen_tsmc_ram_1pnw('TS5N28HPCPLVTA64X144M2F', width, addr_width)
3844f24fc9aSDan Tang    # else:
3854f24fc9aSDan Tang    #   blackbox = "// unknown tsmc lib type\n"
3864f24fc9aSDan Tang    return mem.generate(blackbox)
3874f24fc9aSDan Tang
3884f24fc9aSDan Tang  def generate(self, blackbox, itself_only=False):
3894f24fc9aSDan Tang    if itself_only:
3904f24fc9aSDan Tang      # generate splits or reshapes
3914f24fc9aSDan Tang      if self.sub_srams:
3924f24fc9aSDan Tang        return self.mem.generate("")
3934f24fc9aSDan Tang      # use empty blackbox
3944f24fc9aSDan Tang      elif blackbox:
3954f24fc9aSDan Tang        return super().generate(" ")
3964f24fc9aSDan Tang      # insert tsmc libs
3974f24fc9aSDan Tang      else:
3984f24fc9aSDan Tang        return self.__get_tsmc_lib()
3994f24fc9aSDan Tang    else:
4004f24fc9aSDan Tang      s = self.generate(blackbox, True)
4014f24fc9aSDan Tang      for sram in self.sub_srams:
4024f24fc9aSDan Tang        s += sram.generate(blackbox)
403885733f1SZihao Yu      return s
404885733f1SZihao Yu
4054f24fc9aSDan Tang
406885733f1SZihao Yudef main(args):
407885733f1SZihao Yu  f = open(args.output_file, "w") if (args.output_file) else None
408885733f1SZihao Yu  conf_file = args.conf
409885733f1SZihao Yu  for line in open(conf_file):
4104f24fc9aSDan Tang    sram = SRAM(line)
4114f24fc9aSDan Tang    if args.tsmc28:
4124f24fc9aSDan Tang      sram = SRAM_TSMC28(line)
413885733f1SZihao Yu    else:
4144f24fc9aSDan Tang      sram = SRAM(line)
4154f24fc9aSDan Tang    if f is not None:
4164f24fc9aSDan Tang        f.write(sram.generate(args.blackbox))
4174f24fc9aSDan Tang    else:
4184f24fc9aSDan Tang        print(sram.generate(args.blackbox))
4194f24fc9aSDan Tang
420885733f1SZihao Yu
421885733f1SZihao Yuif __name__ == '__main__':
422885733f1SZihao Yu  import argparse
423885733f1SZihao Yu  parser = argparse.ArgumentParser(description='Memory generator for Rocket Chip')
424885733f1SZihao Yu  parser.add_argument('conf', metavar='.conf file')
4254f24fc9aSDan Tang  parser.add_argument('--tsmc28', action='store_true', help='use tsmc28 sram to generate module body')
426885733f1SZihao Yu  parser.add_argument('--blackbox', '-b', action='store_true', help='set to disable output of module body')
427885733f1SZihao Yu  #parser.add_argument('--use_latches', '-l', action='store_true', help='set to enable use of latches')
428885733f1SZihao Yu  parser.add_argument('--output_file', '-o', help='name of output file, default is stdout')
429885733f1SZihao Yu  args = parser.parse_args()
430885733f1SZihao Yu  #use_latches = args.use_latches
431885733f1SZihao Yu  main(args)
432