aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorEric Kunze <eric.kunze@arm.com>2022-08-05 15:40:12 -0700
committerEric Kunze <eric.kunze@arm.com>2022-08-19 14:19:28 -0700
commit58098a7b1ffcf41da759f862deb753c82fe5b4b0 (patch)
tree75b61a482e23293b8af85adf6210f2d3e4e5695d /tools
parent6361d1664c7b82ecc3afdd0eb87e96afea430f89 (diff)
downloadspecification-58098a7b1ffcf41da759f862deb753c82fe5b4b0.tar.gz
Machine parsable specification
This converts portions of the asciidoc specification into an xml document and schema. For the html and pdf outputs, the xml is converted to asciidoc files that are included into the existing specification. The xml allows future automated uses of the tosa specification while maintaining rough compatibility with the existing document. No significant functional changes are included in this change. Change-Id: I7f1f95c527638e270c157d58fcdec6a3510daea5 Signed-off-by: Eric Kunze <eric.kunze@arm.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/dictionary.dic1
-rwxr-xr-xtools/genspec.py68
-rwxr-xr-xtools/get_descriptions.py9
-rw-r--r--tools/tosa.py97
4 files changed, 169 insertions, 6 deletions
diff --git a/tools/dictionary.dic b/tools/dictionary.dic
index b062ac2..5f53b0c 100644
--- a/tools/dictionary.dic
+++ b/tools/dictionary.dic
@@ -1,5 +1,6 @@
personal_ws-1.1 en 500
activations
+adoc
ARGMAX
AsciiDoc
BILINEAR
diff --git a/tools/genspec.py b/tools/genspec.py
new file mode 100755
index 0000000..c871b75
--- /dev/null
+++ b/tools/genspec.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+import os
+
+import tosa
+
+
+class TOSASpecAsciidocGenerator:
+ def __init__(self, spec):
+ self.spec = spec
+
+ def generate_operator(self, op, file):
+ file.write("\n*Arguments:*\n")
+ file.write("\n|===\n")
+ file.write("|Argument|Type|Name|Shape|Description\n\n")
+ for arg in op.arguments:
+ 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()
+ file.write(
+ f"|{cattext}|{arg.type}|{arg.name}|{arg.shape}|{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")
+
+ def generate(self, outdir):
+ 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)
+
+
+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()
+
+ spec = tosa.TOSASpec(args.xml)
+
+ generator = TOSASpecAsciidocGenerator(spec)
+ generator.generate(args.outdir)
diff --git a/tools/get_descriptions.py b/tools/get_descriptions.py
index beded87..0a39a19 100755
--- a/tools/get_descriptions.py
+++ b/tools/get_descriptions.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-
# Copyright (c) 2022, ARM Limited.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,10 +12,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-
# Script to pull the descriptions out of the specification so that
# they can be run through a spellcheck with less noise
-
import argparse
import re
@@ -40,17 +37,17 @@ for name in args.filenames:
continue
if not in_description:
# Look for the start of an operator
- if re.match(r'^===', text):
+ if re.match(r"^===", text):
in_description = True
print(text)
else:
# Stop when we get to a subsection like *Arguments*
# or pseudocode in a [source] section. Spellcheck is
# not useful there
- if re.match(r'[\[\*]', text):
+ if re.match(r"[\[\*]", text):
in_description = False
# skip comments
- elif re.match(r'\w*\/\/', text):
+ elif re.match(r"\w*\/\/", text):
continue
else:
print(text)
diff --git a/tools/tosa.py b/tools/tosa.py
new file mode 100644
index 0000000..87b4f1a
--- /dev/null
+++ b/tools/tosa.py
@@ -0,0 +1,97 @@
+import re
+import xml.etree.ElementTree as ET
+
+
+class TOSAOperatorArgumentCategory:
+ def __init__(self, name, profiles=None):
+ self.name = name
+ self.profiles = profiles
+
+
+class TOSAOperatorArgument:
+ def __init__(self, name, description, categories, ty, shape):
+ self.name = name
+ self.description = description
+ self.categories = categories
+ self.type = ty
+ self.shape = shape
+
+
+class TOSAOperatorDataTypeSupport:
+ def __init__(self, mode, tymap, profiles=None):
+ self.mode = mode
+ self.tymap = tymap
+ self.profiles = profiles
+
+
+class TOSAOperator:
+ def __init__(self, name, arguments, types, typesupports):
+ self.name = name
+ self.arguments = arguments
+ self.types = types
+ self.typesupports = typesupports
+
+
+class TOSAOperatorGroup:
+ def __init__(self, name, operators):
+ self.name = name
+ self.operators = operators
+
+
+class TOSASpec:
+ def __init__(self, xmlpath):
+ tree = ET.parse(xmlpath)
+ self.xmlroot = tree.getroot()
+ self.operatorgroups = []
+ self.__load_spec()
+
+ def __load_spec(self):
+ for group in self.xmlroot.findall("./operators/operatorgroup"):
+ self.operatorgroups.append(self.__load_operator_group(group))
+
+ def __load_operator_group(self, group):
+ name = group.get("name")
+ operators = []
+ for op in group.findall("operator"):
+ operators.append(self.__load_operator(op))
+ return TOSAOperatorGroup(name, operators)
+
+ def __load_operator(self, op):
+ name = op.find("name").text
+ args = []
+ types = []
+ typesupports = []
+ for arg in op.findall("arguments/argument"):
+ args.append(self.__load_operator_argument(arg))
+
+ # TODO add pseudo-code to operator object?
+
+ for ty in op.findall("types/type"):
+ types.append(ty.get("name"))
+
+ for tysup in op.findall("typesupport"):
+ tsmode = tysup.get("mode")
+ tsmap = {}
+ profiles = tysup.findall("profile")
+ tsprofiles = []
+ for p in profiles:
+ tsprofiles.append(p.get("name"))
+ for ty in types:
+ tsmap[ty] = tysup.get(ty)
+ typesupports.append(TOSAOperatorDataTypeSupport(tsmode, tsmap, tsprofiles))
+ return TOSAOperator(name, args, types, typesupports)
+
+ def __load_operator_argument(self, arg):
+ name = arg.get("name")
+ desc = arg.find("description").text.strip()
+ argcats = []
+ argtype = arg.get("type")
+ shape = arg.get("shape")
+
+ cats = re.findall(
+ r"(input|output|attribute)\(?([A-Z,]+)?\)?", arg.get("category")
+ )
+ for cat in cats:
+ argcats.append(TOSAOperatorArgumentCategory(cat[0], cat[1].split(",")))
+
+ return TOSAOperatorArgument(name, desc, argcats, argtype, shape)