diff options
Diffstat (limited to 'verify.py')
| -rw-r--r-- | verify.py | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/verify.py b/verify.py new file mode 100644 index 0000000..8499da5 --- /dev/null +++ b/verify.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +from subx import clean, classify, parse_segment, parse_instr, is_lref, unlabel, format_instr +from riscv import u, i, bit_concat + +""" +""" + +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 pack_u(instr): + (op, rd, imm) = instr + op = u(unlabel(op), 7) + rd = u(unlabel(rd, 'rd'), 5) + if not is_lref(imm): + imm = i(unlabel(imm, 'imm20'), 20) + + return [op, rd, imm] + +def pack_i(instr): + (op, sub, rd, rs, imm) = instr + op = u(unlabel(op), 7) + sub = u(unlabel(sub, 'subop'), 3) + rd = u(unlabel(rd, 'rd'), 5) + rs = u(unlabel(rs, 'rs'), 5) + if not is_lref(imm): + imm = i(unlabel(imm, 'imm12'), 12) + + return [op, sub, rd, rs, imm] + +def pack_s(instr): + (op, sub, rs1, rs2, imm) = instr + op = u(unlabel(op), 7) + sub = u(unlabel(sub, 'subop'), 3) + rs1 = u(unlabel(rs1, 'rs'), 5) + rs2 = u(unlabel(rs2, 'rs'), 5) + if not is_lref(imm): + imm = i(unlabel(imm, 'disp12'), 12) + + return [op, sub, rs1, rs2, imm] + +def pack_j(instr): + (op, rd, imm) = instr + op = u(unlabel(op), 7) + rd = u(unlabel(rd, 'rd'), 5) + if not is_lref(imm): + imm = i(unlabel(imm, 'disp20u'), 20) + + return [op, rd, imm] + +def pack(iter): + for line in iter: + line = clean(line) + if line == '': + continue + + type = classify(line) + + if type == 'segment' or type == 'label': + yield line + else: + instr = parse_instr(line) + op = instr[0] + if len(op) != 2: + raise ValueError("instruction without op label") + + (op, label) = op + if label not in instr_map: + raise ValueError("unknown instruction label: {}".format(label)) + (format, expected) = instr_map[label] + if op != expected: + raise ValueError("opcode {} doesn't match label {} (expected {})" + .format(op, label, expected)) + + out = None + 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) + else: + raise NotImplementedError() + + yield format_instr(out) + +if __name__ == '__main__': + import sys + pack(sys.stdin) + +import unittest +class TestPackers(unittest.TestCase): + def test_pack_u(self): + final = pack_u([(0x37, 'lui'), (5, 'rd', 't0'), (0x10010, 'imm20')]) + self.assertEqual( + final, + [(0x37, 7), (0x5, 5), (0x10010, 20)] + ) + self.assertEqual(bit_concat(*final)[1], 32) + + label = pack_u([(0x37, 'lui'), (5, 'rd', 't0'), ('pos', 'imm20')]) + self.assertEqual( + label, + [(0x37, 7), (0x5, 5), ('pos', 'imm20')] + ) + + def test_pack_i(self): + final = pack_i([ + (0x13, 'opi'), + (0, 'subop', 'add'), + (6, 'rd', 't1'), + (0, 'rs', 'x0'), + (0x65, 'imm12'), + ]) + self.assertEqual( + final, + [(0x13, 7), (0, 3), (6, 5), (0, 5), (0x65, 12)] + ) + self.assertEqual(bit_concat(*final)[1], 32) + +from io import StringIO +from textwrap import dedent +class TestE2E(unittest.TestCase): + def test_e2e(self): + inv = dedent('''\ + == code 0x80000000 + main: + # load 0x10010000 (UART0) into t0 + 37/lui 5/rd/t0 0x10010/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/disp12 + # 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/disp12 + # 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/disp12 + # 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/disp12 + # 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/disp12 + # 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/disp12 + # jump back up to the top + 6f/jal 0/rd/x0 main/disp20u + ''') + + out = dedent('''\ + == code 0x80000000 + main: + 37/7 05/5 10010/20 + 13/7 00/3 06/5 00/5 48/12 + 23/7 02/3 05/5 06/5 00/12 + 13/7 00/3 06/5 00/5 65/12 + 23/7 02/3 05/5 06/5 00/12 + 13/7 00/3 06/5 00/5 6c/12 + 23/7 02/3 05/5 06/5 00/12 + 13/7 00/3 06/5 00/5 6c/12 + 23/7 02/3 05/5 06/5 00/12 + 13/7 00/3 06/5 00/5 6f/12 + 23/7 02/3 05/5 06/5 00/12 + 13/7 00/3 06/5 00/5 0a/12 + 23/7 02/3 05/5 06/5 00/12 + 6f/7 00/5 main/disp20u + ''') + + got = '' + for line in pack(StringIO(inv)): + got += line + '\n' + + self.assertEqual(got, out) |
