#ifndef __BS_PRIM_OPS_H__ #define __BS_PRIM_OPS_H__ #include #include "bluesim_types.h" #include "bs_wide_data.h" /* These are utility functions used when implementing * bit-granularity primitives on top of coarse C/C++ * primitives. */ /* The organizing principle behind these routines is * determined by the interactions of C++ function overloading * and integral promotion. * * - Overloading works on the function name and argument types, * but not on the return type. Therefore, the return type * is encoded in the function name as 8 (for bool or tUInt8), * 32 (for tUInt32), 64 (for tUInt64) or Wide (for tUWide). * * - For some operators, the return type size is not related to * the argument type size. In this case, you may have several * implementations for the same return size with different * argument sizes (which can be larger or smaller than the * return size). * * - If there is not an exact match for the argument types * in a function call, an approximate match is chosen and the * arguments which are no the correct type undergo integral * promotion to a larger value. This allows us to use one * function with two larger types instead of creating multiple * functions to handle each possible combination of argument * sizes. * * - An ambiguity in overload resolution generates a compiler * error, so it is better to NOT create lots of implementations * when fewer implementations + function overloading will do. */ /* Note: The C/C++ standard says that shifting a value by an * amount greater than the width of the datatype yields an * undefined value, and compiler optimizations *do* take advantage * of this. In Bluespec, a zero value is expected in these * cases, so we have to use a guarded shift operation in situations * where the value is not guaranteed to be in range. * For efficiency, we want to use unguarded shifts when we know * it is safe. */ /* The caller of the mask operations is responsible for ensuring that * the number of bits requested is less than or equal to the result size. */ // This case handles promoted values static inline tUInt8 mask8(tUInt32 n, tSInt32 val) { return (tUInt8)(((1 << n) - 1) & val); } static inline tUInt8 mask8(tUInt32 n, tUInt32 val) { return (tUInt8)(((1 << n) - 1) & val); } static inline tUInt8 mask8(tUInt32 n, tUInt64 val) { return (tUInt8)(((1 << n) - 1) & val); } static inline tUInt8 mask8(tUInt32 n, const tUWide& val) { return val.extract8(n-1,0); } // This case handles promoted values static inline tUInt32 mask32(tUInt32 n, tSInt32 val) { return (tUInt32)((n == 32) ? val : (((1 << n) - 1) & val)); } static inline tUInt32 mask32(tUInt32 n, tUInt32 val) { return (n == 32) ? val : (((1 << n) - 1) & val); } static inline tUInt32 mask32(tUInt32 n, tUInt64 val) { return (tUInt32)(((1llu << n) - 1llu) & val); } static inline tUInt32 mask32(tUInt32 n, const tUWide& val) { return val.extract32(n-1,0); } static inline tUInt64 mask64(tUInt32 n, tUInt64 val) { return (n == 64) ? val : (((1llu << n) - 1llu) & val); } static inline tUInt64 mask64(tUInt32 n, const tUWide& val) { return val.extract64(n-1,0); } static inline tUWide maskWide(tUInt32 n, const tUWide& val) { return val.extractWide(n-1,0); } /* Sign testing operations used for signed relational primitives */ // This case handles promoted values static inline bool sign_bit_set(tUInt32 data_sz, tSInt32 data) { return ((data & (1 << (data_sz - 1))) != 0); } static inline bool sign_bit_set(tUInt32 data_sz, tUInt32 data) { return ((data & (1 << (data_sz - 1))) != 0); } static inline bool sign_bit_set(tUInt32 data_sz, tUInt64 data) { return ((data & (1llu << (data_sz - 1))) != 0llu); } static inline bool sign_bit_set(tUInt32 data_sz, const tUWide& data) { return data.extract1(data_sz - 1); } /* * Definitions of primitive operators that * do not have corresponding C primitives. */ // forward declarations static inline tUInt32 primShiftR32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt32 shift ); static inline tUInt64 primShiftR64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt32 shift ); // 8-bit primitives static inline tUInt8 primSignExt8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data ) { if (sign_bit_set(data_sz, data)) { /* the data is signed, so fill the upper bits with 1 */ return mask8(result_sz, ((~0u) << data_sz) | data); } else { /* the value is unsigned, so just return it */ return data; } } static inline tUInt8 primZeroExt8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data ) { return data; } static inline tUInt8 primShiftR8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 8) return (data >> shift); else return 0; } static inline tUInt8 primShiftR8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 8) return (data >> shift); else return 0; } static inline tUInt8 primShiftR8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 8) return (data >> shift); else return 0; } static inline tUInt8 primShiftR8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 8)) return (data >> shift32); else return 0; } static inline tUInt8 primShiftL8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 8) return mask8(result_sz, data << shift); else return 0; } static inline tUInt8 primShiftL8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 8) return mask8(result_sz, data << shift); else return 0; } static inline tUInt8 primShiftL8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 8) return mask8(result_sz, data << shift); else return 0; } static inline tUInt8 primShiftL8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 8)) return mask8(result_sz, data << shift32); else return 0; } static inline tUInt8 primShiftRA8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt8 shift ) { tUInt8 tmp = 0; if (shift < data_sz) { tmp = primShiftR8(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt8(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask8(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt8 primShiftRA8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt32 shift ) { tUInt8 tmp = 0; if (shift < data_sz) { tmp = primShiftR8(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt8(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask8(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt8 primShiftRA8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , tUInt64 shift ) { tUInt8 tmp = 0; if (shift < data_sz) { tmp = primShiftR8(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt8(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask8(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt8 primShiftRA8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt8 tmp = 0; tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) { tmp = primShiftR8(data_sz, data_sz, data, 32u, shift32); tmp = primSignExt8(result_sz, data_sz - shift32, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask8(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt8 primTrunc8( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data ) { return mask8(result_sz, data); } static inline tUInt8 primTrunc8( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { return mask8(result_sz, data); } static inline tUInt8 primExtract8( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt8 tmp = primShiftR8(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask8(mask_sz, tmp); } static inline tUInt8 primExtract8( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt32 tmp = primShiftR32(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask8(mask_sz, tmp); } static inline tUInt8 primExtract8( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt64 tmp = primShiftR64(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask8(mask_sz, tmp); } static inline tUInt8 primExtract8( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt8 tmp = data.extract8(high,low); return mask8(result_sz, tmp); } // 32-bit primitives static inline tUInt32 primSignExt32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data ) { if (sign_bit_set(data_sz, data)) { /* the data is signed, so fill the upper bits with 1 */ return mask32(result_sz, ((~0u) << (data_sz - 1)) | data); } else { /* the value is unsigned, so just return it */ return data; } } static inline tUInt32 primZeroExt32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data ) { return data; } static inline tUInt32 primShiftR32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 32) return (data >> shift); else return 0; } static inline tUInt32 primShiftR32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 32) return (data >> shift); else return 0; } static inline tUInt32 primShiftR32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 32) return (data >> shift); else return 0; } static inline tUInt32 primShiftR32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 32)) return (data >> shift32); else return 0; } static inline tUInt32 primShiftL32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 32) return mask32(result_sz, data << shift); else return 0; } static inline tUInt32 primShiftL32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 32) return mask32(result_sz, data << shift); else return 0; } static inline tUInt32 primShiftL32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 32) return mask32(result_sz, data << shift); else return 0; } static inline tUInt32 primShiftL32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 32)) return mask32(result_sz, data << shift32); else return 0; } static inline tUInt32 primShiftRA32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt8 shift ) { tUInt32 tmp = 0u; if (shift < data_sz) { tmp = primShiftR32(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt32(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask32(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt32 primShiftRA32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt32 shift ) { tUInt32 tmp = 0u; if (shift < data_sz) { tmp = primShiftR32(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt32(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask32(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt32 primShiftRA32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , tUInt64 shift ) { tUInt32 tmp = 0u; if (shift < data_sz) { tmp = primShiftR32(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt32(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask32(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt32 primShiftRA32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 tmp = 0u; tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) { tmp = primShiftR32(data_sz, data_sz, data, 32u, shift32); tmp = primSignExt32(result_sz, data_sz - shift32, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask32(result_sz, ~0u); // result should be all 1's } return tmp; } static inline tUInt32 primTrunc32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data ) { return mask32(result_sz, data); } static inline tUInt32 primExtract32( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt32 tmp = primShiftR32(data_sz, data_sz, (tUInt32)data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask32(mask_sz, tmp); } static inline tUInt32 primExtract32( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt32 tmp = primShiftR32(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask32(mask_sz, tmp); } static inline tUInt32 primExtract32( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt64 tmp = primShiftR64(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask32(mask_sz, tmp); } static inline tUInt32 primExtract32( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt32 tmp = data.extract32(high,low); return mask32(result_sz, tmp); } // 64-bit primitives static inline tUInt64 primSignExt64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { if (sign_bit_set(data_sz, data)) { /* the data is signed, so fill the upper bits with 1 */ return mask64(result_sz, ((~0llu) << (data_sz - 1)) | data); } else { /* the value is unsigned, so just return it */ return data; } } static inline tUInt64 primZeroExt64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { return data; } static inline tUInt64 primShiftR64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 64) return (data >> shift); else return 0; } static inline tUInt64 primShiftR64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 64) return (data >> shift); else return 0; } static inline tUInt64 primShiftR64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 64) return (data >> shift); else return 0; } static inline tUInt64 primShiftR64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 64)) return (data >> shift32); else return 0; } static inline tUInt64 primShiftL64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < 64) return mask64(result_sz, data << shift); else return 0; } static inline tUInt64 primShiftL64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < 64) return mask64(result_sz, data << shift); else return 0; } static inline tUInt64 primShiftL64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < 64) return mask64(result_sz, data << shift); else return 0; } static inline tUInt64 primShiftL64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < 64)) return mask64(result_sz, data << shift32); else return 0; } static inline tUInt64 primShiftRA64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt8 shift ) { tUInt64 tmp = 0llu; if (shift < data_sz) { tmp = primShiftR64(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt64(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask64(result_sz, ~0llu); // result should be all 1's } return tmp; } static inline tUInt64 primShiftRA64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt32 shift ) { tUInt64 tmp = 0llu; if (shift < data_sz) { tmp = primShiftR64(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt64(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask64(result_sz, ~0llu); // result should be all 1's } return tmp; } static inline tUInt64 primShiftRA64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , tUInt64 shift ) { tUInt64 tmp = 0llu; if (shift < data_sz) { tmp = primShiftR64(data_sz, data_sz, data, shift_sz, shift); tmp = primSignExt64(result_sz, data_sz - shift, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask64(result_sz, ~0llu); // result should be all 1's } return tmp; } static inline tUInt64 primShiftRA64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 shift_sz , const tUWide& shift ) { tUInt64 tmp = 0llu; tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) { tmp = primShiftR64(data_sz, data_sz, data, 32u, shift32); tmp = primSignExt64(result_sz, data_sz - shift32, tmp); } else if (sign_bit_set(data_sz,data)) { tmp = mask64(result_sz, ~0llu); // result should be all 1's } return tmp; } static inline tUInt64 primTrunc64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { return mask64(result_sz, data); } static inline tUInt64 primExtract64( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt64 tmp = primShiftR64(data_sz, data_sz, data, low_sz, low); tUInt32 mask_sz = std::min(result_sz, (high-low+1)); return mask64(mask_sz, tmp); } static inline tUInt64 primExtract64( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { tUInt64 tmp = data.extract64(high,low); return mask64(result_sz, tmp); } // Wide primitives static inline tUWide primSignExtWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data ) { tUWide result(result_sz, NUM_WORDS(result_sz)); result.copy(data); if (sign_bit_set(data_sz, data)) result.set(data_sz); else result.clear(data_sz); return result; } static inline tUWide primSignExtWide( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { tUWide result(result_sz, NUM_WORDS(result_sz)); unsigned int buf[2]; buf[0] = (unsigned int) data; buf[1] = (unsigned int) (data >> 32); result.write(buf, data_sz, 0); if (sign_bit_set(data_sz, data)) result.set(data_sz); else result.clear(data_sz); return result; } static inline tUWide primZeroExtWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data ) { tUWide result(result_sz, NUM_WORDS(result_sz)); result.copy(data); result.clear(data_sz); return result; } static inline tUWide primZeroExtWide( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data ) { tUWide result(result_sz, NUM_WORDS(result_sz)); unsigned int buf[2]; buf[0] = (unsigned int) data; buf[1] = (unsigned int) (data >> 32); result.write(buf, data_sz, 0); result.clear(data_sz); return result; } static inline tUWide primShiftRWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt8 shift ) { return data >> shift; // wide data >> operator handles guarding } static inline tUWide primShiftRWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt32 shift ) { return data >> shift; // wide data >> operator handles guarding } static inline tUWide primShiftRWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < data_sz) { return data >> shift; // wide data >> operator handles guarding } else { WideData result(result_sz, NUM_WORDS(result_sz)); result.clear(); return result; } } static inline tUWide primShiftRWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) { return data >> shift32; // wide data >> operator handles guarding } else { WideData result(result_sz, NUM_WORDS(result_sz)); result.clear(); return result; } } static inline tUWide primShiftLWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt8 shift ) { // wide data << operator handles guarding return maskWide(result_sz, data << shift); } static inline tUWide primShiftLWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt32 shift ) { // wide data << operator handles guarding return maskWide(result_sz, data << shift); } static inline tUWide primShiftLWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < data_sz) { // wide data << operator handles guarding return maskWide(result_sz, data << shift); } else { WideData result(result_sz, NUM_WORDS(result_sz)); result.clear(); return result; } } static inline tUWide primShiftLWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) { // wide data << operator handles guarding return maskWide(result_sz, data << shift32); } else { WideData result(result_sz, NUM_WORDS(result_sz)); result.clear(); return result; } } static inline tUWide primShiftRAWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt8 shift ) { if (shift < data_sz) return primSignExtWide(result_sz, data_sz - shift, data >> shift); else { tUWide tmp; tmp.setSize(result_sz); if (sign_bit_set(data_sz, data)) tmp.set(); else tmp.clear(); return tmp; } } static inline tUWide primShiftRAWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt32 shift ) { if (shift < data_sz) return primSignExtWide(result_sz, data_sz - shift, data >> shift); else { tUWide tmp; tmp.setSize(result_sz); if (sign_bit_set(data_sz, data)) tmp.set(); else tmp.clear(); return tmp; } } static inline tUWide primShiftRAWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , tUInt64 shift ) { if (shift < data_sz) return primSignExtWide(result_sz, data_sz - shift, data >> shift); else { tUWide tmp; tmp.setSize(result_sz); if (sign_bit_set(data_sz, data)) tmp.set(); else tmp.clear(); return tmp; } } static inline tUWide primShiftRAWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 shift_sz , const tUWide& shift ) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) return primSignExtWide(result_sz, data_sz - shift32, data >> shift32); else { tUWide tmp; tmp.setSize(result_sz); if (sign_bit_set(data_sz, data)) tmp.set(); else tmp.clear(); return tmp; } } static inline tUWide primTruncWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data ) { return maskWide(result_sz, data); } static inline tUWide primExtractWide( tUInt32 result_sz , tUInt32 data_sz , tUInt8 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { WideData dataW(data_sz, (tUInt32)data); return dataW.extractWide(high,low); } static inline tUWide primExtractWide( tUInt32 result_sz , tUInt32 data_sz , tUInt32 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { WideData dataW(data_sz, data); return dataW.extractWide(high,low); } static inline tUWide primExtractWide( tUInt32 result_sz , tUInt32 data_sz , tUInt64 data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { WideData dataW(data_sz, data); return dataW.extractWide(high,low); } static inline tUWide primExtractWide( tUInt32 result_sz , tUInt32 data_sz , const tUWide& data , tUInt32 high_sz , tUInt32 high , tUInt32 low_sz , tUInt32 low ) { return data.extractWide(high,low); } // Signed relational operators static inline bool primSLT8( tUInt32 result_sz , tUInt32 data1_sz , tUInt8 data1 , tUInt32 data2_sz , tUInt8 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 < data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLE8( tUInt32 result_sz , tUInt32 data1_sz , tUInt8 data1 , tUInt32 data2_sz , tUInt8 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 <= data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLT8( tUInt32 result_sz , tUInt32 data1_sz , tUInt32 data1 , tUInt32 data2_sz , tUInt32 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 < data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLE8( tUInt32 result_sz , tUInt32 data1_sz , tUInt32 data1 , tUInt32 data2_sz , tUInt32 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 <= data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLT8( tUInt32 result_sz , tUInt32 data1_sz , tUInt64 data1 , tUInt32 data2_sz , tUInt64 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 < data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLE8( tUInt32 result_sz , tUInt32 data1_sz , tUInt64 data1 , tUInt32 data2_sz , tUInt64 data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 <= data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLT8( tUInt32 result_sz , tUInt32 data1_sz , const tUWide& data1 , tUInt32 data2_sz , const tUWide& data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 < data2); } else { return sign_bit_set(data1_sz, data1); } } static inline bool primSLE8( tUInt32 result_sz , tUInt32 data1_sz , const tUWide& data1 , tUInt32 data2_sz , const tUWide& data2 ) { if (sign_bit_set(data1_sz, data1) == sign_bit_set(data2_sz, data2)) { return (data1 <= data2); } else { return sign_bit_set(data1_sz, data1); } } /* prim function calls which originally return wide-data, now take the return address as the last parameter*/ static inline void wop_primSignExtWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, tUWide& result) { result.copy(data); if (sign_bit_set(data_sz, data)) result.set(data_sz); else result.clear(data_sz); } static inline void wop_primSignExtWide( unsigned int result_sz, unsigned int data_sz, unsigned long long data, tUWide& result) { unsigned int buf[2]; buf[0] = (unsigned int) data; buf[1] = (unsigned int) (data >> 32); result.write(buf, data_sz, 0); if (sign_bit_set(data_sz, data)) result.set(data_sz); else result.clear(data_sz); } static inline void wop_primZeroExtWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, tUWide& result) { result.copy(data); result.clear(data_sz); } static inline void wop_primZeroExtWide( unsigned int result_sz, unsigned int data_sz, unsigned long long data, tUWide& result) { unsigned int buf[2]; buf[0] = (unsigned int) data; buf[1] = (unsigned int) (data >> 32); result.write(buf, data_sz, 0); result.clear(data_sz); } static inline void wop_primShiftRWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned char shift, tUWide& result) { wop_srl(data, shift, result); } static inline void wop_primShiftRWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned int shift, tUWide& result) { wop_srl(data, shift, result); } static inline void wop_primShiftRWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned long long shift, tUWide& result) { if (shift < data_sz) wop_srl(data, shift, result); else result.clear(); } static inline void wop_primShiftRWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, const tUWide& shift, tUWide& result) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) wop_srl(data, shift32, result); else result.clear(); } static inline void wop_primShiftLWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned char shift, tUWide& result) { wop_sl(data, shift, result); } static inline void wop_primShiftLWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned int shift, tUWide& result) { wop_sl(data, shift, result); } static inline void wop_primShiftLWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned long long shift, tUWide& result) { if (shift < data_sz) wop_sl(data, shift, result); else result.clear(); } static inline void wop_primShiftLWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, const tUWide& shift, tUWide& result) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) wop_sl(data, shift32, result); else result.clear(); } static inline void wop_primShiftRAWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned char shift, tUWide& result) { if (shift < data_sz) wop_primSignExtWide(result_sz, data_sz - shift, data >> shift, result); else { if (sign_bit_set(data_sz, data)) result.set(); else result.clear(); } } static inline void wop_primShiftRAWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned int shift, tUWide& result) { if (shift < data_sz) wop_primSignExtWide(result_sz, data_sz - shift, data >> shift, result); else { if (sign_bit_set(data_sz, data)) result.set(); else result.clear(); } } static inline void wop_primShiftRAWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, unsigned long long shift, tUWide& result) { if (shift < data_sz) wop_primSignExtWide(result_sz, data_sz - shift, data >> shift, result); else { if (sign_bit_set(data_sz, data)) result.set(); else result.clear(); } } static inline void wop_primShiftRAWide( unsigned int result_sz, unsigned int data_sz, const tUWide& data, unsigned int shift_sz, const tUWide& shift, tUWide& result) { tUInt32 shift32 = shift.extract32(std::min(32u,shift.size()), 0); if (shift.is_clear(33u) && (shift32 < data_sz)) wop_primSignExtWide(result_sz, data_sz - shift32, data >> shift32, result); else { if (sign_bit_set(data_sz, data)) result.set(); else result.clear(); } } static inline void wop_primExtractWide(unsigned int dst_sz, unsigned int src_sz, tUInt8 src, unsigned int high_sz, unsigned int high, unsigned int low_sz, unsigned int low, tUWide &dst) { WideData srcW(src_sz, (tUInt32)src); srcW.wop_extractWide(high, low, dst); } static inline void wop_primExtractWide(unsigned int dst_sz, unsigned int src_sz, tUInt32 src, unsigned int high_sz, unsigned int high, unsigned int low_sz, unsigned int low, tUWide &dst) { WideData srcW(src_sz, src); srcW.wop_extractWide(high, low, dst); } static inline void wop_primExtractWide(unsigned int dst_sz, unsigned int src_sz, tUInt64 src, unsigned int high_sz, unsigned int high, unsigned int low_sz, unsigned int low, tUWide &dst) { WideData srcW(src_sz, src); srcW.wop_extractWide(high, low, dst); } static inline void wop_primExtractWide(unsigned int dst_sz, unsigned int src_sz, tUWide & src, unsigned int high_sz, unsigned int high, unsigned int low_sz, unsigned int low, tUWide &dst) { src.wop_extractWide(high, low, dst); } /* Routines for managing copies of arguments to foreign functions */ // Copy a value into a temporary array unsigned int* copy_arg(const tUInt8* data, unsigned int n = 1); unsigned int* copy_arg(const tUInt32* data); unsigned int* copy_arg(const tUInt64* data, unsigned int n = 2); unsigned int* copy_arg(const unsigned int* data, unsigned int n); char* copy_arg(const std::string& str); // Allocate an uninitialized temporary array unsigned int* ignore_arg(unsigned int n); unsigned int* return_arg(unsigned int n); // Copy data from a return_arg call into the return data location tUInt8 write_return(unsigned int unused, tUInt8* data); tUInt32 write_return(unsigned int unused, tUInt32* data); tUInt64 write_return(unsigned int unused, tUInt64* data); // Delete all of the currently allocated argument copies void delete_arg_copies(); #endif /* __BS_PRIM_OPS__ */