Skip to content

Commit

Permalink
Add MemNode support
Browse files Browse the repository at this point in the history
This commit adds support for PeakRDL MemNode objects.
Register arrays inside MemNode are not being unrolled
to keep memory description brief.
Memories can hold hundreds or even more virtual registers
and unrolling all of them is not beneficial and mudders
the overall picture.

Signed-off-by: Maciej Dudek <[email protected]>
  • Loading branch information
mtdudek authored and MarekPikula committed Apr 16, 2024
1 parent 4297a0d commit 3fe518c
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Add support for Python 3.6
- Add support for MemNode

## [0.1.7]

Expand Down
105 changes: 104 additions & 1 deletion example/accelera_generic_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -971,5 +971,108 @@ how RDL can be utilized in various situations.</p>
- Base Offset: 0x2000
- Size: 0x4

No supported members.
|Offset|Identifier|Name|
|------|----------|----|
| 0x0 | REGS ||

## REGS memory

- Absolute Address: 0x2000
- Base Offset: 0x0
- Size: 0x4

|Offset|Identifier|Name|
|------|----------|----|
| 0x0 | regs[1] ||

### regs register

- Absolute Address: 0x2000
- Base Offset: 0x0
- Size: 0x4
- Array Dimensions: [1]
- Array Stride: 0x4
- Total Size: 0x4

| Bits|Identifier| Access |Reset|Name|
|-----|----------|--------|-----|----|
| 1:0 | data0 |rw, rclr| 0x0 ||
| 3:2 | data1 |rw, rclr| 0x1 ||
| 5:4 | data2 |rw, rclr| 0x2 ||
| 7:6 | data3 |rw, rclr| 0x3 ||
| 9:8 | data4 |rw, rclr| 0x0 ||
|11:10| data5 |rw, rclr| 0x1 ||
|13:12| data6 |rw, rclr| 0x2 ||
|15:14| data7 |rw, rclr| 0x3 ||
|17:16| data8 |rw, rclr| 0x0 ||
|19:18| data9 |rw, rclr| 0x1 ||
|21:20| data10 |rw, rclr| 0x2 ||
|23:22| data11 |rw, rclr| 0x3 ||
|25:24| data12 |rw, rclr| 0x0 ||
|27:26| data13 |rw, rclr| 0x1 ||
|29:28| data14 |rw, rclr| 0x2 ||
|31:30| data15 |rw, rclr| 0x3 ||

#### data0 field

<p>My example 2bit status field</p>

#### data1 field

<p>My example 2bit status field</p>

#### data2 field

<p>My example 2bit status field</p>

#### data3 field

<p>My example 2bit status field</p>

#### data4 field

<p>My example 2bit status field</p>

#### data5 field

<p>My example 2bit status field</p>

#### data6 field

<p>My example 2bit status field</p>

#### data7 field

<p>My example 2bit status field</p>

#### data8 field

<p>My example 2bit status field</p>

#### data9 field

<p>My example 2bit status field</p>

#### data10 field

<p>My example 2bit status field</p>

#### data11 field

<p>My example 2bit status field</p>

#### data12 field

<p>My example 2bit status field</p>

#### data13 field

<p>My example 2bit status field</p>

#### data14 field

<p>My example 2bit status field</p>

#### data15 field

<p>My example 2bit status field</p>
1 change: 1 addition & 0 deletions example/accelera_generic_example.rdl
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ addrmap some_register_map {
external mem {
mementries = 1;
memwidth = 32;
myReg regs [1];
} REGS @ 0x00;
} empty_addrmap @0x2000;

Expand Down
48 changes: 35 additions & 13 deletions src/peakrdl_markdown/exporter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"""PeakRDL Markdown exporter."""

__authors__ = ["Marek Pikuła <marek.pikula at embevity.com>"]
__authors__ = [
"Marek Pikuła <marek.pikula at embevity.com>",
"Maciej Dudek <mdudek at antmicro.com>",
]

from collections import OrderedDict
from dataclasses import dataclass
from functools import reduce
from operator import mul
from pathlib import Path
from typing import List, Optional, Union

Expand All @@ -13,6 +18,7 @@
AddressableNode,
AddrmapNode,
FieldNode,
MemNode,
Node,
RegfileNode,
RegNode,
Expand Down Expand Up @@ -54,9 +60,16 @@ def _addrnode_info(node: AddressableNode):
"""Generate AddressableNode basic information dictionary."""
ret: "OrderedDict[str, str]" = OrderedDict()

set_index = False
if node.is_array and node.current_idx is None:
node.current_idx = [0]
set_index = True
ret["Absolute Address"] = f"0x{node.absolute_address:X}"
ret["Base Offset"] = f"0x{node.raw_address_offset:X}"
ret["Size"] = f"0x{node.size:X}"
if node.is_array and node.array_dimensions is not None and set_index:
ret["Size"] = f"0x{node.size * reduce(mul, node.array_dimensions, 1):X}"
else:
ret["Size"] = f"0x{node.size:X}"

if node.is_array:
ret["Array Dimensions"] = str(node.array_dimensions)
Expand Down Expand Up @@ -84,21 +97,27 @@ def _node_name_sanitized(node: Node) -> str:
name = name.replace("\n", "")
return name

def _addrnode_header(self, node: AddressableNode, heading_level: int) -> str:
def _addrnode_header(
self, node: AddressableNode, msg: MessageHandler, heading_level: int
) -> str:
"""Get the AddressableNode header.
Arguments:
node -- node to generate the header for.
msg -- message handler from top-level.
heading_level -- Markdown heading level.
"""
if isinstance(node, AddrmapNode):
node_type_name = "address map"
elif isinstance(node, RegfileNode):
node_type_name = "register file"
elif isinstance(node, MemNode):
node_type_name = "memory"
elif isinstance(node, RegNode):
node_type_name = "register"
else:
node_type_name = "addressable node"
msg.warning(f"Unsupported type of node ({node.__class__.__name__}).")

ret = self._heading(heading_level, f"{node.inst_name} {node_type_name}")
ret += self._addrnode_info_md(node) + "\n\n"
Expand Down Expand Up @@ -160,7 +179,7 @@ def export( # pylint: disable=too-many-arguments
Path(output_path).parent.mkdir(parents=True, exist_ok=True)

# Run generation.
gen = self._add_addrmap_regfile(top, node.env.msg, depth - 1).generated
gen = self._add_addrmap_regfile_mem(top, node.env.msg, depth - 1).generated

# Write to the file.
with open(output_path, "w", encoding="UTF-8") as output:
Expand All @@ -172,16 +191,16 @@ def export( # pylint: disable=too-many-arguments
)
output.write(gen)

def _add_addrmap_regfile(
def _add_addrmap_regfile_mem(
self,
node: Union[AddrmapNode, RegfileNode],
node: Union[AddrmapNode, RegfileNode, MemNode],
msg: MessageHandler,
depth: int,
) -> GenStageOutput:
"""Generate addrmap or regfile.
"""Generate addrmap, regfile or memory.
Arguments:
node -- RegfileNode or AddrmapNode.
node -- MemNode, RegfileNode or AddrmapNode.
msg -- message handler from top-level.
depth -- depth of generation left.
Expand All @@ -194,9 +213,12 @@ def _add_addrmap_regfile(
"""
members: List[MarkdownExporter.GenStageOutput] = []
member_gen: str = ""
for child in node.children(unroll=True, skip_not_present=False):
if isinstance(child, (AddrmapNode, RegfileNode)):
output = self._add_addrmap_regfile(child, msg, depth - 1)
# Don't unroll register arrays when they are inside memories.
# Memories can contain hundreds of entires.
not_memory = not isinstance(node, MemNode)
for child in node.children(unroll=not_memory, skip_not_present=False):
if isinstance(child, (AddrmapNode, RegfileNode, MemNode)):
output = self._add_addrmap_regfile_mem(child, msg, depth - 1)
member_gen += output.generated
members.append(output)
elif isinstance(child, RegNode):
Expand All @@ -209,7 +231,7 @@ def _add_addrmap_regfile(
f"for {'/'.join(child.get_path_segments())}."
)

gen: str = self._addrnode_header(node, 2)
gen: str = self._addrnode_header(node, msg, 2)

if len(members) == 0:
gen += "No supported members.\n"
Expand Down Expand Up @@ -255,7 +277,7 @@ def _add_reg(self, node: RegNode, msg: MessageHandler) -> GenStageOutput:
field_gen += output.generated
members.append(output)

gen: str = self._addrnode_header(node, 3)
gen: str = self._addrnode_header(node, msg, 3)
gen += (
markdownTable([*map(lambda m: m.table_row, members)])
.setParams(row_sep="markdown", quote=False)
Expand Down

0 comments on commit 3fe518c

Please sign in to comment.