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