11#include "test_codegen/CallServiceCallback.h"
12#include "test_codegen/CallbackWindowedList.h"
13#include "test_codegen/ChannelMultiBurstListRead.h"
14#include "test_codegen/ChannelMultiBurstListWrite.h"
15#include "test_codegen/ChannelNarrowCountListWrite.h"
16#include "test_codegen/ChannelWindowedListRead.h"
17#include "test_codegen/ChannelWindowedListWrite.h"
18#include "test_codegen/CustomServiceDeclChannel.h"
19#include "test_codegen/IndexedFuncGroup.h"
20#include "test_codegen/MmioReadWrite.h"
21#include "test_codegen/TelemetryMetric.h"
22#include "test_codegen/TypedFuncArrayResult.h"
23#include "test_codegen/TypedFuncMultiArg.h"
24#include "test_codegen/TypedFuncNestedStruct.h"
25#include "test_codegen/TypedFuncStruct.h"
26#include "test_codegen/TypedFuncSubByteSigned.h"
27#include "test_codegen/TypedFuncVoidArg.h"
28#include "test_codegen/TypedFuncVoidResult.h"
29#include "test_codegen/TypedFuncWindowedList.h"
30#include "test_codegen/TypedReadChannelStruct.h"
31#include "test_codegen/TypedWriteChannelByte.h"
57 throw std::runtime_error(std::string(
"test_codegen instance '") +
58 appidName +
"' not found");
66 esi_system::TypedFuncMultiArg mod(
67 findInst(accel,
"typed_func_multi_arg_inst"));
68 auto c = mod.connect();
72 uint32_t got = c->call(7u, 6u).get();
74 throw std::runtime_error(
"typed_func_multi_arg: expected 42, got " +
76 std::cout <<
"typed_func_multi_arg ok\n";
84 esi_system::TypedFuncVoidArg mod(
findInst(accel,
"typed_func_void_arg_inst"));
85 auto c = mod.connect();
87 uint32_t got = c->call().get();
88 if (got != 0xCAFEF00Du)
89 throw std::runtime_error(
90 "typed_func_void_arg: expected 0xCAFEF00D, got 0x" +
toHex(got));
91 std::cout <<
"typed_func_void_arg ok\n";
99 esi_system::TypedFuncVoidResult mod(
100 findInst(accel,
"typed_func_void_result_inst"));
101 auto c = mod.connect();
106 c->call(esi_system::AckArgs(0x5A, 0x1234)).get();
107 std::cout <<
"typed_func_void_result ok\n";
115 esi_system::CallServiceCallback mod(
116 findInst(accel,
"call_service_callback_inst"));
117 auto c = mod.connect();
123 std::atomic<bool> got_call(
false);
124 esi_system::NotifyArgs seen{};
125 c->callback.connect([&](
const esi_system::NotifyArgs &a) {
127 got_call.store(
true, std::memory_order_release);
133 constexpr uint32_t kPayload = 0xDEADBEEFu;
134 c->trigger.write(0x10,
static_cast<uint64_t
>(kPayload));
137 using clock = std::chrono::steady_clock;
138 auto deadline = clock::now() + std::chrono::seconds(5);
139 while (!got_call.load(std::memory_order_acquire) && clock::now() < deadline)
140 std::this_thread::sleep_for(std::chrono::milliseconds(10));
141 if (!got_call.load(std::memory_order_acquire))
142 throw std::runtime_error(
143 "call_service_callback: callback did not fire within timeout");
145 if (seen.tag() != 0xA5)
146 throw std::runtime_error(
147 "call_service_callback: wrong tag, expected 0xA5 got 0x" +
148 toHex(
static_cast<uint64_t
>(seen.tag())));
149 if (seen.payload() != kPayload)
150 throw std::runtime_error(
151 "call_service_callback: wrong payload, expected 0x" +
toHex(kPayload) +
152 " got 0x" +
toHex(seen.payload()));
153 std::cout <<
"call_service_callback ok\n";
161 esi_system::TypedReadChannelStruct mod(
162 findInst(accel,
"typed_read_channel_struct_inst"));
163 auto c = mod.connect();
166 constexpr size_t kNum = esi_system::TypedReadChannelStruct::num_events;
167 for (
size_t i = 1; i <= kNum; ++i) {
168 auto ev = c->data.read();
170 throw std::runtime_error(
171 "typed_read_channel_struct: null read result at i=" +
174 throw std::runtime_error(
175 "typed_read_channel_struct: wrong ts at i=" + std::to_string(i) +
176 ", got " + std::to_string(ev->ts()));
177 int32_t expected = -
static_cast<int32_t
>(i);
178 if (ev->val() != expected)
179 throw std::runtime_error(
180 "typed_read_channel_struct: wrong val at i=" + std::to_string(i) +
181 ", got " + std::to_string(ev->val()));
183 std::cout <<
"typed_read_channel_struct ok (" << kNum <<
" events)\n";
191 esi_system::TypedWriteChannelByte mod(
192 findInst(accel,
"typed_write_channel_byte_inst"));
193 auto c = mod.connect();
198 static constexpr uint8_t kBytes[] = {0x11, 0x22, 0x44, 0x88, 0x10, 0x55};
199 uint8_t expected = 0;
200 for (uint8_t b : kBytes) {
207 using clock = std::chrono::steady_clock;
208 auto deadline = clock::now() + std::chrono::seconds(2);
210 while (clock::now() < deadline) {
211 uint64_t resp = c->accumulator.read(0);
212 got =
static_cast<uint8_t
>(resp & 0xff);
215 std::this_thread::sleep_for(std::chrono::milliseconds(5));
218 throw std::runtime_error(
219 "typed_write_channel_byte: accumulator mismatch (expected 0x" +
220 toHex(
static_cast<uint64_t
>(expected)) +
", got 0x" +
221 toHex(
static_cast<uint64_t
>(got)) +
")");
222 std::cout <<
"typed_write_channel_byte ok (acc=0x"
223 <<
toHex(
static_cast<uint64_t
>(expected)) <<
")\n";
231 esi_system::MmioReadWrite mod(
findInst(accel,
"mmio_read_write_inst"));
232 auto c = mod.connect();
236 constexpr uint64_t kToken = 0xA5A51234'56789ABCULL;
237 c->region.write(0x10, kToken);
238 uint64_t got = c->region.read(0x10);
240 throw std::runtime_error(
"mmio_read_write: round-trip mismatch (wrote 0x" +
241 toHex(kToken) +
", read 0x" +
toHex(got) +
")");
242 std::cout <<
"mmio_read_write ok (round-trip 0x" <<
toHex(kToken) <<
")\n";
250 esi_system::TelemetryMetric mod(
findInst(accel,
"telemetry_metric_inst"));
251 auto c = mod.connect();
253 uint64_t first = c->cycleCount.readInt();
256 std::this_thread::sleep_for(std::chrono::milliseconds(50));
257 uint64_t second = c->cycleCount.readInt();
260 throw std::runtime_error(
261 "telemetry_metric: counter did not advance (first=" +
262 std::to_string(first) +
", second=" + std::to_string(second) +
")");
263 std::cout <<
"telemetry_metric ok (advanced by " << (second - first) <<
")\n";
275 esi_system::IndexedFuncGroup mod(
findInst(accel,
"indexed_func_group_inst"));
276 auto c = mod.connect();
277 constexpr size_t kN = esi_system::IndexedFuncGroup::num_entries;
278 for (uint32_t idx = 0; idx < kN; ++idx) {
279 constexpr uint16_t kArg = 100;
280 uint16_t got = c->call[idx](kArg).get();
281 uint16_t expected =
static_cast<uint16_t
>(kArg + (idx + 1));
283 throw std::runtime_error(
"indexed_func_group[" + std::to_string(idx) +
284 "]: expected " + std::to_string(expected) +
285 ", got " + std::to_string(got));
287 std::cout <<
"indexed_func_group ok (" << kN <<
" entries)\n";
303 throw std::runtime_error(
"custom_service_decl_channel[" +
304 std::to_string(idx) +
"]: instance not found");
305 esi_system::CustomServiceDeclChannel mod(it->second);
306 auto c = mod.connect();
316 uint8_t sendVal =
static_cast<uint8_t
>(0x40 + idx);
318 std::unique_ptr<uint8_t> got = fromHw.
read();
319 if (!got || *got != sendVal)
320 throw std::runtime_error(
321 "custom_service_decl_channel[" + std::to_string(idx) +
322 "]: byte loopback mismatch (sent 0x" +
323 toHex(
static_cast<uint64_t
>(sendVal)) +
", got 0x" +
324 toHex(
static_cast<uint64_t
>(got ? *got : 0u)) +
")");
326 std::cout <<
"custom_service_decl_channel_" << idx <<
" ok (byte 0x"
327 <<
toHex(
static_cast<uint64_t
>(sendVal)) <<
")\n";
344 esi_system::TypedFuncStruct mod(
findInst(accel,
"typed_func_struct_inst"));
345 auto c = mod.connect();
347 esi_system::StructArgs arg(0x1234,
static_cast<int8_t
>(-7));
348 esi_system::StructResult res = c->call(arg).get();
349 int8_t expectedX =
static_cast<int8_t
>(arg.b() + 1);
350 if (res.x() != expectedX || res.y() != arg.b())
351 throw std::runtime_error(
352 "typed_func_struct: wrong result (b=" + std::to_string(arg.b()) +
353 " x=" + std::to_string(res.x()) +
" y=" + std::to_string(res.y()) +
355 std::cout <<
"typed_func_struct ok (b=" << (int)arg.b()
356 <<
" -> x=" << (int)res.x() <<
" y=" << (int)res.y() <<
")\n";
364 esi_system::TypedFuncNestedStruct mod(
365 findInst(accel,
"typed_func_nested_struct_inst"));
366 auto c = mod.connect();
368 esi_system::OddStruct arg;
370 arg.b(
static_cast<int8_t
>(-17));
371 auto inner = arg.inner();
373 inner.q(
static_cast<int8_t
>(-7));
377 esi_system::OddStruct res = c->call(arg).get();
378 uint16_t expA =
static_cast<uint16_t
>(arg.a() + 1);
379 int8_t expB =
static_cast<int8_t
>(arg.b() - 3);
380 uint8_t expP =
static_cast<uint8_t
>(arg.inner().p() + 5);
381 int8_t expQ =
static_cast<int8_t
>(arg.inner().q() + 2);
382 uint8_t expR0 =
static_cast<uint8_t
>(arg.inner().r()[0] + 1);
383 uint8_t expR1 =
static_cast<uint8_t
>(arg.inner().r()[1] + 2);
384 if (res.a() != expA || res.b() != expB || res.inner().p() != expP ||
385 res.inner().q() != expQ || res.inner().r()[0] != expR0 ||
386 res.inner().r()[1] != expR1)
387 throw std::runtime_error(
"typed_func_nested_struct: result mismatch");
388 std::cout <<
"typed_func_nested_struct ok (a=" << res.a()
389 <<
" b=" << (int)res.b() <<
" p=" << (int)res.inner().p()
390 <<
" q=" << (int)res.inner().q() <<
" r=["
391 << (int)res.inner().r()[0] <<
"," << (int)res.inner().r()[1]
401 esi_system::TypedFuncSubByteSigned mod(
402 findInst(accel,
"typed_func_subbyte_signed_inst"));
403 auto c = mod.connect();
405 for (int8_t arg : {
static_cast<int8_t
>(5),
static_cast<int8_t
>(-3),
406 static_cast<int8_t
>(-8),
static_cast<int8_t
>(7)}) {
407 int8_t got = c->call(arg).get();
409 throw std::runtime_error(
410 "typed_func_subbyte_signed: arg=" + std::to_string(arg) +
411 " got=" + std::to_string(got));
413 std::cout <<
"typed_func_subbyte_signed ok (4 values)\n";
421 esi_system::TypedFuncArrayResult mod(
422 findInst(accel,
"typed_func_array_result_inst"));
423 auto c = mod.connect();
425 esi_system::TypedFuncArrayResult::callArgs arg{
static_cast<int8_t
>(-3)};
426 esi_system::ArrayResult res = c->call(arg).get();
429 int8_t expect0 = arg[0];
430 int8_t expect1 =
static_cast<int8_t
>(arg[0] + 1);
431 bool ok = (a == expect0 && b == expect1) || (a == expect1 && b == expect0);
433 throw std::runtime_error(
"typed_func_array_result: result mismatch");
434 std::cout <<
"typed_func_array_result ok ([" << (int)a <<
"," << (
int)b
446 esi_system::TypedFuncWindowedList mod(
447 findInst(accel,
"typed_func_windowed_list_inst"));
448 auto c = mod.connect();
450 using ArgT = esi_system::TypedFuncWindowedList::callArgs;
451 using ResT = esi_system::TypedFuncWindowedList::callResult;
452 std::vector<esi_system::TransformListItem> input;
453 for (uint32_t v : {3u, 5u, 7u, 9u, 11u})
454 input.emplace_back(v);
457 ResT result = c->call(arg).get();
459 if (result.data_count() != input.size())
460 throw std::runtime_error(
461 "typed_func_windowed_list: wrong result size (got " +
462 std::to_string(result.data_count()) +
")");
464 for (
const esi_system::TransformListItem &item : result.data()) {
465 uint32_t expected = input[i].v() + input[i].v();
466 if (item.v() != expected)
467 throw std::runtime_error(
"typed_func_windowed_list: element " +
468 std::to_string(i) +
" expected " +
469 std::to_string(expected) +
", got " +
470 std::to_string(item.v()));
473 std::cout <<
"typed_func_windowed_list ok (" << input.size()
474 <<
" items doubled)\n";
483 esi_system::ChannelWindowedListRead mod(
484 findInst(accel,
"channel_windowed_list_read_inst"));
485 auto c = mod.connect();
487 using WinT = esi_system::ChannelWindowedListRead::dataData;
491 c->trigger.write(0x10, 0u);
493 std::unique_ptr<WinT> got = c->data.read();
495 throw std::runtime_error(
"channel_windowed_list_read: null read result");
497 static constexpr uint16_t kTag = 0xCAFE;
498 static const uint32_t kExpected[] = {10u, 20u, 30u, 40u};
499 if (got->tag() != kTag)
500 throw std::runtime_error(
501 "channel_windowed_list_read: wrong tag, expected 0x" +
502 toHex(
static_cast<uint64_t
>(kTag)) +
" got 0x" +
503 toHex(
static_cast<uint64_t
>(got->tag())));
504 if (got->items_count() != 4)
505 throw std::runtime_error(
506 "channel_windowed_list_read: wrong item count, expected 4 got " +
507 std::to_string(got->items_count()));
509 for (uint32_t v : got->items()) {
510 if (v != kExpected[i])
511 throw std::runtime_error(
"channel_windowed_list_read: element " +
512 std::to_string(i) +
" expected " +
513 std::to_string(kExpected[i]) +
" got " +
517 std::cout <<
"channel_windowed_list_read ok (tag=0x"
518 <<
toHex(
static_cast<uint64_t
>(kTag)) <<
", items=[10,20,30,40])\n";
529 esi_system::ChannelMultiBurstListRead mod(
530 findInst(accel,
"channel_multiburst_list_read_inst"));
531 auto c = mod.connect();
533 using WinT = esi_system::ChannelMultiBurstListRead::dataData;
536 c->trigger.write(0x10, 0u);
538 std::unique_ptr<WinT> got = c->data.read();
540 throw std::runtime_error(
"channel_multiburst_list_read: null read result");
544 static constexpr uint16_t kTag = 0xF00D;
545 static constexpr size_t kNumItems = 10;
546 if (got->tag() != kTag)
547 throw std::runtime_error(
548 "channel_multiburst_list_read: wrong tag, expected 0x" +
549 toHex(
static_cast<uint64_t
>(kTag)) +
" got 0x" +
550 toHex(
static_cast<uint64_t
>(got->tag())));
551 if (got->items_count() != kNumItems)
552 throw std::runtime_error(
553 "channel_multiburst_list_read: wrong item count, expected " +
554 std::to_string(kNumItems) +
" got " +
555 std::to_string(got->items_count()));
557 for (uint32_t v : got->items()) {
558 uint32_t expected = 0x1000u +
static_cast<uint32_t
>(i);
560 throw std::runtime_error(
"channel_multiburst_list_read: element " +
561 std::to_string(i) +
" expected 0x" +
565 std::cout <<
"channel_multiburst_list_read ok (10 items reassembled from 3 "
577 esi_system::ChannelWindowedListWrite mod(
578 findInst(accel,
"channel_windowed_list_write_inst"));
579 auto c = mod.connect();
581 using WinT = esi_system::ChannelWindowedListWrite::dataData;
583 static constexpr uint16_t kTag = 0xCAFE;
584 std::vector<uint32_t> items{10u, 20u, 30u, 40u};
585 c->data.write(WinT(kTag, items));
589 using clock = std::chrono::steady_clock;
590 auto deadline = clock::now() + std::chrono::seconds(5);
592 while (clock::now() < deadline) {
593 match = c->match.read(0);
596 std::this_thread::sleep_for(std::chrono::milliseconds(5));
599 throw std::runtime_error(
600 "channel_windowed_list_write: HW did not report a match within "
603 std::cout <<
"channel_windowed_list_write ok (tag=0x"
604 <<
toHex(
static_cast<uint64_t
>(kTag)) <<
", items=[10,20,30,40])\n";
616 esi_system::ChannelMultiBurstListWrite mod(
617 findInst(accel,
"channel_multiburst_list_write_inst"));
618 auto c = mod.connect();
620 using WinT = esi_system::ChannelMultiBurstListWrite::dataData;
624 std::vector<uint8_t> items;
626 for (
int v = 0; v < 256; ++v)
627 items.push_back(
static_cast<uint8_t
>(v));
628 c->data.write(WinT(items));
632 using clock = std::chrono::steady_clock;
633 auto deadline = clock::now() + std::chrono::seconds(5);
635 while (clock::now() < deadline) {
636 match = c->match.read(0);
639 std::this_thread::sleep_for(std::chrono::milliseconds(5));
642 throw std::runtime_error(
643 "channel_multiburst_list_write: HW did not report a match within "
646 std::cout <<
"channel_multiburst_list_write ok (256 items split across 2 "
662 esi_system::ChannelNarrowCountListWrite mod(
663 findInst(accel,
"channel_narrow_count_list_write_inst"));
664 auto c = mod.connect();
666 using WinT = esi_system::ChannelNarrowCountListWrite::dataData;
668 static constexpr uint16_t kTag = 0xBEEF;
669 std::vector<uint32_t> items{0x1000u, 0x1001u, 0x1002u, 0x1003u,
670 0x1004u, 0x1005u, 0x1006u};
671 c->data.write(WinT(kTag, items));
675 using clock = std::chrono::steady_clock;
676 auto deadline = clock::now() + std::chrono::seconds(5);
678 while (clock::now() < deadline) {
679 match = c->match.read(0);
682 std::this_thread::sleep_for(std::chrono::milliseconds(5));
685 throw std::runtime_error(
686 "channel_narrow_count_list_write: HW did not report a match within "
689 std::cout <<
"channel_narrow_count_list_write ok (2-bit count, tag=0x"
690 <<
toHex(
static_cast<uint64_t
>(kTag))
691 <<
", 7 items split across 3 bursts)\n";
702 esi_system::CallbackWindowedList mod(
703 findInst(accel,
"callback_windowed_list_inst"));
704 auto c = mod.connect();
706 using WinT = esi_system::CallbackWindowedList::callbackArgs;
708 std::atomic<bool> got_call(
false);
709 std::string error_msg;
710 std::mutex error_mtx;
711 c->callback.connect([&](
const WinT &arg) {
713 static constexpr uint16_t kTag = 0xCAFE;
714 static const uint32_t kExpected[] = {10u, 20u, 30u, 40u};
715 if (arg.tag() != kTag)
716 throw std::runtime_error(
717 "callback_windowed_list: wrong tag, expected 0x" +
718 toHex(
static_cast<uint64_t
>(kTag)) +
" got 0x" +
719 toHex(
static_cast<uint64_t
>(arg.tag())));
720 if (arg.items_count() != 4)
721 throw std::runtime_error(
722 "callback_windowed_list: wrong item count, expected 4 got " +
723 std::to_string(arg.items_count()));
725 for (uint32_t v : arg.items()) {
726 if (v != kExpected[i])
727 throw std::runtime_error(
"callback_windowed_list: element " +
728 std::to_string(i) +
" expected " +
729 std::to_string(kExpected[i]) +
" got " +
734 std::cout <<
"callback_windowed_list ok (tag=0x"
735 <<
toHex(
static_cast<uint64_t
>(kTag))
736 <<
", items=[10,20,30,40])\n";
737 }
catch (
const std::exception &e) {
738 std::lock_guard<std::mutex> lk(error_mtx);
739 error_msg = e.what();
741 got_call.store(
true, std::memory_order_release);
745 c->trigger.write(0x10, 0u);
747 using clock = std::chrono::steady_clock;
748 auto deadline = clock::now() + std::chrono::seconds(5);
749 while (!got_call.load(std::memory_order_acquire) && clock::now() < deadline)
750 std::this_thread::sleep_for(std::chrono::milliseconds(10));
751 if (!got_call.load(std::memory_order_acquire))
752 throw std::runtime_error(
753 "callback_windowed_list: callback did not fire within timeout");
754 std::lock_guard<std::mutex> lk(error_mtx);
755 if (!error_msg.empty())
756 throw std::runtime_error(error_msg);
762 "Per-port-kind coverage tests for ESI runtime + facade codegen. "
763 "Run a single probe with --probe NAME or run all probes (in registry "
764 "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 runChannelMultiBurstListWrite(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 runChannelMultiBurstListRead(Accelerator *accel)
static int runChannelNarrowCountListWrite(Accelerator *accel)
static int runCustomServiceDeclChannel1(Accelerator *accel)
static int runTypedFuncNestedStruct(Accelerator *accel)
static int runTypedFuncStruct(Accelerator *accel)
static int runChannelWindowedListWrite(Accelerator *accel)