1#include "loopback/LoopbackIP.h"
21 {
AppID(
"loopback_inst", 0),
AppID(
"loopback_tohw")}, lastLookup);
23 throw std::runtime_error(
"No loopback_tohw port found");
25 {
AppID(
"loopback_inst", 0),
AppID(
"loopback_fromhw")}, lastLookup);
27 throw std::runtime_error(
"No loopback_fromhw port found");
34 uint8_t sendVal = 0x5a;
39 if (recvMsg.
getSize() !=
sizeof(uint8_t))
40 throw std::runtime_error(
"Unexpected loopback recv size");
41 uint8_t got = *recvMsg.
as<uint8_t>();
43 throw std::runtime_error(
"Loopback byte mismatch");
45 std::cout <<
"loopback_i8 ok: 0x" << std::hex << (int)got << std::dec <<
"\n";
53 throw std::runtime_error(
"No structFunc port found");
57 throw std::runtime_error(
"structFunc not a FuncService::Function");
60 esi_system::ArgStruct arg{};
62 arg.b(
static_cast<int8_t
>(-7));
65 const auto *res = resMsg.
as<esi_system::ResultStruct>();
67 int8_t expectedX =
static_cast<int8_t
>(arg.b() + 1);
68 if (res->x() != expectedX || res->y() != arg.b())
69 throw std::runtime_error(
"Struct func result mismatch");
71 std::cout <<
"struct_func ok: b=" << (int)arg.b() <<
" x=" << (int)res->x()
72 <<
" y=" << (int)res->y() <<
"\n";
80 throw std::runtime_error(
"No oddStructFunc port found");
84 throw std::runtime_error(
"oddStructFunc not a FuncService::Function");
87 esi_system::OddStruct arg{
89 static_cast<int8_t
>(-17),
90 {5,
static_cast<int8_t
>(-7), {3, 4}},
94 const auto *res = resMsg.
as<esi_system::OddStruct>();
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 ||
103 res->inner().p() != expectP || res->inner().q() != expectQ ||
104 res->inner().r()[0] != expectR0 || res->inner().r()[1] != expectR1)
105 throw std::runtime_error(
"Odd struct func result mismatch");
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";
118 throw std::runtime_error(
"No arrayFunc port found");
122 throw std::runtime_error(
"arrayFunc not a FuncService::Function");
125 int8_t argArray[1] = {
static_cast<int8_t
>(-3)};
127 func->call(
MessageData(
reinterpret_cast<const uint8_t *
>(argArray),
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);
137 bool ok = (a == expect0 && b == expect1) || (a == expect1 && b == expect0);
139 throw std::runtime_error(
"Array func result mismatch");
148 std::cout <<
"array_func ok: " << (int)low <<
" " << (
int)high <<
"\n";
187 std::vector<SerialCoordData>
coords;
197 std::vector<SerialCoordData> &
coords,
201 header.xTranslation = xTrans;
202 header.yTranslation = yTrans;
219 return {
reinterpret_cast<const uint8_t *
>(&
header),
sizeof(
header)};
224 throw std::runtime_error(
225 "SerialCoordInput: coordinates segment has been taken");
229 return {
reinterpret_cast<const uint8_t *
>(&
footer),
sizeof(
footer)};
231 throw std::out_of_range(
"SerialCoordInput: invalid segment index");
234 std::unique_ptr<services::HostMemRegion>
take(
size_t segIdx)
override {
236 throw std::out_of_range(
"SerialCoordInput: invalid segment index");
240 throw std::runtime_error(
241 "SerialCoordInput: coordinates segment has been taken");
256 SerialCoordOutputHeader
header;
257 SerialCoordOutputData
data;
264 const char *probeName) {
265 size_t numCoords = 100;
266 uint32_t xTrans = 10, yTrans = 20;
269 std::mt19937 rng(0xDEADBEEF);
270 std::uniform_int_distribution<uint32_t> dist(0, 1000000);
271 std::vector<Coord> inputCoords;
272 inputCoords.reserve(numCoords);
273 for (uint32_t i = 0; i < numCoords; ++i)
274 inputCoords.push_back({dist(rng), dist(rng)});
278 throw std::runtime_error(
"Serial coord translate test: no "
279 "'coord_translator_serial' child found");
281 auto &ports = child->second->getPorts();
282 auto portIter = ports.find(
AppID(
"translate_coords_serial"));
283 if (portIter == ports.end())
284 throw std::runtime_error(
285 "Serial coord translate test: no 'translate_coords_serial' port found");
289 throw std::runtime_error(
290 "Serial coord translate test: port is not a FuncService::Function");
298 func->getRawWrite(
"arg"));
310 std::vector<SerialCoordData> coords;
311 for (
auto &c : inputCoords)
312 coords.emplace_back(c.x, c.y);
314 std::make_unique<SerialCoordInput>(xTrans, yTrans, coords, allocator);
317 Segment coordsSeg = batch->segment(1);
319 throw std::runtime_error(
320 "Serial coord translate test: coordinates not in a HostMem region");
321 if (batch->take(0) !=
nullptr)
322 throw std::runtime_error(
323 "Serial coord translate test: header segment has a region");
327 argPort.
write(batch);
333 for (
size_t i = 0; i < numCoords + 2; ++i)
334 rawResult.
read(drained);
335 std::cout << probeName <<
" ok\n";
342 if (allocator.
allocate(0, {}) !=
nullptr)
343 throw std::runtime_error(
"HostMem take test: allocate(0) should fail");
345 std::vector<SerialCoordData> coords = {{1, 2}, {3, 4}, {5, 6}};
349 throw std::runtime_error(
350 "HostMem take test: coordinates not in a HostMem region");
354 std::unique_ptr<services::HostMemRegion> region = msg.
take(1);
355 if (region.get() != coordsSeg.
region)
356 throw std::runtime_error(
"HostMem take test: take() returned the wrong "
358 if (std::memcmp(region->getPtr(), coords.data(),
360 throw std::runtime_error(
"HostMem take test: region contents corrupted");
363 auto throws = [](
auto fn) {
366 }
catch (
const std::runtime_error &) {
371 if (!
throws([&] { msg.
segment(1); }) || !
throws([&] { msg.
take(1); }))
372 throw std::runtime_error(
373 "HostMem take test: taken segment is still accessible");
375 throw std::runtime_error(
"HostMem take test: header segment inaccessible");
390 std::cout <<
"depth: 0x" << std::hex << esi_system::LoopbackIP::depth
392 std::cout <<
"depth_constant ok\n";
397 "loopback-cpp",
"Loopback cosim test using generated ESI headers.",
if(parseOptionalKeywordOrOptionalString(parser, result.rawName, found)) return failure()
Top level accelerator class.
BundlePort * resolvePort(const AppIDPath &path, AppIDPath &lastLookup) const
Attempt to resolve a path to a port.
const std::map< AppID, Instance * > & getChildren() const
Access the module's children by ID.
A concrete flat message backed by a single vector of bytes.
const T * as() const
Cast to a type.
size_t getSize() const
Get the size of the data in bytes.
static MessageData from(T &t)
Cast from a type to its raw bytes.
A ChannelPort which reads data from the accelerator.
virtual void connect(ReadCallback callback, const ConnectOptions &options={})
virtual void read(MessageData &outData)
Specify a buffer to read into.
Abstract multi-segment message.
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
void write(const T &data)
A ChannelPort which sends data to the accelerator.
void write(const MessageData &data)
A very basic blocking write API.
virtual void connect(const ConnectOptions &options={}) override
Set up a connection to the accelerator.
A function call which gets attached to a service port.
Interface for anything which can allocate HostMemRegions.
virtual std::unique_ptr< HostMemRegion > allocate(std::size_t size, Options opts) const =0
Allocate a region of host memory in accelerator accessible address space.
static void serialCoordTranslateTest(AcceleratorConnection *, Accelerator *, uint32_t xTrans, uint32_t yTrans, uint32_t numCoords, size_t batchSizeLimit)
static int serialCoordTranslateTest(Accelerator *accel)
static void checkHostMemTake(services::HostMemAllocator &allocator)
static int runDepthConstant(Accelerator *)
static int serialCoordTranslate(Accelerator *accel, services::HostMemAllocator *allocator, const char *probeName)
static int runArrayFunc(Accelerator *accel)
static int serialCoordTranslateHostMemTest(Accelerator *accel)
static int runOddStructFunc(Accelerator *accel)
static int runStructFunc(Accelerator *accel)
static int runLoopbackI8(Accelerator *accel)
esi::AcceleratorConnection * probeConnection
The connection the probes are running against, for probes which need connection-level services (e....
#define ESI_PROBE_REGISTRY(name, description,...)
Convenience macro: defines main() with a probe registry.
Test the CoordTranslator module using message translation.
SerialCoordData(uint32_t x, uint32_t y)
A contiguous, non-owning view of bytes within a SegmentedMessageData.
std::optional< uint64_t > getDeviceAddress() const
Device address of this segment's bytes, if region is set and contains them; std::nullopt otherwise.
services::HostMemRegion * region
The HostMem region (from services::HostMem::allocate()) which holds [data, data + size),...
SerialCoordOutputData data
SerialCoordOutputHeader header