186 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
import sys
 | 
						|
import math
 | 
						|
 | 
						|
# This is based off of reference-chip/vlsi/src/vlsi_mem_gen
 | 
						|
 | 
						|
use_latches = 1
 | 
						|
 | 
						|
 | 
						|
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 xrange(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)]
 | 
						|
 | 
						|
  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()
 |