aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-05-25 13:42:02 +0000
committers-ol <s+removethis@s-ol.nu>2021-05-25 13:42:02 +0000
commit12ca589a55376687c13d2298392ca5ddb344a219 (patch)
treed53f03557db0072eeeb8c0433fbe5444be4510e7
parentuse new bits in format.py (diff)
downloadsubv-12ca589a55376687c13d2298392ca5ddb344a219.tar.gz
subv-12ca589a55376687c13d2298392ca5ddb344a219.zip
update all stages to work
-rw-r--r--bits.py52
-rwxr-xr-xformat.py58
-rwxr-xr-xpack.py4
-rw-r--r--subv.py5
-rwxr-xr-xsurvey.py137
-rw-r--r--test.subv10
6 files changed, 131 insertions, 135 deletions
diff --git a/bits.py b/bits.py
index 34284a2..dd49665 100644
--- a/bits.py
+++ b/bits.py
@@ -283,7 +283,7 @@ class LabelRef(WordBase):
Bitfield(0xa, 8)
"""
if self.label not in labels:
- raise ValueError("label '{}' unresolved".format(self.label))
+ raise ValueError("undefined label '{}'".format(self.label))
value = labels[self.label] + self.offset
@@ -404,3 +404,53 @@ def from_part(part):
val = int(part[0])
size = part[1]
return Bitfield(val, int(size))
+
+global_slice = slice
+ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?$')
+slice_re = re.compile(r'^\[(\d+):(\d+)]$')
+
+def ref(val, default_slice=None):
+ """ add a default slice spec to labels if missing.
+
+ >>> ref(('label', 'imm12'))
+ LabelRef('label', 0, ('imm', 12), 11:0)
+ >>> ref(('label', 'imm12'), slice(12, 1))
+ LabelRef('label', 0, ('imm', 12), 12:1)
+ >>> ref(('label-4', 'imm12'), slice(12, 1))
+ LabelRef('label', -4, ('imm', 12), 12:1)
+ >>> ref(('label', 'imm12', '[14:3]'), slice(12, 1))
+ LabelRef('label', 0, ('imm', 12), 14:3)
+ >>> ref(('label+4', 'imm12', '[14:3]'), slice(12, 1))
+ LabelRef('label', 4, ('imm', 12), 14:3)
+ >>> ref(('label', 'imm12', '[14:3]'), slice(12, 1))
+ LabelRef('label', 0, ('imm', 12), 14:3)
+ >>> ref(('label', 'imm12', '[31:0]'), slice(11, 0))
+ Traceback (most recent call last):
+ ...
+ AssertionError: expected 12 bit slice, got label/imm12/[31:0]
+ """
+ slice = None
+ if len(val) == 3:
+ label_offset, mode, slice = val
+ elif len(val) == 2:
+ label_offset, mode = val
+ else:
+ raise ValueError("expected label reference, got {}".format(val))
+
+ match = ref_re.match(label_offset)
+ assert match, ValueError("invalid label reference")
+ label, offset = match.group(1), int(match.group(2) or 0)
+
+ if isinstance(slice, str):
+ match = slice_re.match(slice)
+ assert match, ValueError("invalid slice syntax")
+ a, b = match.groups()
+ slice = global_slice(int(a), int(b))
+
+ ref = LabelRef(label, offset, mode, slice or default_slice)
+
+ if default_slice:
+ expected = default_slice.start - default_slice.stop + 1
+ assert expected == ref.size, ValueError("expected {} bit slice, got {}".format(expected, ref))
+
+ return ref
diff --git a/format.py b/format.py
index 385c632..942f4f8 100755
--- a/format.py
+++ b/format.py
@@ -98,54 +98,6 @@ def sign_trunc(val, size):
rest = val[size-2:0]
return sign & rest
-global_slice = slice
-def default_slice(val, hi, lo):
- """ add a default slice spec to labels if missing.
-
- >>> default_slice(('label', 'imm12'), 12, 1)
- LabelRef('label', 0, ('imm', 12), 12:1)
- >>> default_slice(('label-4', 'imm12'), 12, 1)
- LabelRef('label', -4, ('imm', 12), 12:1)
- >>> default_slice(('label', 'imm12', '[14:3]'), 12, 1)
- LabelRef('label', 0, ('imm', 12), 14:3)
- >>> default_slice(('label+4', 'imm12', '[14:3]'), 12, 1)
- LabelRef('label', 4, ('imm', 12), 14:3)
- >>> default_slice(('label', 'imm12', '[14:3]'), 12, 1)
- LabelRef('label', 0, ('imm', 12), 14:3)
- >>> default_slice(('label', 'imm12', '[31:0]'), 11, 0)
- Traceback (most recent call last):
- ...
- AssertionError: expected 12 bit slice, got label/imm12/[31:0]
- """
- if len(val) == 3:
- label_offset, mode, slice = val
- elif len(val) == 2:
- label_offset, mode = val
- slice = global_slice(hi, lo)
- else:
- raise ValueError("expected label reference")
-
- import re
-
- ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?$')
- slice_re = re.compile(r'^\[(\d+):(\d+)]$')
-
- match = ref_re.match(label_offset)
- assert match, ValueError("invalid label reference")
- label, offset = match.group(1), int(match.group(2) or 0)
-
- if isinstance(slice, str):
- match = slice_re.match(slice)
- assert match, ValueError("invalid slice syntax")
- a, b = match.groups()
- slice = global_slice(int(a), int(b))
-
- ref = bits.LabelRef(label, offset, mode, slice)
-
- expected = hi - lo + 1
- assert expected == ref.size, ValueError("expected {} bit slice, got {}".format(expected, ref))
- return ref
-
def pack_u(instr):
""" verify & pack U-type instructions.
@@ -167,7 +119,7 @@ def pack_u(instr):
op = bits.u(subv.untag(op), 7)
rd = bits.u(subv.untag(rd, 'rd'), 5)
if subv.is_reference(imm):
- imm = default_slice(imm, 31, 12)
+ imm = bits.ref(imm, slice(31, 12))
else:
imm = bits.i(subv.untag(imm, 'imm20'), 20)
@@ -188,7 +140,7 @@ def pack_i(instr):
rd = bits.u(subv.untag(rd, 'rd'), 5)
rs = bits.u(subv.untag(rs, 'rs'), 5)
if subv.is_reference(imm):
- imm = default_slice(imm, 11, 0)
+ imm = bits.ref(imm, slice(11, 0))
else:
imm = bits.i(subv.untag(imm, 'imm12'), 12)
@@ -210,7 +162,7 @@ def pack_s(instr):
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
if subv.is_reference(imm):
- imm = default_slice(imm, 11, 0)
+ imm = bits.ref(imm, slice(11, 0))
else:
imm = bits.i(subv.untag(imm, 'off12'), 12)
@@ -235,7 +187,7 @@ def pack_j(instr):
rd = bits.u(subv.untag(rd, 'rd'), 5)
if subv.is_reference(imm):
- imm = default_slice(imm, 20, 1)
+ imm = bits.ref(imm, slice(20, 1))
else:
imm = bits.i(subv.untag(imm, 'off20'), 20)
@@ -265,7 +217,7 @@ def pack_b(instr):
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
if subv.is_reference(imm):
- imm = default_slice(imm, 12, 1)
+ imm = bits.ref(imm, slice(12, 1))
else:
imm = bits.i(subv.untag(imm, 'off12'), 12)
diff --git a/pack.py b/pack.py
index 5dbaf95..cf531af 100755
--- a/pack.py
+++ b/pack.py
@@ -19,7 +19,7 @@ Packs bitfields tagged with their size into untagged bytes.
... 23/7 00/5 02/3 05/5 06/5 00/7
... 13/7 06/5 00/3 00/5 0a/12
... 23/7 00/5 02/3 05/5 06/5 00/7
-... 6f/7 00/5 ff/8 01/1 3e6/10 01/1
+... 6f/7 00/5 ff/8 1/1 3e6/10 1/1
... '''[1:-1]))))
== code 0x80000000
b7 02 01 10
@@ -51,7 +51,7 @@ def byteify(word):
>>> byteify(bits.Bitfield(0x13, 9)),
Traceback (most recent call last):
...
- AssertionError: not byte aligned: 0x13'9
+ AssertionError: not byte aligned: 013/9
"""
assert word.size % 8 == 0, "not byte aligned: {}".format(word)
diff --git a/subv.py b/subv.py
index ed30308..c8e6048 100644
--- a/subv.py
+++ b/subv.py
@@ -368,11 +368,12 @@ class LineIterator(object):
return (self.segment, self.line)
def exception(self, msg):
+ stream_name = getattr(self.stream, 'name', '(unnamed)')
if self.line:
- msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, format(self.line))
+ msg = msg + "\n{}:{}: {}".format(stream_name, self.i, format(self.line))
msg = msg + "\nparsed as {}".format(dump(self.line))
elif self.raw_line:
- msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, self.raw_line.strip())
+ msg = msg + "\n{}:{}: {}".format(stream_name, self.i, self.raw_line.strip())
return SubVException(msg)
def with_parsed_lines(process_fn):
diff --git a/survey.py b/survey.py
index bfd9313..6d6aae1 100755
--- a/survey.py
+++ b/survey.py
@@ -10,25 +10,25 @@ Resolves label references and substitutes them with literal values.
... # load 0x10010000 (UART0) into t0
... 37/7 05/5 10010/20
... # store 0x48 (H) in UART0+0
-... 13/7 06/5 00/3 00/5 48/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 048/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # store 0x65 (e) in UART0+0
-... 13/7 06/5 00/3 00/5 65/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 065/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # store 0x6c (l) in UART0+0
-... 13/7 06/5 00/3 00/5 6c/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 06c/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # store 0x6c (l) in UART0+0
-... 13/7 06/5 00/3 00/5 6c/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 06c/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # store 0x6f (o) in UART0+0
-... 13/7 06/5 00/3 00/5 6f/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 06f/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # store 0x0a (\\\\n) in UART0+0
-... 13/7 06/5 00/3 00/5 0a/12
-... 23/7 00/5 02/3 05/5 06/5 00/7
+... 13/7 06/5 0/3 00/5 00a/12
+... 23/7 00/5 2/3 05/5 06/5 00/7
... # jump back up to the top
-... 6f/7 00/5 main[19:12]/off8 main[11:11]/off1 main[10:1]/off10 main[20:20]/off1
+... 6f/7 00/5 main/off21/[19:12] main/off21/[11:11] main/off21/[10:1] main/off21/[20:20]
... '''[1:-1]))))
== code 0x80000000
37/7 05/5 10010/20
@@ -44,7 +44,7 @@ Resolves label references and substitutes them with literal values.
23/7 00/5 02/3 05/5 06/5 00/7
13/7 06/5 00/3 00/5 0a/12
23/7 00/5 02/3 05/5 06/5 00/7
-6f/7 00/5 ff/8 01/1 3e6/10 01/1
+6f/7 00/5 ff/8 1/1 3e6/10 1/1
"""
import subv
import bits
@@ -53,57 +53,44 @@ import re
slice_re = re.compile(r'^([^\[]+)(?:\[(\d+):(\d+)\])?$')
field_re = re.compile(r'^(imm|off)(\d+)$')
-def observe(part, rel_addr, map):
+def observe(word, pc, map):
""" resolve a label reference.
>>> observe((3, '3'), 0, {})
(3, '3')
- >>> observe(('label[31:0]', 'imm32'), 0, {'label': 0x1234})
+ >>> observe(('label', 'imm32', '[31:0]'), 0, {'label': 0x1234})
Bitfield(0x1234, 32)
- >>> observe(('label-2[31:0]', 'imm32'), 0, {'label': 0x1234})
+ >>> observe(('label-2', 'imm32', '[31:0]'), 0, {'label': 0x1234})
Bitfield(0x1232, 32)
- >>> observe(('label[1:0]', 'imm32'), 0, {'label': 0x1236})
+ >>> observe(('label', 'imm32', '[1:0]'), 0, {'label': 0x1236})
Bitfield(0x2, 2)
- >>> observe(('label[31:0]', 'off32'), 0x1000, {'label': 0x1234})
+ >>> observe(('label', 'off32', '[31:0]'), 0x1000, {'label': 0x1234})
Bitfield(0x234, 32)
- >>> observe(('label[31:12]', 'off32'), 0x1000, {'label': 0x10fff})
+ >>> observe(('label', 'off32', '[31:12]'), 0x1000, {'label': 0x10fff})
Bitfield(0xf, 20)
- >>> observe(('label[31:0]', 'off32'), 0x2000, {'label': 0x1000})
+ >>> observe(('label', 'off32', '[31:0]'), 0x2000, {'label': 0x1000})
Bitfield(0xfffff000, 32)
- >>> observe(('label+4[7:0]', 'off32'), 0x1000, {'label': 0x1234})
+ >>> observe(('label+4', 'off32', '[7:0]'), 0x1000, {'label': 0x1234})
Bitfield(0x38, 8)
- >>> observe(('label+4[15:8]', 'off32'), 0x1000, {'label': 0x1234})
+ >>> observe(('label+4', 'off32', '[15:8]'), 0x1000, {'label': 0x1234})
Bitfield(0x2, 8)
- >>> observe(('label[32:0]', 'imm32'), 0, {})
+ >>> observe(('label', 'imm32', '[32:0]'), 0, {})
Traceback (most recent call last):
...
- AssertionError: undefined label 'label'
+ ValueError: undefined label 'label'
"""
- if not subv.is_reference(part):
- return part
+ if not subv.is_reference(word):
+ return word
- ref = subv.parse_reference(part)
- 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':
- addr = bits.u(addr, 32)
- else:
- addr = bits.i(addr - rel_addr, 32)
-
- return addr[ref['hi']:ref['lo']]
+ word = bits.ref(word)
+ return word.as_value(pc=pc, labels=map)
@subv.with_parsed_lines
def survey(iter):
queue = []
map = {}
- addr, bits = -1, 0
+ addr, bitcount = -1, 0
for segment, line in iter:
line['addr'] = addr
queue.append(line)
@@ -111,52 +98,58 @@ def survey(iter):
# step forward addr
type = line['type']
if type == 'segment':
- addr, bits = line['segment'][1], 0
+ addr, bitcount = line['segment'][1], 0
elif type == 'label':
- assert bits == 0, "label isn't byte aligned"
+ assert bitcount == 0, "label isn't byte aligned"
map[line['label']] = addr
elif type == 'instr':
if segment == 'data':
for part in line['instr']:
- bits += int(part[1])
+ bitcount += int(part[1])
- if bits >= 8:
- addr += bits // 8
- bits = bits % 8
+ if bitcount >= 8:
+ addr += bitcount // 8
+ bitcount = bitcount % 8
elif segment == 'code':
- assert bits == 0, "instruction isn't byte aligned ({} bits left)".format(8 - bits)
+ assert bitcount == 0, "instruction isn't byte aligned ({} bitcount left)".format(8 - bitcount)
assert addr % 2 == 0, "instruction isn't 2-byte aligned"
- bits = 0
+ bitcount = 0
for part in line['instr']:
if subv.is_reference(part):
- ref = subv.parse_reference(part)
- bits += ref['size']
+ ref = bits.ref(part)
+ bitcount += ref.size
else:
- bits += int(part[1])
+ bitcount += int(part[1])
- assert bits % 8 == 0, "instruction size not multiple of 8 bits: {}".format(bits)
- addr += bits // 8
- bits = 0
+ assert bitcount % 8 == 0, "instruction size not multiple of 8 bitcount: {}".format(bitcount)
+ addr += bitcount // 8
+ bitcount = 0
else:
raise ValueError("unknown segment '{}'".format(segment))
- for line in queue:
- type = line['type']
- if type == 'instr':
- instr = []
+ for i, line in enumerate(queue, start=1):
+ try:
+ type = line['type']
if type == 'instr':
- # strip label from opcode
- op = line[type].pop(0)
- instr.append(op[:2])
-
- for part in line[type]:
- observed = observe(part, line['addr'], map)
- instr.append(observed)
- line[type] = instr
- yield subv.format(line)
- elif type == 'segment':
- yield line['raw']
+ instr = []
+ if type == 'instr':
+ # strip label from opcode
+ op = line[type].pop(0)
+ instr.append(op[:2])
+
+ for part in line[type]:
+ observed = observe(part, line['addr'], map)
+ instr.append(observed)
+ line[type] = instr
+ yield subv.format(line)
+ elif type == 'segment':
+ yield line['raw']
+ except Exception as e:
+ msg = "failed to survey line"
+ msg = msg + "\n{}:{}: {}".format('(unknown)', i, subv.format(line))
+ msg = msg + "\nparsed as {}".format(subv.dump(line))
+ raise subv.SubVException(msg) from e
if __name__ == '__main__':
import sys
diff --git a/test.subv b/test.subv
index c3b2e8c..aa7d010 100644
--- a/test.subv
+++ b/test.subv
@@ -5,25 +5,25 @@ main:
# x4 = &message
# . load high bits
- 37/lui 4/rd/x4 Message/imm20
+ 37/lui 4/rd/x4 Message/imm
# . add low bits
- 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/imm12
+ 13/opi 0/subop/add 4/rd/x4 4/rs/x4 Message/imm
print:loop:
# load unsigned byte at x4
03/load 4/subop/lbu 6/rd/t1 4/rs/x4 0/imm12
# break loop if zero
- 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off12
+ 63/branch 0/subop/== 6/rs/t1 0/rs/x0 print:break/off13
# print char
23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12
# increment x4
13/opi 0/subop/add 4/rd/x4 4/rs/x4 1/imm12
# jump back up
- 6f/jal 0/rd/x0 print:loop/off20
+ 6f/jal 0/rd/x0 print:loop/off21
print:break:
loop:
# infinite loop
- 6f/jal 0/rd/x0 loop/off20
+ 6f/jal 0/rd/x0 loop/off21
== data 0x80001000
Message: