summaryrefslogtreecommitdiff
path: root/hex2fields.py
blob: a16cabb604a4c264f0d1749ace063b8854dcda58 (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python

import re
import sys
import math

# word = int(sys.argv[1], 16)

def field_disp(lm):
    if lm[0] == lm[1]:
        return "%d" % lm[0]
    else:
        return "%d:%d" % (lm[0], lm[1])

def inv_sort_sizes(sz):
    return sorted([(v, k) for k, v in sz.iteritems()])

class Desc(object):

    SIZES = {
        'B': 8,
        'W': 16,
        'D': 32,
        'Q': 64,
    }

    INV_SIZES = inv_sort_sizes(SIZES)

    def __init__(self, lines):
        self.struct = []
        self.cur = []
        self.curname = None
        self.curbase = None
        self.cursz = None
        self.up = None
        self.base = 0           # base offset (in bits)

        for lnum, line in enumerate(lines):

            lnum += 1
            line = line.strip()
            if not line:
                continue

            if line.upper() in self.SIZES:
                self.new_word(line.upper())
                continue

            parts = re.split(r"\s*:\s*", line)
            if len(parts) == 1:
                parts = parts * 2
            if len(parts) > 2:
                raise ValueError("bad line: %s" % line)
            limits = [int(p) for p in parts]
            if limits[0] < limits[1]:
                raise ValueError("wrong order in line %d: %r" % (lnum, line))
            if limits[1] < 0:
                raise ValueError("bad bit num in line %d: %r" % (lnum, line))

            if self.cursz is None:
                for bn, size_qual in self.INV_SIZES:
                    if bn > limits[0]:
                        self.new_word(size_qual, "auto ")
                        break
                else:
                    raise ValueError("out of range bitfield in line %d: %r" % 
                                     (lnum, line))

            if limits[0] + 1 > self.up:
                raise ValueError("out of range or not in decreasing order "
                                 "at line %d: %r" % (lnum, line))

            if limits[0] + 1 < self.up:
                auto_ins = [self.up - 1, limits[0] + 1]
                self.ins_bitfield(auto_ins, "auto ")

            self.ins_bitfield(limits)

            if limits[1] == 0:
                self.close_cur()

        self.close_cur()

    def ins_bitfield(self, bf, why=""):
        print "%sinserting bit field %s" % (why, field_disp(bf))
        self.up = bf[1]
        self.cur.append(bf)

    def new_word(self, size_qual, why=""):
        bit_num = self.SIZES[size_qual]
        self.close_cur()
        self.cursz = self.up = bit_num
        self.curbase = self.base
        self.curname = "%s@%d(%d)" % (size_qual, self.base / 8, self.base)
        self.base += bit_num
        print "%snew word %s" % (why, self.curname)

    def close_cur(self):
        if self.cursz is None:
            return
        if not self.cur:
            self.ins_bitfield([self.cursz - 1, 0], "auto ")
        elif self.cur[-1][1] > 0:
            self.ins_bitfield([self.cur[-1][1] - 1, 0], "auto ")
        print "closing %s" % self.curname
        self.struct.append((self.curname, self.curbase, self.cur))
        self.cur = []
        self.curname = None
        self.cursz = None
        self.up = None

    def parse_print(self, val):
        for name, base, fields in self.struct:
            wval = val >> base
            print "%s:" % name
            for hb, lb in fields:
                bn = (hb - lb + 1)
                fval = (wval >> lb) & ((1 << bn) - 1)
                print " %s\t%sb\t%sh\t%d" % (
                            field_disp([hb, lb]),
                            to_bin(fval, bn),
                            to_hex(fval, bn),
                            fval)

def to_bin(v, bn):
    pref = ""
    if v & ((1 << bn) - 1) != v:
        pref = "OVERFLOW:"
        bn = int((math.ceil(math.log(v + 1, 2))))
    return pref + ''.join([str((v >> i) & 1) for i in xrange(bn - 1, -1, -1)])

def to_hex(v, bn):
    hn = (bn + 3) / 4
    fmt = "%%0%dx" % hn
    return fmt % v

desc = Desc(sys.stdin)
print
desc.parse_print(int(sys.argv[1], 16))