|  | #!/usr/bin/env python3 | 
|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  | r"""Flash Controller Generator | 
|  | """ | 
|  |  | 
|  | import logging as log | 
|  | import sys | 
|  | from collections import OrderedDict | 
|  | from pathlib import Path | 
|  |  | 
|  | import hjson | 
|  | from mako.template import Template | 
|  |  | 
|  |  | 
|  | class Flash: | 
|  | """Flash class contains information regarding parameter defaults. | 
|  | For now, only expose banks / pages_per_bank for user configuration. | 
|  | For now, also enforce power of 2 requirement. | 
|  | """ | 
|  | max_banks = 4 | 
|  | max_pages_per_bank = 1024 | 
|  |  | 
|  | def __init__(self, mem, base_addr): | 
|  | self.base_addr = int(base_addr, 16) | 
|  | self.banks = mem.get('banks', 2) | 
|  | self.pages_per_bank = mem.get('pages_per_bank', 8) | 
|  | self.program_resolution = mem.get('program_resolution', 128) | 
|  | self.words_per_page = 256 | 
|  | self.data_width = 64 | 
|  | self.metadata_width = 12 | 
|  | self.info_types = 3 | 
|  | self.infos_per_bank = [10, 1, 2] | 
|  | self.word_bytes = int(self.data_width / 8) | 
|  | self.pgm_resolution_bytes = int(self.program_resolution * self.word_bytes) | 
|  | self.check_values() | 
|  |  | 
|  | # populate size variable | 
|  | self.bytes_per_page = self.word_bytes * self.words_per_page | 
|  | self.bytes_per_bank = self.bytes_per_page * self.pages_per_bank | 
|  | self.total_bytes = self.bytes_per_bank * self.banks | 
|  |  | 
|  | size_int = int(self.total_bytes) | 
|  | self.size = hex(size_int) | 
|  | self.end_addr = self.base_addr + size_int | 
|  |  | 
|  | def is_pow2(self, n): | 
|  | return (n != 0) and (n & (n - 1) == 0) | 
|  |  | 
|  | def check_values(self): | 
|  | pow2_check = (self.is_pow2(self.banks) and | 
|  | self.is_pow2(self.pages_per_bank) and | 
|  | self.is_pow2(self.program_resolution)) | 
|  | limit_check = ((self.banks <= Flash.max_banks) and | 
|  | (self.pages_per_bank <= Flash.max_pages_per_bank)) | 
|  |  | 
|  | if not pow2_check: | 
|  | raise ValueError(f'flash power of 2 check failed. A supplied parameter ' | 
|  | 'is not power of 2') | 
|  |  | 
|  | if not limit_check: | 
|  | raise ValueError(f'flash number of banks and pages per bank too large') | 
|  |  | 
|  |  | 
|  | # Common header for generated files | 
|  | def main(): | 
|  |  | 
|  | current = Path(__file__).parent.absolute() | 
|  |  | 
|  | hjson_tpl = Template(filename=str(current / '../data/flash_ctrl.hjson.tpl')) | 
|  | region_cfg_tpl = Template(filename=str(current / '../data/flash_ctrl_region_cfg.sv.tpl')) | 
|  | rtl_tpl = Template(filename=str(current / '../data/flash_ctrl.sv.tpl')) | 
|  | pkg_tpl = Template(filename=str(current / '../data/flash_ctrl_pkg.sv.tpl')) | 
|  |  | 
|  | hjson_out = current / '../data/flash_ctrl.hjson' | 
|  | region_cfg_out = current / '../rtl/flash_ctrl_region_cfg.sv' | 
|  | rtl_out = current / '../rtl/flash_ctrl.sv' | 
|  | pkg_out = current / '../rtl/flash_ctrl_pkg.sv' | 
|  | cfgpath = current / '../../../top_earlgrey/data/autogen/top_earlgrey.gen.hjson' | 
|  |  | 
|  | try: | 
|  | with open(cfgpath, 'r') as cfg: | 
|  | topcfg = hjson.load(cfg, use_decimal=True, object_pairs_hook=OrderedDict) | 
|  | except ValueError: | 
|  | log.error("{} not found".format(cfgpath)) | 
|  | raise SystemExit(sys.exc_info()[1]) | 
|  |  | 
|  |  | 
|  | flash_mems = [module for module in topcfg['module'] if module['type'] == 'flash_ctrl'] | 
|  | if len(flash_mems) > 1: | 
|  | log.error("This design does not currently support multiple flashes") | 
|  | return | 
|  |  | 
|  | cfg = Flash(flash_mems[0]['memory']['mem']['config'], | 
|  | flash_mems[0]['base_addrs']['mem']) | 
|  |  | 
|  | # generate hjson | 
|  | hjson_out.write_text(hjson_tpl.render(cfg=cfg)) | 
|  |  | 
|  | # generate rtl package | 
|  | pkg_out.write_text(pkg_tpl.render(cfg=cfg)) | 
|  |  | 
|  | # generate reg wrap | 
|  | region_cfg_out.write_text(region_cfg_tpl.render(cfg=cfg)) | 
|  |  | 
|  | # generate top level | 
|  | rtl_out.write_text(rtl_tpl.render(cfg=cfg)) | 
|  |  | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | main() |