# Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 """Generate SystemVerilog designs from IpBlock object""" import logging as log import os from typing import Dict, Optional, Tuple from mako import exceptions # type: ignore from mako.template import Template # type: ignore from pkg_resources import resource_filename from .ip_block import IpBlock from .multi_register import MultiRegister from .reg_base import RegBase from .register import Register def escape_name(name: str) -> str: return name.lower().replace(' ', '_') def make_box_quote(msg: str, indent: str = ' ') -> str: hr = indent + ('/' * (len(msg) + 6)) middle = indent + '// ' + msg + ' //' return '\n'.join([hr, middle, hr]) def _get_awparam_name(iface_name: Optional[str]) -> str: return (iface_name or 'Iface').capitalize() + 'Aw' def get_addr_widths(block: IpBlock) -> Dict[Optional[str], Tuple[str, int]]: '''Return the address widths for the device interfaces Returns a dictionary keyed by interface name whose values are pairs: (paramname, width) where paramname is IfaceAw for an unnamed interface and FooAw for an interface called foo. This is constructed in the same order as block.reg_blocks. If there is a single device interface and that interface is unnamed, use the more general parameter name "BlockAw". ''' assert block.reg_blocks if len(block.reg_blocks) == 1 and None in block.reg_blocks: return {None: ('BlockAw', block.reg_blocks[None].get_addr_width())} return {name: (_get_awparam_name(name), rb.get_addr_width()) for name, rb in block.reg_blocks.items()} def get_type_name_pfx(block: IpBlock, iface_name: Optional[str]) -> str: return block.name.lower() + ('' if iface_name is None else '_{}'.format(iface_name.lower())) def get_r0(reg: RegBase) -> Register: '''Get a Register representing an entry in the RegBase''' if isinstance(reg, Register): return reg else: assert isinstance(reg, MultiRegister) return reg.reg def get_iface_tx_type(block: IpBlock, iface_name: Optional[str], hw2reg: bool) -> str: x2x = 'hw2reg' if hw2reg else 'reg2hw' pfx = get_type_name_pfx(block, iface_name) return '_'.join([pfx, x2x, 't']) def get_reg_tx_type(block: IpBlock, reg: RegBase, hw2reg: bool) -> str: '''Get the name of the hw2reg or reg2hw type for reg''' if isinstance(reg, Register): r0 = reg type_suff = 'reg_t' else: assert isinstance(reg, MultiRegister) r0 = reg.reg type_suff = 'mreg_t' x2x = 'hw2reg' if hw2reg else 'reg2hw' return '_'.join([block.name.lower(), x2x, r0.name.lower(), type_suff]) def gen_rtl(block: IpBlock, outdir: str) -> int: # Read Register templates reg_top_tpl = Template( filename=resource_filename('reggen', 'reg_top.sv.tpl')) reg_pkg_tpl = Template( filename=resource_filename('reggen', 'reg_pkg.sv.tpl')) # Generate _reg_pkg.sv # # This defines the various types used to interface between the *_reg_top # module(s) and the block itself. reg_pkg_path = os.path.join(outdir, block.name.lower() + "_reg_pkg.sv") with open(reg_pkg_path, 'w', encoding='UTF-8') as fout: try: fout.write(reg_pkg_tpl.render(block=block)) except: # noqa F722 for template Exception handling log.error(exceptions.text_error_template().render()) return 1 # Generate the register block implementation(s). For a device interface # with no name we generate the register module "_reg_top" (writing # to _reg_top.sv). In any other case, we also need the interface # name, giving __reg_top. lblock = block.name.lower() for if_name, rb in block.reg_blocks.items(): if if_name is None: mod_base = lblock else: mod_base = lblock + '_' + if_name.lower() mod_name = mod_base + '_reg_top' reg_top_path = os.path.join(outdir, mod_name + '.sv') with open(reg_top_path, 'w', encoding='UTF-8') as fout: try: fout.write(reg_top_tpl.render(block=block, mod_base=mod_base, mod_name=mod_name, if_name=if_name, rb=rb)) except: # noqa F722 for template Exception handling log.error(exceptions.text_error_template().render()) return 1 return 0