11#include "test_codegen/CallServiceCallback.h"
12#include "test_codegen/CallbackWindowedList.h"
13#include "test_codegen/ChannelWindowedListRead.h"
14#include "test_codegen/ChannelWindowedListWrite.h"
15#include "test_codegen/CustomServiceDeclChannel.h"
16#include "test_codegen/IndexedFuncGroup.h"
17#include "test_codegen/MmioReadWrite.h"
18#include "test_codegen/TelemetryMetric.h"
19#include "test_codegen/TypedFuncArrayResult.h"
20#include "test_codegen/TypedFuncMultiArg.h"
21#include "test_codegen/TypedFuncNestedStruct.h"
22#include "test_codegen/TypedFuncStruct.h"
23#include "test_codegen/TypedFuncSubByteSigned.h"
24#include "test_codegen/TypedFuncVoidArg.h"
25#include "test_codegen/TypedFuncVoidResult.h"
26#include "test_codegen/TypedFuncWindowedList.h"
27#include "test_codegen/TypedReadChannelStruct.h"
28#include "test_codegen/TypedWriteChannelByte.h"
54 throw std::runtime_error(std::string(
"test_codegen instance '") +
55 appidName +
"' not found");
63 esi_system::TypedFuncMultiArg mod(
64 findInst(accel,
"typed_func_multi_arg_inst"));
65 auto c = mod.connect();
69 uint32_t got = c->call(7u, 6u).get();
71 throw std::runtime_error(
"typed_func_multi_arg: expected 42, got " +
73 std::cout <<
"typed_func_multi_arg ok\n";
81 esi_system::TypedFuncVoidArg mod(
findInst(accel,
"typed_func_void_arg_inst"));
82 auto c = mod.connect();
84 uint32_t got = c->call().get();
85 if (got != 0xCAFEF00Du)
86 throw std::runtime_error(
87 "typed_func_void_arg: expected 0xCAFEF00D, got 0x" +
toHex(got));
88 std::cout <<
"typed_func_void_arg ok\n";
96 esi_system::TypedFuncVoidResult mod(
97 findInst(accel,
"typed_func_void_result_inst"));
98 auto c = mod.connect();
103 c->call(esi_system::AckArgs(0x5A, 0x1234)).get();
104 std::cout <<
"typed_func_void_result ok\n";
112 esi_system::CallServiceCallback mod(
113 findInst(accel,
"call_service_callback_inst"));
114 auto c = mod.connect();
120 std::atomic<bool> got_call(
false);
121 esi_system::NotifyArgs seen{};
122 c->callback.connect([&](
const esi_system::NotifyArgs &a) {
124 got_call.store(
true, std::memory_order_release);
130 constexpr uint32_t kPayload = 0xDEADBEEFu;
131 c->trigger.write(0x10,
static_cast<uint64_t
>(kPayload));
134 using clock = std::chrono::steady_clock;
135 auto deadline = clock::now() + std::chrono::seconds(5);
136 while (!got_call.load(std::memory_order_acquire) && clock::now() < deadline)
137 std::this_thread::sleep_for(std::chrono::milliseconds(10));
138 if (!got_call.load(std::memory_order_acquire))
139 throw std::runtime_error(
140 "call_service_callback: callback did not fire within timeout");
142 if (seen.tag() != 0xA5)
143 throw std::runtime_error(
144 "call_service_callback: wrong tag, expected 0xA5 got 0x" +
145 toHex(
static_cast<uint64_t
>(seen.tag())));
146 if (seen.payload() != kPayload)
147 throw std::runtime_error(
148 "call_service_callback: wrong payload, expected 0x" +
toHex(kPayload) +
149 " got 0x" +
toHex(seen.payload()));
150 std::cout <<
"call_service_callback ok\n";
158 esi_system::TypedReadChannelStruct mod(
159 findInst(accel,
"typed_read_channel_struct_inst"));
160 auto c = mod.connect();
163 constexpr size_t kNum = esi_system::TypedReadChannelStruct::num_events;
164 for (
size_t i = 1; i <= kNum; ++i) {
165 auto ev = c->data.read();
167 throw std::runtime_error(
168 "typed_read_channel_struct: null read result at i=" +
171 throw std::runtime_error(
172 "typed_read_channel_struct: wrong ts at i=" + std::to_string(i) +
173 ", got " + std::to_string(ev->ts()));
174 int32_t expected = -
static_cast<int32_t
>(i);
175 if (ev->val() != expected)
176 throw std::runtime_error(
177 "typed_read_channel_struct: wrong val at i=" + std::to_string(i) +
178 ", got " + std::to_string(ev->val()));
180 std::cout <<
"typed_read_channel_struct ok (" << kNum <<
" events)\n";
188 esi_system::TypedWriteChannelByte mod(
189 findInst(accel,
"typed_write_channel_byte_inst"));
190 auto c = mod.connect();
195 static constexpr uint8_t kBytes[] = {0x11, 0x22, 0x44, 0x88, 0x10, 0x55};
196 uint8_t expected = 0;
197 for (uint8_t b : kBytes) {
204 using clock = std::chrono::steady_clock;
205 auto deadline = clock::now() + std::chrono::seconds(2);
207 while (clock::now() < deadline) {
208 uint64_t resp = c->accumulator.read(0);
209 got =
static_cast<uint8_t
>(resp & 0xff);
212 std::this_thread::sleep_for(std::chrono::milliseconds(5));
215 throw std::runtime_error(
216 "typed_write_channel_byte: accumulator mismatch (expected 0x" +
217 toHex(
static_cast<uint64_t
>(expected)) +
", got 0x" +
218 toHex(
static_cast<uint64_t
>(got)) +
")");
219 std::cout <<
"typed_write_channel_byte ok (acc=0x"
220 <<
toHex(
static_cast<uint64_t
>(expected)) <<
")\n";
228 esi_system::MmioReadWrite mod(
findInst(accel,
"mmio_read_write_inst"));
229 auto c = mod.connect();
233 constexpr uint64_t kToken = 0xA5A51234'56789ABCULL;
234 c->region.write(0x10, kToken);
235 uint64_t got = c->region.read(0x10);
237 throw std::runtime_error(
"mmio_read_write: round-trip mismatch (wrote 0x" +
238 toHex(kToken) +
", read 0x" +
toHex(got) +
")");
239 std::cout <<
"mmio_read_write ok (round-trip 0x" <<
toHex(kToken) <<
")\n";
247 esi_system::TelemetryMetric mod(
findInst(accel,
"telemetry_metric_inst"));
248 auto c = mod.connect();
250 uint64_t first = c->cycleCount.readInt();
253 std::this_thread::sleep_for(std::chrono::milliseconds(50));
254 uint64_t second = c->cycleCount.readInt();
257 throw std::runtime_error(
258 "telemetry_metric: counter did not advance (first=" +
259 std::to_string(first) +
", second=" + std::to_string(second) +
")");
260 std::cout <<
"telemetry_metric ok (advanced by " << (second - first) <<
")\n";
272 esi_system::IndexedFuncGroup mod(
findInst(accel,
"indexed_func_group_inst"));
273 auto c = mod.connect();
274 constexpr size_t kN = esi_system::IndexedFuncGroup::num_entries;
275 for (uint32_t idx = 0; idx < kN; ++idx) {
276 constexpr uint16_t kArg = 100;
277 uint16_t got = c->call[idx](kArg).get();
278 uint16_t expected =
static_cast<uint16_t
>(kArg + (idx + 1));
280 throw std::runtime_error(
"indexed_func_group[" + std::to_string(idx) +
281 "]: expected " + std::to_string(expected) +
282 ", got " + std::to_string(got));
284 std::cout <<
"indexed_func_group ok (" << kN <<
" entries)\n";
300 throw std::runtime_error(
"custom_service_decl_channel[" +
301 std::to_string(idx) +
"]: instance not found");
302 esi_system::CustomServiceDeclChannel mod(it->second);
303 auto c = mod.connect();
313 uint8_t sendVal =
static_cast<uint8_t
>(0x40 + idx);
315 std::unique_ptr<uint8_t> got = fromHw.
read();
316 if (!got || *got != sendVal)
317 throw std::runtime_error(
318 "custom_service_decl_channel[" + std::to_string(idx) +
319 "]: byte loopback mismatch (sent 0x" +
320 toHex(
static_cast<uint64_t
>(sendVal)) +
", got 0x" +
321 toHex(
static_cast<uint64_t
>(got ? *got : 0u)) +
")");
323 std::cout <<
"custom_service_decl_channel_" << idx <<
" ok (byte 0x"
324 <<
toHex(
static_cast<uint64_t
>(sendVal)) <<
")\n";
341 esi_system::TypedFuncStruct mod(
findInst(accel,
"typed_func_struct_inst"));
342 auto c = mod.connect();
344 esi_system::StructArgs arg(0x1234,
static_cast<int8_t
>(-7));
345 esi_system::StructResult res = c->call(arg).get();
346 int8_t expectedX =
static_cast<int8_t
>(arg.b() + 1);
347 if (res.x() != expectedX || res.y() != arg.b())
348 throw std::runtime_error(
349 "typed_func_struct: wrong result (b=" + std::to_string(arg.b()) +
350 " x=" + std::to_string(res.x()) +
" y=" + std::to_string(res.y()) +
352 std::cout <<
"typed_func_struct ok (b=" << (int)arg.b()
353 <<
" -> x=" << (int)res.x() <<
" y=" << (int)res.y() <<
")\n";
361 esi_system::TypedFuncNestedStruct mod(
362 findInst(accel,
"typed_func_nested_struct_inst"));
363 auto c = mod.connect();
365 esi_system::OddStruct arg;
367 arg.b(
static_cast<int8_t
>(-17));
368 auto inner = arg.inner();
370 inner.q(
static_cast<int8_t
>(-7));
374 esi_system::OddStruct res = c->call(arg).get();
375 uint16_t expA =
static_cast<uint16_t
>(arg.a() + 1);
376 int8_t expB =
static_cast<int8_t
>(arg.b() - 3);
377 uint8_t expP =
static_cast<uint8_t
>(arg.inner().p() + 5);
378 int8_t expQ =
static_cast<int8_t
>(arg.inner().q() + 2);
379 uint8_t expR0 =
static_cast<uint8_t
>(arg.inner().r()[0] + 1);
380 uint8_t expR1 =
static_cast<uint8_t
>(arg.inner().r()[1] + 2);
381 if (res.a() != expA || res.b() != expB || res.inner().p() != expP ||
382 res.inner().q() != expQ || res.inner().r()[0] != expR0 ||
383 res.inner().r()[1] != expR1)
384 throw std::runtime_error(
"typed_func_nested_struct: result mismatch");
385 std::cout <<
"typed_func_nested_struct ok (a=" << res.a()
386 <<
" b=" << (int)res.b() <<
" p=" << (int)res.inner().p()
387 <<
" q=" << (int)res.inner().q() <<
" r=["
388 << (int)res.inner().r()[0] <<
"," << (int)res.inner().r()[1]
398 esi_system::TypedFuncSubByteSigned mod(
399 findInst(accel,
"typed_func_subbyte_signed_inst"));
400 auto c = mod.connect();
402 for (int8_t arg : {
static_cast<int8_t
>(5),
static_cast<int8_t
>(-3),
403 static_cast<int8_t
>(-8),
static_cast<int8_t
>(7)}) {
404 int8_t got = c->call(arg).get();
406 throw std::runtime_error(
407 "typed_func_subbyte_signed: arg=" + std::to_string(arg) +
408 " got=" + std::to_string(got));
410 std::cout <<
"typed_func_subbyte_signed ok (4 values)\n";
418 esi_system::TypedFuncArrayResult mod(
419 findInst(accel,
"typed_func_array_result_inst"));
420 auto c = mod.connect();
422 esi_system::TypedFuncArrayResult::callArgs arg{
static_cast<int8_t
>(-3)};
423 esi_system::ArrayResult res = c->call(arg).get();
426 int8_t expect0 = arg[0];
427 int8_t expect1 =
static_cast<int8_t
>(arg[0] + 1);
428 bool ok = (a == expect0 && b == expect1) || (a == expect1 && b == expect0);
430 throw std::runtime_error(
"typed_func_array_result: result mismatch");
431 std::cout <<
"typed_func_array_result ok ([" << (int)a <<
"," << (
int)b
443 esi_system::TypedFuncWindowedList mod(
444 findInst(accel,
"typed_func_windowed_list_inst"));
445 auto c = mod.connect();
447 using ArgT = esi_system::TypedFuncWindowedList::callArgs;
448 using ResT = esi_system::TypedFuncWindowedList::callResult;
449 std::vector<esi_system::TransformListItem> input;
450 for (uint32_t v : {3u, 5u, 7u, 9u, 11u})
451 input.emplace_back(v);
454 ResT result = c->call(arg).get();
456 if (result.data_count() != input.size())
457 throw std::runtime_error(
458 "typed_func_windowed_list: wrong result size (got " +
459 std::to_string(result.data_count()) +
")");
461 for (
const esi_system::TransformListItem &item : result.data()) {
462 uint32_t expected = input[i].v() + input[i].v();
463 if (item.v() != expected)
464 throw std::runtime_error(
"typed_func_windowed_list: element " +
465 std::to_string(i) +
" expected " +
466 std::to_string(expected) +
", got " +
467 std::to_string(item.v()));
470 std::cout <<
"typed_func_windowed_list ok (" << input.size()
471 <<
" items doubled)\n";
480 esi_system::ChannelWindowedListRead mod(
481 findInst(accel,
"channel_windowed_list_read_inst"));
482 auto c = mod.connect();
484 using WinT = esi_system::ChannelWindowedListRead::dataData;
488 c->trigger.write(0x10, 0u);
490 std::unique_ptr<WinT> got = c->data.read();
492 throw std::runtime_error(
"channel_windowed_list_read: null read result");
494 static constexpr uint16_t kTag = 0xCAFE;
495 static const uint32_t kExpected[] = {10u, 20u, 30u, 40u};
496 if (got->tag() != kTag)
497 throw std::runtime_error(
498 "channel_windowed_list_read: wrong tag, expected 0x" +
499 toHex(
static_cast<uint64_t
>(kTag)) +
" got 0x" +
500 toHex(
static_cast<uint64_t
>(got->tag())));
501 if (got->items_count() != 4)
502 throw std::runtime_error(
503 "channel_windowed_list_read: wrong item count, expected 4 got " +
504 std::to_string(got->items_count()));
506 for (uint32_t v : got->items()) {
507 if (v != kExpected[i])
508 throw std::runtime_error(
"channel_windowed_list_read: element " +
509 std::to_string(i) +
" expected " +
510 std::to_string(kExpected[i]) +
" got " +
514 std::cout <<
"channel_windowed_list_read ok (tag=0x"
515 <<
toHex(
static_cast<uint64_t
>(kTag)) <<
", items=[10,20,30,40])\n";
526 esi_system::ChannelWindowedListWrite mod(
527 findInst(accel,
"channel_windowed_list_write_inst"));
528 auto c = mod.connect();
530 using WinT = esi_system::ChannelWindowedListWrite::dataData;
532 static constexpr uint16_t kTag = 0xCAFE;
533 std::vector<uint32_t> items{10u, 20u, 30u, 40u};
534 c->data.write(WinT(kTag, items));
538 using clock = std::chrono::steady_clock;
539 auto deadline = clock::now() + std::chrono::seconds(5);
541 while (clock::now() < deadline) {
542 match = c->match.read(0);
545 std::this_thread::sleep_for(std::chrono::milliseconds(5));
548 throw std::runtime_error(
549 "channel_windowed_list_write: HW did not report a match within "
552 std::cout <<
"channel_windowed_list_write ok (tag=0x"
553 <<
toHex(
static_cast<uint64_t
>(kTag)) <<
", items=[10,20,30,40])\n";
564 esi_system::CallbackWindowedList mod(
565 findInst(accel,
"callback_windowed_list_inst"));
566 auto c = mod.connect();
568 using WinT = esi_system::CallbackWindowedList::callbackArgs;
570 std::atomic<bool> got_call(
false);
571 std::string error_msg;
572 std::mutex error_mtx;
573 c->callback.connect([&](
const WinT &arg) {
575 static constexpr uint16_t kTag = 0xCAFE;
576 static const uint32_t kExpected[] = {10u, 20u, 30u, 40u};
577 if (arg.tag() != kTag)
578 throw std::runtime_error(
579 "callback_windowed_list: wrong tag, expected 0x" +
580 toHex(
static_cast<uint64_t
>(kTag)) +
" got 0x" +
581 toHex(
static_cast<uint64_t
>(arg.tag())));
582 if (arg.items_count() != 4)
583 throw std::runtime_error(
584 "callback_windowed_list: wrong item count, expected 4 got " +
585 std::to_string(arg.items_count()));
587 for (uint32_t v : arg.items()) {
588 if (v != kExpected[i])
589 throw std::runtime_error(
"callback_windowed_list: element " +
590 std::to_string(i) +
" expected " +
591 std::to_string(kExpected[i]) +
" got " +
596 std::cout <<
"callback_windowed_list ok (tag=0x"
597 <<
toHex(
static_cast<uint64_t
>(kTag))
598 <<
", items=[10,20,30,40])\n";
599 }
catch (
const std::exception &e) {
600 std::lock_guard<std::mutex> lk(error_mtx);
601 error_msg = e.what();
603 got_call.store(
true, std::memory_order_release);
607 c->trigger.write(0x10, 0u);
609 using clock = std::chrono::steady_clock;
610 auto deadline = clock::now() + std::chrono::seconds(5);
611 while (!got_call.load(std::memory_order_acquire) && clock::now() < deadline)
612 std::this_thread::sleep_for(std::chrono::milliseconds(10));
613 if (!got_call.load(std::memory_order_acquire))
614 throw std::runtime_error(
615 "callback_windowed_list: callback did not fire within timeout");
616 std::lock_guard<std::mutex> lk(error_mtx);
617 if (!error_msg.empty())
618 throw std::runtime_error(error_msg);
624 "Per-port-kind coverage tests for ESI runtime + facade codegen. "
625 "Run a single probe with --probe NAME or run all probes (in registry "
626 "order) by omitting the flag.",
Top level accelerator class.
Represents either the top level or an instance of a hardware module.
const std::map< AppID, Instance * > & getChildren() const
Access the module's children by ID.
Strongly typed wrapper around a raw read channel.
std::unique_ptr< T > read()
Blocking typed read in polling mode.
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
Connect in polling mode.
void connect(const ChannelPort::ConnectOptions &opts={std::nullopt, false})
void write(const T &data)
std::string toHex(void *val)
#define ESI_PROBE_REGISTRY(name, description,...)
Convenience macro: defines main() with a probe registry.
static int runCustomServiceDeclChannel0(Accelerator *accel)
static int runTypedFuncWindowedList(Accelerator *accel)
static int runChannelWindowedListRead(Accelerator *accel)
static int runMmioReadWrite(Accelerator *accel)
static int runTypedReadChannelStruct(Accelerator *accel)
static int runTypedFuncVoidResult(Accelerator *accel)
static int runCustomServiceDeclChannel(Accelerator *accel, uint32_t idx)
static int runTypedFuncSubByteSigned(Accelerator *accel)
static esi::HWModule * findInst(Accelerator *accel, const char *appidName)
static int runCallServiceCallback(Accelerator *accel)
static int runTypedFuncArrayResult(Accelerator *accel)
static int runCallbackWindowedList(Accelerator *accel)
static int runTypedFuncMultiArg(Accelerator *accel)
static int runTelemetryMetric(Accelerator *accel)
static int runIndexedFuncGroup(Accelerator *accel)
static int runTypedFuncVoidArg(Accelerator *accel)
static int runTypedWriteChannelByte(Accelerator *accel)
static int runCustomServiceDeclChannel1(Accelerator *accel)
static int runTypedFuncNestedStruct(Accelerator *accel)
static int runTypedFuncStruct(Accelerator *accel)
static int runChannelWindowedListWrite(Accelerator *accel)