amd/common: derive ac_debug tables from register JSON
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Mon, 6 May 2019 22:20:23 +0000 (00:20 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 4 Jun 2019 00:05:20 +0000 (20:05 -0400)
src/amd/Android.common.mk
src/amd/common/ac_debug.c
src/amd/common/meson.build
src/amd/common/sid_tables.py

index 4ef7f176e92401917a56b92b413b7955846ae5ee..5418b79f972e72cb25dd37fb237343a74ced669b 100644 (file)
@@ -44,7 +44,7 @@ LOCAL_GENERATED_SOURCES := $(addprefix $(intermediates)/, $(AMD_GENERATED_FILES)
 $(LOCAL_GENERATED_SOURCES): PRIVATE_PYTHON := $(MESA_PYTHON2)
 $(LOCAL_GENERATED_SOURCES): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PYTHON) $^ > $@
 
-$(intermediates)/common/sid_tables.h: $(LOCAL_PATH)/common/sid_tables.py $(LOCAL_PATH)/common/sid.h $(LOCAL_PATH)/common/gfx9d.h
+$(intermediates)/common/sid_tables.h: $(LOCAL_PATH)/common/sid_tables.py $(LOCAL_PATH)/common/sid.h $(LOCAL_PATH)/registers/amdgfxregs.json $(LOCAL_PATH)/registers/pkt3.json
        $(transform-generated-source)
 
 LOCAL_C_INCLUDES := \
index 187e9d6ba6645538f2eb4076a472b09be446a021..18cbeed4515b6dc404b6a6ced6869358bf6e3908 100644 (file)
@@ -120,9 +120,13 @@ void ac_dump_reg(FILE *file, enum chip_class chip_class, unsigned offset,
        const struct si_reg *reg = NULL;
 
        if (chip_class >= GFX9)
-               reg = find_register(gfx9d_reg_table, ARRAY_SIZE(gfx9d_reg_table), offset);
-       if (!reg)
-               reg = find_register(sid_reg_table, ARRAY_SIZE(sid_reg_table), offset);
+               reg = find_register(gfx9_reg_table, ARRAY_SIZE(gfx9_reg_table), offset);
+       else if (chip_class >= GFX8)
+               reg = find_register(vi_reg_table, ARRAY_SIZE(vi_reg_table), offset);
+       else if (chip_class >= GFX7)
+               reg = find_register(cik_reg_table, ARRAY_SIZE(cik_reg_table), offset);
+       else
+               reg = find_register(si_reg_table, ARRAY_SIZE(si_reg_table), offset);
 
        if (reg) {
                const char *reg_name = sid_strings + reg->name_offset;
index c03433929d86ecb43742dc636bed86180495c275..309f3b56e2a99e02230b34a19438f4d748eaf147 100644 (file)
@@ -20,7 +20,7 @@
 
 sid_tables_h = custom_target(
   'sid_tables_h',
-  input : ['sid_tables.py', 'sid.h', 'gfx9d.h'],
+  input : ['sid_tables.py', 'sid.h', '../registers/amdgfxregs.json', '../registers/pkt3.json'],
   output : 'sid_tables.h',
   command : [prog_python, '@INPUT@'],
   capture : true,
index f12bed4b20934ae80aa9507843c8322f3e98e320..7dc606c81e432eb1733e7171b684590938f43c6f 100644 (file)
@@ -2,7 +2,7 @@ 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"),
@@ -26,13 +26,19 @@ CopyRight = '''
  */
 '''
 
-import collections
+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:
     """
@@ -132,27 +138,30 @@ class IntTable:
         ))
 
 class Field:
-    def __init__(self, reg, s_name):
-        self.s_name = s_name
-        self.name = strip_prefix(s_name)
-        self.values = []
+    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(strip_prefix(value[0]))
-            return '{%s, %s(~0u), %s, %s}' % (
-                string_table.add(self.name), self.s_name,
-                len(values_offsets), idx_table.add(values_offsets))
+                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 '{%s, %s(~0u)}' % (string_table.add(self.name), self.s_name)
+            return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals())
 
     def __eq__(self, other):
-        return (self.s_name == other.s_name and
-                self.name == other.name and
+        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)))
 
@@ -168,7 +177,7 @@ class FieldTable:
     def __init__(self):
         self.table = []
         self.idxs = set()
-        self.name_to_idx = collections.defaultdict(lambda: [])
+        self.name_to_idx = defaultdict(lambda: [])
 
     def add(self, array):
         """
@@ -214,130 +223,36 @@ class FieldTable:
         filp.write('};\n')
 
 
-class Reg:
-    def __init__(self, r_name):
-        self.r_name = r_name
-        self.name = strip_prefix(r_name)
-        self.fields = []
-
-    def __eq__(self, other):
-        if not isinstance(other, Reg):
-            return False
-        return (self.r_name == other.r_name and
-                self.name == other.name and
-                len(self.fields) == len(other.fields) and
-                all(a == b for a, b in zip(self.fields, other.fields)))
-
-    def __ne__(self, other):
-        return not (self == other)
-
-
-def strip_prefix(s):
-    '''Strip prefix in the form ._.*_, e.g. R_001234_'''
-    return s[s[2:].find('_')+3:]
-
-
-class Asic:
+def parse_packet3(filp):
     """
-    Store the registers of one ASIC class / group of classes.
+    Parse PKT3 commands from the given header file.
     """
-    def __init__(self, name):
-        self.name = name
-        self.registers = []
-
-    def parse(self, filp, packets, older_asics):
-        """
-        Parse registers from the given header file. Packets are separately
-        stored in the packets array.
-        """
-        for line in filp:
-            if not line.startswith('#define '):
-                continue
-
-            line = line[8:].strip()
+    packets = []
+    for line in filp:
+        if not line.startswith('#define '):
+            continue
 
-            if line.startswith('R_'):
-                name = line.split()[0]
+        line = line[8:].strip()
 
-                for it in self.registers:
-                    if it.r_name == name:
-                        sys.exit('Duplicate register define: %s' % (name))
-                else:
-                    reg = Reg(name)
-                    self.registers.append(reg)
+        if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
+            packets.append(line.split()[0])
+    return packets
 
-            elif line.startswith('S_'):
-                name = line[:line.find('(')]
 
-                for it in reg.fields:
-                    if it.s_name == name:
-                        sys.exit('Duplicate field define: %s' % (name))
-                else:
-                    field = Field(reg, name)
-                    reg.fields.append(field)
-
-            elif line.startswith('V_'):
-                split = line.split()
-                name = split[0]
-                value = int(split[1], 0)
-
-                for (n,v) in field.values:
-                    if n == name:
-                        sys.exit('Duplicate value define: name = ' + name)
-
-                field.values.append((name, value))
-
-            elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
-                packets.append(line.split()[0])
-
-        # Copy values for corresponding fields from older ASICs if they were
-        # not redefined
-        for reg in self.registers:
-            old_reg = False
-            for field in reg.fields:
-                if len(field.values) > 0:
-                    continue
-                if old_reg is False:
-                    for old_reg in itertools.chain(
-                            *(asic.registers for asic in reversed(older_asics))):
-                        if old_reg.name == reg.name:
-                            break
-                    else:
-                        old_reg = None
-                if old_reg is not None:
-                    for old_field in old_reg.fields:
-                        if old_field.name == field.name:
-                            field.values = old_field.values
-                            break
-
-        # 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()
-
-        # Create a dict of registers with fields and '0' in their name
-        for reg in self.registers:
-            if len(reg.fields) and reg.name.find('0') != -1:
-                reg_dict[reg.name] = reg
-
-        # Assign fields
-        for reg in self.registers:
-            if not len(reg.fields):
-                reg0 = reg_dict.get(match_number.sub('0', reg.name))
-                if reg0 != None:
-                    reg.fields = reg0.fields
-
-
-def write_tables(asics, packets):
-    strings = StringTable()
-    strings_offsets = IntTable("int")
-    fields = FieldTable()
-
-    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
 
@@ -361,58 +276,93 @@ struct si_packet3 {
 };
 ''')
 
-    print('static const struct si_packet3 packet3_table[] = {')
-    for pkt in packets:
-        print('\t{%s, %s},' % (strings.add(pkt[5:]), pkt))
-    print('};')
-    print()
-
-    regs = {}
-    for asic in asics:
-        print('static const struct si_reg %s_reg_table[] = {' % (asic.name))
-        for reg in asic.registers:
-            # Only output a register that was changed or added relative to
-            # the previous generation
-            previous = regs.get(reg.r_name, None)
-            if previous == reg:
-                continue
+        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]
 
-            if len(reg.fields):
-                print('\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name,
-                    len(reg.fields), fields.add(reg.fields)))
-            else:
-                print('\t{%s, %s},' % (strings.add(reg.name), reg.r_name))
+                    print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},'
+                          .format(self.__strings.add(regmap.name), **locals()))
+                else:
+                    print('\t{{{0}, {regmap.map.at}}},'
+                          .format(self.__strings.add(regmap.name), **locals()))
 
-            regs[reg.r_name] = reg
-        print('};')
-        print()
+            out('};\n')
 
-    fields.emit(sys.stdout, strings, strings_offsets)
+        self.__fields.emit(file, self.__strings, self.__strings_offsets)
 
-    print()
+        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():
-    asics = []
-    packets = []
-    for arg in sys.argv[1:]:
-        basename = os.path.basename(arg)
-        m = re.match(r'(.*)\.h', basename)
-        asic = Asic(m.group(1))
-        with open(arg) as filp:
-            asic.parse(filp, packets, asics)
-        asics.append(asic)
-    write_tables(asics, 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(['vi', 'fiji', 'stoney'], 'vi')
 
+    # Write it all out
+    w = TableWriter()
+    w.write(regdb, packets)
 
 if __name__ == '__main__':
     main()