Skip to content
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

Add support for enums #10

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/peakrdl_cheader/__peakrdl__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ def add_exporter_arguments(self, arg_group: 'argparse._ActionsContainer') -> Non
"""
)

arg_group.add_argument(
"-e", "--generate-enums",
action="store_true",
default=False,
help="""
Enable generation of enum definitions.
"""
)

arg_group.add_argument(
"-x", "--explode-top",
action="store_true",
Expand Down
3 changes: 3 additions & 0 deletions src/peakrdl_cheader/design_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ def __init__(self, top_node: AddrmapNode, kwargs: Any) -> None:
self.bitfield_order_ltoh: bool
self.bitfield_order_ltoh = kwargs.pop("bitfield_order_ltoh", True)

self.generate_enums: bool
self.generate_enums = kwargs.pop("generate_enums", False)

# If a register is wider than 64-bits, it cannot be represented by a stdint
# type. Therefore it must be represented by an array of subwords
self.wide_reg_subword_size: int
Expand Down
51 changes: 48 additions & 3 deletions src/peakrdl_cheader/header_generator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TextIO, Set, Optional, List
from typing import Type, TextIO, Set, Optional, List
import os
import re

Expand Down Expand Up @@ -39,6 +39,10 @@ def run(self, path: str, top_nodes: List[AddrmapNode]) -> None:
template.stream(context).dump(f)
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
Expand Down Expand Up @@ -102,14 +106,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 \
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")
current_offset += field.width

if current_offset < regwidth:
Expand All @@ -121,7 +130,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:
Expand Down Expand Up @@ -343,3 +352,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")

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())

for user_enum in user_enums:
self.write("\n")
self.write_enum(user_enum)