xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/egd_tables.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1CopyRight = '''
2/*
3 * Copyright 2015 Advanced Micro Devices, Inc.
4 * SPDX-License-Identifier: MIT
5 */
6'''
7
8import sys
9import re
10
11
12class StringTable:
13    """
14    A class for collecting multiple strings in a single larger string that is
15    used by indexing (to avoid relocations in the resulting binary)
16    """
17    def __init__(self):
18        self.table = []
19        self.length = 0
20
21    def add(self, string):
22        # We might get lucky with string being a suffix of a previously added string
23        for te in self.table:
24            if te[0].endswith(string):
25                idx = te[1] + len(te[0]) - len(string)
26                te[2].add(idx)
27                return idx
28
29        idx = self.length
30        self.table.append((string, idx, set((idx,))))
31        self.length += len(string) + 1
32
33        return idx
34
35    def emit(self, filp, name, static=True):
36        """
37        Write
38        [static] const char name[] = "...";
39        to filp.
40        """
41        fragments = [
42            '"%s\\0" /* %s */' % (
43                te[0].encode('unicode_escape').decode(),
44                ', '.join(str(idx) for idx in te[2])
45            )
46            for te in self.table
47        ]
48        filp.write('%sconst char %s[] =\n%s;\n' % (
49            'static ' if static else '',
50            name,
51            '\n'.join('\t' + fragment for fragment in fragments)
52        ))
53
54class IntTable:
55    """
56    A class for collecting multiple arrays of integers in a single big array
57    that is used by indexing (to avoid relocations in the resulting binary)
58    """
59    def __init__(self, typename):
60        self.typename = typename
61        self.table = []
62        self.idxs = set()
63
64    def add(self, array):
65        # We might get lucky and find the array somewhere in the existing data
66        try:
67            idx = 0
68            while True:
69                idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1)
70
71                for i in range(1, len(array)):
72                    if array[i] != self.table[idx + i]:
73                        break
74                else:
75                    self.idxs.add(idx)
76                    return idx
77
78                idx += 1
79        except ValueError:
80            pass
81
82        idx = len(self.table)
83        self.table += array
84        self.idxs.add(idx)
85        return idx
86
87    def emit(self, filp, name, static=True):
88        """
89        Write
90        [static] const typename name[] = { ... };
91        to filp.
92        """
93        idxs = sorted(self.idxs) + [len(self.table)]
94
95        fragments = [
96            ('\t/* %s */ %s' % (
97                idxs[i],
98                ' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]])
99            ))
100            for i in range(len(idxs) - 1)
101        ]
102
103        filp.write('%sconst %s %s[] = {\n%s\n};\n' % (
104            'static ' if static else '',
105            self.typename, name,
106            '\n'.join(fragments)
107        ))
108
109class Field:
110    def __init__(self, reg, s_name):
111        self.s_name = s_name
112        self.name = strip_prefix(s_name)
113        self.values = []
114        self.varname_values = '%s__%s__values' % (reg.r_name.lower(), self.name.lower())
115
116class Reg:
117    def __init__(self, r_name):
118        self.r_name = r_name
119        self.name = strip_prefix(r_name)
120        self.fields = []
121        self.own_fields = True
122
123
124def strip_prefix(s):
125    '''Strip prefix in the form ._.*_, e.g. R_001234_'''
126    return s[s[2:].find('_')+3:]
127
128def parse(filename, regs, packets):
129    stream = open(filename)
130
131    for line in stream:
132        if not line.startswith('#define '):
133            continue
134
135        line = line[8:].strip()
136
137        if line.startswith('R_'):
138            name = line.split()[0]
139
140            for it in regs:
141                if it.r_name == name:
142                    reg = it
143                    break
144            else:
145                reg = Reg(name)
146                regs.append(reg)
147
148        elif line.startswith('S_'):
149            name = line[:line.find('(')]
150
151            for it in reg.fields:
152                if it.s_name == name:
153                    field = it
154                    break
155            else:
156                field = Field(reg, name)
157                reg.fields.append(field)
158
159        elif line.startswith('V_'):
160            split = line.split()
161            name = split[0]
162            value = int(split[1], 0)
163
164            for (n,v) in field.values:
165                if n == name:
166                    if v != value:
167                        sys.exit('Value mismatch: name = ' + name)
168
169            field.values.append((name, value))
170
171        elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
172            packets.append(line.split()[0])
173
174    # Copy fields to indexed registers which have their fields only defined
175    # at register index 0.
176    # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0.
177    match_number = re.compile('[0-9]+')
178    reg_dict = dict()
179
180    # Create a dict of registers with fields and '0' in their name
181    for reg in regs:
182        if len(reg.fields) and reg.name.find('0') != -1:
183            reg_dict[reg.name] = reg
184
185    # Assign fields
186    for reg in regs:
187        if not len(reg.fields):
188            reg0 = reg_dict.get(match_number.sub('0', reg.name))
189            if reg0 != None:
190                reg.fields = reg0.fields
191                reg.fields_owner = reg0
192                reg.own_fields = False
193
194
195def write_tables(regs, packets):
196
197    strings = StringTable()
198    strings_offsets = IntTable("int")
199
200    print('/* This file is autogenerated by egd_tables.py from evergreend.h. Do not edit directly. */')
201    print()
202    print(CopyRight.strip())
203    print('''
204#ifndef EG_TABLES_H
205#define EG_TABLES_H
206
207struct eg_field {
208        unsigned name_offset;
209        unsigned mask;
210        unsigned num_values;
211        unsigned values_offset; /* offset into eg_strings_offsets */
212};
213
214struct eg_reg {
215        unsigned name_offset;
216        unsigned offset;
217        unsigned num_fields;
218        unsigned fields_offset;
219};
220
221struct eg_packet3 {
222        unsigned name_offset;
223        unsigned op;
224};
225''')
226
227    print('static const struct eg_packet3 packet3_table[] = {')
228    for pkt in packets:
229        print('\t{%s, %s},' % (strings.add(pkt[5:]), pkt))
230    print('};')
231    print()
232
233    print('static const struct eg_field egd_fields_table[] = {')
234
235    fields_idx = 0
236    for reg in regs:
237        if len(reg.fields) and reg.own_fields:
238            print('\t/* %s */' % (fields_idx))
239
240            reg.fields_idx = fields_idx
241
242            for field in reg.fields:
243                if len(field.values):
244                    values_offsets = []
245                    for value in field.values:
246                        while value[1] >= len(values_offsets):
247                            values_offsets.append(-1)
248                        values_offsets[value[1]] = strings.add(strip_prefix(value[0]))
249                    print('\t{%s, %s(~0u), %s, %s},' % (
250                        strings.add(field.name), field.s_name,
251                        len(values_offsets), strings_offsets.add(values_offsets)))
252                else:
253                    print('\t{%s, %s(~0u)},' % (strings.add(field.name), field.s_name))
254                fields_idx += 1
255
256    print('};')
257    print()
258
259    print('static const struct eg_reg egd_reg_table[] = {')
260    for reg in regs:
261        if len(reg.fields):
262            print('\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name,
263                len(reg.fields), reg.fields_idx if reg.own_fields else reg.fields_owner.fields_idx))
264        else:
265            print('\t{%s, %s},' % (strings.add(reg.name), reg.r_name))
266    print('};')
267    print()
268
269    strings.emit(sys.stdout, "egd_strings")
270
271    print()
272
273    strings_offsets.emit(sys.stdout, "egd_strings_offsets")
274
275    print()
276    print('#endif')
277
278
279def main():
280    regs = []
281    packets = []
282    for arg in sys.argv[1:]:
283        parse(arg, regs, packets)
284    write_tables(regs, packets)
285
286
287if __name__ == '__main__':
288    main()
289
290# kate: space-indent on; indent-width 4; replace-tabs on;
291