git.s-ol.nu subv / 8cf8176
support offsets on labels s-ol 30 days ago
3 changed file(s) with 60 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
8383
8484 >>> default_slice(('label', 'imm12'), 12, 1)
8585 ('label[12:1]', 'imm12')
86 >>> default_slice(('label-4', 'imm12'), 12, 1)
87 ('label-4[12:1]', 'imm12')
8688 >>> default_slice(('label[14:3]', 'imm12'), 12, 1)
8789 ('label[14:3]', 'imm12')
90 >>> default_slice(('label+4[14:3]', 'imm12'), 12, 1)
91 ('label+4[14:3]', 'imm12')
8892 >>> default_slice(('label[14:3]', 'imm12', 'extra'), 12, 1)
8993 ('label[14:3]', 'imm12', 'extra')
9094 >>> default_slice(('label[31:0]', 'imm12'), 11, 0)
96100 if 'hi' not in parsed:
97101 parsed['hi'] = hi
98102 parsed['lo'] = lo
99
100 ref = '{label}[{hi}:{lo}]'.format(**parsed)
103 ref = subv.format_reference(parsed)
101104
102105 p_size = parsed['hi'] - parsed['lo'] + 1
103 assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref, p_size)
104
105 return (ref, *val[1:])
106 assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref[0], p_size)
107
108 return ref
106109
107110 def slice_bit_or_ref(val, hi, lo):
108111 """ bit.slice but for bitfields and label references.
11 white = re.compile(r'[ \t\.\n]+')
22 hex = re.compile(r'^\-?(0x)?[0-9a-f]+$')
33 num = re.compile(r'^\d+$')
4 slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$')
4 ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?(?:\[(\d+):(\d+)\])?$')
55 field_re = re.compile(r'^(imm|off)(\d+)$')
66
77 # parsing
9090 >>> parse_reference(('lbl', 'imm32'))
9191 {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': ()}
9292
93 >>> parse_reference(('lbl+0', 'imm32'))
94 {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 0}
95
96 >>> parse_reference(('lbl+2', 'imm32'))
97 {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 2}
98
9399 >>> parse_reference(('x[11:0]', 'off12'))
94100 {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0}
101
102 >>> parse_reference(('x-16[11:0]', 'off12'))
103 {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'offset': -16, 'hi': 11, 'lo': 0}
95104 """
96105 ref = part[0]
97106 field = part[1]
98107
99 label, hi, lo = slice_re.match(ref).groups()
108 label, off, hi, lo = ref_re.match(ref).groups()
100109 mode, size = field_re.match(field).groups()
101110
102111 ref = {
105114 'size': int(size),
106115 'meta': part[2:],
107116 }
117
118 if off is not None:
119 ref['offset'] = int(off)
108120
109121 if hi is not None:
110122 ref['hi'] = int(hi)
176188 True
177189 >>> is_reference(('hello:world',))
178190 True
191 >>> is_reference(('hello-4',))
192 True
193 >>> is_reference(('hello[11:0]',))
194 True
179195 >>> is_reference(('$label',))
180196 True
181197 >>> is_reference(('$label:extra',))
182198 True
183199 >>> is_reference(('$label:extra', 'off20'))
200 True
201 >>> is_reference(('$label+3[31:12]', 'off20'))
184202 True
185203 >>> is_reference(('plain', 'off20'))
186204 True
223241 if expect and part[1] != expect:
224242 raise ValueError("expected {} to be labelled {}".format(part, expect))
225243 return part[0]
244
245 def format_reference(ref):
246 """ opposite of parse_reference..
247
248 >>> format_reference({'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': ()})
249 ('lbl', 'imm32')
250 >>> format_reference({'label': 'lbl', 'offset': 0, 'mode': 'imm', 'size': 32, 'meta': ()})
251 ('lbl+0', 'imm32')
252 >>> format_reference({'label': 'lbl', 'offset': 2, 'mode': 'imm', 'size': 32, 'meta': ()})
253 ('lbl+2', 'imm32')
254 >>> format_reference({'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0})
255 ('x[11:0]', 'off12')
256 >>> format_reference({'label': 'x', 'offset': -16, 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0})
257 ('x-16[11:0]', 'off12')
258 >>> format_reference({'label': 'x', 'offset': -16, 'mode': 'off', 'size': 12, 'meta': ('extra', 'stuff'), 'hi': 11, 'lo': 0})
259 ('x-16[11:0]', 'off12', 'extra', 'stuff')
260 """
261 label = ref['label']
262 if 'offset' in ref:
263 label += '{:+}'.format(ref['offset'])
264 if 'hi' in ref:
265 label += '[{hi}:{lo}]'.format(**ref)
266 return (label, '{mode}{size}'.format(**ref), *ref['meta'])
226267
227268 def format_part(part):
228269 """ opposite of parse_part.
5959 (3, '3')
6060 >>> observe(('label[31:0]', 'imm32'), 0, {'label': 1234})
6161 (1234, 32)
62 >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 1234})
63 (1232, 32)
6264 >>> observe(('label[1:0]', 'imm32'), 0, {'label': 1234})
6365 (2, 2)
6466 >>> observe(('label[31:0]', 'off32'), 1000, {'label': 1234})
6769 (16, 20)
6870 >>> observe(('label[31:0]', 'off32'), 2000, {'label': 1000})
6971 (4294966296, 32)
72 >>> observe(('label+4[7:0]', 'off32'), 0x1000, {'label': 0x1234})
73 (56, 8)
74 >>> observe(('label+4[15:8]', 'off32'), 0x1000, {'label': 0x1234})
75 (2, 8)
7076
7177 >>> observe(('label[32:0]', 'imm32'), 0, {})
7278 Traceback (most recent call last):
7985 ref = subv.parse_reference(part)
8086 assert ref['label'] in map, "undefined label '{}'".format(ref['label'])
8187 addr = map[ref['label']]
88
89 if 'offset' in ref:
90 addr += ref['offset']
8291
8392 # @TODO: the hardcoded 32 here is not right, this is going to blow up
8493 # in some circumstances (e.g. a backwards branch 2<<18 bytes away)