139 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#! /usr/bin/env python
 | 
						|
 | 
						|
# See LICENSE.SiFive for license details.
 | 
						|
 | 
						|
from __future__ import division
 | 
						|
from __future__ import print_function
 | 
						|
from __future__ import unicode_literals
 | 
						|
 | 
						|
import doctest
 | 
						|
import sys
 | 
						|
import warnings
 | 
						|
from collections import namedtuple
 | 
						|
 | 
						|
verilog_template = """
 | 
						|
module {name}(
 | 
						|
  input clock,
 | 
						|
  input oe,
 | 
						|
  input me,
 | 
						|
  input [{address_bits_minus_1}:0] address,
 | 
						|
  output [{output_width_minus_1}:0] q
 | 
						|
);
 | 
						|
  reg [{output_width_minus_1}:0] out;
 | 
						|
  reg [{output_width_minus_1}:0] rom [0:{depth_minus_1}];
 | 
						|
 | 
						|
 | 
						|
  // 1024 is the maximum length of $readmemh filename supported by Cadence Incisive
 | 
						|
  reg [1024 * 8 - 1:0] path;
 | 
						|
 | 
						|
  integer i;
 | 
						|
  initial begin
 | 
						|
`ifdef RANDOMIZE
 | 
						|
  `ifdef RANDOMIZE_MEM_INIT
 | 
						|
    for (i = 0; i < {depth}; i = i + 1) begin
 | 
						|
      rom[i] = {{{num_random_blocks}{{$random}}}};
 | 
						|
    end
 | 
						|
  `endif
 | 
						|
`endif
 | 
						|
    if (!$value$plusargs("maskromhex=%s", path)) begin
 | 
						|
      path = "{rom_hex_file}";
 | 
						|
    end
 | 
						|
    $readmemh(path, rom);
 | 
						|
  end
 | 
						|
 | 
						|
 | 
						|
  always @(posedge clock) begin
 | 
						|
    if (me) begin
 | 
						|
      out <= rom[address];
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  assign q = oe ? out : {output_width}'bZ;
 | 
						|
 | 
						|
endmodule
 | 
						|
"""
 | 
						|
 | 
						|
 | 
						|
def gen_rom(name, width, depth, rom_hex_file):
 | 
						|
    variables = {
 | 
						|
        'name': name,
 | 
						|
        'address_bits_minus_1': (depth - 1).bit_length() - 1,
 | 
						|
        'depth': depth,
 | 
						|
        'depth_minus_1': depth - 1,
 | 
						|
        'output_width': width,
 | 
						|
        'output_width_minus_1': width - 1,
 | 
						|
        # $random in verilog returns 32 bits; compute how many times to repeat
 | 
						|
        # $random in order to fill the width
 | 
						|
        'num_random_blocks': (width - 1) // 32 + 1,
 | 
						|
        'rom_hex_file': rom_hex_file,
 | 
						|
    }
 | 
						|
    return verilog_template.format(**variables)
 | 
						|
 | 
						|
 | 
						|
def iterate_by_n(it, n):
 | 
						|
    """Iterate over items in it, yielding n-tuples of successive items.
 | 
						|
 | 
						|
    >>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=2))
 | 
						|
    [(1, 2), (3, 4), (5, 6)]
 | 
						|
    >>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=3))
 | 
						|
    [(1, 2, 3), (4, 5, 6)]
 | 
						|
    >>> list(iterate_by_n([1, 2, 3, 4, 5, 6], n=4))
 | 
						|
    Traceback (most recent call last):
 | 
						|
        ...
 | 
						|
    ValueError: Iterable length not evenly divisible by 4
 | 
						|
    """
 | 
						|
    it = iter(it)
 | 
						|
    while True:
 | 
						|
        batch = ()
 | 
						|
        for i in range(n):
 | 
						|
            try:
 | 
						|
                batch += (next(it),)
 | 
						|
            except StopIteration:
 | 
						|
                if batch:  # If this is not the first iteration
 | 
						|
                    raise ValueError(
 | 
						|
                        'Iterable length not evenly divisible by {}'.format(n)
 | 
						|
                    )
 | 
						|
                else:
 | 
						|
                    raise
 | 
						|
        yield batch
 | 
						|
 | 
						|
 | 
						|
def try_cast_int(x):
 | 
						|
    try:
 | 
						|
        return int(x)
 | 
						|
    except ValueError:
 | 
						|
        return x
 | 
						|
 | 
						|
 | 
						|
ROMParameters = namedtuple('ROMParameters', ['name', 'depth', 'width'])
 | 
						|
default_rom_parameters = ROMParameters(name='', depth=0, width=0)
 | 
						|
 | 
						|
 | 
						|
def parse_line(line):
 | 
						|
    kwargs = {key: try_cast_int(val)
 | 
						|
              for key, val in iterate_by_n(line.split(), 2)}
 | 
						|
    rom_parameters = default_rom_parameters._replace(**kwargs)
 | 
						|
    return rom_parameters._asdict()
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
    if '--run-tests' in sys.argv:
 | 
						|
        (failures, total) = doctest.testmod(verbose=True)
 | 
						|
        sys.exit(1 if failures else 0)
 | 
						|
 | 
						|
    if len(sys.argv) < 2:
 | 
						|
        sys.exit('Please give a .conf file as input')
 | 
						|
 | 
						|
    print('// This file created by ' + __file__)
 | 
						|
    with open(sys.argv[1]) as fp:
 | 
						|
        lines = fp.readlines()
 | 
						|
        if len(lines) > 1:
 | 
						|
            warnings.warn('vlsi_rom_gen detected multiple ROMs. ROM contents will be duplicated.')
 | 
						|
        for line in lines:
 | 
						|
            verilog = gen_rom(rom_hex_file=sys.argv[2],
 | 
						|
                              **parse_line(line))
 | 
						|
            print(verilog)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |