Home | History | Annotate | Download | only in genxml
      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 
     22 from __future__ import (
     23     absolute_import, division, print_function, unicode_literals
     24 )
     25 
     26 import argparse
     27 import os
     28 import sys
     29 import xml.parsers.expat
     30 
     31 from mako.template import Template
     32 
     33 TEMPLATE = Template("""\
     34 <%!
     35 from 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 
     79 static 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
    108 extern "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 
    133 def 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 
    161 def safe_name(name):
    162     name = to_alphanum(name)
    163     if not name[0].isalpha():
    164         name = '_' + name
    165     return name
    166 
    167 class 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 
    193 class 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 
    235 class 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 
    272 class 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 
    323 def 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 
    341 def 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 
    353 if __name__ == '__main__':
    354     main()
    355