lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | """ |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 5 | Generate HTML documentation from IpBlock |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 6 | """ |
| 7 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 8 | from typing import Set, TextIO |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 9 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 10 | from .ip_block import IpBlock |
| 11 | from .html_helpers import expand_paras, render_td |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 12 | from .multi_register import MultiRegister |
| 13 | from .register import Register |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 14 | from .window import Window |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 15 | |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 16 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 17 | def genout(outfile: TextIO, msg: str) -> None: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 18 | outfile.write(msg) |
| 19 | |
| 20 | |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 21 | # Generation of HTML table with register bit-field summary picture |
| 22 | # Max 16-bit wide on one line |
| 23 | |
| 24 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 25 | def gen_tbl_row(outfile: TextIO, msb: int, width: int, close: bool) -> None: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 26 | if (close): |
| 27 | genout(outfile, "</tr>\n") |
| 28 | genout(outfile, "<tr>") |
| 29 | for x in range(msb, msb - width, -1): |
| 30 | genout(outfile, "<td class=\"bitnum\">" + str(x) + "</td>") |
| 31 | |
| 32 | genout(outfile, "</tr><tr>") |
| 33 | |
| 34 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 35 | def gen_html_reg_pic(outfile: TextIO, reg: Register, width: int) -> None: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 36 | |
| 37 | if (width > 32): |
| 38 | bsize = 3 |
| 39 | nextbit = 63 |
| 40 | hdrbits = 16 |
| 41 | nextline = 48 |
| 42 | elif (width > 16): |
| 43 | bsize = 3 |
| 44 | nextbit = 31 |
| 45 | hdrbits = 16 |
| 46 | nextline = 16 |
| 47 | elif (width > 8): |
| 48 | bsize = 3 |
| 49 | nextbit = 15 |
| 50 | nextline = 0 |
| 51 | hdrbits = 16 |
| 52 | else: |
| 53 | bsize = 12 |
| 54 | nextbit = 7 |
| 55 | nextline = 0 |
| 56 | hdrbits = 8 |
| 57 | |
| 58 | genout(outfile, "<table class=\"regpic\">") |
| 59 | gen_tbl_row(outfile, nextbit, hdrbits, False) |
| 60 | |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 61 | for field in reversed(reg.fields): |
| 62 | fieldlsb = field.bits.lsb |
| 63 | fieldwidth = field.bits.width() |
| 64 | fieldmsb = field.bits.msb |
| 65 | fname = field.name |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 66 | |
| 67 | while nextbit > fieldmsb: |
| 68 | if (nextbit >= nextline) and (fieldmsb < nextline): |
| 69 | spans = nextbit - (nextline - 1) |
| 70 | else: |
| 71 | spans = nextbit - fieldmsb |
| 72 | genout( |
| 73 | outfile, "<td class=\"unused\" colspan=" + str(spans) + |
| 74 | "> </td>\n") |
| 75 | if (nextbit >= nextline) and (fieldmsb < nextline): |
| 76 | nextbit = nextline - 1 |
| 77 | gen_tbl_row(outfile, nextbit, hdrbits, True) |
| 78 | nextline = nextline - 16 |
| 79 | else: |
| 80 | nextbit = fieldmsb |
| 81 | |
| 82 | while (fieldmsb >= nextline) and (fieldlsb < nextline): |
| 83 | spans = fieldmsb - (nextline - 1) |
| 84 | genout( |
| 85 | outfile, "<td class=\"fname\" colspan=" + str(spans) + ">" + |
| 86 | fname + "...</td>\n") |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 87 | fname = "..." + field.name |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 88 | fieldwidth = fieldwidth - spans |
| 89 | fieldmsb = nextline - 1 |
| 90 | nextline = nextline - 16 |
| 91 | gen_tbl_row(outfile, fieldmsb, hdrbits, True) |
| 92 | |
| 93 | namelen = len(fname) |
Eunchan Kim | 0bd7566 | 2020-04-24 10:21:18 -0700 | [diff] [blame] | 94 | if namelen == 0 or fname == ' ': |
| 95 | fname = " " |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 96 | if (namelen > bsize * fieldwidth): |
| 97 | usestyle = (" style=\"font-size:" + str( |
| 98 | (bsize * 100 * fieldwidth) / namelen) + "%\"") |
| 99 | else: |
| 100 | usestyle = "" |
| 101 | |
| 102 | genout( |
| 103 | outfile, "<td class=\"fname\" colspan=" + str(fieldwidth) + |
| 104 | usestyle + ">" + fname + "</td>\n") |
| 105 | |
| 106 | if (fieldlsb == nextline) and nextline > 0: |
| 107 | gen_tbl_row(outfile, nextline - 1, hdrbits, True) |
| 108 | nextline = nextline - 16 |
| 109 | |
| 110 | nextbit = fieldlsb - 1 |
| 111 | while (nextbit > 0): |
| 112 | spans = nextbit - (nextline - 1) |
| 113 | genout(outfile, |
| 114 | "<td class=\"unused\" colspan=" + str(spans) + "> </td>\n") |
| 115 | nextbit = nextline - 1 |
| 116 | if (nextline > 0): |
| 117 | gen_tbl_row(outfile, nextline - 1, hdrbits, True) |
| 118 | nextline = nextline - 16 |
| 119 | |
| 120 | genout(outfile, "</tr></table>") |
| 121 | |
| 122 | |
| 123 | # Generation of HTML table with header, register picture and details |
| 124 | |
| 125 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 126 | def gen_html_register(outfile: TextIO, |
| 127 | reg: Register, |
| 128 | comp: str, |
| 129 | width: int, |
| 130 | rnames: Set[str]) -> None: |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 131 | rname = reg.name |
| 132 | offset = reg.offset |
Rupert Swarbrick | e3f9d6f | 2021-02-05 12:40:04 +0000 | [diff] [blame] | 133 | regwen_div = '' |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 134 | if reg.regwen is not None: |
Rupert Swarbrick | e3f9d6f | 2021-02-05 12:40:04 +0000 | [diff] [blame] | 135 | regwen_div = (' <div>Register enable = {}</div>\n' |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 136 | .format(reg.regwen)) |
Rupert Swarbrick | e3f9d6f | 2021-02-05 12:40:04 +0000 | [diff] [blame] | 137 | |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 138 | desc_paras = expand_paras(reg.desc, rnames) |
Rupert Swarbrick | 94926ae | 2021-02-05 13:12:58 +0000 | [diff] [blame] | 139 | desc_head = desc_paras[0] |
| 140 | desc_body = desc_paras[1:] |
| 141 | |
Rupert Swarbrick | e3f9d6f | 2021-02-05 12:40:04 +0000 | [diff] [blame] | 142 | genout(outfile, |
| 143 | '<table class="regdef" id="Reg_{lrname}">\n' |
| 144 | ' <tr>\n' |
| 145 | ' <th class="regdef" colspan=5>\n' |
| 146 | ' <div>{comp}.{rname} @ {off:#x}</div>\n' |
| 147 | ' <div>{desc}</div>\n' |
| 148 | ' <div>Reset default = {resval:#x}, mask {mask:#x}</div>\n' |
| 149 | '{wen}' |
| 150 | ' </th>\n' |
| 151 | ' </tr>\n' |
| 152 | .format(lrname=rname.lower(), |
| 153 | comp=comp, |
| 154 | rname=rname, |
| 155 | off=offset, |
Rupert Swarbrick | 94926ae | 2021-02-05 13:12:58 +0000 | [diff] [blame] | 156 | desc=desc_head, |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 157 | resval=reg.resval, |
| 158 | mask=reg.resmask, |
Rupert Swarbrick | e3f9d6f | 2021-02-05 12:40:04 +0000 | [diff] [blame] | 159 | wen=regwen_div)) |
Rupert Swarbrick | 94926ae | 2021-02-05 13:12:58 +0000 | [diff] [blame] | 160 | if desc_body: |
| 161 | genout(outfile, |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 162 | '<tr><td colspan=5>{}</td></tr>' |
| 163 | .format(''.join(desc_body))) |
Rupert Swarbrick | 94926ae | 2021-02-05 13:12:58 +0000 | [diff] [blame] | 164 | |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 165 | genout(outfile, "<tr><td colspan=5>") |
| 166 | gen_html_reg_pic(outfile, reg, width) |
| 167 | genout(outfile, "</td></tr>\n") |
| 168 | |
| 169 | genout(outfile, "<tr><th width=5%>Bits</th>") |
| 170 | genout(outfile, "<th width=5%>Type</th>") |
| 171 | genout(outfile, "<th width=5%>Reset</th>") |
| 172 | genout(outfile, "<th>Name</th>") |
| 173 | genout(outfile, "<th>Description</th></tr>") |
| 174 | nextbit = 0 |
| 175 | fcount = 0 |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 176 | |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 177 | for field in reg.fields: |
| 178 | fcount += 1 |
| 179 | fname = field.name |
| 180 | |
| 181 | fieldlsb = field.bits.lsb |
| 182 | if fieldlsb > nextbit: |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 183 | genout(outfile, "<tr><td class=\"regbits\">") |
| 184 | if (nextbit == (fieldlsb - 1)): |
| 185 | genout(outfile, str(nextbit)) |
| 186 | else: |
| 187 | genout(outfile, str(fieldlsb - 1) + ":" + str(nextbit)) |
| 188 | genout(outfile, |
| 189 | "</td><td></td><td></td><td></td><td>Reserved</td></tr>") |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 190 | genout(outfile, "<tr><td class=\"regbits\">" + field.bits.as_str() + "</td>") |
| 191 | genout(outfile, "<td class=\"regperm\">" + field.swaccess.key + "</td>") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 192 | genout( |
Garret Kelly | 6f84015 | 2019-11-22 14:38:38 -0500 | [diff] [blame] | 193 | outfile, "<td class=\"regrv\">" + |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 194 | ('x' if field.resval is None else hex(field.resval)) + |
Garret Kelly | 6f84015 | 2019-11-22 14:38:38 -0500 | [diff] [blame] | 195 | "</td>") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 196 | genout(outfile, "<td class=\"regfn\">" + fname + "</td>") |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 197 | |
| 198 | # Collect up any description and enum table |
| 199 | desc_parts = [] |
| 200 | |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 201 | if field.desc is not None: |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 202 | desc_parts += expand_paras(field.desc, rnames) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 203 | |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 204 | if field.enum is not None: |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 205 | desc_parts.append('<table>') |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 206 | for enum in field.enum: |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 207 | enum_desc_paras = expand_paras(enum.desc, rnames) |
| 208 | desc_parts.append('<tr>' |
| 209 | '<td>{val}</td>' |
| 210 | '<td>{name}</td>' |
| 211 | '<td>{desc}</td>' |
| 212 | '</tr>\n' |
| 213 | .format(val=enum.value, |
| 214 | name=enum.name, |
| 215 | desc=''.join(enum_desc_paras))) |
| 216 | desc_parts.append('</table>') |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 217 | if field.has_incomplete_enum(): |
Rupert Swarbrick | 1188003 | 2021-02-19 12:27:00 +0000 | [diff] [blame] | 218 | desc_parts.append("<p>Other values are reserved.</p>") |
| 219 | |
| 220 | genout(outfile, |
| 221 | '<td class="regde">{}</td>'.format(''.join(desc_parts))) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 222 | nextbit = fieldlsb + field.bits.width() |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 223 | |
Tobias Wölfel | 0435a83 | 2021-01-18 09:43:00 +0100 | [diff] [blame] | 224 | genout(outfile, "</table>\n<br>\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 225 | |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 226 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 227 | def gen_html_window(outfile: TextIO, |
| 228 | win: Window, |
| 229 | comp: str, |
| 230 | regwidth: int, |
| 231 | rnames: Set[str]) -> None: |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 232 | wname = win.name or '(unnamed window)' |
| 233 | offset = win.offset |
| 234 | genout(outfile, |
| 235 | '<table class="regdef" id="Reg_{lwname}">\n' |
| 236 | ' <tr>\n' |
| 237 | ' <th class="regdef">\n' |
| 238 | ' <div>{comp}.{wname} @ + {off:#x}</div>\n' |
| 239 | ' <div>{items} item {swaccess} window</div>\n' |
| 240 | ' <div>Byte writes are {byte_writes}supported</div>\n' |
| 241 | ' </th>\n' |
| 242 | ' </tr>\n' |
| 243 | .format(comp=comp, |
| 244 | wname=wname, |
| 245 | lwname=wname.lower(), |
| 246 | off=offset, |
| 247 | items=win.items, |
| 248 | swaccess=win.swaccess.key, |
| 249 | byte_writes=('' if win.byte_write else '<i>not</i> '))) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 250 | genout(outfile, '<tr><td><table class="regpic">') |
| 251 | genout(outfile, '<tr><td width="10%"></td>') |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 252 | wid = win.validbits |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 253 | |
| 254 | for x in range(regwidth - 1, -1, -1): |
| 255 | if x == regwidth - 1 or x == wid - 1 or x == 0: |
| 256 | genout(outfile, '<td class="bitnum">' + str(x) + '</td>') |
| 257 | else: |
| 258 | genout(outfile, '<td class="bitnum"></td>') |
| 259 | genout(outfile, '</tr>') |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 260 | tblmax = win.items - 1 |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 261 | for x in [0, 1, 2, tblmax - 1, tblmax]: |
| 262 | if x == 2: |
| 263 | genout( |
| 264 | outfile, '<tr><td> </td><td align=center colspan=' + |
| 265 | str(regwidth) + '>...</td></tr>') |
| 266 | else: |
| 267 | genout( |
| 268 | outfile, '<tr><td class="regbits">+' + |
| 269 | hex(offset + x * (regwidth // 8)) + '</td>') |
| 270 | if wid < regwidth: |
| 271 | genout( |
| 272 | outfile, '<td class="unused" colspan=' + |
| 273 | str(regwidth - wid) + '> </td>\n') |
| 274 | genout( |
| 275 | outfile, |
| 276 | '<td class="fname" colspan=' + str(wid) + '> </td>\n') |
| 277 | else: |
| 278 | genout( |
| 279 | outfile, '<td class="fname" colspan=' + str(regwidth) + |
| 280 | '> </td>\n') |
| 281 | genout(outfile, '</tr>') |
| 282 | genout(outfile, '</td></tr></table>') |
Rupert Swarbrick | 94926ae | 2021-02-05 13:12:58 +0000 | [diff] [blame] | 283 | genout(outfile, |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 284 | '<tr>{}</tr>'.format(render_td(win.desc, rnames, 'regde'))) |
Tobias Wölfel | 0435a83 | 2021-01-18 09:43:00 +0100 | [diff] [blame] | 285 | genout(outfile, "</table>\n<br>\n") |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 286 | |
| 287 | |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 288 | def gen_html(block: IpBlock, outfile: TextIO) -> int: |
| 289 | rnames = set(block.regs.name_to_offset.keys()) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 290 | |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 291 | for x in block.regs.entries: |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 292 | if isinstance(x, Register): |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 293 | gen_html_register(outfile, x, block.name, block.regwidth, rnames) |
Rupert Swarbrick | c5b3815 | 2021-02-04 09:43:19 +0000 | [diff] [blame] | 294 | continue |
| 295 | if isinstance(x, MultiRegister): |
| 296 | for reg in x.regs: |
Rupert Swarbrick | 269bb3d | 2021-02-23 15:41:56 +0000 | [diff] [blame] | 297 | gen_html_register(outfile, reg, block.name, block.regwidth, |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 298 | rnames) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 299 | continue |
Rupert Swarbrick | bc2bc58 | 2021-02-09 13:30:37 +0000 | [diff] [blame] | 300 | if isinstance(x, Window): |
Rupert Swarbrick | f5fb61f | 2021-03-03 12:20:55 +0000 | [diff] [blame] | 301 | gen_html_window(outfile, x, block.name, block.regwidth, rnames) |
lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 302 | continue |
| 303 | |
Rupert Swarbrick | 6880e21 | 2021-02-10 16:10:00 +0000 | [diff] [blame] | 304 | return 0 |