diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-05-25 13:13:58 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-05-25 13:13:58 +0000 |
| commit | 9de28da73ba6a50f773804fd3a4c0beb342ffc3d (patch) | |
| tree | 5c91df552aa5f5ae4f79d7d166a98043652409d3 | |
| parent | implement LabelRef (diff) | |
| download | subv-9de28da73ba6a50f773804fd3a4c0beb342ffc3d.tar.gz subv-9de28da73ba6a50f773804fd3a4c0beb342ffc3d.zip | |
use new bits in format.py
| -rwxr-xr-x | format.py | 209 | ||||
| -rw-r--r-- | subv.py | 4 |
2 files changed, 107 insertions, 106 deletions
@@ -35,39 +35,40 @@ instruction. ... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12 ... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 ... # jump back up to the top -... 6f/jal 0/rd/x0 main/off20 +... 6f/jal 0/rd/x0 main/off21 ... '''[1:-1])))) == code 0x80000000 main: # 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] """ -from operator import __and__ -from functools import reduce import subv import bits +def _test_format(words): + return ' '.join(map(str, words)) + def ref_slice(ref, hi, lo): if hi < lo: raise ValueError("cant slice reverse range") @@ -81,87 +82,86 @@ def ref_slice(ref, hi, lo): 'size': hi - lo + 1, } +def sign_trunc(val, size): + """ truncate and sign-shrink a number literal. + + >>> sign_trunc(bits.i(4, 32), 8) + Bitfield(0x4, 8) + >>> sign_trunc(bits.i(-4, 32), 8) + Bitfield(0xfc, 8) + >>> sign_trunc(bits.i(0x11ff, 32), 8) + Bitfield(0x7f, 8) + >>> sign_trunc(bits.i(-0x11ff, 32), 8) + Bitfield(0x81, 8) + """ + sign = val[val.size-1] + 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) - ('label[12:1]', 'imm12') + LabelRef('label', 0, ('imm', 12), 12:1) >>> 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) + 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[31:0] (32 bit) + AssertionError: expected 12 bit slice, got label/imm12/[31:0] """ - parsed = subv.parse_reference(val) - if 'hi' not in parsed: - parsed['hi'] = hi - parsed['lo'] = lo - ref = subv.format_reference(parsed) + 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") - p_size = parsed['hi'] - parsed['lo'] + 1 - assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref[0], p_size) + import re - return ref + ref_re = re.compile(r'^([^\[+-]+)(?:([+-]\d+))?$') + slice_re = re.compile(r'^\[(\d+):(\d+)]$') -def slice_bit_or_ref(val, hi, lo): - """ bit.slice but for bitfields and label references. + match = ref_re.match(label_offset) + assert match, ValueError("invalid label reference") + label, offset = match.group(1), int(match.group(2) or 0) - >>> slice_bit_or_ref(('label[31:0]', 'imm32'), 12, 1) - ('label[12:1]', 'imm12') - >>> slice_bit_or_ref(('label[31:0]', 'off32'), 11, 0) - ('label[11:0]', 'off12') - >>> slice_bit_or_ref(('label[31:0]', 'off32'), 31, 12) - ('label[31:12]', 'off20') - >>> slice_bit_or_ref(('label[11:0]', 'imm12', 'extra'), 15, 4) - Traceback (most recent call last): - ... - AssertionError: cant slice outside of bounds - >>> slice_bit_or_ref(('label', 'imm12'), 12, 1) - Traceback (most recent call last): - ... - AssertionError: cant slice label w/o bounds - """ - if isinstance(val, bits.Bitfield): - return val[hi:lo] + 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 = subv.parse_reference(val) - assert 'hi' in ref, "cant slice label w/o bounds" + ref = bits.LabelRef(label, offset, mode, slice) - sz = hi - lo - lo = ref['lo'] + lo - hi = lo + sz - assert hi <= ref['hi'], "cant slice outside of bounds" - - ref['hi'] = hi - ref['lo'] = lo - ref['size'] = sz + 1 - main = '{label}[{hi}:{lo}]'.format(**ref) - field = '{mode}{size}'.format(**ref) - return (main, field, *val[2:]) + 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. - >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')]) - [Bitfield(0x37, 7), Bitfield(0x5, 5), Bitfield(0x10010, 20)] + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])) + '37/7 05/5 10010/20' - >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')]) - [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[31:12]', 'imm20')] + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])) + '37/7 05/5 pos/imm20/[31:12]' - >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[19:0]', 'imm20')]) - [Bitfield(0x37, 7), Bitfield(0x5, 5), ('pos[19:0]', 'imm20')] + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20', '[19:0]')])) + '37/7 05/5 pos/imm20/[19:0]' - >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')]) + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20', '[31:0]')])) Traceback (most recent call last): ... - AssertionError: expected 20 bit slice, got pos[31:0] (32 bit) + AssertionError: expected 20 bit slice, got pos/imm20/[31:0] """ (op, rd, imm) = instr op = bits.u(subv.untag(op), 7) @@ -176,11 +176,11 @@ def pack_u(instr): def pack_i(instr): """ verify & pack I-type instructions. - >>> reduce(__and__, pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (101, 'imm12')])) - Bitfield(0x26600065, 32) + >>> _test_format(pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), (0x65, 'imm12')])) + '13/7 06/5 0/3 00/5 065/12' - >>> pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')]) - [Bitfield(0x13, 7), Bitfield(0x6, 5), Bitfield(0x0, 3), Bitfield(0x0, 5), ('label[11:0]', 'imm12')] + >>> _test_format(pack_i([(0x13, 'opi'), (0, 'subop', 'add'), (6, 'rd', 't1'), (0, 'rs', 'x0'), ('label', 'imm12')])) + '13/7 06/5 0/3 00/5 label/imm12/[11:0]' """ (op, sub, rd, rs, imm) = instr op = bits.u(subv.untag(op), 7) @@ -197,11 +197,11 @@ def pack_i(instr): def pack_s(instr): """ verify & pack S-type instructions. - >>> reduce(__and__, pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')])) - Bitfield(0x46045300, 32) + >>> _test_format(pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), (0, 'off12')])) + '23/7 00/5 2/3 05/5 06/5 00/7' - >>> pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')]) - [Bitfield(0x23, 7), ('home[4:0]', 'off5'), Bitfield(0x2, 3), Bitfield(0x5, 5), Bitfield(0x6, 5), ('home[11:5]', 'off7')] + >>> _test_format(pack_s([(0x23, 'store'), (2, 'subop', 'word'), (5, 'rs', 't0'), (6, 'rs', 't1'), ('home', 'off12')])) + '23/7 home/off12/[4:0] 2/3 05/5 06/5 home/off12/[11:5]' """ (op, sub, rs1, rs2, imm) = instr op = bits.u(subv.untag(op), 7) @@ -214,21 +214,21 @@ def pack_s(instr): else: imm = bits.i(subv.untag(imm, 'off12'), 12) - imm_lo = slice_bit_or_ref(imm, 4, 0) # + ('off[4:0]',) - imm_hi = slice_bit_or_ref(imm, 11, 5) # + ('off[11:5]',) + imm_lo = imm[4:0] + imm_hi = imm[11:5] return [op, imm_lo, sub, rs1, rs2, imm_hi] def pack_j(instr): """ verify & pack J-type instructions. - >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])) - Bitfield(0xde000000, 32) + >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])) + '6f/7 00/5 00/8 0/1 000/10 0/1' - >>> reduce(__and__, pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')])) - Bitfield(0xde0ffffd, 32) + >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')])) + '6f/7 00/5 ff/8 1/1 3fe/10 1/1' - >>> pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')]) - [Bitfield(0x6f, 7), Bitfield(0x2, 5), ('home[19:12]', 'off8'), ('home[11:11]', 'off1'), ('home[10:1]', 'off10'), ('home[20:20]', 'off1')] + >>> _test_format(pack_j([(0x6f, 'jal'), (2, 'rd', 'x2'), ('home', 'off20')])) + '6f/7 02/5 home/off20/[19:12] home/off20/[11:11] home/off20/[10:1] home/off20/[20:20]' """ (op, rd, imm) = instr op = bits.u(subv.untag(op), 7) @@ -239,24 +239,24 @@ def pack_j(instr): else: imm = bits.i(subv.untag(imm, 'off20'), 20) - imm_lo = slice_bit_or_ref(imm, 9, 0) # + ('off[10:1]',) - imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',) - imm_hi = slice_bit_or_ref(imm, 18, 11) # + ('off[19:12]',) - imm_20 = slice_bit_or_ref(imm, 19, 19) # + ('off[20]',) + imm_lo = imm[9:0] + imm_11 = imm[10] + imm_hi = imm[18:11] + imm_20 = imm[19] return [op, rd, imm_hi, imm_11, imm_lo, imm_20] def pack_b(instr): """ verify & pack B-type instructions. - >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')])) - Bitfield(0xc6006000, 32) + >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (0, 'off12')])) + '63/7 0/1 0/4 0/3 06/5 00/5 00/6 0/1' - >>> reduce(__and__, pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')])) - Bitfield(0xc7e0607f, 32) + >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), (-2, 'off12')])) + '63/7 1/1 e/4 0/3 06/5 00/5 3f/6 1/1' - >>> pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')]) - [Bitfield(0x63, 7), ('home[11:11]', 'off1'), ('home[4:1]', 'off4'), Bitfield(0x0, 3), Bitfield(0x6, 5), Bitfield(0x0, 5), ('home[10:5]', 'off6'), ('home[12:12]', 'off1')] + >>> _test_format(pack_b([(0x63, 'branch'), (0, 'subop', '=='), (6, 'rs'), (0, 'rs'), ('home', 'off12')])) + '63/7 home/off12/[11:11] home/off12/[4:1] 0/3 06/5 00/5 home/off12/[10:5] home/off12/[12:12]' """ (op, sub, rs1, rs2, imm) = instr op = bits.u(subv.untag(op), 7) @@ -269,10 +269,11 @@ def pack_b(instr): else: imm = bits.i(subv.untag(imm, 'off12'), 12) - imm_lo = slice_bit_or_ref(imm, 3, 0) # + ('off[4:1]',) - imm_md = slice_bit_or_ref(imm, 9, 4) # + ('off[10:5]',) - imm_11 = slice_bit_or_ref(imm, 10, 10) # + ('off[11]',) - imm_12 = slice_bit_or_ref(imm, 11, 11) # + ('off[12]',) + imm_lo = imm[3:0] + imm_md = imm[9:4] + imm_11 = imm[10] + imm_12 = imm[11] + return [op, imm_11, imm_lo, sub, rs1, rs2, imm_md, imm_12] instr_map = { @@ -299,8 +299,8 @@ def format_part(part): >>> format_part(('$label:suff', 'tag')) '$label:suff/tag' """ - if isinstance(part, bits.Bitfield): - part = ('{:02x}'.format(part.val), part.size) + if isinstance(part, bits.WordBase): + return str(part) elif not is_reference(part): first = '{:02x}'.format(part[0]) part = (first, *part[1:]) |
