#!/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)