genxml: New generated header genX_bits.h (v6)
[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 #ifdef __cplusplus
74 extern "C" {
75 #endif
76 % for _, field in sorted(fields.iteritems(), key=itemgetter(0)):
77
78 /* ${field.container_name}::${field.name} */
79 % for gen, bits in sorted(field.bits_by_gen.iteritems(), reverse=True):
80 #define ${gen.prefix(field.token_name, padded=True)} ${bits}
81 % endfor
82
83 static inline uint32_t ATTRIBUTE_PURE
84 ${field.token_name}(const struct gen_device_info *devinfo)
85 {
86 switch (devinfo->gen) {
87 case 9: return ${field.bits(9)};
88 case 8: return ${field.bits(8)};
89 case 7:
90 if (devinfo->is_haswell) {
91 return ${field.bits(7.5)};
92 } else {
93 return ${field.bits(7)};
94 }
95 case 6: return ${field.bits(6)};
96 case 5: return ${field.bits(5)};
97 case 4:
98 if (devinfo->is_g4x) {
99 return ${field.bits(4.5)};
100 } else {
101 return ${field.bits(4)};
102 }
103 default:
104 unreachable("Invalid hardware generation");
105 }
106 }
107 % endfor
108
109 #ifdef __cplusplus
110 }
111 #endif
112
113 #endif /* ${guard} */""", output_encoding='utf-8')
114
115 def to_alphanum(name):
116 substitutions = {
117 ' ': '',
118 '/': '',
119 '[': '',
120 ']': '',
121 '(': '',
122 ')': '',
123 '-': '',
124 ':': '',
125 '.': '',
126 ',': '',
127 '=': '',
128 '>': '',
129 '#': '',
130 'α': 'alpha',
131 '&': '',
132 '*': '',
133 '"': '',
134 '+': '',
135 '\'': '',
136 }
137
138 for i, j in substitutions.items():
139 name = name.replace(i, j)
140
141 return name
142
143 def safe_name(name):
144 name = to_alphanum(name)
145 if not name[0].isalpha():
146 name = '_' + name
147 return name
148
149 class Gen(object):
150
151 def __init__(self, z):
152 # Convert potential "major.minor" string
153 z = float(z)
154 if z < 10:
155 z *= 10
156 self.tenx = int(z)
157
158 def __lt__(self, other):
159 return self.tenx < other.tenx
160
161 def __hash__(self):
162 return hash(self.tenx)
163
164 def __eq__(self, other):
165 return self.tenx == other.tenx
166
167 def prefix(self, token, padded=False):
168 gen = self.tenx
169 pad = ''
170
171 if gen % 10 == 0:
172 gen //= 10
173 if padded:
174 pad = ' '
175
176 if token[0] == '_':
177 token = token[1:]
178
179 return 'GEN{}_{}{}'.format(gen, token, pad)
180
181 class Field(object):
182
183 def __init__(self, container_name, name):
184 self.container_name = container_name
185 self.name = name
186 self.token_name = safe_name('_'.join([self.container_name, self.name, 'bits']))
187 self.bits_by_gen = {}
188
189 def add_gen(self, gen, xml_attrs):
190 assert isinstance(gen, Gen)
191 start = int(xml_attrs['start'])
192 end = int(xml_attrs['end'])
193 self.bits_by_gen[gen] = 1 + end - start
194
195 def bits(self, gen):
196 if not isinstance(gen, Gen):
197 gen = Gen(gen)
198 return self.bits_by_gen.get(gen, 0)
199
200 class XmlParser(object):
201
202 def __init__(self, fields):
203 self.parser = xml.parsers.expat.ParserCreate()
204 self.parser.StartElementHandler = self.start_element
205 self.parser.EndElementHandler = self.end_element
206
207 self.gen = None
208 self.container_name = None
209 self.fields = fields
210
211 def parse(self, filename):
212 with open(filename) as f:
213 self.parser.ParseFile(f)
214
215 def start_element(self, name, attrs):
216 if name == 'genxml':
217 self.gen = Gen(attrs['gen'])
218 elif name in ('instruction', 'struct', 'register'):
219 self.start_container(attrs)
220 elif name == 'field':
221 self.start_field(attrs)
222 else:
223 pass
224
225 def end_element(self, name):
226 if name == 'genxml':
227 self.gen = None
228 elif name in ('instruction', 'struct', 'register'):
229 self.container_name = None
230 else:
231 pass
232
233 def start_container(self, attrs):
234 assert self.container_name is None
235 self.container_name = attrs['name']
236
237 def start_field(self, attrs):
238 if self.container_name is None:
239 return
240
241 field_name = attrs.get('name', None)
242 if not field_name:
243 return
244
245 key = (self.container_name, field_name)
246 if key not in self.fields:
247 self.fields[key] = Field(self.container_name, field_name)
248 self.fields[key].add_gen(self.gen, attrs)
249
250 def parse_args():
251 p = argparse.ArgumentParser()
252 p.add_argument('-o', '--output', type=str,
253 help="If OUTPUT is unset or '-', then it defaults to '/dev/stdout'")
254 p.add_argument('--cpp-guard', type=str,
255 help='If unset, then CPP_GUARD is derived from OUTPUT.')
256 p.add_argument('xml_sources', metavar='XML_SOURCE', nargs='+')
257
258 pargs = p.parse_args()
259
260 if pargs.output in (None, '-'):
261 pargs.output = '/dev/stdout'
262
263 if pargs.cpp_guard is None:
264 pargs.cpp_guard = os.path.basename(pargs.output).upper().replace('.', '_')
265
266 return pargs
267
268 def main():
269 pargs = parse_args()
270
271 # Maps (container_name, field_name) => Field
272 fields = {}
273
274 for source in pargs.xml_sources:
275 XmlParser(fields).parse(source)
276
277 with open(pargs.output, 'wb') as f:
278 f.write(TEMPLATE.render(fields=fields, guard=pargs.cpp_guard))
279
280 if __name__ == '__main__':
281 main()