1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
def u(num, bits):
""" parse an unsigned integer into a bitfield.
>>> u(0x08, 8)
(8, 8)
>>> u(0xff, 8)
(255, 8)
>>> u(0xf0, 7)
Traceback (most recent call last):
...
ValueError: value 240 (u8) too large for u7 field
>>> u(-1, 8)
Traceback (most recent call last):
...
ValueError: negative value not allowed: -1
"""
if num < 0:
raise ValueError("negative value not allowed: {}".format(num))
if num.bit_length() > bits:
raise ValueError("value {} (u{}) too large for u{} field"
.format(num, num.bit_length(), bits))
return (num, bits)
def i(num, bits):
""" parse a signed integer into a bitfield.
>>> i(8, 8)
(8, 8)
>>> i(-4, 8)
(252, 8)
>>> i(127, 8)
(127, 8)
>>> i(-128, 8)
(128, 8)
>>> i(128, 8)
Traceback (most recent call last):
...
ValueError: value 128 (i9) too large for i8 field [-128;127]
>>> i(-129, 8)
Traceback (most recent call last):
...
ValueError: value -129 (i9) too large for i8 field [-128;127]
"""
min = -(1 << (bits - 1))
max = -1 - min
if num > max or num < min:
raise ValueError("value {} (i{}) too large for i{} field [{};{}]"
.format(num, num.bit_length()+1, bits, min, max))
if num < 0:
num = (1 << bits) + num
return u(num, bits)
def from_part(part):
""" parse a size-tagged subv part into a bit.
>>> from_part((34, 2))
(34, 2)
>>> from_part((34, 2, 'extra'))
(34, 2)
"""
val = int(part[0])
size = part[1]
return (val, int(size))
def concat(*parts):
""" concatenate multiple bitfields.
>>> concat((0b10, 2), (0b00, 2))
(2, 4)
>>> concat((0b1, 1), (0b0110, 4), (0b110, 3))
(205, 8)
"""
val, size = 0, 0
for (pval, psize) in parts:
val = val | pval << size
size += psize
return (val, size)
def slice(bits, hi, lo):
""" slice a bitfield given hi and lo bit indices.
>>> slice((0x7f, 8), 7, 4)
(7, 4)
>>> slice((0b100, 3), 2, 2)
(1, 1)
>>> slice((0x12345678, 32), 7, 0)
(120, 8)
>>> slice((0x12345678, 32), 15, 8)
(86, 8)
>>> slice((0x12345678, 32), 23, 16)
(52, 8)
>>> slice((0xf, 4), 4, 0)
Traceback (most recent call last):
...
ValueError: slice [4:0] out of range (4 bit value)
>>> slice((0xf, 4), 2, 3)
Traceback (most recent call last):
...
ValueError: cant slice reverse range
>>> slice((0xf, 4), 3, -1)
Traceback (most recent call last):
...
ValueError: slice [3:-1] out of range (4 bit value)
"""
(val, size) = bits
if hi < lo:
raise ValueError("cant slice reverse range")
elif lo < 0 or hi >= size:
raise ValueError("slice [{}:{}] out of range ({} bit value)".format(hi, lo, size))
size = hi - lo + 1
val = (val >> lo) & ((1 << size) - 1)
return (val, size)
|