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