Skip to content
Merged
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
14 changes: 13 additions & 1 deletion rdl2ot/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# rdl2ot cli tool
A PeakRDL extension to generate Opentitan style source files from SystemRDL files.

## How to generate the Opentitan register interfaces from a RDL file
## Using as a standalone tool
### How to generate the Opentitan register interfaces from a RDL file
```sh
rdl2ot export-rtl <input_rdl> <output_dir>
```
Expand All @@ -12,6 +13,17 @@ mkdir -p /tmp/lc_ctrl
rdl2ot export-rtl tests/snapshots/lc_ctrl.rdl /tmp/lc_ctrl/
```

## Using as a Peakrdl pluggin
### Installing
```sh
pip install peakrdl rdl2ot
```
### Running
```sh
mkdir -p /tmp/lc_ctrl
peakrdl rdl2ot tests/snapshots/lc_ctrl.rdl -o /tmp/lc_ctrl/
```

## Contributing
### How to run tests
```sh
Expand Down
4 changes: 4 additions & 0 deletions rdl2ot/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Homepage = "https://github.com/lowrisc/benevisrdl"
Issues = "https://github.com/lowrisc/benevisrdl/issues"
Documentation = "https://github.com/lowrisc/benevisrdl"

[project.entry-points."peakrdl.exporters"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I learnt something new today... https://setuptools.pypa.io/en/latest/userguide/entry_point.html#entry-points-for-plugins

Didn't realise such a neat mechanism for plugin discovery was available. In the past I've only used entry-points for scripts.

rdl2ot = "rdl2ot.__peakrdl__:Exporter"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Expand All @@ -38,3 +41,4 @@ executionEnvironments = [

[tool.hatch.build.targets.wheel]
packages = ["src/rdl2ot", "src/templates"]

31 changes: 31 additions & 0 deletions rdl2ot/src/rdl2ot/__peakrdl__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line shouldn't be required, as the entry point script will automatically be created.

Suggested change
#!/usr/bin/env python3

Same goes for the cli.py which I didn't notice before.

# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

"""Generates Opentitan regblock RTL."""

from pathlib import Path
from typing import TYPE_CHECKING

from peakrdl.plugins.exporter import ExporterSubcommandPlugin # pylint: disable=import-error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What import error is being disabled here? peakrdl is a package dependency so this import should be valid if it's correct?

Also this is a pylint specific disable, isn't the project now using ruff? So if you need to disable a lint there is an equivalent ruff disable. If this is just to keep your LSP happy, then maybe consider disabling pylint and just using rufls instead. Trying to use both could confuse the LSP setup?


from rdl2ot import rtl_exporter

if TYPE_CHECKING:
import argparse

from systemrdl.node import AddrmapNode


class Exporter(ExporterSubcommandPlugin):
"""Generates Opentitan regblock RTL."""

short_desc = "Generates Opentitan register block RTL."

def add_exporter_arguments(self, arg_group: "argparse.ArgumentParser") -> None:
"""No extra arguments."""

def do_export(self, top_node: "AddrmapNode", options: "argparse.Namespace") -> None:
"""Plugin entry function."""
rtl_exporter.run(top_node, Path(options.output))
2 changes: 1 addition & 1 deletion rdl2ot/src/rdl2ot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ def export_rtl(input_file: str, out_dir: str) -> None:
rdlc.compile_file(input_file)
root = rdlc.elaborate()

rtl_exporter.run(rdlc, root, Path(out_dir))
rtl_exporter.run(root.top, Path(out_dir))

print("Successfully finished!\n")
13 changes: 4 additions & 9 deletions rdl2ot/src/rdl2ot/rtl_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pathlib import Path

from jinja2 import Environment, FileSystemLoader
from systemrdl import RDLCompiler, node
from systemrdl import node
from systemrdl.rdltypes import OnReadType

from rdl2ot import opentitan
Expand All @@ -17,10 +17,10 @@
DEFAULT_INTERFACE_NAME = "regs"


def run(rdlc: RDLCompiler, obj: node.RootNode, out_dir: Path) -> None:
def run(root_node: node.AddrmapNode, out_dir: Path) -> None:
"""Export RDL to opentitan RTL."""
factory = OtInterfaceBuilder(rdlc)
data = factory.parse_root(obj.top)
factory = OtInterfaceBuilder()
data = factory.parse_root(root_node)

Path(out_dir / "rdl.json").write_text(json.dumps(data, indent=2), encoding="utf-8")

Expand Down Expand Up @@ -54,11 +54,6 @@ class OtInterfaceBuilder:
async_registers: list = [(int, str)] # List of all the (index, register) with async clock
any_shadowed_reg: bool = False
reg_index: int = 0
rdlc: RDLCompiler

def __init__(self, rdlc: RDLCompiler) -> None:
"""Constructor."""
self.rdlc = rdlc

def get_field(self, field: node.FieldNode) -> dict:
"""Parse a field and return a dictionary."""
Expand Down
3 changes: 3 additions & 0 deletions rdl2ot/tests/test_rdl2ot.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ def _run_cli_tool(input_file_path: Path, output_dir_path: Path) -> subprocess.Co
]
return subprocess.run(command, capture_output=True, text=True, check=False) # noqa: S603


test_ips = ["lc_ctrl", "uart"]


@pytest.mark.parametrize("ip_block", test_ips)
def test_export_ip(tmp_path: Path, ip_block: str) -> None:
"""Test an given ip block."""
Expand Down