Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / amd / common / sid_tables.py
index 01970caa7be913354931e2dc1e7afba89dc6128f..a0cb5b2d8327455a4fad40890456f23289ee1705 100644 (file)
@@ -1,7 +1,8 @@
+from __future__ import print_function, division, unicode_literals
 
 CopyRight = '''
 /*
- * Copyright 2015 Advanced Micro Devices, Inc.
+ * Copyright 2015-2019 Advanced Micro Devices, Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -25,8 +26,18 @@ CopyRight = '''
  */
 '''
 
-import sys
+from collections import defaultdict
+import functools
+import itertools
+import json
+import os.path
 import re
+import sys
+
+AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers"))
+sys.path.append(AMD_REGISTERS)
+
+from regdb import Object, RegisterDatabase
 
 
 class StringTable:
@@ -60,8 +71,8 @@ class StringTable:
         """
         fragments = [
             '"%s\\0" /* %s */' % (
-                te[0].encode('string_escape'),
-                ', '.join(str(idx) for idx in te[2])
+                te[0].encode('unicode_escape').decode(),
+                ', '.join(str(idx) for idx in sorted(te[2]))
             )
             for te in self.table
         ]
@@ -127,99 +138,121 @@ class IntTable:
         ))
 
 class Field:
-    def __init__(self, reg, s_name):
-        self.s_name = s_name
-        self.name = strip_prefix(s_name)
-        self.values = []
-
-class Reg:
-    def __init__(self, r_name):
-        self.r_name = r_name
-        self.name = strip_prefix(r_name)
-        self.fields = []
-        self.own_fields = True
-
-
-def strip_prefix(s):
-    '''Strip prefix in the form ._.*_, e.g. R_001234_'''
-    return s[s[2:].find('_')+3:]
+    def __init__(self, name, bits):
+        self.name = name
+        self.bits = bits   # [first, last]
+        self.values = []   # [(name, value), ...]
+
+    def format(self, string_table, idx_table):
+        mask = ((1 << (self.bits[1] - self.bits[0] + 1)) - 1) << self.bits[0]
+        if len(self.values):
+            values_offsets = []
+            for value in self.values:
+                while value[1] >= len(values_offsets):
+                    values_offsets.append(-1)
+                values_offsets[value[1]] = string_table.add(value[0])
+            return '{{{0}, 0x{mask:X}, {1}, {2}}}'.format(
+                string_table.add(self.name),
+                len(values_offsets), idx_table.add(values_offsets),
+                **locals()
+            )
+        else:
+            return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals())
 
-def parse(filename, regs, packets):
-    stream = open(filename)
+    def __eq__(self, other):
+        return (self.name == other.name and
+                self.bits[0] == other.bits[0] and self.bits[1] == other.bits[1] and
+                len(self.values) == len(other.values) and
+                all(a[0] == b[0] and a[1] == b[1] for a, b, in zip(self.values, other.values)))
 
-    for line in stream:
-        if not line.startswith('#define '):
-            continue
+    def __ne__(self, other):
+        return not (self == other)
 
-        line = line[8:].strip()
 
-        if line.startswith('R_'):
-            name = line.split()[0]
+class FieldTable:
+    """
+    A class for collecting multiple arrays of register fields in a single big
+    array that is used by indexing (to avoid relocations in the resulting binary)
+    """
+    def __init__(self):
+        self.table = []
+        self.idxs = set()
+        self.name_to_idx = defaultdict(lambda: [])
 
-            for it in regs:
-                if it.r_name == name:
-                    reg = it
+    def add(self, array):
+        """
+        Add an array of Field objects, and return the index of where to find
+        the array in the table.
+        """
+        # Check if we can find the array in the table already
+        for base_idx in self.name_to_idx.get(array[0].name, []):
+            if base_idx + len(array) > len(self.table):
+                continue
+
+            for i, a in enumerate(array):
+                b = self.table[base_idx + i]
+                if a != b:
                     break
             else:
-                reg = Reg(name)
-                regs.append(reg)
+                return base_idx
 
-        elif line.startswith('S_'):
-            name = line[:line.find('(')]
+        base_idx = len(self.table)
+        self.idxs.add(base_idx)
 
-            for it in reg.fields:
-                if it.s_name == name:
-                    field = it
-                    break
-            else:
-                field = Field(reg, name)
-                reg.fields.append(field)
+        for field in array:
+            self.name_to_idx[field.name].append(len(self.table))
+            self.table.append(field)
 
-        elif line.startswith('V_'):
-            split = line.split()
-            name = split[0]
-            value = int(split[1], 0)
+        return base_idx
 
-            for (n,v) in field.values:
-                if n == name:
-                    if v != value:
-                        sys.exit('Value mismatch: name = ' + name)
+    def emit(self, filp, string_table, idx_table):
+        """
+        Write
+        static const struct si_field sid_fields_table[] = { ... };
+        to filp.
+        """
+        idxs = sorted(self.idxs) + [len(self.table)]
 
-            field.values.append((name, value))
+        filp.write('static const struct si_field sid_fields_table[] = {\n')
 
-        elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
-            packets.append(line.split()[0])
+        for start, end in zip(idxs, idxs[1:]):
+            filp.write('\t/* %s */\n' % (start))
+            for field in self.table[start:end]:
+                filp.write('\t%s,\n' % (field.format(string_table, idx_table)))
 
-    # Copy fields to indexed registers which have their fields only defined
-    # at register index 0.
-    # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0.
-    match_number = re.compile('[0-9]+')
-    reg_dict = dict()
+        filp.write('};\n')
 
-    # Create a dict of registers with fields and '0' in their name
-    for reg in regs:
-        if len(reg.fields) and reg.name.find('0') != -1:
-            reg_dict[reg.name] = reg
 
-    # Assign fields
-    for reg in regs:
-        if not len(reg.fields):
-            reg0 = reg_dict.get(match_number.sub('0', reg.name))
-            if reg0 != None:
-                reg.fields = reg0.fields
-                reg.fields_owner = reg0
-                reg.own_fields = False
+def parse_packet3(filp):
+    """
+    Parse PKT3 commands from the given header file.
+    """
+    packets = []
+    for line in filp:
+        if not line.startswith('#define '):
+            continue
 
+        line = line[8:].strip()
 
-def write_tables(regs, packets):
+        if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
+            packets.append(line.split()[0])
+    return packets
 
-    strings = StringTable()
-    strings_offsets = IntTable("int")
 
-    print '/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */'
-    print
-    print CopyRight.strip()
-    print '''
+class TableWriter(object):
+    def __init__(self):
+        self.__strings = StringTable()
+        self.__strings_offsets = IntTable('int')
+        self.__fields = FieldTable()
+
+    def write(self, regdb, packets, file=sys.stdout):
+        def out(*args):
+            print(*args, file=file)
+
+        out('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */')
+        out()
+        out(CopyRight.strip())
+        out('''
 #ifndef SID_TABLES_H
 #define SID_TABLES_H
 
@@ -241,67 +274,95 @@ struct si_packet3 {
         unsigned name_offset;
         unsigned op;
 };
-'''
-
-    print 'static const struct si_packet3 packet3_table[] = {'
-    for pkt in packets:
-        print '\t{%s, %s},' % (strings.add(pkt[5:]), pkt)
-    print '};'
-    print
-
-    print 'static const struct si_field sid_fields_table[] = {'
-
-    fields_idx = 0
-    for reg in regs:
-        if len(reg.fields) and reg.own_fields:
-            print '\t/* %s */' % (fields_idx)
-
-            reg.fields_idx = fields_idx
-
-            for field in reg.fields:
-                if len(field.values):
-                    values_offsets = []
-                    for value in field.values:
-                        while value[1] >= len(values_offsets):
-                            values_offsets.append(-1)
-                        values_offsets[value[1]] = strings.add(strip_prefix(value[0]))
-                    print '\t{%s, %s(~0u), %s, %s},' % (
-                        strings.add(field.name), field.s_name,
-                        len(values_offsets), strings_offsets.add(values_offsets))
+''')
+
+        out('static const struct si_packet3 packet3_table[] = {')
+        for pkt in packets:
+            out('\t{%s, %s},' % (self.__strings.add(pkt[5:]), pkt))
+        out('};')
+        out()
+
+        regmaps_by_chip = defaultdict(list)
+
+        for regmap in regdb.register_mappings():
+            for chip in regmap.chips:
+                regmaps_by_chip[chip].append(regmap)
+
+        regtypes = {}
+
+        # Sorted iteration over chips for deterministic builds
+        for chip in sorted(regmaps_by_chip.keys()):
+            regmaps = regmaps_by_chip[chip]
+            regmaps.sort(key=lambda regmap: (regmap.map.to, regmap.map.at))
+
+            out('static const struct si_reg {chip}_reg_table[] = {{'.format(**locals()))
+
+            for regmap in regmaps:
+                if hasattr(regmap, 'type_ref'):
+                    if not regmap.type_ref in regtypes:
+                        regtype = regdb.register_type(regmap.type_ref)
+                        fields = []
+                        for dbfield in regtype.fields:
+                            field = Field(dbfield.name, dbfield.bits)
+                            if hasattr(dbfield, 'enum_ref'):
+                                enum = regdb.enum(dbfield.enum_ref)
+                                for entry in enum.entries:
+                                    field.values.append((entry.name, entry.value))
+                            fields.append(field)
+
+                        num_fields = len(regtype.fields)
+                        fields_offset = self.__fields.add(fields)
+                        regtypes[regmap.type_ref] = (num_fields, fields_offset)
+                    else:
+                        num_fields, fields_offset = regtypes[regmap.type_ref]
+
+                    print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},'
+                          .format(self.__strings.add(regmap.name), **locals()))
                 else:
-                    print '\t{%s, %s(~0u)},' % (strings.add(field.name), field.s_name)
-                fields_idx += 1
+                    print('\t{{{0}, {regmap.map.at}}},'
+                          .format(self.__strings.add(regmap.name), **locals()))
 
-    print '};'
-    print
+            out('};\n')
 
-    print 'static const struct si_reg sid_reg_table[] = {'
-    for reg in regs:
-        if len(reg.fields):
-            print '\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name,
-                len(reg.fields), reg.fields_idx if reg.own_fields else reg.fields_owner.fields_idx)
-        else:
-            print '\t{%s, %s},' % (strings.add(reg.name), reg.r_name)
-    print '};'
-    print
+        self.__fields.emit(file, self.__strings, self.__strings_offsets)
+
+        out()
 
-    strings.emit(sys.stdout, "sid_strings")
+        self.__strings.emit(file, "sid_strings")
 
-    print
+        out()
 
-    strings_offsets.emit(sys.stdout, "sid_strings_offsets")
+        self.__strings_offsets.emit(file, "sid_strings_offsets")
 
-    print
-    print '#endif'
+        out()
+        out('#endif')
 
 
 def main():
-    regs = []
-    packets = []
-    for arg in sys.argv[1:]:
-        parse(arg, regs, packets)
-    write_tables(regs, packets)
+    # Parse PKT3 types
+    with open(sys.argv[1], 'r') as filp:
+        packets = parse_packet3(filp)
+
+    # Register database parse
+    regdb = None
+    for filename in sys.argv[2:]:
+        with open(filename, 'r') as filp:
+            try:
+                db = RegisterDatabase.from_json(json.load(filp))
+                if regdb is None:
+                    regdb = db
+                else:
+                    regdb.update(db)
+            except json.JSONDecodeError as e:
+                print('Error reading {}'.format(sys.argv[1]), file=sys.stderr)
+                raise
+
+    # The ac_debug code only distinguishes by chip_class
+    regdb.merge_chips(['gfx8', 'fiji', 'stoney'], 'gfx8')
 
+    # Write it all out
+    w = TableWriter()
+    w.write(regdb, packets)
 
 if __name__ == '__main__':
     main()