-
Notifications
You must be signed in to change notification settings - Fork 19
Add support for enums #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| from typing import TextIO, Set, Optional, List, Union | ||
| from typing import Type, TextIO, Set, Optional, List, Union | ||
| import os | ||
| import re | ||
|
|
||
|
|
@@ -36,6 +36,10 @@ def run(self, path: str, top_nodes: List[Union[AddrmapNode, MemNode, RegfileNode | |
| template.stream(context).dump(f) # type: ignore # jinja incorrectly typed | ||
| f.write("\n") | ||
|
|
||
| # Write enums | ||
| if self.ds.generate_enums: | ||
| self.write_enums(top_nodes) | ||
|
|
||
| # Generate definitions | ||
| for node in top_nodes: | ||
| self.root_node = node | ||
|
|
@@ -99,14 +103,19 @@ def write_bitfields(self, grp_name: str, regwidth: int, fields: List[FieldNode]) | |
| self.write("struct __attribute__ ((__packed__)) {\n") | ||
| self.push_indent() | ||
|
|
||
| def get_field_type(field: FieldNode) -> str: | ||
| encode = field.get_property("encode") | ||
| return f"uint{regwidth}_t" if not self.ds.generate_enums or encode is None else \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code will cause a runtime error. The variable |
||
| f"{self.get_enum_prefix(encode)}_e" | ||
|
|
||
| if self.ds.bitfield_order_ltoh: | ||
| # Bits are packed in struct LSb --> MSb | ||
| current_offset = 0 | ||
| for field in fields: | ||
| if field.low > current_offset: | ||
| self.write(f"uint{regwidth}_t :{field.low - current_offset:d};\n") | ||
| current_offset = field.low | ||
| self.write(f"uint{regwidth}_t {kwf(field.inst_name)} :{field.width:d};\n") | ||
| self.write(f"{get_field_type(field)} {kwf(field.inst_name)} :{field.width:d};\n") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure it is generically safe to use the enum type in C bitfields. I would recommend removing this change, and only generate the enum typedefs on the side without actually using them in the struct definition. C is weakly typed in this sense, so the utility of having the enum definition still benefits the user. |
||
| current_offset += field.width | ||
|
|
||
| if current_offset < regwidth: | ||
|
|
@@ -118,7 +127,7 @@ def write_bitfields(self, grp_name: str, regwidth: int, fields: List[FieldNode]) | |
| if field.high < current_offset: | ||
| self.write(f"uint{regwidth}_t :{current_offset - field.high:d};\n") | ||
| current_offset = field.high | ||
| self.write(f"uint{regwidth}_t {kwf(field.inst_name)} :{field.width:d};\n") | ||
| self.write(f"{get_field_type(field)} {kwf(field.inst_name)} :{field.width:d};\n") | ||
| current_offset -= field.width | ||
|
|
||
| if current_offset > -1: | ||
|
|
@@ -344,3 +353,39 @@ def write_group_struct_member(self, node: AddressableNode) -> None: | |
|
|
||
| struct_name = self.get_struct_name(node) | ||
| self.write(f"{struct_name} {kwf(node.inst_name)}{array_suffix};\n") | ||
|
|
||
| @staticmethod | ||
| def get_enum_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 write_enum(self, user_enum: Type['UserEnum']) -> None: | ||
| prefix = self.get_enum_prefix(user_enum) | ||
| lines = [] | ||
| for enum_member in user_enum: | ||
| lines.append(f" {prefix}__{enum_member.name} = {enum_member.value}") | ||
|
|
||
| self.write("typedef enum {\n" | ||
| + ",\n".join(lines) | ||
| + f"\n}} {prefix}_e;\n") | ||
maltaisn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def write_enums(self, top_nodes: List[AddrmapNode]) -> None: | ||
| user_enums = [] | ||
|
|
||
| class Listener(RDLListener): | ||
| def enter_Field(listener, node: FieldNode) -> Optional[WalkerAction]: | ||
| encode = node.get_property("encode") | ||
| if encode is not None and encode not in user_enums: | ||
| user_enums.append(encode) | ||
| return None | ||
|
|
||
| for node in top_nodes: | ||
| self.root_node = node | ||
| RDLWalker().walk(node, Listener()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please do not nest another listener/walker here. I think it would be cleaner to have enum typedefs be emitted alongside the registers that use them in the existing listener. Recommend emitting enums in an |
||
|
|
||
| for user_enum in user_enums: | ||
| self.write("\n") | ||
| self.write_enum(user_enum) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove the option, and have enums always be part of the output.