2 # Initial version written by lkcl Oct 2020
3 # This program analyses the Power 9 op codes and looks at in/out register uses
4 # The results are displayed:
5 # https://libre-soc.org/openpower/opcode_regs_deduped/
7 # It finds .csv files in the directory isatables/
11 from os
.path
import dirname
, join
13 from collections
import OrderedDict
15 # Return absolute path (ie $PWD) + isatables + name
18 def find_wiki_file(name
):
19 filedir
= os
.path
.dirname(os
.path
.abspath(__file__
))
20 tabledir
= join(filedir
, 'isatables')
21 file_path
= join(tabledir
, name
)
24 # Return an array of dictionaries from the CSV file name:
28 file_path
= find_wiki_file(name
)
29 with
open(file_path
, 'r') as csvfile
:
30 reader
= csv
.DictReader(csvfile
)
33 # This will return True if all values are true.
34 # Not sure what this is about
38 # for v in row.values():
39 # if 'SPR' in v: # skip all SPRs
41 for v
in row
.values():
46 # General purpose registers have names like: RA, RT, R1, ...
47 # Floating point registers names like: FRT, FRA, FR1, ..., FRTp, ...
48 # Return True if field is a register
52 return field
.startswith('R') or field
.startswith('FR')
55 # These are the attributes of the instructions,
57 keycolumns
= ['unit', 'in1', 'in2', 'in3', 'out', 'CR in', 'CR out',
58 ] # don't think we need these: 'ldst len', 'rc', 'lk']
60 tablecols
= ['unit', 'in', 'outcnt', 'CR in', 'CR out', 'imm'
61 ] # don't think we need these: 'ldst len', 'rc', 'lk']
67 for key
in keycolumns
:
68 # registers IN - special-case: count number of regs RA/RB/RC/RS
69 if key
in ['in1', 'in2', 'in3']:
77 # If upd is 1 then increment the count of outputs
78 if 'outcnt' not in res
:
85 # CRs (Condition Register) (CR0 .. CR7)
86 if key
.startswith('CR'):
87 if row
[key
].startswith('NONE'):
91 if row
['comment'].startswith('cr'):
95 if row
[key
] == 'LDST': # we care about LDST units
99 # LDST len (LoadStore length)
100 if key
.startswith('ldst'):
101 if row
[key
].startswith('NONE'):
106 if key
in ['rc', 'lk']:
107 if row
[key
] == 'ONE':
109 elif row
[key
] == 'NONE':
116 # Convert the numerics 'in' & 'outcnt' to strings
117 res
['in'] = str(res
['in'])
118 res
['outcnt'] = str(res
['outcnt'])
121 if row
['in2'].startswith('CONST_'):
122 res
['imm'] = "1" # row['in2'].split("_")[1]
133 for k
, v
in d
.items():
134 res
.append("%s: %s" % (k
, v
))
138 def print_table_row(*cols
):
139 print(f
"| {' | '.join(cols)} |")
142 def print_table_header(*cols
):
143 print_table_row(*cols
)
144 print_table_row(*map(lambda v
: '-'*max(1, len(v
)), cols
))
149 if row
['unit'] != 'OTHER':
150 res
.append(row
['unit'])
152 res
.append('%sR' % row
['in'])
153 if row
['outcnt'] != '0':
154 res
.append('%sW' % row
['outcnt'])
155 if row
['CR in'] == '1' and row
['CR out'] == '1':
157 res
.append("CR=2R1W")
160 elif row
['CR in'] == '1':
162 elif row
['CR out'] == '1':
164 elif 'imm' in row
and row
['imm']:
173 dictkeys
= OrderedDict()
176 print("# OpenPOWER ISA register 'profile's")
178 print("this page is auto-generated, do not edit")
179 print("created by https://libre-soc.org/openpower/sv_analysis.py")
182 # Expand that (all .csv files)
183 pth
= find_wiki_file("*.csv")
185 # Ignore those containing: valid test sprs
186 for fname
in glob(pth
):
195 csvname
= os
.path
.split(fname
)[1]
196 # csvname is something like: minor_59.csv, fname the whole path
202 dkey
= create_key(row
)
203 key
= tuple(dkey
.values())
209 bykey
[key
].append((csvname
, row
['opcode'], row
['comment'],
210 row
['form'].upper() + '-Form'))
212 # detect immediates, collate them (useful info)
213 if row
['in2'].startswith('CONST_'):
214 imm
= row
['in2'].split("_")[1]
215 if key
not in immediates
:
216 immediates
[key
] = set()
217 immediates
[key
].add(imm
)
219 primarykeys
= list(primarykeys
)
222 # mapping to old SVPrefix "Forms"
223 mapsto
= {'3R-1W-CRio': 'FR4',
229 '1R-CRio': 'TBD - need close inspection',
240 '1W-CRi': 'TBD - needs close inspection',
247 'LDST-2R-1W-imm': 'S',
250 'LDST-1R-1W-imm': 'I',
251 'LDST-1R-2W-imm': 'I',
252 'LDST-3R': 'R/TBD - st*x', # these are st*x
253 'LDST-3R-CRo': 'R/TBD - st*x', # st*x
254 'LDST-3R-1W': 'R/TBD - st*x', # st*x
256 print("# map to old SV Prefix")
258 print_table_header("register profile", "old SV Prefix")
259 for key
in primarykeys
:
260 name
= keyname(dictkeys
[key
])
261 value
= mapsto
.get(name
, "-")
262 print_table_row(name
, value
)
267 print_table_header(*tablecols
, "imms", "name")
268 for key
in primarykeys
:
269 name
= keyname(dictkeys
[key
])
270 imms
= list(immediates
.get(key
, ""))
272 print_table_row(*dictkeys
[key
].values(), "/".join(imms
), name
)
275 for key
in primarykeys
:
276 name
= keyname(dictkeys
[key
])
277 value
= mapsto
.get(name
, "-")
278 print("## %s (%s)" % (name
, value
))
280 print_table_header('CSV', 'opcode', 'asm', 'form')
284 print_table_row(*row
)
287 # TODO(lkcl): what did this do:
289 # for fname, csv in csvs.items():
293 if __name__
== '__main__':