diff options
| -rwxr-xr-x | format.py | 67 | ||||
| -rw-r--r-- | subv.py | 21 |
2 files changed, 61 insertions, 27 deletions
@@ -91,17 +91,18 @@ def default_slice(val, hi, lo): >>> default_slice(('label[31:0]', 'imm12'), 11, 0) Traceback (most recent call last): ... - AssertionError: expected 12 bit slice + AssertionError: expected 12 bit slice, got label[31:0] (32 bit) """ parsed = subv.parse_reference(val) if 'hi' not in parsed: parsed['hi'] = hi parsed['lo'] = lo + ref = '{label}[{hi}:{lo}]'.format(**parsed) + p_size = parsed['hi'] - parsed['lo'] + 1 - assert parsed['size'] == p_size, "expected {} bit slice".format(parsed['size']) + assert parsed['size'] == p_size, "expected {} bit slice, got {} ({} bit)".format(parsed['size'], ref, p_size) - ref = '{label}[{hi}:{lo}]'.format(**parsed) return (ref, *val[1:]) def slice_bit_or_ref(val, hi, lo): @@ -155,7 +156,7 @@ def pack_u(instr): >>> pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos[31:0]', 'imm20')]) Traceback (most recent call last): ... - AssertionError: expected 20 bit slice + AssertionError: expected 20 bit slice, got pos[31:0] (32 bit) """ (op, rd, imm) = instr op = bits.u(subv.untag(op), 7) @@ -283,27 +284,43 @@ instr_map = { def format(iter): segment = None - for line in iter: - line = subv.parse(line) - - if segment == 'code' and line['type'] == '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)) - (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']) - yield subv.format(line) - else: - if line['type'] == 'segment': - segment = line['segment'][0] - yield line['raw'] + for line_no, raw_line in enumerate(iter, start=1): + try: + line = subv.parse(raw_line) + except AssertionError as e: + message = ''' +failed to format line: +<input>:{} {} +parsed as {} + '''.strip().format(line_no, raw_line.strip()) + raise Exception(message) from e + + try: + if segment == 'code' and line['type'] == '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)) + (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']) + yield subv.format(line) + else: + if line['type'] == 'segment': + segment = line['segment'][0] + yield line['raw'] + except AssertionError as e: + message = ''' +failed to format line: +<input>:{} {} +parsed as {} + '''.strip().format(line_no, raw_line.strip(), subv.dump(line)) + raise Exception(message) from e if __name__ == '__main__': import sys @@ -223,12 +223,16 @@ def untag(part, expect=None): return part[0] def format_part(part): - """ oppposite of parse_part. + """ opposite of parse_part. >>> format_part((0,)) '00' >>> format_part((0x00,)) '00' + >>> format_part((16,)) + '10' + >>> format_part((0x10,)) + '10' >>> format_part(('label', 'tag*')) 'label/tag*' @@ -245,7 +249,7 @@ def format_part(part): return '/'.join([str(p) for p in part]) def format(line): - """ oppposite of parse. + """ opposite of parse. >>> format({ ... 'type': 'instr', @@ -262,6 +266,19 @@ def format(line): else: raise NotImplementedError() +def dump(line): + """ debug-friendly string representation of parsed lines. + + >>> dump({ + ... 'type': 'instr', + ... 'instr': [(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label[11:0]', 'imm12')], + ... 'comment': "this does things." + ... }) + "instr[(255, 'op'), (0, 'subop', 'add'), (1, 'rd', 'x1'), ('label[11:0]', 'imm12')]" + """ + + return '{}{}'.format(line['type'], line[line['type']]) + def join_all(gen): res = '\n'.join(gen) return res |
