• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Nic30 / pyMathBitPrecise / b9b6e894-1ad4-4717-a415-40272de4f9f0

21 May 2024 08:39PM UTC coverage: 80.19% (-1.3%) from 81.514%
b9b6e894-1ad4-4717-a415-40272de4f9f0

push

circleci

Nic30
style: valToInt -> Bits3valToInt

199 of 265 branches covered (75.09%)

Branch coverage included in aggregate %.

728 of 891 relevant lines covered (81.71%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.15
/pyMathBitPrecise/bit_utils.py
1
#!/usr/bin/env python3
2
# -*- coding: UTF-8 -*-
3
from pyMathBitPrecise.utils import grouper
1✔
4
from typing import List, Tuple, Generator
1✔
5

6

7
def mask(bits: int) -> int:
1✔
8
    """
9
    Generate mask of specified size (sequence of '1')
10
    """
11
    return (1 << bits) - 1
1✔
12

13

14
def bit_field(_from: int, to: int) -> int:
1✔
15
    """
16
    Generate int which has bits '_from' to 'to' set to '1'
17

18
    :note: _from 0 to 1 -> '1'
19
    """
20
    w = to - _from
1✔
21
    return mask(w) << _from
1✔
22

23

24
def get_bit(val: int, bitNo: int) -> int:
1✔
25
    """
26
    Get bit from int
27
    """
28
    return (val >> bitNo) & 1
1✔
29

30

31
def get_bit_range(val: int, bitsStart: int, bitsLen: int) -> int:
1✔
32
    """
33
    Get sequence of bits from an int value
34
    """
35
    val >>= bitsStart
1✔
36
    return val & mask(bitsLen)
1✔
37

38

39
def clean_bit(val: int, bitNo: int) -> int:
1✔
40
    """
41
    Set a specified bit to '0'
42
    """
43
    return val & ~(1 << bitNo)
1✔
44

45

46
def set_bit(val: int, bitNo: int) -> int:
1✔
47
    """
48
    Set a specified bit to '1'
49
    """
50
    return val | (1 << bitNo)
1✔
51

52

53
def toggle_bit(val: int, bitNo: int) -> int:
1✔
54
    """
55
    Toggle specified bit in int
56
    """
57
    return val ^ (1 << bitNo)
1✔
58

59

60
def set_bit_range(val: int, bitStart: int, bitsLen: int, newBits: int) -> int:
1✔
61
    """
62
    Set specified range of bits in int to a specified value
63
    """
64
    _mask = mask(bitsLen)
1✔
65
    newBits &= _mask
1✔
66

67
    _mask <<= bitStart
1✔
68
    newBits <<= bitStart
1✔
69

70
    return (val & ~_mask) | newBits
1✔
71

72

73
def bit_set_to(val: int, bitNo: int, bitVal: int) -> int:
1✔
74
    """
75
    Set specified bit in int to a specified value
76
    """
77
    if bitVal == 0:
1✔
78
        return clean_bit(val, bitNo)
1✔
79
    elif bitVal == 1:
1!
80
        return set_bit(val, bitNo)
1✔
81
    else:
82
        raise ValueError(("Invalid value of bit to set", bitVal))
×
83

84

85
def apply_set_and_clear(val: int, set_flag: int, clear_flag: int):
1✔
86
    """
87
    :param val: an input value of the flag(s)
88
    :param set_flag: a mask of bits to set to 1
89
    :param clear_flag: a mask of bits to set to 0
90
    :note: set has higher priority
91

92
    :return: new value of the flag
93
    """
94
    return (val & ~clear_flag) | set_flag
1✔
95

96

97
def align(val: int, lowerBitCntToAlign: int) -> int:
1✔
98
    """
99
    Cut off lower bits to align a int value.
100
    """
101
    val = val >> lowerBitCntToAlign
1✔
102
    return val << lowerBitCntToAlign
1✔
103

104

105
def align_with_known_width(val, width: int, lowerBitCntToAlign: int):
1✔
106
    """
107
    Does same as :func:`~.align` just with the known width of val
108
    """
109
    return val & (mask(width - lowerBitCntToAlign) << lowerBitCntToAlign)
×
110

111

112
def iter_bits(val: int, length: int) -> Generator[int, None, None]:
1✔
113
    """
114
    Iterate bits in int. LSB first.
115
    """
116
    for _ in range(length):
1✔
117
        yield val & 1
1✔
118
        val >>= 1
1✔
119

120

121
def iter_bits_sequences(val: int, length: int) -> Generator[Tuple[int, int], None, None]:
1✔
122
    """
123
    Iter tuples (bitVal, number of same bits), lsb first
124
    """
125
    assert length > 0, length
×
126
    assert val >= 0
×
127
    # start of new bit seqence
128
    w = 1
×
129
    valBit = val & 1
×
130
    val >>= 1
×
131
    foundBit = valBit
×
132
    for _ in range(length-1):
×
133
        # extract single bit from val
134
        valBit = val & 1
×
135
        val >>= 1
×
136
        # check if it fits into current bit sequence
137
        if valBit == foundBit:
×
138
            w += 1
×
139
        else:
140
            # end of sequence of same bits
141
            yield (foundBit, w)
×
142
            foundBit = valBit
×
143
            w = 1
×
144

145
    if w != 0:
×
146
        yield (foundBit, w)
×
147

148

149
def to_signed(val: int, width: int) -> int:
1✔
150
    """
151
    Convert unsigned int to negative int which has same bits set (emulate sign overflow).
152

153
    :note: bits in value are not changed, just python int object
154
        has signed flag set properly. And number is in expected range.
155
    """
156
    if val > 0:
1✔
157
        msb = 1 << (width - 1)
1✔
158
        if val & msb:
1✔
159
            val -= mask(width) + 1
1✔
160
    return val
1✔
161

162

163
def to_unsigned(val, width) -> int:
1✔
164
    if val < 0:
1!
165
        return val & mask(width)
1✔
166
    else:
167
        return val
×
168

169

170
def mask_bytes(val: int, byte_mask: int, mask_bit_length: int) -> int:
1✔
171
    """
172
    Use each bit in byte_mask as a mask for each byte in val.
173

174
    :note: Useful for masking of value for HW interfaces where mask
175
        is represented by a vector of bits where each bit is mask
176
        for byte in data vector.
177
    """
178
    res = 0
1✔
179
    for i, m in enumerate(iter_bits(byte_mask, mask_bit_length)):
1✔
180
        if m:
1✔
181
            res |= (val & 0xff) << (i * 8)
1✔
182
        val >>= 8
1✔
183
    return res
1✔
184

185

186
INT_BASES = {
1✔
187
    "b": 2,
188
    "o": 8,
189
    "d": 10,
190
    "h": 16,
191
}
192

193

194
class ValidityError(ValueError):
1✔
195
    """
196
    Value is not fully defined and thus can not be used
197
    """
198

199

200
def normalize_slice(s: slice, obj_width: int) -> Tuple[int, int]:
1✔
201
    start, stop, step = s.start, s.stop, s.step
1✔
202
    if step is not None and step != -1:
1✔
203
        raise NotImplementedError(s.step)
204
    else:
205
        step = -1
1✔
206
    if stop is None:
1✔
207
        stop = 0
1✔
208
    else:
209
        stop = int(stop)
1✔
210

211
    if start is None:
1✔
212
        start = int(obj_width)
1✔
213
    else:
214
        start = int(start)
1✔
215
    # n...0
216
    if start <= stop:
1✔
217
        raise IndexError(s)
1✔
218
    firstBitNo = stop
1✔
219
    size = start - stop
1✔
220
    if start < 0 or stop < 0 or size < 0 or start > obj_width:
1✔
221
        raise IndexError(s)
1✔
222

223
    return firstBitNo, size
1✔
224

225

226
def reverse_bits(val, width):
1✔
227
    """
228
    Reverse bits in integer value of specified width
229
    """
230
    v = 0
1✔
231
    for i in range(width):
1✔
232
        v |= (get_bit(val, width - i - 1) << i)
1✔
233
    return v
1✔
234

235

236
def extend_to_size(collection, items, pad=0):
1✔
237
    toAdd = items - len(collection)
1✔
238
    assert toAdd >= 0
1✔
239
    for _ in range(toAdd):
1✔
240
        collection.append(pad)
1✔
241

242
    return collection
1✔
243

244

245
def bit_list_reversed_endianity(bitList, extend=True):
1✔
246
    w = len(bitList)
1✔
247
    i = w
1✔
248

249
    items = []
1✔
250
    while i > 0:
1✔
251
        # take last 8 bytes or rest
252
        lower = max(i - 8, 0)
1✔
253
        b = bitList[lower:i]
1✔
254
        if extend:
1!
255
            extend_to_size(b, 8)
1✔
256
        items.extend(b)
1✔
257
        i -= 8
1✔
258

259
    return items
1✔
260

261

262
def bit_list_reversed_bits_in_bytes(bitList: List[int], extend=None):
1✔
263
    "Byte reflection  (0x0f -> 0xf0)"
264
    w = len(bitList)
1✔
265
    if extend is None:
1!
266
        assert w % 8 == 0
1✔
267
    tmp = []
1✔
268
    for db in grouper(8, bitList, padvalue=0):
1✔
269
        tmp.extend(reversed(db))
1✔
270

271
    if not extend and len(tmp) != w:
1!
272
        rem = w % 8
×
273
        # rm zeros from [0, 0, 0, 0, 0, d[2], d[1], d[0]] like
274
        tmp = tmp[:w - rem] + tmp[-rem:]
×
275

276
    return tmp
1✔
277

278

279
def byte_list_to_be_int(_bytes: List[int]):
1✔
280
    """
281
    In input list LSB first, in result little endian ([1, 0] -> 0x0001)
282
    """
283
    return int_list_to_int(_bytes, 8)
×
284

285

286
def bit_list_to_int(bitList: List[int]):
1✔
287
    """
288
    In input list LSB first, in result little endian ([0, 1] -> 0b10)
289
    """
290
    res = 0
1✔
291
    for i, r in enumerate(bitList):
1✔
292
        res |= (r & 0x1) << i
1✔
293
    return res
1✔
294

295

296
def int_list_to_int(il: List[int], item_width: int):
1✔
297
    """
298
    [0x0201, 0x0403] -> 0x04030201
299
    """
300
    v = 0
1✔
301
    for i, b in enumerate(il):
1✔
302
        v |= b << (i * item_width)
1✔
303

304
    return v
1✔
305

306

307
def int_to_int_list(v: int, item_width: int, number_of_items: int):
1✔
308
    """
309
    opposite of :func:`~.int_list_to_int`
310
    """
311
    item_mask = mask(item_width)
1✔
312
    res = []
1✔
313
    for _ in range(number_of_items):
1✔
314
        res.append(v & item_mask)
1✔
315
        v >>= item_width
1✔
316

317
    assert v == 0, ("there should be nothing left, the value is larger", v)
1✔
318
    return res
1✔
319

320

321
def reverse_byte_order(val: "Bits3val"):
1✔
322
    """
323
    Reverse byteorder (littleendian/bigendian) of signal or value
324
    """
325
    w = val._dtype.bit_length()
×
326
    i = w
×
327
    items = []
×
328

329
    while i > 0:
×
330
        # take last 8 bytes or rest
331
        lower = max(i - 8, 0)
×
332
        items.append(val[i:lower])
×
333
        i -= 8
×
334
    
335
    # Concat(*items)
336
    top = None
×
337
    for s in items:
×
338
        if top is None:
×
339
            top = s
×
340
        else:
341
            top = top._concat(s)
×
342
    return top
×
343

344

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc