aboutsummaryrefslogtreecommitdiff
path: root/tools/genspec.py
blob: bdca32c5717b3bc8c7e582b87734f7c3baabbfe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
# Copyright (c) 2023-2024, ARM Limited.
# SPDX-License-Identifier: Apache-2.0
import os

import tosa


class TOSASpecAsciidocGenerator:
    def __init__(self, spec):
        self.spec = spec

    def generate_enum(self, enum, file):
        file.write(f"\n=== {enum.name}\n")
        file.write(f"{enum.description}\n")
        file.write("|===\n")
        file.write("|Name|Value|Description\n\n")
        for val in enum.values:
            file.write(f"|{val[0]}|{val[1]}|{val[2]}\n")
        file.write("|===\n")

    def generate_operator(self, op, file):
        file.write("\n*Arguments:*\n")
        file.write("[cols='3,3,2,2,4,8']")
        file.write("\n|===\n")
        file.write("|Argument|Type|Name|Shape|Rank|Description\n\n")
        for arg in op.arguments:
            # Argument
            cats = arg.categories
            if len(cats) > 1:
                cattext = ""
                sep = ""
                for cat in cats:
                    proflist = "/".join(cat.profiles)
                    profcaption = "profiles" if len(cat.profiles) > 1 else "profile"
                    cattext += sep + cat.name.title() + f" ({proflist} {profcaption})"
                    sep = " "
            else:
                cattext = cats[0].name.title()

            # Type
            if arg.type == "tensor_t":
                argtype = f"T<{arg.tensor_element_type}>"
            elif arg.type == "tensor_list_t":
                if arg.tensor_element_type == "-":
                    argtype = "tensor_list_t"
                else:
                    argtype = f"tensor_list_t<T<{arg.tensor_element_type}>>"
            elif arg.type == "shape_t":
                if arg.shape != "-":
                    argtype = f"shape_t<{arg.shape}>"
                else:
                    argtype = "shape_t<>"
            else:
                argtype = arg.type

            # Rank
            if len(arg.rank) > 0:
                if arg.rank[0] == arg.rank[1]:
                    rank = f"{arg.rank[0]}"
                else:
                    rank = f"{arg.rank[0]} to {arg.rank[1]}"
            else:
                rank = ""

            # Format and write line
            file.write(
                f"|{cattext}|{argtype}|{arg.name}|{arg.shape}"
                f"|{rank}|{arg.description}\n"
            )

        file.write("|===\n")
        if op.typesupports:
            file.write("\n*Supported Data Types:*\n\n")
            file.write("|===\n")
            header = "|Profile|Mode"
            for ty in op.types:
                header += f"|{ty}"
            file.write(header)
            file.write("\n\n")
            for tysup in op.typesupports:
                profile = ", ".join(tysup.profiles) if tysup.profiles else "Any"
                entry = f"|{profile}|{tysup.mode}"
                for ty in op.types:
                    entry += f"|{tysup.tymap[ty]}"
                entry += "\n"
                file.write(entry)
            file.write("|===\n")
        file.write("\n*Operation Function:*\n\n")
        leveltext = ""
        for arg in op.arguments:
            if len(arg.levellimits) > 0:
                for limit in arg.levellimits:
                    leveltext += "LEVEL_CHECK(" + limit[0] + " <= " + limit[1] + ");\n"
        if len(leveltext) > 0:
            file.write(f"[source,c++]\n----\n{leveltext}\n----\n")

    def generate(self, outdir):
        os.makedirs(outdir, exist_ok=True)

        # Generate version information
        major = self.spec.version_major
        minor = self.spec.version_minor
        patch = self.spec.version_patch
        with open(os.path.join(outdir, "version.adoc"), "w") as f:
            f.write(":tosa-version-string: {}.{}.{}".format(major, minor, patch))
            if self.spec.version_is_draft:
                f.write(" draft")
            f.write("\n")

        # Generate level maximums table
        with open(os.path.join(outdir, "levels.adoc"), "w") as f:
            f.write("|===\n")
            f.write("|tosa_level_t")
            for level in self.spec.levels:
                f.write("|tosa_level_{}".format(level.name))
            f.write("\n")
            f.write("|Description")
            for level in self.spec.levels:
                f.write("|{}".format(level.desc))
            f.write("\n")
            for param in self.spec.levels[0].maximums:
                f.write("|{}".format(param))
                for level in self.spec.levels:
                    f.write("|{}".format(level.maximums[param]))
                f.write("\n")
            f.write("|===\n")

        # Generator operators
        opdir = os.path.join(outdir, "operators")
        os.makedirs(opdir, exist_ok=True)
        for group in self.spec.operatorgroups:
            for op in group.operators:
                with open(os.path.join(opdir, op.name + ".adoc"), "w") as f:
                    self.generate_operator(op, f)
        with open(os.path.join(outdir, "enums.adoc"), "w") as f:
            for enum in self.spec.enums:
                self.generate_enum(enum, f)


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--xml", required=True, help="Path to specification XML")
    parser.add_argument("--outdir", required=True, help="Output directory")
    args = parser.parse_args()

    try:
        spec = tosa.TOSASpec(args.xml)
    except RuntimeError as e:
        print(f"Failure reading/validating XML spec: {str(e)}")
        exit(1)

    generator = TOSASpecAsciidocGenerator(spec)
    generator.generate(args.outdir)