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