[doc] Add autogen generator that can run commands The tool looks for: <!-- BEGIN AUTOGEN cmd --> ... <!-- END AUTOGEN --> and replaces ... with the output of `cmd`. Note that the command is executed in a shell. Signed-off-by: Amaury Pouly <amaury.pouly@lowrisc.org> Co-authored-by: Hugo McNally <hugo.mcnally@gmail.com>
diff --git a/hw/top_earlgrey/doc/design/README.md b/hw/top_earlgrey/doc/design/README.md index 8cb6fd2..fd03e15 100644 --- a/hw/top_earlgrey/doc/design/README.md +++ b/hw/top_earlgrey/doc/design/README.md
@@ -379,13 +379,141 @@ For the purpose of `top_earlgrey`, the first option has been chosen to benefit software development and testing -{{< topLevelDoc "earlgrey" "mmap" >}} +<!-- BEGIN AUTOGEN util/design/gen-top-docs.py -t hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson -g mmap --> +| Name | Type | Byte Address | +|:------------------|:--------------|:------------------| +| uart0 | uart | 0x40000000 (regs) | +| uart1 | uart | 0x40010000 (regs) | +| uart2 | uart | 0x40020000 (regs) | +| uart3 | uart | 0x40030000 (regs) | +| gpio | gpio | 0x40040000 (regs) | +| spi_device | spi_device | 0x40050000 (regs) | +| i2c0 | i2c | 0x40080000 (regs) | +| i2c1 | i2c | 0x40090000 (regs) | +| i2c2 | i2c | 0x400A0000 (regs) | +| pattgen | pattgen | 0x400E0000 (regs) | +| rv_timer | rv_timer | 0x40100000 (regs) | +| otp_ctrl | otp_ctrl | 0x40130000 (core) | +| | | 0x40132000 (prim) | +| lc_ctrl | lc_ctrl | 0x40140000 (regs) | +| alert_handler | alert_handler | 0x40150000 (regs) | +| spi_host0 | spi_host | 0x40300000 (regs) | +| spi_host1 | spi_host | 0x40310000 (regs) | +| usbdev | usbdev | 0x40320000 (regs) | +| pwrmgr_aon | pwrmgr | 0x40400000 (regs) | +| rstmgr_aon | rstmgr | 0x40410000 (regs) | +| clkmgr_aon | clkmgr | 0x40420000 (regs) | +| sysrst_ctrl_aon | sysrst_ctrl | 0x40430000 (regs) | +| adc_ctrl_aon | adc_ctrl | 0x40440000 (regs) | +| pwm_aon | pwm | 0x40450000 (regs) | +| pinmux_aon | pinmux | 0x40460000 (regs) | +| aon_timer_aon | aon_timer | 0x40470000 (regs) | +| ast | ast | 0x40480000 (regs) | +| sensor_ctrl | sensor_ctrl | 0x40490000 (regs) | +| sram_ctrl_ret_aon | sram_ctrl | 0x40500000 (regs) | +| | | 0x40600000 (ram) | +| flash_ctrl | flash_ctrl | 0x41000000 (core) | +| | | 0x41008000 (prim) | +| | | 0x20000000 (mem) | +| rv_dm | rv_dm | 0x00010000 (mem) | +| | | 0x41200000 (regs) | +| rv_plic | rv_plic | 0x48000000 (regs) | +| aes | aes | 0x41100000 (regs) | +| hmac | hmac | 0x41110000 (regs) | +| kmac | kmac | 0x41120000 (regs) | +| otbn | otbn | 0x41130000 (regs) | +| keymgr | keymgr | 0x41140000 (regs) | +| csrng | csrng | 0x41150000 (regs) | +| entropy_src | entropy_src | 0x41160000 (regs) | +| edn0 | edn | 0x41170000 (regs) | +| edn1 | edn | 0x41180000 (regs) | +| sram_ctrl_main | sram_ctrl | 0x411C0000 (regs) | +| | | 0x10000000 (ram) | +| rom_ctrl | rom_ctrl | 0x00008000 (rom) | +| | | 0x411e0000 (regs) | +| rv_core_ibex | rv_core_ibex | 0x411F0000 (cfg) | + +<!-- END AUTOGEN --> ## Hardware Interfaces ### Pinout -{{< topLevelDoc "earlgrey" "pinout" >}} +<!-- BEGIN AUTOGEN util/design/gen-top-docs.py -t hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson -g pinout --> +| ID | Name | Bank | Type | Connection Type | Description | +|:-----|:-----------------|:-------|:-------------|:------------------|:-------------------------------------------| +| 0 | POR_N | VCC | InputStd | manual | System reset | +| 1 | USB_P | VCC | DualBidirTol | manual | USB P signal | +| 2 | USB_N | VCC | DualBidirTol | manual | USB N signal | +| 3 | CC1 | AVCC | InputStd | manual | ADC input 1 | +| 4 | CC2 | AVCC | InputStd | manual | ADC input 2 | +| 5 | FLASH_TEST_VOLT | VCC | AnalogIn0 | manual | Flash test voltage input | +| 6 | FLASH_TEST_MODE0 | VCC | InputStd | manual | Flash test mode signal | +| 7 | FLASH_TEST_MODE1 | VCC | InputStd | manual | Flash test mode signal | +| 8 | OTP_EXT_VOLT | VCC | AnalogIn1 | manual | OTP external voltage input | +| 9 | SPI_HOST_D0 | VIOA | BidirStd | direct | SPI host data | +| 10 | SPI_HOST_D1 | VIOA | BidirStd | direct | SPI host data | +| 11 | SPI_HOST_D2 | VIOA | BidirStd | direct | SPI host data | +| 12 | SPI_HOST_D3 | VIOA | BidirStd | direct | SPI host data | +| 13 | SPI_HOST_CLK | VIOA | BidirStd | direct | SPI host clock | +| 14 | SPI_HOST_CS_L | VIOA | BidirStd | direct | SPI host chip select | +| 15 | SPI_DEV_D0 | VIOA | BidirStd | direct | SPI device data | +| 16 | SPI_DEV_D1 | VIOA | BidirStd | direct | SPI device data | +| 17 | SPI_DEV_D2 | VIOA | BidirStd | direct | SPI device data | +| 18 | SPI_DEV_D3 | VIOA | BidirStd | direct | SPI device data | +| 19 | SPI_DEV_CLK | VIOA | InputStd | direct | SPI device clock | +| 20 | SPI_DEV_CS_L | VIOA | InputStd | direct | SPI device chip select | +| 0 | IOA0 | VIOA | BidirStd | muxed | Muxed IO pad | +| 1 | IOA1 | VIOA | BidirStd | muxed | Muxed IO pad | +| 2 | IOA2 | VIOA | BidirStd | muxed | Muxed IO pad | +| 3 | IOA3 | VIOA | BidirStd | muxed | Muxed IO pad | +| 4 | IOA4 | VIOA | BidirStd | muxed | Muxed IO pad | +| 5 | IOA5 | VIOA | BidirStd | muxed | Muxed IO pad | +| 6 | IOA6 | VIOA | BidirOd | muxed | Muxed IO pad | +| 7 | IOA7 | VIOA | BidirOd | muxed | Muxed IO pad | +| 8 | IOA8 | VIOA | BidirOd | muxed | Muxed IO pad | +| 9 | IOB0 | VIOB | BidirStd | muxed | Muxed IO pad | +| 10 | IOB1 | VIOB | BidirStd | muxed | Muxed IO pad | +| 11 | IOB2 | VIOB | BidirStd | muxed | Muxed IO pad | +| 12 | IOB3 | VIOB | BidirStd | muxed | Muxed IO pad | +| 13 | IOB4 | VIOB | BidirStd | muxed | Muxed IO pad | +| 14 | IOB5 | VIOB | BidirStd | muxed | Muxed IO pad | +| 15 | IOB6 | VIOB | BidirStd | muxed | Muxed IO pad | +| 16 | IOB7 | VIOB | BidirStd | muxed | Muxed IO pad | +| 17 | IOB8 | VIOB | BidirStd | muxed | Muxed IO pad | +| 18 | IOB9 | VIOB | BidirOd | muxed | Muxed IO pad | +| 19 | IOB10 | VIOB | BidirOd | muxed | Muxed IO pad | +| 20 | IOB11 | VIOB | BidirOd | muxed | Muxed IO pad | +| 21 | IOB12 | VIOB | BidirOd | muxed | Muxed IO pad | +| 22 | IOC0 | VCC | BidirStd | muxed | Muxed IO pad | +| 23 | IOC1 | VCC | BidirStd | muxed | Muxed IO pad | +| 24 | IOC2 | VCC | BidirStd | muxed | Muxed IO pad | +| 25 | IOC3 | VCC | BidirStd | muxed | Muxed IO pad | +| 26 | IOC4 | VCC | BidirStd | muxed | Muxed IO pad | +| 27 | IOC5 | VCC | BidirStd | muxed | Muxed IO pad | +| 28 | IOC6 | VCC | BidirStd | muxed | Muxed IO pad | +| 29 | IOC7 | VCC | BidirStd | muxed | Muxed IO pad | +| 30 | IOC8 | VCC | BidirStd | muxed | Muxed IO pad | +| 31 | IOC9 | VCC | BidirStd | muxed | Muxed IO pad | +| 32 | IOC10 | VCC | BidirOd | muxed | Muxed IO pad | +| 33 | IOC11 | VCC | BidirOd | muxed | Muxed IO pad | +| 34 | IOC12 | VCC | BidirOd | muxed | Muxed IO pad | +| 35 | IOR0 | VCC | BidirStd | muxed | Muxed IO pad | +| 36 | IOR1 | VCC | BidirStd | muxed | Muxed IO pad | +| 37 | IOR2 | VCC | BidirStd | muxed | Muxed IO pad | +| 38 | IOR3 | VCC | BidirStd | muxed | Muxed IO pad | +| 39 | IOR4 | VCC | BidirStd | muxed | Muxed IO pad | +| 40 | IOR5 | VCC | BidirStd | muxed | Muxed IO pad | +| 41 | IOR6 | VCC | BidirStd | muxed | Muxed IO pad | +| 42 | IOR7 | VCC | BidirStd | muxed | Muxed IO pad | +| 21 | IOR8 | VCC | BidirOd | direct | Dedicated sysrst_ctrl output (ec_rst_l) | +| 22 | IOR9 | VCC | BidirOd | direct | Dedicated sysrst_ctrl output (flash_wp_l)) | +| 43 | IOR10 | VCC | BidirOd | muxed | Muxed IO pad | +| 44 | IOR11 | VCC | BidirOd | muxed | Muxed IO pad | +| 45 | IOR12 | VCC | BidirOd | muxed | Muxed IO pad | +| 46 | IOR13 | VCC | BidirOd | muxed | Muxed IO pad | + +<!-- END AUTOGEN --> # RTL Implementation Notes
diff --git a/util/autogen_md.py b/util/autogen_md.py new file mode 100755 index 0000000..e68bf30 --- /dev/null +++ b/util/autogen_md.py
@@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Go through all markdown files and autogenerate content based on commands +recorded in the file. +""" + +import sys +from pathlib import Path +import re +import subprocess +import argparse +import os +from typing import Callable + +START_MARKER_PATTERN = re.compile(r"\n<!--\s*BEGIN\s*AUTOGEN\s*(?P<cmd>.+)\s*-->\n") +END_MARKER_PATTERN = re.compile(r"\n<!--\s*END\s*AUTOGEN\s*-->\n") + + +def apply_to_all_files(path: Path, fn: Callable[[Path], None]): + for child in path.iterdir(): + if child.is_file(): + fn(child) + if child.is_dir(): + apply_to_all_files(child, fn) + + +def autogen_rewrite_md(filepath: Path, dry_run: bool): + # only consider .md files + if not filepath.name.endswith(".md"): + return + content = filepath.read_text() + modified = False + pos = 0 + while True: + # search next start marker + match_start = START_MARKER_PATTERN.search(content, pos) + if match_start is None: + # no more replacements to do + break + cmd = match_start.group('cmd').strip() + # search end marker after the start marker + match_end = END_MARKER_PATTERN.search(content, pos) + if match_end is None: + sys.exit(f"Error in {filepath}: start marker with command '{cmd}' without end marker") + + print(f"In {filepath}: running '{cmd}'") + if dry_run: + # don't run + pos = match_end.end(0) + continue + res = subprocess.run(cmd, shell=True, capture_output=True) + if res.stderr: + print( + f"The command '{cmd}' output " + f"the following error messages:\n{res.stderr.decode()}" + ) + if res.returncode != 0: + sys.exit(f"The command '{cmd}' had a non-zero return code.") + + new_content = res.stdout.decode() + # replace content + content = content[0:match_start.end(0)] + new_content + content[match_end.start(0):] + modified = True + # resume after end line, adjust for new content size + pos = match_end.end(0) + len(new_content) - (match_end.start(0) - match_start.end(0)) + # write back + if modified: + filepath.write_text(content) + + +def main(args: argparse.Namespace): + this_file_path = Path(__file__) + repo_root = this_file_path.parent.parent.resolve() + os.chdir(repo_root) + apply_to_all_files(repo_root, lambda x: autogen_rewrite_md(x, args.dry_run)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--dry-run", + help = "print commands to execute but do not execute them", + action="store_true") + args = parser.parse_args() + main(args)
diff --git a/util/design/gen-top-docs.py b/util/design/gen-top-docs.py index 784a712..5cceed5 100755 --- a/util/design/gen-top-docs.py +++ b/util/design/gen-top-docs.py
@@ -4,9 +4,9 @@ # SPDX-License-Identifier: Apache-2.0 r"""Generates top level documentation from an hjson configuration file.""" +import sys import argparse import logging as log -from pathlib import Path import hjson from lib import common @@ -72,40 +72,30 @@ description=common.wrapped_docstring(), formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument("--topcfg", - "-t", - required=True, - help="Topgen generated config file `top_{name}.hjson`.") parser.add_argument( - "--outdir", - "-o", - help="Target TOP documentation directory.") - + "--topcfg", + "-t", + required=True, + help="Topgen generated config file `top_{name}.hjson`.", + ) + parser.add_argument( + "--generator", + "-g", + help="Select generator", + ) args = parser.parse_args() + gen = args.generator - outdir = Path(args.outdir) - - doc_generators = [ - { - "filename": "mmap.md", - "generator": generate_mmap_table, - }, - { - "filename": "pinout.md", - "generator": generate_pinout_table, - }, - ] - + doc_generators = { + "mmap": generate_mmap_table, + "pinout": generate_pinout_table, + } with open(args.topcfg, 'r') as infile: top_level = hjson.load(infile) - top_outdir = outdir / top_level["name"] - top_outdir.mkdir(parents=True, exist_ok=True) + if gen not in doc_generators: + sys.exit(f"Unknown generator {gen}") - for doc in doc_generators: - outfile = top_outdir / doc["filename"] - table = doc["generator"](top_level) - with open(outfile, 'w') as f: - f.write(to_markdown(table)) + print(doc_generators[gen](top_level)) if __name__ == "__main__":
diff --git a/util/reggen/README.md b/util/reggen/README.md index 1c84eab..b13a1a6 100644 --- a/util/reggen/README.md +++ b/util/reggen/README.md
@@ -29,7 +29,344 @@ For more detail on the non-register entries of the Hjson configuration file, see [this section](../../doc/contributing/hw/comportability/README.md#configuration-description-hjson) of the Comportability Specification. -{{% selfdoc "reggen" %}} +<!-- BEGIN AUTOGEN python3 util/selfdoc.py reggen --> + + +<!-- Start of output generated by `regtool.py --doc` --> + +The tables describe each key and the type of the value. The following +types are used: + +Type | Description +---- | ----------- +int | integer (binary 0b, octal 0o, decimal, hex 0x) +xint | x for undefined otherwise int +bitrange | bit number as decimal integer, or bit-range as decimal integers msb:lsb +list | comma separated list enclosed in `[]` +name list | comma separated list enclosed in `[]` of one or more groups that have just name and dscr keys. e.g. `{ name: "name", desc: "description"}` +name list+ | name list that optionally contains a width +parameter list | parameter list having default value optionally +group | comma separated group of key:value enclosed in `{}` +list of group | comma separated group of key:value enclosed in `{}` the second entry of the list is the sub group format +string | string, typically short +text | string, may be multi-line enclosed in `'''` may use `**bold**`, `*italic*` or `!!Reg` markup +tuple | tuple enclosed in () +python int | Native Python type int (generated) +python Bool | Native Python type Bool (generated) +python list | Native Python type list (generated) +python enum | Native Python type enum (generated) + + +Register fields are tagged using the swaccess key to describe the +permitted access and side-effects. This key must have one of these +values: + + +Key | Description +--- | ----------- +none | No access +ro | Read Only +rc | Read Only, reading clears +rw | Read/Write +r0w1c | Read zero, Write with 1 clears +rw1s | Read, Write with 1 sets +rw1c | Read, Write with 1 clears +rw0c | Read, Write with 0 clears +wo | Write Only + + +Register fields are tagged using the hwaccess key to describe the +permitted access from hardware logic and side-effects. This key must +have one of these values: + + +Key | Description +--- | ----------- +hro | Read Only +hrw | Read/Write +hwo | Write Only +none | No Access Needed + + +The top level of the JSON is a group containing the following keys: + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +name | required | string | name of the component +clocking | required | list | clocking for the device +bus_interfaces | required | list | bus interfaces for the device +registers | required | list | list of register definition groups and offset control groups +one_line_desc | optional | string | one-line description of the component +one_paragraph_desc | optional | string | one-paragraph description of the component +revisions | optional | list | list with revision records +design_spec | optional | string | path to the design specification, relative to repo root +dv_doc | optional | string | path to the DV document, relative to repo root +hw_checklist | optional | string | path to the hw_checklist, relative to repo root +sw_checklist | optional | string | path to the sw_checklist, relative to repo root +design_stage | optional | string | design stage of module +dif_stage | optional | string | DIF stage of module +verification_stage | optional | string | verification stage of module +notes | optional | string | random notes +version | optional | string | module version +life_stage | optional | string | life stage of module +commit_id | optional | string | commit ID of last stage sign-off +alert_list | optional | name list+ | list of peripheral alerts +available_inout_list | optional | name list+ | list of available peripheral inouts +available_input_list | optional | name list+ | list of available peripheral inputs +available_output_list | optional | name list+ | list of available peripheral outputs +expose_reg_if | optional | python Bool | if set, expose reg interface in reg2hw signal +interrupt_list | optional | name list+ | list of peripheral interrupts +inter_signal_list | optional | list | list of inter-module signals +no_auto_alert_regs | optional | string | Set to true to suppress automatic generation of alert test registers. Defaults to true if no alert_list is present. Otherwise this defaults to false. +no_auto_intr_regs | optional | string | Set to true to suppress automatic generation of interrupt registers. Defaults to true if no interrupt_list is present. Otherwise this defaults to false. +param_list | optional | parameter list | list of parameters of the IP +regwidth | optional | int | width of registers in bits (default 32) +reset_request_list | optional | list | list of signals requesting reset +scan | optional | python Bool | Indicates the module have `scanmode_i` +scan_reset | optional | python Bool | Indicates the module have `scan_rst_ni` +scan_en | optional | python Bool | Indicates the module has `scan_en_i` +SPDX-License-Identifier | optional | string | License ientifier (if using pure json) Only use this if unable to put this information in a comment at the top of the file. +wakeup_list | optional | name list+ | list of peripheral wakeups +countermeasures | optional | name list | list of countermeasures in this block + +The basic structure of a register definition file is thus: + +```hjson +{ + name: "GP", + regwidth: "32", + registers: [ + // register definitions... + ] +} + +``` + + + +The list of registers includes register definition groups containing the following keys: + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +name | required | string | name of the register +desc | required | text | description of the register. This field supports the markdown syntax. +fields | required | list | list of register field description groups +alias_target | optional | string | name of the register to apply the alias definition to. +async | optional | string | indicates the register must cross to a different clock domain before use. The value shown here should correspond to one of the module's clocks. +sync | optional | string | indicates the register needs to be on another clock/reset domain.The value shown here should correspond to one of the module's clocks. +swaccess | optional | string | software access permission to use for fields that don't specify swaccess +hwaccess | optional | string | hardware access permission to use for fields that don't specify hwaccess +hwext | optional | string | 'true' if the register is stored outside of the register module +hwqe | optional | string | 'true' if hardware uses 'q' enable signal, which is latched signal of software write pulse. +hwre | optional | string | 'true' if hardware uses 're' signal, which is latched signal of software read pulse. +regwen | optional | string | if register is write-protected by another register, that register name should be given here. empty-string for no register write protection +resval | optional | int | reset value of full register (default 0) +tags | optional | string | tags for the register, following the format 'tag_name:item1:item2...' +shadowed | optional | string | 'true' if the register is shadowed +update_err_alert | optional | string | alert that will be triggered if this shadowed register has update error +storage_err_alert | optional | string | alert that will be triggered if this shadowed register has storage error + + +The basic register definition group will follow this pattern: + +```hjson + { name: "REGA", + desc: "Description of register", + swaccess: "rw", + resval: "42", + fields: [ + // bit field definitions... + ] + } +``` + +The name and brief description are required. If the swaccess key is +provided it describes the access pattern that will be used by all +bitfields in the register that do not override with their own swaccess +key. This is a useful shortcut because in most cases a register will +have the same access restrictions for all fields. The reset value of +the register may also be provided here or in the individual fields. If +it is provided in both places then they must match, if it is provided +in neither place then the reset value defaults to zero for all except +write-only fields when it defaults to x. + + + +In the fields list each field definition is a group itself containing the following keys: + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +bits | required | bitrange | bit or bit range (msb:lsb) +name | optional | string | name of the field +desc | optional | text | description of field (required if the field has a name). This field supports the markdown syntax. +alias_target | optional | string | name of the field to apply the alias definition to. +swaccess | optional | string | software access permission, copied from register if not provided in field. (Tool adds if not provided.) +hwaccess | optional | string | hardware access permission, copied from register if not provided in field. (Tool adds if not provided.) +hwqe | optional | bitrange | 'true' if hardware uses 'q' enable signal, which is latched signal of software write pulse. Copied from register if not provided in field. (Tool adds if not provided.) +resval | optional | xint | reset value, comes from register resval if not provided in field. Zero if neither are provided and the field is readable, x if neither are provided and the field is wo. Must match if both are provided. +enum | optional | list | list of permitted enumeration groups +tags | optional | string | tags for the field, followed by the format 'tag_name:item1:item2...' +mubi | optional | bitrange | boolean flag for whether the field is a multi-bit type +auto_split | optional | bitrange | boolean flag which determines whether the field should be automatically separated into 1-bit sub-fields.This flag is used as a hint for automatically generated software headers with register description. + + +Field names should be relatively short because they will be used +frequently (and need to fit in the register layout picture!) The field +description is expected to be longer and will most likely make use of +the Hjson ability to include multi-line strings. An example with three +fields: + +```hjson + fields: [ + { bits: "15:0", + name: "RXS", + desc: ''' + Last 16 oversampled values of RX. These are captured at 16x the baud + rate clock. This is a shift register with the most recent bit in + bit 0 and the oldest in bit 15. Only valid when ENRXS is set. + ''' + } + { bits: "16", + name: "ENRXS", + desc: ''' + If this bit is set the receive oversampled data is collected + in the RXS field. + ''' + } + {bits: "20:19", name: "TXILVL", + desc: "Trigger level for TX interrupts", + resval: "2", + enum: [ + { value: "0", name: "txlvl1", desc: "1 character" }, + { value: "1", name: "txlvl4", desc: "4 characters" }, + { value: "2", name: "txlvl8", desc: "8 characters" }, + { value: "3", name: "txlvl16", desc: "16 characters" } + ] + } + ] +``` + +In all of these the swaccess parameter is inherited from the register +level, and will be added so this key is always available to the +backend. The RXS and ENRXS will default to zero reset value (unless +something different is provided for the register) and will have the +key added, but TXILVL expicitly sets its reset value as 2. + +The missing bits 17 and 18 will be treated as reserved by the tool, as +will any bits between 21 and the maximum in the register. + +The TXILVL is an example using an enumeration to specify all valid +values for the field. In this case all possible values are described, +if the list is incomplete then the field is marked with the rsvdenum +key so the backend can take appropriate action. (If the enum field is +more than 7 bits then the checking is not done.) + + + +Definitions in an enumeration group contain: + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +name | required | string | name of the member of the enum +desc | required | text | description when field has this value +value | required | int | value of this member of the enum + + +The list of registers may include single entry groups to control the offset, open a window or generate registers: + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +reserved | optional | int | number of registers to reserve space for +skipto | optional | int | set next register offset to value +window | optional | group | group defining an address range for something other than standard registers +multireg | optional | group | group defining registers generated from a base instance. + + + + +Registers can protect themselves from software writes by using the +register attribute regwen. When not an emptry string (the default +value), regwen indicates that another register must be true in order +to allow writes to this register. This is useful for the prevention +of software modification. The register-enable register (call it +REGWEN) must be one bit in width, and should default to 1 and be rw1c +for preferred security control. This allows all writes to proceed +until at some point software disables future modifications by clearing +REGWEN. An error is reported if REGWEN does not exist, contains more +than one bit, is not `rw1c` or does not default to 1. One REGWEN can +protect multiple registers. The REGWEN register must precede those +registers that refer to it in the .hjson register list. An example: + +```hjson + { name: "REGWEN", + desc: "Register write enable for a bank of registers", + swaccess: "rw1c", + fields: [ { bits: "0", resval: "1" } ] + } + { name: "REGA", + swaccess: "rw", + regwen: "REGWEN", + ... + } + { name: "REGB", + swaccess: "rw", + regwen: "REGWEN", + ... + } +``` + + +A window defines an open region of the register space that can be used +for things that are not registers (for example access to a buffer ram). + + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +name | required | string | name of the window +desc | required | text | description of the window +items | required | int | size in fieldaccess width words of the window +swaccess | required | string | software access permitted +data-intg-passthru | optional | string | True if the window has data integrity pass through. Defaults to false if not present. +byte-write | optional | string | True if byte writes are supported. Defaults to false if not present. +validbits | optional | int | Number of valid data bits within regwidth sized word. Defaults to regwidth. If smaller than the regwidth then in each word of the window bits [regwidth-1:validbits] are unused and bits [validbits-1:0] are valid. +unusual | optional | string | True if window has unusual parameters (set to prevent Unusual: errors).Defaults to false if not present. + + +The multireg expands on the register required fields and will generate +a list of the generated registers (that contain all required and +generated keys for an actual register). + + +Key | Kind | Type | Description of Value +--- | ---- | ---- | -------------------- +name | required | string | base name of the registers +desc | required | text | description of the registers +count | required | string | number of instances to generate. This field can be integer or string matching from param_list. +cname | required | string | base name for each instance, mostly useful for referring to instance in messages. +fields | required | list | list of register field description groups. Describes bit positions used for base instance. +alias_target | optional | string | name of the register to apply the alias definition to. +async | optional | string | indicates the register must cross to a different clock domain before use. The value shown here should correspond to one of the module's clocks. +sync | optional | string | indicates the register needs to be on another clock/reset domain.The value shown here should correspond to one of the module's clocks. +swaccess | optional | string | software access permission to use for fields that don't specify swaccess +hwaccess | optional | string | hardware access permission to use for fields that don't specify hwaccess +hwext | optional | string | 'true' if the register is stored outside of the register module +hwqe | optional | string | 'true' if hardware uses 'q' enable signal, which is latched signal of software write pulse. +hwre | optional | string | 'true' if hardware uses 're' signal, which is latched signal of software read pulse. +regwen | optional | string | if register is write-protected by another register, that register name should be given here. empty-string for no register write protection +resval | optional | int | reset value of full register (default 0) +tags | optional | string | tags for the register, following the format 'tag_name:item1:item2...' +shadowed | optional | string | 'true' if the register is shadowed +update_err_alert | optional | string | alert that will be triggered if this shadowed register has update error +storage_err_alert | optional | string | alert that will be triggered if this shadowed register has storage error +regwen_multi | optional | python Bool | If true, regwen term increments along with current multireg count. +compact | optional | python Bool | If true, allow multireg compacting.If false, do not compact. +cdc | optional | string | indicates the register must cross to a different clock domain before use. The value shown here should correspond to one of the module's clocks. + + +(end of output generated by `regtool.py --doc`) + + +<!-- END AUTOGEN --> The tool will normally generate the register address offset by starting from 0 and allocating the registers in the order they are in the input file. Between each register the offset is incremented by the number of bytes in the `regwidth` (4 bytes for the default 32-bit `regwidth`), so the registers end up packed into the smallest space.
diff --git a/util/selfdoc.py b/util/selfdoc.py new file mode 100755 index 0000000..d67ec3a --- /dev/null +++ b/util/selfdoc.py
@@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import sys +import reggen.gen_selfdoc as reggen_selfdoc +import tlgen +from typing import TextIO + + +def generate_selfdocs(tool: str, fout: TextIO): + """Generate documents for the tools in `util/` + + Each tool creates selfdoc differently. Manually invoked. + """ + if tool == "reggen": + reggen_selfdoc.document(fout) + elif tool == "tlgen": + fout.write(tlgen.selfdoc(heading=3, cmd='tlgen.py --doc')) + else: + sys.exit(f"unknown tool \"{tool}\"") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.exit("usage: selfdoc <tool>") + # running this file as standalone prints the documentation + generate_selfdocs(sys.argv[1], sys.stdout)
diff --git a/util/tlgen/README.md b/util/tlgen/README.md index c050275..e52cbe3 100644 --- a/util/tlgen/README.md +++ b/util/tlgen/README.md
@@ -53,7 +53,88 @@ *Optional* keys may be provided in the input files. The tool also may insert the optional keys with default value. -{{% selfdoc "tlgen" %}} +<!-- BEGIN AUTOGEN python3 util/selfdoc.py tlgen --> + + +The tables describe each key and the type of the value. The following +types are used: + +Type | Description +---- | ----------- +int | integer (binary 0b, octal 0o, decimal, hex 0x) +xint | x for undefined otherwise int +bitrange | bit number as decimal integer, or bit-range as decimal integers msb:lsb +list | comma separated list enclosed in `[]` +name list | comma separated list enclosed in `[]` of one or more groups that have just name and dscr keys. e.g. `{ name: "name", desc: "description"}` +name list+ | name list that optionally contains a width +parameter list | parameter list having default value optionally +group | comma separated group of key:value enclosed in `{}` +list of group | comma separated group of key:value enclosed in `{}` the second entry of the list is the sub group format +string | string, typically short +text | string, may be multi-line enclosed in `'''` may use `**bold**`, `*italic*` or `!!Reg` markup +tuple | tuple enclosed in () +python int | Native Python type int (generated) +python Bool | Native Python type Bool (generated) +python list | Native Python type list (generated) +python enum | Native Python type enum (generated) +### Top configuration + + +Crossbar configuration format. + + + +Field | Kind | Type | Description +----- | ---- | ---- | ------------ +name | required | string | Name of the crossbar +clock | required | string | Main clock. Internal components use this clock. If not specified, it is assumed to be in main clock domain +reset | required | string | Main reset +connections | required | group | List of edge. Key is host, entry in value list is device +clock_connections | required | group | list of clocks +nodes | required | list of group | List of nodes group +type | optional | string | Indicate Hjson type. "xbar" always if exist +clock_group | optional | string | Remnant from auto-generation scripts. Ignore. +clock_srcs | optional | group | Remnant from auto-generation scripts. Ignore. +domain | optional | string | Power domain for the crossbar +reset_connections | added by tool | group | Generated by topgen. Key is the reset signal inside IP and value is the top reset signal + + +### Node configuration + + +Crossbar node description. It can be host, device, or internal nodes. + + + +Field | Kind | Type | Description +----- | ---- | ---- | ------------ +name | required | string | Module instance name +stub | required | python Bool | Real node or stub. Stubs only occupy address ranges +type | required | string | Module type: {"host", "device", "async", "socket_1n", "socket_m1"} +clock | optional | string | main clock of the port +reset | optional | string | main reset of the port +pipeline | optional | python Bool | If true, pipeline is added in front of the port +req_fifo_pass | optional | python Bool | If true, pipeline fifo has passthrough behavior on req +rsp_fifo_pass | optional | python Bool | If true, pipeline fifo has passthrough behavior on rsp +inst_type | optional | string | Instance type +xbar | optional | python Bool | If true, the node is connected to another Xbar +addr_range | optional | list of group | List of addr_range group + + +### Address configuration + +Device Node address configuration. It contains the base address and the size in bytes. + + + +Field | Kind | Type | Description +----- | ---- | ---- | ------------ +base_addr | required | int | Base address of the device. It is required for the device +size_byte | required | int | Memory space of the device. It is required for the device + + + +<!-- END AUTOGEN --> ## Fabrication process