1b8e80941Smrg#encoding=utf-8
2b8e80941Smrg# Copyright © 2017 Intel Corporation
3b8e80941Smrg
4b8e80941Smrg# Permission is hereby granted, free of charge, to any person obtaining a copy
5b8e80941Smrg# of this software and associated documentation files (the "Software"), to deal
6b8e80941Smrg# in the Software without restriction, including without limitation the rights
7b8e80941Smrg# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8b8e80941Smrg# copies of the Software, and to permit persons to whom the Software is
9b8e80941Smrg# furnished to do so, subject to the following conditions:
10b8e80941Smrg
11b8e80941Smrg# The above copyright notice and this permission notice shall be included in
12b8e80941Smrg# all copies or substantial portions of the Software.
13b8e80941Smrg
14b8e80941Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b8e80941Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b8e80941Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17b8e80941Smrg# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18b8e80941Smrg# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19b8e80941Smrg# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20b8e80941Smrg# SOFTWARE.
21b8e80941Smrg
22b8e80941Smrgfrom __future__ import (
23b8e80941Smrg    absolute_import, division, print_function, unicode_literals
24b8e80941Smrg)
25b8e80941Smrg
26b8e80941Smrgimport argparse
27b8e80941Smrgimport os
28b8e80941Smrgimport re
29b8e80941Smrgimport xml.parsers.expat
30b8e80941Smrg
31b8e80941Smrgfrom mako.template import Template
32b8e80941Smrg
33b8e80941SmrgTEMPLATE = Template("""\
34b8e80941Smrg<%!
35b8e80941Smrgfrom operator import itemgetter
36b8e80941Smrg%>\
37b8e80941Smrg/*
38b8e80941Smrg * Copyright © 2017 Intel Corporation
39b8e80941Smrg *
40b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
41b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
42b8e80941Smrg * to deal in the Software without restriction, including without limitation
43b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
44b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
45b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
46b8e80941Smrg *
47b8e80941Smrg * The above copyright notice and this permission notice (including the next
48b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
49b8e80941Smrg * Software.
50b8e80941Smrg *
51b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
52b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
53b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
54b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
55b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
56b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
57b8e80941Smrg * IN THE SOFTWARE.
58b8e80941Smrg */
59b8e80941Smrg
60b8e80941Smrg/* THIS FILE HAS BEEN GENERATED, DO NOT HAND EDIT.
61b8e80941Smrg *
62b8e80941Smrg * Sizes of bitfields in genxml instructions, structures, and registers.
63b8e80941Smrg */
64b8e80941Smrg
65b8e80941Smrg#ifndef ${guard}
66b8e80941Smrg#define ${guard}
67b8e80941Smrg
68b8e80941Smrg#include <stdint.h>
69b8e80941Smrg
70b8e80941Smrg#include "dev/gen_device_info.h"
71b8e80941Smrg#include "util/macros.h"
72b8e80941Smrg
73b8e80941Smrg<%def name="emit_per_gen_prop_func(item, prop)">
74b8e80941Smrg%if item.has_prop(prop):
75b8e80941Smrg% for gen, value in sorted(item.iter_prop(prop), reverse=True):
76b8e80941Smrg#define ${gen.prefix(item.token_name)}_${prop}  ${value}
77b8e80941Smrg% endfor
78b8e80941Smrg
79b8e80941Smrgstatic inline uint32_t ATTRIBUTE_PURE
80b8e80941Smrg${item.token_name}_${prop}(const struct gen_device_info *devinfo)
81b8e80941Smrg{
82b8e80941Smrg   switch (devinfo->gen) {
83b8e80941Smrg   case 11: return ${item.get_prop(prop, 11)};
84b8e80941Smrg   case 10: return ${item.get_prop(prop, 10)};
85b8e80941Smrg   case 9: return ${item.get_prop(prop, 9)};
86b8e80941Smrg   case 8: return ${item.get_prop(prop, 8)};
87b8e80941Smrg   case 7:
88b8e80941Smrg      if (devinfo->is_haswell) {
89b8e80941Smrg         return ${item.get_prop(prop, 7.5)};
90b8e80941Smrg      } else {
91b8e80941Smrg         return ${item.get_prop(prop, 7)};
92b8e80941Smrg      }
93b8e80941Smrg   case 6: return ${item.get_prop(prop, 6)};
94b8e80941Smrg   case 5: return ${item.get_prop(prop, 5)};
95b8e80941Smrg   case 4:
96b8e80941Smrg      if (devinfo->is_g4x) {
97b8e80941Smrg         return ${item.get_prop(prop, 4.5)};
98b8e80941Smrg      } else {
99b8e80941Smrg         return ${item.get_prop(prop, 4)};
100b8e80941Smrg      }
101b8e80941Smrg   default:
102b8e80941Smrg      unreachable("Invalid hardware generation");
103b8e80941Smrg   }
104b8e80941Smrg}
105b8e80941Smrg%endif
106b8e80941Smrg</%def>
107b8e80941Smrg
108b8e80941Smrg#ifdef __cplusplus
109b8e80941Smrgextern "C" {
110b8e80941Smrg#endif
111b8e80941Smrg% for _, container in sorted(containers.items(), key=itemgetter(0)):
112b8e80941Smrg
113b8e80941Smrg/* ${container.name} */
114b8e80941Smrg
115b8e80941Smrg${emit_per_gen_prop_func(container, 'length')}
116b8e80941Smrg
117b8e80941Smrg% for _, field in sorted(container.fields.items(), key=itemgetter(0)):
118b8e80941Smrg
119b8e80941Smrg/* ${container.name}::${field.name} */
120b8e80941Smrg
121b8e80941Smrg${emit_per_gen_prop_func(field, 'bits')}
122b8e80941Smrg
123b8e80941Smrg${emit_per_gen_prop_func(field, 'start')}
124b8e80941Smrg
125b8e80941Smrg% endfor
126b8e80941Smrg% endfor
127b8e80941Smrg
128b8e80941Smrg#ifdef __cplusplus
129b8e80941Smrg}
130b8e80941Smrg#endif
131b8e80941Smrg
132b8e80941Smrg#endif /* ${guard} */""", output_encoding='utf-8')
133b8e80941Smrg
134b8e80941Smrgalphanum_nono = re.compile(r'[ /\[\]()\-:.,=>#&*"+\\]+')
135b8e80941Smrgdef to_alphanum(name):
136b8e80941Smrg    global alphanum_nono
137b8e80941Smrg    return alphanum_nono.sub('', name).replace('α', 'alpha')
138b8e80941Smrg
139b8e80941Smrgdef safe_name(name):
140b8e80941Smrg    name = to_alphanum(name)
141b8e80941Smrg    if not name[0].isalpha():
142b8e80941Smrg        name = '_' + name
143b8e80941Smrg    return name
144b8e80941Smrg
145b8e80941Smrgclass Gen(object):
146b8e80941Smrg
147b8e80941Smrg    def __init__(self, z):
148b8e80941Smrg        # Convert potential "major.minor" string
149b8e80941Smrg        self.tenx = int(float(z) * 10)
150b8e80941Smrg
151b8e80941Smrg    def __lt__(self, other):
152b8e80941Smrg        return self.tenx < other.tenx
153b8e80941Smrg
154b8e80941Smrg    def __hash__(self):
155b8e80941Smrg        return hash(self.tenx)
156b8e80941Smrg
157b8e80941Smrg    def __eq__(self, other):
158b8e80941Smrg        return self.tenx == other.tenx
159b8e80941Smrg
160b8e80941Smrg    def prefix(self, token):
161b8e80941Smrg        gen = self.tenx
162b8e80941Smrg
163b8e80941Smrg        if gen % 10 == 0:
164b8e80941Smrg            gen //= 10
165b8e80941Smrg
166b8e80941Smrg        if token[0] == '_':
167b8e80941Smrg            token = token[1:]
168b8e80941Smrg
169b8e80941Smrg        return 'GEN{}_{}'.format(gen, token)
170b8e80941Smrg
171b8e80941Smrgclass Container(object):
172b8e80941Smrg
173b8e80941Smrg    def __init__(self, name):
174b8e80941Smrg        self.name = name
175b8e80941Smrg        self.token_name = safe_name(name)
176b8e80941Smrg        self.length_by_gen = {}
177b8e80941Smrg        self.fields = {}
178b8e80941Smrg
179b8e80941Smrg    def add_gen(self, gen, xml_attrs):
180b8e80941Smrg        assert isinstance(gen, Gen)
181b8e80941Smrg        if 'length' in xml_attrs:
182b8e80941Smrg            self.length_by_gen[gen] = xml_attrs['length']
183b8e80941Smrg
184b8e80941Smrg    def get_field(self, field_name, create=False):
185b8e80941Smrg        if field_name not in self.fields:
186b8e80941Smrg            if create:
187b8e80941Smrg                self.fields[field_name] = Field(self, field_name)
188b8e80941Smrg            else:
189b8e80941Smrg                return None
190b8e80941Smrg        return self.fields[field_name]
191b8e80941Smrg
192b8e80941Smrg    def has_prop(self, prop):
193b8e80941Smrg        if prop == 'length':
194b8e80941Smrg            return bool(self.length_by_gen)
195b8e80941Smrg        else:
196b8e80941Smrg            raise ValueError('Invalid property: "{0}"'.format(prop))
197b8e80941Smrg
198b8e80941Smrg    def iter_prop(self, prop):
199b8e80941Smrg        if prop == 'length':
200b8e80941Smrg            return self.length_by_gen.items()
201b8e80941Smrg        else:
202b8e80941Smrg            raise ValueError('Invalid property: "{0}"'.format(prop))
203b8e80941Smrg
204b8e80941Smrg    def get_prop(self, prop, gen):
205b8e80941Smrg        if not isinstance(gen, Gen):
206b8e80941Smrg            gen = Gen(gen)
207b8e80941Smrg
208b8e80941Smrg        if prop == 'length':
209b8e80941Smrg            return self.length_by_gen.get(gen, 0)
210b8e80941Smrg        else:
211b8e80941Smrg            raise ValueError('Invalid property: "{0}"'.format(prop))
212b8e80941Smrg
213b8e80941Smrgclass Field(object):
214b8e80941Smrg
215b8e80941Smrg    def __init__(self, container, name):
216b8e80941Smrg        self.name = name
217b8e80941Smrg        self.token_name = safe_name('_'.join([container.name, self.name]))
218b8e80941Smrg        self.bits_by_gen = {}
219b8e80941Smrg        self.start_by_gen = {}
220b8e80941Smrg
221b8e80941Smrg    def add_gen(self, gen, xml_attrs):
222b8e80941Smrg        assert isinstance(gen, Gen)
223b8e80941Smrg        start = int(xml_attrs['start'])
224b8e80941Smrg        end = int(xml_attrs['end'])
225b8e80941Smrg        self.start_by_gen[gen] = start
226b8e80941Smrg        self.bits_by_gen[gen] = 1 + end - start
227b8e80941Smrg
228b8e80941Smrg    def has_prop(self, prop):
229b8e80941Smrg        return True
230b8e80941Smrg
231b8e80941Smrg    def iter_prop(self, prop):
232b8e80941Smrg        if prop == 'bits':
233b8e80941Smrg            return self.bits_by_gen.items()
234b8e80941Smrg        elif prop == 'start':
235b8e80941Smrg            return self.start_by_gen.items()
236b8e80941Smrg        else:
237b8e80941Smrg            raise ValueError('Invalid property: "{0}"'.format(prop))
238b8e80941Smrg
239b8e80941Smrg    def get_prop(self, prop, gen):
240b8e80941Smrg        if not isinstance(gen, Gen):
241b8e80941Smrg            gen = Gen(gen)
242b8e80941Smrg
243b8e80941Smrg        if prop == 'bits':
244b8e80941Smrg            return self.bits_by_gen.get(gen, 0)
245b8e80941Smrg        elif prop == 'start':
246b8e80941Smrg            return self.start_by_gen.get(gen, 0)
247b8e80941Smrg        else:
248b8e80941Smrg            raise ValueError('Invalid property: "{0}"'.format(prop))
249b8e80941Smrg
250b8e80941Smrgclass XmlParser(object):
251b8e80941Smrg
252b8e80941Smrg    def __init__(self, containers):
253b8e80941Smrg        self.parser = xml.parsers.expat.ParserCreate()
254b8e80941Smrg        self.parser.StartElementHandler = self.start_element
255b8e80941Smrg        self.parser.EndElementHandler = self.end_element
256b8e80941Smrg
257b8e80941Smrg        self.gen = None
258b8e80941Smrg        self.containers = containers
259b8e80941Smrg        self.container = None
260b8e80941Smrg
261b8e80941Smrg    def parse(self, filename):
262b8e80941Smrg        with open(filename, 'rb') as f:
263b8e80941Smrg            self.parser.ParseFile(f)
264b8e80941Smrg
265b8e80941Smrg    def start_element(self, name, attrs):
266b8e80941Smrg        if name == 'genxml':
267b8e80941Smrg            self.gen = Gen(attrs['gen'])
268b8e80941Smrg        elif name in ('instruction', 'struct', 'register'):
269b8e80941Smrg            if name == 'instruction' and 'engine' in attrs:
270b8e80941Smrg                engines = set(attrs['engine'].split('|'))
271b8e80941Smrg                if not engines & self.engines:
272b8e80941Smrg                    return
273b8e80941Smrg            self.start_container(attrs)
274b8e80941Smrg        elif name == 'field':
275b8e80941Smrg            self.start_field(attrs)
276b8e80941Smrg        else:
277b8e80941Smrg            pass
278b8e80941Smrg
279b8e80941Smrg    def end_element(self, name):
280b8e80941Smrg        if name == 'genxml':
281b8e80941Smrg            self.gen = None
282b8e80941Smrg        elif name in ('instruction', 'struct', 'register'):
283b8e80941Smrg            self.container = None
284b8e80941Smrg        else:
285b8e80941Smrg            pass
286b8e80941Smrg
287b8e80941Smrg    def start_container(self, attrs):
288b8e80941Smrg        assert self.container is None
289b8e80941Smrg        name = attrs['name']
290b8e80941Smrg        if name not in self.containers:
291b8e80941Smrg            self.containers[name] = Container(name)
292b8e80941Smrg        self.container = self.containers[name]
293b8e80941Smrg        self.container.add_gen(self.gen, attrs)
294b8e80941Smrg
295b8e80941Smrg    def start_field(self, attrs):
296b8e80941Smrg        if self.container is None:
297b8e80941Smrg            return
298b8e80941Smrg
299b8e80941Smrg        field_name = attrs.get('name', None)
300b8e80941Smrg        if not field_name:
301b8e80941Smrg            return
302b8e80941Smrg
303b8e80941Smrg        self.container.get_field(field_name, True).add_gen(self.gen, attrs)
304b8e80941Smrg
305b8e80941Smrgdef parse_args():
306b8e80941Smrg    p = argparse.ArgumentParser()
307b8e80941Smrg    p.add_argument('-o', '--output', type=str,
308b8e80941Smrg                   help="If OUTPUT is unset or '-', then it defaults to '/dev/stdout'")
309b8e80941Smrg    p.add_argument('--cpp-guard', type=str,
310b8e80941Smrg                   help='If unset, then CPP_GUARD is derived from OUTPUT.')
311b8e80941Smrg    p.add_argument('--engines', nargs='?', type=str, default='render',
312b8e80941Smrg                   help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)")
313b8e80941Smrg    p.add_argument('xml_sources', metavar='XML_SOURCE', nargs='+')
314b8e80941Smrg
315b8e80941Smrg    pargs = p.parse_args()
316b8e80941Smrg
317b8e80941Smrg    if pargs.output in (None, '-'):
318b8e80941Smrg        pargs.output = '/dev/stdout'
319b8e80941Smrg
320b8e80941Smrg    if pargs.cpp_guard is None:
321b8e80941Smrg        pargs.cpp_guard = os.path.basename(pargs.output).upper().replace('.', '_')
322b8e80941Smrg
323b8e80941Smrg    return pargs
324b8e80941Smrg
325b8e80941Smrgdef main():
326b8e80941Smrg    pargs = parse_args()
327b8e80941Smrg
328b8e80941Smrg    engines = pargs.engines.split(',')
329b8e80941Smrg    valid_engines = [ 'render', 'blitter', 'video' ]
330b8e80941Smrg    if set(engines) - set(valid_engines):
331b8e80941Smrg        print("Invalid engine specified, valid engines are:\n")
332b8e80941Smrg        for e in valid_engines:
333b8e80941Smrg            print("\t%s" % e)
334b8e80941Smrg        sys.exit(1)
335b8e80941Smrg
336b8e80941Smrg    # Maps name => Container
337b8e80941Smrg    containers = {}
338b8e80941Smrg
339b8e80941Smrg    for source in pargs.xml_sources:
340b8e80941Smrg        p = XmlParser(containers)
341b8e80941Smrg        p.engines = set(engines)
342b8e80941Smrg        p.parse(source)
343b8e80941Smrg
344b8e80941Smrg    with open(pargs.output, 'wb') as f:
345b8e80941Smrg        f.write(TEMPLATE.render(containers=containers, guard=pargs.cpp_guard))
346b8e80941Smrg
347b8e80941Smrgif __name__ == '__main__':
348b8e80941Smrg    main()
349