Skip to content
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
8 changes: 8 additions & 0 deletions docs/output.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,11 @@ C's ``<stdint.h>`` types only extend up to 64-bit types.

If a register is encountered that is larger than this, the generated
header will represent it using an array of smaller sub-words.


Enumerations used in encodings
------------------------------

``enum`` components used in field encodings are emitted as ``#define``
macros at their first occurrence. They are prefixed with the parent
scope and the enum's type name to avoid collisions.
46 changes: 46 additions & 0 deletions src/peakrdl_cheader/header_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
from systemrdl.node import AddrmapNode, AddressableNode, RegNode, FieldNode, Node, MemNode, RegfileNode
from systemrdl.component import Regfile
from systemrdl.rdltypes.user_enum import UserEnum

from .design_state import DesignState
from .identifier_filter import kw_filter as kwf
Expand All @@ -19,6 +21,7 @@ def __init__(self, ds: DesignState) -> None:
self.defined_namespace: Set[str]
self.defined_namespace = set()
self.indent_level = 0
self.seen_enums: Set[type[UserEnum]] = set()

def run(self, path: str, top_nodes: List[Union[AddrmapNode, MemNode, RegfileNode]]) -> None:
with open(path, "w", encoding='utf-8') as f:
Expand Down Expand Up @@ -127,6 +130,47 @@ def write_bitfields(self, grp_name: str, regwidth: int, fields: List[FieldNode])
self.pop_indent()
self.write(f"}} {grp_name};\n")


def write_enums(self, node: RegNode) -> None:
# Write out enums used in 'encode' properies.
written = False
for field in node.fields():
enc = field.get_property("encode")
if not enc:
continue
if enc in self.seen_enums:
continue

# Construct a parent scope prefix for the enum.
parent = enc.get_parent_scope()
if not parent:
pprefix: Optional[str] = ""
elif isinstance(parent, Regfile):
pprefix = enc.get_scope_path("_")
else:
pprefix = parent.get_scope_path("_")

# Uppercase and append an underscore. If the parent scope
# is the root, leave it empty.
if pprefix:
pprefix = f"{pprefix.upper()}_"
else:
pprefix = ""

# Drop the optional "_encoding" at the end, and append the
# enum type name as the prefix.
eprefix = enc.type_name.removesuffix("_encoding").upper()

if not written:
self.write("\n// enums\n")
written = True
for mem in enc.members.values():
self.write(f"#define {pprefix}{eprefix}_{mem.name} {mem.value:#x}\n")

# Only emit an enum once.
self.seen_enums.add(enc)


def enter_Reg(self, node: RegNode) -> Optional[WalkerAction]:
prefix = self.get_node_prefix(node).upper()

Expand All @@ -148,6 +192,8 @@ def enter_Reg(self, node: RegNode) -> Optional[WalkerAction]:
if isinstance(reset, int):
self.write(f"#define {field_prefix}_reset {reset:#x}\n")

self.write_enums(node)

# No need to traverse fields
return WalkerAction.SkipDescendants

Expand Down
37 changes: 37 additions & 0 deletions tests/testcases/basic.rdl
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,41 @@ addrmap basic {
field { fieldwidth=8; sw = r; } basicfield_r;
} basicreg_g;

// enum encodings

// "global"
enum some_global_encoding {
ABC = 5;
DEF = 6;
};

reg {
field {
// defined inside field
enum basicfield_s_encoding {
FOO = 1;
BAR = 2;
};
encode = basicfield_s_encoding;
} basicfield_s[4];

// defined in reg
enum basicreg_h_encoding {
FOO = 3;
BAR = 4;
};
field {
encode = basicreg_h_encoding;
} basicfield_t[4];

// use global enum
field {
encode = some_global_encoding;
} basicfield_u[4];

field {
// reuse previously defined one in reg scope
encode = basicreg_h_encoding;
} basicfield_v[4];
} basicreg_h;
};