Top Generation Tool
The top generation tool, topgen.py, is used to build top modules - for example, top_egret.
Currently, as part of this generation process, the following top-specific modules are created
- Overall top module
- Crossbars
- A number of templated peripherals, which are expanded according to top specific configurations This document explains the overall generation process, the required inputs, the output locations, as well as how the tool should be invoked.
Topgen relies on a number of other tools and libraries within ACE as well, so it would be wise to refer to their respective sets of documentation as well.
ipgen’s documentation provides information on how to handle IP templates.regtool/reggen’s documentation provides information on how to specify individual IP blocks and their registers, and valid data types.tlgen’s documentation provides information on how to specify and generate TL-UL crossbars.
Generation Process
Overview
The details of a particular top variant are described in a top-specific Hjson file.
For example see top_egret.
For detailed information about how the top Hjson should be written, see the Top Hjson Schema section of this document.
The top specific Hjson describes how the design looks and how it should connect, for example:
- Overall fabric data width
- Clock sources
- Reset sources
- Address spaces
- List of instantiated peripherals
- Module type of each peripheral (it is possible to have multiple instantiations of a particular module)
- Clock / reset connectivity of each peripheral
- Base address of each peripheral for each connected address space
- List of instantiated crossbars
- System memories
- Fabric construction
- Clock / reset connectivity of each fabric component
- Interrupt sources
- Pinmux construction
- List of dedicated or muxed pins
The top level Hjson however, does not contain details such as:
- Specific clock / reset port names for each peripheral
- Number of interrupts in each peripheral
- Number of input or output pins in each peripheral
- Details of crossbar connection and which host can reach which device
There are two kinds of peripherals:
- Generic peripherals, which are the same for any top configuration
- Ipgen peripherals, which have a set of template files, and are expanded based on top-specific parameters
The topgen tool thus hierarchically gathers and generates the missing information from additional Hjson files that describe the detail of each component. These are primarily located in the following places:
hw/ip/*/data/*.hjsonfor generic peripheralshw/ip_templates/*/data/*.hjson.tplfor ipgen peripherals (during top generation, these Hjson templates are used to generatehw/top_*/ip_autogen/*/data/*.hjson)hw/top_*/data/xbar_*.hjsonfor crossbars which are also generated from templateshw/top_*/ip/*/data/*.hjsonfor manually written (ie., non-ipgen) top-specific peripherals
In the process of gathering, each individual Hjson file is validated for input correctness and then merged into a final generated Hjson output that represents the complete information that makes up each design.
For example, see top_egret’s complete configuration.
Note specifically the generated interrupt list, the pinmux connections, and the port-to-net mapping of clocks and resets, all of which were not present in the original input.
The purpose for this two step process, instead of describing the design completely inside one Hjson file, is to decouple the top and components development while allowing re-use of components by multiple tops.
This process also clearly separates what information needs to be known by top vs. what needs to be known by a specific component.
For example, a component does not need to know how many clock sources a top has or how many muxed pins it contains.
Likewise, the top does not need to know the details of why an interrupt is generated, just how many there are.
The user supplied top_*.hjson thus acts like a integration specification while the remaining details are filled in through lower level inputs.
In addition to design collateral, the tool also generates all the top level RAL (Register Abstraction Layer) models necessary for verification.
Validation, Merge and Output
As stated previously, each of the gathered component Hjson files is validated for correctness.
For the peripherals, this is done by invoking util/reggen/validate.py, while the xbar components are validated through util/tlgen/validate.py.
The peripheral and xbar components are then validated through util/topgen/validate.py.
Topgen’s validation also performs extensive checks on the top configuration; for example on interrupts, pinmuxes, clocks, and reset consistency.
Once all validation is passed, the final Hjson is created by util/topgen/merge.py.
This Hjson is then used to generate the final top RTL and/or other selected outputs.
As part of this process, topgen invokes other tools.
Please see the documentation for ipgen, reggen, and tlgen for more tool-specific details.
Generation Flow
In order to generate the complete set of artifacts for a given top, the first step is to generate the complete top configuration file (named top_*/data/autogen/top_*.gen.hjson as mentioned above).
Most other artifacts, like the top-level module(s), ipgen peripherals, and top-level SV and software collateral require this file for generation.
These artifacts can be generated independently after the complete top configuration is created.
Generating the Complete Top Configuration
The generation of ipgen peripherals is delicate since they depend on each other. All these dependencies are captured in the top configuration as it is completed. As ipgen peripherals are expanded, they provide information that will be used for expanding other ipgen peripherals. This means the order in which ipgen peripherals are expanded needs to be carefully chosen in order to avoid divergent/inconsistent generation results. The top configuration is completed progressively as individual peripherals are processed. All this is done in-memory, and the individual peripherals are added in the following order:
- The generic peripherals
- The ipgen peripherals, topologically sorted based on their inter-dependencies
- The crossbars
It is important to progressively complete the top config with the most up-to-date data specific to each ipgen peripheral before expanding it.
The completion is done using functions that are called in merge_top, except they get an extra argument to allow incomplete configuration since not all ipgen peripherals will have been expanded.
Once all ipgen peripherals are expanded, one last merge is performed, with incomplete configurations causing an error.
To make sure there are no mistakes in the order of ipgen peripherals, the expansion can make multiple generation passes, stopping when the complete top configuration is stable.
Only one pass will be required when the order in which ipgen peripherals are generated is right.
Generating other Artifacts
From the complete top configuration Hjson (sometimes along with a top secrets configuration), other tools can generate other top-relevant assets.
Tools that use the complete top config include:
util/gen_top_ral.py: generates the top level’s RAL modelutil/top_cm_and_blocks.py: depending on subcommand used, either checks countermeasures of a top’s IPs or lists which blocks are present within a top level- This script’s list of blocks can be fed to regtool to generate the IP block registers
util/gen_top_ipconfigs.py: creates IP configuration Hjson files that can be used to generate templated IPs or crossbars from top level information- ipgen and tlgen can use the output of this script to generate IP templates and TL-UL crossbars (respectively)
util/gen_top_docs.py: generates top level’s pinmux and target documentationutil/gen_top_sw.py: generates the software (C, Rust, Bazel) files for a top levelutil/gen_top_sv.py: generates the SystemVerilog files associated with a top level design
Usage
The most generic use of topgen is to let it generate everything.
This can be done through direct invocation, or the ${REPO_TOP}/hw makefile.
The example below shows the latter:
cd ${REPO_TOP}
make -C hw top
Another means of generating the complete config with topgen is by invoking it through Bazel.
Each top can make use of its gen_completecfg target in order to regenerate it:
./bazelisk.sh run //hw/top_dragonfly/data:gen_completecfg
It is possible to restrict what the tool should generate.
$ util/topgen.py --help
usage: topgen [-h] --topcfg TOPCFG --seedcfg SEEDCFG [--outdir OUTDIR]
[--hjson-path HJSON_PATH] [--verbose]
[--version-stamp VERSION_STAMP]
[--alias-files ALIAS_FILES [ALIAS_FILES ...]]
options:
-h, --help show this help message and exit
--topcfg TOPCFG, -t TOPCFG
`top_{name}.hjson` file.
--seedcfg SEEDCFG, -s SEEDCFG
top_{name} seed configuration file.
--outdir OUTDIR, -o OUTDIR
Target TOP directory. Module is created under rtl/.
(default: dir(topcfg)/..)
--hjson-path HJSON_PATH
If defined, topgen uses supplied path to search for ip
hjson. This applies only to ip's with the
`reggen_only` attribute. If an hjson is located both
in the conventional path and the alternate path, the
alternate path has priority.
--verbose, -v Verbose
--version-stamp VERSION_STAMP
If version stamping, the location of workspace version
stamp file.
--alias-files ALIAS_FILES [ALIAS_FILES ...]
If defined, topgen uses supplied alias hjson file(s)
to override the generic register definitions when
building the RAL model. This argument is only relevant
in conjunction with the `--top_ral` switch.
Top Hjson Schema
Top Configuration
Configuration options for creating a top with ACE
Properties
name(string, required): Top name.type(string, required): type of hjson. Shall be ‘top’ always. Must be one of:["top"].datawidth(integer): default data width.racl_config(string): Path to a RACL configuration HJSON file.power(object): power domains supported by the design.unmanaged_clocks(array, required): list of unmanaged external clocks.clocks(object, required): group of clock properties.resets(object, required): list of resets.reset_requests: define reset requests grouped by type. Refer to urn:topgen:reset_requests.num_cores(integer): number of computing units.default_plic(string): Modules not defining plic have interrupts sent here.default_alert_handler(string): Modules not defining alert_handler have alerts sent here.addr_spaces(array, required): list of address spaces.module(array, required): list of modules to instantiate.- Items: Refer to urn:topgen:module.
port(array): assign special attributes to specific ports.inter_module(object): define the signal connections between the modules.xbar(array, required): list of the xbars used in the top.pinout: pinout configuration. Refer to urn:topgen:pinout.pinmux: pinmux configuration. Refer to urn:topgen:pinmux.targets(array, required): target configurations.- Items: Refer to urn:topgen:target.
incoming_alert(object): Parsed incoming alerts; added property.incoming_interrupt(object): Parsed incoming interrupts; added property.exported_clks(object): clock signal routing rules; added property.racl(object): the expansion of the racl_config file; added property.wakeups(array): list of wakeup requests each holding name, width, and module; added property.- Items: Refer to urn:topgen:wakeup.
unmanaged_resets(array): List of unmanaged external resets; added property.exported_rsts(object): external resets grouped by each module’sclock_reset_exportfield; added property.alert(array): alerts; added property.- Items: Refer to urn:topgen:alert.
outgoing_alert(object): the outgoing alert groups; added property.interrupt(array): interrupts; added property.- Items: Refer to urn:topgen:interrupt.
outgoing_interrupt(object): the outgoing interrupt groups; added property.alert_module(array): list of the modules that connects to alert_handler; added property.alert_connections(object)interrupt_module(array): list of the modules that connects to rv_plic; added property.outgoing_alert_module(object): added property.outgoing_interrupt_module(object): added property.alert_lpgs(array): added property.outgoing_alert_lpgs(object): added property.inter_signal(object): added property.
The top configuration partially specifies its list of modules.
Module
Hardware module within a top level
Properties
name(string, required): name of the instance.type(string, required): comportable IP type.template_type(string): Base template type of ipgen IPs.clock_srcs(object, required): dict with clock sources.clock_group(string, required): clock group.reset_connections(object, required): dict with reset sources.clock_connections(object): generated clock connections; added property.domain(array): optional list of power domains, defaults to the top config’s default power domain.clock_reset_export(array): optional list with prefixes for exported clocks and resets at the chip level.base_addr(object): dict of address space mapped to the corresponding hex start address of the peripheral (if the IP has only a single TL-UL interface).base_addrs(object): hex start addresses of the peripheral (if the IP has multiple TL-UL interfaces).memory(object): optional dict with memory region attributes..*: Refer to urn:topgen:memory.
otp_map(object): OTP Map information for OTP Ctrl.otp_mmap(object): Full OTP memory map configuration with secret parameters; added property.ipgen_params(object): Optional ipgen parameters for that instance.param_decl(object): optional dict that allows to override instantiation parameters.param_list(array): list of parameters; added property.- Items: Refer to urn:topgen:parameter.
inter_signal_list(array): generated signal information; added property.- Items: Refer to urn:topgen:inter_signal.
generate_dif(boolean): optional bool to indicate if a DIF should be generated for that module.racl_group(string): Only valid for racl_ctrl IPs. Defines the RACL group this control IP is associated to.racl_mappings(object): dict that maps an interface to its associated RACL mapping.racl_mapping(string): A special case of racl_mappings. If specified, this is taken to represent a dict that associates all interfaces with the given mapping. It is an error to specify both this and racl_mappings.attr(string): optional attribute indicating whether the IP is ‘ipgen’, ‘reggen_top’, or ‘reggen_only’. Must be one of:["ipgen", "reggen_top", "reggen_only"].targets(array): Optional list of targets for this PLIC.plic(string): Interrupt controller managing this module’s interrupts.alert_handler(string): Alert handler managing this module’s alerts.outgoing_alert(string): optional string to indicate alerts are routed externally to the named group.outgoing_interrupt(string): optional string to indicate interrupts are routed externally to the named group.incoming_alert(array): optional list of paths to incoming alert configurations for the alert_handler.incoming_interrupt(object): Parsed incoming interrupts; added property.
Tops must also come with a seed configuration Hjson.
Seed Configuration
Configuration options for random seeds
Properties
name(string, required): name of top for seeding.topgen_seed(integer, required): seed for topgen generated random netlist constants.otp_img_seed(integer): Seed for OTP image generation.lc_ctrl_seed(integer): Seed for lc_ctrl generated random netlist constants.
Other schemas
Alert
Alert description
Properties
name(string, required): name of the alert signal.width(integer, required): the number of alerts in this signal, typically 1.type(string): should contain ‘alert’.async(boolean, required): alert is asynchronous.handler(string, required): alert handler managing this alert.module_name(string, required): The module name of the source.desc(string): the description of the alert.lpg_name(string): the low power group of the alert.lpg_idx(integer): the index in the lpg group.
Eflash
Flash memory configuration
Properties
type(string, required): string indicating type of memory.banks(integer, required): number of flash banks.pages_per_bank(integer, required): number of data pages per flash bank.program_resolution(integer, required): maximum number of flash words allowed to program at a time.words_per_page(integer, required): number of words per page.data_width(integer, required): number of bits per data word.integrity_width(integer, required): number of integrity bits per data word.info_types(integer, required): number of different info page types.infos_per_bank(array, required): number of pages per info type, the size of the list must match ‘info_types’.
Inter-Module Signal
Configuration of direct signal between IP blocks
Properties
name(string, required): the name of the signal.desc(string): the inter signal description.struct(string, required): the data type of the signal.package(string): the package declaring the struct.type(string, required): whether the signal is unidirectional or part of a request-response pair.act(string, required): whether it is a request (req) or a response (rsp).inst_name(string): the instance this signal connects to.width([‘integer’, ‘string’], required): the number of items of the signal for arrays.default(string): default signal value; added property.end_idx(integer): end index of req_rsp connection (not using full width); added property.top_signame(string): name of the signal within the top SV file; added property.index(integer): the index when this is connected to an array; added property.
Interrupt
Interrupt signal description
Properties
name(string, required): the name of the interrupt.width(integer, required): the number of interrupts in this signal, typically 1.type(string): should contain ‘interrupt’.module_name(string, required): The module name of the source.desc(string): the description of the interrupt.intr_type([‘string’, ‘integer’], required): The IntrType, either Event or Status.default_val(boolean, required): default value of a Status interrupt (invalid for Event interrupt).incoming(boolean, required): comes from rv_plic module.plic(string): controller for this interrupt.outgoing(boolean, required): whether interrupt leaves toplevel.
Memory
Module memory mapping
Properties
label(string, required): region label for the linker script.swaccess(string, required): access attributes for the memory region (ro, rw). Must be one of:["ro", "rw"].data_intg_passthru(boolean): Integrity bits are passed through directly from the memory.exec(boolean, required): executable region indication for the linker script.byte_write(boolean, required): indicate whether the memory supports byte write accesses.size(integer): Memory region size in bytes for the linker script, xbar, and RTL parameterizations. This field must be specified ifconfigis not specified.config: Extra configuration for a particular memory.- Any of
- : Refer to urn:topgen:eflash.
- Any of
Pad
I/O pad configuration
Properties
name(string, required): Pad name.type(string, required): Pad type.bank(string, required): IO power bank for the pad.connection(string, required): Specification of connection type, can be direct, manual or muxed. Must be one of:["direct", "manual", "muxed"].desc(string): Pad description.port_type(string): Special port type other thaninout wire.idx(integer): the index of the pad; added property.
Parameter
Parameter configuration passed down from top level to module
Properties
name(string, required): the parameter name.desc(string, required): the parameter description.type(string, required): the data type of the parameter.unpacked_dimensions(string): the unpacked dimensions for arrays.randtype(string): whether it is for ‘data’ or ’perm’issions.randcount(integer): number of bits to randomize in the parameter.default: the default value of the parameter.local(boolean): whether it is a localparam.expose(boolean): parameter is exposed to top level; added property.name_top(string): the name in the top-level.randwidth(integer): the number of bits.
Pinmux
Top level pin multiplexing configuration
Properties
signals(array): List of Dedicated IOs.- Items: Refer to urn:topgen:pinmux_signal.
wkup_cnt_width(integer): Number of bits in wakeup detector counters.num_wkup_detect(integer): Number of wakeup detectors.enable_usb_wakeup(boolean, required): Enable USB wakeup in pinmux.enable_strap_sampling(boolean, required): Enable hardware strap sampling of pinmux.ios(array): Full list of IO; added property.- Items: Refer to urn:topgen:pinmux_io.
io_counts(object): count of ios grouped by dedicated or muxed; added property..*: Refer to urn:topgen:pinmux_io_count.
Pinmux I/O
Top level I/O listing for pinmux
Properties
name(string, required): the name of the io.width(integer, required): the bit width of the io.type(string, required): input, output, or inout. Must be one of:["input", "output", "inout"].idx(integer): index of the io (for bus signals with width > 1).pad(string): Pad name for direct connections.attr(string): Pad type for generating the correct attribute CSR.connection(string, required): Specification of connection type, can be direct, manual or muxed. Must be one of:["direct", "manual", "muxed"].desc(string): Signal description.glob_idx(integer): global index of the io.
Pinmux I/O Count
Number of pinmux I/Os of each type
Properties
inouts(integer, required): the count of inout ios of the io type.inputs(integer, required): the count of input ios of the io type.outputs(integer, required): the count of output ios of the io type.pads(integer, required): the count of pads of the io type.
Pinmux Signal
Signal configurations for pinmux
Properties
instance(string, required): Module instance name.port(string): Port name of module.connection(string, required): Specification of connection type, can be direct, manual or muxed. Must be one of:["direct", "manual", "muxed"].pad(string): Pad name for direct connections.desc(string): Signal description.attr(string): Pad type for generating the correct attribute CSR.
Pinout
Top level pinout
Properties
banks(array, required): List of IO power banks.pads(array, required): List of pads.- Items: Refer to urn:topgen:pad.
Reset Connection
Module reset connection
Properties
Reset Request
Reset request item
Properties
name(string, required): the reset request name.width(integer): the reset request signal width.desc(string, required): the reset request description.module(string, required): the reset request source.enabled_after_reset(boolean): whether the reset is enabled after a reset (put differently, whether the reset value of the reset enable is high).
Reset Requests
Top level listing of reset requests
Pattern Properties
.*- Items: Refer to urn:topgen:reset_request.
Properties
int(array): internal request list, for example, escalation reset and power glitches.debug(array): debug request list, since a different set of resets becomes active.peripheral(array): peripheral request list, where the reset requests are explicit in the top config.
Special Signal
Special signal for pinmux
Properties
name(string, required): DIO name.pad(string, required): Pad name.desc(string): Description of signal connection.idx(integer): the index of the signal; added property.
Straps
Configuration for straps
Properties
tap0(string, required): Name of tap0 pad.tap1(string, required): Name of tap1 pad.dft0(string, required): Name of dft0 pad.dft1(string, required): Name of dft1 pad.
Target
Hardware target for a top level design, such as an FPGA or ASIC
Properties
name(string, required): Name of target.pinout: Target-specific pinout configuration. Refer to urn:topgen:target_pinout.pinmux: Target-specific pinmux configuration. Refer to urn:topgen:target_pinmux.
Target Pinmux
Top level target’s pinmux configuration
Properties
special_signals(array, required): List of special signals and the pad they are mapped to.- Items: Refer to urn:topgen:special_signal.
Target Pinout
Top level target’s pinout configuration
Properties
remove_ports(array, required): List of port names to remove from the port list.remove_pads(array, required): List of pad names to remove and stub out.add_pads(array, required): List of manual pads to add.
Wakeup
Wakeup request description