#include <endian.h> /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
#include <assert.h>
-/* We can't shift a int from 32 bit, >> 32 on int is undefined */
+/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
#define _ctf_piecewise_rshift(v, shift) \
({ \
unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \
_v >>= final; \
})
+#define _ctf_piecewise_lshift(v, shift) \
+({ \
+ unsigned long sb = (shift) / (sizeof(v) * CHAR_BIT - 1); \
+ unsigned long final = (shift) % (sizeof(v) * CHAR_BIT - 1); \
+ typeof(v) _v = (v); \
+ \
+ for (; sb; sb--) \
+ _v <<= sizeof(v) * CHAR_BIT - 1; \
+ _v <<= final; \
+})
+
+#define _ctf_is_signed_type(type) (((type)(-1)) < 0)
+
+#define _ctf_unsigned_cast(type, v) \
+({ \
+ (sizeof(v) < sizeof(type)) ? \
+ ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \
+ (type) (v); \
+})
+
/*
* ctf_bitfield_write - write integer to a bitfield in native endianness
*
#define _ctf_bitfield_write_le(ptr, _start, _length, _v) \
do { \
+ typeof(_v) v = (_v); \
typeof(*(ptr)) mask, cmask; \
+ unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
unsigned long start = (_start), length = (_length); \
- typeof(_v) v = (_v); \
unsigned long start_unit, end_unit, this_unit; \
unsigned long end, cshift; /* cshift is "complement shift" */ \
- unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
\
if (!length) \
break; \
if (end % ts) \
mask |= (~(typeof(*(ptr))) 0) << (end % ts); \
cmask = (typeof(*(ptr))) v << (start % ts); \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
break; \
cshift = start % ts; \
mask = ~((~(typeof(*(ptr))) 0) << cshift); \
cmask = (typeof(*(ptr))) v << cshift; \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
v = _ctf_piecewise_rshift(v, ts - cshift); \
if (end % ts) { \
mask = (~(typeof(*(ptr))) 0) << (end % ts); \
cmask = (typeof(*(ptr))) v; \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
} else \
#define _ctf_bitfield_write_be(ptr, _start, _length, _v) \
do { \
typeof(_v) v = (_v); \
+ typeof(*(ptr)) mask, cmask; \
+ unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
unsigned long start = _start, length = _length; \
unsigned long start_unit, end_unit, this_unit; \
unsigned long end, cshift; /* cshift is "complement shift" */ \
- typeof(*(ptr)) mask, cmask; \
- unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
\
if (!length) \
break; \
if (start % ts) \
mask |= (~((typeof(*(ptr))) 0)) << (ts - (start % ts)); \
cmask = (typeof(*(ptr))) v << ((ts - (end % ts)) % ts); \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
break; \
cshift = end % ts; \
mask = ~((~(typeof(*(ptr))) 0) << (ts - cshift)); \
cmask = (typeof(*(ptr))) v << (ts - cshift); \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
v = _ctf_piecewise_rshift(v, cshift); \
end -= cshift; \
this_unit--; \
} \
- for (; (long)this_unit >= (long)start_unit + 1; this_unit--) { \
+ for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
(ptr)[this_unit] = (typeof(*(ptr))) v; \
v = _ctf_piecewise_rshift(v, ts); \
end -= ts; \
if (start % ts) { \
mask = (~(typeof(*(ptr))) 0) << (ts - (start % ts)); \
cmask = (typeof(*(ptr))) v; \
+ cmask &= ~mask; \
(ptr)[this_unit] &= mask; \
(ptr)[this_unit] |= cmask; \
} else \
#endif
-#if 0
-#define _ctf_bitfield_read_le(ptr, _start, _length, _vptr) \
+#define _ctf_bitfield_read_le(ptr, _start, _length, vptr) \
do { \
- typeof(_vptr) vptr = (_vptr); \
+ typeof(*(vptr)) v; \
+ typeof(*(ptr)) mask, cmask; \
+ unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
unsigned long start = _start, length = _length; \
unsigned long start_unit, end_unit, this_unit; \
unsigned long end, cshift; /* cshift is "complement shift" */ \
+ \
+ if (!length) { \
+ *(vptr) = 0; \
+ break; \
+ } \
+ \
+ end = start + length; \
+ start_unit = start / ts; \
+ end_unit = (end + (ts - 1)) / ts; \
+ \
+ this_unit = end_unit - 1; \
+ if (_ctf_is_signed_type(typeof(v)) \
+ && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << ((end % ts ? : ts) - 1)))) \
+ v = ~(typeof(v)) 0; \
+ else \
+ v = 0; \
+ if (start_unit == end_unit - 1) { \
+ cmask = (ptr)[this_unit]; \
+ cmask >>= (start % ts); \
+ if ((end - start) % ts) { \
+ mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \
+ cmask &= mask; \
+ } \
+ v = _ctf_piecewise_lshift(v, end - start); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ *(vptr) = v; \
+ break; \
+ } \
+ if (end % ts) { \
+ cshift = end % ts; \
+ mask = ~((~(typeof(*(ptr))) 0) << cshift); \
+ cmask = (ptr)[this_unit]; \
+ cmask &= mask; \
+ v = _ctf_piecewise_lshift(v, cshift); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ end -= cshift; \
+ this_unit--; \
+ } \
+ for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \
+ v = _ctf_piecewise_lshift(v, ts); \
+ v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \
+ end -= ts; \
+ } \
+ if (start % ts) { \
+ mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \
+ cmask = (ptr)[this_unit]; \
+ cmask >>= (start % ts); \
+ cmask &= mask; \
+ v = _ctf_piecewise_lshift(v, ts - (start % ts)); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ } else { \
+ v = _ctf_piecewise_lshift(v, ts); \
+ v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \
+ } \
+ *(vptr) = v; \
+} while (0)
+
+#define _ctf_bitfield_read_be(ptr, _start, _length, vptr) \
+do { \
+ typeof(*(vptr)) v; \
typeof(*(ptr)) mask, cmask; \
unsigned long ts = sizeof(typeof(*(ptr))) * CHAR_BIT; /* type size */ \
+ unsigned long start = _start, length = _length; \
+ unsigned long start_unit, end_unit, this_unit; \
+ unsigned long end, cshift; /* cshift is "complement shift" */ \
\
- if (!length) \
+ if (!length) { \
+ *(vptr) = 0; \
break; \
+ } \
\
end = start + length; \
start_unit = start / ts; \
end_unit = (end + (ts - 1)) / ts; \
+ \
+ this_unit = start_unit; \
+ if (_ctf_is_signed_type(typeof(v)) \
+ && ((ptr)[this_unit] & ((typeof(*(ptr))) 1 << (ts - (start % ts) - 1)))) \
+ v = ~(typeof(v)) 0; \
+ else \
+ v = 0; \
+ if (start_unit == end_unit - 1) { \
+ cmask = (ptr)[this_unit]; \
+ cmask >>= (ts - (end % ts)) % ts; \
+ if ((end - start) % ts) {\
+ mask = ~((~(typeof(*(ptr))) 0) << (end - start)); \
+ cmask &= mask; \
+ } \
+ v = _ctf_piecewise_lshift(v, end - start); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ *(vptr) = v; \
+ break; \
+ } \
+ if (start % ts) { \
+ mask = ~((~(typeof(*(ptr))) 0) << (ts - (start % ts))); \
+ cmask = (ptr)[this_unit]; \
+ cmask &= mask; \
+ v = _ctf_piecewise_lshift(v, ts - (start % ts)); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ start += ts - (start % ts); \
+ this_unit++; \
+ } \
+ for (; this_unit < end_unit - 1; this_unit++) { \
+ v = _ctf_piecewise_lshift(v, ts); \
+ v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \
+ start += ts; \
+ } \
+ if (end % ts) { \
+ mask = ~((~(typeof(*(ptr))) 0) << (end % ts)); \
+ cmask = (ptr)[this_unit]; \
+ cmask >>= ts - (end % ts); \
+ cmask &= mask; \
+ v = _ctf_piecewise_lshift(v, end % ts); \
+ v |= _ctf_unsigned_cast(typeof(v), cmask); \
+ } else { \
+ v = _ctf_piecewise_lshift(v, ts); \
+ v |= _ctf_unsigned_cast(typeof(v), (ptr)[this_unit]); \
+ } \
+ *(vptr) = v; \
} while (0)
-#endif //0
-
/*
- * Read a bitfield byte-wise. This function is arch-agnostic.
+ * ctf_bitfield_read - read integer from a bitfield in native endianness
+ * ctf_bitfield_read_le - read integer from a bitfield in little endian
+ * ctf_bitfield_read_be - read integer from a bitfield in big endian
*/
-static inline
-uint64_t _ctf_bitfield_read_64(const unsigned char *ptr,
- unsigned long start, unsigned long len,
- int byte_order, int signedness)
-{
- long start_unit, end_unit, this_unit;
- unsigned long end, cshift; /* cshift is "complement shift" */
- unsigned long ts = sizeof(unsigned char) * CHAR_BIT;
- unsigned char mask, cmask;
- uint64_t v = 0;
-
- if (!len)
- return 0;
- end = start + len;
- start_unit = start / ts;
- end_unit = (end + (ts - 1)) / ts;
-
- /*
- * We can now fill v piece-wise, from lower bits to upper bits.
- * We read the bitfield in the opposite direction it was written.
- */
- switch (byte_order) {
- case LITTLE_ENDIAN:
- this_unit = end_unit - 1;
- if (signedness) {
- if (ptr[this_unit] & (1U << ((end % ts ? : ts) - 1)))
- v = ~(uint64_t) 0;
- }
- if (start_unit == end_unit - 1) {
- mask = (~(unsigned char) 0) << (end % ts ? : ts);
- mask |= ~((~(unsigned char) 0) << (start % ts));
- cmask = ptr[this_unit];
- cmask &= ~mask;
- cmask >>= (start % ts);
- v <<= end - start;
- v |= cmask;
- break;
- }
- if (end % ts) {
- cshift = (end % ts ? : ts);
- mask = (~(unsigned char) 0) << cshift;
- cmask = ptr[this_unit];
- cmask &= ~mask;
- v <<= cshift;
- v |= (uint64_t) cmask;
- end -= cshift;
- this_unit--;
- }
- for (; this_unit >= start_unit + 1; this_unit--) {
- v <<= ts;
- v |= (uint64_t) ptr[this_unit];
- end -= ts;
- }
- if (start % ts) {
- cmask = ptr[this_unit] >> (start % ts);
- v <<= ts - (start % ts);
- v |= (uint64_t) cmask;
- } else {
- v <<= ts;
- v |= (uint64_t) ptr[this_unit];
- }
- break;
- case BIG_ENDIAN:
- this_unit = start_unit;
- if (signedness) {
- if (ptr[this_unit] & (1U << (ts - (start % ts) - 1)))
- v = ~(uint64_t) 0;
- }
- if (start_unit == end_unit - 1) {
- mask = (~(unsigned char) 0) << (ts - (start % ts));
- mask |= ~((~(unsigned char) 0) << ((ts - (end % ts)) % ts));
- cmask = ptr[this_unit];
- cmask &= ~mask;
- cmask >>= (ts - (end % ts)) % ts;
- v <<= end - start;
- v |= (uint64_t) cmask;
- break;
- }
- if (start % ts) {
- mask = (~(unsigned char) 0) << (ts - (start % ts));
- cmask = ptr[this_unit];
- cmask &= ~mask;
- v <<= ts - (start % ts);
- v |= (uint64_t) cmask;
- start += ts - (start % ts);
- this_unit++;
- }
- for (; this_unit < end_unit - 1; this_unit++) {
- v <<= ts;
- v |= (uint64_t) ptr[this_unit];
- start += ts;
- }
- if (end % ts) {
- cmask = ptr[this_unit];
- cmask >>= (ts - (end % ts)) % ts;
- v <<= (end % ts);
- v |= (uint64_t) cmask;
- } else {
- v <<= ts;
- v |= (uint64_t) ptr[this_unit];
- }
- break;
- default:
- assert(0); /* TODO: support PDP_ENDIAN */
- }
- return v;
-}
-
-static inline
-uint64_t ctf_bitfield_unsigned_read(const uint8_t *ptr,
- unsigned long start, unsigned long len,
- int byte_order)
-{
- return (uint64_t) _ctf_bitfield_read_64(ptr, start, len, byte_order, 0);
-}
-
-static inline
-int64_t ctf_bitfield_signed_read(const uint8_t *ptr,
- unsigned long start, unsigned long len,
- int byte_order)
-{
- return (int64_t) _ctf_bitfield_read_64(ptr, start, len, byte_order, 1);
-}
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+
+#define ctf_bitfield_read(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_le(ptr, _start, _length, _vptr)
+
+#define ctf_bitfield_read_le(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_le(ptr, _start, _length, _vptr)
+
+#define ctf_bitfield_read_be(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_be((const uint8_t *) (ptr), _start, _length, _vptr)
+
+#elif (BYTE_ORDER == BIG_ENDIAN)
+
+#define ctf_bitfield_read(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_be(ptr, _start, _length, _vptr)
+
+#define ctf_bitfield_read_le(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_le((const uint8_t *) (ptr), _start, _length, _vptr)
+
+#define ctf_bitfield_read_be(ptr, _start, _length, _vptr) \
+ _ctf_bitfield_read_be(ptr, _start, _length, _vptr)
+
+#else /* (BYTE_ORDER == PDP_ENDIAN) */
+
+#error "Byte order not supported"
+
+#endif
#endif /* _CTF_BITFIELD_H */
for (l = nrbits; l < (CHAR_BIT * TEST_LEN) - s; l++) {
init_byte_array(target.c, TEST_LEN, 0xFF);
ctf_bitfield_write(target.c, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (bytewise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0xFF);
ctf_bitfield_write(target.s, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (shortwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0xFF);
ctf_bitfield_write(target.i, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (intwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0xFF);
ctf_bitfield_write(target.l, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (longwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0xFF);
ctf_bitfield_write(target.ll, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (longlongwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
for (l = nrbits; l < (8 * TEST_LEN) - s; l++) {
init_byte_array(target.c, TEST_LEN, 0x0);
ctf_bitfield_write(target.c, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (bytewise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0x0);
ctf_bitfield_write(target.s, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (shortwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0x0);
ctf_bitfield_write(target.i, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (intwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0x0);
ctf_bitfield_write(target.l, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (longwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
init_byte_array(target.c, TEST_LEN, 0x0);
ctf_bitfield_write(target.ll, s, l, src);
- readval = _ctf_bitfield_read_64(target.c, s, l, BYTE_ORDER, 1);
+ ctf_bitfield_read(target.c, s, l, &readval);
if (readval != src) {
printf("Error (longlongwise) src %lX read %llX shift %d len %d\n",
src, readval, s, l);
printf("lluwise\n");
print_byte_array(target.c, 8);
- readval = _ctf_bitfield_read_64(target.c, shift, len, BYTE_ORDER, 0);
+ ctf_bitfield_read(target.c, shift, len, &readval);
printf("read: %llX\n", readval);
ret = run_test();