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