CIRCT 23.0.0git
Loading...
Searching...
No Matches
ESIRuntimeTest.cpp
Go to the documentation of this file.
1//===- ESIRuntimeTest.cpp - ESI Runtime Type System Tests ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "esi/Types.h"
10#include "esi/Values.h"
11#include "gtest/gtest.h"
12#include <any>
13#include <cstdint>
14#include <map>
15#include <vector>
16
17using namespace esi;
18
19namespace {
20
21// Test VoidType serialization and deserialization
22TEST(ESITypesTest, VoidTypeSerialization) {
23 VoidType voidType("void");
24
25 // Test valid void value (empty std::any)
26 std::any voidValue;
27 EXPECT_NO_THROW(voidType.ensureValid(voidValue));
28
29 // Test valid void value (nullptr)
30 std::any nullptrValue = std::any(nullptr);
31 EXPECT_NO_THROW(voidType.ensureValid(nullptrValue));
32
33 // Test invalid void value
34 std::any invalidValue = std::any(42);
35 EXPECT_THROW(voidType.ensureValid(invalidValue), std::runtime_error);
36
37 // Void carries no logical data, so serialize produces zero bits.
38 // Transports (DMA, cosim, etc.) that require a non-empty message add
39 // their own placeholder byte; that pad/strip lives in the channel-port
40 // base classes (WriteChannelPort::maybePadEmptyMessage /
41 // ReadChannelPort::invokeCallback), not at the type-serialization layer.
42 EXPECT_EQ(voidType.getBitWidth(), 0)
43 << "VoidType should report a 0-bit logical width";
44 auto serialized = voidType.serialize(voidValue);
45 EXPECT_EQ(serialized.size(), 0UL)
46 << "VoidType serialization should produce zero bits";
47
48 // Test deserialization consumes nothing.
49 std::vector<uint8_t> empty;
51 auto deserialized = voidType.deserialize(v);
52 EXPECT_FALSE(deserialized.has_value())
53 << "VoidType deserialization should not have a value";
54 EXPECT_EQ(v.width(), 0UL)
55 << "VoidType deserialization should consume no data";
56}
57
58// Test BitsType serialization and deserialization
59TEST(ESITypesTest, BitsTypeSerialization) {
60 BitsType bitsType("bits8", 8);
61
62 // Test valid bits value
63 std::vector<uint8_t> bitsValue = {0xAB};
64 std::any validBits = std::any(bitsValue);
65 EXPECT_NO_THROW(bitsType.ensureValid(validBits));
66
67 // Test invalid size
68 std::vector<uint8_t> wrongSize = {0xAB, 0xCD};
69 std::any invalidBits = std::any(wrongSize);
70 EXPECT_THROW(bitsType.ensureValid(invalidBits), std::runtime_error);
71
72 // Test serialization
73 MessageData serialized(bitsType.serialize(validBits).takeStorage());
74 EXPECT_EQ(serialized.getSize(), 1UL)
75 << "BitsType(8) serialization should produce exactly 1 byte";
76 EXPECT_EQ(serialized.getData()[0], 0xAB)
77 << "BitsType serialization should preserve the input byte value";
78
79 // Test deserialization
80 BitVector serializedBits(serialized.getData());
81 auto deserialized = bitsType.deserialize(serializedBits);
82 auto deserializedBits = std::any_cast<std::vector<uint8_t>>(deserialized);
83 EXPECT_EQ(deserializedBits.size(), 1UL)
84 << "BitsType(8) deserialization should produce 1 byte";
85 EXPECT_EQ(deserializedBits[0], 0xAB)
86 << "BitsType deserialization should preserve the original value";
87 EXPECT_EQ(serializedBits.size(), 0UL)
88 << "BitsType deserialization should consume all data";
89}
90
91// Test UIntType serialization and deserialization
92TEST(ESITypesTest, UIntTypeSerialization) {
93 UIntType uintType("uint16", 16);
94
95 // Test valid uint value
96 uint64_t uintValue = 0x1234;
97 std::any validUInt = std::any(uintValue);
98 EXPECT_NO_THROW(uintType.ensureValid(validUInt));
99
100 // Test out of range value
101 uint64_t outOfRange = 0x10000; // Too big for 16-bit
102 std::any invalidUInt = std::any(outOfRange);
103 EXPECT_THROW(uintType.ensureValid(invalidUInt), std::runtime_error);
104
105 // Test serialization (little-endian)
106 MessageData serialized(uintType.serialize(validUInt).takeStorage());
107 EXPECT_EQ(serialized.getSize(), 2UL)
108 << "UIntType(16) serialization should produce exactly 2 bytes";
109 EXPECT_EQ(serialized.getData()[0], 0x34)
110 << "UIntType serialization low byte should be 0x34 (little-endian)";
111 EXPECT_EQ(serialized.getData()[1], 0x12)
112 << "UIntType serialization high byte should be 0x12 (little-endian)";
113
114 // Test deserialization
115 BitVector serializedBits(serialized.getData());
116 auto deserialized = uintType.deserialize(serializedBits);
117 auto deserializedUInt =
118 static_cast<uint16_t>(std::any_cast<UInt>(deserialized));
119 EXPECT_EQ(deserializedUInt, 0x1234)
120 << "UIntType deserialization should reconstruct original value 0x1234";
121 EXPECT_EQ(serializedBits.size(), 0UL)
122 << "UIntType deserialization should consume all data";
123
124 // Test that different input types work (uint8_t, uint16_t, uint32_t)
125 uint8_t smallVal = 42;
126 uint16_t mediumVal = 1000;
127 uint32_t largeVal = 50000;
128
129 EXPECT_NO_THROW(uintType.ensureValid(std::any(smallVal)));
130 EXPECT_NO_THROW(uintType.ensureValid(std::any(mediumVal)));
131 EXPECT_NO_THROW(uintType.ensureValid(std::any(largeVal)));
132}
133
134// Test SIntType serialization and deserialization
135TEST(ESITypesTest, SIntTypeSerialization) {
136 SIntType sintType("sint16", 16);
137
138 // Test valid positive sint value
139 int64_t positiveValue = 0x1234;
140 std::any validSInt = std::any(positiveValue);
141 EXPECT_NO_THROW(sintType.ensureValid(validSInt));
142
143 // Test valid negative sint value
144 int64_t negativeValue = -1000;
145 std::any validNegSInt = std::any(negativeValue);
146 EXPECT_NO_THROW(sintType.ensureValid(validNegSInt));
147
148 // Test serialization of positive value
149 MessageData serialized(sintType.serialize(validSInt).takeStorage());
150 EXPECT_EQ(serialized.getSize(), 2UL)
151 << "SIntType(16) serialization should produce exactly 2 bytes";
152 EXPECT_EQ(serialized.getData()[0], 0x34)
153 << "SIntType serialization low byte should be 0x34 (little-endian)";
154 EXPECT_EQ(serialized.getData()[1], 0x12)
155 << "SIntType serialization high byte should be 0x12 (little-endian)";
156
157 // Test deserialization
158 BitVector serializedBits(serialized.getData());
159 auto deserialized = sintType.deserialize(serializedBits);
160 auto deserializedSInt =
161 static_cast<int16_t>(std::any_cast<Int>(deserialized));
162 EXPECT_EQ(deserializedSInt, 0x1234)
163 << "SIntType deserialization should reconstruct original positive value";
164 EXPECT_EQ(serializedBits.size(), 0UL)
165 << "SIntType deserialization should consume all data";
166
167 // Test negative value serialization/deserialization
168 MessageData negSerialized(sintType.serialize(validNegSInt).takeStorage());
169 EXPECT_EQ(negSerialized.getSize(), 2UL)
170 << "SIntType(16) negative value should serialize to 2 bytes";
171 // -1000 in 16-bit two's complement: 0xFC18
172 EXPECT_EQ(negSerialized.getData()[0], 0x18)
173 << "SIntType negative serialization low byte should be 0x18 "
174 "(little-endian)";
175 EXPECT_EQ(negSerialized.getData()[1], 0xFC)
176 << "SIntType negative serialization high byte should be 0xFC "
177 "(little-endian)";
178
179 BitVector negSerializedBits(negSerialized.getData());
180 auto negDeserialized = sintType.deserialize(negSerializedBits);
181 auto deserializedNegSInt =
182 static_cast<int16_t>(std::any_cast<Int>(negDeserialized));
183 EXPECT_EQ(deserializedNegSInt, -1000)
184 << "SIntType deserialization should reconstruct original negative value "
185 "(-1000)";
186
187 // Test that different input types work (int8_t, int16_t, int32_t)
188 int8_t smallVal = -42;
189 int16_t mediumVal = -1000;
190 int32_t largeVal = -30000;
191
192 EXPECT_NO_THROW(sintType.ensureValid(std::any(smallVal)));
193 EXPECT_NO_THROW(sintType.ensureValid(std::any(mediumVal)));
194 EXPECT_NO_THROW(sintType.ensureValid(std::any(largeVal)));
195}
196
197// Test SIntType sign extension logic comprehensively
198TEST(ESITypesTest, SIntTypeSignExtension) {
199 // Test 8-bit signed integers
200 SIntType sint8("sint8", 8);
201
202 // Test -1 (all bits set in 8-bit: 0xFF)
203 int64_t minusOne = -1;
204 MessageData serializedMinusOne(
205 sint8.serialize(std::any(minusOne)).takeStorage());
206 EXPECT_EQ(serializedMinusOne.getSize(), 1UL)
207 << "SIntType(8) serialization of -1 should produce 1 byte";
208 EXPECT_EQ(serializedMinusOne.getData()[0], 0xFF)
209 << "SIntType(8) serialization of -1 should be 0xFF (all bits set)";
210
211 BitVector serializedMinusOneBits(serializedMinusOne.getData());
212 auto deserializedMinusOne = sint8.deserialize(serializedMinusOneBits);
213 auto resultMinusOne =
214 static_cast<int8_t>(std::any_cast<Int>(deserializedMinusOne));
215 EXPECT_EQ(resultMinusOne, -1)
216 << "SIntType(8) deserialization of 0xFF should reconstruct -1";
217
218 // Test maximum negative value for 8-bit (-128 = 0x80)
219 int64_t maxNeg8 = -128;
220 MessageData serializedMaxNeg(
221 sint8.serialize(std::any(maxNeg8)).takeStorage());
222 EXPECT_EQ(serializedMaxNeg.getSize(), 1UL)
223 << "SIntType(8) serialization of -128 should produce 1 byte";
224 EXPECT_EQ(serializedMaxNeg.getData()[0], 0x80)
225 << "SIntType(8) serialization of -128 should be 0x80";
226
227 BitVector serializedMaxNegBits(serializedMaxNeg.getData());
228 auto deserializedMaxNeg = sint8.deserialize(serializedMaxNegBits);
229 auto resultMaxNeg =
230 static_cast<int8_t>(std::any_cast<Int>(deserializedMaxNeg));
231 EXPECT_EQ(resultMaxNeg, -128) << "SIntType(8) deserialization should "
232 "reconstruct maximum negative value (-128)";
233
234 // Test maximum positive value for 8-bit (127 = 0x7F)
235 int64_t maxPos8 = 127;
236 MessageData serializedMaxPos(
237 sint8.serialize(std::any(maxPos8)).takeStorage());
238 EXPECT_EQ(serializedMaxPos.getSize(), 1UL)
239 << "SIntType(8) serialization of 127 should produce 1 byte";
240 EXPECT_EQ(serializedMaxPos.getData()[0], 0x7F)
241 << "SIntType(8) serialization of 127 should be 0x7F";
242
243 BitVector serializedMaxPosBits(serializedMaxPos.getData());
244 auto deserializedMaxPos = sint8.deserialize(serializedMaxPosBits);
245 auto resultMaxPos =
246 static_cast<int8_t>(std::any_cast<Int>(deserializedMaxPos));
247 EXPECT_EQ(resultMaxPos, 127) << "SIntType(8) deserialization should "
248 "reconstruct maximum positive value (127)";
249
250 // Test 4-bit signed integers (edge case for smaller widths)
251 SIntType sint4("sint4", 4);
252
253 // Test -1 in 4-bit (0x0F in the lower nibble, should sign extend to all 1s)
254 int64_t minus1w4bit = -1;
255 MessageData serialized4bit(
256 sint4.serialize(std::any(minus1w4bit)).takeStorage());
257 EXPECT_EQ(serialized4bit.getSize(), 1UL)
258 << "SIntType(4) serialization should produce 1 byte";
259 EXPECT_EQ(serialized4bit.getData()[0] & 0x0F, 0x0F)
260 << "SIntType(4) serialization of -1 should have lower 4 bits set to "
261 "1111";
262
263 BitVector serialized4bitBits(serialized4bit.getData());
264 auto deserialized4bit = sint4.deserialize(serialized4bitBits);
265 auto result4bit = static_cast<int8_t>(std::any_cast<Int>(deserialized4bit));
266 EXPECT_EQ(result4bit, -1)
267 << "SIntType(4) deserialization should sign-extend -1 correctly";
268
269 // Test maximum negative for 4-bit (-8 = 0x8 in 4 bits)
270 int64_t maxNeg4 = -8;
271 MessageData serializedMaxNeg4(
272 sint4.serialize(std::any(maxNeg4)).takeStorage());
273 BitVector serializedMaxNeg4Bits(serializedMaxNeg4.getData());
274 auto deserializedMaxNeg4 = sint4.deserialize(serializedMaxNeg4Bits);
275 auto resultMaxNeg4 =
276 static_cast<int8_t>(std::any_cast<Int>(deserializedMaxNeg4));
277 EXPECT_EQ(resultMaxNeg4, -8)
278 << "SIntType(4) should handle maximum negative value (-8) correctly";
279
280 // Test maximum positive for 4-bit (7 = 0x7 in 4 bits)
281 int64_t maxPos4 = 7;
282 MessageData serializedMaxPos4(
283 sint4.serialize(std::any(maxPos4)).takeStorage());
284 BitVector serializedMaxPos4Bits(serializedMaxPos4.getData());
285 auto deserializedMaxPos4 = sint4.deserialize(serializedMaxPos4Bits);
286 auto resultMaxPos4 =
287 static_cast<int8_t>(std::any_cast<Int>(deserializedMaxPos4));
288 EXPECT_EQ(resultMaxPos4, 7)
289 << "SIntType(4) should handle maximum positive value (7) correctly";
290
291 // Test 12-bit signed integers (non-byte-aligned case)
292 SIntType sint12("sint12", 12);
293
294 // Test -1 in 12-bit (should be 0xFFF in lower 12 bits)
295 int64_t minus1w12bit = -1;
296 MessageData serialized12bit(
297 sint12.serialize(std::any(minus1w12bit)).takeStorage());
298 EXPECT_EQ(serialized12bit.getSize(), 2UL)
299 << "SIntType(12) serialization should produce 2 bytes (12 bits = 2 "
300 "bytes)";
301 EXPECT_EQ(serialized12bit.getData()[0], 0xFF)
302 << "SIntType(12) serialization of -1 should have lower byte 0xFF";
303 EXPECT_EQ(serialized12bit.getData()[1] & 0x0F, 0x0F)
304 << "SIntType(12) serialization of -1 should have upper nibble 0x0F";
305
306 BitVector serialized12bitBits(serialized12bit.getData());
307 auto deserialized12bit = sint12.deserialize(serialized12bitBits);
308 auto result12bit =
309 static_cast<int16_t>(std::any_cast<Int>(deserialized12bit));
310 EXPECT_EQ(result12bit, -1)
311 << "SIntType(12) deserialization should sign-extend -1 correctly";
312
313 // Test a value that requires sign extension: -100 in 12-bit
314 int64_t neg100w12bit = -100;
315 MessageData serializedNeg100(
316 sint12.serialize(std::any(neg100w12bit)).takeStorage());
317 BitVector serializedNeg100Bits(serializedNeg100.getData());
318 auto deserializedNeg100 = sint12.deserialize(serializedNeg100Bits);
319 auto resultNeg100 =
320 static_cast<int16_t>(std::any_cast<Int>(deserializedNeg100));
321 EXPECT_EQ(resultNeg100, -100)
322 << "SIntType(12) should correctly handle sign extension for -100";
323}
324
325// Test boundary conditions for sign extension
326TEST(ESITypesTest, SIntTypeSignExtensionBoundaries) {
327 // Test various bit widths to ensure sign extension works correctly
328 for (int width = 1; width <= 16; ++width) {
329 SIntType sintType("sint" + std::to_string(width), width);
330
331 // Calculate the range for this bit width
332 int64_t maxVal = (width == 64) ? INT64_MAX : ((1LL << (width - 1)) - 1);
333 int64_t minVal = (width == 64) ? INT64_MIN : (-(1LL << (width - 1)));
334
335 // Test maximum positive value
336 MessageData serializedMax(
337 sintType.serialize(std::any(maxVal)).takeStorage());
338 BitVector serializedMaxBits(serializedMax.getData());
339 auto deserializedMax = sintType.deserialize(serializedMaxBits);
340
341 // Cast to appropriate type based on width
342 if (width <= 8) {
343 auto resultMax = static_cast<int8_t>(std::any_cast<Int>(deserializedMax));
344 EXPECT_EQ(resultMax, static_cast<int8_t>(maxVal))
345 << "Failed for width " << width << " max value";
346 } else if (width <= 16) {
347 auto resultMax =
348 static_cast<int16_t>(std::any_cast<Int>(deserializedMax));
349 EXPECT_EQ(resultMax, static_cast<int16_t>(maxVal))
350 << "Failed for width " << width << " max value";
351 } else if (width <= 32) {
352 auto resultMax =
353 static_cast<int32_t>(std::any_cast<Int>(deserializedMax));
354 EXPECT_EQ(resultMax, static_cast<int32_t>(maxVal))
355 << "Failed for width " << width << " max value";
356 } else {
357 auto resultMax =
358 static_cast<int64_t>(std::any_cast<Int>(deserializedMax));
359 EXPECT_EQ(resultMax, maxVal)
360 << "Failed for width " << width << " max value";
361 }
362
363 // Test maximum negative value
364 MessageData serializedMin(
365 sintType.serialize(std::any(minVal)).takeStorage());
366 BitVector serializedMinBits(serializedMin.getData());
367 auto deserializedMin = sintType.deserialize(serializedMinBits);
368
369 if (width <= 8) {
370 auto resultMin = static_cast<int8_t>(std::any_cast<Int>(deserializedMin));
371 EXPECT_EQ(resultMin, static_cast<int8_t>(minVal))
372 << "Failed for width " << width << " min value";
373 } else if (width <= 16) {
374 auto resultMin =
375 static_cast<int16_t>(std::any_cast<Int>(deserializedMin));
376 EXPECT_EQ(resultMin, static_cast<int16_t>(minVal))
377 << "Failed for width " << width << " min value";
378 } else if (width <= 32) {
379 auto resultMin =
380 static_cast<int32_t>(std::any_cast<Int>(deserializedMin));
381 EXPECT_EQ(resultMin, static_cast<int32_t>(minVal))
382 << "Failed for width " << width << " min value";
383 } else {
384 auto resultMin =
385 static_cast<int64_t>(std::any_cast<Int>(deserializedMin));
386 EXPECT_EQ(resultMin, minVal)
387 << "Failed for width " << width << " min value";
388 }
389
390 // Test -1 (all bits set case)
391 MessageData serializedMinusOne(
392 sintType.serialize(std::any(static_cast<int64_t>(-1))).takeStorage());
393 BitVector serializedMinusOneBits(serializedMinusOne.getData());
394 auto deserializedMinusOne = sintType.deserialize(serializedMinusOneBits);
395
396 if (width <= 8) {
397 auto resultMinusOne =
398 static_cast<int8_t>(std::any_cast<Int>(deserializedMinusOne));
399 EXPECT_EQ(resultMinusOne, -1)
400 << "Failed for width " << width << " value -1";
401 } else if (width <= 16) {
402 auto resultMinusOne =
403 static_cast<int16_t>(std::any_cast<Int>(deserializedMinusOne));
404 EXPECT_EQ(resultMinusOne, -1)
405 << "Failed for width " << width << " value -1";
406 } else if (width <= 32) {
407 auto resultMinusOne =
408 static_cast<int32_t>(std::any_cast<Int>(deserializedMinusOne));
409 EXPECT_EQ(resultMinusOne, -1)
410 << "Failed for width " << width << " value -1";
411 } else {
412 auto resultMinusOne =
413 static_cast<int64_t>(std::any_cast<Int>(deserializedMinusOne));
414 EXPECT_EQ(resultMinusOne, -1)
415 << "Failed for width " << width << " value -1";
416 }
417 }
418}
419
420// Test wide UIntType serialization and deserialization (>64 bits)
421TEST(ESITypesTest, WideUIntTypeSerialization) {
422 // Test 128-bit unsigned integer
423 UIntType uint128("uint128", 128);
424
425 // Test a specific 128-bit value: 0x123456789ABCDEF0FEDCBA9876543210
426 // This will be represented as a BitVector and serialized/deserialized
427 uint64_t lowPart = 0xFEDCBA9876543210ULL;
428 uint64_t highPart = 0x123456789ABCDEF0ULL;
429
430 // Construct the 128-bit value by creating bytes in little-endian order
431 std::vector<uint8_t> bytes(16, 0);
432 for (size_t i = 0; i < 8; ++i) {
433 bytes[i] = static_cast<uint8_t>((lowPart >> (8 * i)) & 0xFF);
434 bytes[i + 8] = static_cast<uint8_t>((highPart >> (8 * i)) & 0xFF);
435 }
436
437 // Create a UInt from the bytes.
438 std::any uint128Value = std::any(UInt(std::move(bytes)));
439
440 // Test validation
441 EXPECT_NO_THROW(uint128.ensureValid(uint128Value));
442
443 // Test serialization
444 MessageData serialized(uint128.serialize(uint128Value).takeStorage());
445 EXPECT_EQ(serialized.getSize(), 16UL)
446 << "UIntType(128) serialization should produce exactly 16 bytes";
447
448 // Verify byte values in little-endian order
449 for (size_t i = 0; i < 8; ++i) {
450 EXPECT_EQ(serialized.getData()[i],
451 static_cast<uint8_t>((lowPart >> (8 * i)) & 0xFF))
452 << "Low part byte " << i << " mismatch";
453 EXPECT_EQ(serialized.getData()[i + 8],
454 static_cast<uint8_t>((highPart >> (8 * i)) & 0xFF))
455 << "High part byte " << i << " mismatch";
456 }
457
458 // Test deserialization
459 BitVector serializedBits(serialized.getData());
460 auto deserialized = uint128.deserialize(serializedBits);
461 auto deserializedUInt = std::any_cast<UInt>(deserialized);
462 EXPECT_EQ(deserializedUInt.width(), 128u)
463 << "Deserialized UInt(128) should have width 128";
464 EXPECT_EQ(serializedBits.size(), 0UL)
465 << "UIntType(128) deserialization should consume all data";
466
467 // Test 80-bit value (non-power-of-2)
468 UIntType uint80("uint80", 80);
469 std::vector<uint8_t> bytes80(10, 0);
470 uint64_t val80 = 0x123456789ABCDEFULL;
471 for (size_t i = 0; i < 10; ++i) {
472 bytes80[i] = static_cast<uint8_t>((val80 >> (8 * i)) & 0xFF);
473 }
474
475 std::any uint80Value = std::any(UInt(std::move(bytes80), 80));
476
477 EXPECT_NO_THROW(uint80.ensureValid(uint80Value));
478
479 MessageData serialized80(uint80.serialize(uint80Value).takeStorage());
480 EXPECT_EQ(serialized80.getSize(), 10UL)
481 << "UIntType(80) serialization should produce exactly 10 bytes";
482
483 BitVector serialized80Bits(serialized80.getData());
484 auto deserialized80 = uint80.deserialize(serialized80Bits);
485 auto deserializedUInt80 = std::any_cast<UInt>(deserialized80);
486 EXPECT_EQ(deserializedUInt80.width(), 80u)
487 << "Deserialized UInt(80) should have width 80";
488 EXPECT_EQ(serialized80Bits.size(), 0UL)
489 << "UIntType(80) deserialization should consume all data";
490}
491
492// Test wide SIntType serialization and deserialization (>64 bits)
493TEST(ESITypesTest, WideSIntTypeSerialization) {
494 // Test 128-bit signed integer with positive value
495 SIntType sint128("sint128", 128);
496
497 // Create a positive 128-bit value: 0x123456789ABCDEF0 (upper bits 0)
498 std::vector<uint8_t> bytes(16, 0);
499 uint64_t val = 0x123456789ABCDEF0ULL;
500 for (size_t i = 0; i < 8; ++i) {
501 bytes[i] = static_cast<uint8_t>((val >> (8 * i)) & 0xFF);
502 }
503
504 std::any sint128Value = std::any(Int(std::move(bytes), 128));
505
506 // Test validation
507 EXPECT_NO_THROW(sint128.ensureValid(sint128Value));
508
509 // Test serialization
510 MessageData serialized(sint128.serialize(sint128Value).takeStorage());
511 EXPECT_EQ(serialized.getSize(), 16UL)
512 << "SIntType(128) serialization should produce exactly 16 bytes";
513
514 // Test deserialization
515 BitVector serializedBits(serialized.getData());
516 auto deserialized = sint128.deserialize(serializedBits);
517 auto deserializedSInt = std::any_cast<Int>(deserialized);
518 EXPECT_EQ(deserializedSInt.width(), 128u)
519 << "Deserialized SInt(128) should have width 128";
520 EXPECT_EQ(serializedBits.size(), 0UL)
521 << "SIntType(128) deserialization should consume all data";
522
523 // Test 128-bit signed integer with negative value: -1 (all bits set)
524 std::vector<uint8_t> bytesNegOne(16, 0xFF);
525 std::any sint128NegOne = std::any(Int(std::move(bytesNegOne), 128));
526
527 EXPECT_NO_THROW(sint128.ensureValid(sint128NegOne));
528
529 MessageData serializedNegOne(sint128.serialize(sint128NegOne).takeStorage());
530 EXPECT_EQ(serializedNegOne.getSize(), 16UL)
531 << "SIntType(128) serialization of -1 should produce 16 bytes";
532
533 // Verify all bytes are 0xFF
534 for (size_t i = 0; i < 16; ++i) {
535 EXPECT_EQ(serializedNegOne.getData()[i], 0xFF)
536 << "All bytes in -1 should be 0xFF";
537 }
538
539 // Test deserialization of -1
540 BitVector serializedNegOneBits(serializedNegOne.getData());
541 auto deserializedNegOne = sint128.deserialize(serializedNegOneBits);
542 auto deserializedSIntNegOne = std::any_cast<Int>(deserializedNegOne);
543 EXPECT_EQ(deserializedSIntNegOne.width(), 128u)
544 << "Deserialized SInt(128) of -1 should have width 128";
545
546 // Test 192-bit signed integer (3 bytes x 8 bits = 24 bytes x 8 bits)
547 SIntType sint192("sint192", 192);
548 std::vector<uint8_t> bytes192(24, 0);
549 // Set a pattern in the lower 16 bytes
550 uint64_t val192Low = 0xDEADBEEFCAFEBABEULL;
551 uint64_t val192Mid = 0x0123456789ABCDEFULL;
552 for (size_t i = 0; i < 8; ++i) {
553 bytes192[i] = static_cast<uint8_t>((val192Low >> (8 * i)) & 0xFF);
554 bytes192[i + 8] = static_cast<uint8_t>((val192Mid >> (8 * i)) & 0xFF);
555 }
556
557 std::any sint192Value = std::any(Int(std::move(bytes192), 192));
558
559 EXPECT_NO_THROW(sint192.ensureValid(sint192Value));
560
561 MessageData serialized192(sint192.serialize(sint192Value).takeStorage());
562 EXPECT_EQ(serialized192.getSize(), 24UL)
563 << "SIntType(192) serialization should produce exactly 24 bytes";
564
565 BitVector serialized192Bits(serialized192.getData());
566 auto deserialized192 = sint192.deserialize(serialized192Bits);
567 auto deserializedSInt192 = std::any_cast<Int>(deserialized192);
568 EXPECT_EQ(deserializedSInt192.width(), 192u)
569 << "Deserialized SInt(192) should have width 192";
570 EXPECT_EQ(serialized192Bits.size(), 0UL)
571 << "SIntType(192) deserialization should consume all data";
572
573 // Test 72-bit signed integer (non-byte-aligned, non-power-of-2)
574 SIntType sint72("sint72", 72);
575 std::vector<uint8_t> bytes72(9, 0);
576 uint64_t val72 = 0x0123456789ABCDEFULL;
577 for (size_t i = 0; i < 8; ++i) {
578 bytes72[i] = static_cast<uint8_t>((val72 >> (8 * i)) & 0xFF);
579 }
580 bytes72[8] = 0x01; // High byte with bit 72 representing sign bit position
581
582 std::any sint72Value = std::any(Int(std::move(bytes72), 72));
583
584 EXPECT_NO_THROW(sint72.ensureValid(sint72Value));
585
586 MessageData serialized72(sint72.serialize(sint72Value).takeStorage());
587 EXPECT_EQ(serialized72.getSize(), 9UL)
588 << "SIntType(72) serialization should produce exactly 9 bytes";
589
590 BitVector serialized72Bits(serialized72.getData());
591 auto deserialized72 = sint72.deserialize(serialized72Bits);
592 auto deserializedSInt72 = std::any_cast<Int>(deserialized72);
593 EXPECT_EQ(deserializedSInt72.width(), 72u)
594 << "Deserialized SInt(72) should have width 72";
595 EXPECT_EQ(serialized72Bits.size(), 0UL)
596 << "SIntType(72) deserialization should consume all data";
597}
598
599// Test StructType serialization and deserialization
600TEST(ESITypesTest, StructTypeSerialization) {
601 // Create field types
602 auto uintType = std::make_unique<UIntType>("uint8", 8);
603 auto sintType = std::make_unique<SIntType>("sint8", 8);
604
605 // Create struct type with fields
606 StructType::FieldVector fields = {{"field1", uintType.get()},
607 {"field2", sintType.get()}};
608 StructType structType("testStruct", fields);
609
610 // Test valid struct value
611 std::map<std::string, std::any> structValue = {
612 {"field1", std::any(static_cast<uint64_t>(42))},
613 {"field2", std::any(static_cast<int64_t>(-10))}};
614 std::any validStruct = std::any(structValue);
615 EXPECT_NO_THROW(structType.ensureValid(validStruct));
616
617 // Test missing field
618 std::map<std::string, std::any> incompleteStruct = {
619 {"field1", std::any(static_cast<uint64_t>(42))}};
620 std::any invalidStruct = std::any(incompleteStruct);
621 EXPECT_THROW(structType.ensureValid(invalidStruct), std::runtime_error);
622
623 // Test field not in type.
624 std::map<std::string, std::any> incompatibleStruct = {
625 {"UnknownField", std::any(static_cast<uint64_t>(0xdeadbeef))}};
626 std::any incompatibleStructAny = std::any(incompatibleStruct);
627 EXPECT_THROW(structType.ensureValid(incompatibleStructAny),
628 std::runtime_error);
629
630 // Test serialization
631 MessageData serialized(structType.serialize(validStruct).takeStorage());
632 EXPECT_EQ(serialized.getSize(), 2UL)
633 << "StructType with uint8 + sint8 fields should serialize to 2 bytes";
634
635 // Test deserialization
636 BitVector serializedBits(serialized.getData());
637 auto deserialized = structType.deserialize(serializedBits);
638 auto deserializedStruct =
639 std::any_cast<std::map<std::string, std::any>>(deserialized);
640 EXPECT_EQ(deserializedStruct.size(), 2UL)
641 << "Deserialized struct should contain exactly 2 fields";
642 EXPECT_TRUE(deserializedStruct.find("field1") != deserializedStruct.end())
643 << "Deserialized struct should contain field1";
644 EXPECT_TRUE(deserializedStruct.find("field2") != deserializedStruct.end())
645 << "Deserialized struct should contain field2";
646 EXPECT_EQ(serializedBits.size(), 0UL)
647 << "StructType deserialization should consume all data";
648
649 // Verify field values
650 auto field1Val =
651 static_cast<uint8_t>(std::any_cast<UInt>(deserializedStruct["field1"]));
652 auto field2Val =
653 static_cast<int8_t>(std::any_cast<Int>(deserializedStruct["field2"]));
654 EXPECT_EQ(field1Val, 42) << "Deserialized field1 should have value 42";
655 EXPECT_EQ(field2Val, -10) << "Deserialized field2 should have value -10";
656
657 // Test struct with non-byte aligned field. Should succeed.
658 auto oddUintType = std::make_unique<UIntType>("uint6", 6);
659 auto boolType = std::make_unique<BitsType>("bool", 1);
660 StructType::FieldVector oddFields = {{"field1", uintType.get()},
661 {"bool1", boolType.get()},
662 {"field2", oddUintType.get()},
663 {"bool2", boolType.get()}};
664 StructType oddStruct("oddStruct", oddFields);
665
666 std::map<std::string, std::any> oddStructValue = {
667 {"field1", std::any(static_cast<uint64_t>(1))},
668 {"bool1", std::any(std::vector<uint8_t>{1})},
669 {"field2", std::any(static_cast<uint64_t>(2))},
670 {"bool2", std::any(std::vector<uint8_t>{0})},
671 };
672
673 std::any validOddStruct = std::any(oddStructValue);
674 EXPECT_NO_THROW(oddStruct.ensureValid(validOddStruct));
675 MessageData oddSerialized(oddStruct.serialize(validOddStruct).takeStorage());
676 // Expect 2 bytes (round up from 14 bits)
677 EXPECT_EQ(oddSerialized.size(), 2UL);
678
679 BitVector oddSerializedBits(oddSerialized.getData());
680 auto oddDeserialized = oddStruct.deserialize(oddSerializedBits);
681 auto deserializedOddStruct =
682 std::any_cast<std::map<std::string, std::any>>(oddDeserialized);
683 EXPECT_EQ(deserializedOddStruct.size(), 4UL)
684 << "Deserialized odd struct should contain exactly 4 fields";
685 EXPECT_EQ(oddSerializedBits.size(), 0UL)
686 << "Odd StructType deserialization should consume all data";
687 // Verify field values
688 auto oddField1Val = static_cast<uint8_t>(
689 std::any_cast<UInt>(deserializedOddStruct["field1"]));
690 auto bool1Val =
691 std::any_cast<std::vector<uint8_t>>(deserializedOddStruct["bool1"]);
692 auto oddField2Val = static_cast<uint8_t>(
693 std::any_cast<UInt>(deserializedOddStruct["field2"]));
694 auto bool2Val =
695 std::any_cast<std::vector<uint8_t>>(deserializedOddStruct["bool2"]);
696
697 EXPECT_EQ(oddField1Val, 1) << "Deserialized odd field1 should have value 1";
698 EXPECT_EQ(bool1Val.size(), 1ULL)
699 << "Deserialized odd bool1 should have size 1";
700 EXPECT_EQ(bool1Val[0], 1) << "Deserialized odd bool1 should have value true";
701 EXPECT_EQ(oddField2Val, 2) << "Deserialized odd field2 should have value 2";
702 EXPECT_EQ(bool2Val.size(), 1ULL)
703 << "Deserialized odd bool2 should have size 1";
704 EXPECT_EQ(bool2Val[0], 0) << "Deserialized odd bool2 should have value false";
705}
706
707// Test ArrayType serialization and deserialization
708TEST(ESITypesTest, ArrayTypeSerialization) {
709 // Create element type
710 auto uintType = std::make_unique<UIntType>("uint8", 8);
711
712 // Create array type
713 ArrayType arrayType("uint8Array", uintType.get(), 3);
714
715 // Test valid array value
716 std::vector<std::any> arrayValue = {std::any(static_cast<uint64_t>(10)),
717 std::any(static_cast<uint64_t>(20)),
718 std::any(static_cast<uint64_t>(30))};
719 std::any validArray = std::any(arrayValue);
720 EXPECT_NO_THROW(arrayType.ensureValid(validArray));
721
722 // Test wrong size array
723 std::vector<std::any> wrongSizeArray = {std::any(static_cast<uint64_t>(10)),
724 std::any(static_cast<uint64_t>(20))};
725 std::any invalidArray = std::any(wrongSizeArray);
726 EXPECT_THROW(arrayType.ensureValid(invalidArray), std::runtime_error);
727
728 // Test serialization
729 MessageData serialized(arrayType.serialize(validArray).takeStorage());
730 EXPECT_EQ(serialized.getSize(), 3UL)
731 << "ArrayType of 3 uint8 elements should serialize to 3 bytes";
732 EXPECT_EQ(serialized.getData()[0], 30)
733 << "First array element should serialize to 30 but got "
734 << static_cast<uint32_t>(serialized.getData()[0]);
735 EXPECT_EQ(serialized.getData()[1], 20)
736 << "Second array element should serialize to 20 but got "
737 << static_cast<uint32_t>(serialized.getData()[1]);
738 EXPECT_EQ(serialized.getData()[2], 10)
739 << "Third array element should serialize to 10 but got "
740 << static_cast<uint32_t>(serialized.getData()[2]);
741
742 // Test deserialization
743 BitVector serializedBits(serialized.getData());
744 auto deserialized = arrayType.deserialize(serializedBits);
745 auto deserializedArray = std::any_cast<std::vector<std::any>>(deserialized);
746 EXPECT_EQ(deserializedArray.size(), 3UL)
747 << "Deserialized array should contain exactly 3 elements";
748 EXPECT_EQ(serializedBits.size(), 0UL)
749 << "ArrayType deserialization should consume all data";
750
751 // Verify element values
752 auto elem0 = static_cast<uint8_t>(std::any_cast<UInt>(deserializedArray[0]));
753 auto elem1 = static_cast<uint8_t>(std::any_cast<UInt>(deserializedArray[1]));
754 auto elem2 = static_cast<uint8_t>(std::any_cast<UInt>(deserializedArray[2]));
755 EXPECT_EQ(elem0, 10) << "First array element should have value 10";
756 EXPECT_EQ(elem1, 20) << "Second array element should have value 20";
757 EXPECT_EQ(elem2, 30) << "Third array element should have value 30";
758}
759
760// Test bit width calculations
761TEST(ESITypesTest, BitWidthCalculations) {
762 VoidType voidType("void");
763 EXPECT_EQ(voidType.getBitWidth(), 0)
764 << "VoidType should have a 0-bit logical width; transport-level "
765 "placeholder bytes are added by the channel-port base classes.";
766
767 BitsType bitsType("bits16", 16);
768 EXPECT_EQ(bitsType.getBitWidth(), 16)
769 << "BitsType(16) should have bit width of 16";
770
771 UIntType uintType("uint32", 32);
772 EXPECT_EQ(uintType.getBitWidth(), 32)
773 << "UIntType(32) should have bit width of 32";
774
775 SIntType sintType("sint64", 64);
776 EXPECT_EQ(sintType.getBitWidth(), 64)
777 << "SIntType(64) should have bit width of 64";
778
779 // Test struct bit width
780 auto uintType8 = std::make_unique<UIntType>("uint8", 8);
781 auto sintType16 = std::make_unique<SIntType>("sint16", 16);
782 StructType::FieldVector fields = {{"field1", uintType8.get()},
783 {"field2", sintType16.get()}};
784 StructType structType("testStruct", fields);
785 EXPECT_EQ(structType.getBitWidth(), 24)
786 << "StructType with uint8 + sint16 should have bit width of 24 (8 + "
787 "16)";
788
789 // Test array bit width
790 ArrayType arrayType("uint8Array", uintType8.get(), 5);
791 EXPECT_EQ(arrayType.getBitWidth(), 40)
792 << "ArrayType of 5 uint8 elements should have bit width of 40 (8 * 5)";
793}
794} // namespace
static InstancePath empty
Arrays have a compile time specified (static) size and an element type.
Definition Types.h:283
A lightweight, non-owning bit vector view backed by a byte array span.
Definition Values.h:42
Bits are just an array of bits.
Definition Types.h:206
A concrete flat message backed by a single vector of bytes.
Definition Common.h:155
Signed integer.
Definition Types.h:224
Structs are an ordered collection of fields, each with a name and a type.
Definition Types.h:246
std::vector< std::pair< std::string, const Type * > > FieldVector
Definition Types.h:248
Unsigned integer.
Definition Types.h:235
The "void" type is a special type which can be used to represent no type.
Definition Types.h:141
Definition esi.py:1