gen_bits_header.py revision 9f464c52
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 22from __future__ import ( 23 absolute_import, division, print_function, unicode_literals 24) 25 26import argparse 27import os 28import re 29import xml.parsers.expat 30 31from mako.template import Template 32 33TEMPLATE = Template("""\ 34<%! 35from 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 "dev/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 79static inline uint32_t ATTRIBUTE_PURE 80${item.token_name}_${prop}(const struct gen_device_info *devinfo) 81{ 82 switch (devinfo->gen) { 83 case 11: return ${item.get_prop(prop, 11)}; 84 case 10: return ${item.get_prop(prop, 10)}; 85 case 9: return ${item.get_prop(prop, 9)}; 86 case 8: return ${item.get_prop(prop, 8)}; 87 case 7: 88 if (devinfo->is_haswell) { 89 return ${item.get_prop(prop, 7.5)}; 90 } else { 91 return ${item.get_prop(prop, 7)}; 92 } 93 case 6: return ${item.get_prop(prop, 6)}; 94 case 5: return ${item.get_prop(prop, 5)}; 95 case 4: 96 if (devinfo->is_g4x) { 97 return ${item.get_prop(prop, 4.5)}; 98 } else { 99 return ${item.get_prop(prop, 4)}; 100 } 101 default: 102 unreachable("Invalid hardware generation"); 103 } 104} 105%endif 106</%def> 107 108#ifdef __cplusplus 109extern "C" { 110#endif 111% for _, container in sorted(containers.items(), key=itemgetter(0)): 112 113/* ${container.name} */ 114 115${emit_per_gen_prop_func(container, 'length')} 116 117% for _, field in sorted(container.fields.items(), key=itemgetter(0)): 118 119/* ${container.name}::${field.name} */ 120 121${emit_per_gen_prop_func(field, 'bits')} 122 123${emit_per_gen_prop_func(field, 'start')} 124 125% endfor 126% endfor 127 128#ifdef __cplusplus 129} 130#endif 131 132#endif /* ${guard} */""", output_encoding='utf-8') 133 134alphanum_nono = re.compile(r'[ /\[\]()\-:.,=>#&*"+\\]+') 135def to_alphanum(name): 136 global alphanum_nono 137 return alphanum_nono.sub('', name).replace('α', 'alpha') 138 139def safe_name(name): 140 name = to_alphanum(name) 141 if not name[0].isalpha(): 142 name = '_' + name 143 return name 144 145class Gen(object): 146 147 def __init__(self, z): 148 # Convert potential "major.minor" string 149 self.tenx = int(float(z) * 10) 150 151 def __lt__(self, other): 152 return self.tenx < other.tenx 153 154 def __hash__(self): 155 return hash(self.tenx) 156 157 def __eq__(self, other): 158 return self.tenx == other.tenx 159 160 def prefix(self, token): 161 gen = self.tenx 162 163 if gen % 10 == 0: 164 gen //= 10 165 166 if token[0] == '_': 167 token = token[1:] 168 169 return 'GEN{}_{}'.format(gen, token) 170 171class Container(object): 172 173 def __init__(self, name): 174 self.name = name 175 self.token_name = safe_name(name) 176 self.length_by_gen = {} 177 self.fields = {} 178 179 def add_gen(self, gen, xml_attrs): 180 assert isinstance(gen, Gen) 181 if 'length' in xml_attrs: 182 self.length_by_gen[gen] = xml_attrs['length'] 183 184 def get_field(self, field_name, create=False): 185 if field_name not in self.fields: 186 if create: 187 self.fields[field_name] = Field(self, field_name) 188 else: 189 return None 190 return self.fields[field_name] 191 192 def has_prop(self, prop): 193 if prop == 'length': 194 return bool(self.length_by_gen) 195 else: 196 raise ValueError('Invalid property: "{0}"'.format(prop)) 197 198 def iter_prop(self, prop): 199 if prop == 'length': 200 return self.length_by_gen.items() 201 else: 202 raise ValueError('Invalid property: "{0}"'.format(prop)) 203 204 def get_prop(self, prop, gen): 205 if not isinstance(gen, Gen): 206 gen = Gen(gen) 207 208 if prop == 'length': 209 return self.length_by_gen.get(gen, 0) 210 else: 211 raise ValueError('Invalid property: "{0}"'.format(prop)) 212 213class Field(object): 214 215 def __init__(self, container, name): 216 self.name = name 217 self.token_name = safe_name('_'.join([container.name, self.name])) 218 self.bits_by_gen = {} 219 self.start_by_gen = {} 220 221 def add_gen(self, gen, xml_attrs): 222 assert isinstance(gen, Gen) 223 start = int(xml_attrs['start']) 224 end = int(xml_attrs['end']) 225 self.start_by_gen[gen] = start 226 self.bits_by_gen[gen] = 1 + end - start 227 228 def has_prop(self, prop): 229 return True 230 231 def iter_prop(self, prop): 232 if prop == 'bits': 233 return self.bits_by_gen.items() 234 elif prop == 'start': 235 return self.start_by_gen.items() 236 else: 237 raise ValueError('Invalid property: "{0}"'.format(prop)) 238 239 def get_prop(self, prop, gen): 240 if not isinstance(gen, Gen): 241 gen = Gen(gen) 242 243 if prop == 'bits': 244 return self.bits_by_gen.get(gen, 0) 245 elif prop == 'start': 246 return self.start_by_gen.get(gen, 0) 247 else: 248 raise ValueError('Invalid property: "{0}"'.format(prop)) 249 250class XmlParser(object): 251 252 def __init__(self, containers): 253 self.parser = xml.parsers.expat.ParserCreate() 254 self.parser.StartElementHandler = self.start_element 255 self.parser.EndElementHandler = self.end_element 256 257 self.gen = None 258 self.containers = containers 259 self.container = None 260 261 def parse(self, filename): 262 with open(filename, 'rb') as f: 263 self.parser.ParseFile(f) 264 265 def start_element(self, name, attrs): 266 if name == 'genxml': 267 self.gen = Gen(attrs['gen']) 268 elif name in ('instruction', 'struct', 'register'): 269 if name == 'instruction' and 'engine' in attrs: 270 engines = set(attrs['engine'].split('|')) 271 if not engines & self.engines: 272 return 273 self.start_container(attrs) 274 elif name == 'field': 275 self.start_field(attrs) 276 else: 277 pass 278 279 def end_element(self, name): 280 if name == 'genxml': 281 self.gen = None 282 elif name in ('instruction', 'struct', 'register'): 283 self.container = None 284 else: 285 pass 286 287 def start_container(self, attrs): 288 assert self.container is None 289 name = attrs['name'] 290 if name not in self.containers: 291 self.containers[name] = Container(name) 292 self.container = self.containers[name] 293 self.container.add_gen(self.gen, attrs) 294 295 def start_field(self, attrs): 296 if self.container is None: 297 return 298 299 field_name = attrs.get('name', None) 300 if not field_name: 301 return 302 303 self.container.get_field(field_name, True).add_gen(self.gen, attrs) 304 305def parse_args(): 306 p = argparse.ArgumentParser() 307 p.add_argument('-o', '--output', type=str, 308 help="If OUTPUT is unset or '-', then it defaults to '/dev/stdout'") 309 p.add_argument('--cpp-guard', type=str, 310 help='If unset, then CPP_GUARD is derived from OUTPUT.') 311 p.add_argument('--engines', nargs='?', type=str, default='render', 312 help="Comma-separated list of engines whose instructions should be parsed (default: %(default)s)") 313 p.add_argument('xml_sources', metavar='XML_SOURCE', nargs='+') 314 315 pargs = p.parse_args() 316 317 if pargs.output in (None, '-'): 318 pargs.output = '/dev/stdout' 319 320 if pargs.cpp_guard is None: 321 pargs.cpp_guard = os.path.basename(pargs.output).upper().replace('.', '_') 322 323 return pargs 324 325def main(): 326 pargs = parse_args() 327 328 engines = pargs.engines.split(',') 329 valid_engines = [ 'render', 'blitter', 'video' ] 330 if set(engines) - set(valid_engines): 331 print("Invalid engine specified, valid engines are:\n") 332 for e in valid_engines: 333 print("\t%s" % e) 334 sys.exit(1) 335 336 # Maps name => Container 337 containers = {} 338 339 for source in pargs.xml_sources: 340 p = XmlParser(containers) 341 p.engines = set(engines) 342 p.parse(source) 343 344 with open(pargs.output, 'wb') as f: 345 f.write(TEMPLATE.render(containers=containers, guard=pargs.cpp_guard)) 346 347if __name__ == '__main__': 348 main() 349