sv_binutils: generate entries and num_entries via classes
[openpower-isa.git] / src / openpower / sv / sv_analysis.py
index edd4b9d60283916429817a9599ba51a14f282217..d2b7c7abcd2dd4ad065e5704b115f6c1a9e0a2a1 100644 (file)
@@ -18,6 +18,7 @@ import enum
 import os
 from os.path import dirname, join
 from glob import glob
+from collections import defaultdict
 from collections import OrderedDict
 from openpower.decoder.power_svp64 import SVP64RM
 from openpower.decoder.power_enums import find_wiki_file, get_csv
@@ -179,11 +180,58 @@ class Format(enum.Enum):
     def __str__(self):
         return self.name.lower()
 
+    def declarations(self, values, lens):
+        def declaration_binutils(value, width):
+            yield f"/* TODO: implement binutils declaration (value={value!r}, width={width!r}) */"
+
+        def declaration_vhdl(value, width):
+            yield f"    type sv_{value}_rom_array_t is " \
+                f"array(0 to {width}) of sv_decode_rom_t;"
+
+        for value in values:
+            if value not in lens:
+                todo = [f"TODO {value} (or no SVP64 augmentation)"]
+                todo = self.wrap_comment(todo)
+                yield from map(lambda line: f"    {line}", todo)
+            else:
+                width = lens[value]
+                yield from {
+                    Format.BINUTILS: declaration_binutils,
+                    Format.VHDL: declaration_vhdl,
+                }[self](value, width)
+
+    def definitions(self, entries_svp64, fullcols):
+        def definitions_vhdl():
+            for (value, entries) in entries_svp64.items():
+                yield ""
+                yield f"    constant sv_{value}_decode_rom_array :"
+                yield f"             sv_{value}_rom_array_t := ("
+                yield f"        -- {'  '.join(fullcols)}"
+
+                for (op, insn, row) in entries:
+                    yield f"    {op:>13} => ({', '.join(row)}), -- {insn}"
+
+                yield f"    {'others':>13} => sv_illegal_inst"
+                yield "    );"
+                yield ""
+
+        def definitions_binutils():
+            yield f"/* TODO: implement binutils definitions */"
+
+        yield from {
+            Format.BINUTILS: definitions_binutils,
+            Format.VHDL: definitions_vhdl,
+        }[self]()
+
     def wrap_comment(self, lines):
         def wrap_comment_binutils(lines):
-            yield "/*"
-            yield from map(lambda line: f" * {line}", lines)
-            yield "*/"
+            lines = tuple(lines)
+            if len(lines) == 1:
+                yield f"/* {lines[0]} */"
+            else:
+                yield "/*"
+                yield from map(lambda line: f" * {line}", lines)
+                yield " */"
 
         def wrap_comment_vhdl(lines):
             yield from map(lambda line: f"-- {line}", lines)
@@ -643,6 +691,12 @@ def process_csvs(format):
 
     # now write out the csv files
     for value, csv in svp64.items():
+        if value == '-':
+            from time import sleep
+            print ("WARNING, filename '-' should NOT exist. instrs missing")
+            print ("TODO: fix this (and put in the bugreport number here)")
+            sleep(2)
+            continue
         # print out svp64 tables by category
         print("## %s" % value)
         print('')
@@ -681,10 +735,10 @@ def process_csvs(format):
     csvcols = ['insn', 'Ptype', 'Etype']
     csvcols += ['in1', 'in2', 'in3', 'out', 'out2', 'CR in', 'CR out']
 
-    if format == Format.VHDL:
+    if format is Format.VHDL:
         # and a nice microwatt VHDL file
         file_path = find_wiki_file("sv_decode.vhdl")
-    elif format == Format.BINUTILS:
+    elif format is Format.BINUTILS:
         file_path = find_wiki_file("binutils.c")
 
     with open(file_path, 'w') as stream:
@@ -704,54 +758,40 @@ def output_autogen_disclaimer(format, stream):
 
 
 def output(format, svt, csvcols, insns, csvs_svp64, stream):
+    lens = {
+        'major': 63,
+        'minor_4': 63,
+        'minor_19': 7,
+        'minor_30': 15,
+        'minor_31': 1023,
+        'minor_58': 63,
+        'minor_59': 31,
+        'minor_62': 63,
+        'minor_63l': 511,
+        'minor_63h': 16,
+    }
+
+    def svp64_canonicalize(item):
+        (value, csv) = item
+        value = value.lower().replace("-", "_")
+        return (value, csv)
+
+    csvs_svp64_canon = dict(map(svp64_canonicalize, csvs_svp64.items()))
+
+    # disclaimer
     output_autogen_disclaimer(format, stream)
 
-    if format == Format.BINUTILS:
-        stream.write("/* TODO: implement proper support */\n")
-        return
-
-    # first create array types
-    lens = {'major': 63,
-            'minor_4': 63,
-            'minor_19': 7,
-            'minor_30': 15,
-            'minor_31': 1023,
-            'minor_58': 63,
-            'minor_59': 31,
-            'minor_62': 63,
-            'minor_63l': 511,
-            'minor_63h': 16,
-            }
-    for value, csv in csvs_svp64.items():
-        # munge name
-        value = value.lower()
-        value = value.replace("-", "_")
-        if value not in lens:
-            todo = "    -- TODO %s (or no SVP64 augmentation)\n"
-            stream.write(todo % value)
-            continue
-        width = lens[value]
-        typarray = "    type sv_%s_rom_array_t is " \
-                    "array(0 to %d) of sv_decode_rom_t;\n"
-        stream.write(typarray % (value, width))
+    # declarations
+    for line in format.declarations(csvs_svp64_canon.keys(), lens):
+        stream.write(f"{line}\n")
 
-    # now output structs
+    # definitions
     sv_cols = ['sv_in1', 'sv_in2', 'sv_in3', 'sv_out', 'sv_out2',
-                'sv_cr_in', 'sv_cr_out']
+               'sv_cr_in', 'sv_cr_out']
     fullcols = csvcols + sv_cols
-    hdr = "\n" \
-            "    constant sv_%s_decode_rom_array :\n" \
-            "             sv_%s_rom_array_t := (\n" \
-            "        -- %s\n"
-    ftr = "          others  => sv_illegal_inst\n" \
-            "    );\n\n"
-    for value, csv in csvs_svp64.items():
-        # munge name
-        value = value.lower()
-        value = value.replace("-", "_")
-        if value not in lens:
-            continue
-        stream.write(hdr % (value, value, "  ".join(fullcols)))
+
+    entries_svp64 = defaultdict(list)
+    for (value, csv) in filter(lambda kv: kv[0] in lens, csvs_svp64_canon.items()):
         for entry in csv:
             insn = str(entry['insn'])
             condition = str(entry['CONDITIONS'])
@@ -777,15 +817,22 @@ def output(format, svt, csvcols, insns, csvs_svp64, stream):
                 else:
                     re = sventry[colname]
                 row.append(re)
-            row = ', '.join(row)
-            stream.write("    %13s => (%s), -- %s\n" % (op, row, insn))
-        stream.write(ftr)
+            entries_svp64[value].append((op, insn, row))
 
+    for line in format.definitions(entries_svp64, fullcols):
+        stream.write(f"{line}\n")
 
-if __name__ == '__main__':
+
+def main():
     parser = argparse.ArgumentParser()
     parser.add_argument("-f", "--format",
-        type=Format, choices=Format, default=Format.VHDL,
-        help="format to be used (binutils or VHDL)")
+                        type=Format, choices=Format, default=Format.VHDL,
+                        help="format to be used (binutils or VHDL)")
     args = parser.parse_args()
     process_csvs(args.format)
+
+
+if __name__ == '__main__':
+    # don't do anything other than call main() here, cuz this code is bypassed
+    # by the sv_analysis command created by setup.py
+    main()