# Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 """ Generate HTML documentation from IpBlock """ from typing import Set, TextIO from .ip_block import IpBlock from .html_helpers import expand_paras, render_td from .multi_register import MultiRegister from .reg_block import RegBlock from .register import Register from .window import Window def genout(outfile: TextIO, msg: str) -> None: outfile.write(msg) # Generation of HTML table with register bit-field summary picture # Max 16-bit wide on one line def gen_tbl_row(outfile: TextIO, msb: int, width: int, close: bool) -> None: if (close): genout(outfile, "\n") genout(outfile, "") for x in range(msb, msb - width, -1): genout(outfile, "" + str(x) + "") genout(outfile, "") def gen_html_reg_pic(outfile: TextIO, reg: Register, width: int) -> None: if (width > 32): bsize = 3 nextbit = 63 hdrbits = 16 nextline = 48 elif (width > 16): bsize = 3 nextbit = 31 hdrbits = 16 nextline = 16 elif (width > 8): bsize = 3 nextbit = 15 nextline = 0 hdrbits = 16 else: bsize = 12 nextbit = 7 nextline = 0 hdrbits = 8 genout(outfile, "") gen_tbl_row(outfile, nextbit, hdrbits, False) for field in reversed(reg.fields): fieldlsb = field.bits.lsb fieldwidth = field.bits.width() fieldmsb = field.bits.msb fname = field.name while nextbit > fieldmsb: if (nextbit >= nextline) and (fieldmsb < nextline): spans = nextbit - (nextline - 1) else: spans = nextbit - fieldmsb genout( outfile, "\n") if (nextbit >= nextline) and (fieldmsb < nextline): nextbit = nextline - 1 gen_tbl_row(outfile, nextbit, hdrbits, True) nextline = nextline - 16 else: nextbit = fieldmsb while (fieldmsb >= nextline) and (fieldlsb < nextline): spans = fieldmsb - (nextline - 1) genout( outfile, "\n") fname = "..." + field.name fieldwidth = fieldwidth - spans fieldmsb = nextline - 1 nextline = nextline - 16 gen_tbl_row(outfile, fieldmsb, hdrbits, True) namelen = len(fname) if namelen == 0 or fname == ' ': fname = " " if (namelen > bsize * fieldwidth): usestyle = (" style=\"font-size:" + str( (bsize * 100 * fieldwidth) / namelen) + "%\"") else: usestyle = "" genout( outfile, "\n") if (fieldlsb == nextline) and nextline > 0: gen_tbl_row(outfile, nextline - 1, hdrbits, True) nextline = nextline - 16 nextbit = fieldlsb - 1 while (nextbit > 0): spans = nextbit - (nextline - 1) genout(outfile, "\n") nextbit = nextline - 1 if (nextline > 0): gen_tbl_row(outfile, nextline - 1, hdrbits, True) nextline = nextline - 16 genout(outfile, "
 " + fname + "..." + fname + " 
") # Generation of HTML table with header, register picture and details def gen_html_register(outfile: TextIO, reg: Register, comp: str, width: int, rnames: Set[str]) -> None: rname = reg.name offset = reg.offset regwen_div = '' if reg.regwen is not None: regwen_div = ('
Register enable = {}
\n' .format(reg.regwen)) desc_paras = expand_paras(reg.desc, rnames) desc_head = desc_paras[0] desc_body = desc_paras[1:] genout(outfile, '\n' ' \n' ' \n' ' \n' .format(lrname=rname.lower(), comp=comp, rname=rname, off=offset, desc=desc_head, resval=reg.resval, mask=reg.resmask, wen=regwen_div)) if desc_body: genout(outfile, '' .format(''.join(desc_body))) genout(outfile, "\n") genout(outfile, "") genout(outfile, "") genout(outfile, "") genout(outfile, "") genout(outfile, "") nextbit = 0 fcount = 0 for field in reg.fields: fcount += 1 fname = field.name fieldlsb = field.bits.lsb if fieldlsb > nextbit: genout(outfile, "") genout(outfile, "") genout(outfile, "") genout( outfile, "") genout(outfile, "") # Collect up any description and enum table desc_parts = [] if field.desc is not None: desc_parts += expand_paras(field.desc, rnames) if field.enum is not None: desc_parts.append('
\n' '
{comp}.{rname} @ {off:#x}
\n' '
{desc}
\n' '
Reset default = {resval:#x}, mask {mask:#x}
\n' '{wen}' '
{}
") gen_html_reg_pic(outfile, reg, width) genout(outfile, "
BitsTypeResetNameDescription
") if (nextbit == (fieldlsb - 1)): genout(outfile, str(nextbit)) else: genout(outfile, str(fieldlsb - 1) + ":" + str(nextbit)) genout(outfile, "Reserved
" + field.bits.as_str() + "" + field.swaccess.key + "" + ('x' if field.resval is None else hex(field.resval)) + "" + fname + "
') for enum in field.enum: enum_desc_paras = expand_paras(enum.desc, rnames) desc_parts.append('' '' '' '' '\n' .format(val=enum.value, name=enum.name, desc=''.join(enum_desc_paras))) desc_parts.append('
{val}{name}{desc}
') if field.has_incomplete_enum(): desc_parts.append("

Other values are reserved.

") genout(outfile, '{}'.format(''.join(desc_parts))) nextbit = fieldlsb + field.bits.width() genout(outfile, "\n
\n") def gen_html_window(outfile: TextIO, win: Window, comp: str, regwidth: int, rnames: Set[str]) -> None: wname = win.name or '(unnamed window)' offset = win.offset genout(outfile, '\n' ' \n' ' \n' ' \n' .format(comp=comp, wname=wname, lwname=wname.lower(), off=offset, items=win.items, swaccess=win.swaccess.key, byte_writes=('' if win.byte_write else 'not '))) genout(outfile, '{}'.format(render_td(win.desc, rnames, 'regde'))) genout(outfile, "
\n' '
{comp}.{wname} @ + {off:#x}
\n' '
{items} item {swaccess} window
\n' '
Byte writes are {byte_writes}supported
\n' '
') genout(outfile, '') wid = win.validbits for x in range(regwidth - 1, -1, -1): if x == regwidth - 1 or x == wid - 1 or x == 0: genout(outfile, '') else: genout(outfile, '') genout(outfile, '') tblmax = win.items - 1 for x in [0, 1, 2, tblmax - 1, tblmax]: if x == 2: genout( outfile, '') else: genout( outfile, '') if wid < regwidth: genout( outfile, '\n') genout( outfile, '\n') else: genout( outfile, '\n') genout(outfile, '') genout(outfile, '
' + str(x) + '
 ...
+' + hex(offset + x * (regwidth // 8)) + '   
') genout(outfile, '
\n
\n") def gen_html_reg_block(outfile: TextIO, rb: RegBlock, comp: str, width: int, rnames: Set[str]) -> None: for x in rb.entries: if isinstance(x, Register): gen_html_register(outfile, x, comp, width, rnames) elif isinstance(x, MultiRegister): for reg in x.regs: gen_html_register(outfile, reg, comp, width, rnames) else: assert isinstance(x, Window) gen_html_window(outfile, x, comp, width, rnames) def gen_html(block: IpBlock, outfile: TextIO) -> int: rnames = block.get_rnames() assert block.reg_blocks # Handle the case where there's just one interface if len(block.reg_blocks) == 1: rb = list(block.reg_blocks.values())[0] gen_html_reg_block(outfile, rb, block.name, block.regwidth, rnames) return 0 # Handle the case where there is more than one device interface and, # correspondingly, more than one reg block. for iface_name, rb in block.reg_blocks.items(): iface_desc = ('device interface {}'.format(iface_name) if iface_name is not None else 'the unnamed device interface') genout(outfile, '

Registers visible under {}

'.format(iface_desc)) gen_html_reg_block(outfile, rb, block.name, block.regwidth, rnames) return 0