blob: 130c07e6f79732e9842d7fadb743240be4e3ae26 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30
31#include "bcmos_system.h"
32#include "math.h"
33#include "bcmolt_bit_utils.h"
34
35
36/** dynamically allocate space for an array of `nbits' bits and initalize
37 * the bits to all be zero.
38 *
39 * \param[out] bv pointer to a bit_vector struct.
40 * \param[in] nbits number of bits to allocate.
41 * \return FALSE if space was not available, otherwise TRUE.
42 */
43bcmos_bool bcmolt_bv_new(bit_vector *bv, const uint32_t nbits)
44{
45 uint32_t nwords = BCMOS_DIVIDE_ROUND_UP(nbits, (BITS_SZ));
46
47 bv->nbits = nbits;
48 bv->vector = (bv_bits *)calloc(nwords, sizeof(bv_bits));
49 return (bv->vector != NULL);
50}
51
52
53/** return the value of the `offset'th bit element of the bit vector.
54 *
55 * \param[in] bv pointer to a bit_vector struct.
56 * \param[in] offset offset of bit to test.
57 * \return FALSE if the bit offset is out of range, otherwise TRUE.
58 */
59bcmos_bool bcmolt_bv_get(const bit_vector *bv, const uint32_t offset)
60{
61 bcmos_bool rv = BCMOS_FALSE;
62
63 if (offset <= bv->nbits)
64 {
65 rv = test_bits_set(bv->vector[(offset / BITS_SZ)],
66 (1 << (offset % BITS_SZ)));
67 }
68 else
69 {
70 BCMOS_TRACE_ERR("out of range %u\n", offset);
71 }
72 return rv;
73}
74
75
76/** set or clear the bit in position `offset' of the bit vector.
77 * bv->vector[bit_pos] is to be set (assigned to 1) if value is TRUE,
78 * otherwise it is to be cleared (assigned to 0).
79 *
80 * \param[in] bv pointer to a bit_vector struct.
81 * \param[in] offset offset of bit to set or clear.
82 * \param[in] value boolean value. TRUE for set, BCMOS_FALSE for clear.
83 * \return FALSE if the bit offset is out of range, otherwise TRUE.
84 */
85void bcmolt_bv_assign(bit_vector *bv,
86 const uint32_t offset,
87 const bcmos_bool value)
88{
89 if (offset <= bv->nbits)
90 {
91 if (value)
92 {
93 bv->vector[offset / BITS_SZ] |= (1 << (offset % BITS_SZ));
94 }
95 else
96 {
97 bv->vector[offset / BITS_SZ] &= ~(1 << (offset % BITS_SZ));
98 }
99 }
100 else
101 {
102 BCMOS_TRACE_ERR("out of range %u\n", offset);
103 }
104}
105
106
107/** toggle the bit in position `offset' of the bit vector.
108 * i.e. if it was 1 it is 0; if it was 0 it is 1.
109 *
110 * \param[in] bv pointer to a bit_vector struct.
111 * \param[in] offset offset of bit to toggle.
112 * \return FALSE if the bit offset is out of range, otherwise TRUE.
113 */
114void bcmolt_bv_toggle(bit_vector *bv, const uint32_t offset)
115{
116 if (offset <= bv->nbits)
117 {
118 bv->vector[offset / BITS_SZ] ^= (1 << (offset % BITS_SZ));
119 }
120 else
121 {
122 BCMOS_TRACE_ERR("out of range %u\n", offset);
123 }
124}
125
126
127/** copy bit vector from 'src' to 'dst'.
128 *
129 * \param[out] dst pointer to a bit_vector struct to copy to.
130 * \param[in] src pointer to a bit_vector struct to copy from.
131 * \param[in] nbits number of bits to copy.
132 * \return none.
133 */
134void bcmolt_bv_copy(bit_vector *dst,
135 const bit_vector *src,
136 const uint32_t nbits)
137{
138 uint32_t i;
139 uint32_t nwords = nbits / BITS_SZ;
140 bv_bits bit_remainder = nbits % BITS_SZ;
141
142 if ((nbits <= dst->nbits) && (nbits <= src->nbits))
143 {
144 for (i = 0; i < nwords; i++)
145 {
146 dst->vector[i] = src->vector[i];
147 }
148
149 if (0 != bit_remainder)
150 {
151 dst->vector[nwords] = (dst->vector[nwords] & ~((2^bit_remainder) - 1)) |
152 (src->vector[nwords] & ((2^bit_remainder) - 1));
153 }
154 }
155 else
156 {
157 BCMOS_TRACE_ERR("out of range %u\n", nbits);
158 }
159}
160
161
162/** Print bit pattern of word FORMATTED to string.
163 *
164 * \param[in] value value to transform to bit string.
165 * \param[in] bitcnt count of bits to be shown.
166 * \param[out] outstr pointer to a output buffer to store the string.
167 * \return none
168 * \warning this fn doesn't check the size of 'outstr'.
169 * the caller should ensure 'outstr' has enough room for the
170 * bit string, space characters and null terminator.
171 */
172void bcmolt_bit_string(const bv_bits value, const uint32_t bitcnt, char *outstr)
173{
174 uint32_t offset;
175
176 if (bitcnt <= BITS_SZ)
177 {
178 for (offset = 0; offset < bitcnt; offset++)
179 {
180 *outstr++ = ((value >> offset) & 1) + '0';
181 if ((((offset + 1) % 4) == 0))
182 {
183 *outstr++ = ' ';
184 }
185 }
186 }
187
188 *outstr = '\0';
189}
190
191
192/** Print all bits in the bit vector.
193 *
194 * \param[in] bv pointer to a bit_vector struct.
195 * \return none.
196 */
197void bcmolt_bv_dump(const bit_vector *bv)
198{
199 uint32_t idx; /* word idx */
200 char outstr[BITS_SZ + 8 + 1]; /* 8 spaces + null */
201
202 for (idx = 0; idx < (bv->nbits / BITS_SZ); idx++)
203 {
204 bcmolt_bit_string(bv->vector[idx], BITS_SZ, outstr);
205 bcmos_printf("%s\n", outstr);
206 }
207
208 if (0 != (bv->nbits % BITS_SZ))
209 {
210 bcmolt_bit_string(bv->vector[idx], (bv->nbits % BITS_SZ), outstr);
211 bcmos_printf("%s\n", outstr);
212 }
213}
214
215
216/** Count the number of bits set in a long integer.
217 *
218 * \param[in] num integer value.
219 * \return number of bits set.
220 */
221uint32_t bcmolt_bit_count(uint32_t num)
222{
223 num = ((num & 0xAAAAAAAAL) >> 1) + (num & 0x55555555L);
224 num = ((num & 0xCCCCCCCCL) >> 2) + (num & 0x33333333L);
225 num = ((num & 0xF0F0F0F0L) >> 4) + (num & 0x0F0F0F0FL);
226 num = ((num & 0xFF00FF00L) >> 8) + (num & 0x00FF00FFL);
227 num = ((num & 0xFFFF0000L) >> 16) + (num & 0x0000FFFFL);
228 return num;
229}
230
231
232/** Count the number of bits set in the whole bit vector.
233 *
234 * \param[in] bv pointer to the bit vector struct.
235 * \return number of bits set.
236 */
237uint32_t bcmolt_bv_bit_count(const bit_vector *bv)
238{
239 uint32_t nwords = BCMOS_DIVIDE_ROUND_UP(bv->nbits, (BITS_SZ));
240 uint32_t cnt = 0;
241
242 while (0 != nwords--)
243 {
244 cnt += bcmolt_bit_count(bv->vector[nwords]);
245 }
246
247 return cnt;
248}
249
250
251
252/** Copy bit range from a 32-bit word array to an arbitrary bit position of
253 * the destination 32-bit word array.
254 *
255 * \param[in] dst destination buffer
256 * \param[in] dst_bytes destination buffer size in bytes
257 * \param[in] dst_bit_pos least bit position to dest
258 * \param[in] src source buffer
259 * \param[in] n_bits how many bits to copy from source
260 * \note src is in little endian and dst is in big endian.
261 */
262void bcmos_bit_range_set(uint32_t *dst, uint32_t dst_bytes, uint16_t dst_bit_pos,
263 uint32_t *src, uint16_t n_bits)
264{
265 uint16_t bp = dst_bit_pos;
266 uint16_t len;
267 uint32_t wp;
268 uint32_t mask;
269 uint32_t src_idx;
270 uint32_t dst_idx;
271
272 wp = bp / 32;
273 bp = bp & (32 - 1);
274 src_idx = 0;
275
276 for (len = n_bits; len > 0; len -= 32)
277 {
278 if (bp != 0)
279 {
280 mask = (len < 32) ? (1 << len) - 1 : 0xFFFFFFFF;
281 dst_idx = wp;
282 dst[dst_idx] &= ~(mask << bp);
283 dst[dst_idx] |= src[src_idx] << bp;
284 wp++;
285 if (len > (32 - bp))
286 {
287 dst_idx = wp;
288 dst[dst_idx] &= ~(mask >> (32 - bp));
289 dst[dst_idx] |= src[src_idx] >> (32 - bp) & ((1 << bp) - 1);
290 }
291 }
292 else
293 {
294 dst_idx = wp;
295 if (len < 32)
296 {
297 mask = (1 << len) - 1;
298 dst[dst_idx] &= ~mask;
299 dst[dst_idx] |= src[src_idx] << bp;
300 }
301 else
302 {
303 dst[dst_idx] = src[src_idx];
304 }
305 wp++;
306 }
307 src_idx++;
308 }
309}
310
311
312/** Get bit range at an arbitrary bit position of a 32-bit word array
313 *
314 * \param[in] src source buffer (e.g. dataport)
315 * \param[in] src_bytes source buffer size in bytes
316 * \param[in] src_bit_pos least bit position of the source
317 * \param[in] dst destination buffer to store the bit value
318 * \param[in] n_bits how many bits to copy from srouce
319 * \note src is in big endian and dst is in little endian.
320 */
321void bcmos_bit_range_get(const uint32_t *src, uint32_t src_bytes,
322 uint16_t src_bit_pos, uint32_t *dst, uint16_t n_bits)
323{
324 uint16_t bp = src_bit_pos; /* for readability */
325 uint16_t len = n_bits;
326 uint32_t wp;
327 uint32_t src_idx;
328 uint32_t dst_idx;
329
330 if (n_bits == 1)
331 {
332 wp = bp / 32;
333 bp = bp & (32 - 1);
334 src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp;
335 dst[0] = ((src[src_idx] & (1 << bp)) != 0) ? 1: 0;
336 return;
337 }
338
339 wp = bp / 32;
340 bp = bp & (32 - 1);
341 dst_idx = 0;
342
343 for (; len > 0; len -= 32)
344 {
345 if (bp != 0)
346 {
347 src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp;
348 dst[dst_idx] = src[src_idx] >> bp & ((1 << (32 - bp)) - 1);
349 wp++;
350 if (len > (32 - bp))
351 {
352 src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp;
353 dst[dst_idx] |= src[src_idx] << (32 - bp);
354 }
355 }
356 else
357 {
358 src_idx = BCMOS_DIVIDE_ROUND_UP(src_bytes, 4) - 1 - wp;
359 dst[dst_idx] = src[src_idx];
360 wp++;
361 }
362
363 if (len < 32)
364 {
365 dst[dst_idx] &= ((1 << len) - 1);
366 }
367 dst_idx++;
368 }
369}
370