diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-07-05 12:01:38 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-07-05 12:02:19 +0000 |
| commit | ae0e0c052e7f1f613fb27d5aa21dfa83fbafcd61 (patch) | |
| tree | fcc6e9a67329620b6427756b51b598d659746b45 | |
| parent | update survey for new stage order (diff) | |
| download | subv-ae0e0c052e7f1f613fb27d5aa21dfa83fbafcd61.tar.gz subv-ae0e0c052e7f1f613fb27d5aa21dfa83fbafcd61.zip | |
update format for new pipeline
| -rwxr-xr-x | format.py | 268 | ||||
| -rw-r--r-- | subv.py | 30 | ||||
| -rwxr-xr-x | survey.py | 46 | ||||
| -rwxr-xr-x | validate.py | 175 |
4 files changed, 226 insertions, 293 deletions
@@ -1,44 +1,44 @@ #!/usr/bin/env python3 """ format.py -Verifies instruction formats, orders and pre-bit-packs arguments. +Bit-packs instructions and verifies value ranges according to instruction formats. 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. +which has to be tagged with the instruction-format name. Arguments have to be provided +in the correct order, 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. +Some immediates can be given in different sizes and will be sliced to size automatically. +For example the "j" instruction-format can take an "imm20" pre-sliced immediate, or an +"imm21" immediate, truncating the lowest bit (and asserting that it is zero). >>> from io import StringIO >>> # doctest: +REPORT_NDIFF ... print(subv.join_all(format(StringIO(''' ... == code 0x80000000 -... main: +... # main: ... # load 0x10010000 (UART0) into t0 -... 37/lui 5/rd/t0 0x10010/imm20 +... 37/u 5/rd 10010/imm20 ... # store 0x48 (H) in UART0+0 -... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 48/imm12 -... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 13/i 6/rd 0/funct3 0/rs 48/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x65 (e) in UART0+0 -... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 65/imm12 -... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 13/i 6/rd 0/funct3 0/rs 65/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 -... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12 -... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 13/i 6/rd 0/funct3 0/rs 6c/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 -... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6c/imm12 -... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 13/i 6/rd 0/funct3 0/rs 6c/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6f (o) in UART0+0 -... 13/opi 0/subop/add 6/rd/t1 0/rs/x0 6f/imm12 -... 23/store 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 13/i 6/rd 0/funct3 0/rs 6f/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x0a (\\\\n) in UART0+0 -... 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 +... 13/i 6/rd 0/funct3 0/rs a/imm12 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # jump back up to the top -... 6f/jal 0/rd/x0 main/off21 +... 6f/j 0/rd -34/imm21 ... '''[1:-1])))) == code 0x80000000 -main: +# main: # load 0x10010000 (UART0) into t0 37/7 05/5 10010/20 # store 0x48 (H) in UART0+0 @@ -60,7 +60,7 @@ main: 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/off21/[19:12] main/off21/[11:11] main/off21/[10:1] main/off21/[20:20] +6f/7 00/5 ff/8 1/1 3e6/10 1/1 """ import subv @@ -71,135 +71,105 @@ def _test_format(words): return " ".join(map(str, words)) -def ref_slice(ref, hi, lo): - if hi < lo: - raise ValueError("cant slice reverse range") - elif hi >= ref["size"]: - raise ValueError( - "cant slice [{}:{}] from {} bit value".format(hi, lo, ref["size"]) - ) - - return { - **ref, - "hi": hi, - "lo": 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 - +def pack_i(instr): + """verify & pack I-type instructions. -def pack_u(instr): - """verify & pack U-type instructions. + >>> _test_format(pack_i([(0x13, 'i'), (6, 'rd'), (0, 'funct3'), (0, 'rs'), (0x65, 'imm12')])) + '13/7 06/5 0/3 00/5 065/12' + """ + (op, rd, funct, rs, imm) = instr + op_tag = op[1] + op = bits.u(subv.untag(op), 7) + rd = bits.u(subv.untag(rd, "rd"), 5) + funct = bits.u(subv.untag(funct, "funct3"), 3) + rs = bits.u(subv.untag(rs, "rs"), 5) + imm = bits.i(subv.untag(imm, "imm12"), 12) - >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])) - '37/7 05/5 10010/20' + return [op, rd, funct, rs, imm] - >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')])) - '37/7 05/5 pos/imm20/[31:12]' - >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20', '[19:0]')])) - '37/7 05/5 pos/imm20/[19:0]' +def pack_s(instr): + """verify & pack S-type instructions. - >>> _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/imm20/[31:0] + >>> _test_format(pack_s([(0x23, 's'), (5, 'rs1'), (0, 'imm12'), (2, 'funct3'), (6, 'rs2')])) + '23/7 00/5 2/3 05/5 06/5 00/7' """ - (op, rd, imm) = instr + (op, rs1, imm, funct, rs2) = instr op = bits.u(subv.untag(op), 7) - rd = bits.u(subv.untag(rd, "rd"), 5) - if subv.is_reference(imm): - imm = bits.ref(imm, slice(31, 12)) - else: - imm = bits.i(subv.untag(imm, "imm20"), 20) + rs1 = bits.u(subv.untag(rs1, "rs1"), 5) + imm = bits.i(subv.untag(imm, "imm12"), 12) + funct = bits.u(subv.untag(funct, "funct3"), 3) + rs2 = bits.u(subv.untag(rs2, "rs2"), 5) - return [op, rd, imm] + imm_lo = imm[4:0] + imm_hi = imm[11:5] + return [op, imm_lo, funct, rs1, rs2, imm_hi] -def pack_i(instr): - """verify & pack I-type instructions. +def pack_b(instr): + """verify & pack B-type instructions. - >>> _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' + >>> _test_format(pack_b([(0x63, 'branch'), (0, 'funct3'), (6, 'rs1'), (0, 'rs2'), (0, 'imm12')])) + '63/7 0/1 0/4 0/3 06/5 00/5 00/6 0/1' - >>> _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]' + >>> _test_format(pack_b([(0x63, 'branch'), (0, 'funct3'), (6, 'rs1'), (0, 'rs2'), (-2, 'imm12')])) + '63/7 1/1 e/4 0/3 06/5 00/5 3f/6 1/1' """ - (op, sub, rd, rs, imm) = instr - op_tag = op[1] + (op, funct, rs1, rs2, imm) = instr op = bits.u(subv.untag(op), 7) - 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_reference(imm): - imm = bits.ref(imm, slice(11, 0)) + funct = bits.u(subv.untag(funct, "funct3"), 3) + rs1 = bits.u(subv.untag(rs1, "rs1"), 5) + rs2 = bits.u(subv.untag(rs2, "rs2"), 5) + + if imm[1] == "imm13": + imm = bits.i(subv.untag(imm, "imm13"), 13) + imm = imm[12:1] else: imm = bits.i(subv.untag(imm, "imm12"), 12) - return [op, rd, sub, rs, imm] + imm_lo = imm[3:0] + imm_md = imm[9:4] + imm_11 = imm[10] + imm_12 = imm[11] + return [op, imm_11, imm_lo, funct, rs1, rs2, imm_md, imm_12] -def pack_s(instr): - """verify & pack S-type instructions. - >>> _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' +def pack_u(instr): + """verify & pack U-type instructions. - >>> _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]' + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')])) + '37/7 05/5 10010/20' + + >>> _test_format(pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (-0x1234, 'imm20')])) + '37/7 05/5 fedcc/20' """ - (op, sub, rs1, rs2, imm) = instr + (op, rd, imm) = instr op = bits.u(subv.untag(op), 7) - sub = bits.u(subv.untag(sub, "subop"), 3) - rs1 = bits.u(subv.untag(rs1, "rs"), 5) - rs2 = bits.u(subv.untag(rs2, "rs"), 5) - - if subv.is_reference(imm): - imm = bits.ref(imm, slice(11, 0)) - else: - imm = bits.i(subv.untag(imm, "off12"), 12) + rd = bits.u(subv.untag(rd, "rd"), 5) + imm = bits.i(subv.untag(imm, "imm20"), 20) - imm_lo = imm[4:0] - imm_hi = imm[11:5] - return [op, imm_lo, sub, rs1, rs2, imm_hi] + return [op, rd, imm] def pack_j(instr): """verify & pack J-type instructions. - >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'off20')])) + >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (0, 'imm20')])) '6f/7 00/5 00/8 0/1 000/10 0/1' - >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'off20')])) + >>> _test_format(pack_j([(0x6f, 'jal'), (0, 'rd', 'x0'), (-2, 'imm20')])) '6f/7 00/5 ff/8 1/1 3fe/10 1/1' - - >>> _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) rd = bits.u(subv.untag(rd, "rd"), 5) - if subv.is_reference(imm): - imm = bits.ref(imm, slice(20, 1)) + if imm[1] == "imm21": + imm = bits.i(subv.untag(imm, "imm21"), 21) + imm = imm[20:1] else: - imm = bits.i(subv.untag(imm, "off20"), 20) + imm = bits.i(subv.untag(imm, "imm20"), 20) imm_lo = imm[9:0] imm_11 = imm[10] @@ -209,47 +179,13 @@ def pack_j(instr): return [op, rd, imm_hi, imm_11, imm_lo, imm_20] -def pack_b(instr): - """verify & pack B-type instructions. - - >>> _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' - - >>> _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' - - >>> _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) - sub = bits.u(subv.untag(sub, "subop"), 3) - rs1 = bits.u(subv.untag(rs1, "rs"), 5) - rs2 = bits.u(subv.untag(rs2, "rs"), 5) - - if subv.is_reference(imm): - imm = bits.ref(imm, slice(12, 1)) - else: - imm = bits.i(subv.untag(imm, "off12"), 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 = { - # '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), +format_map = { + # "r": pack_r, + "i": pack_i, + "s": pack_s, + "b": pack_b, + "u": pack_u, + "j": pack_j, } @@ -258,20 +194,14 @@ def format(iter): for segment, line in iter: if line["type"] == "instr" and segment == "code": 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)) - (formatter, expected) = instr_map[label] - if op != expected: - raise ValueError( - "opcode {} doesn't match label {} (expected {})".format( - op, label, expected - ) - ) - - line["instr"] = formatter(line["instr"]) + assert len(op) == 2, "instruction without format label: {}".format(op) + + (op, format) = op + if format not in format_map: + raise ValueError("unknown instruction format: {}".format(format)) + formatter = format_map[format] + + line["instr"] = formatter(line["instr"][:]) line = yield subv.format(line) else: line = yield line["raw"] @@ -5,7 +5,7 @@ white = re.compile(r"[ \t\.\n]+") hex = re.compile(r"^\-?(0x)?[0-9a-f]+$") num = re.compile(r"^\d+$") ref_re = re.compile(r"^([^\[+-]+)(?:([+-]\d+))?$") -field_re = re.compile(r"^(imm|off)(\d+)(hi|lo)?$") +immediate_re = re.compile(r"^(imm|off)(\d+)(hi|lo)?$") # parsing def parse_part(part): @@ -91,6 +91,24 @@ def parse_label(line): return line[:-1] +def parse_immediate(particle): + match = immediate_re.match(particle) + if not match: + return None + + mode, size, split = match.groups() + + imm = { + "mode": mode, + "size": int(size), + } + + if split is not None: + imm["split"] = split + + return imm + + def parse_reference(part): """parse a sliced-label part. @@ -109,7 +127,7 @@ def parse_reference(part): field = part[1] label, off = ref_re.match(ref).groups() - mode, size, split = field_re.match(field).groups() + mode, size, split = immediate_re.match(field).groups() ref = { "label": label, @@ -280,6 +298,14 @@ def format_reference(ref): return (label, "{mode}{size}".format(**ref), *ref["meta"]) +def format_immediate(imm): + tag = "{mode}{size}".format(**imm) + if "split" in imm: + tag += imm["split"] + + return tag + + def format_part(part): """opposite of parse_part. @@ -11,22 +11,22 @@ Resolves label references and substitutes them with literal values. ... 37/u 5/rd 10010/imm20 ... # store 0x48 (H) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs 48/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x65 (e) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs 65/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs 6c/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs 6c/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x6f (o) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs 6f/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # store 0x0a (\\\\n) in UART0+0 ... 13/i 6/rd 0/funct3 0/rs a/imm12 -... 23/s 5/rs1 0/off12 2/funct3 6/rs2 +... 23/s 5/rs1 0/imm12 2/funct3 6/rs2 ... # jump back up to the top ... 6f/j 0/rd main/off21 ... '''[1:-1])))) @@ -36,24 +36,24 @@ Resolves label references and substitutes them with literal values. 37/u 5/rd 10010/imm20 # store 0x48 (H) in UART0+0 13/i 6/rd 0/funct3 0/rs 48/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x65 (e) in UART0+0 13/i 6/rd 0/funct3 0/rs 65/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6c (l) in UART0+0 13/i 6/rd 0/funct3 0/rs 6c/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6c (l) in UART0+0 13/i 6/rd 0/funct3 0/rs 6c/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6f (o) in UART0+0 13/i 6/rd 0/funct3 0/rs 6f/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x0a (\\n) in UART0+0 13/i 6/rd 0/funct3 0/rs a/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # jump back up to the top -6f/j 0/rd -34/off21 +6f/j 0/rd -34/imm21 >>> # doctest: +REPORT_NDIFF ... print(subv.join_all(survey(StringIO(''' @@ -88,8 +88,8 @@ Resolves label references and substitutes them with literal values. # store 0x0a (\\n) in UART0+0 13/i 0/subop/add 6/rd/t1 0/rs/x0 a/imm12 23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 -17/u 7/rd/t2 0/off20 -67/i 0/subop 0/rd/x0 7/rs/t2 -1c/off12 +17/u 7/rd/t2 0/imm20 +67/i 0/subop 0/rd/x0 7/rs/t2 -1c/imm12 """ import subv import bits @@ -105,19 +105,19 @@ def observe(word, pc, map): >>> subv.format_part(observe(('label-2', 'imm20',), 0, {'label': 0x1234})) '1232/imm20' >>> subv.format_part(observe(('label', 'off32'), 0x1000, {'label': 0x1234})) - '234/off32' + '234/imm32' >>> subv.format_part(observe(('label+4', 'off32'), 0x1000, {'label': 0x1234})) - '238/off32' + '238/imm32' >>> subv.format_part(observe(('label', 'off32'), 0x1234, {'label': 0x1000})) - '-234/off32' + '-234/imm32' >>> subv.format_part(observe(('label', 'off20hi'), 0x1000, {'label': 0x3234})) - '2/off20' + '2/imm20' >>> subv.format_part(observe(('label', 'off12lo'), 0x1000, {'label': 0x3234})) - '234/off12' + '234/imm12' >>> subv.format_part(observe(('label', 'off20hi'), 0x3234, {'label': 0x1000})) - '-2/off20' + '-2/imm20' >>> subv.format_part(observe(('label', 'off12lo'), 0x3234, {'label': 0x1000})) - '-234/off12' + '-234/imm12' >>> observe(('label', 'imm32'), 0, {}) Traceback (most recent call last): @@ -171,7 +171,7 @@ def observe(word, pc, map): ) ) - return (value, "{mode}{size}".format(**ref)) + return (value, "imm{size}".format(**ref)) @subv.with_parsed_lines diff --git a/validate.py b/validate.py index 452b4fa..84bb036 100755 --- a/validate.py +++ b/validate.py @@ -38,28 +38,27 @@ main: 37/u 5/rd 10010/imm20 # store 0x48 (H) in UART0+0 13/i 6/rd 0/funct3 0/rs 48/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x65 (e) in UART0+0 13/i 6/rd 0/funct3 0/rs 65/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6c (l) in UART0+0 13/i 6/rd 0/funct3 0/rs 6c/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6c (l) in UART0+0 13/i 6/rd 0/funct3 0/rs 6c/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x6f (o) in UART0+0 13/i 6/rd 0/funct3 0/rs 6f/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # store 0x0a (\\n) in UART0+0 13/i 6/rd 0/funct3 0/rs a/imm12 -23/s 5/rs1 0/off12 2/funct3 6/rs2 +23/s 5/rs1 0/imm12 2/funct3 6/rs2 # jump back up to the top 6f/j 0/rd main/off21 """ import subv -import bits def pop_piece(line, labels): @@ -71,48 +70,26 @@ def pop_piece(line, labels): raise ValueError("Expected a part with labels {}".format(labels)) -REG_NAMES = {} -REG_NAMES.update( - { - name: i - for i, name in enumerate( - [ - "zero", - "ra", - "sp", - "gp", - "tp", - "t0", - "t1", - "t2", - "s0", - "s1", - "a0", - "a1", - "a2", - "a3", - "a4", - "a5", - "a6", - "a7", - "s2", - "s3", - "s4", - "s5", - "s6", - "s7", - "s8", - "s9", - "s10", - "s11", - "t3", - "t4", - "t5", - "t6", - ] - ) - } -) +def pop_immediate(line, sizes, allow_offset=False): + if isinstance(sizes, int): + sizes = [sizes] + + for part in line: + imm = subv.parse_immediate(part[1]) + if imm and imm["size"] in sizes: + line.remove(part) + if not isinstance(part[0], str): + imm["mode"] = "imm" + + return (part[0], subv.format_immediate(imm)) + + raise ValueError( + "Expected an immediate with size {}".format("/".join(str(s) for s in sizes)) + ) + + +REG_NAMES = "zero,ra,sp,gp,tp,t0,t1,t2,s0,s1,a0,a1,a2,a3,a4,a5,a6,a7,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,t3,t4,t5,t6" +REG_NAMES = {name: i for i, name in enumerate(REG_NAMES.split(","))} REG_NAMES.update({"x{}".format(i): i for i in range(32)}) @@ -143,35 +120,22 @@ def pop_register(line, labels): raise ValueError("Expected a register with labels {}".format(labels)) -def validate_u(inputs): +def validate_r(inputs): op = inputs.pop(0) - rd = pop_register(inputs, ["rd", "dest"]) - imm = inputs.pop() - assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) - - return [ - (op[0], "u"), - rd, - imm, - ] - - -def validate_s(inputs): - op = inputs.pop(0) - width = pop_piece(inputs, ["funct3", "funct", "width"]) - base = pop_register(inputs, ["rs1", "rs", "base"]) - src = pop_register(inputs, ["rs2", "rs", "src"]) - offset = inputs.pop() + dest = pop_register(inputs, ["rd", "dest"]) + funct = pop_piece(inputs, ["funct7", "funct", "subop"]) + rs1 = pop_register(inputs, ["rs1", "rs", "src1", "src"]) + rs2 = pop_register(inputs, ["rs2", "rs", "src2", "src"]) assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) return [ - (op[0], "s"), - base, - offset, - width, - src, + (op[0], "r"), + dest, + funct, + rs1, + rs2, ] @@ -185,7 +149,7 @@ def validate_i(inputs): dest = pop_register(inputs, ["rd", "dest"]) funct = pop_piece(inputs, ["funct3", "funct", "subop"]) rs = pop_register(inputs, ["rs", rs_name]) - imm = inputs.pop() + imm = pop_immediate(inputs, 12) assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) @@ -198,69 +162,82 @@ def validate_i(inputs): ] -def validate_r(inputs): +def validate_s(inputs): op = inputs.pop(0) + base = pop_register(inputs, ["rs1", "rs", "base"]) + offset = pop_immediate(inputs, 12, allow_offset=True) + width = pop_piece(inputs, ["funct3", "funct", "width"]) + src = pop_register(inputs, ["rs2", "rs", "src"]) - dest = pop_register(inputs, ["rd", "dest"]) - funct = pop_piece(inputs, ["funct7", "funct", "subop"]) + assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) + + return [ + (op[0], "s"), + base, + offset, + width, + src, + ] + + +def validate_b(inputs): + op = inputs.pop(0) + + funct = pop_piece(inputs, ["funct3", "funct", "subop"]) rs1 = pop_register(inputs, ["rs1", "rs", "src1", "src"]) rs2 = pop_register(inputs, ["rs2", "rs", "src2", "src"]) + offset = pop_immediate(inputs, [12, 13], allow_offset=True) assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) return [ - (op[0], "r"), - dest, + (op[0], "b"), funct, - rs1, - rs2, + src1, + src2, + offset, ] -def validate_j(inputs): +def validate_u(inputs): op = inputs.pop(0) - - dest = pop_register(inputs, ["rd", "dest"]) - offset = inputs.pop() + rd = pop_register(inputs, ["rd", "dest"]) + imm = pop_immediate(inputs, 20, allow_offset=True) assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) return [ - (op[0], "j"), - dest, - offset, + (op[0], "u"), + rd, + imm, ] -def validate_b(inputs): +def validate_j(inputs): op = inputs.pop(0) - funct = pop_piece(inputs, ["funct3", "funct", "subop"]) - rs1 = pop_register(inputs, ["rs1", "rs", "src1", "src"]) - rs2 = pop_register(inputs, ["rs2", "rs", "src2", "src"]) - offset = inputs.pop() + dest = pop_register(inputs, ["rd", "dest"]) + offset = pop_immediate(inputs, [21, 20], allow_offset=True) assert len(inputs) == 0, ValueError("Extra arguments: {}".format(inputs)) return [ - (op[0], "b"), - funct, - src1, - src2, + (op[0], "j"), + dest, offset, ] instr_map = { - "opi": (validate_i, 0x13), "opr": (validate_r, 0x33), + "opi": (validate_i, 0x13), "load": (validate_i, 0x03), - "store": (validate_s, 0x23), - "jal": (validate_j, 0x6F), "jalr": (validate_i, 0x67), + "store": (validate_s, 0x23), "branch": (validate_b, 0x63), "lui": (validate_u, 0x37), "auipc": (validate_u, 0x17), + "jal": (validate_j, 0x6F), } |
