| #!/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() |