Add support for user defined enums in field encode property. #29
This commit is contained in:
committed by
Alex Mykyta
parent
80f670bf30
commit
0c7e493976
@@ -448,7 +448,10 @@ Misc
|
|||||||
|
|
||||||
encode
|
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
|
next
|
||||||
^^^^
|
^^^^
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ class RegblockExporter:
|
|||||||
package_name=package_name,
|
package_name=package_name,
|
||||||
in_hier_signal_paths=scanner.in_hier_signal_paths,
|
in_hier_signal_paths=scanner.in_hier_signal_paths,
|
||||||
out_of_hier_signals=scanner.out_of_hier_signals,
|
out_of_hier_signals=scanner.out_of_hier_signals,
|
||||||
|
user_enums=scanner.user_enums,
|
||||||
reuse_typedefs=reuse_hwif_typedefs,
|
reuse_typedefs=reuse_hwif_typedefs,
|
||||||
hwif_report_file=hwif_report_file,
|
hwif_report_file=hwif_report_file,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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.node import AddrmapNode, SignalNode, FieldNode, RegNode
|
||||||
from systemrdl.rdltypes import PropertyReference
|
from systemrdl.rdltypes import PropertyReference, UserEnum
|
||||||
|
|
||||||
from ..utils import get_indexed_path
|
from ..utils import get_indexed_path
|
||||||
from ..identifier_filter import kw_filter as kwf
|
from ..identifier_filter import kw_filter as kwf
|
||||||
|
|
||||||
from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier
|
from .generators import InputStructGenerator_Hier, OutputStructGenerator_Hier
|
||||||
from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope
|
from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_TypeScope
|
||||||
|
from .generators import EnumGenerator
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..exporter import RegblockExporter
|
from ..exporter import RegblockExporter
|
||||||
@@ -22,6 +23,7 @@ class Hwif:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, exp: 'RegblockExporter', package_name: str,
|
self, exp: 'RegblockExporter', package_name: str,
|
||||||
|
user_enums: List[Type[UserEnum]],
|
||||||
in_hier_signal_paths: Set[str], out_of_hier_signals: Dict[str, SignalNode],
|
in_hier_signal_paths: Set[str], out_of_hier_signals: Dict[str, SignalNode],
|
||||||
reuse_typedefs: bool, hwif_report_file: Optional[TextIO]
|
reuse_typedefs: bool, hwif_report_file: Optional[TextIO]
|
||||||
):
|
):
|
||||||
@@ -33,6 +35,7 @@ class Hwif:
|
|||||||
|
|
||||||
self.in_hier_signal_paths = in_hier_signal_paths
|
self.in_hier_signal_paths = in_hier_signal_paths
|
||||||
self.out_of_hier_signals = out_of_hier_signals
|
self.out_of_hier_signals = out_of_hier_signals
|
||||||
|
self.user_enums = user_enums
|
||||||
|
|
||||||
self.hwif_report_file = hwif_report_file
|
self.hwif_report_file = hwif_report_file
|
||||||
|
|
||||||
@@ -76,6 +79,13 @@ class Hwif:
|
|||||||
else:
|
else:
|
||||||
self.has_output_struct = False
|
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)
|
return "\n\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING, Optional, List
|
from typing import TYPE_CHECKING, Optional, List, Type
|
||||||
|
|
||||||
from systemrdl.node import FieldNode
|
from systemrdl.node import FieldNode
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ from ..identifier_filter import kw_filter as kwf
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from systemrdl.node import Node, SignalNode, RegNode
|
from systemrdl.node import Node, SignalNode, RegNode
|
||||||
from . import Hwif
|
from . import Hwif
|
||||||
|
from systemrdl.rdltypes import UserEnum
|
||||||
|
|
||||||
class HWIFStructGenerator(RDLFlatStructGenerator):
|
class HWIFStructGenerator(RDLFlatStructGenerator):
|
||||||
def __init__(self, hwif: 'Hwif', hwif_name: str) -> None:
|
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'
|
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:
|
def get_field_type_name_suffix(field: FieldNode) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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 collections import OrderedDict
|
||||||
|
|
||||||
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
|
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
|
||||||
@@ -7,6 +7,7 @@ from systemrdl.node import SignalNode
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from systemrdl.node import Node, RegNode, FieldNode
|
from systemrdl.node import Node, RegNode, FieldNode
|
||||||
from .exporter import RegblockExporter
|
from .exporter import RegblockExporter
|
||||||
|
from systemrdl.rdltypes import UserEnum
|
||||||
|
|
||||||
|
|
||||||
class DesignScanner(RDLListener):
|
class DesignScanner(RDLListener):
|
||||||
@@ -29,6 +30,9 @@ class DesignScanner(RDLListener):
|
|||||||
self.has_buffered_write_regs = False
|
self.has_buffered_write_regs = False
|
||||||
self.has_buffered_read_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:
|
def _get_out_of_hier_field_reset(self) -> None:
|
||||||
current_node = self.exp.top_node.parent
|
current_node = self.exp.top_node.parent
|
||||||
while current_node is not None:
|
while current_node is not None:
|
||||||
@@ -83,6 +87,10 @@ class DesignScanner(RDLListener):
|
|||||||
else:
|
else:
|
||||||
self.in_hier_signal_paths.add(path)
|
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
|
return None
|
||||||
|
|
||||||
def enter_Reg(self, node: 'RegNode') -> None:
|
def enter_Reg(self, node: 'RegNode') -> None:
|
||||||
|
|||||||
0
tests/test_enum/__init__.py
Normal file
0
tests/test_enum/__init__.py
Normal file
12
tests/test_enum/regblock.rdl
Normal file
12
tests/test_enum/regblock.rdl
Normal file
@@ -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;
|
||||||
|
};
|
||||||
22
tests/test_enum/tb_template.sv
Normal file
22
tests/test_enum/tb_template.sv
Normal file
@@ -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 %}
|
||||||
5
tests/test_enum/testcase.py
Normal file
5
tests/test_enum/testcase.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ..lib.sim_testcase import SimTestCase
|
||||||
|
|
||||||
|
class Test(SimTestCase):
|
||||||
|
def test_dut(self):
|
||||||
|
self.run_test()
|
||||||
Reference in New Issue
Block a user