lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 4 | """Generate SystemVerilog designs from IpBlock object""" |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 5 | |
| 6 | import logging as log |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 7 | import os |
| 8 | from typing import Dict, Optional, Tuple |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 9 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 10 | from mako import exceptions # type: ignore |
| 11 | from mako.template import Template # type: ignore |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 12 | from pkg_resources import resource_filename |
| 13 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 14 | from .ip_block import IpBlock |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 15 | from .multi_register import MultiRegister |
| 16 | from .reg_base import RegBase |
| 17 | from .register import Register |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 18 | |
Eunchan Kim | 51461cd | 2019-09-18 14:00:49 -0700 | [diff] [blame] | 19 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 20 | def escape_name(name: str) -> str: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 21 | return name.lower().replace(' ', '_') |
| 22 | |
| 23 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 24 | def make_box_quote(msg: str, indent: str = ' ') -> str: |
| 25 | hr = indent + ('/' * (len(msg) + 6)) |
| 26 | middle = indent + '// ' + msg + ' //' |
| 27 | return '\n'.join([hr, middle, hr]) |
| 28 | |
| 29 | |
| 30 | def _get_awparam_name(iface_name: Optional[str]) -> str: |
| 31 | return (iface_name or 'Iface').capitalize() + 'Aw' |
| 32 | |
| 33 | |
| 34 | def get_addr_widths(block: IpBlock) -> Dict[Optional[str], Tuple[str, int]]: |
| 35 | '''Return the address widths for the device interfaces |
| 36 | |
| 37 | Returns a dictionary keyed by interface name whose values are pairs: |
| 38 | (paramname, width) where paramname is IfaceAw for an unnamed interface and |
| 39 | FooAw for an interface called foo. This is constructed in the same order as |
| 40 | block.reg_blocks. |
| 41 | |
| 42 | If there is a single device interface and that interface is unnamed, use |
| 43 | the more general parameter name "BlockAw". |
| 44 | |
| 45 | ''' |
| 46 | assert block.reg_blocks |
| 47 | if len(block.reg_blocks) == 1 and None in block.reg_blocks: |
| 48 | return {None: ('BlockAw', block.reg_blocks[None].get_addr_width())} |
| 49 | |
| 50 | return {name: (_get_awparam_name(name), rb.get_addr_width()) |
| 51 | for name, rb in block.reg_blocks.items()} |
| 52 | |
| 53 | |
| 54 | def get_type_name_pfx(block: IpBlock, iface_name: Optional[str]) -> str: |
| 55 | return block.name.lower() + ('' if iface_name is None |
| 56 | else '_{}'.format(iface_name.lower())) |
| 57 | |
| 58 | |
| 59 | def get_r0(reg: RegBase) -> Register: |
| 60 | '''Get a Register representing an entry in the RegBase''' |
| 61 | if isinstance(reg, Register): |
| 62 | return reg |
| 63 | else: |
| 64 | assert isinstance(reg, MultiRegister) |
| 65 | return reg.reg |
| 66 | |
| 67 | |
| 68 | def get_iface_tx_type(block: IpBlock, |
| 69 | iface_name: Optional[str], |
| 70 | hw2reg: bool) -> str: |
| 71 | x2x = 'hw2reg' if hw2reg else 'reg2hw' |
| 72 | pfx = get_type_name_pfx(block, iface_name) |
| 73 | return '_'.join([pfx, x2x, 't']) |
| 74 | |
| 75 | |
| 76 | def get_reg_tx_type(block: IpBlock, reg: RegBase, hw2reg: bool) -> str: |
| 77 | '''Get the name of the hw2reg or reg2hw type for reg''' |
| 78 | if isinstance(reg, Register): |
| 79 | r0 = reg |
| 80 | type_suff = 'reg_t' |
| 81 | else: |
| 82 | assert isinstance(reg, MultiRegister) |
| 83 | r0 = reg.reg |
| 84 | type_suff = 'mreg_t' |
| 85 | |
| 86 | x2x = 'hw2reg' if hw2reg else 'reg2hw' |
| 87 | return '_'.join([block.name.lower(), |
| 88 | x2x, |
| 89 | r0.name.lower(), |
| 90 | type_suff]) |
| 91 | |
| 92 | |
| 93 | def gen_rtl(block: IpBlock, outdir: str) -> int: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 94 | # Read Register templates |
| 95 | reg_top_tpl = Template( |
Michael Schaffner | c703936 | 2019-10-22 16:16:06 -0700 | [diff] [blame] | 96 | filename=resource_filename('reggen', 'reg_top.sv.tpl')) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 97 | reg_pkg_tpl = Template( |
Michael Schaffner | c703936 | 2019-10-22 16:16:06 -0700 | [diff] [blame] | 98 | filename=resource_filename('reggen', 'reg_pkg.sv.tpl')) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 99 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 100 | # Generate <block>_reg_pkg.sv |
| 101 | # |
| 102 | # This defines the various types used to interface between the *_reg_top |
| 103 | # module(s) and the block itself. |
| 104 | reg_pkg_path = os.path.join(outdir, block.name.lower() + "_reg_pkg.sv") |
| 105 | with open(reg_pkg_path, 'w', encoding='UTF-8') as fout: |
Eunchan Kim | cb28a17 | 2019-10-08 16:35:48 -0700 | [diff] [blame] | 106 | try: |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 107 | fout.write(reg_pkg_tpl.render(block=block)) |
Rupert Swarbrick | 6880e21 | 2021-02-10 16:10:00 +0000 | [diff] [blame] | 108 | except: # noqa F722 for template Exception handling |
Eunchan Kim | cb28a17 | 2019-10-08 16:35:48 -0700 | [diff] [blame] | 109 | log.error(exceptions.text_error_template().render()) |
Rupert Swarbrick | 6880e21 | 2021-02-10 16:10:00 +0000 | [diff] [blame] | 110 | return 1 |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 111 | |
Rupert Swarbrick | 200d8b4 | 2021-03-08 12:32:11 +0000 | [diff] [blame] | 112 | # Generate the register block implementation(s). For a device interface |
| 113 | # with no name we generate the register module "<block>_reg_top" (writing |
| 114 | # to <block>_reg_top.sv). In any other case, we also need the interface |
| 115 | # name, giving <block>_<ifname>_reg_top. |
| 116 | lblock = block.name.lower() |
| 117 | for if_name, rb in block.reg_blocks.items(): |
| 118 | if if_name is None: |
| 119 | mod_base = lblock |
| 120 | else: |
| 121 | mod_base = lblock + '_' + if_name.lower() |
| 122 | |
| 123 | mod_name = mod_base + '_reg_top' |
| 124 | reg_top_path = os.path.join(outdir, mod_name + '.sv') |
| 125 | with open(reg_top_path, 'w', encoding='UTF-8') as fout: |
| 126 | try: |
| 127 | fout.write(reg_top_tpl.render(block=block, |
| 128 | mod_base=mod_base, |
| 129 | mod_name=mod_name, |
| 130 | if_name=if_name, |
| 131 | rb=rb)) |
| 132 | except: # noqa F722 for template Exception handling |
| 133 | log.error(exceptions.text_error_template().render()) |
| 134 | return 1 |
Rupert Swarbrick | 6880e21 | 2021-02-10 16:10:00 +0000 | [diff] [blame] | 135 | |
| 136 | return 0 |