diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-29 11:50:25 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-05-29 11:50:25 +0000 |
| commit | 517f3e141c3e3bede4e7b0c0ea7237544f28ce90 (patch) | |
| tree | d8e12207c006bc5e03a0fea3ddbab261ac09e6c7 /format.py | |
| parent | new label-slice syntax in format.py; switch to doctest (diff) | |
| download | subv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.tar.gz subv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.zip | |
switch bit.py, subv.py to doctest
Diffstat (limited to 'format.py')
| -rwxr-xr-x | format.py | 90 |
1 files changed, 46 insertions, 44 deletions
@@ -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] |
