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