#! /usr/bin/env python # See LICENSE for license details. # This is based off of reference-chip/vlsi/src/vlsi_mem_gen import sys import math use_latches = False module_template = '''module %s( %s ); %s %s always @(posedge CLK) begin %s end %s endmodule ''' mask_assert_template = ''' `ifndef SYNTHESIS integer i; integer j; always @(posedge CLK) begin%s end `endif ''' assert_template = ''' for (i=0; i<%d; i=i+%d) begin for (j=1; j<%d; j=j+1) begin if (%sM[i] != %sM[i+j]) begin $fwrite(32'h80000002, "ASSERTION FAILED: write mask granularity\\n"); $finish; end end end''' def parse_line(line): name = '' width = 0 depth = 0 ports = '' mask_gran = 1 tokens = line.split() i = 0 for i in range(0,len(tokens),2): s = tokens[i] if s == 'name': name = tokens[i+1] elif s == 'width': width = int(tokens[i+1]) elif s == 'depth': depth = int(tokens[i+1]) elif s == 'ports': ports = tokens[i+1].split(',') elif s == 'mask_gran': mask_gran = int(tokens[i+1]) else: sys.exit('%s: unknown argument %s' % (sys.argv[0], a)) return (name, width, depth, ports, mask_gran) def gen_range(mask_index, mask_gran, max_width): return '%d:%d' % (min(mask_gran*(mask_index+1),max_width)-1, min(mask_gran*(mask_index),max_width)) def gen_mem(name, width, depth, ports, mask_gran): addr_width = max(math.ceil(math.log(depth)/math.log(2)),1) mask_width = int(math.ceil(float(width) / mask_gran)) port_spec = ['input CLK', 'input RST', 'input init'] readports = [] writeports = [] latchports = [] rwports = [] decl = [] combinational = [] sequential = [] maskedports = {} mask_asserts = '' for pid in range(len(ports)): ptype = ports[pid] if ptype[0:1] == 'm': ptype = ptype[1:] maskedports[pid] = pid if ptype == 'read': port_spec += ['input [%d:0] R%dA' % (addr_width-1, pid)] port_spec += ['input R%dE' % pid] port_spec += ['output [%d:0] R%dO' % (width-1, pid)] readports += [pid] elif ptype == 'write': port_spec += ['input [%d:0] W%dA' % (addr_width-1, pid)] port_spec += ['input W%dE' % pid] port_spec += ['input [%d:0] W%dI' % (width-1, pid)] if pid in maskedports: port_spec += ['input [%d:0] W%dM' % (width-1, pid)] if not use_latches or pid in maskedports: writeports += [pid] else: latchports += [pid] elif ptype == 'rw': port_spec += ['input [%d:0] RW%dA' % (addr_width-1, pid)] port_spec += ['input RW%dE' % pid] port_spec += ['input RW%dW' % pid] if pid in maskedports: port_spec += ['input [%d:0] RW%dM' % (width-1, pid)] port_spec += ['input [%d:0] RW%dI' % (width-1, pid)] port_spec += ['output [%d:0] RW%dO' % (width-1, pid)] rwports += [pid] else: sys.exit('%s: unknown port type %s' % (sys.argv[0], ptype)) decl += ['reg [%d:0] ram [%d:0];' % (width-1, depth-1)] decl += ['`ifndef SYNTHESIS'] decl += [' integer initvar;'] decl += [' initial begin'] decl += [' #0.002;'] decl += [' for (initvar = 0; initvar < %d; initvar = initvar+1)' % depth] decl += [' ram[initvar] = {%d {$random}};' % ((width-1)/32+1)] decl += [' end'] decl += ['`endif'] for pid in readports: decl += ['reg [%d:0] reg_R%dA;' % (addr_width-1, pid)] sequential += ['if (R%dE) reg_R%dA <= R%dA;' % (pid, pid, pid)] combinational += ['assign R%dO = ram[reg_R%dA];' % (pid, pid)] for pid in rwports: decl += ['reg [%d:0] reg_RW%dA;' % (addr_width-1, pid)] sequential += ['if (RW%dE && !RW%dW) reg_RW%dA <= RW%dA;' % (pid, pid, pid, pid)] combinational += ['assign RW%dO = ram[reg_RW%dA];' % (pid, pid)] for pid in latchports: decl += ['reg [%d:0] latch_W%dA;' % (addr_width-1, pid)] decl += ['reg [%d:0] latch_W%dI;' % (width-1, pid)] decl += ['reg latch_W%dE;' % (pid)] combinational += ['always @(*) begin'] combinational += [' if (!CLK && W%dE) latch_W%dA <= W%dA;' % (pid, pid, pid)] combinational += [' if (!CLK && W%dE) latch_W%dI <= W%dI;' % (pid, pid, pid)] combinational += [' if (!CLK) latch_W%dE <= W%dE;' % (pid, pid)] combinational += ['end'] combinational += ['always @(*)'] combinational += [' if (CLK && latch_W%dE)' % (pid)] combinational += [' ram[latch_W%dA] <= latch_W%dI;' % (pid, pid)] for pid in writeports: if pid not in maskedports: sequential += ['if (W%dE) ram[W%dA] <= W%dI;' % (pid, pid, pid)] else: for mask_index in range(mask_width): rs = gen_range(mask_index, mask_gran, width) sequential += ['if (W%dE && W%dM[%d]) ram[W%dA][%s] <= W%dI[%s];' % (pid, pid, mask_index*mask_gran, pid, rs, pid, rs)] mask_asserts += assert_template % (mask_width, mask_gran, mask_gran, 'W'+str(pid), 'W'+str(pid)) for pid in rwports: if pid not in maskedports: sequential += ['if (RW%dE && RW%dW) ram[RW%dA] <= RW%dI;' % (pid, pid, pid, pid)] else: for mask_index in range(mask_width): rs = gen_range(mask_index, mask_gran, width) sequential += ['if (RW%dE && RW%dW && RW%dM[%d]) ram[RW%dA][%s] <= RW%dI[%s];' % (pid, pid, pid, mask_index*mask_gran, pid, rs, pid, rs)] mask_asserts += assert_template % (mask_width, mask_gran, mask_gran, 'RW'+str(pid), 'RW'+str(pid)) check_masks = '' if len(maskedports) == 0 else mask_assert_template % mask_asserts return module_template % (name, ',\n '.join(port_spec), check_masks, '\n '.join(decl), '\n '.join(sequential), '\n '.join(combinational)) def main(): if len(sys.argv) < 2: sys.exit('Please give a .conf file as input') for line in open(sys.argv[1]): print(gen_mem(*parse_line(line))) if __name__ == '__main__': main()