101e04c3fSmrgCopyRight = '''
201e04c3fSmrg/*
37ec681f3Smrg * Copyright 2015-2019 Advanced Micro Devices, Inc.
401e04c3fSmrg *
501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
601e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
701e04c3fSmrg * to deal in the Software without restriction, including without limitation
801e04c3fSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
901e04c3fSmrg * license, and/or sell copies of the Software, and to permit persons to whom
1001e04c3fSmrg * the Software is furnished to do so, subject to the following conditions:
1101e04c3fSmrg *
1201e04c3fSmrg * The above copyright notice and this permission notice (including the next
1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1401e04c3fSmrg * Software.
1501e04c3fSmrg *
1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1901e04c3fSmrg * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
2001e04c3fSmrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2101e04c3fSmrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2201e04c3fSmrg * USE OR OTHER DEALINGS IN THE SOFTWARE.
2301e04c3fSmrg *
2401e04c3fSmrg */
2501e04c3fSmrg'''
2601e04c3fSmrg
277ec681f3Smrgfrom collections import defaultdict
2801e04c3fSmrgimport functools
2901e04c3fSmrgimport itertools
307ec681f3Smrgimport json
3101e04c3fSmrgimport os.path
3201e04c3fSmrgimport re
3301e04c3fSmrgimport sys
3401e04c3fSmrg
357ec681f3SmrgAMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers"))
367ec681f3Smrgsys.path.append(AMD_REGISTERS)
377ec681f3Smrg
387ec681f3Smrgfrom regdb import Object, RegisterDatabase
397ec681f3Smrg
407ec681f3Smrg
417ec681f3Smrgdef string_to_chars(string):
427ec681f3Smrg    return "'" + "', '".join(string) + "', '\\0',"
437ec681f3Smrg
4401e04c3fSmrg
4501e04c3fSmrgclass StringTable:
4601e04c3fSmrg    """
4701e04c3fSmrg    A class for collecting multiple strings in a single larger string that is
4801e04c3fSmrg    used by indexing (to avoid relocations in the resulting binary)
4901e04c3fSmrg    """
5001e04c3fSmrg    def __init__(self):
5101e04c3fSmrg        self.table = []
5201e04c3fSmrg        self.length = 0
5301e04c3fSmrg
5401e04c3fSmrg    def add(self, string):
5501e04c3fSmrg        # We might get lucky with string being a suffix of a previously added string
5601e04c3fSmrg        for te in self.table:
5701e04c3fSmrg            if te[0].endswith(string):
5801e04c3fSmrg                idx = te[1] + len(te[0]) - len(string)
5901e04c3fSmrg                te[2].add(idx)
6001e04c3fSmrg                return idx
6101e04c3fSmrg
6201e04c3fSmrg        idx = self.length
6301e04c3fSmrg        self.table.append((string, idx, set((idx,))))
6401e04c3fSmrg        self.length += len(string) + 1
6501e04c3fSmrg
6601e04c3fSmrg        return idx
6701e04c3fSmrg
6801e04c3fSmrg    def emit(self, filp, name, static=True):
6901e04c3fSmrg        """
7001e04c3fSmrg        Write
7101e04c3fSmrg        [static] const char name[] = "...";
7201e04c3fSmrg        to filp.
7301e04c3fSmrg        """
7401e04c3fSmrg        fragments = [
757ec681f3Smrg            '%s /* %s (%s) */' % (
767ec681f3Smrg                string_to_chars(te[0].encode('unicode_escape').decode()),
7701e04c3fSmrg                te[0].encode('unicode_escape').decode(),
7801e04c3fSmrg                ', '.join(str(idx) for idx in sorted(te[2]))
7901e04c3fSmrg            )
8001e04c3fSmrg            for te in self.table
8101e04c3fSmrg        ]
827ec681f3Smrg        filp.write('%sconst char %s[] = {\n%s\n};\n' % (
8301e04c3fSmrg            'static ' if static else '',
8401e04c3fSmrg            name,
8501e04c3fSmrg            '\n'.join('\t' + fragment for fragment in fragments)
8601e04c3fSmrg        ))
8701e04c3fSmrg
8801e04c3fSmrgclass IntTable:
8901e04c3fSmrg    """
9001e04c3fSmrg    A class for collecting multiple arrays of integers in a single big array
9101e04c3fSmrg    that is used by indexing (to avoid relocations in the resulting binary)
9201e04c3fSmrg    """
9301e04c3fSmrg    def __init__(self, typename):
9401e04c3fSmrg        self.typename = typename
9501e04c3fSmrg        self.table = []
9601e04c3fSmrg        self.idxs = set()
9701e04c3fSmrg
9801e04c3fSmrg    def add(self, array):
9901e04c3fSmrg        # We might get lucky and find the array somewhere in the existing data
10001e04c3fSmrg        try:
10101e04c3fSmrg            idx = 0
10201e04c3fSmrg            while True:
10301e04c3fSmrg                idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1)
10401e04c3fSmrg
10501e04c3fSmrg                for i in range(1, len(array)):
10601e04c3fSmrg                    if array[i] != self.table[idx + i]:
10701e04c3fSmrg                        break
10801e04c3fSmrg                else:
10901e04c3fSmrg                    self.idxs.add(idx)
11001e04c3fSmrg                    return idx
11101e04c3fSmrg
11201e04c3fSmrg                idx += 1
11301e04c3fSmrg        except ValueError:
11401e04c3fSmrg            pass
11501e04c3fSmrg
11601e04c3fSmrg        idx = len(self.table)
11701e04c3fSmrg        self.table += array
11801e04c3fSmrg        self.idxs.add(idx)
11901e04c3fSmrg        return idx
12001e04c3fSmrg
12101e04c3fSmrg    def emit(self, filp, name, static=True):
12201e04c3fSmrg        """
12301e04c3fSmrg        Write
12401e04c3fSmrg        [static] const typename name[] = { ... };
12501e04c3fSmrg        to filp.
12601e04c3fSmrg        """
12701e04c3fSmrg        idxs = sorted(self.idxs) + [len(self.table)]
12801e04c3fSmrg
12901e04c3fSmrg        fragments = [
13001e04c3fSmrg            ('\t/* %s */ %s' % (
13101e04c3fSmrg                idxs[i],
13201e04c3fSmrg                ' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]])
13301e04c3fSmrg            ))
13401e04c3fSmrg            for i in range(len(idxs) - 1)
13501e04c3fSmrg        ]
13601e04c3fSmrg
13701e04c3fSmrg        filp.write('%sconst %s %s[] = {\n%s\n};\n' % (
13801e04c3fSmrg            'static ' if static else '',
13901e04c3fSmrg            self.typename, name,
14001e04c3fSmrg            '\n'.join(fragments)
14101e04c3fSmrg        ))
14201e04c3fSmrg
14301e04c3fSmrgclass Field:
1447ec681f3Smrg    def __init__(self, name, bits):
1457ec681f3Smrg        self.name = name
1467ec681f3Smrg        self.bits = bits   # [first, last]
1477ec681f3Smrg        self.values = []   # [(name, value), ...]
14801e04c3fSmrg
14901e04c3fSmrg    def format(self, string_table, idx_table):
1507ec681f3Smrg        mask = ((1 << (self.bits[1] - self.bits[0] + 1)) - 1) << self.bits[0]
15101e04c3fSmrg        if len(self.values):
15201e04c3fSmrg            values_offsets = []
15301e04c3fSmrg            for value in self.values:
15401e04c3fSmrg                while value[1] >= len(values_offsets):
15501e04c3fSmrg                    values_offsets.append(-1)
1567ec681f3Smrg                values_offsets[value[1]] = string_table.add(value[0])
1577ec681f3Smrg            return '{{{0}, 0x{mask:X}, {1}, {2}}}'.format(
1587ec681f3Smrg                string_table.add(self.name),
1597ec681f3Smrg                len(values_offsets), idx_table.add(values_offsets),
1607ec681f3Smrg                **locals()
1617ec681f3Smrg            )
16201e04c3fSmrg        else:
1637ec681f3Smrg            return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals())
16401e04c3fSmrg
16501e04c3fSmrg    def __eq__(self, other):
1667ec681f3Smrg        return (self.name == other.name and
1677ec681f3Smrg                self.bits[0] == other.bits[0] and self.bits[1] == other.bits[1] and
16801e04c3fSmrg                len(self.values) == len(other.values) and
16901e04c3fSmrg                all(a[0] == b[0] and a[1] == b[1] for a, b, in zip(self.values, other.values)))
17001e04c3fSmrg
17101e04c3fSmrg    def __ne__(self, other):
17201e04c3fSmrg        return not (self == other)
17301e04c3fSmrg
17401e04c3fSmrg
17501e04c3fSmrgclass FieldTable:
17601e04c3fSmrg    """
17701e04c3fSmrg    A class for collecting multiple arrays of register fields in a single big
17801e04c3fSmrg    array that is used by indexing (to avoid relocations in the resulting binary)
17901e04c3fSmrg    """
18001e04c3fSmrg    def __init__(self):
18101e04c3fSmrg        self.table = []
18201e04c3fSmrg        self.idxs = set()
1837ec681f3Smrg        self.name_to_idx = defaultdict(lambda: [])
18401e04c3fSmrg
18501e04c3fSmrg    def add(self, array):
18601e04c3fSmrg        """
18701e04c3fSmrg        Add an array of Field objects, and return the index of where to find
18801e04c3fSmrg        the array in the table.
18901e04c3fSmrg        """
19001e04c3fSmrg        # Check if we can find the array in the table already
19101e04c3fSmrg        for base_idx in self.name_to_idx.get(array[0].name, []):
19201e04c3fSmrg            if base_idx + len(array) > len(self.table):
19301e04c3fSmrg                continue
19401e04c3fSmrg
19501e04c3fSmrg            for i, a in enumerate(array):
19601e04c3fSmrg                b = self.table[base_idx + i]
19701e04c3fSmrg                if a != b:
19801e04c3fSmrg                    break
19901e04c3fSmrg            else:
20001e04c3fSmrg                return base_idx
20101e04c3fSmrg
20201e04c3fSmrg        base_idx = len(self.table)
20301e04c3fSmrg        self.idxs.add(base_idx)
20401e04c3fSmrg
20501e04c3fSmrg        for field in array:
20601e04c3fSmrg            self.name_to_idx[field.name].append(len(self.table))
20701e04c3fSmrg            self.table.append(field)
20801e04c3fSmrg
20901e04c3fSmrg        return base_idx
21001e04c3fSmrg
21101e04c3fSmrg    def emit(self, filp, string_table, idx_table):
21201e04c3fSmrg        """
21301e04c3fSmrg        Write
21401e04c3fSmrg        static const struct si_field sid_fields_table[] = { ... };
21501e04c3fSmrg        to filp.
21601e04c3fSmrg        """
21701e04c3fSmrg        idxs = sorted(self.idxs) + [len(self.table)]
21801e04c3fSmrg
21901e04c3fSmrg        filp.write('static const struct si_field sid_fields_table[] = {\n')
22001e04c3fSmrg
22101e04c3fSmrg        for start, end in zip(idxs, idxs[1:]):
22201e04c3fSmrg            filp.write('\t/* %s */\n' % (start))
22301e04c3fSmrg            for field in self.table[start:end]:
22401e04c3fSmrg                filp.write('\t%s,\n' % (field.format(string_table, idx_table)))
22501e04c3fSmrg
22601e04c3fSmrg        filp.write('};\n')
22701e04c3fSmrg
22801e04c3fSmrg
2297ec681f3Smrgdef parse_packet3(filp):
23001e04c3fSmrg    """
2317ec681f3Smrg    Parse PKT3 commands from the given header file.
23201e04c3fSmrg    """
2337ec681f3Smrg    packets = []
2347ec681f3Smrg    for line in filp:
2357ec681f3Smrg        if not line.startswith('#define '):
2367ec681f3Smrg            continue
23701e04c3fSmrg
2387ec681f3Smrg        line = line[8:].strip()
23901e04c3fSmrg
2407ec681f3Smrg        if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
2417ec681f3Smrg            packets.append(line.split()[0])
2427ec681f3Smrg    return packets
24301e04c3fSmrg
24401e04c3fSmrg
2457ec681f3Smrgclass TableWriter(object):
2467ec681f3Smrg    def __init__(self):
2477ec681f3Smrg        self.__strings = StringTable()
2487ec681f3Smrg        self.__strings_offsets = IntTable('int')
2497ec681f3Smrg        self.__fields = FieldTable()
2507ec681f3Smrg
2517ec681f3Smrg    def write(self, regdb, packets, file=sys.stdout):
2527ec681f3Smrg        def out(*args):
2537ec681f3Smrg            print(*args, file=file)
2547ec681f3Smrg
2557ec681f3Smrg        out('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */')
2567ec681f3Smrg        out()
2577ec681f3Smrg        out(CopyRight.strip())
2587ec681f3Smrg        out('''
25901e04c3fSmrg#ifndef SID_TABLES_H
26001e04c3fSmrg#define SID_TABLES_H
26101e04c3fSmrg
26201e04c3fSmrgstruct si_field {
26301e04c3fSmrg        unsigned name_offset;
26401e04c3fSmrg        unsigned mask;
26501e04c3fSmrg        unsigned num_values;
26601e04c3fSmrg        unsigned values_offset; /* offset into sid_strings_offsets */
26701e04c3fSmrg};
26801e04c3fSmrg
26901e04c3fSmrgstruct si_reg {
27001e04c3fSmrg        unsigned name_offset;
27101e04c3fSmrg        unsigned offset;
27201e04c3fSmrg        unsigned num_fields;
27301e04c3fSmrg        unsigned fields_offset;
27401e04c3fSmrg};
27501e04c3fSmrg
27601e04c3fSmrgstruct si_packet3 {
27701e04c3fSmrg        unsigned name_offset;
27801e04c3fSmrg        unsigned op;
27901e04c3fSmrg};
28001e04c3fSmrg''')
28101e04c3fSmrg
2827ec681f3Smrg        out('static const struct si_packet3 packet3_table[] = {')
2837ec681f3Smrg        for pkt in packets:
2847ec681f3Smrg            out('\t{%s, %s},' % (self.__strings.add(pkt[5:]), pkt))
2857ec681f3Smrg        out('};')
2867ec681f3Smrg        out()
2877ec681f3Smrg
2887ec681f3Smrg        regmaps_by_chip = defaultdict(list)
2897ec681f3Smrg
2907ec681f3Smrg        for regmap in regdb.register_mappings():
2917ec681f3Smrg            for chip in regmap.chips:
2927ec681f3Smrg                regmaps_by_chip[chip].append(regmap)
2937ec681f3Smrg
2947ec681f3Smrg        regtypes = {}
2957ec681f3Smrg
2967ec681f3Smrg        # Sorted iteration over chips for deterministic builds
2977ec681f3Smrg        for chip in sorted(regmaps_by_chip.keys()):
2987ec681f3Smrg            regmaps = regmaps_by_chip[chip]
2997ec681f3Smrg            regmaps.sort(key=lambda regmap: (regmap.map.to, regmap.map.at))
3007ec681f3Smrg
3017ec681f3Smrg            out('static const struct si_reg {chip}_reg_table[] = {{'.format(**locals()))
3027ec681f3Smrg
3037ec681f3Smrg            for regmap in regmaps:
3047ec681f3Smrg                if hasattr(regmap, 'type_ref'):
3057ec681f3Smrg                    if not regmap.type_ref in regtypes:
3067ec681f3Smrg                        regtype = regdb.register_type(regmap.type_ref)
3077ec681f3Smrg                        fields = []
3087ec681f3Smrg                        for dbfield in regtype.fields:
3097ec681f3Smrg                            field = Field(dbfield.name, dbfield.bits)
3107ec681f3Smrg                            if hasattr(dbfield, 'enum_ref'):
3117ec681f3Smrg                                enum = regdb.enum(dbfield.enum_ref)
3127ec681f3Smrg                                for entry in enum.entries:
3137ec681f3Smrg                                    field.values.append((entry.name, entry.value))
3147ec681f3Smrg                            fields.append(field)
3157ec681f3Smrg
3167ec681f3Smrg                        num_fields = len(regtype.fields)
3177ec681f3Smrg                        fields_offset = self.__fields.add(fields)
3187ec681f3Smrg                        regtypes[regmap.type_ref] = (num_fields, fields_offset)
3197ec681f3Smrg                    else:
3207ec681f3Smrg                        num_fields, fields_offset = regtypes[regmap.type_ref]
32101e04c3fSmrg
3227ec681f3Smrg                    print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},'
3237ec681f3Smrg                          .format(self.__strings.add(regmap.name), **locals()))
3247ec681f3Smrg                else:
3257ec681f3Smrg                    print('\t{{{0}, {regmap.map.at}}},'
3267ec681f3Smrg                          .format(self.__strings.add(regmap.name), **locals()))
32701e04c3fSmrg
3287ec681f3Smrg            out('};\n')
32901e04c3fSmrg
3307ec681f3Smrg        self.__fields.emit(file, self.__strings, self.__strings_offsets)
33101e04c3fSmrg
3327ec681f3Smrg        out()
33301e04c3fSmrg
3347ec681f3Smrg        self.__strings.emit(file, "sid_strings")
33501e04c3fSmrg
3367ec681f3Smrg        out()
33701e04c3fSmrg
3387ec681f3Smrg        self.__strings_offsets.emit(file, "sid_strings_offsets")
33901e04c3fSmrg
3407ec681f3Smrg        out()
3417ec681f3Smrg        out('#endif')
34201e04c3fSmrg
34301e04c3fSmrg
34401e04c3fSmrgdef main():
3457ec681f3Smrg    # Parse PKT3 types
3467ec681f3Smrg    with open(sys.argv[1], 'r') as filp:
3477ec681f3Smrg        packets = parse_packet3(filp)
3487ec681f3Smrg
3497ec681f3Smrg    # Register database parse
3507ec681f3Smrg    regdb = None
3517ec681f3Smrg    for filename in sys.argv[2:]:
3527ec681f3Smrg        with open(filename, 'r') as filp:
3537ec681f3Smrg            try:
3547ec681f3Smrg                db = RegisterDatabase.from_json(json.load(filp))
3557ec681f3Smrg                if regdb is None:
3567ec681f3Smrg                    regdb = db
3577ec681f3Smrg                else:
3587ec681f3Smrg                    regdb.update(db)
3597ec681f3Smrg            except json.JSONDecodeError as e:
3607ec681f3Smrg                print('Error reading {}'.format(sys.argv[1]), file=sys.stderr)
3617ec681f3Smrg                raise
3627ec681f3Smrg
3637ec681f3Smrg    # The ac_debug code only distinguishes by chip_class
3647ec681f3Smrg    regdb.merge_chips(['gfx8', 'fiji', 'stoney'], 'gfx8')
36501e04c3fSmrg
3667ec681f3Smrg    # Write it all out
3677ec681f3Smrg    w = TableWriter()
3687ec681f3Smrg    w.write(regdb, packets)
36901e04c3fSmrg
37001e04c3fSmrgif __name__ == '__main__':
37101e04c3fSmrg    main()
37201e04c3fSmrg
37301e04c3fSmrg# kate: space-indent on; indent-width 4; replace-tabs on;
374