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