diff --git a/docs/props/field.rst b/docs/props/field.rst index f054c9c..cd90298 100644 --- a/docs/props/field.rst +++ b/docs/props/field.rst @@ -448,7 +448,10 @@ Misc encode ^^^^^^ -|NO| +If assigned a user-defined enumeration, the resulting package file will include +its definition. Due to limitations from type-strictness rules in SystemVerilog, +the field will remain as a ``logic`` datatype. + next ^^^^ diff --git a/src/peakrdl_regblock/exporter.py b/src/peakrdl_regblock/exporter.py index dd224af..9cc364f 100644 --- a/src/peakrdl_regblock/exporter.py +++ b/src/peakrdl_regblock/exporter.py @@ -162,6 +162,7 @@ class RegblockExporter: package_name=package_name, in_hier_signal_paths=scanner.in_hier_signal_paths, out_of_hier_signals=scanner.out_of_hier_signals, + user_enums=scanner.user_enums, reuse_typedefs=reuse_hwif_typedefs, hwif_report_file=hwif_report_file, ) diff --git a/src/peakrdl_regblock/hwif/__init__.py b/src/peakrdl_regblock/hwif/__init__.py index e56e305..179ecba 100644 --- a/src/peakrdl_regblock/hwif/__init__.py +++ b/src/peakrdl_regblock/hwif/__init__.py @@ -1,13 +1,14 @@ -from typing import TYPE_CHECKING, Union, Set, Dict, Optional, TextIO +from typing import TYPE_CHECKING, Union, Set, Dict, Optional, TextIO, Type, List from systemrdl.node import AddrmapNode, SignalNode, FieldNode, RegNode -from systemrdl.rdltypes import PropertyReference +from systemrdl.rdltypes import PropertyReference, UserEnum from ..utils import get_indexed_path from ..identifier_filter import kw_filter as kwf from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope +from .generators import EnumGenerator if TYPE_CHECKING: from ..exporter import RegblockExporter @@ -22,6 +23,7 @@ class Hwif: def __init__( self, exp: 'RegblockExporter', package_name: str, + user_enums: List[Type[UserEnum]], in_hier_signal_paths: Set[str], out_of_hier_signals: Dict[str, SignalNode], reuse_typedefs: bool, hwif_report_file: Optional[TextIO] ): @@ -33,6 +35,7 @@ class Hwif: self.in_hier_signal_paths = in_hier_signal_paths self.out_of_hier_signals = out_of_hier_signals + self.user_enums = user_enums self.hwif_report_file = hwif_report_file @@ -76,6 +79,13 @@ class Hwif: else: self.has_output_struct = False + gen_enum = EnumGenerator() + enums = gen_enum.get_enums( + self.user_enums + ) + if enums is not None: + lines.append(enums) + return "\n\n".join(lines) diff --git a/src/peakrdl_regblock/hwif/generators.py b/src/peakrdl_regblock/hwif/generators.py index 2ec86f5..eac1e4b 100644 --- a/src/peakrdl_regblock/hwif/generators.py +++ b/src/peakrdl_regblock/hwif/generators.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Optional, List +from typing import TYPE_CHECKING, Optional, List, Type from systemrdl.node import FieldNode @@ -8,6 +8,7 @@ from ..identifier_filter import kw_filter as kwf if TYPE_CHECKING: from systemrdl.node import Node, SignalNode, RegNode from . import Hwif + from systemrdl.rdltypes import UserEnum class HWIFStructGenerator(RDLFlatStructGenerator): def __init__(self, hwif: 'Hwif', hwif_name: str) -> None: @@ -178,6 +179,43 @@ class OutputStructGenerator_TypeScope(OutputStructGenerator_Hier): return f'{scope_path}__{node.type_name}{extra_suffix}__out_t' +#------------------------------------------------------------------------------- +class EnumGenerator: + """ + Generator for user-defined enum definitions + """ + + def get_enums(self, user_enums: List[Type['UserEnum']]) -> Optional[str]: + if not user_enums: + return None + + lines = [] + for user_enum in user_enums: + lines.append(self._enum_typedef(user_enum)) + + return '\n\n'.join(lines) + + @staticmethod + def _get_prefix(user_enum: Type['UserEnum']) -> str: + scope = user_enum.get_scope_path("__") + if scope: + return f"{scope}__{user_enum.type_name}" + else: + return user_enum.type_name + + def _enum_typedef(self, user_enum: Type['UserEnum']) -> str: + prefix = self._get_prefix(user_enum) + + lines = [] + for enum_member in user_enum: + lines.append(f" {prefix}__{enum_member.name} = 'd{enum_member.value}") + + return ( + "typedef enum {\n" + + ",\n".join(lines) + + f"\n}} {prefix}_e;" + ) + def get_field_type_name_suffix(field: FieldNode) -> str: """ diff --git a/src/peakrdl_regblock/scan_design.py b/src/peakrdl_regblock/scan_design.py index 9b793b8..693adb4 100644 --- a/src/peakrdl_regblock/scan_design.py +++ b/src/peakrdl_regblock/scan_design.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Set, Optional +from typing import TYPE_CHECKING, Set, Optional, Type, List from collections import OrderedDict from systemrdl.walker import RDLListener, RDLWalker, WalkerAction @@ -7,6 +7,7 @@ from systemrdl.node import SignalNode if TYPE_CHECKING: from systemrdl.node import Node, RegNode, FieldNode from .exporter import RegblockExporter + from systemrdl.rdltypes import UserEnum class DesignScanner(RDLListener): @@ -29,6 +30,9 @@ class DesignScanner(RDLListener): self.has_buffered_write_regs = False self.has_buffered_read_regs = False + # Track any referenced enums + self.user_enums = [] # type: List[Type[UserEnum]] + def _get_out_of_hier_field_reset(self) -> None: current_node = self.exp.top_node.parent while current_node is not None: @@ -83,6 +87,10 @@ class DesignScanner(RDLListener): else: self.in_hier_signal_paths.add(path) + if prop_name == "encode": + if value not in self.user_enums: + self.user_enums.append(value) + return None def enter_Reg(self, node: 'RegNode') -> None: diff --git a/tests/test_enum/__init__.py b/tests/test_enum/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_enum/regblock.rdl b/tests/test_enum/regblock.rdl new file mode 100644 index 0000000..adb4fe4 --- /dev/null +++ b/tests/test_enum/regblock.rdl @@ -0,0 +1,12 @@ +addrmap top { + enum my_enum { + val_1 = 3 {name = "Value 1";}; + val_2 = 4 {desc = "Second value";}; + }; + reg { + field { + encode = my_enum; + sw=rw; hw=na; + } f[2:0] = my_enum::val_2; + } r0; +}; diff --git a/tests/test_enum/tb_template.sv b/tests/test_enum/tb_template.sv new file mode 100644 index 0000000..457bd2b --- /dev/null +++ b/tests/test_enum/tb_template.sv @@ -0,0 +1,22 @@ +{% extends "lib/tb_base.sv" %} + +{% block seq %} + {% sv_line_anchor %} + ##1; + cb.rst <= '0; + ##1; + + // check enum values + assert(regblock_pkg::top__my_enum__val_1 == 'd3); + assert(regblock_pkg::top__my_enum__val_2 == 'd4); + + // check initial conditions + cpuif.assert_read('h0, regblock_pkg::top__my_enum__val_2); + + //--------------------------------- + // set r0 = val_1 + cpuif.write('h0, regblock_pkg::top__my_enum__val_1); + + cpuif.assert_read('h0, regblock_pkg::top__my_enum__val_1); + +{% endblock %} diff --git a/tests/test_enum/testcase.py b/tests/test_enum/testcase.py new file mode 100644 index 0000000..835b5ef --- /dev/null +++ b/tests/test_enum/testcase.py @@ -0,0 +1,5 @@ +from ..lib.sim_testcase import SimTestCase + +class Test(SimTestCase): + def test_dut(self): + self.run_test()