Home | History | Annotate | Download | only in cle
      1 #encoding=utf-8
      2 
      3 # Copyright (C) 2016 Intel Corporation
      4 # Copyright (C) 2016 Broadcom
      5 #
      6 # Permission is hereby granted, free of charge, to any person obtaining a
      7 # copy of this software and associated documentation files (the "Software"),
      8 # to deal in the Software without restriction, including without limitation
      9 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10 # and/or sell copies of the Software, and to permit persons to whom the
     11 # Software is furnished to do so, subject to the following conditions:
     12 #
     13 # The above copyright notice and this permission notice (including the next
     14 # paragraph) shall be included in all copies or substantial portions of the
     15 # Software.
     16 #
     17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     23 # IN THE SOFTWARE.
     24 
     25 from __future__ import (
     26     absolute_import, division, print_function, unicode_literals
     27 )
     28 import xml.parsers.expat
     29 import re
     30 import sys
     31 import copy
     32 
     33 license =  """/* Generated code, see packets.xml and gen_packet_header.py */
     34 """
     35 
     36 pack_header = """%(license)s
     37 
     38 /* Packets, enums and structures for %(platform)s.
     39  *
     40  * This file has been generated, do not hand edit.
     41  */
     42 
     43 #ifndef %(guard)s
     44 #define %(guard)s
     45 
     46 #include "v3d_packet_helpers.h"
     47 
     48 """
     49 
     50 def to_alphanum(name):
     51     substitutions = {
     52         ' ': '_',
     53         '/': '_',
     54         '[': '',
     55         ']': '',
     56         '(': '',
     57         ')': '',
     58         '-': '_',
     59         ':': '',
     60         '.': '',
     61         ',': '',
     62         '=': '',
     63         '>': '',
     64         '#': '',
     65         '': 'alpha',
     66         '&': '',
     67         '*': '',
     68         '"': '',
     69         '+': '',
     70         '\'': '',
     71     }
     72 
     73     for i, j in substitutions.items():
     74         name = name.replace(i, j)
     75 
     76     return name
     77 
     78 def safe_name(name):
     79     name = to_alphanum(name)
     80     if not name[0].isalpha():
     81         name = '_' + name
     82 
     83     return name
     84 
     85 def prefixed_upper_name(prefix, name):
     86     if prefix:
     87         name = prefix + "_" + name
     88     return safe_name(name).upper()
     89 
     90 def num_from_str(num_str):
     91     if num_str.lower().startswith('0x'):
     92         return int(num_str, base=16)
     93     else:
     94         assert(not num_str.startswith('0') and 'octals numbers not allowed')
     95         return int(num_str)
     96 
     97 class Field(object):
     98     ufixed_pattern = re.compile(r"u(\d+)\.(\d+)")
     99     sfixed_pattern = re.compile(r"s(\d+)\.(\d+)")
    100 
    101     def __init__(self, parser, attrs):
    102         self.parser = parser
    103         if "name" in attrs:
    104             self.name = safe_name(attrs["name"]).lower()
    105 
    106         if str(attrs["start"]).endswith("b"):
    107             self.start = int(attrs["start"][:-1]) * 8
    108         else:
    109             self.start = int(attrs["start"])
    110         # packet <field> entries in XML start from the bit after the
    111         # opcode, so shift everything up by 8 since we'll also have a
    112         # Field for the opcode.
    113         if not parser.struct:
    114             self.start += 8
    115 
    116         self.end = self.start + int(attrs["size"]) - 1
    117         self.type = attrs["type"]
    118 
    119         if self.type == 'bool' and self.start != self.end:
    120             print("#error Field {} has bool type but more than one bit of size".format(self.name));
    121 
    122         if "prefix" in attrs:
    123             self.prefix = safe_name(attrs["prefix"]).upper()
    124         else:
    125             self.prefix = None
    126 
    127         if "default" in attrs:
    128             self.default = int(attrs["default"])
    129         else:
    130             self.default = None
    131 
    132         ufixed_match = Field.ufixed_pattern.match(self.type)
    133         if ufixed_match:
    134             self.type = 'ufixed'
    135             self.fractional_size = int(ufixed_match.group(2))
    136 
    137         sfixed_match = Field.sfixed_pattern.match(self.type)
    138         if sfixed_match:
    139             self.type = 'sfixed'
    140             self.fractional_size = int(sfixed_match.group(2))
    141 
    142     def emit_template_struct(self, dim):
    143         if self.type == 'address':
    144             type = '__gen_address_type'
    145         elif self.type == 'bool':
    146             type = 'bool'
    147         elif self.type == 'float':
    148             type = 'float'
    149         elif self.type == 'ufixed':
    150             type = 'float'
    151         elif self.type == 'sfixed':
    152             type = 'float'
    153         elif self.type == 'uint' and self.end - self.start > 32:
    154             type = 'uint64_t'
    155         elif self.type == 'offset':
    156             type = 'uint64_t'
    157         elif self.type == 'int':
    158             type = 'int32_t'
    159         elif self.type == 'uint':
    160             type = 'uint32_t'
    161         elif self.type in self.parser.structs:
    162             type = 'struct ' + self.parser.gen_prefix(safe_name(self.type))
    163         elif self.type in self.parser.enums:
    164             type = 'enum ' + self.parser.gen_prefix(safe_name(self.type))
    165         elif self.type == 'mbo':
    166             return
    167         else:
    168             print("#error unhandled type: %s" % self.type)
    169             type = "uint32_t"
    170 
    171         print("   %-36s %s%s;" % (type, self.name, dim))
    172 
    173         for value in self.values:
    174             name = prefixed_upper_name(self.prefix, value.name)
    175             print("#define %-40s %d" % (name, value.value))
    176 
    177     def overlaps(self, field):
    178         return self != field and max(self.start, field.start) <= min(self.end, field.end)
    179 
    180 
    181 class Group(object):
    182     def __init__(self, parser, parent, start, count):
    183         self.parser = parser
    184         self.parent = parent
    185         self.start = start
    186         self.count = count
    187         self.size = 0
    188         self.fields = []
    189 
    190     def emit_template_struct(self, dim):
    191         if self.count == 0:
    192             print("   /* variable length fields follow */")
    193         else:
    194             if self.count > 1:
    195                 dim = "%s[%d]" % (dim, self.count)
    196 
    197             for field in self.fields:
    198                 field.emit_template_struct(dim)
    199 
    200     class Byte:
    201         def __init__(self):
    202             self.size = 8
    203             self.fields = []
    204             self.address = None
    205 
    206     def collect_bytes(self, bytes):
    207         for field in self.fields:
    208             first_byte = field.start // 8
    209             last_byte = field.end // 8
    210 
    211             for b in xrange(first_byte, last_byte + 1):
    212                 if not b in bytes:
    213                     bytes[b] = self.Byte()
    214 
    215                 bytes[b].fields.append(field)
    216 
    217                 if field.type == "address":
    218                     # assert bytes[index].address == None
    219                     bytes[b].address = field
    220 
    221     def emit_pack_function(self, start):
    222         # Determine number of bytes in this group.
    223         self.length = max(field.end // 8 for field in self.fields) + 1
    224 
    225         bytes = {}
    226         self.collect_bytes(bytes)
    227 
    228         relocs_emitted = set()
    229         memcpy_fields = set()
    230 
    231         for index in range(self.length):
    232             # Handle MBZ bytes
    233             if not index in bytes:
    234                 print("   cl[%2d] = 0;" % index)
    235                 continue
    236             byte = bytes[index]
    237 
    238             # Call out to the driver to note our relocations.  Inside of the
    239             # packet we only store offsets within the BOs, and we store the
    240             # handle to the packet outside.  Unlike Intel genxml, we don't
    241             # need to have the other bits that will be stored together with
    242             # the address during the reloc process, so there's no need for the
    243             # complicated combine_address() function.
    244             if byte.address and byte.address not in relocs_emitted:
    245                 print("   __gen_emit_reloc(data, &values->%s);" % byte.address.name)
    246                 relocs_emitted.add(byte.address)
    247 
    248             # Special case: floats can't have any other fields packed into
    249             # them (since they'd change the meaning of the float), and the
    250             # per-byte bitshifting math below bloats the pack code for floats,
    251             # so just copy them directly here.  Also handle 16/32-bit
    252             # uints/ints with no merged fields.
    253             if len(byte.fields) == 1:
    254                 field = byte.fields[0]
    255                 if field.type in ["float", "uint", "int"] and field.start % 8 == 0 and field.end - field.start == 31:
    256                     if field in memcpy_fields:
    257                         continue
    258 
    259                     if not any(field.overlaps(scan_field) for scan_field in self.fields):
    260                         assert(field.start == index * 8)
    261                         print("")
    262                         print("   memcpy(&cl[%d], &values->%s, sizeof(values->%s));" %
    263                                 (index, field.name, field.name))
    264                         memcpy_fields.add(field)
    265                         continue
    266 
    267             byte_start = index * 8
    268 
    269             v = None
    270             prefix = "   cl[%2d] =" % index
    271 
    272             field_index = 0
    273             for field in byte.fields:
    274                 if field.type != "mbo":
    275                     name = field.name
    276 
    277                 start = field.start
    278                 end = field.end
    279                 field_byte_start = (field.start // 8) * 8
    280                 start -= field_byte_start
    281                 end -= field_byte_start
    282                 extra_shift = 0
    283 
    284                 if field.type == "mbo":
    285                     s = "__gen_mbo(%d, %d)" % \
    286                         (start, end)
    287                 elif field.type == "address":
    288                     extra_shift = (31 - (end - start)) // 8 * 8
    289                     s = "__gen_address_offset(&values->%s)" % byte.address.name
    290                 elif field.type == "uint":
    291                     s = "__gen_uint(values->%s, %d, %d)" % \
    292                         (name, start, end)
    293                 elif field.type in self.parser.enums:
    294                     s = "__gen_uint(values->%s, %d, %d)" % \
    295                         (name, start, end)
    296                 elif field.type == "int":
    297                     s = "__gen_sint(values->%s, %d, %d)" % \
    298                         (name, start, end)
    299                 elif field.type == "bool":
    300                     s = "__gen_uint(values->%s, %d, %d)" % \
    301                         (name, start, end)
    302                 elif field.type == "float":
    303                     s = "#error %s float value mixed in with other fields" % name
    304                 elif field.type == "offset":
    305                     s = "__gen_offset(values->%s, %d, %d)" % \
    306                         (name, start, end)
    307                 elif field.type == 'ufixed':
    308                     s = "__gen_ufixed(values->%s, %d, %d, %d)" % \
    309                         (name, start, end, field.fractional_size)
    310                 elif field.type == 'sfixed':
    311                     s = "__gen_sfixed(values->%s, %d, %d, %d)" % \
    312                         (name, start, end, field.fractional_size)
    313                 elif field.type in self.parser.structs:
    314                     s = "__gen_uint(v%d_%d, %d, %d)" % \
    315                         (index, field_index, start, end)
    316                     field_index = field_index + 1
    317                 else:
    318                     print("/* unhandled field %s, type %s */\n" % (name, field.type))
    319                     s = None
    320 
    321                 if not s == None:
    322                     shift = byte_start - field_byte_start + extra_shift
    323                     if shift:
    324                         s = "%s >> %d" % (s, shift)
    325 
    326                     if field == byte.fields[-1]:
    327                         print("%s %s;" % (prefix, s))
    328                     else:
    329                         print("%s %s |" % (prefix, s))
    330                     prefix = "           "
    331 
    332             print("")
    333             continue
    334 
    335     def emit_unpack_function(self, start):
    336         for field in self.fields:
    337             if field.type != "mbo":
    338                 convert = None
    339 
    340                 args = []
    341                 args.append('cl')
    342                 args.append(str(start + field.start))
    343                 args.append(str(start + field.end))
    344 
    345                 if field.type == "address":
    346                     convert = "__gen_unpack_address"
    347                 elif field.type == "uint":
    348                     convert = "__gen_unpack_uint"
    349                 elif field.type in self.parser.enums:
    350                     convert = "__gen_unpack_uint"
    351                 elif field.type == "int":
    352                     convert = "__gen_unpack_sint"
    353                 elif field.type == "bool":
    354                     convert = "__gen_unpack_uint"
    355                 elif field.type == "float":
    356                     convert = "__gen_unpack_float"
    357                 elif field.type == "offset":
    358                     convert = "__gen_unpack_offset"
    359                 elif field.type == 'ufixed':
    360                     args.append(str(field.fractional_size))
    361                     convert = "__gen_unpack_ufixed"
    362                 elif field.type == 'sfixed':
    363                     args.append(str(field.fractional_size))
    364                     convert = "__gen_unpack_sfixed"
    365                 else:
    366                     print("/* unhandled field %s, type %s */\n" % (field.name, field.type))
    367                     s = None
    368 
    369                 print("   values->%s = %s(%s);" % \
    370                       (field.name, convert, ', '.join(args)))
    371 
    372 class Value(object):
    373     def __init__(self, attrs):
    374         self.name = attrs["name"]
    375         self.value = int(attrs["value"])
    376 
    377 class Parser(object):
    378     def __init__(self):
    379         self.parser = xml.parsers.expat.ParserCreate()
    380         self.parser.StartElementHandler = self.start_element
    381         self.parser.EndElementHandler = self.end_element
    382 
    383         self.packet = None
    384         self.struct = None
    385         self.structs = {}
    386         # Set of enum names we've seen.
    387         self.enums = set()
    388         self.registers = {}
    389 
    390     def gen_prefix(self, name):
    391         if name[0] == "_":
    392             return 'V3D%s%s' % (self.ver, name)
    393         else:
    394             return 'V3D%s_%s' % (self.ver, name)
    395 
    396     def gen_guard(self):
    397         return self.gen_prefix("PACK_H")
    398 
    399     def start_element(self, name, attrs):
    400         if name == "vcxml":
    401             self.platform = "V3D {}".format(attrs["gen"])
    402             self.ver = attrs["gen"].replace('.', '')
    403             print(pack_header % {'license': license, 'platform': self.platform, 'guard': self.gen_guard()})
    404         elif name in ("packet", "struct", "register"):
    405             default_field = None
    406 
    407             object_name = self.gen_prefix(safe_name(attrs["name"].upper()))
    408             if name == "packet":
    409                 self.packet = object_name
    410 
    411                 # Add a fixed Field for the opcode.  We only make <field>s in
    412                 # the XML for the fields listed in the spec, and all of those
    413                 # start from bit 0 after of the opcode.
    414                 default_field = {
    415                     "name" : "opcode",
    416                     "default" : attrs["code"],
    417                     "type" : "uint",
    418                     "start" : -8,
    419                     "size" : 8,
    420                 }
    421             elif name == "struct":
    422                 self.struct = object_name
    423                 self.structs[attrs["name"]] = 1
    424             elif name == "register":
    425                 self.register = object_name
    426                 self.reg_num = num_from_str(attrs["num"])
    427                 self.registers[attrs["name"]] = 1
    428 
    429             self.group = Group(self, None, 0, 1)
    430             if default_field:
    431                 field = Field(self, default_field)
    432                 field.values = []
    433                 self.group.fields.append(field)
    434 
    435         elif name == "field":
    436             self.group.fields.append(Field(self, attrs))
    437             self.values = []
    438         elif name == "enum":
    439             self.values = []
    440             self.enum = safe_name(attrs["name"])
    441             self.enums.add(attrs["name"])
    442             if "prefix" in attrs:
    443                 self.prefix = attrs["prefix"]
    444             else:
    445                 self.prefix= None
    446         elif name == "value":
    447             self.values.append(Value(attrs))
    448 
    449     def end_element(self, name):
    450         if name  == "packet":
    451             self.emit_packet()
    452             self.packet = None
    453             self.group = None
    454         elif name == "struct":
    455             self.emit_struct()
    456             self.struct = None
    457             self.group = None
    458         elif name == "register":
    459             self.emit_register()
    460             self.register = None
    461             self.reg_num = None
    462             self.group = None
    463         elif name  == "field":
    464             self.group.fields[-1].values = self.values
    465         elif name  == "enum":
    466             self.emit_enum()
    467             self.enum = None
    468         elif name == "vcxml":
    469             print('#endif /* %s */' % self.gen_guard())
    470 
    471     def emit_template_struct(self, name, group):
    472         print("struct %s {" % name)
    473         group.emit_template_struct("")
    474         print("};\n")
    475 
    476     def emit_pack_function(self, name, group):
    477         print("static inline void\n%s_pack(__gen_user_data *data, uint8_t * restrict cl,\n%sconst struct %s * restrict values)\n{" %
    478               (name, ' ' * (len(name) + 6), name))
    479 
    480         group.emit_pack_function(0)
    481 
    482         print("}\n")
    483 
    484         print('#define %-33s %6d' %
    485               (name + "_length", self.group.length))
    486 
    487     def emit_unpack_function(self, name, group):
    488         print("#ifdef __gen_unpack_address")
    489         print("static inline void")
    490         print("%s_unpack(const uint8_t * restrict cl,\n%sstruct %s * restrict values)\n{" %
    491               (name, ' ' * (len(name) + 8), name))
    492 
    493         group.emit_unpack_function(0)
    494 
    495         print("}\n#endif\n")
    496 
    497     def emit_header(self, name):
    498         default_fields = []
    499         for field in self.group.fields:
    500             if not type(field) is Field:
    501                 continue
    502             if field.default == None:
    503                 continue
    504             default_fields.append("   .%-35s = %6d" % (field.name, field.default))
    505 
    506         print('#define %-40s\\' % (name + '_header'))
    507         print(",  \\\n".join(default_fields))
    508         print('')
    509 
    510     def emit_packet(self):
    511         name = self.packet
    512 
    513         assert(self.group.fields[0].name == "opcode")
    514         print('#define %-33s %6d' %
    515               (name + "_opcode", self.group.fields[0].default))
    516 
    517         self.emit_header(name)
    518         self.emit_template_struct(self.packet, self.group)
    519         self.emit_pack_function(self.packet, self.group)
    520         self.emit_unpack_function(self.packet, self.group)
    521 
    522         print('')
    523 
    524     def emit_register(self):
    525         name = self.register
    526         if not self.reg_num == None:
    527             print('#define %-33s 0x%04x' %
    528                   (self.gen_prefix(name + "_num"), self.reg_num))
    529 
    530         self.emit_template_struct(self.register, self.group)
    531         self.emit_pack_function(self.register, self.group)
    532         self.emit_unpack_function(self.register, self.group)
    533 
    534     def emit_struct(self):
    535         name = self.struct
    536 
    537         self.emit_header(name)
    538         self.emit_template_struct(self.struct, self.group)
    539         self.emit_pack_function(self.struct, self.group)
    540         self.emit_unpack_function(self.struct, self.group)
    541 
    542         print('')
    543 
    544     def emit_enum(self):
    545         print('enum %s {' % self.gen_prefix(self.enum))
    546         for value in self.values:
    547             name = value.name
    548             if self.prefix:
    549                 name = self.prefix + "_" + name
    550             name = safe_name(name).upper()
    551             print('        % -36s = %6d,' % (name, value.value))
    552         print('};\n')
    553 
    554     def parse(self, filename):
    555         file = open(filename, "rb")
    556         self.parser.ParseFile(file)
    557         file.close()
    558 
    559 if len(sys.argv) < 2:
    560     print("No input xml file specified")
    561     sys.exit(1)
    562 
    563 input_file = sys.argv[1]
    564 
    565 p = Parser()
    566 p.parse(input_file)
    567