Skip to content
This repository was archived by the owner on Oct 23, 2024. It is now read-only.

Commit d52075e

Browse files
committed
cxxsim: basic support.
1 parent 27c3609 commit d52075e

2 files changed

Lines changed: 134 additions & 3 deletions

File tree

rainhdx/rainhdx/__init__.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import json
2-
import logging
32
import sys
43
from argparse import ArgumentParser
54
from functools import partialmethod
65
from pathlib import Path
76

87
from amaranth import Elaboratable
98

10-
from . import build, formal, logger, test
9+
from . import build, cxxsim, formal, test
1110
from .platform import Platform
1211

1312
__all__ = ["Project", "Platform", "FormalHelper", "cli"]
@@ -63,6 +62,12 @@ class Project:
6362
required=True,
6463
issubclass=Elaboratable,
6564
),
65+
Prop(
66+
"cxxsim_top",
67+
description="a reference to the top-level C++ simulator test elaboratable",
68+
required=False,
69+
issubclass=Elaboratable,
70+
),
6671
Prop(
6772
"formal_top",
6873
description="a reference to the top-level formal elaboratable",
@@ -102,7 +107,10 @@ def cli(rp):
102107
subparsers = parser.add_subparsers(required=True)
103108

104109
test.add_arguments(rp, subparsers.add_parser("test", help="run the unit tests"))
105-
# cxxsim
110+
if hasattr(rp, "cxxsim_top"):
111+
cxxsim.add_arguments(
112+
rp, subparsers.add_parser("cxxsim", help="run the C++ simulator tests")
113+
)
106114
if hasattr(rp, "formal_top"):
107115
formal.add_arguments(
108116
rp, subparsers.add_parser("formal", help="formally verify the design")

rainhdx/rainhdx/cxxsim.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import inspect
2+
import subprocess
3+
from enum import Enum
4+
from functools import partial
5+
from pathlib import Path
6+
7+
from amaranth._toolchain.yosys import find_yosys
8+
from amaranth.back import rtlil
9+
10+
from .platform import Platform
11+
12+
__all__ = ["add_arguments"]
13+
14+
15+
class _Optimize(Enum):
16+
none = "none"
17+
rtl = "rtl"
18+
19+
def __str__(self):
20+
return self.value
21+
22+
@property
23+
def opt_rtl(self) -> bool:
24+
return self in (self.rtl,)
25+
26+
27+
def add_arguments(rp, parser):
28+
parser.set_defaults(func=partial(main, rp))
29+
parser.add_argument(
30+
"-c",
31+
"--compile",
32+
action="store_true",
33+
help="compile only; don't run",
34+
)
35+
parser.add_argument(
36+
"-O",
37+
"--optimize",
38+
type=_Optimize,
39+
choices=_Optimize,
40+
help="build with optimizations (default: rtl)",
41+
default=_Optimize.rtl,
42+
)
43+
parser.add_argument(
44+
"-v",
45+
"--vcd",
46+
action="store_true",
47+
help="output a VCD file",
48+
)
49+
50+
51+
def main(rp, args):
52+
yosys = find_yosys(lambda ver: ver >= (0, 10))
53+
54+
platform = Platform["cxxsim"]
55+
sig = inspect.signature(rp.cxxsim_top)
56+
kwargs = {}
57+
if "platform" in sig.parameters:
58+
kwargs["platform"] = platform
59+
design = rp.cxxsim_top(**kwargs)
60+
61+
cxxrtl_cc_path = rp.path.build(f"{rp.name}.cc")
62+
_cxxrtl_convert_with_header(
63+
yosys,
64+
cxxrtl_cc_path,
65+
design,
66+
platform,
67+
black_boxes={},
68+
ports=design.ports(platform),
69+
)
70+
71+
cc_o_paths = {
72+
rp.path("cxxsim/main.cc"): rp.path.build("main.o"),
73+
}
74+
75+
for cc_path, o_path in cc_o_paths.items():
76+
subprocess.run(
77+
[
78+
"c++",
79+
*(["-O3"] if args.optimize.opt_rtl else []),
80+
"-I" + str(rp.path(".")),
81+
"-I" + str(yosys.data_dir() / "include" / "backends" / "cxxrtl" / "runtime"),
82+
"-c",
83+
cc_path,
84+
"-o",
85+
o_path,
86+
],
87+
check=True,
88+
)
89+
90+
exe_o_path = rp.path.build("cxxsim")
91+
subprocess.run(
92+
[
93+
"c++",
94+
*(["-O3"] if args.optimize.opt_rtl else []),
95+
*cc_o_paths.values(),
96+
"-o",
97+
exe_o_path,
98+
],
99+
check=True,
100+
)
101+
102+
if not args.compile:
103+
cmd = [exe_o_path]
104+
if args.vcd:
105+
cmd += ["--vcd"]
106+
subprocess.run(cmd, cwd=rp.path("cxxsim"), check=True)
107+
108+
109+
def _cxxrtl_convert_with_header(yosys, cc_out, design, platform, *, black_boxes, ports):
110+
if cc_out.is_absolute():
111+
try:
112+
cc_out = cc_out.relative_to(Path.cwd())
113+
except ValueError:
114+
raise AssertionError(
115+
"cc_out must be relative to cwd for builtin-yosys to write to it"
116+
)
117+
rtlil_text = rtlil.convert(design, platform=platform, ports=ports)
118+
script = []
119+
for box_source in black_boxes.values():
120+
script.append(f"read_rtlil <<rtlil\n{box_source}\nrtlil")
121+
script.append(f"read_rtlil <<rtlil\n{rtlil_text}\nrtlil")
122+
script.append(f"write_cxxrtl -header {cc_out}")
123+
yosys.run(["-q", "-"], "\n".join(script))

0 commit comments

Comments
 (0)