diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-05-23 09:41:11 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-05-23 09:41:11 +0000 |
| commit | 8cf8176db625c93f940c2527e5e3bfb6b2d652de (patch) | |
| tree | 40ca0f2c79478f10128d42357290d6134ae6e4ba | |
| parent | revert to code detection by segment (diff) | |
| download | subv-8cf8176db625c93f940c2527e5e3bfb6b2d652de.tar.gz subv-8cf8176db625c93f940c2527e5e3bfb6b2d652de.zip | |
support offsets on labels
| -rwxr-xr-x | format.py | 11 | ||||
| -rw-r--r-- | subv.py | 45 | ||||
| -rwxr-xr-x | survey.py | 9 |
3 files changed, 59 insertions, 6 deletions
@@ -84,8 +84,12 @@ def default_slice(val, hi, lo): >>> default_slice(('label', 'imm12'), 12, 1) ('label[12:1]', 'imm12') + >>> default_slice(('label-4', 'imm12'), 12, 1) + ('label-4[12:1]', 'imm12') >>> default_slice(('label[14:3]', 'imm12'), 12, 1) ('label[14:3]', 'imm12') + >>> default_slice(('label+4[14:3]', 'imm12'), 12, 1) + ('label+4[14:3]', 'imm12') >>> default_slice(('label[14:3]', 'imm12', 'extra'), 12, 1) ('label[14:3]', 'imm12', 'extra') >>> default_slice(('label[31:0]', 'imm12'), 11, 0) @@ -97,13 +101,12 @@ def default_slice(val, hi, lo): if 'hi' not in parsed: parsed['hi'] = hi parsed['lo'] = lo - - ref = '{label}[{hi}:{lo}]'.format(**parsed) + ref = subv.format_reference(parsed) p_size = parsed['hi'] - parsed['lo'] + 1 - assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref, p_size) + assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref[0], p_size) - return (ref, *val[1:]) + return ref def slice_bit_or_ref(val, hi, lo): """ bit.slice but for bitfields and label references. @@ -2,7 +2,7 @@ import re white = re.compile(r'[ \t\.\n]+') hex = re.compile(r'^\-?(0x)?[0-9a-f]+$') num = re.compile(r'^\d+$') -slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$') +ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?(?:\[(\d+):(\d+)\])?$') field_re = re.compile(r'^(imm|off)(\d+)$') # parsing @@ -91,13 +91,22 @@ def parse_reference(part): >>> parse_reference(('lbl', 'imm32')) {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': ()} + >>> parse_reference(('lbl+0', 'imm32')) + {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 0} + + >>> parse_reference(('lbl+2', 'imm32')) + {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 2} + >>> parse_reference(('x[11:0]', 'off12')) {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0} + + >>> parse_reference(('x-16[11:0]', 'off12')) + {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'offset': -16, 'hi': 11, 'lo': 0} """ ref = part[0] field = part[1] - label, hi, lo = slice_re.match(ref).groups() + label, off, hi, lo = ref_re.match(ref).groups() mode, size = field_re.match(field).groups() ref = { @@ -107,6 +116,9 @@ def parse_reference(part): 'meta': part[2:], } + if off is not None: + ref['offset'] = int(off) + if hi is not None: ref['hi'] = int(hi) ref['lo'] = int(lo) @@ -177,12 +189,18 @@ def is_reference(part): True >>> is_reference(('hello:world',)) True + >>> is_reference(('hello-4',)) + True + >>> is_reference(('hello[11:0]',)) + True >>> is_reference(('$label',)) True >>> is_reference(('$label:extra',)) True >>> is_reference(('$label:extra', 'off20')) True + >>> is_reference(('$label+3[31:12]', 'off20')) + True >>> is_reference(('plain', 'off20')) True @@ -225,6 +243,29 @@ def untag(part, expect=None): raise ValueError("expected {} to be labelled {}".format(part, expect)) return part[0] +def format_reference(ref): + """ opposite of parse_reference.. + + >>> format_reference({'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': ()}) + ('lbl', 'imm32') + >>> format_reference({'label': 'lbl', 'offset': 0, 'mode': 'imm', 'size': 32, 'meta': ()}) + ('lbl+0', 'imm32') + >>> format_reference({'label': 'lbl', 'offset': 2, 'mode': 'imm', 'size': 32, 'meta': ()}) + ('lbl+2', 'imm32') + >>> format_reference({'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0}) + ('x[11:0]', 'off12') + >>> format_reference({'label': 'x', 'offset': -16, 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0}) + ('x-16[11:0]', 'off12') + >>> format_reference({'label': 'x', 'offset': -16, 'mode': 'off', 'size': 12, 'meta': ('extra', 'stuff'), 'hi': 11, 'lo': 0}) + ('x-16[11:0]', 'off12', 'extra', 'stuff') + """ + label = ref['label'] + if 'offset' in ref: + label += '{:+}'.format(ref['offset']) + if 'hi' in ref: + label += '[{hi}:{lo}]'.format(**ref) + return (label, '{mode}{size}'.format(**ref), *ref['meta']) + def format_part(part): """ opposite of parse_part. @@ -60,6 +60,8 @@ def observe(part, rel_addr, map): (3, '3') >>> observe(('label[31:0]', 'imm32'), 0, {'label': 1234}) (1234, 32) + >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 1234}) + (1232, 32) >>> observe(('label[1:0]', 'imm32'), 0, {'label': 1234}) (2, 2) >>> observe(('label[31:0]', 'off32'), 1000, {'label': 1234}) @@ -68,6 +70,10 @@ def observe(part, rel_addr, map): (16, 20) >>> observe(('label[31:0]', 'off32'), 2000, {'label': 1000}) (4294966296, 32) + >>> observe(('label+4[7:0]', 'off32'), 0x1000, {'label': 0x1234}) + (56, 8) + >>> observe(('label+4[15:8]', 'off32'), 0x1000, {'label': 0x1234}) + (2, 8) >>> observe(('label[32:0]', 'imm32'), 0, {}) Traceback (most recent call last): @@ -81,6 +87,9 @@ def observe(part, rel_addr, map): assert ref['label'] in map, "undefined label '{}'".format(ref['label']) addr = map[ref['label']] + if 'offset' in ref: + addr += ref['offset'] + # @TODO: the hardcoded 32 here is not right, this is going to blow up # in some circumstances (e.g. a backwards branch 2<<18 bytes away) if ref['mode'] == 'imm': |
