use dict.get() in column_header_replacement function
[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 priorities = ['high', 'med', 'low', 'TBD']
36
37 def sort_by_priority(p1, p2):
38 p1 = priorities.index(p1['priority'])
39 p2 = priorities.index(p2['priority'])
40 if p1 < p2: return -1
41 if p1 > p2: return 1
42 return 0
43
44 def sort_by_cost(p1, p2):
45 p1 = p1['cost']
46 p2 = p2['cost']
47 if not p1.isdigit(): p1 = 0
48 if not p2.isdigit(): p2 = 0
49 p1 = int(p1)
50 p2 = int(p2)
51 if p1 < p2: return -1
52 if p1 > p2: return 1
53 return 0
54
55 def sort_by_cost_priority_page(p1, p2):
56 v = sort_by_cost(p1, p2)
57 if v == 0:
58 v = sort_by_priority(p1, p2)
59 if v == 0:
60 v = sort_by_page(p1, p2)
61 return v
62
63
64 def by_cost_then_priority_then_page(areas):
65 # first blat all columns together (drop area-dict)
66 res = []
67 for row in areas.values():
68 res += row
69 # now sort them
70 res = sorted(res, key=functools.cmp_to_key(sort_by_cost_priority_page))
71 # now split out into a dict again this time by cost-priority
72 costs = {}
73 for row in res:
74 cost = row['cost']
75 if cost not in costs:
76 costs[cost] = []
77 costs[cost].append(row)
78 return costs
79
80
81 # For prettier printing, replace short column heading
82 # names with full, consistent names.
83 # Expected input is a list of column strings
84 def column_header_replacement(header):
85 replacement_col = {'cost': 'XO Cost'}
86 new_header = deepcopy(header)
87 for index, shortname in enumerate(replacement_col.keys()):
88 # update with replacement if any otherwise leave alone
89 new_header[index] = replacement_col.get(shortname, shortname)
90 return new_header
91
92
93 def print_table(title, header, areas, sortby):
94 fname = title.lower().replace(" ", "_")
95 with open("ls012/%s.mdwn" % fname, "w") as f:
96 # write out the page header
97 f.write("\\newpage{}\n")
98 f.write("\n")
99 f.write("# %s\n" % title)
100 f.write("\n")
101 # sort everything if required
102 if sortby is not None:
103 areas = sortby(areas)
104 linecount = None
105 # start writing out areas
106 for title, rows in areas.items():
107 # start new page (if not first newpage)
108 if linecount is not None:
109 # allow 60 rows per page
110 linecount += len(rows)
111 if linecount >= 60:
112 linecount = 0
113 if linecount == 0:
114 f.write("\\newpage{}\n")
115 f.write("\n")
116 if linecount is None: # skipped first newpage
117 linecount = 0
118
119 f.write("## %s\n" % title)
120 f.write("\n")
121
122 # work out maximum length of items, and adjust header
123 hdr = deepcopy(header)
124 cols = {}
125 for hd in hdr:
126 cols[hd] = len(hd)
127 for row in rows:
128 for hd, value in row.items():
129 cols[hd] = max(cols[hd], len(value))
130 # adjust header (add spaces)
131 for i, hd in enumerate(hdr):
132 n_spaces = cols[hd] - len(hd)
133 hdr[i] = hdr[i] + " " * n_spaces
134 # write out header
135 write_mdwn_row(f, hdr)
136 write_mdwn_row(f, underlines(hdr))
137 for row in rows:
138 # adjust row (add same spaces as header width)
139 r = []
140 for key in row.keys():
141 col_len, value = cols[key], row[key]
142 if key == 'page':
143 prefix = 'https://libre-soc.org/openpower/'
144 v = value.replace("_", "\_") # latex, duh
145 url = '[%s](%s%s)' % (value, prefix, v)
146 r.append(url)
147 elif key == 'rfc' and value.startswith('ls'):
148 prefix = 'https://libre-soc.org/openpower/sv/rfc/'
149 url = '[%s](%s%s)' % (value, prefix, value)
150 r.append(url)
151 else:
152 value = value.replace("_", "\_") # latex, duh
153 n_spaces = col_len - len(value)
154 r.append(value + " " * n_spaces)
155 # write row
156 write_mdwn_row(f, r)
157 f.write("\n\n")
158
159 # approx 8 lines per header
160 linecount += 9
161
162 if __name__ == '__main__':
163 with open("ls012/optable.csv") as f:
164 l = map(str.strip, f.readlines())
165 areas = {}
166 header = None
167 for line in l:
168 if line.startswith("#"):
169 area = line[1:].strip()
170 areas[area]= []
171 continue
172 # split line by commas, whitespace-strip it
173 line = list(map(str.strip, line.split(',')))
174 # identify header
175 if header is None:
176 header = line
177 continue
178 # create a dictionary by tuple of header+line
179 linedict = dict(zip(header, line))
180 #print (area)
181 #print (linedict)
182 #print ()
183 # store line in area
184 areas[area].append(linedict)
185
186 # exccellent - now have a dictionary of list of dictionaries:
187 # area - list-of-instructions - dictionary-by-heading
188 print_table("Areas", header, areas, None)
189
190 # now sort by cost and then by page
191 print_table("XO cost", header, areas, by_cost_then_priority_then_page)
192