aboutsummaryrefslogtreecommitdiffstats
path: root/pack.py
blob: c93a78f5220261e8684aa11e58d468a259a35a35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python3
""" pack.py
Packs bitfields tagged with their size into untagged bytes.

>>> from io import StringIO
>>> # doctest: +REPORT_NDIFF
... print(subv.join_all(pack(StringIO('''
... == code 0x80000000
... main:
... 37/7 05/5 10010/20
... 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 00/3 00/5 65/12
... 23/7 00/5 02/3 05/5 06/5 00/7
... 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 00/3 00/5 6c/12
... 23/7 00/5 02/3 05/5 06/5 00/7
... 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 00/3 00/5 0a/12
... 23/7 00/5 02/3 05/5 06/5 00/7
... 6f/7 00/5 ff/8 1/1 3e6/10 1/1
... '''[1:-1]))))
== code 0x80000000
main:
b7 02 01 10
13 03 80 04
23 a0 62 00
13 03 50 06
23 a0 62 00
13 03 c0 06
23 a0 62 00
13 03 c0 06
23 a0 62 00
13 03 f0 06
23 a0 62 00
13 03 a0 00
23 a0 62 00
6f f0 df fc
"""

import subv
import bits


def byteify(word):
    """split longer bitfield into bytes.

    >>> byteify(bits.Bitfield(0x12345678, 32))
    [(120,), (86,), (52,), (18,)]
    >>> byteify(bits.Bitfield(0x4801813, 32))
    [(19,), (24,), (128,), (4,)]
    >>> byteify(bits.Bitfield(0x13, 9)),
    Traceback (most recent call last):
        ...
    AssertionError: not byte aligned: 013/9
    """
    assert word.size % 8 == 0, "not byte aligned: {}".format(word)

    out = []
    for i in range(0, word.size, 8):
        byte = word[i + 7 : i]
        out.append((byte.val,))
    return out


@subv.with_parsed_lines
def pack(iter):
    out = []
    buf = bits.empty

    def flush_bytes():
        line = " ".join("{:02x}".format(b.val) for b in out)
        out.clear()
        return line

    last_segment = None
    for segment, line in iter:
        if last_segment != segment:
            assert buf.size == 0, "segment '{}' end isn't byte-aligned".format(segment)
            if out:
                yield subv.format(flush_bytes())

        if line["type"] == "instr":
            for part in line["instr"]:
                buf = bits.from_part(part) & buf
        else:
            yield line["raw"]

        while buf.size >= 8:
            byte = buf[7:0]
            buf = buf.slice_allowempty(slice(buf.size - 1, 8))
            out.append(byte)

            if len(out) == 4:
                yield flush_bytes()

        last_segment = segment

    assert buf.size == 0, "segment '{}' end isn't byte-aligned".format(segment)

    if len(out) > 0:
        yield flush_bytes()


if __name__ == "__main__":
    import sys

    for line in pack(sys.stdin):
        print(line)