(no commit message)
[libreriscv.git] / openpower / sv / rfc / ls012_optable.py
1 #!/usr/bin/env python3
2 # generates markdown tables from CSV files, after doing lovely sorting
3 # by different columns, blah blah...
4 from copy import deepcopy
5 import functools
6
7 def write_mdwn_row(f, row):
8 row = "|".join(row)
9 row = "|%s|\n" % row
10 f.write(row)
11
12 def underlines(header):
13 row = []
14 for col in header:
15 row.append("-" * len(col))
16 return row
17
18 # sorting functions
19 def is_svp64_page(page):
20 return page in ['sv/setvl', 'sv/svstep', 'sv/remap']
21
22 def sort_by_page(p1, p2):
23 p1 = p1['page']
24 p2 = p2['page']
25 if not (is_svp64_page(p1) ^ is_svp64_page(p2)):
26 if p1 < p2: return -1
27 if p1 > p2: return 1
28 return 0
29 if is_svp64_page(p1):
30 return -1
31 if is_svp64_page(p2):
32 return 1
33 return 0
34
35 levels = ['SFFS', 'SV/E', 'SV/D', 'SV/S', 'opt']
36
37 def sort_by_level(p1, p2):
38 p1 = levels.index(p1['level'])
39 p2 = levels.index(p2['level'])
40 if p1 < p2: return -1
41 if p1 > p2: return 1
42 return 0
43
44 priorities = ['high', 'med', 'low', 'TBD']
45
46 def sort_by_priority(p1, p2):
47 p1 = priorities.index(p1['priority'])
48 p2 = priorities.index(p2['priority'])
49 if p1 < p2: return -1
50 if p1 > p2: return 1
51 return 0
52
53 def sort_by_cost(p1, p2):
54 p1 = p1['cost']
55 p2 = p2['cost']
56 if not p1.isdigit(): p1 = 0
57 if not p2.isdigit(): p2 = 0
58 p1 = int(p1)
59 p2 = int(p2)
60 if p1 < p2: return -1
61 if p1 > p2: return 1
62 return 0
63
64 def sort_by_level_priority_cost(p1, p2):
65 v = sort_by_level(p1, p2)
66 if v == 0:
67 v = sort_by_priority(p1, p2)
68 if v == 0:
69 v = sort_by_cost(p1, p2)
70 return v
71
72
73 def sort_by_cost_priority_page(p1, p2):
74 v = sort_by_cost(p1, p2)
75 if v == 0:
76 v = sort_by_priority(p1, p2)
77 if v == 0:
78 v = sort_by_page(p1, p2)
79 return v
80
81
82 def by_levelpriority_then_cost(areas):
83 # first blat all columns together (drop area-dict)
84 res = []
85 for row in areas.values():
86 res += row
87 # now sort them
88 res = sorted(res, key=functools.cmp_to_key(sort_by_level_priority_cost))
89 # now split out into a dict again this time by cost-priority
90 levels = {}
91 for row in res:
92 key = row['level']+row['priority']
93 if key not in levels:
94 levels[key] = []
95 levels[key].append(row)
96 return levels
97
98
99 def by_cost_then_priority_then_page(areas):
100 # first blat all columns together (drop area-dict)
101 res = []
102 for row in areas.values():
103 res += row
104 # now sort them
105 res = sorted(res, key=functools.cmp_to_key(sort_by_cost_priority_page))
106 # now split out into a dict again this time by cost-priority
107 costs = {}
108 for row in res:
109 cost = row['cost']
110 if cost not in costs:
111 costs[cost] = []
112 costs[cost].append(row)
113 return costs
114
115
116 # For prettier printing, replace short column heading
117 # names with full, consistent names.
118 # Expected input is a list of column strings
119 def column_header_replacement(header):
120 replacement_col = {'cost': 'XO Cost'}
121 new_header = deepcopy(header)
122 for index, shortname in enumerate(replacement_col.keys()):
123 # update with replacement if any otherwise leave alone
124 new_header[index] = replacement_col.get(shortname, shortname)
125 return new_header
126
127
128 def print_table(title, header, areas, sortby):
129 fname = title.lower().replace(" ", "_")
130 with open("ls012/%s.mdwn" % fname, "w") as f:
131 # write out the page header
132 f.write("\\newpage{}\n")
133 f.write("\n")
134 f.write("# %s\n" % title)
135 f.write("\n")
136 # sort everything if required
137 if sortby is not None:
138 areas = sortby(areas)
139 linecount = None
140 # start writing out areas
141 for title, rows in areas.items():
142 # start new page (if not first newpage)
143 if linecount is not None:
144 # allow 58 rows per page
145 linecount += len(rows)
146 if linecount >= 58:
147 linecount = 0
148 if linecount == 0:
149 f.write("\\newpage{}\n")
150 f.write("\n")
151 if linecount is None: # skipped first newpage
152 linecount = 0
153
154 f.write("## %s\n" % title)
155 f.write("\n")
156
157 # work out maximum length of items, and adjust header
158 hdr = deepcopy(header)
159 cols = {}
160 for hd in hdr:
161 cols[hd] = len(hd)
162 for row in rows:
163 for hd, value in row.items():
164 cols[hd] = max(cols[hd], len(value))
165 # adjust header (add spaces)
166 for i, hd in enumerate(hdr):
167 n_spaces = cols[hd] - len(hd)
168 hdr[i] = hdr[i] + " " * n_spaces
169 # write out header
170 write_mdwn_row(f, hdr)
171 write_mdwn_row(f, underlines(hdr))
172 for row in rows:
173 # adjust row (add same spaces as header width)
174 r = []
175 for key in row.keys():
176 col_len, value = cols[key], row[key]
177 if key == 'page':
178 prefix = 'https://libre-soc.org/openpower/'
179 v = value.replace("_", "\_") # latex, duh
180 url = '[%s](%s%s)' % (value, prefix, v)
181 r.append(url)
182 elif key == 'rfc' and value.startswith('ls'):
183 prefix = 'https://libre-soc.org/openpower/sv/rfc/'
184 url = '[%s](%s%s)' % (value, prefix, value)
185 r.append(url)
186 else:
187 value = value.replace("_", "\_") # latex, duh
188 n_spaces = col_len - len(value)
189 r.append(value + " " * n_spaces)
190 # write row
191 write_mdwn_row(f, r)
192 f.write("\n\n")
193
194 # approx 8 lines per header
195 linecount += 9
196
197 if __name__ == '__main__':
198 with open("ls012/optable.csv") as f:
199 l = map(str.strip, f.readlines())
200 areas = {}
201 header = None
202 for line in l:
203 if line.startswith("#"):
204 area = line[1:].strip()
205 areas[area]= []
206 continue
207 # split line by commas, whitespace-strip it
208 line = list(map(str.strip, line.split(',')))
209 # identify header
210 if header is None:
211 header = line
212 continue
213 # create a dictionary by tuple of header+line
214 linedict = dict(zip(header, line))
215 #print (area)
216 #print (linedict)
217 #print ()
218 # store line in area
219 areas[area].append(linedict)
220
221 # excellent - now have a dictionary of list of dictionaries:
222 # area - list-of-instructions - dictionary-by-heading
223 print_table("Areas", header, areas, None)
224
225 # now sort by cost and then by page
226 print_table("XO cost", header, areas, by_cost_then_priority_then_page)
227
228 # now sort by level combined with priority, then cost
229 print_table("Level", header, areas, by_levelpriority_then_cost)
230