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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
class Bitfield(object):
def __init__(self, val, size):
self.val = val
self.size = size
def __repr__(self):
return "Bitfield(0x{:x}, {})".format(self.val, self.size)
def __str__(self):
return "0x{:x}'{}".format(self.val, self.size)
def __getitem__(self, range):
""" slice a bitfield given hi and lo bit indices.
>>> Bitfield(0x7f, 8)[7:4]
Bitfield(0x7, 4)
>>> Bitfield(0b100, 3)[2:2]
Bitfield(0x1, 1)
>>> Bitfield(0x12345678, 32)[7:0]
Bitfield(0x78, 8)
>>> Bitfield(0x12345678, 32)[15:8]
Bitfield(0x56, 8)
>>> Bitfield(0x12345678, 32)[23:16]
Bitfield(0x34, 8)
>>> Bitfield(0xf, 4)[4:0]
Traceback (most recent call last):
...
ValueError: slice [4:0] out of range of 0xf'4
>>> Bitfield(0xf, 4)[2:3]
Traceback (most recent call last):
...
ValueError: cant slice reverse range
>>> Bitfield(0xf, 4)[3:-1]
Traceback (most recent call last):
...
ValueError: slice [3:-1] out of range of 0xf'4
"""
if not isinstance(range, slice):
range = slice(range, range)
hi, lo = range.start, range.stop
if hi < lo:
raise ValueError("cant slice reverse range")
elif lo < 0 or hi >= self.size:
raise ValueError("slice [{0.start}:{0.stop}] out of range of {1}".format(range, self))
size = hi - lo + 1
val = (self.val >> lo) & ((1 << size) - 1)
return Bitfield(val, size)
def slice_allowempty(self, range):
if not isinstance(range, slice):
range = slice(range, range)
hi, lo = range.start, range.stop
if hi < lo:
return empty
return self[range]
def __and__(self, other):
""" concatenate multiple bitfields.
>>> Bitfield(0b00, 2) & Bitfield(0b10, 2)
Bitfield(0x2, 4)
>>> Bitfield(0b110, 3) & Bitfield(0b0110, 4) & Bitfield(0b1, 1)
Bitfield(0xcd, 8)
"""
if not isinstance(other, Bitfield):
raise NotImplementedError()
return Bitfield(self.val << other.size | other.val, self.size + other.size)
empty = Bitfield(0, 0)
def u(num, bits):
""" parse an unsigned integer into a bitfield.
>>> u(0x08, 8)
Bitfield(0x8, 8)
>>> u(0xff, 8)
Bitfield(0xff, 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 Bitfield(num, bits)
def i(num, bits):
""" parse a signed integer into a bitfield.
>>> i(8, 8)
Bitfield(0x8, 8)
>>> i(-4, 8)
Bitfield(0xfc, 8)
>>> i(0x7f, 8)
Bitfield(0x7f, 8)
>>> i(-128, 8)
Bitfield(0x80, 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((0x12, 2))
Bitfield(0x12, 2)
>>> from_part((0x12, 2, 'extra'))
Bitfield(0x12, 2)
"""
val = int(part[0])
size = part[1]
return Bitfield(val, int(size))
|