start filling in svp64 insns
[libreriscv.git] / openpower / sv_analysis.py
index fe4744250735940cdecbd6c72193ed4e617534ac..4812f8663b40d0ef81e0101dd131ea3fd466d783 100644 (file)
@@ -1,10 +1,16 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python2
+#
+# NOTE that this program is python2 compatible, please do not stop it
+# from working by adding syntax that prevents that.
+#
 # Initial version written by lkcl Oct 2020
 # This program analyses the Power 9 op codes and looks at in/out register uses
 # The results are displayed:
 #      https://libre-soc.org/openpower/opcode_regs_deduped/
 #
 # It finds .csv files in the directory isatables/
+# then goes through the categories and creates svp64 CSV augmentation
+# tables on a per-opcode basis
 
 import csv
 import os
@@ -16,7 +22,7 @@ from collections import OrderedDict
 def find_wiki_file(name):
     filedir = os.path.dirname(os.path.abspath(__file__))
     tabledir = join(filedir, 'isatables')
-    file_path = join(tabledir, name) 
+    file_path = join(tabledir, name)
     return file_path
 
 # Return an array of dictionaries from the CSV file name:
@@ -26,6 +32,14 @@ def get_csv(name):
         reader = csv.DictReader(csvfile)
         return list(reader)
 
+# Write an array of dictionaries to the CSV file name:
+def write_csv(name, items, headers):
+    file_path = find_wiki_file(name)
+    with open(file_path, 'w') as csvfile:
+        writer = csv.DictWriter(csvfile, fieldnames)
+        writer.writeheader()
+        writer.writerows(items)
+
 # This will return True if all values are true.
 # Not sure what this is about
 def blank_key(row):
@@ -79,6 +93,8 @@ def create_key(row):
                 res[key] = '0'
             else:
                 res[key] = '1'
+            if row['comment'].startswith('cr'):
+                res['crop'] = '1'
         # unit
         if key == 'unit':
             if row[key] == 'LDST': # we care about LDST units
@@ -106,6 +122,7 @@ def create_key(row):
     res['in'] = str(res['in'])
     res['outcnt'] = str(res['outcnt'])
 
+
     # constants
     if row['in2'].startswith('CONST_'):
         res['imm'] = "1" # row['in2'].split("_")[1]
@@ -122,7 +139,7 @@ def dformat(d):
     return ' '.join(res)
 
 def tformat(d):
-    return ' | '.join(d) + "|"
+    return ' | '.join(d) + " |"
 
 def keyname(row):
     res = []
@@ -133,10 +150,10 @@ def keyname(row):
     if row['outcnt'] != '0':
         res.append('%sW' % row['outcnt'])
     if row['CR in'] == '1' and row['CR out'] == '1':
-        #if row['comment'].startswith('cr'):
-        #    res.append("CR-2io")
-        #else:
-        res.append("CRio")
+        if 'crop' in row:
+            res.append("CR=2R1W")
+        else:
+            res.append("CRio")
     elif row['CR in'] == '1':
         res.append("CRi")
     elif row['CR out'] == '1':
@@ -151,6 +168,14 @@ def process_csvs():
     bykey = {}
     primarykeys = set()
     dictkeys = OrderedDict()
+    immediates = {}
+    insns = {} # dictionary of CSV row, by instruction
+
+    print ("# OpenPOWER ISA register 'profile's")
+    print ('')
+    print ("this page is auto-generated, do not edit")
+    print ("created by http://libre-soc.org/openpower/sv_analysis.py")
+    print ('')
 
     # Expand that (all .csv files)
     pth = find_wiki_file("*.csv")
@@ -172,6 +197,7 @@ def process_csvs():
         for row in csv:
             if blank_key(row):
                 continue
+            insns[row['comment']] = row # accumulate csv data by instruction
             dkey = create_key(row)
             key = tuple(dkey.values())
             # print("key=", key)
@@ -182,27 +208,49 @@ def process_csvs():
             bykey[key].append((csvname, row['opcode'], row['comment'],
                                row['form'].upper() + '-Form'))
 
+            # detect immediates, collate them (useful info)
+            if row['in2'].startswith('CONST_'):
+                imm = row['in2'].split("_")[1]
+                if key not in immediates:
+                    immediates[key] = set()
+                immediates[key].add(imm)
+
     primarykeys = list(primarykeys)
     primarykeys.sort()
 
     # mapping to old SVPrefix "Forms"
-    mapsto = {'3R-1W-CRio': 'FR4',
-              '2R-1W-CRio': 'R',
-              '2R-1W-CRi': 'R',
-              '2R-1W-CRo': 'R',
-              '2R-1W': 'R',
-              '2R-CRio': 'R',
-              '2R-CRo': 'R',
-              '1R-1W-CRio': 'R',
-              '1R-1W-CRo': 'R',
-              '1R-1W': 'R',
-              '1R-1W-imm': 'I',
-              '1R-Imm': 'U',
-              'CRio': 'R',
-              'LDST-2R-imm': 'S',
-              'LDST-2R-1W-imm': 'S',
-              'LDST-1R-1W-imm': 'I',
-              'LDST-1R-2W-imm': 'I',
+    mapsto = {'3R-1W-CRio': 'RM-1P-3S1D',
+              '2R-1W-CRio': 'RM-1P-2S1D',
+              '2R-1W-CRi': 'RM-1P-3S1D',
+              '2R-1W-CRo': 'RM-1P-2S1D',
+              '2R': 'non-SV',
+              '2R-1W': 'RM-1P-2S1D',
+              '1R-CRio': 'RM-2P-2S1D',
+              '2R-CRio': 'RM-1P-2S1D',
+              '2R-CRo': 'RM-1P-2S1D',
+              '1R': 'non-SV',
+              '1R-1W-CRio': 'RM-2P-1S1D',
+              '1R-1W-CRo': 'RM-2P-1S1D',
+              '1R-1W': 'RM-2P-1S1D',
+              '1R-1W-imm': 'RM-2P-1S1D',
+              '1R-CRo': 'RM-2P-1S1D',
+              '1R-imm': 'non-SV',
+              '1W': 'non-SV',
+              '1W-CRi': 'RM-2P-1S1D',
+              'CRio': 'RM-2P-1S1D',
+              'CR=2R1W': 'RM-1P-2S1D',
+              'CRi': 'non-SV',
+              'imm': 'non-SV',
+              '': 'non-SV',
+              'LDST-2R-imm': 'LDSTRM-2P-2S',
+              'LDST-2R-1W-imm': 'LDSTRM-2P-2S1D',
+              'LDST-2R-1W': 'LDSTRM-2P-2S1D',
+              'LDST-2R-2W': 'LDSTRM-2P-2S1D',
+              'LDST-1R-1W-imm': 'LDSTRM-2P-1S1D',
+              'LDST-1R-2W-imm': 'LDSTRM-2P-1S2D',
+              'LDST-3R': 'LDSTRM-2P-3S',
+              'LDST-3R-CRo': 'LDSTRM-2P-3S',  # st*x
+              'LDST-3R-1W': 'LDSTRM-2P-2S1D',  # st*x
               }
     print ("# map to old SV Prefix")
     print ('')
@@ -217,17 +265,25 @@ def process_csvs():
     print ("# keys")
     print ('')
     print ('[[!table  data="""')
-    print (tformat(tablecols) + " name |")
+    print (tformat(tablecols) + " imms | name |")
 
+    # print out the keys and the table from which they're derived
     for key in primarykeys:
         name = keyname(dictkeys[key])
-        print (tformat(dictkeys[key].values()) + " %s |" % name)
+        row = tformat(dictkeys[key].values())
+        imms = list(immediates.get(key, ""))
+        imms.sort()
+        row += " %s | " % ("/".join(imms))
+        row += " %s |" % name
+        print (row)
     print ('"""]]')
     print ('')
 
+    # print out, by remap name, all the instructions under that category
     for key in primarykeys:
         name = keyname(dictkeys[key])
-        print ("## %s " % name)
+        value = mapsto.get(name, "-")
+        print ("## %s (%s)" % (name, value))
         print ('')
         print ('[[!table  data="""')
         print (tformat(['CSV', 'opcode', 'asm', 'form']))
@@ -238,9 +294,146 @@ def process_csvs():
         print ('"""]]')
         print ('')
 
-    bykey = {}
-    for fname, csv in csvs.items():
-        key
+    #for fname, csv in csvs.items():
+    #    print (fname)
+
+    #for insn, row in insns.items():
+    #    print (insn, row)
+
+    print ("# svp64 remaps")
+    svp64 = OrderedDict()
+    # create a CSV file, per category, with SV "augmentation" info
+    csvcols = ['insn', 'Ptype', 'Etype', '0', '1', '2', '3']
+    for key in primarykeys:
+        # get the decoded key containing row-analysis, and name/value
+        dkey = dictkeys[key]
+        name = keyname(dkey)
+        value = mapsto.get(name, "-")
+        if value == 'non-SV':
+            continue
+
+        # store csv entries by svp64 RM category
+        if value not in svp64:
+            svp64[value] = []
+
+        # print out svp64 tables by category
+        print ("## %s (%s)" % (name, value))
+        print ('')
+        print ('[[!table  data="""')
+        print (tformat(csvcols))
+        rows = bykey[key]
+        rows.sort()
+
+        for row in rows:
+            # get the instruction
+            insn_name = row[2]
+            insn = insns[insn_name]
+            # start constructing svp64 CSV row
+            res = OrderedDict()
+            res['insn'] = insn_name
+            res['Ptype'] = value.split('-')[1] # predication type (RM-xN-xxx)
+            # get whether R_xxx_EXTRAn fields are 2-bit or 3-bit
+            res['Etype'] = 'EXTRA2'
+            # go through each register matching to Rxxxx_EXTRAx
+            for k in ['0', '1', '2', '3']:
+                res[k] = ''
+    
+            # temporary useful info
+            for k in ['in1', 'in2', 'in3', 'out', 'CR in', 'CR out']:
+                if insn[k].startswith('CONST'):
+                    res[k] = ''
+                else:
+                    res[k] = insn[k]
+
+            # sigh now the fun begins.  this isn't the sanest way to do it
+            # but the patterns are pretty regular.
+            if value == 'LDSTRM-2P-1S1D':
+                res['Etype'] = 'EXTRA3' # RM EXTRA3 type
+                res['0'] = 'd:RT' # RT: Rdest_EXTRA3
+                res['1'] = 's:RA' # RA: Rsrc1_EXTRA3
+
+            elif value == 'LDSTRM-2P-1S2D':
+                res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                res['0'] = 'd:RT' # RT: Rdest1_EXTRA2
+                res['1'] = 's:RA' # RA: Rsrc1_EXTRA2
+                res['2'] = 'd:RA' # RA: Rdest2_EXTRA2
+
+            elif value == 'LDSTRM-2P-2S':
+                res['Etype'] = 'EXTRA3' # RM EXTRA2 type
+                res['0'] = 'd:RS' # RT: Rdest1_EXTRA2
+                res['1'] = 's:RA' # RA: Rsrc1_EXTRA2
+
+            elif value == 'LDSTRM-2P-2S1D':
+                if 'st' in insn and 'x' not in insn: # stwu/stbu etc
+                    res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                    res['0'] = 'd:RS' # RS: Rdest1_EXTRA2
+                    res['1'] = 'd:RA' # RA: Rdest2_EXTRA2
+                    res['2'] = 's:RA' # RA: Rsrc1_EXTRA2
+                if 'st' in insn and 'x' in insn: # stwux
+                    res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                    res['0'] = 'd:RS' # RS: Rdest1_EXTRA2
+                    res['1'] = 'd:RA' # RA: Rdest2_EXTRA2, RA: Rsrc1_EXTRA2
+                    res['2'] = 's:RB' # RB: Rsrc2_EXTRA2
+                elif 'u' in insn: # ldux etc.
+                    res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                    res['0'] = 'd:RT' # RT: Rdest1_EXTRA2
+                    res['1'] = 'd:RA' # RA: Rdest2_EXTRA2
+                    res['2'] = 's:RB' # RB: Rsrc1_EXTRA2
+                else:
+                    res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                    res['d0'] = 'RT' # RT: Rdest1_EXTRA2
+                    res['s1'] = 'RA' # RA: Rsrc1_EXTRA2
+                    res['s2'] = 'RB' # RB: Rsrc2_EXTRA2
+
+            elif value == 'LDSTRM-2P-3S':
+                res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                res['0'] = 's:RS,d:CR0' # RS: Rsrc1_EXTRA2 CR0: dest
+                res['1'] = 's:RA' # RA: Rsrc2_EXTRA2
+                res['2'] = 's:RB' # RA: Rsrc3_EXTRA2
+
+            elif value == 'RM-2P-1S1D':
+                res['Etype'] = 'EXTRA3' # RM EXTRA3 type
+                if key == 'CRio' and insn == 'mcrf':
+                    res['0'] = 'd:BF' # BFA: Rdest1_EXTRA3
+                    res['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
+                elif insn == 'setb':
+                    res['0'] = 'd:RT' # RT: Rdest1_EXTRA3
+                    res['1'] = 's:BFA' # BFA: Rsrc1_EXTRA3
+                elif insn_name.startswith('cmp'): # cmpi
+                    res['0'] = 'd:BF' # BF: Rdest1_EXTRA3
+                    res['1'] = 's:RA' # RA: Rsrc1_EXTRA3
+                else:
+                    res['0'] = 'TODO'
+
+            elif value == 'RM-1P-2S1D':
+                res['Etype'] = 'EXTRA3' # RM EXTRA3 type
+                if insn_name.startswith('cr'):
+                    res['0'] = 'd:BT' # BT: Rdest1_EXTRA3
+                    res['1'] = 's:BA' # BA: Rsrc1_EXTRA3
+                    res['2'] = 's:BB' # BB: Rsrc2_EXTRA3
+                elif insn_name.startswith('cmp'): # cmp
+                    res['0'] = 'd:BF' # BF: Rdest1_EXTRA3
+                    res['1'] = 's:RA' # RA: Rsrc1_EXTRA3
+                    res['2'] = 's:RB' # RB: Rsrc1_EXTRA3
+                else:
+                    res['0'] = 'TODO'
+
+            elif value == 'RM-2P-2S1D':
+                res['Etype'] = 'EXTRA2' # RM EXTRA2 type
+                if insn_name.startswith('mt'): # mtcrf
+                    res['0'] = 'd:CR' # CR: Rdest1_EXTRA2
+                    res['1'] = 's:RS' # RS: Rsrc1_EXTRA2
+                    res['2'] = 's:CR' # CR: Rsrc2_EXTRA2
+                else:
+                    res['0'] = 'TODO'
+
+            # print out the row
+            print (tformat(res.values()))
+            # add to svp64 csvs
+            svp64[value].append(res)
+
+        print ('"""]]')
+        print ('')
 
 if __name__ == '__main__':
     process_csvs()