CIRCT 23.0.0git
Loading...
Searching...
No Matches
test_loopback_cpp.py
Go to the documentation of this file.
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2# See https://llvm.org/LICENSE.txt for license information.
3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5from __future__ import annotations
6
7from pathlib import Path
8import shutil
9import subprocess
10import sys
11
12import pytest
13
14from esiaccel.cosim.pytest import cosim_test
15
16from .conftest import (HW_DIR, SW_DIR, build_cpp_test, check_lines,
17 get_runtime_root, require_tool, run_probe)
18
19LOOPBACK_PROBES = [
20 ("depth_constant", ["depth: 0x5", "depth_constant ok"]),
21 ("loopback_i8", ["loopback_i8 ok: 0x5a"]),
22 ("struct_func", ["struct_func ok: b=-7 x=-6 y=-7"]),
23 ("odd_struct_func",
24 ["odd_struct_func ok: a=2749 b=-20 p=10 q=-5 r0=4 r1=6"]),
25 ("array_func", ["array_func ok: -3 -2"]),
26 ("serial_coord_translate", ["serial_coord_translate ok"]),
27]
28
29LOOPBACK_TYPED_PROBES = [
30 ("depth_constant", ["depth: 0x5", "depth_constant ok"]),
31 ("loopback_i8", ["loopback_i8 ok: 0x5a"]),
32 ("sint4_loopback", ["sint4_loopback ok: pos=5 neg=-3"]),
33 ("struct_func", ["struct_func ok: b=-7 x=-6 y=-7"]),
34 ("odd_struct_func",
35 ["odd_struct_func ok: a=2749 b=-20 p=10 q=-5 r0=4 r1=6"]),
36 ("array_func", ["array_func ok: -3 -2"]),
37 ("serial_coord_translate", ["serial_coord_translate ok"]),
38]
39
40
41def _build_loopback_codegen(tmp_path: Path, host: str, port: int) -> Path:
42 """Run live-connection codegen and build the loopback_test binary.
43
44 This test deliberately uses ``esiaccel.codegen --platform cosim`` (live
45 connection) rather than ``--file`` (offline manifest) to exercise that
46 codegen path.
47 """
48 require_tool("cmake")
49
50 runtime_root = get_runtime_root()
51
52 include_dir = tmp_path / "include"
53 generated_dir = include_dir / "loopback"
54 generated_dir.mkdir(parents=True, exist_ok=True)
55
56 subprocess.run(
57 [
58 sys.executable,
59 "-m",
60 "esiaccel.codegen",
61 "--platform",
62 "cosim",
63 "--connection",
64 f"{host}:{port}",
65 "--output-dir",
66 str(generated_dir),
67 ],
68 check=True,
69 )
70
71 # Verify generated header content (LOOPBACK-H checks).
72 header_path = generated_dir / "LoopbackIP.h"
73 assert header_path.exists(), "Generated header LoopbackIP.h not found"
74 header_content = header_path.read_text()
75 check_lines(header_content, [
76 "/// Generated header for esi_system module LoopbackIP.",
77 "#pragma once",
78 '#include "types.h"',
79 "namespace esi_system {",
80 "class LoopbackIP {",
81 "static constexpr uint32_t depth = 0x5;",
82 "} // namespace esi_system",
83 ])
84
85 build_dir = tmp_path / "loopback-build"
86 result = subprocess.run(
87 [
88 "cmake",
89 "-S",
90 str(SW_DIR),
91 "-B",
92 str(build_dir),
93 f"-DLOOPBACK_GENERATED_DIR={include_dir}",
94 f"-DESI_RUNTIME_ROOT={runtime_root}",
95 ],
96 capture_output=True,
97 text=True,
98 )
99 assert result.returncode == 0, (
100 f"cmake configure failed (rc={result.returncode}):\n"
101 f"--- stdout ---\n{result.stdout}\n"
102 f"--- stderr ---\n{result.stderr}")
103
104 result = subprocess.run(
105 ["cmake", "--build",
106 str(build_dir), "--target", "loopback_test"],
107 capture_output=True,
108 text=True,
109 )
110 assert result.returncode == 0, (
111 f"cmake build failed (rc={result.returncode}):\n"
112 f"--- stdout ---\n{result.stdout}\n"
113 f"--- stderr ---\n{result.stderr}")
114
115 return build_dir / "loopback_test"
116
117
118@cosim_test(HW_DIR / "loopback.py")
120 """Tests for esiquery against the loopback design."""
121
122 def test_loopback_cpp_codegen(self, tmp_path: Path, host: str,
123 port: int) -> None:
124 """Build against live-connection codegen and run all probes."""
125 binary = _build_loopback_codegen(tmp_path, host, port)
126 for probe, expected in LOOPBACK_PROBES:
127 run_probe(binary, host, port, probe, expected)
128
129 def test_loopback_typed_cpp_codegen(self, host: str, port: int,
130 sources_dir: Path) -> None:
131 binary = build_cpp_test(sources_dir, "loopback_typed_test", "loopback")
132 for probe, expected in LOOPBACK_TYPED_PROBES:
133 run_probe(binary, host, port, probe, expected)
134
135 def test_loopback_query_info(self, sources_dir: Path) -> None:
136 """Verify esiquery info output against the generated manifest
137 (QUERY-INFO checks)."""
138 require_tool("esiquery")
139 manifest = sources_dir / "esi_system_manifest.json"
140 assert manifest.exists(), "Manifest not found"
141 result = subprocess.run(
142 ["esiquery", "trace", f"w:{manifest}", "info"],
143 check=True,
144 capture_output=True,
145 text=True,
146 )
147 check_lines(result.stdout, [
148 "API version: 0",
149 "* Module information",
150 "- LoopbackIP v0.0",
151 "IP which simply echos bytes",
152 "Constants:",
153 "depth: 5",
154 "Extra metadata:",
155 "foo: 1",
156 ])
157
158 def test_loopback_query_hier(self, sources_dir: Path) -> None:
159 """Verify esiquery hier output against the generated manifest
160 (QUERY-HIER checks)."""
161 require_tool("esiquery")
162 manifest = sources_dir / "esi_system_manifest.json"
163 assert manifest.exists(), "Manifest not found"
164 result = subprocess.run(
165 ["esiquery", "trace", f"w:{manifest}", "hier"],
166 check=True,
167 capture_output=True,
168 text=True,
169 )
170 check_lines(result.stdout, [
171 "* Design hierarchy",
172 "func1: function uint16(uint16)",
173 "structFunc: function ResultStruct(ArgStruct)",
174 "arrayFunc: function ResultArray(sint8[1])",
175 "* Instance: loopback_inst[0]",
176 "loopback_tohw:",
177 "recv: bits8",
178 "loopback_fromhw:",
179 "send: bits8",
180 "mysvc_recv:",
181 "recv: void",
182 "mysvc_send:",
183 "send: void",
184 "* Instance: loopback_inst[1]",
185 ])
None test_loopback_typed_cpp_codegen(self, str host, int port, Path sources_dir)
None test_loopback_cpp_codegen(self, Path tmp_path, str host, int port)
Path _build_loopback_codegen(Path tmp_path, str host, int port)