ac/debug: take ASIC generation into account when printing registers

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.

Acked-by: Marek Olšák <marek.olsak@amd.com>
This commit is contained in:
Nicolai Hähnle
2017-09-04 11:05:13 +02:00
parent 274f1dace7
commit 552aaa11ed
2 changed files with 174 additions and 104 deletions

View File

@@ -101,16 +101,32 @@ static void print_named_value(FILE *file, const char *name, uint32_t value,
print_value(file, value, bits); 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, void ac_dump_reg(FILE *file, enum chip_class chip_class, unsigned offset,
uint32_t value, uint32_t field_mask) 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++) { if (chip_class >= GFX9)
const struct si_reg *reg = &sid_reg_table[r]; 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) {
const char *reg_name = sid_strings + reg->name_offset; const char *reg_name = sid_strings + reg->name_offset;
if (reg->offset == offset) {
bool first_field = true; bool first_field = true;
print_spaces(file, INDENT_PKT); print_spaces(file, INDENT_PKT);
@@ -122,7 +138,7 @@ void ac_dump_reg(FILE *file, enum chip_class chip_class, unsigned offset,
return; return;
} }
for (f = 0; f < reg->num_fields; f++) { for (unsigned f = 0; f < reg->num_fields; f++) {
const struct si_field *field = sid_fields_table + reg->fields_offset + f; const struct si_field *field = sid_fields_table + reg->fields_offset + f;
const int *values_offsets = sid_strings_offsets + field->values_offset; const int *values_offsets = sid_strings_offsets + field->values_offset;
uint32_t val = (value & field->mask) >> uint32_t val = (value & field->mask) >>
@@ -149,7 +165,6 @@ void ac_dump_reg(FILE *file, enum chip_class chip_class, unsigned offset,
} }
return; return;
} }
}
print_spaces(file, INDENT_PKT); print_spaces(file, INDENT_PKT);
fprintf(file, COLOR_YELLOW "0x%05x" COLOR_RESET " <- 0x%08x\n", offset, value); fprintf(file, COLOR_YELLOW "0x%05x" COLOR_RESET " <- 0x%08x\n", offset, value);

View File

@@ -27,8 +27,10 @@ CopyRight = '''
import collections import collections
import functools import functools
import sys import itertools
import os.path
import re import re
import sys
class StringTable: class StringTable:
@@ -217,15 +219,37 @@ class Reg:
self.name = strip_prefix(r_name) self.name = strip_prefix(r_name)
self.fields = [] 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): def strip_prefix(s):
'''Strip prefix in the form ._.*_, e.g. R_001234_''' '''Strip prefix in the form ._.*_, e.g. R_001234_'''
return s[s[2:].find('_')+3:] return s[s[2:].find('_')+3:]
def parse(filename, regs, packets):
stream = open(filename)
for line in stream: class Asic:
"""
Store the registers of one ASIC class / group of classes.
"""
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 '): if not line.startswith('#define '):
continue continue
@@ -234,21 +258,19 @@ def parse(filename, regs, packets):
if line.startswith('R_'): if line.startswith('R_'):
name = line.split()[0] name = line.split()[0]
for it in regs: for it in self.registers:
if it.r_name == name: if it.r_name == name:
reg = it sys.exit('Duplicate register define: %s' % (name))
break
else: else:
reg = Reg(name) reg = Reg(name)
regs.append(reg) self.registers.append(reg)
elif line.startswith('S_'): elif line.startswith('S_'):
name = line[:line.find('(')] name = line[:line.find('(')]
for it in reg.fields: for it in reg.fields:
if it.s_name == name: if it.s_name == name:
field = it sys.exit('Duplicate field define: %s' % (name))
break
else: else:
field = Field(reg, name) field = Field(reg, name)
reg.fields.append(field) reg.fields.append(field)
@@ -260,14 +282,33 @@ def parse(filename, regs, packets):
for (n,v) in field.values: for (n,v) in field.values:
if n == name: if n == name:
if v != value: sys.exit('Duplicate value define: name = ' + name)
sys.exit('Value mismatch: name = ' + name)
field.values.append((name, value)) field.values.append((name, value))
elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1: elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
packets.append(line.split()[0]) 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 # Copy fields to indexed registers which have their fields only defined
# at register index 0. # at register index 0.
# For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0. # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0.
@@ -275,20 +316,19 @@ def parse(filename, regs, packets):
reg_dict = dict() reg_dict = dict()
# Create a dict of registers with fields and '0' in their name # Create a dict of registers with fields and '0' in their name
for reg in regs: for reg in self.registers:
if len(reg.fields) and reg.name.find('0') != -1: if len(reg.fields) and reg.name.find('0') != -1:
reg_dict[reg.name] = reg reg_dict[reg.name] = reg
# Assign fields # Assign fields
for reg in regs: for reg in self.registers:
if not len(reg.fields): if not len(reg.fields):
reg0 = reg_dict.get(match_number.sub('0', reg.name)) reg0 = reg_dict.get(match_number.sub('0', reg.name))
if reg0 != None: if reg0 != None:
reg.fields = reg0.fields reg.fields = reg0.fields
def write_tables(regs, packets): def write_tables(asics, packets):
strings = StringTable() strings = StringTable()
strings_offsets = IntTable("int") strings_offsets = IntTable("int")
fields = FieldTable() fields = FieldTable()
@@ -326,13 +366,23 @@ struct si_packet3 {
print '};' print '};'
print print
print 'static const struct si_reg sid_reg_table[] = {' regs = {}
for reg in 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): if len(reg.fields):
print '\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name, print '\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name,
len(reg.fields), fields.add(reg.fields)) len(reg.fields), fields.add(reg.fields))
else: else:
print '\t{%s, %s},' % (strings.add(reg.name), reg.r_name) print '\t{%s, %s},' % (strings.add(reg.name), reg.r_name)
regs[reg.r_name] = reg
print '};' print '};'
print print
@@ -351,11 +401,16 @@ struct si_packet3 {
def main(): def main():
regs = [] asics = []
packets = [] packets = []
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
parse(arg, regs, packets) basename = os.path.basename(arg)
write_tables(regs, packets) 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__': if __name__ == '__main__':