diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-07-05 10:35:01 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-07-05 10:35:01 +0000 |
| commit | 218a4f2f7286042d7462ed9329f1b5b623662308 (patch) | |
| tree | 6434b21ebd554e05a069b0e99f833b9a1289e77b | |
| parent | add validate layer (diff) | |
| download | subv-218a4f2f7286042d7462ed9329f1b5b623662308.tar.gz subv-218a4f2f7286042d7462ed9329f1b5b623662308.zip | |
update survey for new stage order
| -rw-r--r-- | subv.py | 50 | ||||
| -rwxr-xr-x | survey.py | 209 |
2 files changed, 142 insertions, 117 deletions
@@ -4,8 +4,8 @@ import bits 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+))?(?:\[(\d+):(\d+)\])?$") -field_re = re.compile(r"^(imm|off)(\d+)$") +ref_re = re.compile(r"^([^\[+-]+)(?:([+-]\d+))?$") +field_re = re.compile(r"^(imm|off)(\d+)(hi|lo)?$") # parsing def parse_part(part): @@ -95,39 +95,31 @@ def parse_reference(part): """parse a sliced-label part. >>> parse_reference(('lbl', 'imm32')) - {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': ()} - - >>> parse_reference(('lbl+0', 'imm32')) - {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 0} - + {'label': 'lbl', 'mode': 'imm', 'size': 32, offset: 0} + >>> parse_reference(('lbl+0', 'off32')) + {'label': 'lbl', 'mode': 'off', 'size': 32, 'offset': 0} >>> parse_reference(('lbl+2', 'imm32')) - {'label': 'lbl', 'mode': 'imm', 'size': 32, 'meta': (), 'offset': 2} - - >>> parse_reference(('x[11:0]', 'off12')) - {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'hi': 11, 'lo': 0} - - >>> parse_reference(('x-16[11:0]', 'off12')) - {'label': 'x', 'mode': 'off', 'size': 12, 'meta': (), 'offset': -16, 'hi': 11, 'lo': 0} + {'label': 'lbl', 'mode': 'imm', 'size': 32, 'offset': 2} + >>> parse_reference(('lbl+2', 'off20hi')) + {'label': 'lbl', 'mode': 'off', 'size': 20, 'offset': 2, 'split': 'hi'} + >>> parse_reference(('lbl+2', 'off12lo')) + {'label': 'lbl', 'mode': 'off', 'size': 12, 'offset': 2, 'split': 'lo'} """ ref = part[0] field = part[1] - label, off, hi, lo = ref_re.match(ref).groups() - mode, size = field_re.match(field).groups() + label, off = ref_re.match(ref).groups() + mode, size, split = field_re.match(field).groups() ref = { "label": label, "mode": mode, "size": int(size), - "meta": part[2:], + "offset": int(off or 0), } - if off is not None: - ref["offset"] = int(off) - - if hi is not None: - ref["hi"] = int(hi) - ref["lo"] = int(lo) + if split is not None: + ref["split"] = split return ref @@ -292,9 +284,9 @@ def format_part(part): """opposite of parse_part. >>> format_part((0,)) - '00' + '0' >>> format_part((0x00,)) - '00' + '0' >>> format_part((16,)) '10' >>> format_part((0x10,)) @@ -322,10 +314,10 @@ def format(line): >>> format({ ... 'type': 'instr', - ... 'instr': [(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label[11:0]', 'imm12')], + ... 'instr': [(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label', 'imm12')], ... 'comment': "this does things." ... }) - 'ff/op 00/subop/add 01/rd/x1 label[11:0]/imm12 # this does things.' + 'ff/op 0/subop/add 1/rd/x1 label/imm12 # this does things.' """ type = line["type"] if type == "instr" or type == "data": @@ -342,10 +334,10 @@ def dump(line): >>> dump({ ... 'type': 'instr', - ... 'instr': [(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label[11:0]', 'imm12')], + ... 'instr': [(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label', 'imm12')], ... 'comment': "this does things." ... }) - "instr[(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label[11:0]', 'imm12')]" + "instr[(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label', 'imm12')]" """ return "{}{}".format(line["type"], line[line["type"]]) @@ -8,52 +8,52 @@ Resolves label references and substitutes them with literal values. ... == code 0x80000000 ... main: ... # load 0x10010000 (UART0) into t0 -... 37/7 05/5 10010/20 +... 37/u 5/rd 10010/imm20 ... # store 0x48 (H) in UART0+0 -... 13/7 06/5 0/3 00/5 048/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs 48/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # store 0x65 (e) in UART0+0 -... 13/7 06/5 0/3 00/5 065/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs 65/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 -... 13/7 06/5 0/3 00/5 06c/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs 6c/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # store 0x6c (l) in UART0+0 -... 13/7 06/5 0/3 00/5 06c/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs 6c/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # store 0x6f (o) in UART0+0 -... 13/7 06/5 0/3 00/5 06f/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs 6f/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # store 0x0a (\\\\n) in UART0+0 -... 13/7 06/5 0/3 00/5 00a/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 6/rd 0/funct3 0/rs a/imm12 +... 23/s 5/rs1 0/off12 2/funct3 6/rs2 ... # 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/j 0/rd main/off21 ... '''[1:-1])))) == code 0x80000000 # main: # load 0x10010000 (UART0) into t0 -37/7 05/5 10010/20 +37/u 5/rd 10010/imm20 # 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/i 6/rd 0/funct3 0/rs 48/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # 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/i 6/rd 0/funct3 0/rs 65/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # 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/i 6/rd 0/funct3 0/rs 6c/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # 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/i 6/rd 0/funct3 0/rs 6c/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # 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/i 6/rd 0/funct3 0/rs 6f/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # 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/i 6/rd 0/funct3 0/rs a/imm12 +23/s 5/rs1 0/off12 2/funct3 6/rs2 # jump back up to the top -6f/7 00/5 ff/8 1/1 3e6/10 1/1 +6f/j 0/rd -34/off21 >>> # doctest: +REPORT_NDIFF ... print(subv.join_all(survey(StringIO(''' @@ -61,37 +61,35 @@ Resolves label references and substitutes them with literal values. ... # repeatedly print "Hi\\\\n" ... main: ... # load 0x10010000 (UART0) into t0 -... 37/7 05/5 10010/20 +... 37/u 5/rd/t0 0x10010/imm20 ... # store 0x48 (H) in UART0+0 -... 13/7 06/5 0/3 00/5 048/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 0/subop/add 6/rd/t1 0/rs/x0 48/imm12 +... 23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 ... # store 0x69 (i) in UART0+0 -... 13/7 06/5 0/3 00/5 069/12 -... 23/7 00/5 2/3 05/5 06/5 00/7 +... 13/i 0/subop/add 6/rd/t1 0/rs/x0 69/imm12 +... 23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 ... # store 0x0a (\\\\n) in UART0+0 -... 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 -... 17/7 07/5 main/off32/[31:12] -... 67/7 00/5 0/3 07/5 main+4/off32/[11:0] +... 13/i 0/subop/add 6/rd/t1 0/rs/x0 0a/imm12 +... 23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 +... 17/u 7/rd/t2 main/off20hi +... 67/i 0/subop 0/rd/x0 7/rs/t2 main+4/off12lo ... '''[1:-1])))) == code 0x80000000 # repeatedly print "Hi\\n" # main: # load 0x10010000 (UART0) into t0 -37/7 05/5 10010/20 +37/u 5/rd/t0 10010/imm20 # 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/i 0/subop/add 6/rd/t1 0/rs/x0 48/imm12 +23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 # store 0x69 (i) in UART0+0 -13/7 06/5 00/3 00/5 69/12 -23/7 00/5 02/3 05/5 06/5 00/7 +13/i 0/subop/add 6/rd/t1 0/rs/x0 69/imm12 +23/s 2/subop/word 5/rs/t0 6/rs/t1 0/off12 # 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 -# jump back up to the top -17/7 07/5 00000/20 -67/7 00/5 00/3 07/5 fe4/12 +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 """ import subv import bits @@ -102,33 +100,78 @@ def observe(word, pc, map): >>> observe((3, '3'), 0, {}) (3, '3') - >>> observe(('label', 'imm32', '[31:0]'), 0, {'label': 0x1234}) - Bitfield(0x1234, 32) - >>> observe(('label-2', 'imm32', '[31:0]'), 0, {'label': 0x1234}) - Bitfield(0x1232, 32) - >>> observe(('label', 'imm32', '[1:0]'), 0, {'label': 0x1236}) - Bitfield(0x2, 2) - >>> observe(('label', 'off32', '[31:0]'), 0x1000, {'label': 0x1234}) - Bitfield(0x234, 32) - >>> observe(('label', 'off32', '[31:12]'), 0x1000, {'label': 0x10fff}) - Bitfield(0xf, 20) - >>> observe(('label', 'off32', '[31:0]'), 0x2000, {'label': 0x1000}) - Bitfield(0xfffff000, 32) - >>> observe(('label+4', 'off32', '[7:0]'), 0x1000, {'label': 0x1234}) - Bitfield(0x38, 8) - >>> observe(('label+4', 'off32', '[15:8]'), 0x1000, {'label': 0x1234}) - Bitfield(0x2, 8) - - >>> observe(('label', 'imm32', '[32:0]'), 0, {}) + >>> subv.format_part(observe(('label', 'imm32'), 0, {'label': 0x1234})) + '1234/imm32' + >>> subv.format_part(observe(('label-2', 'imm20',), 0, {'label': 0x1234})) + '1232/imm20' + >>> subv.format_part(observe(('label', 'off32'), 0x1000, {'label': 0x1234})) + '234/off32' + >>> subv.format_part(observe(('label+4', 'off32'), 0x1000, {'label': 0x1234})) + '238/off32' + >>> subv.format_part(observe(('label', 'off32'), 0x1234, {'label': 0x1000})) + '-234/off32' + >>> subv.format_part(observe(('label', 'off20hi'), 0x1000, {'label': 0x3234})) + '2/off20' + >>> subv.format_part(observe(('label', 'off12lo'), 0x1000, {'label': 0x3234})) + '234/off12' + >>> subv.format_part(observe(('label', 'off20hi'), 0x3234, {'label': 0x1000})) + '-2/off20' + >>> subv.format_part(observe(('label', 'off12lo'), 0x3234, {'label': 0x1000})) + '-234/off12' + + >>> observe(('label', 'imm32'), 0, {}) Traceback (most recent call last): ... ValueError: undefined label 'label' + >>> observe(('label', 'imm8'), 0, {'label': 0x1234}) + Traceback (most recent call last): + ... + ValueError: label reference out of range (8 bit): 'label' (0x1234) """ if not subv.is_reference(word): return word - word = bits.ref(word) - return word.as_value(pc=pc, labels=map) + ref = subv.parse_reference(word) + + if ref["label"] not in map: + raise ValueError("undefined label '{}'".format(ref["label"])) + + value = map[ref["label"]] + ref["offset"] + + if ref["mode"] == "off": + value -= pc + + if "split" in ref: + sgn = -1 if value < 0 else 1 + value *= sgn + + if ref["split"] == "hi" and ref["size"] == 20: + value = value >> 12 + elif ref["split"] == "lo" and ref["size"] == 12: + value = value & 0xFFF + else: + raise ValueError( + "unknown label split mode {mode}{size}{split}".format(**ref) + ) + + value *= sgn + + if value > 0: + if value >= (1 << ref["size"]): + raise ValueError( + "label reference out of range ({size} bit): '{label}' (0x{:x})".format( + value, **ref + ) + ) + else: + if value < -(1 << (ref["size"] - 1)): + raise ValueError( + "label reference out of range ({size} bit): '{label}' (-0x{:x})".format( + abs(value), **ref + ) + ) + + return (value, "{mode}{size}".format(**ref)) @subv.with_parsed_lines @@ -148,6 +191,9 @@ def survey(iter): assert bitcount == 0, "label isn't byte aligned" map[line["label"]] = addr elif type == "instr": + if len(line["instr"]) == 0: + continue + if segment == "data": for part in line["instr"]: bitcount += int(part[1]) @@ -163,19 +209,12 @@ def survey(iter): ) assert addr % 2 == 0, "instruction isn't 2-byte aligned" - bitcount = 0 - for part in line["instr"]: - if subv.is_reference(part): - ref = bits.ref(part) - bitcount += ref.size - else: - bitcount += int(part[1]) - - assert ( - bitcount % 8 == 0 - ), "instruction size not multiple of 8 bitcount: {}".format(bitcount) - addr += bitcount // 8 - bitcount = 0 + op = line["instr"][0] + instr_size = 0 + if op[1] in "usirjb": + addr += 4 + else: + raise ValueError("Unknown instruction format '{}'".format(op[1])) else: raise ValueError("unknown segment '{}'".format(segment)) @@ -184,14 +223,8 @@ def survey(iter): type = line["type"] if type == "instr": 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) + instr.append(observe(part, line["addr"], map)) line[type] = instr yield subv.format(line) elif type == "label": |
