aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-05-23 09:41:11 +0000
committers-ol <s+removethis@s-ol.nu>2021-05-23 09:41:11 +0000
commit8cf8176db625c93f940c2527e5e3bfb6b2d652de (patch)
tree40ca0f2c79478f10128d42357290d6134ae6e4ba
parentrevert to code detection by segment (diff)
downloadsubv-8cf8176db625c93f940c2527e5e3bfb6b2d652de.tar.gz
subv-8cf8176db625c93f940c2527e5e3bfb6b2d652de.zip
support offsets on labels
-rwxr-xr-xformat.py11
-rw-r--r--subv.py45
-rwxr-xr-xsurvey.py9
3 files changed, 59 insertions, 6 deletions
diff --git a/format.py b/format.py
index 7798589..9e0ead0 100755
--- a/format.py
+++ b/format.py
@@ -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.
diff --git a/subv.py b/subv.py
index fae4a3e..4f38988 100644
--- a/subv.py
+++ b/subv.py
@@ -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.
diff --git a/survey.py b/survey.py
index f8df47d..55a8ab0 100755
--- a/survey.py
+++ b/survey.py
@@ -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':