aboutsummaryrefslogtreecommitdiffstats
path: root/pack.py
blob: 5dbaf953f0f9336f5881d94cf97a7ca08d3a8e09 (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
#!/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
... 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 01/1 3e6/10 01/1
... '''[1:-1]))))
== code 0x80000000
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: 0x13'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():
        tmp = out[:]
        out.clear()
        return {
          'type': 'instr',
          'instr': tmp,
          'comment': None,
        }

    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.val,))

            if len(out) == 4:
                yield subv.format(flush_bytes())

        last_segment = segment

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

if __name__ == '__main__':
    import sys
    for line in pack(sys.stdin):
        print(line)