-#!/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
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:
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):
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
res['in'] = str(res['in'])
res['outcnt'] = str(res['outcnt'])
+
# constants
if row['in2'].startswith('CONST_'):
res['imm'] = "1" # row['in2'].split("_")[1]
return ' '.join(res)
def tformat(d):
- return ' | '.join(d) + "|"
+ return ' | '.join(d) + " |"
def keyname(row):
res = []
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':
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")
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)
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 ('')
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']))
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()