diff options
author | Shakeeb <shakeebbk@in.ibm.com> | 2016-09-01 06:24:44 -0500 |
---|---|---|
committer | AMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com> | 2016-09-01 07:48:28 -0400 |
commit | 5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2 (patch) | |
tree | b3d6cd12b5eb0c92404ae5ac0352bb360b38fa95 /src/import/hwpf/fapi2/include/variable_buffer.H | |
parent | 1008ef70a71fcfdec398ff30923d5025991c85f4 (diff) | |
download | talos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.tar.gz talos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.zip |
SBE move import`
Change-Id: I726951318cdb19fd445af2f7910e0d6872eff18c
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/29086
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Sachin Gupta <sgupta2m@in.ibm.com>
Reviewed-by: AMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com>
Diffstat (limited to 'src/import/hwpf/fapi2/include/variable_buffer.H')
-rw-r--r-- | src/import/hwpf/fapi2/include/variable_buffer.H | 1291 |
1 files changed, 1291 insertions, 0 deletions
diff --git a/src/import/hwpf/fapi2/include/variable_buffer.H b/src/import/hwpf/fapi2/include/variable_buffer.H new file mode 100644 index 00000000..e32c69e7 --- /dev/null +++ b/src/import/hwpf/fapi2/include/variable_buffer.H @@ -0,0 +1,1291 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: import/hwpf/fapi2/include/variable_buffer.H $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file variable_buffer.H + * @brief definitions for fapi2 variable length buffers + */ + +#ifndef __FAPI2_VARIABLE_BUFFER__ +#define __FAPI2_VARIABLE_BUFFER__ + +#include <buffer_parameters.H> +#include <buffer_traits.H> +#include <return_code_defs.H> +#include <plat_trace.H> + +namespace fapi2 +{ + +// forward fapi2::Assert() +extern void Assert(bool); + + +/// @brief Get a 32 bit mask quickly +// This is one of the main reasons we static_assert in the ctor's +// to ensure the unit_type is 32 bits. +inline uint32_t fast_mask32(int32_t i_pos, int32_t i_len) +{ + // generates an arbitrary 32-bit mask using two operations, not too shabby + + static const uint32_t l_mask32[] = + { + 0x00000000, + 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, + 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, + 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, + 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, + 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, + 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, + 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, + 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, + }; + return l_mask32[i_len] >> i_pos; +} + +// +// General set a series of bits in the buffer. +// + +/// +/// @cond +/// @brief Internal bit inserting method. +/// @tparam unit_type The type of a unit of the arrays +/// @tparam bits_type The type of the bit counting values +/// @param[in] i_source The incoming data +/// @param[in] i_source_length The length in bits of the incoming data +/// @param[in] i_target The outgoing data +/// @param[in] i_target_length The length in bits of the outgoing data +/// @param[in] i_source_start_bit The starting bit location in the +/// incoming data +/// @param[in] i_target_start_bit The starting bit position in this +/// @param[in] i_length The length, in bits, the user wants copied. +/// +template<typename unit_type, typename bits_type, typename output_type> +inline fapi2::ReturnCodes _insert(const unit_type* i_source, + bits_type i_source_length, + output_type* i_target, + bits_type i_target_length, + bits_type i_source_start_bit, + bits_type i_target_start_bit, + bits_type i_length) +{ + const bits_type bits_per_input_unit = parameterTraits<unit_type>::bit_length(); + const bits_type bits_per_output_unit = parameterTraits<output_type>::bit_length(); + + // targetStart is defaulted to the sizeof(target) - (sizeof(source) - i_source_start_bit) + // which makes this act like insert from right + if (i_target_start_bit == static_cast<bits_type>(~0)) + { + i_target_start_bit = (i_target_length - (i_source_length - i_source_start_bit)); + } + + // len defaults to (sizeof(OT) * 8) - i_source_start_bit + if (i_length == static_cast<bits_type>(~0)) + { + i_length = i_source_length - i_source_start_bit; + } + + // Check for overflow + if ((i_length + i_target_start_bit > i_target_length) || + (i_length + i_source_start_bit > i_source_length)) + { + return fapi2::FAPI2_RC_OVERFLOW; + } + + do + { + const bits_type src_idx = i_source_start_bit / bits_per_input_unit; + const bits_type trg_idx = i_target_start_bit / bits_per_output_unit; + + // "slop" = unaligned bits + const bits_type src_slop = i_source_start_bit % bits_per_input_unit; + const bits_type trg_slop = i_target_start_bit % bits_per_output_unit; + + // "cnt" = largest number of bits to be moved each pass + bits_type cnt = std::min(i_length, bits_per_input_unit); + cnt = std::min(cnt, bits_per_input_unit - src_slop); + cnt = std::min(cnt, bits_per_output_unit - trg_slop); + + // generate the source mask only once + bits_type mask = fast_mask32(src_slop, cnt); + + // read the source bits only once + bits_type src_bits = i_source[src_idx] & mask; + + // "shift" = amount of shifting needed for target alignment + int32_t shift = trg_slop - src_slop; + + if (shift < 0) + { + src_bits <<= -shift; + mask <<= -shift; + } + else + { + src_bits >>= shift; + mask >>= shift; + } + + // clear source '0' bits in the target + i_target[trg_idx] &= ~mask; + + // set source '1' bits in the target + i_target[trg_idx] |= src_bits; + + i_source_start_bit += cnt; + i_target_start_bit += cnt; + + i_length -= cnt; + + } + while (0 < i_length); + + return fapi2::FAPI2_RC_SUCCESS; +} +/// @endcond + +/// @brief Class representing a FAPI variable_buffer. +/// @remark Variable buffers are buffers which can be variable in length +/// (and "odd sized.") These best represent the FAPI 1.X ecmdDataBuffer, +/// however they are implemented using the same template techniques +/// as the new fapi::buffer. +/// @note Variable buffers are not (presently) declared as std::bitset +/// as bitsets' size is fixed at runtime. It is not clear if this is +/// acceptable for variable_buffers at this time. +/// @note Variable buffers are implemented as a std::vector of uint32_t +/// as this keeps simple compatibility with ecmdDataBuffers. Cronus (at +// least) needs to interwork the two. +class variable_buffer +{ + + public: + + /// Shortcut typedef to get to our traits class + typedef typename bufferTraits<bits_container>::bits_type bits_type; + /// Shortcut typedef to get to our traits class + typedef typename bufferTraits<bits_container>::unit_type unit_type; + + /// + /// @brief Variable buffer constructor + /// @param[in] i_value number of *bits* (sizeof(uint_type) * 8) + /// needed. + inline variable_buffer(bits_type i_value = 0): + iv_data(_vector_size(i_value)), + iv_perceived_bit_length(i_value) + { + static_assert(std::is_same<unit_type, uint32_t>::value, + "code currently needs unit_type to be a unit32_t"); + } +#ifndef NO_INITIALIZER_LIST + /// + /// @brief Variable buffer list constructor + /// @param[in] i_value an initializer list to initialize the container. + /// @warning Input data is assumed to be right-aligned and must be 32 bits + /// + inline variable_buffer(const std::initializer_list<unit_type>& i_value): + iv_data(i_value), + iv_perceived_bit_length(i_value.size() * sizeof(unit_type) * 8) + { + static_assert(std::is_same<unit_type, uint32_t>::value, + "code currently needs unit_type to be a unit32_t"); + } +#endif + /// + /// @brief Variable buffer copy constructor + /// @param[in] i_buffer the buffer to copy from + /// + inline variable_buffer(const variable_buffer& i_buffer) + { + iv_perceived_bit_length = i_buffer.iv_perceived_bit_length; + iv_data = i_buffer.iv_data; + } + + /// + /// @brief Variable buffer move constructor + /// @param[in] i_buffer the buffer to move + /// + inline variable_buffer(variable_buffer&& i_buffer) + { + iv_perceived_bit_length = i_buffer.iv_perceived_bit_length; + i_buffer.iv_perceived_bit_length = 0; + iv_data = std::move(i_buffer.iv_data); + } + + /// + /// @brief Variable buffer array constructor + /// @param[in] i_value a uint32_t array to initialize the container. + /// @param[in] i_length the length of the array in 32-bit words + /// @param[in] i_bit_length the length of the resulting buffer in bits. + /// @warning This assumes the underlying container of a variable_buffer + /// is a uint32_t - which it is. + /// @note To use this constructor given an ecmdDataBuffer, you would + /// ecmd.memCopyOut( buffer, ... ); + /// variable_buffer( buffer, ecmd.getCapacity(), ecmd.getBitLength()); + /// + inline variable_buffer(const uint32_t* i_value, const uint32_t i_length, + const uint32_t i_bit_length): + iv_perceived_bit_length(i_bit_length) + { + static_assert(std::is_same<unit_type, uint32_t>::value, + "code currently needs unit_type to be a unit32_t"); + + // Copy the array in to our vector. + iv_data.insert(iv_data.end(), i_value, &i_value[i_length]); + } + + +#if !defined(DOXYGEN) && defined(FAPI2_DEBUG) + /// @brief Print the contents of the buffer to stdout + inline void print(void) const + { + bufferTraits<bits_container>::print(iv_data); + } +#endif + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator bits_container() const + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator bits_container& () + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline bits_container& operator()(void) + { + return iv_data; + } + + /// + /// @brief Get the contents of the buffer + /// @return Reference to the contents of the buffer + /// + inline const bits_container& operator()(void) const + { + return iv_data; + } + + /// @name Buffer Manipulation Functions + ///@{ + + /// + /// @brief Set an OT of data in buffer. + /// + /// It is possible to write the incomplete last OT of a buffer that's not + /// an integer multiple of OT's size in bits; in that case, the value will + /// be treated left aligned and truncated. + /// + /// @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 + /// + template< typename OT> + inline fapi2::ReturnCodes 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 bits_type bits_in_value = parameterTraits<OT>::bit_length(); + const bits_type bit_offset = i_offset * bits_in_value; + + if (bit_offset >= iv_perceived_bit_length) + { + return FAPI2_RC_OVERFLOW; + } + + const bits_type available_space = iv_perceived_bit_length - bit_offset; + + return insert<OT>( i_value, (i_offset * bits_in_value), std::min(available_space, bits_in_value), 0); + + } + + /// + /// @brief Get an OT of data from buffer + /// + /// It is possible to read the incomplete last OT of a buffer that's not + /// an integer multiple of OT's size in bits; in that case, the return + /// value will contain the remaining bits left-aligned. + /// + /// @tparam OT the type of the data to get + /// @param[in] i_offset Start OT (start word, for example) in buffer + /// - defaults to 0 (will by default read the left most element) + /// @return OT + /// @note uint8_t b = get<uint8_t>(N) <- gets the N'th left byte from the buffer + /// + template< typename OT> + inline OT get(const bits_type i_offset = 0) const; + + /// @name Bit/Word Manipulation Functions + ///@{ + + /// + /// @brief Return the length of the buffer in bits + /// @return Length in bits + /// + inline uint32_t getBitLength(void) const + { + return iv_perceived_bit_length; + } + + /// + /// @brief Return the length of the buffer in OT units + /// @return Length in OT units rounded up + /// @tparam OT the type to get the length of. For example, if one + /// wanted the length in double words, OT would be uint64_t + /// (getLength<uint64_t>().) Similarly, to get the length in words, + /// getLength<uin32_t>(). + /// + template< typename OT > + inline uint32_t getLength(void) const + { + static const uint32_t bits_in_ot = sizeof(OT) * 8; + return (getBitLength() + (bits_in_ot - 1)) / bits_in_ot; + } + + /// + /// @brief Set a bit in buffer + /// @tparam SB Start bit in buffer to clear. + /// @tparam L Number of consecutive bits from start bit to + /// clear + /// @return FAPI2_RC_SUCCESS on success + inline fapi2::ReturnCodes setBit( const bits_type SB, bits_type L = 1) + { + + ReturnCodes rc; + // make sure we stay within our container + fapi2::Assert((L > 0) && ((SB + L) <= this->iv_perceived_bit_length) ); + + uint32_t mask = 0; + + // last bit to check + bits_type EB = SB + L - 1; + + // index where first bit to check is located + bits_type start_index = SB / bits_per_unit; + + // index where last bit is located + bits_type end_index = EB / bits_per_unit; + + if( start_index == end_index ) + { + // normalize our SB to be within a unit + bits_type TempSB = SB - (start_index * bits_per_unit); + + // grab a mask from SB for L number of bits. + mask = fast_mask32(TempSB, L); + + iv_data[start_index] |= mask; + + rc = FAPI2_RC_SUCCESS; + + } + else + { + // the bits span more than one internal unit, need to break + // it up to process it. + + // make TempSB point to the start of the next unit, adjust the + // length and go again, process the bits in the previous index + // when we get back. + bits_type TempSB = (start_index + 1) * bits_per_unit; + bits_type TempL = EB - TempSB + 1; + + rc = this->setBit( TempSB, TempL ); + + if(rc == FAPI2_RC_SUCCESS) + { + // now check the bits in the previous index up to the next index. + // normalize our SB to be within a unit + TempSB = SB - (start_index * bits_per_unit); + + // get a mask for the new SB location to the end of this unit. + mask = fast_mask32(TempSB, L - TempL); + + // merge theses bits with the others. + iv_data[start_index] |= mask; + } + + } + + return rc; + } + + /// + /// @brief Clear a bit in buffer + /// @tparam SB Start bit in buffer to clear. + /// @tparam L Number of consecutive bits from start bit to + /// clear + /// @return FAPI2_RC_SUCCESS on success + /// @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::ReturnCodes clearBit(bits_type SB, bits_type L = 1) + { + ReturnCodes rc = invert().setBit(SB, L); + + invert(); + + return rc; + } + + /// + /// @brief invert a bit or range of bits in a buffer + /// @tparam SB Start bit in buffer to invert. + /// @tparam L Number of consecutive bits from start bit to + /// invert, defaults to 1 + /// @return FAPI2_RC_SUCCESS on success + /// + inline fapi2::ReturnCodes flipBit( bits_type SB, bits_type L = 1) + { + ReturnCodes rc; + + // make sure we are within our container + if((SB + L) <= this->iv_perceived_bit_length) + { + // loop for L bits flipping as you go + for( bits_type i = 0; i < L; i++) + { + bits_type bit = SB + i; + + if(this->isBitSet(bit)) + { + rc = this->clearBit(bit); + } + else + { + rc = this->setBit(bit); + } + } + } + else + { + rc = FAPI2_RC_OVERFLOW; + } + + return rc; + } + + /// + /// @brief Get the value of a bit in the buffer + /// @tparam B Bit in buffer to get. + /// @return true/1 if bit is on, false/0 if bit is off + /// @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 bool getBit(void) const + { + const bits_type index = B / bits_per_unit; + const unit_type mask = unit_type(1) << + ((bits_per_unit - 1) - (B - (index * bits_per_unit))); + return iv_data[index] & mask; + } + + /// + /// @brief Test if multiple bits are set + /// @param SB Start bit in buffer to test. + /// @param L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// @return true if all bits in range are set - false if any + /// bit is clear + /// @note Example: fapi2::buffer<uint64_t>().isBitSet(4,3); + inline bool isBitSet( bits_type SB, bits_type L = 1 ) const + { + // make sure we stay within our container + fapi2::Assert( ((L > 0) && ((SB + L) <= this->iv_perceived_bit_length)) ); + + bool is_set = false; + uint32_t mask = 0; + + // last bit to check + bits_type EB = SB + L - 1; + + // index where first bit to check is located + bits_type start_index = SB / bits_per_unit; + + // index where last bit is located + bits_type end_index = EB / bits_per_unit; + + if( start_index == end_index ) + { + // normalize our SB to be within a unit + bits_type TempSB = SB - (start_index * bits_per_unit); + + // grab a mask from SB for L number of bits. + mask = fast_mask32(TempSB, L); + + is_set = + (( iv_data[start_index] & mask) == mask ) ? true : false; + + } + else + { + // the bits span more than one internal unit, need to break + // it up to process it. + + // make TempSB point to the start of the next unit, adjust the + // length and go again, process the bits in the previous index + // when we get back. + bits_type TempSB = (start_index + 1) * bits_per_unit; + bits_type TempL = EB - TempSB + 1; + + is_set = this->isBitSet( TempSB, TempL ); + + // now check the bits in the previous index up to the next index. + // normalize our SB to be within a unit + TempSB = SB - (start_index * bits_per_unit); + + // get a mask for the new SB location to the end of this unit. + mask = fast_mask32(TempSB, L - TempL); + + // test these bits against the others.. + is_set &= + (( iv_data[start_index] & mask) == mask ) ? true : false; + + } + + return is_set; + } + + /// + /// @brief Test if multiple bits are clear + /// @param SB Start bit in buffer to test. + /// @param L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// @return true if bit is clear - false if bit is set + /// + inline bool isBitClear( bits_type SB, bits_type L = 1 ) const + { + variable_buffer l_buf = *this; + + return l_buf.invert().isBitSet(SB, L); + } + + /// + /// @brief Count number of bits set in a range + /// @tparam SB Start bit in buffer to test. + /// @tparam L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// + inline bits_type getNumBitsSet(bits_type SB, bits_type L = 1) const + { + bits_type number_of_bits_set = 0; + + for(bits_type i = 0; i < L; i++) + { + if( this->isBitSet(SB + i) ) + { + number_of_bits_set++; + } + } + + return number_of_bits_set; + } + + /// + /// @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 variable_buffer&, Useful for method chaining + /// + template< uint8_t X > + inline variable_buffer& flush(void) + { + static_assert( (X == 1) || (X == 0), "bad argument to flush" ); + (0 == X) ? bufferTraits<bits_container>::clear(iv_data) : bufferTraits<bits_container>::set(iv_data); + return *this; + } + + /// + /// @brief Invert entire buffer + /// @return variable_buffer&, Useful for method chaining + /// + inline variable_buffer& invert(void) + { + bufferTraits<bits_container>::invert(iv_data); + return *this; + } + + ///@} + + /// @name Buffer Manipulation Functions + ///@{ + + /// + /// @brief Shift a buffer left a defined number of bits, from a start bit + /// @param[in] i_shiftNum number of bits to shift + /// @param[in] i_offset offset from 0 to start shift, defaults to ~0 (see operator<<()) + /// @note an offset of ~(0) implies "end of the buffer" + /// @warning there is no shiftLeftandResize - resizing the buffer is left to + /// the caller to alight the operations with integral buffers. + /// @return FAPI2_RC_SUCCESS on success + /// + inline ReturnCodes shiftLeft(bits_type i_shiftNum, bits_type i_offset = ~0); + + /// + /// @brief Shift a buffer right a defined number of bits, from a start bit + /// @param[in] i_shiftNum number of bits to shift + /// @param[in] i_offset offset from 0 to start shift, defaults to 0 (see operator>>()) + /// @warning there is no shiftRightandResize - resizing the buffer is left to + /// the caller to alight the operations with integral buffers. + /// @return FAPI2_RC_SUCCESS on success + /// + inline ReturnCodes shiftRight(bits_type i_shiftNum, bits_type i_offset = 0); + + /// + /// @brief move operator=() + /// @note To use: new_buffer = std::move(old_buffer). old_buffer will be + /// destroyed and no copy will be made (moved) + /// + inline variable_buffer& operator=(variable_buffer&& other) + { + iv_perceived_bit_length = other.iv_perceived_bit_length; + other.iv_perceived_bit_length = 0; + iv_data = std::move(other.iv_data); + return *this; + } + + /// + /// @brief operator=() + /// + inline variable_buffer& operator=(const variable_buffer& other) + { + iv_perceived_bit_length = other.iv_perceived_bit_length; + iv_data = other.iv_data; + return *this; + } + + /// + /// @brief operator>>() + /// + inline variable_buffer& operator>>(bits_type i_shiftnum) + { + // This is just a right shift from the begining of the buffer + // Why void? Well, there's no place to return the return + // code and in reality the only problem which can arise + // is the offset is out of bounds. But since we're hard-wiring it + // to 0, it can't be out of bounds. So there's no real problem + // which can arise here. + static_cast<void>(shiftRight(i_shiftnum)); + return *this; + } + + /// + /// @brief operator<<() + /// + inline variable_buffer& operator<<(bits_type i_shiftnum) + { + // This is just a left shift from the end of the buffer + // Why void? Well, there's no place to return the return + // code and in reality the only problem which can arise + // is the offset is out of bounds. But since we're hard-wiring it + // to 0, it can't be out of bounds. So there's no real problem + // which can arise here. + static_cast<void>(shiftLeft(i_shiftnum)); + return *this; + } + + + /// + /// @brief operator+() + /// @param[in] rhs A variable_buffer to append to this + /// + inline variable_buffer& operator+(const variable_buffer& rhs) + { + iv_perceived_bit_length += rhs.iv_perceived_bit_length; + iv_data.insert(iv_data.end(), rhs.iv_data.begin(), rhs.iv_data.end()); + return *this; + } + + /// + /// @brief operator+() + /// @param[in] rhs A number of bits to add to this buffer + /// + inline variable_buffer& operator+(const bits_type& rhs) + { + if (rhs != 0) + { + iv_perceived_bit_length += rhs; + iv_data.resize(_vector_size(iv_perceived_bit_length)); + } + + return *this; + } + + /// + /// @brief resize() + /// @param[in] rhs Desired resulting size of the buffer, in bits + /// + inline variable_buffer& resize(const bits_type& rhs) + { + return operator+(rhs - iv_perceived_bit_length); + } + + /// + /// @brief operator+=() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator+=(const T& rhs); +#endif + + /// + /// @brief operator|=() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator|=(const T& rhs); +#endif + + /// + /// @brief operator&=() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator&=(const T& rhs); +#endif + + /// + /// @brief operator|() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator|(const T& rhs); +#endif + + /// + /// @brief operator&() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator&(const T& rhs); +#endif + + /// + /// @brief operator^=() + /// +#ifdef DOXYGEN + inline variable_buffer<T>& operator^=(const T& rhs); +#endif + + /// + /// @brief Get a pointer to the buffer bits + /// @return Pointer to the buffer itself + /// + inline unit_type* pointer(void) + { + return &(iv_data[0]); + } + + /// + /// @brief operator!=() + /// + inline bool operator!=(const variable_buffer& rhs) const + { + return ! operator==(rhs); + } + + /// + /// @brief operator==() + /// @return true if and only if lhs == rhs + /// + inline bool operator==(const variable_buffer& rhs) const + { + if (&iv_data == &rhs.iv_data) + { + return true; + } + + return (iv_data == rhs.iv_data) && + (iv_perceived_bit_length == rhs.iv_perceived_bit_length); + } + + /// + /// @brief Copy part of an element into the DataBuffer + /// @param[in] i_data OT value to copy into DataBuffer + /// @param[in] i_targetStart The position in this where the copy starts + /// @param[in] i_len How many bits to copy + /// @param[in] i_sourceStart The start positon in i_data, defaults to 0 + /// @return FAPI2_RC_SUCCESS on success, FAPI2_RC_OVERFLOW otherwise + /// + template<typename OT> + inline fapi2::ReturnCodes insert(const OT& i_data, + bits_type i_targetStart = 0, + bits_type i_len = ~0, + bits_type i_sourceStart = 0) + { + // Compile time check to make sure OT is integral + static_assert( std::is_integral<OT>::value, + "Input must be an integral type" ); + + // _insert likes 32-bit sources. So lets make our source 32 bits. + uint32_t l_source = static_cast<uint32_t>(i_data); + bits_type l_sourceStart = i_sourceStart + + parameterTraits<uint32_t>::bit_length() - + parameterTraits<OT>::bit_length(); + + return _insert(&l_source, parameterTraits<uint32_t>::bit_length(), + &(iv_data[0]), getBitLength(), + l_sourceStart, i_targetStart, i_len); + } + + /// + /// @brief Copy in a right aligned (decimal) element + /// @param[in] i_data the incoming data + /// - data is taken right aligned + /// @param[in] i_targetStart The starting bit position in this + /// - Defaults to 0 + /// @param[in] i_len The length, in bits, the user wants copied. + /// - Defaults to all of the bits in the source which fit + /// @return FAPI2_RC_SUCCESS on success, FAPI2_RC_OVERFLOW otherwise + /// + template<typename OT> + inline fapi2::ReturnCodes insertFromRight(const OT& i_data, + bits_type i_targetStart = 0, + bits_type i_len = ~0) + { + return _insertFromRight(i_data, parameterTraits<OT>::bit_length(), + i_targetStart, i_len); + } + + /// + /// @brief Copy data from this buffer into an OT + /// @tparam OT the type of the outgoing data + /// @param[out] o_out OT to copy into - data is placed left aligned + /// @param[in] i_start Start bit to copy from - defaults to 0 + /// @param[in] i_len Length of bits to copy - defaults to filling o_out + /// @return FAPI2_RC_SUCCESS on success + /// @warning fapi2::extract() does not extend the argument buffer. The caller + /// should adjust the size proir to calling extract() (resize()). This is to + /// keep the semantics the same with integral buffers, which can't be resized. + /// + // Generic extract. Extract is an insert with the arguments reversed. + template< typename OT > + inline fapi2::ReturnCodes extract(OT& o_out, + bits_type i_start = 0, + bits_type i_len = ~0) const + { + // If they didn't pass an i_len, assume they want all the data + // which will fit. + if (i_len == static_cast<bits_type>(~0)) + { + i_len = std::min(getBitLength(), + parameterTraits<OT>::bit_length()); + } + + if (i_len > getBitLength()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + // _insert likes 32-bit targets. So lets make our target 32 bits. + uint32_t l_data = static_cast<uint32_t>(o_out); + + ReturnCodes rc; + + if ((rc = _insert((container_unit*)&iv_data[0], getBitLength(), + &l_data, + parameterTraits<uint32_t>::bit_length(), + i_start, 0U, i_len)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + // Shift back to the original bit width. + o_out = l_data >> (parameterTraits<uint32_t>::bit_length() - + parameterTraits<OT>::bit_length()); + return FAPI2_RC_SUCCESS; + } + + /// + /// @brief Copy data from this buffer into an OT and right justify + /// @tparam OT the type of the outgoing data + /// @param[out] o_out OT to copy into - data is placed right aligned + /// @param[in] i_start Start bit to copy from - defaults to 0 + /// @param[in] i_len Length of bits to copy - defaults to filling o_out + /// @return FAPI2_RC_SUCCESS on success + /// + // Extract is an insert with the arguments reversed. + template< typename OT > + inline fapi2::ReturnCodes extractToRight(OT& o_out, + bits_type i_start = 0, + bits_type i_len = ~0) const + { + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + if ((i_len == static_cast<bits_type>(~0)) || + (i_len > parameterTraits<OT>::bit_length())) + { + i_len = std::min(getBitLength(), + parameterTraits<OT>::bit_length()); + } + + // _insert likes 32-bit targets. So lets make our target 32 bits. + uint32_t l_data = static_cast<uint32_t>(o_out); + + ReturnCodes rc; + + if ((rc = _insert( + reinterpret_cast<const container_unit*>(&iv_data[0]), + getBitLength(), + &l_data, + parameterTraits<uint32_t>::bit_length(), + i_start, + parameterTraits<uint32_t>::bit_length() - + i_len, i_len)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + o_out = l_data; + return FAPI2_RC_SUCCESS; + } + + ///@} + + private: + // Just shorthand ... + static const bits_type bits_per_unit = bufferTraits<bits_container>::bits_per_unit(); + + ///@cond + /// + /// @brief Return the size of the internal vector given a desired bit size + /// @param[in] The size in bits + /// @return The size in units. + /// + inline bits_type _vector_size(const bits_type& bits_size) + { + // If we fit in one unit, we allocate one unit. + if (bits_size < parameterTraits<unit_type>::bit_length()) + { + return 1; + } + + // Otherwise, the number of units is calculates - add one if + // we cross the unit boundary. + else + { + bits_type my_size = bits_type(bits_size / 8 / sizeof(unit_type)); + my_size += (bits_size % parameterTraits<unit_type>::bit_length() == 0) ? 0 : 1; + return my_size; + } + } + ///@endcond + + /// The contents of the buffer + bits_container iv_data; + + // The number of bits the user asked for. The actual size of the + // container might be larger. + bits_type iv_perceived_bit_length; + + /// + /// @brief Internal insertFromRight + /// @param[in] i_data, the incoming data + /// @param[in] i_data_length The length in bits of the incoming data + /// @param[in] i_target_start_bit The starting bit position in this + /// @param[in] i_length The length, in bits, the user wants copied. + /// + template<typename OT> + inline fapi2::ReturnCodes _insertFromRight(const OT& i_data, + bits_type i_data_length, + bits_type i_targetStart, + bits_type i_len) + { + // If they didn't pass in a length, assume they want all the i_data + // which will fit. + if( i_len == static_cast<bits_type>(~0) ) + { + // The longest the length can be is the length of the data + // This is the miniumum of the length of the data or the + // number of available bits + i_len = std::min(i_data_length, getBitLength() - i_targetStart); + } + + // Source start is the length, counted from the right + return insert(i_data, i_targetStart, i_len, i_data_length - i_len); + } + +}; + +// If the source is 64-bits, treat that as 2x32 +template<> +inline fapi2::ReturnCodes variable_buffer::insert(const uint64_t& i_source, + bits_type i_targetStart, + bits_type i_len, + bits_type i_sourceStart) +{ + // _insert wants 32 bit chunks, so lets turn our uint64_t into a + // uint32_t array (of 64 bits in length). Looks like a 64 bit + // variable_buffer. + uint32_t l_source[2] = + { + static_cast<uint32_t>((i_source & 0xFFFFFFFF00000000) >> 32), + static_cast<uint32_t>((i_source & 0x00000000FFFFFFFF)) + }; + + return _insert(l_source, parameterTraits<uint64_t>::bit_length(), + &(iv_data[0]), getBitLength(), + i_sourceStart, i_targetStart, i_len); +} + +// Insert another variable_buffer +template<> +inline fapi2::ReturnCodes variable_buffer::insert( + const variable_buffer& i_data, + bits_type i_targetStart, + bits_type i_len, + bits_type i_sourceStart) +{ + return _insert(reinterpret_cast<const unit_type*>(&(i_data()[0])), + i_data.getBitLength(), + &(iv_data[0]), getBitLength(), + i_sourceStart, i_targetStart, i_len); +} + +// variable_buffer insert from right +template<> +inline fapi2::ReturnCodes variable_buffer::insertFromRight( + const variable_buffer& i_data, + bits_type i_targetStart, + bits_type i_len) +{ + const bits_type bit_length_of_source = i_data.getBitLength(); + return _insertFromRight(i_data, bit_length_of_source, + i_targetStart, i_len); +} + +template<> +inline fapi2::ReturnCodes variable_buffer::extract( + uint64_t& i_data, + bits_type i_start, + bits_type i_len) const +{ + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + if ((i_len == static_cast<bits_type>(~0)) || + (i_len > parameterTraits<uint64_t>::bit_length())) + { + i_len = std::min(getBitLength(), + parameterTraits<uint64_t>::bit_length()); + } + + // _insert wants 32 bit chunks, so lets turn our uint64_t into a + // uint32_t array (of 64 bits in length). Looks like a 64 bit + // variable_buffer. + uint32_t l_data[2] = + { + static_cast<uint32_t>((i_data & 0xFFFFFFFF00000000) >> 32), + static_cast<uint32_t>((i_data & 0x00000000FFFFFFFF)) + }; + + ReturnCodes rc; + + if ((rc = _insert((container_unit*)&iv_data[0], getBitLength(), + l_data, parameterTraits<uint64_t>::bit_length(), + i_start, 0U, i_len)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + i_data = static_cast<uint64_t>(l_data[0]) << 32; + i_data |= l_data[1]; + + return FAPI2_RC_SUCCESS; +} + +// Extract in to another variable_bufer +template<> +inline fapi2::ReturnCodes variable_buffer::extract( + variable_buffer& i_data, + bits_type i_start, + bits_type i_len) const +{ + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + if (i_len == static_cast<bits_type>(~0)) + { + i_len = i_data.getBitLength(); + } + + return _insert(reinterpret_cast<const container_unit*>( + &iv_data[0]), + getBitLength(), + &(i_data()[0]), i_data.getBitLength(), + i_start, 0U, i_len); +} + +template<> +inline fapi2::ReturnCodes variable_buffer::extractToRight( + uint64_t& i_data, + bits_type i_start, + bits_type i_len) const +{ + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + if ((i_len == static_cast<bits_type>(~0)) || + (i_len > parameterTraits<uint64_t>::bit_length())) + { + i_len = std::min(getBitLength(), + parameterTraits<uint64_t>::bit_length()); + } + + // _insert wants 32 bit chunks, so lets turn our uint64_t into a + // uint32_t array (of 64 bits in length). + uint32_t l_data[2] = + { + static_cast<uint32_t>((i_data & 0xFFFFFFFF00000000) >> 32), + static_cast<uint32_t>((i_data & 0x00000000FFFFFFFF)) + }; + + ReturnCodes rc; + + if ((rc = _insert( + reinterpret_cast<const container_unit*>(&iv_data[0]), + getBitLength(), + l_data, parameterTraits<uint64_t>::bit_length(), + i_start, + parameterTraits<uint64_t>::bit_length() - i_len, i_len)) + != FAPI2_RC_SUCCESS) + { + return rc; + } + + i_data = static_cast<uint64_t>(l_data[0]) << 32; + i_data |= l_data[1]; + + return FAPI2_RC_SUCCESS; +} + +inline fapi2::ReturnCodes variable_buffer::shiftLeft( + bits_type i_shiftNum, + bits_type i_offset) +{ + if (i_offset == 0) + { + return FAPI2_RC_SUCCESS; + } + + if (i_offset == static_cast<bits_type>(~0)) + { + i_offset = getBitLength(); + } + + else if (i_offset > getBitLength()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + /* To shift the data, extact the piece being shifted and then re-insert it at the new location */ + variable_buffer shiftData(i_offset); + ReturnCodes rc; + + // Get the hunk of data + if ((rc = extract(shiftData, 0, i_offset)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + // Clear the hole that was opened + if ((rc = clearBit((i_offset - i_shiftNum), i_shiftNum)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + // Stick the data back in + rc = insert(shiftData, 0, (shiftData.getBitLength() - i_shiftNum), i_shiftNum); + + return rc; +} + +inline fapi2::ReturnCodes variable_buffer::shiftRight( + bits_type i_shiftNum, + bits_type i_offset) +{ + if (i_offset == getBitLength()) + { + return FAPI2_RC_SUCCESS; + } + + if (i_offset > getBitLength()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + /* To shift the data, extact the piece being shifted and then re-insert it at the new location */ + variable_buffer shiftData(getBitLength() - i_offset); + ReturnCodes rc; + + // Get the hunk of data + if ((rc = extract(shiftData, i_offset, getBitLength() - i_offset)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + // Clear the hole that was opened + if ((rc = clearBit(i_offset, i_shiftNum)) != FAPI2_RC_SUCCESS) + { + return rc; + } + + // Stick the data back in + rc = insert(shiftData, (i_offset + i_shiftNum), (shiftData.getBitLength() - i_shiftNum)); + + return rc; +} + +template< typename OT> +inline OT variable_buffer::get(const bits_type i_offset) const +{ + const bits_type bits_in_value = parameterTraits<OT>::bit_length(); + const bits_type bit_offset = i_offset * bits_in_value; + + if (bit_offset >= iv_perceived_bit_length) + { + FAPI_ERR("Overrun in variable_buffer::get<OT>() - bits_in_value=%d bit_offset=%d iv_perceived_bit_length=%d", + bits_in_value, bit_offset, iv_perceived_bit_length); + fapi2::Assert(false); + } + + // Get is just an extract. + OT l_tmp = OT(0); + const bits_type available_space = iv_perceived_bit_length - bit_offset; + extract(l_tmp, bit_offset, std::min(available_space, bits_in_value)); + return l_tmp; +} +} +#endif |