diff options
Diffstat (limited to 'src/ppe/hwpf/plat/include/buffer.H')
-rw-r--r-- | src/ppe/hwpf/plat/include/buffer.H | 693 |
1 files changed, 517 insertions, 176 deletions
diff --git a/src/ppe/hwpf/plat/include/buffer.H b/src/ppe/hwpf/plat/include/buffer.H index 607107d..80b0f32 100644 --- a/src/ppe/hwpf/plat/include/buffer.H +++ b/src/ppe/hwpf/plat/include/buffer.H @@ -30,48 +30,118 @@ #ifndef __FAPI2_INTEGRAL_BUFFER__ #define __FAPI2_INTEGRAL_BUFFER__ -#include <buffer_base.H> +#include <buffer_parameters.H> +#include <buffer_traits.H> #include <return_code.H> namespace fapi2 { - /// @brief Class representing a FAPI buffer<T> - /// @note Buffers support method chaining. So, rather than - /// this - /// @code - /// buffer<T> mask; - /// mask.setBit<B>(); - /// mask.invert(); - /// my_buffer &= mask; - /// @endcode - /// You can do - /// @code - /// my_buffer &= buffer<T>().setBit<B>.invert(); - /// @endcode - template <typename T> - class buffer : public buffer_base<T> - { +/// @brief Class representing a FAPI buffer<T> +/// @tparam T, the integral type of the buffer (uint16_t, uint64_t, etc.) +template <typename T, typename TT = bufferTraits<T> > +class buffer +{ public: - /// Shortcut typedef to map to our traits class - typedef typename buffer_base<T, buffer>::bits_type bits_type; + /// Shortcut typedef to get to our traits class + typedef typename TT::bits_type bits_type; /// /// @brief Integral buffer assignment constructor /// @param[in] i_value initial value of the buffer /// Meaningless for variable types and thus protected. /// - inline buffer(T i_value = 0) + inline buffer(T i_value = 0): + iv_data(i_value) + { + } + + ~buffer(void) = default; + + #if !defined(DOXYGEN) && defined(FAPI2_DEBUG) + /// @brief Print the contents of the buffer to stdout + inline void print(void) const + { + TT::print(iv_data); + } + #endif + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator T() const + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator T&() + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline T& operator()(void) + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return Reference to the contents of the buffer + /// + inline const T& operator()(void) const + { + return iv_data; + } + + /// @name Buffer Manipulation Functions + ///@{ + + /// + /// @brief Set an OT of data in buffer + /// @param[in] i_value sizeof(OT) bits of data + /// @param[in] i_offset Start OT (start word, for example) in buffer + /// - defaults to 0 (will by default write the left most element) + /// @return FAPI2_RC_SUCCESS on success, FAPI2_RC_OVERFLOW otherwise + /// @note This is is only available for integral types. To set a + /// variable_buffer into a variable_buffer, use insert() + /// + template< typename OT> + inline fapi2::ReturnCode set(OT i_value, const bits_type i_offset = 0) + { + // Compile time check to make sure OT is integral + static_assert( std::is_integral<OT>::value, + "Input must be an integral type" ); + + const uint32_t length = TT:: template size<OT>(iv_data); + static const bits_type bits_in_value = parameterTraits<OT>::bit_length(); + const bits_type bit_length = TT::bit_length(iv_data); + + if (i_offset + bits_in_value >= bit_length) { - // Why not an initializer list? That would force buffer_base<T> - // to have a ctor which took a T, and I want to avoid that in - // the generic case: this makes it more clear that the two - // ctor's (integral and container) behave very differently. - // variable_buffers also have a ctor which takes a single - // numerical value, and that represents a bit count, not an - // initial value. - this->iv_data = i_value; + return FAPI2_RC_OVERFLOW; } + // Create mask if part of this byte is not in the valid part of the buffer, + // Shift it left by the amount of unused bits, + // Clear the unused bits + if (((i_offset + 1) == length) && (bit_length % bits_in_value)) + { + i_value &= parameterTraits<OT>::mask() << ((bits_in_value * length) - + bit_length); + } + + parameterTraits<OT>::template write_element<typename TT::unit_type> + (TT::get_address(iv_data), i_value, i_offset); + return FAPI2_RC_SUCCESS; + } /// @name Bit/Word Manipulation Functions ///@{ @@ -81,7 +151,9 @@ namespace fapi2 /// @return Length in bits /// inline constexpr uint32_t getBitLength(void) const - { return bufferTraits<T>::bit_length(this->iv_data); } + { + return TT::bit_length(iv_data); + } /// /// @brief Return the length of the buffer in OT units @@ -94,100 +166,198 @@ namespace fapi2 template< typename OT > inline constexpr uint32_t getLength(void) const { - return bufferTraits<T>::template size<OT>(this->iv_data); + return TT::template size<OT>(iv_data); } /// /// @brief Templated setBit for integral types /// @tparam B the bit number to set. + /// @tparam C the count of bits to set, defaults to 1 /// @return buffer& Useful for method chaining /// @note 0 is left-most /// @note Example: fapi2::buffer<uint64_t>().setBit<3>(); /// - template <bits_type B> + template< bits_type B, bits_type C = 1 > inline buffer& setBit(void) { static_assert((B >= 0) && - (B < bufferTraits<T>::bits_per_unit), "failed range check"); + ((B + C - 1) < TT::bits_per_unit()), "failed range check"); - // Force iv_data to be dependent on the template type to force - // its look up in the second phase - this->iv_data |= (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - B - 1); + // This would be a candidate for a fast_mask (see variable_buffer) but + // we'd need tables for all the integral types which maybe we need to + // do ... + iv_data |= (T(~0) >> (TT::bits_per_unit() - C)) << (TT::bits_per_unit() - B - + C); return *this; } /// + /// @brief Set a bit in the buffer + /// @param[in] i_bit the bit number to set. + /// @param[in] i_count the count of bits to set, defaults to 1 + /// @note 0 is left-most + /// @return FAPI2_RC_SUCCESS if OK + /// + inline fapi2::ReturnCode setBit(const bits_type& i_bit, + const bits_type& i_count = 1) + { + if ((i_count + i_bit - 1) >= TT::bits_per_unit()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + iv_data |= (T(~0) >> (TT::bits_per_unit() - i_count)) << + (TT::bits_per_unit() - i_bit - i_count); + + return FAPI2_RC_SUCCESS; + } + + /// /// @brief Clear a bit in buffer /// @tparam B Bit in buffer to clear. + /// @tparam C the count of bits to clear, defaults to 1 /// @return buffer& Useful for method chaining /// @note Asserting that all the parameters are known at /// compile time so this can be templated only. If that is not /// the case we can add a function parameter version. /// - template< bits_type B > + template< bits_type B, bits_type C = 1> inline buffer& clearBit(void) { static_assert((B >= 0) && - (B < bufferTraits<T>::bits_per_unit), "failed range check"); + ((B + C - 1)< TT::bits_per_unit()), "failed range check"); - this->iv_data &= buffer<T>().setBit<B>().invert(); + iv_data &= buffer<T>().setBit<B, C>().invert(); return *this; } /// - /// @brief Invert bit - /// @tparam B Bit in buffer to invert. + /// @brief Clear a bit in the buffer + /// @param[in] i_bit the bit number to clear. + /// @param[in] i_count the count of bits to clear, defaults to 1 + /// @note 0 is left-most + /// @return FAPI2_RC_SUCCESS if OK + /// + inline fapi2::ReturnCode clearBit(const bits_type& i_bit, + const bits_type& i_count = 1) + { + if ((i_count + i_bit - 1) >= TT::bits_per_unit()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + fapi2::buffer<T> l_scratch; + + if (l_scratch.setBit(i_bit, i_count) != FAPI2_RC_SUCCESS) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + iv_data &= l_scratch.invert(); + + return FAPI2_RC_SUCCESS; + } + + /// + /// @brief Write a bit in buffer to a given value + /// @tparam B Bit in buffer to write + /// @tparam C the count of bits to write, defaults to 1 /// @return buffer& Useful for method chaining /// @note Asserting that all the parameters are known at /// compile time so this can be templated only. If that is not /// the case we can add a function parameter version. /// - template< bits_type B > - inline buffer& flipBit(void) + template< bits_type B, bits_type C = 1 > + inline buffer& writeBit(const bool i_value) { static_assert((B >= 0) && - (B < bufferTraits<T>::bits_per_unit), "failed range check"); + ((B + C - 1)< TT::bits_per_unit()), "failed range check"); - this->iv_data ^= buffer<T>().setBit<B>(); + (i_value == 0) ? clearBit<B, C>() : setBit<B, C>(); return *this; } + /// - /// @brief Set a bit in the buffer - /// @param[in] i_bit the bit number to set. - /// @note 0 is left-most - /// @return FAPI2_RC_SUCCESS if OK + /// @brief Invert bit + /// @tparam B Bit in buffer to invert. + /// @tparam C the count of bits to flip, defaults to 1 + /// @return buffer& Useful for method chaining + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. /// - inline fapi2::ReturnCode setBit(const bits_type& i_bit) - { - if (i_bit >= bufferTraits<T>::bits_per_unit) - { - return FAPI2_RC_INVALID_PARAMETER; - } - - // Force iv_data to be dependent on the template type to force - // its look up in the second phase - this->iv_data |= - (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - i_bit - 1); - return FAPI2_RC_SUCCESS; - } + template< bits_type B, bits_type C = 1 > + inline buffer& flipBit(void) + { + static_assert((B >= 0) && + ((B + C - 1) < TT::bits_per_unit()), "failed range check"); + + iv_data ^= buffer<T>().setBit<B, C>(); + return *this; + } /// /// @brief Get the value of a bit in the buffer /// @tparam B Bit in buffer to get. - /// @return true if bit is on, false if bit is off + /// @tparam C the count of bits to get, defaults to 1 + /// @return true if *any* bit is on, false if *every* bit is off /// - template< bits_type B > + template< bits_type B, bits_type C = 1> inline bool getBit(void) const - { - return buffer<T>().setBit<B>() & this->iv_data; - } + { + return buffer<T>().setBit<B, C>() & iv_data; + } + + /// + /// @brief Set and entire buffer to X's + /// @tparam X {0,1} depending if you want to clear (0) + /// or fill (1) a buffer + /// @return buffer_base&, Useful for method chaining + /// + template< uint8_t X > + inline buffer& flush(void) + { + static_assert( (X == 1) || (X == 0), "bad argument to flush" ); + (0 == X) ? TT::clear(iv_data) : TT::set(iv_data); + return *this; + } + + /// + /// @brief Invert entire buffer + /// @return buffer_base&, Useful for method chaining + /// + inline buffer& invert(void) + { + TT::invert(iv_data); + return *this; + } + + /// + /// @brief Bit reverse entire buffer + /// @return buffer_base&, Useful for method chaining + /// + inline buffer& reverse(void) + { + TT::reverse(iv_data); + return *this; + } + ///@} /// @name Buffer Manipulation Functions ///@{ + /// + /// @brief Get a pointer to the buffer bits + /// @return Pointer to the buffer itself + /// + inline T* pointer(void) + { + return &iv_data; + } + // Note: Many (all?) of these are not needed and the compiler complains // as the cast to T yields a better operator. There are here mainly for // documenation purposes. @@ -195,104 +365,102 @@ namespace fapi2 /// /// @brief operator>>() /// -#ifdef DOXYGEN - buffer<T>& operator>>(bits_type i_shiftnum); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator>>(bits_type i_shiftnum); + #endif /// /// @brief operator<<() /// -#ifdef DOXYGEN - buffer<T>& operator<<(bits_type i_shiftnum); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator<<(bits_type i_shiftnum); + #endif /// /// @brief operator+() /// -#ifdef DOXYGEN - buffer<T>& operator+(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator+(const T& rhs); + #endif /// /// @brief operator+=() /// -#ifdef DOXYGEN - buffer<T>& operator+=(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator+=(const T& rhs); + #endif /// /// @brief operator|=() /// -#ifdef DOXYGEN - buffer<T>& operator|=(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator|=(const T& rhs); + #endif /// /// @brief operator&=() /// -#ifdef DOXYGEN - buffer<T>& operator&=(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator&=(const T& rhs); + #endif /// /// @brief operator|() /// -#ifdef DOXYGEN - buffer<T>& operator|(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator|(const T& rhs); + #endif /// /// @brief operator&() /// -#ifdef DOXYGEN - buffer<T>& operator&(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator&(const T& rhs); + #endif /// /// @brief operator^=() /// -#ifdef DOXYGEN - buffer<T>& operator^=(const T& rhs); -#endif + #ifdef DOXYGEN + inline buffer<T>& operator^=(const T& rhs); + #endif /// /// @brief operator~() /// -#ifdef DOXYGEN - buffer<T>& operator~(const T& rhs) const; -#endif + #ifdef DOXYGEN + inline buffer<T>& operator~(const T& rhs) const; + #endif /// /// @brief operator==() /// -#ifdef DOXYGEN - bool operator==(const T& rhs) const; -#endif + #ifdef DOXYGEN + inline bool operator==(const T& rhs) const; + #endif /// /// @brief operator!=() /// -#ifdef DOXYGEN - bool operator!=(const T& rhs) const; -#endif + #ifdef DOXYGEN + inline bool operator!=(const T& rhs) const; + #endif /// /// @brief Copy part of a OT into the DataBuffer /// @tparam TS Start bit to insert into (target start) /// @tparam L Length of bits to insert - /// @tparam SS Start bit in source + /// @tparam SS Start bit in source - defaults to bit 0 /// @tparam OT the type of the incoming (origin) data /// @param[in] i_datain OT value to copy into DataBuffer /// - data is taken left aligned - /// @note Asserting that all the parameters are known at - /// compile time so this can be templated only. If that is not - /// the case we can add a function parameter version. + /// @return buffer& Useful for method chaining /// - template<bits_type TS, bits_type L, bits_type SS, typename OT> - inline void insert(const OT i_datain) + template<bits_type TS, bits_type L, bits_type SS = 0, typename OT> + inline buffer& insert(const OT i_datain) { - const bits_type target_length = parameterTraits<T>::bit_length; - const bits_type source_length = parameterTraits<OT>::bit_length; + const bits_type target_length = parameterTraits<T>::bit_length(); + const bits_type source_length = parameterTraits<OT>::bit_length(); // Error if input data don't make sense static_assert((TS + L) <= target_length, @@ -304,49 +472,109 @@ namespace fapi2 static_assert(SS < source_length, "insert(): Source Start is out of bounds"); + // Normalize the input to 2 64 bit integers and adjust the starts accordingly + uint64_t source = static_cast<uint64_t>(i_datain); + const uint64_t target = static_cast<uint64_t>(iv_data); + + const bits_type source_start = parameterTraits<uint64_t>::bit_length() - + (source_length - SS); + const bits_type target_start = parameterTraits<uint64_t>::bit_length() - + (target_length - TS); + // Get mask value for Target buffer - // Note: Need "& ((T)-1) because bit shift left for Target buffer doesn't roll off - T mask =((T(~0) << (target_length - L)) & T(~0)) >> TS; + // Note: Need "& 0UL" because bit shift left for Target buffer doesn't roll off + uint64_t mask = ((~0UL << (parameterTraits<uint64_t>::bit_length() - L)) & ~0UL) + >> target_start; - // Calculate the equivalent position of the input Source start for the size of the Target buffer. + // Align the source to the target. Make things signed so we know which way to shift. + int32_t shift = source_start - target_start; - // Assume OT is smaller (sizeof(T) > sizeof(OT)) - uint64_t sourceShift = abs(TS - ((target_length - source_length) + SS)); - uint64_t sourceAlign = T(i_datain) << sourceShift; + if (shift > 0) + { + source <<= shift; + } + else + { + shift = target_start - source_start; + source >>= shift; + } + + iv_data = ((target & ~mask) | (source & mask)); + return *this; + } + + /// + /// @brief Copy part of a OT into the DataBuffer + /// @tparam OT the type of the incoming (origin) data + /// @param[in] i_datain OT value to copy into DataBuffer + /// - data is taken left aligned + /// @param[in] Start bit to insert into (target start) + /// @param[in] Length of bits to insert + /// @param[in] Start bit in source - defaults to bit 0 + + /// @return FAPI2_RC_SUCCESS if successful + /// + template<typename OT> + fapi2::ReturnCode insert(const OT i_datain, const bits_type i_targetStart, + const bits_type i_len, const bits_type i_sourceStart = 0) + { + const bits_type target_length = parameterTraits<T>::bit_length(); + const bits_type source_length = parameterTraits<OT>::bit_length(); + + // Error if input data don't make sense + if ((i_targetStart + i_len) > target_length) + { + FAPI_ERR("insert(): (Target Start + Len) is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; + } + + if ((i_sourceStart + i_len) > source_length) + { + FAPI_ERR("insert(): (Source Start + Len) is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; + } + + if (i_targetStart >= target_length) + { + FAPI_ERR("insert(): Target Start is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; + } - if (sizeof(T) == sizeof(OT)) + if (i_sourceStart >= source_length) { - sourceShift = abs(SS - TS); - sourceAlign = (SS > TS) ? ((T)i_datain) << sourceShift : ((T)i_datain) >> sourceShift; + FAPI_ERR("insert(): Source Start is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; } - if (sizeof(T) < sizeof(OT)) + // Normalize the input to 2 64 bit integers and adjust the starts accordingly + uint64_t source = static_cast<uint64_t>(i_datain); + const uint64_t target = static_cast<uint64_t>(iv_data); + + const bits_type source_start = parameterTraits<uint64_t>::bit_length() - + (source_length - i_sourceStart); + const bits_type target_start = parameterTraits<uint64_t>::bit_length() - + (target_length - i_targetStart); + + // Get mask value for Target buffer + // Note: Need "& 0UL" because bit shift left for Target buffer doesn't roll off + uint64_t mask = ((~0UL << (parameterTraits<uint64_t>::bit_length() - i_len)) & + ~0UL) >> target_start; + + // Align the source to the target. Make things signed so we know which way to shift. + int32_t shift = source_start - target_start; + + if (shift > 0) { - sourceShift = source_length - target_length; - if (SS <= sourceShift) - { - sourceShift = sourceShift + TS - SS; - sourceAlign = ((OT)i_datain) >> sourceShift; - } - - // (SS > sourceShift) - else - { - if (sourceShift > TS) - { - sourceShift = SS - sourceShift - TS; - sourceAlign = OT(i_datain) << sourceShift; - } - else - { - sourceShift = SS - sourceShift; - sourceAlign = (sourceShift < TS) ? OT(i_datain) >> sourceShift : OT(i_datain); - } - } + source <<= shift; + } + else + { + shift = target_start - source_start; + source >>= shift; } - this->iv_data = (this->iv_data & ~mask) | (sourceAlign & mask); - return; + iv_data = ((target & ~mask) | (source & mask)); + return FAPI2_RC_SUCCESS; } /// @@ -356,68 +584,181 @@ namespace fapi2 /// @tparam OT the type of the incoming (origin) data /// @param[in] i_datain OT value to copy into DataBuffer /// - data is taken right aligned + /// @return buffer& Useful for method chaining /// @note Data is assumed to be aligned on the word boundary of L - /// @note Asserting that all the parameters are known at - /// compile time so this can be templated only. If that is not - /// the case we can add a function parameter version. /// template<bits_type TS, bits_type L, typename OT> - inline void insertFromRight(const OT i_datain) + inline buffer& insertFromRight(const OT i_datain) { // Error if input data don't make sense - static_assert(L <= parameterTraits<OT>::bit_length, - "insertFromRight(): Len >= input buffer"); - static_assert(TS < parameterTraits<T>::bit_length, + static_assert(L <= parameterTraits<OT>::bit_length(), + "insertFromRight(): Len > input buffer"); + static_assert(TS < parameterTraits<T>::bit_length(), "insertFromRight(): Target Start is out of bounds"); - static_assert((TS + L) <= parameterTraits<T>::bit_length, + static_assert((TS + L) <= parameterTraits<T>::bit_length(), "InsertFromRight(): (Target Start + Len) is out of bounds"); - this->insert<TS, L, parameterTraits<OT>::bit_length - L>(i_datain); - return; + this->insert<TS, L, parameterTraits<OT>::bit_length() - L>(i_datain); + return *this; + } + + /// + /// @brief Copy in a right aligned value + /// @tparam OT the type of the incoming (origin) data + /// @param[in] i_datain OT value to copy into DataBuffer + /// - data is taken right aligned + /// @param[in] Start bit to insert into + /// @param[in] Length of bits to insert + /// @return FAPi2_RC_SUCCESS if no error + /// @note Data is assumed to be aligned on the word boundary of L + /// + template<typename OT> + fapi2::ReturnCode insertFromRight(const OT i_datain, + const bits_type i_targetStart, + const bits_type i_len) + { + // Error if input data don't make sense + if ((i_targetStart + i_len) > parameterTraits<T>::bit_length()) + { + FAPI_ERR("insertFromRight(): (Target Start + Len) is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; + } + + if (i_targetStart >= parameterTraits<T>::bit_length()) + { + FAPI_ERR("insertFromRight(): Target Start is out of bounds"); + return FAPI2_RC_INVALID_PARAMETER; + } + + if (i_len > parameterTraits<OT>::bit_length()) + { + FAPI_ERR("insertFromRight(): Len > input buffer"); + return FAPI2_RC_INVALID_PARAMETER; + } + + return this->insert(i_datain, i_targetStart, i_len, + parameterTraits<OT>::bit_length() - i_len); } /// /// @brief Copy data from this buffer into an OT - /// @tparam TS Start bit to insert into (target start) + /// @tparam SS Start bit in source /// @tparam L Length of bits to insert + /// @tparam TS Start bit to insert into (target start) + /// @tparam OT the type of the outgoing (target) + /// @param[out] o_out OT to copy into - data is placed left aligned + /// @return const buffer& Useful for method chaining + /// + template<bits_type SS, bits_type L, bits_type TS = 0, typename OT> + inline const buffer& extract(OT& o_out) const + { + // Extraction is just an insert into o_out + + buffer<OT> out(o_out); + out.insert<TS, L, SS>(iv_data); + o_out = out; + return *this; + } + + /// + /// @brief Copy data from this buffer into an OT /// @tparam SS Start bit in source + /// @tparam L Length of bits to insert + /// @tparam TS Start bit to insert into (target start) /// @tparam OT the type of the outgoing (target) /// @param[out] o_out OT to copy into - data is placed left aligned - /// @note Asserting that all the parameters are known at - /// compile time so this can be templated only. If that is not - /// the case we can add a function parameter version. + /// @return buffer& Useful for method chaining /// - template<bits_type TS, bits_type L, bits_type SS, typename OT> - inline void extract(OT& o_out) + template<bits_type SS, bits_type L, bits_type TS = 0, typename OT> + inline buffer& extract(OT& o_out) { // Extraction is just an insert into o_out buffer<OT> out(o_out); - out.insert<TS, L, SS>(this->iv_data); + out.insert<TS, L, SS>(iv_data); o_out = out; - return; + return *this; + } + + /// + /// @brief Copy data from this buffer into an OT + /// @tparam OT the type of the outgoing (target) + /// @param[out] o_out OT to copy into - data is placed left aligned + /// @param[in] Start bit in source + /// @param[in] Length of bits to extract + /// @param[in] Start bit to insert into (target start) + /// @return FAPI2_RC_SUCCESS if ok + /// + template<typename OT> + fapi2::ReturnCode extract(OT& o_out, const bits_type i_sourceStart, + const bits_type i_len, const bits_type i_targetStart = 0) const + { + // Extraction is just an insert into o_out + + buffer<OT> out(o_out); + + if (out.insert(iv_data, i_targetStart, i_len, + i_sourceStart) != FAPI2_RC_SUCCESS) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + o_out = out; + return FAPI2_RC_SUCCESS; } -#if 0 /// /// @brief Copy data from this buffer into an OT and right justify - /// @tparam OT the type of the outgoing data - defaults to T - /// @tparam SB Start bit to insert into - defaults to 0 - /// @tparam SS Start bit in o_out - default value is zero - /// @tparam L Length of bits to copy - defaults to sizeof(OT) * 8 + /// @tparam SS Start bit to insert into (source start) + /// @tparam L Length of bits to extract + /// @tparam OT the type of the outgoing (target) /// @param[out] o_out OT to copy into - data is placed right aligned - /// @note Asserting that all the parameters are known at - /// compile time so this can be templated only. If that is not - /// the case we can add a function parameter version. - /// @post Data is copied from specified location to o_out, right - /// aligned. Data is only right aligned if L < sizeof(bits_type) + /// @return const buffer& Useful for method chaining /// - template< typename OT = T, bits_type L = parameterTraits<OT>::bit_length, - bits_type SB = 0, bits_type SS = 0 > - void extractFromRight(OT& o_out); -#endif + template<bits_type SS, bits_type L, typename OT> + inline const buffer& extractToRight(OT& o_out) const + { + extract<SS, L, parameterTraits<OT>::bit_length() - L>(o_out); + return *this; + } + + /// + /// @brief Copy data from this buffer into an OT and right justify + /// @tparam SS Start bit to insert into (source start) + /// @tparam L Length of bits to extract + /// @tparam OT the type of the outgoing (target) + /// @param[out] o_out OT to copy into - data is placed right aligned + /// @return buffer& Useful for method chaining + /// + template<bits_type SS, bits_type L, typename OT> + inline buffer& extractToRight(OT& o_out) + { + extract<SS, L, parameterTraits<OT>::bit_length() - L>(o_out); + return *this; + } + + /// + /// @brief Copy data from this buffer into an OT and right justify + /// @tparam OT the type of the outgoing (target) + /// @param[out] o_out OT to copy into - data is placed right aligned + /// @param[in] Start bit to insert into (source start) + /// @param[in] Length of bits to insert + /// @return FAPI2_RC_SUCCESS if ok + /// + template<typename OT> + fapi2::ReturnCode extractToRight(OT& o_out, const bits_type i_sourceStart, + const bits_type i_len) const + { + return extract(o_out, i_sourceStart, i_len, + parameterTraits<OT>::bit_length() - i_len); + } + ///@} - }; + + private: + /// The contents of the buffer + T iv_data; }; +} #endif |