Flags: constraints in dependencies

Flags in FuseSoC are global boolean variables that influence the dependency resolution and other aspects of the build. Flags can be used in multiples places in core files to take conditional actions. For example, dependencies and files can be included depending on a flag, different toplevels can be selected, and much more.

Facts about flags:

  • Flags are boolean variables, they are either “set” (true) or “unset” (false).

  • Flags are global, i.e. they apply to the whole build. All cores see the same flags under the same name.

  • A valid flag name starts with a letter, and consists only of letters from the English alphabet, numbers, and the underscore (_).

  • Flag names are case-sensitive. It is recommended to use lower-case letters only.

Setting flags

Built-in flags are made available automatically. User-defined flags can be set as a dict of key/value pairs in the flags section of a target. These are turned into flags called <key>_<value> internally. This is intended to set default values for flags that normally needs to have them define. Finally, flags can be applied on the command line and these override user-defined flags in targets and built-in flags.

Built-in flags

When running fusesoc run some flags are automatically made available.

  • tool_TOOLNAME: A flag that is set only if a particular tool is used during the build process. TOOLNAME is replaced with the name of the used tool. For example, when building a design for Xilinx Vivado, tool_vivado will be set.

  • target_TARGETNAME: A flag that is set if a particular target is being built. TARGETNAME is replaced with the name of the target that is being built. For example, if the target synth is being built, the flag target_synth will be set.

User-defined flags

Flags can be set when building a design with fusesoc run by passing the --flag argument.

To set a flag, specify only the flag name, or alternatively, prefix it with a plus, i.e. --flag FLAGNAME or --flag +FLAGNAME. To unset a flag, prefix the name of the flag with a hyphen, i.e. pass --flag -FLAGNAME.

The --flag argument can be used multiple times to set or unset more than one flag.

Examples:

# Set the flag "my_flag".
fusesoc run --flag "my_flag" fusesoc:examples:blinky:1.0.0

# Alternative: set the flag "my_flag"
fusesoc run --flag "+my_flag" fusesoc:examples:blinky:1.0.0

# Set two flags, "my_flag" and "my_other_flag"
fusesoc run --flag "my_flag" --flag "my_other_flag" fusesoc:examples:blinky:1.0.0

# Unset the flag "my_flag"
fusesoc run --flag "-my_flag" fusesoc:examples:blinky:1.0.0

Note

Order matters! The FuseSoC command line is “context sensitive.” Place the --flags argument after the run command, but before the name of the core you are building.

Default values for flags can be set directly in the flags section of a target, like this.

# An excerpt from a core file.
targets:
  sim:
    # ...
    flags:
      fpu : true # Always enable the FPU for simulations. This will turn into a flag called fpu
      sram : sim # Use simulation models for SRAM. This will turn into a flag called sram_sim

Using flags

Flags can be used in core files to influence the build as part of a CAPI2 expression.

  • To test if a flag is set (true) and return my_string in that case, use the expression my_flag ? (my_string).

  • To test if a flag is not set (false) and return my_string in that case, use the expression !my_flag ? (my_string).

Note

Quotation marks are required for strings starting with an exclamation mark (!), but always recommended.

CAPI2 expressions are not full ternary operators, i.e. no “else” branch is available. Use two inverted expressions for if/else support.

The following use cases show some ways in which flags can be used in core description files.

Use case: Conditional dependencies

Flags can be used to influence which dependencies are included in a build. A typical use case for this feature are dependencies which are tool-specific.

The following example shows how to depend on a core named fusesoc:examples:xilinx-fifo (presumably implementing a Xilinx-specific FIFO) only if the vivado tool is used. Otherwise a core providing a tool-agnostic implementation is used.

# An excerpt from a core file.
filesets:
  rtl:
    # ...
    depend:
      - "tool_vivado ? (fusesoc:examples:xilinx-fifo)"
      - "!tool_vivado ? (fusesoc:examples:generic-fifo)"

Use case: Conditionally include files

Similar to the way dependencies can be conditionally specified source files can also be included conditionally.

The following example shows how to include a file rtl/fifo_xilinx.sv only if Vivado is used, and rtl/fifo_generic.sv otherwise.

# An excerpt from a core file.
filesets:
  rtl:
    # ...
    files:
      - "tool_vivado ? (rtl/fifo_xilinx.sv)"
      - "!tool_vivado ? (rtl/fifo_generic.sv)"

Use case: Conditional filesets in a target

Use flags in CAPI2 expressions in the targets.TARGETNAME.filesets block to conditionally include file sets.

The code snippet below shows how to include a fileset verilator_tb only if the verilator tool is used; otherwise the fileset any_other_tool_tb is included.

# An excerpt from a core file.
targets:
  # ...
  tb:
    # ...
    filesets:
      # Always include the rtl and tb filesets.
      - "rtl"
      - "tb"
      # Include the verilator_tb fileset only if verilator is used.
      - "tool_verilator ? (verilator_tb)"
      # Include the any_other_tool_tb fileset for all other tools.
      - "!tool_verilator ? (any_other_tool_tb)"

Use case: Conditionally choose a toplevel

Flags can also be used to choose the name a design toplevel based on certain conditions.

In the following code snippet, the user-defined flag experimental_toplevel is used to switch between two toplevels.

# An excerpt from a core file.
name: "fusesoc:examples:my_core"
targets:
  # ...
  synth:
    toplevel:
      - "experimental_toplevel ? (top_experimental)"
      - "!experimental_toplevel ? (top_production)"
    # ...

With this setup in place users can choose which toplevel they want to build by passing the --flag command line argument to fusesoc, as illustrated in the following example.

# Build top_experimental
fusesoc run --flag experimental_toplevel --target synth fusesoc:examples:my_core

# Build top_production
fusesoc run --target synth fusesoc:examples:my_core

Further use cases

Flags can be used in more places than shown here. To find all valid places where flags can be used, refer to the ref_capi2. Expressions with flags can be used whenever the data type is StringWithUseFlags, StringWithUseFlagsOrDict, or StringWithUseFlagsOrList.