xref: /aosp_15_r20/external/mesa3d/src/etnaviv/hwdb/hwdb.h.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*61046927SAndroid Build Coastguard Worker#
3*61046927SAndroid Build Coastguard Worker# Copyright © 2024 Igalia S.L.
4*61046927SAndroid Build Coastguard Worker# SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker
6*61046927SAndroid Build Coastguard Workerimport argparse
7*61046927SAndroid Build Coastguard Workerimport ctypes
8*61046927SAndroid Build Coastguard Workerimport logging
9*61046927SAndroid Build Coastguard Workerimport re
10*61046927SAndroid Build Coastguard Workerfrom datetime import datetime
11*61046927SAndroid Build Coastguard Workerfrom mako.template import Template
12*61046927SAndroid Build Coastguard Workerfrom pycparser import parse_file, c_ast
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Workerlogger = logging.getLogger('hwdb')
15*61046927SAndroid Build Coastguard Worker
16*61046927SAndroid Build Coastguard Workertemplate = """/*
17*61046927SAndroid Build Coastguard Worker * Copyright © 2024 Igalia S.L.
18*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
19*61046927SAndroid Build Coastguard Worker */
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker#pragma once
22*61046927SAndroid Build Coastguard Worker
23*61046927SAndroid Build Coastguard Worker#include <stdint.h>
24*61046927SAndroid Build Coastguard Worker
25*61046927SAndroid Build Coastguard Workertypedef struct
26*61046927SAndroid Build Coastguard Worker{
27*61046927SAndroid Build Coastguard Worker% for type, name in struct:
28*61046927SAndroid Build Coastguard Worker   ${type} ${name};
29*61046927SAndroid Build Coastguard Worker% endfor
30*61046927SAndroid Build Coastguard Worker} gcsFEATURE_DATABASE;
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Workerstatic gcsFEATURE_DATABASE gChipInfo[] = {
33*61046927SAndroid Build Coastguard Worker% for entry in entries:
34*61046927SAndroid Build Coastguard Worker   {
35*61046927SAndroid Build Coastguard Worker% for name, value in entry:
36*61046927SAndroid Build Coastguard Worker      ${value}, /* ${name} */
37*61046927SAndroid Build Coastguard Worker% endfor
38*61046927SAndroid Build Coastguard Worker   },
39*61046927SAndroid Build Coastguard Worker% endfor
40*61046927SAndroid Build Coastguard Worker};
41*61046927SAndroid Build Coastguard Worker
42*61046927SAndroid Build Coastguard Workerstatic inline gcsFEATURE_DATABASE *
43*61046927SAndroid Build Coastguard WorkergcQueryFeatureDB(
44*61046927SAndroid Build Coastguard Worker    uint32_t ChipID,
45*61046927SAndroid Build Coastguard Worker    uint32_t ChipVersion,
46*61046927SAndroid Build Coastguard Worker    uint32_t ProductID,
47*61046927SAndroid Build Coastguard Worker    uint32_t EcoID,
48*61046927SAndroid Build Coastguard Worker    uint32_t CustomerID
49*61046927SAndroid Build Coastguard Worker    )
50*61046927SAndroid Build Coastguard Worker{
51*61046927SAndroid Build Coastguard Worker    int entryNum = sizeof(gChipInfo) / sizeof(gChipInfo[0]);
52*61046927SAndroid Build Coastguard Worker
53*61046927SAndroid Build Coastguard Worker    /* check formal release entries first */
54*61046927SAndroid Build Coastguard Worker    for (int i = 0; i < entryNum; ++i)
55*61046927SAndroid Build Coastguard Worker    {
56*61046927SAndroid Build Coastguard Worker        if ((gChipInfo[i].chipID == ChipID)
57*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].chipVersion == ChipVersion)
58*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].productID == ProductID)
59*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].ecoID == EcoID)
60*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].customerID == CustomerID)
61*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].formalRelease)
62*61046927SAndroid Build Coastguard Worker           )
63*61046927SAndroid Build Coastguard Worker        {
64*61046927SAndroid Build Coastguard Worker            return &gChipInfo[i];
65*61046927SAndroid Build Coastguard Worker        }
66*61046927SAndroid Build Coastguard Worker    }
67*61046927SAndroid Build Coastguard Worker
68*61046927SAndroid Build Coastguard Worker    /* check informal release entries if we dont find in formal entries */
69*61046927SAndroid Build Coastguard Worker    for (int i = 0; i < entryNum; ++i)
70*61046927SAndroid Build Coastguard Worker    {
71*61046927SAndroid Build Coastguard Worker        if ((gChipInfo[i].chipID == ChipID)
72*61046927SAndroid Build Coastguard Worker            && ((gChipInfo[i].chipVersion & 0xFFF0) == (ChipVersion & 0xFFF0))
73*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].productID == ProductID)
74*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].ecoID == EcoID)
75*61046927SAndroid Build Coastguard Worker            && (gChipInfo[i].customerID == CustomerID)
76*61046927SAndroid Build Coastguard Worker            && (!gChipInfo[i].formalRelease)
77*61046927SAndroid Build Coastguard Worker           )
78*61046927SAndroid Build Coastguard Worker        {
79*61046927SAndroid Build Coastguard Worker            return &gChipInfo[i];
80*61046927SAndroid Build Coastguard Worker        }
81*61046927SAndroid Build Coastguard Worker    }
82*61046927SAndroid Build Coastguard Worker
83*61046927SAndroid Build Coastguard Worker    return 0;
84*61046927SAndroid Build Coastguard Worker}
85*61046927SAndroid Build Coastguard Worker"""
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Workerclass HeaderFile(c_ast.NodeVisitor):
89*61046927SAndroid Build Coastguard Worker    """Class representing a complete header file"""
90*61046927SAndroid Build Coastguard Worker
91*61046927SAndroid Build Coastguard Worker    # Regular expression to match the date and time in the comment
92*61046927SAndroid Build Coastguard Worker    _DATE_RE = re.compile(r'/\*Auto created on (\d{4}-\d{2}-\d{2} \d{2}:\d{2})\*/')
93*61046927SAndroid Build Coastguard Worker
94*61046927SAndroid Build Coastguard Worker    def __init__(self, filename):
95*61046927SAndroid Build Coastguard Worker        self.filename = filename
96*61046927SAndroid Build Coastguard Worker        self.structs = {}
97*61046927SAndroid Build Coastguard Worker        self.data = []
98*61046927SAndroid Build Coastguard Worker        self.date_time = None
99*61046927SAndroid Build Coastguard Worker        self.database_struct = None
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker        self._read_date()
102*61046927SAndroid Build Coastguard Worker        self._parse()
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker        logger.debug('Parsed %s (autogenerated at %s, %u struct members, %u entries)', self.filename, self.date_time, len(self.database_struct._fields_), len(self.data))
105*61046927SAndroid Build Coastguard Worker
106*61046927SAndroid Build Coastguard Worker    def _read_date(self):
107*61046927SAndroid Build Coastguard Worker        """Function parsing the creation date with re."""
108*61046927SAndroid Build Coastguard Worker        # Read the content of the file and search for pattern
109*61046927SAndroid Build Coastguard Worker        with open(self.filename, 'r', encoding="utf-8") as file:
110*61046927SAndroid Build Coastguard Worker            file_content = file.read()
111*61046927SAndroid Build Coastguard Worker
112*61046927SAndroid Build Coastguard Worker        match = self._DATE_RE.search(file_content)
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker        if match:
115*61046927SAndroid Build Coastguard Worker            self.date_time = datetime.strptime(match.group(1), '%Y-%m-%d %H:%M')
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker    def _parse(self):
118*61046927SAndroid Build Coastguard Worker        ast = parse_file(self.filename, use_cpp=True, cpp_args=['-E', r'-I./utils/fake_libc_include', '-DgctUINT32=unsigned int', '-DgctINT=int'])
119*61046927SAndroid Build Coastguard Worker        self.visit(ast)
120*61046927SAndroid Build Coastguard Worker
121*61046927SAndroid Build Coastguard Worker        self.database_struct = self.structs['gcsFEATURE_DATABASE']
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker    def visit_Typedef(self, node):
124*61046927SAndroid Build Coastguard Worker        if isinstance(node.type, c_ast.TypeDecl) and isinstance(node.type.type, c_ast.Struct):
125*61046927SAndroid Build Coastguard Worker            struct_node = node.type.type
126*61046927SAndroid Build Coastguard Worker            struct_name = node.name  # Typedef name as the struct name
127*61046927SAndroid Build Coastguard Worker            fields = self._extract_fields_from_struct(struct_node)
128*61046927SAndroid Build Coastguard Worker            if fields is not None:
129*61046927SAndroid Build Coastguard Worker                # Create the ctypes.Structure subclass and add it to the structures dictionary
130*61046927SAndroid Build Coastguard Worker                self.structs[struct_name] = type(struct_name, (ctypes.Structure,), {'_fields_': fields})
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker    def _extract_fields_from_struct(self, struct_node):
133*61046927SAndroid Build Coastguard Worker        """Function returning all fields of struct."""
134*61046927SAndroid Build Coastguard Worker        fields = []
135*61046927SAndroid Build Coastguard Worker        for decl in (struct_node.decls or []):
136*61046927SAndroid Build Coastguard Worker            if isinstance(decl.type, c_ast.TypeDecl) or isinstance(decl.type, c_ast.PtrDecl):
137*61046927SAndroid Build Coastguard Worker                field_name = decl.name
138*61046927SAndroid Build Coastguard Worker                field_type = self._map_type_to_ctypes(decl.type.type, decl.bitsize)
139*61046927SAndroid Build Coastguard Worker                if field_type:
140*61046927SAndroid Build Coastguard Worker                    fields.append((field_name, field_type))
141*61046927SAndroid Build Coastguard Worker            elif isinstance(decl.type, c_ast.ArrayDecl):
142*61046927SAndroid Build Coastguard Worker                # Handle array type
143*61046927SAndroid Build Coastguard Worker                field_name = decl.type.type.declname
144*61046927SAndroid Build Coastguard Worker                element_type = self._map_type_to_ctypes(decl.type.type.type)
145*61046927SAndroid Build Coastguard Worker                array_size = int(decl.type.dim.value)  # Assuming dim is a Constant node with the size as its value
146*61046927SAndroid Build Coastguard Worker                if element_type:
147*61046927SAndroid Build Coastguard Worker                    fields.append((field_name, element_type * array_size))
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker        return fields if fields else None
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker    def _map_type_to_ctypes(self, type_node, bitsize=None):
152*61046927SAndroid Build Coastguard Worker        """Function returning a ctype type based node type."""
153*61046927SAndroid Build Coastguard Worker        type_mappings = {
154*61046927SAndroid Build Coastguard Worker            'bool': ctypes.c_bool,
155*61046927SAndroid Build Coastguard Worker            'unsigned int': ctypes.c_uint,
156*61046927SAndroid Build Coastguard Worker            'int': ctypes.c_int,
157*61046927SAndroid Build Coastguard Worker        }
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker        if isinstance(type_node, c_ast.IdentifierType):
160*61046927SAndroid Build Coastguard Worker            c_type = ' '.join(type_node.names)
161*61046927SAndroid Build Coastguard Worker
162*61046927SAndroid Build Coastguard Worker            if bitsize and bitsize.value == '1':
163*61046927SAndroid Build Coastguard Worker                c_type = 'bool'
164*61046927SAndroid Build Coastguard Worker
165*61046927SAndroid Build Coastguard Worker            return type_mappings.get(c_type)
166*61046927SAndroid Build Coastguard Worker        elif isinstance(type_node, c_ast.TypeDecl):
167*61046927SAndroid Build Coastguard Worker            return ctypes.c_char_p
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker        return None
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker    def visit_Decl(self, node):
172*61046927SAndroid Build Coastguard Worker        # Check if the node is a declaration of an array of structs
173*61046927SAndroid Build Coastguard Worker        if isinstance(node.type, c_ast.ArrayDecl) and isinstance(node.type.type, c_ast.TypeDecl):
174*61046927SAndroid Build Coastguard Worker            struct_name = node.type.type.type.names[0]
175*61046927SAndroid Build Coastguard Worker            if struct_name in self.structs:
176*61046927SAndroid Build Coastguard Worker                elements = self._parse_array_initializer(node.init, self.structs[struct_name])
177*61046927SAndroid Build Coastguard Worker                self.data.extend(elements)
178*61046927SAndroid Build Coastguard Worker
179*61046927SAndroid Build Coastguard Worker    def _parse_initializer(self, initializer, struct):
180*61046927SAndroid Build Coastguard Worker        """Function returning one parsed struct initializer."""
181*61046927SAndroid Build Coastguard Worker        return [
182*61046927SAndroid Build Coastguard Worker            (param if not isinstance(param, str) else param.encode('utf-8'))
183*61046927SAndroid Build Coastguard Worker            for index, expr in enumerate(initializer.exprs)
184*61046927SAndroid Build Coastguard Worker            for param in [self._parse_expr(expr, getattr(struct._fields_[index][1], '_length_', None))]
185*61046927SAndroid Build Coastguard Worker        ]
186*61046927SAndroid Build Coastguard Worker
187*61046927SAndroid Build Coastguard Worker    def _parse_array_initializer(self, init, struct_class):
188*61046927SAndroid Build Coastguard Worker        """Function returning a fully processed struct initializer list."""
189*61046927SAndroid Build Coastguard Worker        assert (isinstance(init, c_ast.InitList))
190*61046927SAndroid Build Coastguard Worker        return [struct_class(*self._parse_initializer(initializer, struct_class)) for initializer in init.exprs]
191*61046927SAndroid Build Coastguard Worker
192*61046927SAndroid Build Coastguard Worker    def _parse_expr(self, expr, expected_size=None):
193*61046927SAndroid Build Coastguard Worker        """Function returning parsed expression."""
194*61046927SAndroid Build Coastguard Worker        # Direct handling of constant types
195*61046927SAndroid Build Coastguard Worker        if isinstance(expr, c_ast.Constant):
196*61046927SAndroid Build Coastguard Worker            if expr.type == "int":
197*61046927SAndroid Build Coastguard Worker                # Base 0 automatically handles decimal, hex, and octal
198*61046927SAndroid Build Coastguard Worker                return int(expr.value, 0)
199*61046927SAndroid Build Coastguard Worker            elif expr.type == "string":
200*61046927SAndroid Build Coastguard Worker                return expr.value.strip('"')
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker        # Handling arrays with potential conversion to ctypes arrays
203*61046927SAndroid Build Coastguard Worker        elif isinstance(expr, c_ast.InitList) and expected_size is not None:
204*61046927SAndroid Build Coastguard Worker            element_list = [self._parse_expr(e) for e in expr.exprs]
205*61046927SAndroid Build Coastguard Worker
206*61046927SAndroid Build Coastguard Worker            # Ensure the list matches expected size, filling with zeros if necessary
207*61046927SAndroid Build Coastguard Worker            if len(element_list) < expected_size:
208*61046927SAndroid Build Coastguard Worker                element_list.extend([0] * (expected_size - len(element_list)))
209*61046927SAndroid Build Coastguard Worker
210*61046927SAndroid Build Coastguard Worker            # Convert to ctypes array, dynamically adjusting type based on context if needed
211*61046927SAndroid Build Coastguard Worker            return (ctypes.c_uint * expected_size)(*element_list)
212*61046927SAndroid Build Coastguard Worker
213*61046927SAndroid Build Coastguard Worker        # Fallback or default return for unhandled cases
214*61046927SAndroid Build Coastguard Worker        return None
215*61046927SAndroid Build Coastguard Worker
216*61046927SAndroid Build Coastguard Worker
217*61046927SAndroid Build Coastguard Workerdef merge_structures(structures):
218*61046927SAndroid Build Coastguard Worker    """Function creating a new type by merging provided types."""
219*61046927SAndroid Build Coastguard Worker    combined_fields = []
220*61046927SAndroid Build Coastguard Worker    for struct in structures:
221*61046927SAndroid Build Coastguard Worker        for field_name, field_type in struct._fields_:
222*61046927SAndroid Build Coastguard Worker            # Check if the field name already exists
223*61046927SAndroid Build Coastguard Worker            if field_name not in [field[0] for field in combined_fields]:
224*61046927SAndroid Build Coastguard Worker                combined_fields.append((field_name, field_type))
225*61046927SAndroid Build Coastguard Worker
226*61046927SAndroid Build Coastguard Worker    # Create a new structure dynamically
227*61046927SAndroid Build Coastguard Worker    return type("MergedStructure", (ctypes.Structure,), {'_fields_': combined_fields})
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker
230*61046927SAndroid Build Coastguard Workerdef get_field_type(c, field_name):
231*61046927SAndroid Build Coastguard Worker    """Function returning the type of a field type based on its name."""
232*61046927SAndroid Build Coastguard Worker    for field in c._fields_:
233*61046927SAndroid Build Coastguard Worker        if field[0] == field_name:
234*61046927SAndroid Build Coastguard Worker            return field[1]
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker    return None
237*61046927SAndroid Build Coastguard Worker
238*61046927SAndroid Build Coastguard Worker
239*61046927SAndroid Build Coastguard Workerdef create_merged_struct(c, entry):
240*61046927SAndroid Build Coastguard Worker    """Function returning a fully populate instance of MergedStructure."""
241*61046927SAndroid Build Coastguard Worker    fields = []
242*61046927SAndroid Build Coastguard Worker    for field_name, field_type in c._fields_:
243*61046927SAndroid Build Coastguard Worker        # We might need to 'upgrade' to an array - check field type too.
244*61046927SAndroid Build Coastguard Worker        # e.g. VIP_SRAM_SIZE_ARRAY -> VIP_SRAM_SIZE_ARRAY[9]
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker        if hasattr(entry, field_name) and get_field_type(entry, field_name) is field_type:
247*61046927SAndroid Build Coastguard Worker            fields.append(getattr(entry, field_name))
248*61046927SAndroid Build Coastguard Worker        else:
249*61046927SAndroid Build Coastguard Worker            # Add a suitable default value
250*61046927SAndroid Build Coastguard Worker            if field_type == ctypes.c_uint or field_type == ctypes.c_bool:
251*61046927SAndroid Build Coastguard Worker                fields.append(0)
252*61046927SAndroid Build Coastguard Worker            else:
253*61046927SAndroid Build Coastguard Worker                # It must be an array
254*61046927SAndroid Build Coastguard Worker                expected_size = getattr(field_type, '_length_')
255*61046927SAndroid Build Coastguard Worker                fields.append((ctypes.c_uint * expected_size)(*[0] * expected_size))
256*61046927SAndroid Build Coastguard Worker
257*61046927SAndroid Build Coastguard Worker    return c(*fields)
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Workerdef enumerate_struct(obj):
261*61046927SAndroid Build Coastguard Worker    for field_name, field_type in obj._fields_:
262*61046927SAndroid Build Coastguard Worker        type = 'uint32_t'
263*61046927SAndroid Build Coastguard Worker
264*61046927SAndroid Build Coastguard Worker        if field_type == ctypes.c_char_p:
265*61046927SAndroid Build Coastguard Worker            type = 'const char *'
266*61046927SAndroid Build Coastguard Worker
267*61046927SAndroid Build Coastguard Worker        if field_type == ctypes.c_bool:
268*61046927SAndroid Build Coastguard Worker            field_name = field_name + ':1'
269*61046927SAndroid Build Coastguard Worker
270*61046927SAndroid Build Coastguard Worker        if hasattr(field_type, '_length_'):
271*61046927SAndroid Build Coastguard Worker            field_name = f'{field_name}[{field_type._length_}]'
272*61046927SAndroid Build Coastguard Worker
273*61046927SAndroid Build Coastguard Worker        yield type, field_name
274*61046927SAndroid Build Coastguard Worker
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Workerdef enumerate_values(obj):
277*61046927SAndroid Build Coastguard Worker    for field_name, field_type in obj._fields_:
278*61046927SAndroid Build Coastguard Worker        value = getattr(obj, field_name)
279*61046927SAndroid Build Coastguard Worker
280*61046927SAndroid Build Coastguard Worker        if field_type in {ctypes.c_uint, ctypes.c_bool}:
281*61046927SAndroid Build Coastguard Worker            value = hex(value)
282*61046927SAndroid Build Coastguard Worker        elif field_type == ctypes.c_char_p:
283*61046927SAndroid Build Coastguard Worker            value = '"{}"'.format(value.decode('utf-8'))
284*61046927SAndroid Build Coastguard Worker        elif isinstance(value, ctypes.Array):
285*61046927SAndroid Build Coastguard Worker            value = '{{{}}}'.format(', '.join(str(element) for element in value))
286*61046927SAndroid Build Coastguard Worker
287*61046927SAndroid Build Coastguard Worker        yield field_name, value
288*61046927SAndroid Build Coastguard Worker
289*61046927SAndroid Build Coastguard Worker
290*61046927SAndroid Build Coastguard Workerdef main():
291*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
292*61046927SAndroid Build Coastguard Worker    parser.add_argument('--output', required=True, type=str, action="store",
293*61046927SAndroid Build Coastguard Worker                        help='output C header file')
294*61046927SAndroid Build Coastguard Worker    parser.add_argument('headers', metavar='header', type=str, nargs='+',
295*61046927SAndroid Build Coastguard Worker                        help='gc database header to process')
296*61046927SAndroid Build Coastguard Worker    parser.add_argument('--verbose', "-v", action="store_true",
297*61046927SAndroid Build Coastguard Worker                        help='be verbose')
298*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
299*61046927SAndroid Build Coastguard Worker
300*61046927SAndroid Build Coastguard Worker    if args.verbose:
301*61046927SAndroid Build Coastguard Worker        logging.basicConfig(level=logging.DEBUG)
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker    files = [HeaderFile(header) for header in args.headers]
304*61046927SAndroid Build Coastguard Worker    structs = [file.database_struct for file in files]
305*61046927SAndroid Build Coastguard Worker    merged = merge_structures(structs)
306*61046927SAndroid Build Coastguard Worker    logger.debug('merged struct: %u members', len(merged._fields_))
307*61046927SAndroid Build Coastguard Worker
308*61046927SAndroid Build Coastguard Worker    entries = []
309*61046927SAndroid Build Coastguard Worker    for file in files:
310*61046927SAndroid Build Coastguard Worker        logger.debug('Processing %s', file.filename)
311*61046927SAndroid Build Coastguard Worker        for entry in file.data:
312*61046927SAndroid Build Coastguard Worker            merged_entry = create_merged_struct(merged, entry)
313*61046927SAndroid Build Coastguard Worker            entry_data = list(enumerate_values(merged_entry))
314*61046927SAndroid Build Coastguard Worker            entries.append(entry_data)
315*61046927SAndroid Build Coastguard Worker
316*61046927SAndroid Build Coastguard Worker    logger.debug('Total entries: %u', len(entries))
317*61046927SAndroid Build Coastguard Worker
318*61046927SAndroid Build Coastguard Worker    with open(args.output, "w", encoding="UTF-8") as fh:
319*61046927SAndroid Build Coastguard Worker        print(Template(template).render(struct=enumerate_struct(merged), entries=entries), file=fh)
320*61046927SAndroid Build Coastguard Worker
321*61046927SAndroid Build Coastguard Worker
322*61046927SAndroid Build Coastguard Workerif __name__ == '__main__':
323*61046927SAndroid Build Coastguard Worker    main()
324