| /* |
| <:copyright-BRCM:2016:DUAL/GPL:standard |
| |
| Broadcom Proprietary and Confidential.(c) 2016 Broadcom |
| All Rights Reserved |
| |
| Unless you and Broadcom execute a separate written software license |
| agreement governing use of this software, this software is licensed |
| to you under the terms of the GNU General Public License version 2 |
| (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| with the following added to such license: |
| |
| As a special exception, the copyright holders of this software give |
| you permission to link this software with independent modules, and |
| to copy and distribute the resulting executable under terms of your |
| choice, provided that you also meet, for each linked independent |
| module, the terms and conditions of the license of that module. |
| An independent module is a module which is not derived from this |
| software. The special exception does not apply to any modifications |
| of the software. |
| |
| Not withstanding the above, under no circumstances may you combine |
| this software in any way with any other Broadcom software provided |
| under a license other than the GPL, without Broadcom's express prior |
| written consent. |
| |
| :> |
| */ |
| |
| |
| #include "bcmos_system.h" |
| #include "math.h" |
| #include "bcmolt_bit_utils.h" |
| |
| |
| /** dynamically allocate space for an array of `nbits' bits and initalize |
| * the bits to all be zero. |
| * |
| * \param[out] bv pointer to a bit_vector struct. |
| * \param[in] nbits number of bits to allocate. |
| * \return FALSE if space was not available, otherwise TRUE. |
| */ |
| bcmos_bool bcmolt_bv_new(bit_vector *bv, const uint32_t nbits) |
| { |
| uint32_t nwords = BCMOS_DIVIDE_ROUND_UP(nbits, (BITS_SZ)); |
| |
| bv->nbits = nbits; |
| bv->vector = (bv_bits *)calloc(nwords, sizeof(bv_bits)); |
| return (bv->vector != NULL); |
| } |
| |
| |
| /** return the value of the `offset'th bit element of the bit vector. |
| * |
| * \param[in] bv pointer to a bit_vector struct. |
| * \param[in] offset offset of bit to test. |
| * \return FALSE if the bit offset is out of range, otherwise TRUE. |
| */ |
| bcmos_bool bcmolt_bv_get(const bit_vector *bv, const uint32_t offset) |
| { |
| bcmos_bool rv = BCMOS_FALSE; |
| |
| if (offset <= bv->nbits) |
| { |
| rv = test_bits_set(bv->vector[(offset / BITS_SZ)], |
| (1 << (offset % BITS_SZ))); |
| } |
| else |
| { |
| BCMOS_TRACE_ERR("out of range %u\n", offset); |
| } |
| return rv; |
| } |
| |
| |
| /** set or clear the bit in position `offset' of the bit vector. |
| * bv->vector[bit_pos] is to be set (assigned to 1) if value is TRUE, |
| * otherwise it is to be cleared (assigned to 0). |
| * |
| * \param[in] bv pointer to a bit_vector struct. |
| * \param[in] offset offset of bit to set or clear. |
| * \param[in] value boolean value. TRUE for set, BCMOS_FALSE for clear. |
| * \return FALSE if the bit offset is out of range, otherwise TRUE. |
| */ |
| void bcmolt_bv_assign(bit_vector *bv, |
| const uint32_t offset, |
| const bcmos_bool value) |
| { |
| if (offset <= bv->nbits) |
| { |
| if (value) |
| { |
| bv->vector[offset / BITS_SZ] |= (1 << (offset % BITS_SZ)); |
| } |
| else |
| { |
| bv->vector[offset / BITS_SZ] &= ~(1 << (offset % BITS_SZ)); |
| } |
| } |
| else |
| { |
| BCMOS_TRACE_ERR("out of range %u\n", offset); |
| } |
| } |
| |
| |
| /** toggle the bit in position `offset' of the bit vector. |
| * i.e. if it was 1 it is 0; if it was 0 it is 1. |
| * |
| * \param[in] bv pointer to a bit_vector struct. |
| * \param[in] offset offset of bit to toggle. |
| * \return FALSE if the bit offset is out of range, otherwise TRUE. |
| */ |
| void bcmolt_bv_toggle(bit_vector *bv, const uint32_t offset) |
| { |
| if (offset <= bv->nbits) |
| { |
| bv->vector[offset / BITS_SZ] ^= (1 << (offset % BITS_SZ)); |
| } |
| else |
| { |
| BCMOS_TRACE_ERR("out of range %u\n", offset); |
| } |
| } |
| |
| |
| /** copy bit vector from 'src' to 'dst'. |
| * |
| * \param[out] dst pointer to a bit_vector struct to copy to. |
| * \param[in] src pointer to a bit_vector struct to copy from. |
| * \param[in] nbits number of bits to copy. |
| * \return none. |
| */ |
| void bcmolt_bv_copy(bit_vector *dst, |
| const bit_vector *src, |
| const uint32_t nbits) |
| { |
| uint32_t i; |
| uint32_t nwords = nbits / BITS_SZ; |
| bv_bits bit_remainder = nbits % BITS_SZ; |
| |
| if ((nbits <= dst->nbits) && (nbits <= src->nbits)) |
| { |
| for (i = 0; i < nwords; i++) |
| { |
| dst->vector[i] = src->vector[i]; |
| } |
| |
| if (0 != bit_remainder) |
| { |
| dst->vector[nwords] = (dst->vector[nwords] & ~((2^bit_remainder) - 1)) | |
| (src->vector[nwords] & ((2^bit_remainder) - 1)); |
| } |
| } |
| else |
| { |
| BCMOS_TRACE_ERR("out of range %u\n", nbits); |
| } |
| } |
| |
| |
| /** Print bit pattern of word FORMATTED to string. |
| * |
| * \param[in] value value to transform to bit string. |
| * \param[in] bitcnt count of bits to be shown. |
| * \param[out] outstr pointer to a output buffer to store the string. |
| * \return none |
| * \warning this fn doesn't check the size of 'outstr'. |
| * the caller should ensure 'outstr' has enough room for the |
| * bit string, space characters and null terminator. |
| */ |
| void bcmolt_bit_string(const bv_bits value, const uint32_t bitcnt, char *outstr) |
| { |
| uint32_t offset; |
| |
| if (bitcnt <= BITS_SZ) |
| { |
| for (offset = 0; offset < bitcnt; offset++) |
| { |
| *outstr++ = ((value >> offset) & 1) + '0'; |
| if ((((offset + 1) % 4) == 0)) |
| { |
| *outstr++ = ' '; |
| } |
| } |
| } |
| |
| *outstr = '\0'; |
| } |
| |
| |
| /** Print all bits in the bit vector. |
| * |
| * \param[in] bv pointer to a bit_vector struct. |
| * \return none. |
| */ |
| void bcmolt_bv_dump(const bit_vector *bv) |
| { |
| uint32_t idx; /* word idx */ |
| char outstr[BITS_SZ + 8 + 1]; /* 8 spaces + null */ |
| |
| for (idx = 0; idx < (bv->nbits / BITS_SZ); idx++) |
| { |
| bcmolt_bit_string(bv->vector[idx], BITS_SZ, outstr); |
| bcmos_printf("%s\n", outstr); |
| } |
| |
| if (0 != (bv->nbits % BITS_SZ)) |
| { |
| bcmolt_bit_string(bv->vector[idx], (bv->nbits % BITS_SZ), outstr); |
| bcmos_printf("%s\n", outstr); |
| } |
| } |
| |
| |
| /** Count the number of bits set in a long integer. |
| * |
| * \param[in] num integer value. |
| * \return number of bits set. |
| */ |
| uint32_t bcmolt_bit_count(uint32_t num) |
| { |
| num = ((num & 0xAAAAAAAAL) >> 1) + (num & 0x55555555L); |
| num = ((num & 0xCCCCCCCCL) >> 2) + (num & 0x33333333L); |
| num = ((num & 0xF0F0F0F0L) >> 4) + (num & 0x0F0F0F0FL); |
| num = ((num & 0xFF00FF00L) >> 8) + (num & 0x00FF00FFL); |
| num = ((num & 0xFFFF0000L) >> 16) + (num & 0x0000FFFFL); |
| return num; |
| } |
| |
| |
| /** Count the number of bits set in the whole bit vector. |
| * |
| * \param[in] bv pointer to the bit vector struct. |
| * \return number of bits set. |
| */ |
| uint32_t bcmolt_bv_bit_count(const bit_vector *bv) |
| { |
| uint32_t nwords = BCMOS_DIVIDE_ROUND_UP(bv->nbits, (BITS_SZ)); |
| uint32_t cnt = 0; |
| |
| while (0 != nwords--) |
| { |
| cnt += bcmolt_bit_count(bv->vector[nwords]); |
| } |
| |
| return cnt; |
| } |
| |
| |
| |
| /** Copy bit range from a 32-bit word array to an arbitrary bit position of |
| * the destination 32-bit word array. |
| * |
| * \param[in] dst destination buffer |
| * \param[in] dst_bytes destination buffer size in bytes |
| * \param[in] dst_bit_pos least bit position to dest |
| * \param[in] src source buffer |
| * \param[in] n_bits how many bits to copy from source |
| * \note src is in little endian and dst is in big endian. |
| */ |
| void bcmos_bit_range_set(uint32_t *dst, uint32_t dst_bytes, uint16_t dst_bit_pos, |
| uint32_t *src, uint16_t n_bits) |
| { |
| uint16_t bp = dst_bit_pos; |
| uint16_t len; |
| uint32_t wp; |
| uint32_t mask; |
| uint32_t src_idx; |
| uint32_t dst_idx; |
| |
| wp = bp / 32; |
| bp = bp & (32 - 1); |
| src_idx = 0; |
| |
| for (len = n_bits; len > 0; len -= 32) |
| { |
| if (bp != 0) |
| { |
| mask = (len < 32) ? (1 << len) - 1 : 0xFFFFFFFF; |
| dst_idx = wp; |
| dst[dst_idx] &= ~(mask << bp); |
| dst[dst_idx] |= src[src_idx] << bp; |
| wp++; |
| if (len > (32 - bp)) |
| { |
| dst_idx = wp; |
| dst[dst_idx] &= ~(mask >> (32 - bp)); |
| dst[dst_idx] |= src[src_idx] >> (32 - bp) & ((1 << bp) - 1); |
| } |
| } |
| else |
| { |
| dst_idx = wp; |
| if (len < 32) |
| { |
| mask = (1 << len) - 1; |
| dst[dst_idx] &= ~mask; |
| dst[dst_idx] |= src[src_idx] << bp; |
| } |
| else |
| { |
| dst[dst_idx] = src[src_idx]; |
| } |
| wp++; |
| } |
| src_idx++; |
| } |
| } |
| |
| |
| /** Get bit range at an arbitrary bit position of a 32-bit word array |
| * |
| * \param[in] src source buffer (e.g. dataport) |
| * \param[in] src_bytes source buffer size in bytes |
| * \param[in] src_bit_pos least bit position of the source |
| * \param[in] dst destination buffer to store the bit value |
| * \param[in] n_bits how many bits to copy from srouce |
| * \note src is in big endian and dst is in little endian. |
| */ |
| void bcmos_bit_range_get(const uint32_t *src, uint32_t src_bytes, |
| uint16_t src_bit_pos, uint32_t *dst, uint16_t n_bits) |
| { |
| uint16_t bp = src_bit_pos; /* for readability */ |
| uint16_t len = n_bits; |
| uint32_t wp; |
| uint32_t src_idx; |
| uint32_t dst_idx; |
| |
| if (n_bits == 1) |
| { |
| wp = bp / 32; |
| bp = bp & (32 - 1); |
| src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp; |
| dst[0] = ((src[src_idx] & (1 << bp)) != 0) ? 1: 0; |
| return; |
| } |
| |
| wp = bp / 32; |
| bp = bp & (32 - 1); |
| dst_idx = 0; |
| |
| for (; len > 0; len -= 32) |
| { |
| if (bp != 0) |
| { |
| src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp; |
| dst[dst_idx] = src[src_idx] >> bp & ((1 << (32 - bp)) - 1); |
| wp++; |
| if (len > (32 - bp)) |
| { |
| src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp; |
| dst[dst_idx] |= src[src_idx] << (32 - bp); |
| } |
| } |
| else |
| { |
| src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp; |
| dst[dst_idx] = src[src_idx]; |
| wp++; |
| } |
| |
| if (len < 32) |
| { |
| dst[dst_idx] &= ((1 << len) - 1); |
| } |
| dst_idx++; |
| } |
| } |
| |