blob: d8885326dfd4e615f893fe58ebb32cd9d7aae786 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4"""
5Generate html documentation from validated register json tree
6"""
7
8import logging as log
9import re
10import sys
11
12
13def genout(outfile, msg):
14 outfile.write(msg)
15
16
17# expand !!register references into html links, gen **bold** and *italic*
18def desc_expand(s, rnames):
19 def fieldsub(match):
20 base = match.group(1).partition('.')[0].lower()
21 if base in rnames:
22 if match.group(1)[-1] == ".":
23 return ('<a href="#Reg_' + base + '"><code class=\"reg\">' +
24 match.group(1)[:-1] + '</code></a>.')
25 else:
26 return ('<a href="#Reg_' + base + '"><code class=\"reg\">' +
27 match.group(1) + '</code></a>')
28 log.warn('!!' + match.group(1).partition('.')[0] +
29 ' not found in register list.')
30 return match.group(0)
31
32 s = re.sub(r"!!([A-Za-z0-9_.]+)", fieldsub, s)
33 s = re.sub(r"(?s)\*\*(.+?)\*\*", r'<B>\1</B>', s)
34 s = re.sub(r"\*([^*]+?)\*", r'<I>\1</I>', s)
35 return s
36
37
38# Generation of HTML table with register bit-field summary picture
39# Max 16-bit wide on one line
40
41
42def gen_tbl_row(outfile, msb, width, close):
43 if (close):
44 genout(outfile, "</tr>\n")
45 genout(outfile, "<tr>")
46 for x in range(msb, msb - width, -1):
47 genout(outfile, "<td class=\"bitnum\">" + str(x) + "</td>")
48
49 genout(outfile, "</tr><tr>")
50
51
52def gen_html_reg_pic(outfile, reg, width):
53
54 if (width > 32):
55 bsize = 3
56 nextbit = 63
57 hdrbits = 16
58 nextline = 48
59 elif (width > 16):
60 bsize = 3
61 nextbit = 31
62 hdrbits = 16
63 nextline = 16
64 elif (width > 8):
65 bsize = 3
66 nextbit = 15
67 nextline = 0
68 hdrbits = 16
69 else:
70 bsize = 12
71 nextbit = 7
72 nextline = 0
73 hdrbits = 8
74
75 genout(outfile, "<table class=\"regpic\">")
76 gen_tbl_row(outfile, nextbit, hdrbits, False)
77
78 for field in reversed(reg['fields']):
79 fieldlsb = field['bitinfo'][2]
80 fieldwidth = field['bitinfo'][1]
81 fieldmsb = fieldlsb + fieldwidth - 1
82 fname = field['name']
83
84 while nextbit > fieldmsb:
85 if (nextbit >= nextline) and (fieldmsb < nextline):
86 spans = nextbit - (nextline - 1)
87 else:
88 spans = nextbit - fieldmsb
89 genout(
90 outfile, "<td class=\"unused\" colspan=" + str(spans) +
91 ">&nbsp;</td>\n")
92 if (nextbit >= nextline) and (fieldmsb < nextline):
93 nextbit = nextline - 1
94 gen_tbl_row(outfile, nextbit, hdrbits, True)
95 nextline = nextline - 16
96 else:
97 nextbit = fieldmsb
98
99 while (fieldmsb >= nextline) and (fieldlsb < nextline):
100 spans = fieldmsb - (nextline - 1)
101 genout(
102 outfile, "<td class=\"fname\" colspan=" + str(spans) + ">" +
103 fname + "...</td>\n")
104 fname = "..." + field['name']
105 fieldwidth = fieldwidth - spans
106 fieldmsb = nextline - 1
107 nextline = nextline - 16
108 gen_tbl_row(outfile, fieldmsb, hdrbits, True)
109
110 namelen = len(fname)
111 if namelen == 0 or fname == ' ': fname = "&nbsp;"
112 if (namelen > bsize * fieldwidth):
113 usestyle = (" style=\"font-size:" + str(
114 (bsize * 100 * fieldwidth) / namelen) + "%\"")
115 else:
116 usestyle = ""
117
118 genout(
119 outfile, "<td class=\"fname\" colspan=" + str(fieldwidth) +
120 usestyle + ">" + fname + "</td>\n")
121
122 if (fieldlsb == nextline) and nextline > 0:
123 gen_tbl_row(outfile, nextline - 1, hdrbits, True)
124 nextline = nextline - 16
125
126 nextbit = fieldlsb - 1
127 while (nextbit > 0):
128 spans = nextbit - (nextline - 1)
129 genout(outfile,
130 "<td class=\"unused\" colspan=" + str(spans) + ">&nbsp;</td>\n")
131 nextbit = nextline - 1
132 if (nextline > 0):
133 gen_tbl_row(outfile, nextline - 1, hdrbits, True)
134 nextline = nextline - 16
135
136 genout(outfile, "</tr></table>")
137
138
139# Generation of HTML table with header, register picture and details
140
141
142def gen_html_register(outfile, reg, comp, width, rnames, toc, toclvl):
143 def gen_merge(outfile, fieldlsb, mergebase, mergeprev, mergedesc):
144 genout(
145 outfile, "<tr><td class=\"regbits\">" + str(fieldlsb - 1) + ':' +
146 str(mergebase) + "</td>")
147 genout(outfile, "<td class=\"regperm\"></td>")
148 genout(outfile, "<td class=\"regrv\"></td>")
149 genout(outfile, "<td class=\"regfn\"></td>")
150 if mergeprev != mergedesc:
151 genout(outfile,
152 "<td class=\"regde\">" + mergedesc + ".." + mergeprev[4:])
153 else:
154 genout(outfile, "<td class=\"regde\">" + mergedesc)
155 genout(outfile, "</td></tr>\n")
156
157 rname = reg['name']
158 offset = reg['genoffset']
159 #in a multireg with multiple regs give anchor with base register name
160 if 'genbasebits' in reg and rname[-1] == '0':
161 genout(outfile, "<div id=\"Reg_" + rname[:-1].lower() + "\"></div>\n")
162 regwen_string = ''
163 if 'regwen' in reg and (reg['regwen'] != ''):
164 regwen_string = '<br>Register enable = ' + reg['regwen']
165 genout(
166 outfile, "<table class=\"regdef\" id=\"Reg_" + rname.lower() + "\">\n"
167 "<tr><th class=\"regdef\" colspan=5>" + comp + "." + rname + " @ + " +
168 hex(offset) + "<br>" + desc_expand(reg['desc'], rnames) + "<br>" +
169 "Reset default = " + hex(reg['genresval']) + ", mask " + hex(
170 reg['genresmask']) + regwen_string + "</th></tr>\n")
171 if toc != None:
172 toc.append((toclvl, comp + "." + rname, "Reg_" + rname.lower()))
173 genout(outfile, "<tr><td colspan=5>")
174 gen_html_reg_pic(outfile, reg, width)
175 genout(outfile, "</td></tr>\n")
176
177 genout(outfile, "<tr><th width=5%>Bits</th>")
178 genout(outfile, "<th width=5%>Type</th>")
179 genout(outfile, "<th width=5%>Reset</th>")
180 genout(outfile, "<th>Name</th>")
181 genout(outfile, "<th>Description</th></tr>")
182 nextbit = 0
183 fcount = 0
184 mergebase = -1
185 for field in reg['fields']:
186 fcount += 1
187 if not 'name' in field:
188 fname = "field " + str(fcount)
189 else:
190 fname = field['name']
191
192 fieldlsb = field['bitinfo'][2]
193 if (fieldlsb > nextbit) and mergebase < 0:
194 genout(outfile, "<tr><td class=\"regbits\">")
195 if (nextbit == (fieldlsb - 1)):
196 genout(outfile, str(nextbit))
197 else:
198 genout(outfile, str(fieldlsb - 1) + ":" + str(nextbit))
199 genout(outfile,
200 "</td><td></td><td></td><td></td><td>Reserved</td></tr>")
201 if 'genbasebits' in reg:
202 if (((1 << fieldlsb) & reg['genbasebits']) == 0):
203 mergeprev = field['desc']
204 if (mergebase < 0):
205 mergebase = fieldlsb
206 mergedesc = field['desc']
207 nextbit = fieldlsb + field['bitinfo'][1]
208 continue
209 else:
210 if (mergebase >= 0):
211 gen_merge(outfile, fieldlsb, mergebase, mergeprev,
212 mergedesc)
213 mergebase = -1
214 genout(outfile, "<tr><td class=\"regbits\">" + field['bits'] + "</td>")
215 genout(outfile, "<td class=\"regperm\">" + field['swaccess'] + "</td>")
216 genout(
217 outfile,
218 "<td class=\"regrv\">" + ('x' if field['genresvalx'] else hex(
219 field['genresval'])) + "</td>")
220 genout(outfile, "<td class=\"regfn\">" + fname + "</td>")
221 if 'desc' in field:
222 genout(
223 outfile, "<td class=\"regde\">" + desc_expand(
224 field['desc'], rnames) + "\n")
225 else:
226 genout(outfile, "<td>\n")
227
228 if 'enum' in field:
229 genout(outfile, " <table>")
230 for enum in field['enum']:
231 if (not 'name' in enum):
232 ename = "enum for " + fname + " in " + rname
233 else:
234 ename = enum['name']
235 genout(outfile, " <tr><td>" + enum['value'] + "</td>")
236 genout(outfile, "<td>" + ename + "</td>")
237 genout(
238 outfile, "<td>" + desc_expand(enum['desc'], rnames) +
239 "</td></tr>\n")
240
241 genout(outfile, " </table>")
242 if 'genrsvdenum' in field:
243 genout(outfile, "Other values are reserved.")
244 genout(outfile, "</td></tr>\n")
245 nextbit = fieldlsb + field['bitinfo'][1]
246
247 # could be in the middle of a merge
248 if (mergebase >= 0):
249 gen_merge(outfile, nextbit, mergebase, mergeprev, mergedesc)
250
251 genout(outfile, "</table>\n<br><br>\n")
252
253 return
254
255
256def gen_html_window(outfile, win, comp, regwidth, rnames, toc, toclvl):
257 wname = win['name']
258 offset = win['genoffset']
259 genout(
260 outfile, '<table class="regdef" id="Reg_' + wname.lower() + '">\n'
261 '<tr><th class="regdef">' + comp + '.' + wname + ' @ + ' + hex(offset)
262 + '<br>' + win['items'] + ' item ' + win['swaccess'] +
263 ' window<br>Byte writes are ' +
264 ('' if win['genbyte-write'] else '<i>not</i> ') +
265 'supported</th></tr>\n')
266 genout(outfile, '<tr><td><table class="regpic">')
267 genout(outfile, '<tr><td width="10%"></td>')
268 wid = win['genvalidbits']
269
270 for x in range(regwidth - 1, -1, -1):
271 if x == regwidth - 1 or x == wid - 1 or x == 0:
272 genout(outfile, '<td class="bitnum">' + str(x) + '</td>')
273 else:
274 genout(outfile, '<td class="bitnum"></td>')
275 genout(outfile, '</tr>')
276 tblmax = int(win['items']) - 1
277 for x in [0, 1, 2, tblmax - 1, tblmax]:
278 if x == 2:
279 genout(
280 outfile, '<tr><td>&nbsp;</td><td align=center colspan=' +
281 str(regwidth) + '>...</td></tr>')
282 else:
283 genout(
284 outfile, '<tr><td class="regbits">+' +
285 hex(offset + x * (regwidth // 8)) + '</td>')
286 if wid < regwidth:
287 genout(
288 outfile, '<td class="unused" colspan=' +
289 str(regwidth - wid) + '>&nbsp;</td>\n')
290 genout(
291 outfile,
292 '<td class="fname" colspan=' + str(wid) + '>&nbsp;</td>\n')
293 else:
294 genout(
295 outfile, '<td class="fname" colspan=' + str(regwidth) +
296 '>&nbsp;</td>\n')
297 genout(outfile, '</tr>')
298 genout(outfile, '</td></tr></table>')
299 genout(
300 outfile, '<tr><td class="regde">' + desc_expand(win['desc'], rnames) +
301 '</td></tr>')
302 genout(outfile, "</table>\n<br><br>\n")
303 if toc != None:
304 toc.append((toclvl, comp + "." + wname, "Reg_" + wname.lower()))
305
306
307# Must have called validate, so should have no errors
308
309
310def gen_html(regs, outfile, toclist=None, toclevel=3):
311 component = regs['name']
312 registers = regs['registers']
313 rnames = regs['genrnames']
314
315 if 'regwidth' in regs:
316 regwidth = int(regs['regwidth'], 0)
317 else:
318 regwidth = 32
319
320 for x in registers:
321 if 'reserved' in x:
322 continue
323
324 if 'skipto' in x:
325 continue
326
327 if 'sameaddr' in x:
328 for sareg in x['sameaddr']:
329 gen_html_register(outfile, sareg, component, regwidth, rnames,
330 toclist, toclevel)
331 continue
332
333 if 'window' in x:
334 gen_html_window(outfile, x['window'], component, regwidth, rnames,
335 toclist, toclevel)
336 continue
337
338 if 'multireg' in x:
339 for reg in x['multireg']['genregs']:
340 gen_html_register(outfile, reg, component, regwidth, rnames,
341 toclist, toclevel)
342 continue
343
344 gen_html_register(outfile, x, component, regwidth, rnames, toclist,
345 toclevel)
346 return