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 sys 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 "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 79static inline uint32_t ATTRIBUTE_PURE 80${item.token_name}_${prop}(const struct gen_device_info *devinfo) 81{ 82 switch (devinfo->gen) { 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 108extern "C" { 109#endif 110% for _, container in sorted(containers.iteritems(), key=itemgetter(0)): 111 112/* ${container.name} */ 113 114${emit_per_gen_prop_func(container, 'length')} 115 116% for _, field in sorted(container.fields.iteritems(), 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 133def 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 161def safe_name(name): 162 name = to_alphanum(name) 163 if not name[0].isalpha(): 164 name = '_' + name 165 return name 166 167class 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 193class 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.iteritems() 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 235class 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.iteritems() 256 elif prop == 'start': 257 return self.start_by_gen.iteritems() 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 272class 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) 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 323def 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 341def 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 353if __name__ == '__main__': 354 main() 355