[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