aboutsummaryrefslogtreecommitdiffstats
path: root/format.py
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-05-29 11:50:25 +0000
committers-ol <s-ol@users.noreply.github.com>2020-05-29 11:50:25 +0000
commit517f3e141c3e3bede4e7b0c0ea7237544f28ce90 (patch)
treed8e12207c006bc5e03a0fea3ddbab261ac09e6c7 /format.py
parentnew label-slice syntax in format.py; switch to doctest (diff)
downloadsubv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.tar.gz
subv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.zip
switch bit.py, subv.py to doctest
Diffstat (limited to 'format.py')
-rwxr-xr-xformat.py90
1 files changed, 46 insertions, 44 deletions
diff --git a/format.py b/format.py
index 0fed092..e97fac2 100755
--- a/format.py
+++ b/format.py
@@ -1,5 +1,14 @@
#!/usr/bin/env python3
-"""
+""" format.py
+Verifies instruction formats, orders and pre-bit-packs arguments.
+Every instruction-line in the code segment needs to start with the opcode,
+which has to be correctly tagged. Arguments have to be provided in the correct
+order currently, and their first tag is verified also.
+
+Labels can be referenced in the immXX/offXX fields of most instructions. If no
+bitslice is given for the labels, the default slice is picked based on the
+instruction.
+
>>> from io import StringIO
>>> # doctest: +REPORT_NDIFF
... print(subv.join_all(format(StringIO('''
@@ -57,18 +66,6 @@ main:
import subv
import bits
-instr_map = {
- 'opr': ('r', 0x33),
- 'load': ('i', 0x03),
- 'opi': ('i', 0x13),
- 'jalr': ('i', 0x67),
- 'store': ('s', 0x23),
- 'branch': ('b', 0x63),
- 'lui': ('u', 0x37),
- 'auipc': ('u', 0x17),
- 'jal': ('j', 0x6f),
-}
-
def ref_slice(ref, hi, lo):
if hi < lo:
raise ValueError("cant slice reverse range")
@@ -83,7 +80,8 @@ def ref_slice(ref, hi, lo):
}
def default_slice(val, hi, lo):
- """ ...
+ """ add a default slice spec to labels if missing,
+
>>> default_slice(('label', 'imm12'), 12, 1)
('label[12:1]', 'imm12')
>>> default_slice(('label[14:3]', 'imm12'), 12, 1)
@@ -93,7 +91,7 @@ def default_slice(val, hi, lo):
>>> default_slice(('label[31:0]', 'imm12'), 11, 0)
Traceback (most recent call last):
...
- AssertionError: slice doesnt match metadata
+ AssertionError: expected 12 bit slice
"""
parsed = subv.parse_reference(val)
if 'hi' not in parsed:
@@ -101,13 +99,14 @@ def default_slice(val, hi, lo):
parsed['lo'] = lo
p_size = parsed['hi'] - parsed['lo'] + 1
- assert parsed['size'] == p_size, "slice doesnt match metadata"
+ assert parsed['size'] == p_size, "expected {} bit slice".format(parsed['size'])
ref = '{label}[{hi}:{lo}]'.format(**parsed)
return (ref, *val[1:])
def slice_bit_or_ref(val, hi, lo):
- """ ...
+ """ bit.slice but for bitfields and label references.
+
>>> slice_bit_or_ref(('label[31:0]', 'imm32'), 12, 1)
('label[12:1]', 'imm12')
>>> slice_bit_or_ref(('label[31:0]', 'off32'), 11, 0)
@@ -156,12 +155,12 @@ def pack_u(instr):
>>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')])
Traceback (most recent call last):
...
- AssertionError: slice doesnt match metadata
+ AssertionError: expected 20 bit slice
"""
(op, rd, imm) = instr
op = bits.u(subv.untag(op), 7)
rd = bits.u(subv.untag(rd, 'rd'), 5)
- if subv.is_lref(imm):
+ if subv.is_reference(imm):
imm = default_slice(imm, 31, 12)
else:
imm = bits.i(subv.untag(imm, 'imm20'), 20)
@@ -170,6 +169,7 @@ def pack_u(instr):
def pack_i(instr):
""" verify & pack I-type instructions.
+
>>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')])
[(19, 7), (6, 5), (0, 3), (0, 5), (101, 12)]
@@ -181,7 +181,7 @@ def pack_i(instr):
sub = bits.u(subv.untag(sub, 'subop'), 3)
rd = bits.u(subv.untag(rd, 'rd'), 5)
rs = bits.u(subv.untag(rs, 'rs'), 5)
- if subv.is_lref(imm):
+ if subv.is_reference(imm):
imm = default_slice(imm, 11, 0)
else:
imm = bits.i(subv.untag(imm, 'imm12'), 12)
@@ -189,7 +189,8 @@ def pack_i(instr):
return [op, rd, sub, rs, imm]
def pack_s(instr):
- """
+ """ verify & pack S-type instructions.
+
>>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')])
[(35, 7), (0, 5), (2, 3), (5, 5), (6, 5), (0, 7)]
@@ -202,7 +203,7 @@ def pack_s(instr):
rs1 = bits.u(subv.untag(rs1, 'rs'), 5)
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
- if subv.is_lref(imm):
+ if subv.is_reference(imm):
imm = default_slice(imm, 11, 0)
else:
imm = bits.i(subv.untag(imm, 'off12'), 12)
@@ -212,7 +213,8 @@ def pack_s(instr):
return [op, imm_lo, sub, rs1, rs2, imm_hi]
def pack_j(instr):
- """
+ """ verify & pack J-type instructions.
+
>>> pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])
[(111, 7), (0, 5), (0, 8), (0, 1), (0, 10), (0, 1)]
@@ -226,7 +228,7 @@ def pack_j(instr):
op = bits.u(subv.untag(op), 7)
rd = bits.u(subv.untag(rd, 'rd'), 5)
- if subv.is_lref(imm):
+ if subv.is_reference(imm):
imm = default_slice(imm, 20, 1)
else:
imm = bits.i(subv.untag(imm, 'off20'), 20)
@@ -239,7 +241,8 @@ def pack_j(instr):
return [op, rd, imm_hi, imm_11, imm_lo, imm_20]
def pack_b(instr):
- """
+ """ verify & pack B-type instructions.
+
>>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')])
[(99, 7), (0, 1), (0, 4), (0, 3), (6, 5), (0, 5), (0, 6), (0, 1)]
@@ -255,7 +258,7 @@ def pack_b(instr):
rs1 = bits.u(subv.untag(rs1, 'rs'), 5)
rs2 = bits.u(subv.untag(rs2, 'rs'), 5)
- if subv.is_lref(imm):
+ if subv.is_reference(imm):
imm = default_slice(imm, 12, 1)
else:
imm = bits.i(subv.untag(imm, 'off12'), 12)
@@ -266,38 +269,37 @@ def pack_b(instr):
imm_12 = slice_bit_or_ref(imm, 11, 11) # + ('off[12]',)
return [op, imm_11, imm_lo, sub, rs1, rs2, imm_md, imm_12]
+instr_map = {
+ # 'opr': (pack_r, 0x33),
+ 'load': (pack_i, 0x03),
+ 'opi': (pack_i, 0x13),
+ 'jalr': (pack_i, 0x67),
+ 'store': (pack_s, 0x23),
+ 'branch': (pack_b, 0x63),
+ 'lui': (pack_u, 0x37),
+ 'auipc': (pack_u, 0x17),
+ 'jal': (pack_j, 0x6f),
+}
+
def format(iter):
segment = None
for line in iter:
line = subv.parse(line)
if segment == 'code' and line['type'] == 'instr':
- instr = line['instr']
- op = instr[0]
- assert len(op) == 2, 'instruction without op label: {}'.format(instr)
+ op = line['instr'][0]
+ assert len(op) == 2, 'instruction without op label: {}'.format(op)
(op, label) = op
if label not in instr_map:
raise ValueError("unknown instruction label: {}".format(label))
- (format, expected) = instr_map[label]
+ (formatter, expected) = instr_map[label]
if op != expected:
raise ValueError("opcode {} doesn't match label {} (expected {})"
.format(op, label, expected))
- if format == 'u':
- out = pack_u(instr)
- elif format == 'i':
- out = pack_i(instr)
- elif format == 's':
- out = pack_s(instr)
- elif format == 'j':
- out = pack_j(instr)
- elif format == 'b':
- out = pack_b(instr)
- else:
- raise NotImplementedError()
-
- yield subv.format_instr(out)
+ line['instr'] = formatter(line['instr'])
+ yield subv.format(line)
else:
if line['type'] == 'segment':
segment = line['segment'][0]