[Mesa-dev] [PATCH 4/4] ac/debug: take ASIC generation into account when printing registers

Nicolai Hähnle nhaehnle at gmail.com
Tue Sep 5 06:53:13 UTC 2017


On 05.09.2017 01:05, Marek Olšák wrote:
> gfx9d.h contains almost no named values. Does it obtain named values
> from sid.h when the same field is also present in gfx9d.h?

One possible difference from the old code is that the new code assumes 
that if *any* values are defined for a field in gfx9d.h, then *all* 
values are defined.

In the old code, values in gfx9d.h would have just overwritten values 
from sid.h. I don't know if there are any fields like that with partial 
value definitions in gfx9d.h.

Cheers,
Nicolai


> 
> Marek
> 
> 
> On Mon, Sep 4, 2017 at 2:11 PM, Nicolai Hähnle <nhaehnle at gmail.com> wrote:
>> From: Nicolai Hähnle <nicolai.haehnle at amd.com>
>>
>> There were some overlapping changes in gfx9 especially in the CB/DB
>> blocks which made register dumps rather misleading.
>>
>> The split is along the lines of the header files, so we'll print VI-only
>> fields on SI and CI, for example, but we won't print GFX9 fields on
>> SI/CI/VI, and we won't print SI/CI/VI fields on GFX9.
>> ---
>>   src/amd/common/ac_debug.c    |  83 ++++++++++--------
>>   src/amd/common/sid_tables.py | 201 +++++++++++++++++++++++++++----------------
>>   2 files changed, 177 insertions(+), 107 deletions(-)
>>
>> diff --git a/src/amd/common/ac_debug.c b/src/amd/common/ac_debug.c
>> index 570ba850851..54685356f1d 100644
>> --- a/src/amd/common/ac_debug.c
>> +++ b/src/amd/common/ac_debug.c
>> @@ -94,68 +94,83 @@ static void print_value(FILE *file, uint32_t value, int bits)
>>   }
>>
>>   static void print_named_value(FILE *file, const char *name, uint32_t value,
>>                                int bits)
>>   {
>>          print_spaces(file, INDENT_PKT);
>>          fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ", name);
>>          print_value(file, value, bits);
>>   }
>>
>> +static const struct si_reg *find_register(const struct si_reg *table,
>> +                                         unsigned table_size,
>> +                                         unsigned offset)
>> +{
>> +       for (unsigned i = 0; i < table_size; i++) {
>> +               const struct si_reg *reg = &table[i];
>> +
>> +               if (reg->offset == offset)
>> +                       return reg;
>> +       }
>> +
>> +       return NULL;
>> +}
>> +
>>   void ac_dump_reg(FILE *file, enum chip_class chip_class, unsigned offset,
>>                   uint32_t value, uint32_t field_mask)
>>   {
>> -       int r, f;
>> +       const struct si_reg *reg = NULL;
>>
>> -       for (r = 0; r < ARRAY_SIZE(sid_reg_table); r++) {
>> -               const struct si_reg *reg = &sid_reg_table[r];
>> -               const char *reg_name = sid_strings + reg->name_offset;
>> +       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);
>>
>> -               if (reg->offset == offset) {
>> -                       bool first_field = true;
>> +       if (reg) {
>> +               const char *reg_name = sid_strings + reg->name_offset;
>> +               bool first_field = true;
>>
>> -                       print_spaces(file, INDENT_PKT);
>> -                       fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ",
>> -                               reg_name);
>> +               print_spaces(file, INDENT_PKT);
>> +               fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ",
>> +                       reg_name);
>>
>> -                       if (!reg->num_fields) {
>> -                               print_value(file, value, 32);
>> -                               return;
>> -                       }
>> +               if (!reg->num_fields) {
>> +                       print_value(file, value, 32);
>> +                       return;
>> +               }
>>
>> -                       for (f = 0; f < reg->num_fields; f++) {
>> -                               const struct si_field *field = sid_fields_table + reg->fields_offset + f;
>> -                               const int *values_offsets = sid_strings_offsets + field->values_offset;
>> -                               uint32_t val = (value & field->mask) >>
>> -                                              (ffs(field->mask) - 1);
>> +               for (unsigned f = 0; f < reg->num_fields; f++) {
>> +                       const struct si_field *field = sid_fields_table + reg->fields_offset + f;
>> +                       const int *values_offsets = sid_strings_offsets + field->values_offset;
>> +                       uint32_t val = (value & field->mask) >>
>> +                                      (ffs(field->mask) - 1);
>>
>> -                               if (!(field->mask & field_mask))
>> -                                       continue;
>> +                       if (!(field->mask & field_mask))
>> +                               continue;
>>
>> -                               /* Indent the field. */
>> -                               if (!first_field)
>> -                                       print_spaces(file,
>> -                                                    INDENT_PKT + strlen(reg_name) + 4);
>> +                       /* Indent the field. */
>> +                       if (!first_field)
>> +                               print_spaces(file,
>> +                                            INDENT_PKT + strlen(reg_name) + 4);
>>
>> -                               /* Print the field. */
>> -                               fprintf(file, "%s = ", sid_strings + field->name_offset);
>> +                       /* Print the field. */
>> +                       fprintf(file, "%s = ", sid_strings + field->name_offset);
>>
>> -                               if (val < field->num_values && values_offsets[val] >= 0)
>> -                                       fprintf(file, "%s\n", sid_strings + values_offsets[val]);
>> -                               else
>> -                                       print_value(file, val,
>> -                                                   util_bitcount(field->mask));
>> +                       if (val < field->num_values && values_offsets[val] >= 0)
>> +                               fprintf(file, "%s\n", sid_strings + values_offsets[val]);
>> +                       else
>> +                               print_value(file, val,
>> +                                           util_bitcount(field->mask));
>>
>> -                               first_field = false;
>> -                       }
>> -                       return;
>> +                       first_field = false;
>>                  }
>> +               return;
>>          }
>>
>>          print_spaces(file, INDENT_PKT);
>>          fprintf(file, COLOR_YELLOW "0x%05x" COLOR_RESET " <- 0x%08x\n", offset, value);
>>   }
>>
>>   static uint32_t ac_ib_get(struct ac_ib_parser *ib)
>>   {
>>          uint32_t v = 0;
>>
>> diff --git a/src/amd/common/sid_tables.py b/src/amd/common/sid_tables.py
>> index 808a96f834f..4e53acefa44 100644
>> --- a/src/amd/common/sid_tables.py
>> +++ b/src/amd/common/sid_tables.py
>> @@ -20,22 +20,24 @@ CopyRight = '''
>>    * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
>>    * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
>>    * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
>>    * USE OR OTHER DEALINGS IN THE SOFTWARE.
>>    *
>>    */
>>   '''
>>
>>   import collections
>>   import functools
>> -import sys
>> +import itertools
>> +import os.path
>>   import re
>> +import sys
>>
>>
>>   class StringTable:
>>       """
>>       A class for collecting multiple strings in a single larger string that is
>>       used by indexing (to avoid relocations in the resulting binary)
>>       """
>>       def __init__(self):
>>           self.table = []
>>           self.length = 0
>> @@ -210,92 +212,130 @@ 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:]
>>
>> -def parse(filename, regs, packets):
>> -    stream = open(filename)
>> -
>> -    for line in stream:
>> -        if not line.startswith('#define '):
>> -            continue
>> -
>> -        line = line[8:].strip()
>> -
>> -        if line.startswith('R_'):
>> -            name = line.split()[0]
>> -
>> -            for it in regs:
>> -                if it.r_name == name:
>> -                    reg = it
>> -                    break
>> -            else:
>> -                reg = Reg(name)
>> -                regs.append(reg)
>> -
>> -        elif line.startswith('S_'):
>> -            name = line[:line.find('(')]
>> -
>> -            for it in reg.fields:
>> -                if it.s_name == name:
>> -                    field = it
>> -                    break
>> -            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:
>> -                    if v != value:
>> -                        sys.exit('Value mismatch: 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])
>> +class Asic:
>> +    """
>> +    Store the registers of one ASIC class / group of classes.
>> +    """
>> +    def __init__(self, name):
>> +        self.name = name
>> +        self.registers = []
>>
>> -    # 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()
>> +    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
>>
>> -    # 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
>> +            line = line[8:].strip()
>>
>> -    # 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
>> +            if line.startswith('R_'):
>> +                name = line.split()[0]
>>
>> +                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)
>>
>> -def write_tables(regs, 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 '''
>>   #ifndef SID_TABLES_H
>>   #define SID_TABLES_H
>> @@ -319,46 +359,61 @@ struct si_packet3 {
>>           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_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), fields.add(reg.fields))
>> -        else:
>> -            print '\t{%s, %s},' % (strings.add(reg.name), reg.r_name)
>> -    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
>> +
>> +            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)
>> +
>> +            regs[reg.r_name] = reg
>> +        print '};'
>> +        print
>>
>>       fields.emit(sys.stdout, strings, strings_offsets)
>>
>>       print
>>
>>       strings.emit(sys.stdout, "sid_strings")
>>
>>       print
>>
>>       strings_offsets.emit(sys.stdout, "sid_strings_offsets")
>>
>>       print
>>       print '#endif'
>>
>>
>>   def main():
>> -    regs = []
>> +    asics = []
>>       packets = []
>>       for arg in sys.argv[1:]:
>> -        parse(arg, regs, packets)
>> -    write_tables(regs, packets)
>> +        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)
>>
>>
>>   if __name__ == '__main__':
>>       main()
>>
>>   # kate: space-indent on; indent-width 4; replace-tabs on;
>> --
>> 2.11.0
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list