git.s-ol.nu subv / acfaab0
turn bits into a class s-ol 29 days ago
5 changed file(s) with 163 addition(s) and 130 deletion(s). Raw diff Collapse all Expand all
0 empty = (0, 0)
0 class Bitfield(object):
1 def __init__(self, val, size):
2 self.val = val
3 self.size = size
4
5 def __repr__(self):
6 return "Bitfield(0x{:x}, {})".format(self.val, self.size)
7
8 def __str__(self):
9 return "0x{:x}'{}".format(self.val, self.size)
10
11 def __getitem__(self, range):
12 """ slice a bitfield given hi and lo bit indices.
13
14 >>> Bitfield(0x7f, 8)[7:4]
15 Bitfield(0x7, 4)
16 >>> Bitfield(0b100, 3)[2:2]
17 Bitfield(0x1, 1)
18 >>> Bitfield(0x12345678, 32)[7:0]
19 Bitfield(0x78, 8)
20 >>> Bitfield(0x12345678, 32)[15:8]
21 Bitfield(0x56, 8)
22 >>> Bitfield(0x12345678, 32)[23:16]
23 Bitfield(0x34, 8)
24
25 >>> Bitfield(0xf, 4)[4:0]
26 Traceback (most recent call last):
27 ...
28 ValueError: slice [4:0] out of range of 0xf'4
29 >>> Bitfield(0xf, 4)[2:3]
30 Traceback (most recent call last):
31 ...
32 ValueError: cant slice reverse range
33 >>> Bitfield(0xf, 4)[3:-1]
34 Traceback (most recent call last):
35 ...
36 ValueError: slice [3:-1] out of range of 0xf'4
37 """
38 if not isinstance(range, slice):
39 range = slice(range, range)
40 hi, lo = range.start, range.stop
41
42 if hi < lo:
43 raise ValueError("cant slice reverse range")
44 elif lo < 0 or hi >= self.size:
45 raise ValueError("slice [{0.start}:{0.stop}] out of range of {1}".format(range, self))
46
47 size = hi - lo + 1
48 val = (self.val >> lo) & ((1 << size) - 1)
49 return Bitfield(val, size)
50
51 def slice_allowempty(self, range):
52 if not isinstance(range, slice):
53 range = slice(range, range)
54 hi, lo = range.start, range.stop
55
56 if hi < lo:
57 return empty
58
59 return self[range]
60
61 def __and__(self, other):
62 """ concatenate multiple bitfields.
63
64 >>> Bitfield(0b00, 2) & Bitfield(0b10, 2)
65 Bitfield(0x2, 4)
66 >>> Bitfield(0b110, 3) & Bitfield(0b0110, 4) & Bitfield(0b1, 1)
67 Bitfield(0xcd, 8)
68 """
69 if not isinstance(other, Bitfield):
70 raise NotImplementedError()
71
72 return Bitfield(self.val << other.size | other.val, self.size + other.size)
73
74 empty = Bitfield(0, 0)
175
276 def u(num, bits):
377 """ parse an unsigned integer into a bitfield.
478
579 >>> u(0x08, 8)
6 (8, 8)
80 Bitfield(0x8, 8)
781 >>> u(0xff, 8)
8 (255, 8)
82 Bitfield(0xff, 8)
983
1084 >>> u(0xf0, 7)
1185 Traceback (most recent call last):
2397 raise ValueError("value {} (u{}) too large for u{} field"
2498 .format(num, num.bit_length(), bits))
2599
26 return (num, bits)
100 return Bitfield(num, bits)
27101
28102 def i(num, bits):
29103 """ parse a signed integer into a bitfield.
30104
31105 >>> i(8, 8)
32 (8, 8)
106 Bitfield(0x8, 8)
33107 >>> i(-4, 8)
34 (252, 8)
35 >>> i(127, 8)
36 (127, 8)
108 Bitfield(0xfc, 8)
109 >>> i(0x7f, 8)
110 Bitfield(0x7f, 8)
37111 >>> i(-128, 8)
38 (128, 8)
112 Bitfield(0x80, 8)
39113
40114 >>> i(128, 8)
41115 Traceback (most recent call last):
61135 def from_part(part):
62136 """ parse a size-tagged subv part into a bit.
63137
64 >>> from_part((34, 2))
65 (34, 2)
66 >>> from_part((34, 2, 'extra'))
67 (34, 2)
138 >>> from_part((0x12, 2))
139 Bitfield(0x12, 2)
140 >>> from_part((0x12, 2, 'extra'))
141 Bitfield(0x12, 2)
68142 """
69143 val = int(part[0])
70144 size = part[1]
71 return (val, int(size))
72
73 def concat(*parts):
74 """ concatenate multiple bitfields.
75
76 >>> concat((0b10, 2), (0b00, 2))
77 (2, 4)
78 >>> concat((0b1, 1), (0b0110, 4), (0b110, 3))
79 (205, 8)
80 """
81 val, size = 0, 0
82 for (pval, psize) in parts:
83 val = val | pval << size
84 size += psize
85 return (val, size)
86
87 def slice(bits, hi, lo, allow_empty=False):
88 """ slice a bitfield given hi and lo bit indices.
89
90 >>> slice((0x7f, 8), 7, 4)
91 (7, 4)
92 >>> slice((0b100, 3), 2, 2)
93 (1, 1)
94 >>> slice((0x12345678, 32), 7, 0)
95 (120, 8)
96 >>> slice((0x12345678, 32), 15, 8)
97 (86, 8)
98 >>> slice((0x12345678, 32), 23, 16)
99 (52, 8)
100
101 >>> slice((0xf, 4), 4, 0)
102 Traceback (most recent call last):
103 ...
104 ValueError: slice [4:0] out of range (4 bit value)
105 >>> slice((0xf, 4), 2, 3)
106 Traceback (most recent call last):
107 ...
108 ValueError: cant slice reverse range
109 >>> slice((0xf, 4), 2, 3, allow_empty=True)
110 (0, 0)
111 >>> slice((0xf, 4), 3, -1)
112 Traceback (most recent call last):
113 ...
114 ValueError: slice [3:-1] out of range (4 bit value)
115 """
116 (val, size) = bits
117
118 if hi < lo:
119 if allow_empty:
120 return empty
121 raise ValueError("cant slice reverse range")
122 elif lo < 0 or hi >= size:
123 raise ValueError("slice [{}:{}] out of range ({} bit value)".format(hi, lo, size))
124
125 size = hi - lo + 1
126 val = (val >> lo) & ((1 << size) - 1)
127 return (val, size)
145 return Bitfield(val, int(size))
6262 6f/7 00/5 main[19:12]/off8 main[11:11]/off1 main[10:1]/off10 main[20:20]/off1
6363 """
6464
65 from operator import __and__
66 from functools import reduce
6567 import subv
6668 import bits
6769
7981 }
8082
8183 def default_slice(val, hi, lo):
82 """ add a default slice spec to labels if missing,
84 """ add a default slice spec to labels if missing.
8385
8486 >>> default_slice(('label', 'imm12'), 12, 1)
8587 ('label[12:1]', 'imm12')
98100 """
99101 parsed = subv.parse_reference(val)
100102 if 'hi' not in parsed:
101 parsed['hi'] = hi
102 parsed['lo'] = lo
103 parsed['hi'] = hi
104 parsed['lo'] = lo
103105 ref = subv.format_reference(parsed)
104106
105107 p_size = parsed['hi'] - parsed['lo'] + 1
125127 ...
126128 AssertionError: cant slice label w/o bounds
127129 """
128 if not isinstance(val[0], str):
129 return bits.slice(val, hi, lo)
130 if isinstance(val, bits.Bitfield):
131 return val[hi:lo]
130132
131133 ref = subv.parse_reference(val)
132134 assert 'hi' in ref, "cant slice label w/o bounds"
147149 """ verify & pack U-type instructions.
148150
149151 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])
150 [(55, 7), (5, 5), (65552, 20)]
152 [Bitfield(0x37, 7), Bitfield(0x5, 5), Bitfield(0x10010, 20)]
151153
152154 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])
153 [(55, 7), (5, 5), ('pos[31:12]', 'imm20')]
155 [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[31:12]', 'imm20')]
154156
155157 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[19:0]', 'imm20')])
156 [(55, 7), (5, 5), ('pos[19:0]', 'imm20')]
158 [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[19:0]', 'imm20')]
157159
158160 >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')])
159161 Traceback (most recent call last):
173175 def pack_i(instr):
174176 """ verify & pack I-type instructions.
175177
176 >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')])
177 [(19, 7), (6, 5), (0, 3), (0, 5), (101, 12)]
178 >>> reduce(__and__, pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')]))
179 Bitfield(0x26600065, 32)
178180
179181 >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')])
180 [(19, 7), (6, 5), (0, 3), (0, 5), ('label[11:0]', 'imm12')]
182 [Bitfield(0x13, 7), Bitfield(0x6, 5), Bitfield(0x0, 3), Bitfield(0x0, 5), ('label[11:0]', 'imm12')]
181183 """
182184 (op, sub, rd, rs, imm) = instr
183185 op = bits.u(subv.untag(op), 7)
194196 def pack_s(instr):
195197 """ verify & pack S-type instructions.
196198
197 >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')])
198 [(35, 7), (0, 5), (2, 3), (5, 5), (6, 5), (0, 7)]
199 >>> reduce(__and__, pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')]))
200 Bitfield(0x46045300, 32)
199201
200202 >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')])
201 [(35, 7), ('home[4:0]', 'off5'), (2, 3), (5, 5), (6, 5), ('home[11:5]', 'off7')]
203 [Bitfield(0x23, 7), ('home[4:0]', 'off5'), Bitfield(0x2, 3), Bitfield(0x5, 5), Bitfield(0x6, 5), ('home[11:5]', 'off7')]
202204 """
203205 (op, sub, rs1, rs2, imm) = instr
204206 op = bits.u(subv.untag(op), 7)
218220 def pack_j(instr):
219221 """ verify & pack J-type instructions.
220222
221 >>> pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])
222 [(111, 7), (0, 5), (0, 8), (0, 1), (0, 10), (0, 1)]
223
224 >>> pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')])
225 [(111, 7), (0, 5), (255, 8), (1, 1), (1022, 10), (1, 1)]
223 >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')]))
224 Bitfield(0xde000000, 32)
225
226 >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')]))
227 Bitfield(0xde0ffffd, 32)
226228
227229 >>> pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')])
228 [(111, 7), (2, 5), ('home[19:12]', 'off8'), ('home[11:11]', 'off1'), ('home[10:1]', 'off10'), ('home[20:20]', 'off1')]
230 [Bitfield(0x6f, 7), Bitfield(0x2, 5), ('home[19:12]', 'off8'), ('home[11:11]', 'off1'), ('home[10:1]', 'off10'), ('home[20:20]', 'off1')]
229231 """
230232 (op, rd, imm) = instr
231233 op = bits.u(subv.untag(op), 7)
246248 def pack_b(instr):
247249 """ verify & pack B-type instructions.
248250
249 >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')])
250 [(99, 7), (0, 1), (0, 4), (0, 3), (6, 5), (0, 5), (0, 6), (0, 1)]
251
252 >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')])
253 [(99, 7), (1, 1), (14, 4), (0, 3), (6, 5), (0, 5), (63, 6), (1, 1)]
251 >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')]))
252 Bitfield(0xc6006000, 32)
253
254 >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')]))
255 Bitfield(0xc7e0607f, 32)
254256
255257 >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')])
256 [(99, 7), ('home[11:11]', 'off1'), ('home[4:1]', 'off4'), (0, 3), (6, 5), (0, 5), ('home[10:5]', 'off6'), ('home[12:12]', 'off1')]
258 [Bitfield(0x63, 7), ('home[11:11]', 'off1'), ('home[4:1]', 'off4'), Bitfield(0x0, 3), Bitfield(0x6, 5), Bitfield(0x0, 5), ('home[10:5]', 'off6'), ('home[12:12]', 'off1')]
257259 """
258260 (op, sub, rs1, rs2, imm) = instr
259261 op = bits.u(subv.untag(op), 7)
4343 def byteify(word):
4444 """ split longer bitfield into bytes.
4545
46 >>> byteify((0x12345678, 32))
46 >>> byteify(bits.Bitfield(0x12345678, 32))
4747 [(120,), (86,), (52,), (18,)]
48 >>> byteify((0x4801813, 32))
48 >>> byteify(bits.Bitfield(0x4801813, 32))
4949 [(19,), (24,), (128,), (4,)]
50 >>> byteify((0x13, 9)),
50 >>> byteify(bits.Bitfield(0x13, 9)),
5151 Traceback (most recent call last):
5252 ...
53 AssertionError: not byte aligned: 9 bits
53 AssertionError: not byte aligned: 0x13'9
5454 """
55 (val, size) = word
56 assert size % 8 == 0, "not byte aligned: {} bits".format(size)
55 assert word.size % 8 == 0, "not byte aligned: {}".format(word)
5756
5857 out = []
59 for i in range(0, size, 8):
60 byte = bits.slice(word, i+7, i)
61 out.append(byte[:1])
58 for i in range(0, word.size, 8):
59 byte = word[i+7:i]
60 out.append((byte.val,))
6261 return out
6362
6463 @subv.with_parsed_lines
7877 last_segment = None
7978 for segment, line in iter:
8079 if last_segment != segment:
81 assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment)
80 assert buf.size == 0, "segment '{}' end isn't byte-aligned".format(segment)
8281 if out:
8382 yield subv.format(flush_bytes())
8483
8584 if line['type'] == 'instr':
8685 for part in line['instr']:
87 buf = bits.concat(buf, bits.from_part(part))
86 buf = bits.from_part(part) & buf
8887 else:
8988 yield line['raw']
9089
91 while buf[1] >= 8:
92 byte = bits.slice(buf, 7, 0)
93 buf = bits.slice(buf, buf[1] - 1, 8, allow_empty=True)
94 out.append(byte[:1])
90 while buf.size >= 8:
91 byte = buf[7:0]
92 buf = buf.slice_allowempty(slice(buf.size-1, 8))
93 out.append((byte.val,))
9594
9695 if len(out) == 4:
9796 yield subv.format(flush_bytes())
9897
9998 last_segment = segment
10099
101 assert buf[1] == 0, "segment '{}' end isn't byte-aligned".format(segment)
100 assert buf.size == 0, "segment '{}' end isn't byte-aligned".format(segment)
102101
103102 if __name__ == '__main__':
104103 import sys
00 import re
1 import bits
12 white = re.compile(r'[ \t\.\n]+')
23 hex = re.compile(r'^\-?(0x)?[0-9a-f]+$')
34 num = re.compile(r'^\d+$')
229230 >>> untag(('$label', 'imm20'), expect='imm20')
230231 '$label'
231232
233 >>> untag((2, 'num'), expect=['num', 'imm20'])
234 2
235 >>> untag(('$label', 'imm20'), expect=['num', 'imm20'])
236 '$label'
237
232238 >>> untag((2, 'imm12'), expect='imm20')
233239 Traceback (most recent call last):
234240 ...
237243 Traceback (most recent call last):
238244 ...
239245 ValueError: expected ('$label', 'imm20') to be labelled off12
240 """
241 if expect and part[1] != expect:
246 >>> untag((2, 'imm12'), expect=['num', 'off12'])
247 Traceback (most recent call last):
248 ...
249 ValueError: expected (2, 'imm12') to be labelled one of ['num', 'off12']
250 """
251 if isinstance(expect, str) and part[1] != expect:
242252 raise ValueError("expected {} to be labelled {}".format(part, expect))
253 elif isinstance(expect, list) and part[1] not in expect:
254 raise ValueError("expected {} to be labelled one of {}".format(part, expect))
243255 return part[0]
244256
245257 def format_reference(ref):
286298 >>> format_part(('$label:suff', 'tag'))
287299 '$label:suff/tag'
288300 """
289 if not is_reference(part):
301 if isinstance(part, bits.Bitfield):
302 part = ('{:02x}'.format(part.val), part.size)
303 elif not is_reference(part):
290304 first = '{:02x}'.format(part[0])
291305 part = (first, *part[1:])
292306 return '/'.join([str(p) for p in part])
5757
5858 >>> observe((3, '3'), 0, {})
5959 (3, '3')
60 >>> observe(('label[31:0]', 'imm32'), 0, {'label': 1234})
61 (1234, 32)
62 >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 1234})
63 (1232, 32)
64 >>> observe(('label[1:0]', 'imm32'), 0, {'label': 1234})
65 (2, 2)
66 >>> observe(('label[31:0]', 'off32'), 1000, {'label': 1234})
67 (234, 32)
68 >>> observe(('label[31:12]', 'off32'), 1000, {'label': 0x10fff})
69 (16, 20)
70 >>> observe(('label[31:0]', 'off32'), 2000, {'label': 1000})
71 (4294966296, 32)
60 >>> observe(('label[31:0]', 'imm32'), 0, {'label': 0x1234})
61 Bitfield(0x1234, 32)
62 >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 0x1234})
63 Bitfield(0x1232, 32)
64 >>> observe(('label[1:0]', 'imm32'), 0, {'label': 0x1236})
65 Bitfield(0x2, 2)
66 >>> observe(('label[31:0]', 'off32'), 0x1000, {'label': 0x1234})
67 Bitfield(0x234, 32)
68 >>> observe(('label[31:12]', 'off32'), 0x1000, {'label': 0x10fff})
69 Bitfield(0xf, 20)
70 >>> observe(('label[31:0]', 'off32'), 0x2000, {'label': 0x1000})
71 Bitfield(0xfffff000, 32)
7272 >>> observe(('label+4[7:0]', 'off32'), 0x1000, {'label': 0x1234})
73 (56, 8)
73 Bitfield(0x38, 8)
7474 >>> observe(('label+4[15:8]', 'off32'), 0x1000, {'label': 0x1234})
75 (2, 8)
75 Bitfield(0x2, 8)
7676
7777 >>> observe(('label[32:0]', 'imm32'), 0, {})
7878 Traceback (most recent call last):
9696 else:
9797 addr = bits.i(addr - rel_addr, 32)
9898
99 return bits.slice(addr, ref['hi'], ref['lo'])
99 return addr[ref['hi']:ref['lo']]
100100
101101 @subv.with_parsed_lines
102102 def survey(iter):