X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=openpower%2Fsv_analysis.py;h=ec0a442b0fcc0514f79776784b3148393419ac8d;hb=9557a17af04d90df5e58549ecc2358e35c42f557;hp=ac03ac7416454ac8c9e9dd60c42e10028ebb5f1c;hpb=9b924555eb6866359186b6171ab811095ffca1be;p=libreriscv.git diff --git a/openpower/sv_analysis.py b/openpower/sv_analysis.py index ac03ac741..ec0a442b0 100644 --- a/openpower/sv_analysis.py +++ b/openpower/sv_analysis.py @@ -1,41 +1,65 @@ #!/usr/bin/env python3 +# 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/ + import csv import os from os.path import dirname, join from glob import glob from collections import OrderedDict +# Return absolute path (ie $PWD) + isatables + name + 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: + + def get_csv(name): file_path = find_wiki_file(name) with open(file_path, 'r') as csvfile: reader = csv.DictReader(csvfile) return list(reader) +# This will return True if all values are true. +# Not sure what this is about + + def blank_key(row): - #for v in row.values(): - # if 'SPR' in v: # skip all SPRs - # return True + # for v in row.values(): + # if 'SPR' in v: # skip all SPRs + # return True for v in row.values(): if v: return False return True +# General purpose registers have names like: RA, RT, R1, ... +# Floating point registers names like: FRT, FRA, FR1, ..., FRTp, ... +# Return True if field is a register + + def isreg(field): return field.startswith('R') or field.startswith('FR') +# These are the attributes of the instructions, +# register names keycolumns = ['unit', 'in1', 'in2', 'in3', 'out', 'CR in', 'CR out', - ] # don't think we need these: 'ldst len', 'rc', 'lk'] + ] # don't think we need these: 'ldst len', 'rc', 'lk'] + +tablecols = ['unit', 'in', 'outcnt', 'CR in', 'CR out', 'imm' + ] # don't think we need these: 'ldst len', 'rc', 'lk'] -tablecols = ['unit', 'in', 'out', 'CR in', 'CR out', - ] # don't think we need these: 'ldst len', 'rc', 'lk'] def create_key(row): res = OrderedDict() @@ -47,25 +71,32 @@ def create_key(row): res['in'] = 0 if isreg(row[key]): res['in'] += 1 + # registers OUT if key == 'out': + # If upd is 1 then increment the count of outputs + if 'outcnt' not in res: + res['outcnt'] = 0 if isreg(row[key]): - res[key] = 'R' - else: - res[key] = '0' - # CRs + res['outcnt'] += 1 + if row['upd'] == '1': + res['outcnt'] += 1 + + # CRs (Condition Register) (CR0 .. CR7) if key.startswith('CR'): if row[key].startswith('NONE'): 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 + if row[key] == 'LDST': # we care about LDST units res[key] = row[key] else: res[key] = 'OTHER' - # LDST len + # LDST len (LoadStore length) if key.startswith('ldst'): if row[key].startswith('NONE'): res[key] = '0' @@ -82,34 +113,57 @@ def create_key(row): if key == 'lk': res[key] = row[key] + # Convert the numerics 'in' & 'outcnt' to strings res['in'] = str(res['in']) + res['outcnt'] = str(res['outcnt']) + + # constants + if row['in2'].startswith('CONST_'): + res['imm'] = "1" # row['in2'].split("_")[1] + else: + res['imm'] = '' return res +# + + def dformat(d): res = [] for k, v in d.items(): res.append("%s: %s" % (k, v)) return ' '.join(res) -def tformat(d): - return ' | '.join(d) + "|" + +def print_table_row(*cols): + print(f"| {' | '.join(cols)} |") + + +def print_table_header(*cols): + print_table_row(*cols) + print_table_row(*map(lambda v: '-'*max(1, len(v)), cols)) + def keyname(row): - if row['out'] == 'R': - out = '1' - else: - out = '0' - res = '%sR-%sW' % (row['in'], out) + res = [] + if row['unit'] != 'OTHER': + res.append(row['unit']) + if row['in'] != '0': + res.append('%sR' % row['in']) + if row['outcnt'] != '0': + res.append('%sW' % row['outcnt']) if row['CR in'] == '1' and row['CR out'] == '1': - res += "-CRio" + if 'crop' in row: + res.append("CR=2R1W") + else: + res.append("CRio") elif row['CR in'] == '1': - res += "-CRi" + res.append("CRi") elif row['CR out'] == '1': - res += "-CRo" - if row['unit'] != 'OTHER': - return '%s-' % row['unit'] + res - return res + res.append("CRo") + elif 'imm' in row and row['imm']: + res.append("imm") + return '-'.join(res) def process_csvs(): @@ -117,8 +171,18 @@ def process_csvs(): bykey = {} primarykeys = set() dictkeys = OrderedDict() + immediates = {} + print("# OpenPOWER ISA register 'profile's") + print() + print("this page is auto-generated, do not edit") + print("created by https://libre-soc.org/openpower/sv_analysis.py") + print() + + # Expand that (all .csv files) pth = find_wiki_file("*.csv") + + # Ignore those containing: valid test sprs for fname in glob(pth): if 'valid' in fname: continue @@ -126,8 +190,10 @@ def process_csvs(): continue if 'sprs' in fname: continue + #print (fname) csvname = os.path.split(fname)[1] + # csvname is something like: minor_59.csv, fname the whole path csv = get_csv(fname) csvs[fname] = csv for row in csv: @@ -135,6 +201,7 @@ def process_csvs(): continue dkey = create_key(row) key = tuple(dkey.values()) + # print("key=", key) dictkeys[key] = dkey primarykeys.add(key) if key not in bykey: @@ -142,36 +209,86 @@ 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() - print ("# keys") - print ('') - print ('[[!table data="""') - print (tformat(tablecols) + " name |") + # mapping to old SVPrefix "Forms" + mapsto = {'3R-1W-CRio': 'FR4', + '2R-1W-CRio': 'R', + '2R-1W-CRi': 'R', + '2R-1W-CRo': 'R', + '2R': 'non-SV', + '2R-1W': 'R', + '1R-CRio': 'TBD - need close inspection', + '2R-CRio': 'R', + '2R-CRo': 'R', + '1R': 'non-SV', + '1R-1W-CRio': 'R', + '1R-1W-CRo': 'R', + '1R-1W': 'R', + '1R-1W-imm': 'I', + '1R-CRo': 'I', + '1R-imm': 'non-SV', + '1W': 'non-SV', + '1W-CRi': 'TBD - needs close inspection', + 'CRio': 'R', + 'CR=2R1W': 'R', + 'CRi': 'non-SV', + 'imm': 'non-SV', + '': 'non-SV', + 'LDST-2R-imm': 'S', + 'LDST-2R-1W-imm': 'S', + 'LDST-2R-1W': 'I', + 'LDST-2R-2W': 'I', + 'LDST-1R-1W-imm': 'I', + 'LDST-1R-2W-imm': 'I', + 'LDST-3R': 'R/TBD - st*x', # these are st*x + 'LDST-3R-CRo': 'R/TBD - st*x', # st*x + 'LDST-3R-1W': 'R/TBD - st*x', # st*x + } + print("# map to old SV Prefix") + print() + print_table_header("register profile", "old SV Prefix") + for key in primarykeys: + name = keyname(dictkeys[key]) + value = mapsto.get(name, "-") + print_table_row(name, value) + print() + print("# keys") + print() + print_table_header(*tablecols, "imms", "name") for key in primarykeys: name = keyname(dictkeys[key]) - print (tformat(dictkeys[key].values()) + " %s |" % name) - print ('"""]]') - print ('') + imms = list(immediates.get(key, "")) + imms.sort() + print_table_row(*dictkeys[key].values(), "/".join(imms), name) + print() for key in primarykeys: name = keyname(dictkeys[key]) - print ("## %s " % name) - print ('') - print ('[[!table data="""') - print (tformat(['CSV', 'opcode', 'asm', 'form'])) + value = mapsto.get(name, "-") + print("## %s (%s)" % (name, value)) + print() + print_table_header('CSV', 'opcode', 'asm', 'form') rows = bykey[key] rows.sort() for row in rows: - print (tformat(row)) - print ('"""]]') - print ('') + print_table_row(*row) + print() + + # TODO(lkcl): what did this do: + # bykey = {} + # for fname, csv in csvs.items(): + # key - bykey = {} - for fname, csv in csvs.items(): - key if __name__ == '__main__': process_csvs()