8f4d266e49768d11b242c125198569013beca466
[libreriscv.git] / openpower / sv_analysis.py
1 #!/usr/bin/env python3
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/
6 #
7 # It finds .csv files in the directory isatables/
8
9 import csv
10 import os
11 from os.path import dirname, join
12 from glob import glob
13 from collections import OrderedDict
14
15 # Return absolute path (ie $PWD) + isatables + name
16 def find_wiki_file(name):
17 filedir = os.path.dirname(os.path.abspath(__file__))
18 tabledir = join(filedir, 'isatables')
19 file_path = join(tabledir, name)
20 return file_path
21
22 # Return an array of dictionaries from the CSV file name:
23 def get_csv(name):
24 file_path = find_wiki_file(name)
25 with open(file_path, 'r') as csvfile:
26 reader = csv.DictReader(csvfile)
27 return list(reader)
28
29 # This will return True if all values are true.
30 # Not sure what this is about
31 def blank_key(row):
32 #for v in row.values():
33 # if 'SPR' in v: # skip all SPRs
34 # return True
35 for v in row.values():
36 if v:
37 return False
38 return True
39
40 # General purpose registers have names like: RA, RT, R1, ...
41 # Floating point registers names like: FRT, FRA, FR1, ..., FRTp, ...
42 # Return True if field is a register
43 def isreg(field):
44 return field.startswith('R') or field.startswith('FR')
45
46
47 # These are the attributes of the instructions,
48 # register names
49 keycolumns = ['unit', 'in1', 'in2', 'in3', 'out', 'CR in', 'CR out',
50 ] # don't think we need these: 'ldst len', 'rc', 'lk']
51
52 tablecols = ['unit', 'in', 'out', 'CR in', 'CR out', 'outcnt',
53 ] # don't think we need these: 'ldst len', 'rc', 'lk']
54
55 def create_key(row):
56 res = OrderedDict()
57 #print ("row", row)
58 for key in keycolumns:
59 # registers IN - special-case: count number of regs RA/RB/RC/RS
60 if key in ['in1', 'in2', 'in3']:
61 if 'in' not in res:
62 res['in'] = 0
63 if isreg(row[key]):
64 res['in'] += 1
65
66 # registers OUT
67 if key == 'out':
68 if isreg(row[key]):
69 res[key] = 'R'
70 else:
71 res[key] = '0'
72
73 # If upd is 1 then increment the count of outputs
74 if 'outcnt' not in res:
75 res['outcnt'] = 0
76 if row['upd'] == '1':
77 res['outcnt'] += 1
78
79 # CRs (Condition Register) (CR0 .. CR7)
80 if key.startswith('CR'):
81 if row[key].startswith('NONE'):
82 res[key] = '0'
83 else:
84 res[key] = '1'
85 # unit
86 if key == 'unit':
87 if row[key] == 'LDST': # we care about LDST units
88 res[key] = row[key]
89 else:
90 res[key] = 'OTHER'
91 # LDST len (LoadStore length)
92 if key.startswith('ldst'):
93 if row[key].startswith('NONE'):
94 res[key] = '0'
95 else:
96 res[key] = '1'
97 # rc, lk
98 if key in ['rc', 'lk']:
99 if row[key] == 'ONE':
100 res[key] = '1'
101 elif row[key] == 'NONE':
102 res[key] = '0'
103 else:
104 res[key] = 'R'
105 if key == 'lk':
106 res[key] = row[key]
107
108 # Convert the numerics 'in' & 'outcnt' to strings
109 res['in'] = str(res['in'])
110 res['outcnt'] = str(res['outcnt'])
111
112 return res
113
114 #
115 def dformat(d):
116 res = []
117 for k, v in d.items():
118 res.append("%s: %s" % (k, v))
119 return ' '.join(res)
120
121 def tformat(d):
122 return ' | '.join(d) + "|"
123
124 def keyname(row):
125 res = []
126 if row['unit'] != 'OTHER':
127 res.append(row['unit'])
128 if row['in'] != '0':
129 res.append('%sR' % row['in'])
130 if row['out'] == 'R':
131 res.append('1W')
132 if row['CR in'] == '1' and row['CR out'] == '1':
133 res.append("CRio")
134 elif row['CR in'] == '1':
135 res.append("CRi")
136 elif row['CR out'] == '1':
137 res.append("CRo")
138 return '-'.join(res)
139
140
141 def process_csvs():
142 csvs = {}
143 bykey = {}
144 primarykeys = set()
145 dictkeys = OrderedDict()
146
147 # Expand that (all .csv files)
148 pth = find_wiki_file("*.csv")
149
150 # Ignore those containing: valid test sprs
151 for fname in glob(pth):
152 if 'valid' in fname:
153 continue
154 if 'test' in fname:
155 continue
156 if 'sprs' in fname:
157 continue
158
159 #print (fname)
160 csvname = os.path.split(fname)[1]
161 # csvname is something like: minor_59.csv, fname the whole path
162 csv = get_csv(fname)
163 csvs[fname] = csv
164 for row in csv:
165 if blank_key(row):
166 continue
167 dkey = create_key(row)
168 key = tuple(dkey.values())
169 # print("key=", key)
170 dictkeys[key] = dkey
171 primarykeys.add(key)
172 if key not in bykey:
173 bykey[key] = []
174 bykey[key].append((csvname, row['opcode'], row['comment'],
175 row['form'].upper() + '-Form'))
176
177 primarykeys = list(primarykeys)
178 primarykeys.sort()
179
180 print ("# keys")
181 print ('')
182 print ('[[!table data="""')
183 print (tformat(tablecols) + " name |")
184
185 for key in primarykeys:
186 name = keyname(dictkeys[key])
187 print (tformat(dictkeys[key].values()) + " %s |" % name)
188 print ('"""]]')
189 print ('')
190
191 for key in primarykeys:
192 name = keyname(dictkeys[key])
193 print ("## %s " % name)
194 print ('')
195 print ('[[!table data="""')
196 print (tformat(['CSV', 'opcode', 'asm', 'form']))
197 rows = bykey[key]
198 rows.sort()
199 for row in rows:
200 print (tformat(row))
201 print ('"""]]')
202 print ('')
203
204 bykey = {}
205 for fname, csv in csvs.items():
206 key
207
208 if __name__ == '__main__':
209 process_csvs()