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 auto inner = arg.inner();
89 inner.p(5);
90 inner.q(static_cast<int8_t>(-7));
91 inner.r({3, 4});
92 arg.inner(inner);
93
94 esi_system::OddStruct res = func.call(arg).get();
95
96 uint16_t expectA = static_cast<uint16_t>(arg.a() + 1);
97 int8_t expectB = static_cast<int8_t>(arg.b() - 3);
98 uint8_t expectP = static_cast<uint8_t>(arg.inner().p() + 5);
99 int8_t expectQ = static_cast<int8_t>(arg.inner().q() + 2);
100 uint8_t expectR0 = static_cast<uint8_t>(arg.inner().r()[0] + 1);
101 uint8_t expectR1 = static_cast<uint8_t>(arg.inner().r()[1] + 2);
102 if (res.a() != expectA || res.b() != expectB || res.inner().p() != expectP ||
103 res.inner().q() != expectQ || res.inner().r()[0] != expectR0 ||
104 res.inner().r()[1] != expectR1)
105 throw std::runtime_error("Odd struct func result mismatch");
106
107 std::cout << "odd_struct_func ok: a=" << res.a() << " b=" << (int)res.b()
108 << " p=" << (int)res.inner().p() << " q=" << (int)res.inner().q()
109 << " r0=" << (int)res.inner().r()[0]
110 << " r1=" << (int)res.inner().r()[1] << "\n";
111 return 0;
112}
113
114static int runArrayFunc(Accelerator *accel) {
115 AppIDPath lastLookup;
116 BundlePort *port = accel->resolvePort({AppID("arrayFunc")}, lastLookup);
117 if (!port)
118 throw std::runtime_error("No arrayFunc port found");
119
120 auto *func = port->getAs<services::FuncService::Function>();
121 if (!func)
122 throw std::runtime_error("arrayFunc not a FuncService::Function");
123 func->connect();
124
125 int8_t argArray[1] = {static_cast<int8_t>(-3)};
126 MessageData resMsg =
127 func->call(MessageData(reinterpret_cast<const uint8_t *>(argArray),
128 sizeof(argArray)))
129 .get();
130
131 const auto *res = resMsg.as<esi_system::ResultArray>();
132 int8_t a = (*res)[0];
133 int8_t b = (*res)[1];
134 int8_t expect0 = argArray[0];
135 int8_t expect1 = static_cast<int8_t>(argArray[0] + 1);
136
137 bool ok = (a == expect0 && b == expect1) || (a == expect1 && b == expect0);
138 if (!ok)
139 throw std::runtime_error("Array func result mismatch");
140
141 int8_t low = a;
142 int8_t high = b;
143 if (low > high) {
144 int8_t tmp = low;
145 low = high;
146 high = tmp;
147 }
148 std::cout << "array_func ok: " << (int)low << " " << (int)high << "\n";
149 return 0;
150}
151
152static int runSInt4Loopback(Accelerator *accel) {
153 AppIDPath lastLookup;
154 BundlePort *port = accel->resolvePort({AppID("sint4Func")}, lastLookup);
155 if (!port)
156 throw std::runtime_error("No sint4Func port found");
157
158 // Use TypedFunction<int8_t, int8_t> for si4 → si4 loopback.
159 // si4 fits in int8_t (width 4 <= 8). Tests sign extension of small widths.
162 func.connect();
163
164 // Test positive value.
165 int8_t posArg = 5;
166 int8_t posResult = func.call(posArg).get();
167 if (posResult != posArg)
168 throw std::runtime_error("sint4 loopback positive mismatch: got " +
169 std::to_string(posResult));
170
171 // Test negative value (-3, which is 0x0D in si4 wire format).
172 int8_t negArg = -3;
173 int8_t negResult = func.call(negArg).get();
174 if (negResult != negArg)
175 throw std::runtime_error("sint4 loopback negative mismatch: got " +
176 std::to_string(negResult));
177
178 std::cout << "sint4_loopback ok: pos=" << (int)posResult
179 << " neg=" << (int)negResult << "\n";
180 return 0;
181}
182
183//
184// SerialCoordTranslator test
185//
186
187using SerialCoordInput = esi_system::
188 _struct_x_translation_i32_y_translation_i32_coords__esi_list__hw_struct_x__i32__y__i32___serial_coord_args;
189using SerialCoordResult = esi_system::
190 _struct_coords__esi_list__hw_struct_x__i32__y__i32___serial_coord_result;
191using SerialCoordValue = SerialCoordInput::value_type;
192
194 size_t numCoords = 100;
195 uint32_t xTrans = 10, yTrans = 20;
196
197 // Generate random coordinates.
198 std::mt19937 rng(0xDEADBEEF);
199 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
200 std::vector<SerialCoordValue> coords;
201 coords.reserve(numCoords);
202 for (uint32_t i = 0; i < numCoords; ++i)
203 coords.emplace_back(dist(rng), dist(rng));
204
205 auto childIt = accel->getChildren().find(AppID("coord_translator_serial"));
206 if (childIt == accel->getChildren().end())
207 throw std::runtime_error("Serial coord translate test: no "
208 "'coord_translator_serial' child found");
209
210 esi_system::SerialCoordTranslator translator(childIt->second);
211 auto connected = translator.connect();
212
213 // Drive the serial-list window through the generated facade. The
214 // TypedFunction member handles frame packing and result reassembly;
215 // the emplace-style call() overload constructs SerialCoordInput
216 // in-place from the forwarded constructor arguments.
217 SerialCoordResult result =
218 connected->translate_coords_serial(xTrans, yTrans, coords).get();
219
220 if (result.coords_count() != coords.size())
221 throw std::runtime_error("Serial coord translate result size mismatch");
222 size_t i = 0;
223 for (const SerialCoordValue &got : result.coords()) {
224 uint32_t expX = coords[i].x() + xTrans;
225 uint32_t expY = coords[i].y() + yTrans;
226 if (got.x() != expX || got.y() != expY)
227 throw std::runtime_error("Serial coord translate result mismatch");
228 ++i;
229 }
230 std::cout << "serial_coord_translate ok\n";
231 return 0;
232}
233
235 std::cout << "depth: 0x" << std::hex << esi_system::LoopbackIP::depth
236 << std::dec << "\n";
237 std::cout << "depth_constant ok\n";
238 return 0;
239}
240
242 "loopback-typed-cpp",
243 "Loopback cosim test using generated ESI headers and typed ports.",
244 {"depth_constant", &runDepthConstant}, {"loopback_i8", &runLoopbackI8},
245 {"sint4_loopback", &runSInt4Loopback}, {"struct_func", &runStructFunc},
246 {"odd_struct_func", &runOddStructFunc}, {"array_func", &runArrayFunc},
247 {"serial_coord_translate", &serialCoordTranslateTest}, );
Top level accelerator class.
Definition Accelerator.h:77
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.