CIRCT 23.0.0git
Loading...
Searching...
No Matches
loopback_typed.cpp
Go to the documentation of this file.
1#include "loopback/LoopbackIP.h"
2#include "loopback/SerialCoordTranslator.h"
3
4#include "probe_runner.h"
5
6#include "esi/Accelerator.h"
7#include "esi/Manifest.h"
8#include "esi/Services.h"
9#include "esi/TypedPorts.h"
10
11#include <cstdint>
12#include <iostream>
13#include <random>
14#include <stdexcept>
15#include <vector>
16
17using namespace esi;
18
19static int runLoopbackI8(Accelerator *accel) {
20 AppIDPath lastLookup;
21 BundlePort *inPort = accel->resolvePort(
22 {AppID("loopback_inst", 0), AppID("loopback_tohw")}, lastLookup);
23 if (!inPort)
24 throw std::runtime_error("No loopback_tohw port found");
25 BundlePort *outPort = accel->resolvePort(
26 {AppID("loopback_inst", 0), AppID("loopback_fromhw")}, lastLookup);
27 if (!outPort)
28 throw std::runtime_error("No loopback_fromhw port found");
29
30 // Use TypedWritePort and TypedReadPort instead of raw channels.
31 TypedWritePort<uint8_t> toHw(inPort->getRawWrite("recv"));
32 TypedReadPort<uint8_t> fromHw(outPort->getRawRead("send"));
33 toHw.connect();
34 fromHw.connect();
35
36 uint8_t sendVal = 0x5a;
37 toHw.write(sendVal);
38
39 std::unique_ptr<uint8_t> got = fromHw.read();
40 if (!got || *got != sendVal)
41 throw std::runtime_error("Loopback byte mismatch");
42
43 std::cout << "loopback_i8 ok: 0x" << std::hex << (int)*got << std::dec
44 << "\n";
45 return 0;
46}
47
48static int runStructFunc(Accelerator *accel) {
49 AppIDPath lastLookup;
50 BundlePort *port = accel->resolvePort({AppID("structFunc")}, lastLookup);
51 if (!port)
52 throw std::runtime_error("No structFunc port found");
53
54 // Use TypedFunction instead of raw FuncService::Function.
57 func.connect();
58
59 esi_system::ArgStruct arg{};
60 arg.a = 0x1234;
61 arg.b = static_cast<int8_t>(-7);
62
63 esi_system::ResultStruct res = func.call(arg).get();
64
65 int8_t expectedX = static_cast<int8_t>(arg.b + 1);
66 if (res.x != expectedX || res.y != arg.b)
67 throw std::runtime_error("Struct func result mismatch");
68
69 std::cout << "struct_func ok: b=" << (int)arg.b << " x=" << (int)res.x
70 << " y=" << (int)res.y << "\n";
71 return 0;
72}
73
74static int runOddStructFunc(Accelerator *accel) {
75 AppIDPath lastLookup;
76 BundlePort *port = accel->resolvePort({AppID("oddStructFunc")}, lastLookup);
77 if (!port)
78 throw std::runtime_error("No oddStructFunc port found");
79
80 // Use TypedFunction with OddStruct for both arg and result.
83 func.connect();
84
85 esi_system::OddStruct arg{};
86 arg.a = 0xabc;
87 arg.b = static_cast<int8_t>(-17);
88 arg.inner.p = 5;
89 arg.inner.q = static_cast<int8_t>(-7);
90 arg.inner.r[0] = 3;
91 arg.inner.r[1] = 4;
92
93 esi_system::OddStruct res = func.call(arg).get();
94
95 uint16_t expectA = static_cast<uint16_t>(arg.a + 1);
96 int8_t expectB = static_cast<int8_t>(arg.b - 3);
97 uint8_t expectP = static_cast<uint8_t>(arg.inner.p + 5);
98 int8_t expectQ = static_cast<int8_t>(arg.inner.q + 2);
99 uint8_t expectR0 = static_cast<uint8_t>(arg.inner.r[0] + 1);
100 uint8_t expectR1 = static_cast<uint8_t>(arg.inner.r[1] + 2);
101 if (res.a != expectA || res.b != expectB || res.inner.p != expectP ||
102 res.inner.q != expectQ || res.inner.r[0] != expectR0 ||
103 res.inner.r[1] != expectR1)
104 throw std::runtime_error("Odd struct func result mismatch");
105
106 std::cout << "odd_struct_func ok: a=" << res.a << " b=" << (int)res.b
107 << " p=" << (int)res.inner.p << " q=" << (int)res.inner.q
108 << " r0=" << (int)res.inner.r[0] << " r1=" << (int)res.inner.r[1]
109 << "\n";
110 return 0;
111}
112
113static int runArrayFunc(Accelerator *accel) {
114 AppIDPath lastLookup;
115 BundlePort *port = accel->resolvePort({AppID("arrayFunc")}, lastLookup);
116 if (!port)
117 throw std::runtime_error("No arrayFunc port found");
118
119 auto *func = port->getAs<services::FuncService::Function>();
120 if (!func)
121 throw std::runtime_error("arrayFunc not a FuncService::Function");
122 func->connect();
123
124 int8_t argArray[1] = {static_cast<int8_t>(-3)};
125 MessageData resMsg =
126 func->call(MessageData(reinterpret_cast<const uint8_t *>(argArray),
127 sizeof(argArray)))
128 .get();
129
130 const auto *res = resMsg.as<esi_system::ResultArray>();
131 int8_t a = (*res)[0];
132 int8_t b = (*res)[1];
133 int8_t expect0 = argArray[0];
134 int8_t expect1 = static_cast<int8_t>(argArray[0] + 1);
135
136 bool ok = (a == expect0 && b == expect1) || (a == expect1 && b == expect0);
137 if (!ok)
138 throw std::runtime_error("Array func result mismatch");
139
140 int8_t low = a;
141 int8_t high = b;
142 if (low > high) {
143 int8_t tmp = low;
144 low = high;
145 high = tmp;
146 }
147 std::cout << "array_func ok: " << (int)low << " " << (int)high << "\n";
148 return 0;
149}
150
151static int runSInt4Loopback(Accelerator *accel) {
152 AppIDPath lastLookup;
153 BundlePort *port = accel->resolvePort({AppID("sint4Func")}, lastLookup);
154 if (!port)
155 throw std::runtime_error("No sint4Func port found");
156
157 // Use TypedFunction<int8_t, int8_t> for si4 → si4 loopback.
158 // si4 fits in int8_t (width 4 <= 8). Tests sign extension of small widths.
161 func.connect();
162
163 // Test positive value.
164 int8_t posArg = 5;
165 int8_t posResult = func.call(posArg).get();
166 if (posResult != posArg)
167 throw std::runtime_error("sint4 loopback positive mismatch: got " +
168 std::to_string(posResult));
169
170 // Test negative value (-3, which is 0x0D in si4 wire format).
171 int8_t negArg = -3;
172 int8_t negResult = func.call(negArg).get();
173 if (negResult != negArg)
174 throw std::runtime_error("sint4 loopback negative mismatch: got " +
175 std::to_string(negResult));
176
177 std::cout << "sint4_loopback ok: pos=" << (int)posResult
178 << " neg=" << (int)negResult << "\n";
179 return 0;
180}
181
182//
183// SerialCoordTranslator test
184//
185
186using SerialCoordInput = esi_system::
187 _struct_x_translation_i32_y_translation_i32_coords__esi_list__hw_struct_x__i32__y__i32___serial_coord_args;
188using SerialCoordResult = esi_system::
189 _struct_coords__esi_list__hw_struct_x__i32__y__i32___serial_coord_result;
190using SerialCoordValue = SerialCoordInput::value_type;
191
193 size_t numCoords = 100;
194 uint32_t xTrans = 10, yTrans = 20;
195
196 // Generate random coordinates.
197 std::mt19937 rng(0xDEADBEEF);
198 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
199 std::vector<SerialCoordValue> coords;
200 coords.reserve(numCoords);
201 for (uint32_t i = 0; i < numCoords; ++i)
202 coords.emplace_back(dist(rng), dist(rng));
203
204 auto childIt = accel->getChildren().find(AppID("coord_translator_serial"));
205 if (childIt == accel->getChildren().end())
206 throw std::runtime_error("Serial coord translate test: no "
207 "'coord_translator_serial' child found");
208
209 esi_system::SerialCoordTranslator translator(childIt->second);
210 auto connected = translator.connect();
211
212 // Drive the serial-list window through the generated facade. The
213 // TypedFunction member handles frame packing and result reassembly;
214 // the emplace-style call() overload constructs SerialCoordInput
215 // in-place from the forwarded constructor arguments.
216 SerialCoordResult result =
217 connected->translate_coords_serial(xTrans, yTrans, coords).get();
218
219 if (result.coords_count() != coords.size())
220 throw std::runtime_error("Serial coord translate result size mismatch");
221 size_t i = 0;
222 for (const SerialCoordValue &got : result.coords()) {
223 uint32_t expX = coords[i].x + xTrans;
224 uint32_t expY = coords[i].y + yTrans;
225 if (got.x != expX || got.y != expY)
226 throw std::runtime_error("Serial coord translate result mismatch");
227 ++i;
228 }
229 std::cout << "serial_coord_translate ok\n";
230 return 0;
231}
232
234 std::cout << "depth: 0x" << std::hex << esi_system::LoopbackIP::depth
235 << std::dec << "\n";
236 std::cout << "depth_constant ok\n";
237 return 0;
238}
239
241 "loopback-typed-cpp",
242 "Loopback cosim test using generated ESI headers and typed ports.",
243 {"depth_constant", &runDepthConstant}, {"loopback_i8", &runLoopbackI8},
244 {"sint4_loopback", &runSInt4Loopback}, {"struct_func", &runStructFunc},
245 {"odd_struct_func", &runOddStructFunc}, {"array_func", &runArrayFunc},
246 {"serial_coord_translate", &serialCoordTranslateTest}, );
Top level accelerator class.
Definition Accelerator.h:70
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
Definition Ports.h:611
T * getAs() const
Cast this Bundle port to a subclass which is actually useful.
Definition Ports.h:639
ReadChannelPort & getRawRead(const std::string &name) const
Definition Ports.cpp:52
WriteChannelPort & getRawWrite(const std::string &name) const
Get access to the raw byte streams of a channel.
Definition Ports.cpp:42
BundlePort * resolvePort(const AppIDPath &path, AppIDPath &lastLookup) const
Attempt to resolve a path to a port.
Definition Design.cpp:72
const std::map< AppID, Instance * > & getChildren() const
Access the module's children by ID.
Definition Design.h:71
A concrete flat message backed by a single vector of bytes.
Definition Common.h:155
const T * as() const
Cast to a type.
Definition Common.h:190
std::future< ResultT > call(const ArgT &arg)
Strongly typed wrapper around a raw read channel.
Definition TypedPorts.h:718
std::unique_ptr< T > read()
Blocking typed read in polling mode.
Definition TypedPorts.h:801
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Connect in polling mode.
Definition TypedPorts.h:737
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Definition TypedPorts.h:626
void write(const T &data)
Definition TypedPorts.h:636
A function call which gets attached to a service port.
Definition Services.h:353
static int serialCoordTranslateTest(Accelerator *accel)
static int runSInt4Loopback(Accelerator *accel)
esi_system::_struct_coords__esi_list__hw_struct_x__i32__y__i32___serial_coord_result SerialCoordResult
static int runDepthConstant(Accelerator *)
static int runArrayFunc(Accelerator *accel)
static int runOddStructFunc(Accelerator *accel)
static int runStructFunc(Accelerator *accel)
static int runLoopbackI8(Accelerator *accel)
SerialCoordInput::value_type SerialCoordValue
Definition esi.py:1
#define ESI_PROBE_REGISTRY(name, description,...)
Convenience macro: defines main() with a probe registry.