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