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