verible-verilog-format
is the SystemVerilog formatter tool. You can can
get a full set of avilable flags using the --helpfull
flag.
For automatic formatting suggestions on github pull requests, there is a easy to integrate github action available.
usage: verible-verilog-format [options] <file> [<file...>]
To pipe from stdin, use '-' as <file>.
Flags from common/formatting/basic_format_style_init.cc:
--column_limit (Target line length limit to stay under when formatting.);
default: 100;
--indentation_spaces (Each indentation level adds this many spaces.);
default: 2;
--line_break_penalty (Penalty added to solution for each introduced line
break.); default: 2;
--over_column_limit_penalty (For penalty minimization, this represents the
baseline penalty value of exceeding the column limit. Additional penalty
of 1 is incurred for each character over this limit); default: 100;
--wrap_spaces (Each wrap level adds this many spaces. This applies when the
first element after an open-group section is wrapped. Otherwise, the
indentation level is set to the column position of the open-group
operator.); default: 4;
Flags from verilog/formatting/format_style_init.cc:
--assignment_statement_alignment (Format various assignments:
{align,flush-left,preserve,infer}); default: infer;
--case_items_alignment (Format case items:
{align,flush-left,preserve,infer}); default: infer;
--class_member_variable_alignment (Format class member variables:
{align,flush-left,preserve,infer}); default: infer;
--compact_indexing_and_selections (Use compact binary expressions inside
indexing / bit selection operators); default: true;
--distribution_items_alignment (Aligh distribution items:
{align,flush-left,preserve,infer}); default: infer;
--enum_assignment_statement_alignment (Format assignments with enums:
{align,flush-left,preserve,infer}); default: infer;
--expand_coverpoints (If true, always expand coverpoints.); default: false;
--formal_parameters_alignment (Format formal parameters:
{align,flush-left,preserve,infer}); default: infer;
--formal_parameters_indentation (Indent formal parameters: {indent,wrap});
default: wrap;
--module_net_variable_alignment (Format net/variable declarations:
{align,flush-left,preserve,infer}); default: infer;
--named_parameter_alignment (Format named actual parameters:
{align,flush-left,preserve,infer}); default: infer;
--named_parameter_indentation (Indent named parameter assignments:
{indent,wrap}); default: wrap;
--named_port_alignment (Format named port connections:
{align,flush-left,preserve,infer}); default: infer;
--named_port_indentation (Indent named port connections: {indent,wrap});
default: wrap;
--port_declarations_alignment (Format port declarations:
{align,flush-left,preserve,infer}); default: infer;
--port_declarations_indentation (Indent port declarations: {indent,wrap});
default: wrap;
--port_declarations_right_align_packed_dimensions (If true, packed
dimensions in contexts with enabled alignment are aligned to the right.);
default: false;
--port_declarations_right_align_unpacked_dimensions (If true, unpacked
dimensions in contexts with enabled alignment are aligned to the right.);
default: false;
--struct_union_members_alignment (Format struct/union members:
{align,flush-left,preserve,infer}); default: infer;
--try_wrap_long_lines (If true, let the formatter attempt to optimize line
wrapping decisions where wrapping is needed, else leave them unformatted.
This is a short-term measure to reduce risk-of-harm.); default: false;
Flags from verilog/tools/formatter/verilog_format.cc:
--failsafe_success (If true, always exit with 0 status, even if there were
input errors or internal errors. In all error conditions, the original
text is always preserved. This is useful in deploying services where
fail-safe behaviors should be considered a success.); default: true;
--inplace (If true, overwrite the input file on successful conditions.);
default: false;
--lines (Specific lines to format, 1-based, comma-separated, inclusive N-M
ranges, N is short for N-N. By default, left unspecified, all lines are
enabled for formatting. (repeatable, cumulative)); default: ;
--max_search_states (Limits the number of search states explored during line
wrap optimization.); default: 100000;
--show_equally_optimal_wrappings (If true, print when multiple optimal
solutions are found (stderr), but continue to operate normally.);
default: false;
--show_inter_token_info (If true, along with show_token_partition_tree,
include inter-token information such as spacing and break penalties.);
default: false;
--show_largest_token_partitions (If > 0, print token partitioning and then
exit without formatting output.); default: 0;
--show_token_partition_tree (If true, print diagnostics after token
partitioning and then exit without formatting output.); default: false;
--stdin_name (When using '-' to read from stdin, this gives an alternate
name for diagnostic purposes. Otherwise this is ignored.);
default: "<stdin>";
--verbose (Be more verbose.); default: false;
--verify_convergence (If true, and not incrementally formatting with
--lines, verify that re-formatting the formatted output yields no further
changes, i.e. formatting is convergent.); default: true;
When you want to exempt a range of text from formatting, write:
// verilog_format: off
... untouched code ...
// verilog_format: on
or
/* verilog_format: off */
... untouched code ...
/* verilog_format: on */
As a good practice, include a reason why you choose to disable a section.
// verilog_format: off // my alignment is prettier than the tool's
// verilog_format: off // issue #N: working around.
These directives take precedence over --lines
specifications.
For files that are included as snippets in other contexts, e.g. only statements,
or only module body items, adding a
parsing mode directive (such as // verilog_syntax: parse-as-module-body
) will let the formatter parse and format
such files successfully.
The formatter is ever a work-in-progress and may not always behave the way a user would like it to behave. If you wish to review changes introduced by the formatter and apply them interactively, we've provided a helper script (that is actually formatter-agnostic) for the job.
verible-transform-interactive.sh -- verible-verilog-format -- files...
This will run the formatter on the affected files without modifying them
initially, and pass the diff
-generated patch into a tool
(verible-patch-tool
) that interactively applies patch hunks.
Answer the [y/n] prompts.
The original files will be modified in-place with the elected changes.
For convenience, one could create an alias like:
alias verilog-format-interactive='verible-transform-interactive.sh -- verible-verilog-format --'
If you wish to format only changed lines (a.k.a. incremental or partial formatting), the following tools are provided to assist.
git-verible-verilog-format.sh
(installed along with verible-verilog-format
)
can be run from within any subdirectory of a Git project. It automatically
detects new and changed lines, and generates the --lines
flag for each
modified file in your workspace.
From --help
:
git-verible-verilog-format.sh:
Performs incremental file formatting (verible-verilog-format) based on current diffs.
New files explicitly git-add-ed by the user are wholly formatted.
Actions:
1) Runs 'git add -u' to stage currently modified files to the index.
To format new files (wholly), 'git add' those before calling this script.
2) Runs 'git diff -u --cached' to generate a unified diff.
3) Diff is scanned to determine added or modified lines in each file.
4) Invokes 'verible-verilog-format --inplace' on all touched or new Verilog files,
but does not 'git add' so that the changes may be examined and tested.
Formatting can be easily undone with:
'git diff | git apply --reverse -'.
usage: git-verible-verilog-format.sh [script options] [-- [verilog_format options]]
(no positional arguments)
Run from anywhere inside a git project tree.
script options: (options with arguments can be: --flag=VALUE or --flag VALUE)
--help | -h : print help and exit
--verbose | -v : execute verbosely
--dry-run : stop before running formatter, and print formatting commands
--formatter TOOL : path to verilog_format binary
[using: /usr/local/bin/verible-verilog-format]
-- : stops option processing, and forwards remaining args as flags to the
underlying --formatter tool.
In your locally modified client (p4, git) run:
verible-verilog-format-changed-lines-interactive.sh
and follow the prompts.
NOTE: git and hg users can pass in a different base revision to diff against:
# Diff against the previous revision in hg verible-verilog-format-changed-lines-interactive.sh --rev .^ # Diff against upstream mainline in git verible-verilog-format-changed-lines-interactive.sh --rev origin/main
There are several sections of code that are eligible for aligned formatting. In each of these contexts, the user has some control over the alignment behavior. Without alignment, the default behavior is to flush-left, which respects indentation and minimum inter-token spacing constraints.
Yet, alignment is not always desired. So how does the formatter know whether or not the user intended for alignment? It can only examine the original code and make some judgment.
Consider the following example (module formal parameters):
module m #(
int W,
type T
);
...
endmodule
With alignment, this formats to:
module m #(
int W,
type T
);
...
endmodule
When the spacing difference between between aligned and flushed-left formatting is "sufficiently small", the formatter will align because the small difference has low risk of compromising readability.
In contrast, aligning the following example could be considered less readable.
original:
module m #(
int W,
some_long_name T
);
...
endmodule
aligned:
module m #(
int W,
some_long_name T
);
...
endmodule
To detect the above condition, the formatter examines the number of excess spaces (spacing errors) within an alignment group (original vs. flushed-left). If that value is lower than a threshold, the formatter infers that the author intended flush-left formatting.
To induce alignment, the author needs to inject four excess spaces between
any two tokens in any row in the aligned section, not before first tokens (which
fall under indentation, not alignment). In this example, spaces are deliberately
injected before W
(but after W
would work too):
module m #(
int W,
some_long_name T
);
...
endmodule
formatted with alignment:
module m #(
int W,
some_long_name T
);
...
endmodule
This also implies that previously aligned code will most likely remain aligned.
Finally, if none of the above conditions hold, the formatter will leave the original code as-is, preserving all pre-existing spaces.
A formatter must not corrupt data.
On rare conditions, you may observe that the formatter leaves the original code untouched. You may have encountered a fail-safe condition, in which the formatter conservatively gives up to keep your code from being corrupted. This can happen for one of several reasons.
On failure to lex/parse, the formatter gives up because it doesn't have a syntax tree to work with.
Before outputting the formatted result, several properties are checked:
- Equivalence: The output is lexically equivalent to the input, meaning that only whitespaces may have changed, but all other tokens are equal. For example, if two identifiers accidentally got merged together into one (by removing spaces between them), this check would fail. Lexical equivalence also implies that the output is still parseable.
- Convergence: Re-formatting the output results in no further changes. This property is particularly important when the formatter is used to check that a file is formatted properly. Without convergence, such a check would fail after formatting, potentially asking the user to run formatting two or more times. Note that this requirement is stricter than eventual convergence, which allows multiple iterations before reaching a fixed-point.
If an optimization such as line-wrapping optimization fails to complete within time resource limits, then the formatter also gives up to avoid hanging.
If the formatter crashes for any other reason, it will leave the original file intact. The formatter does not attempt to open any file for writing in-place until all formatting calculations have been done and internal verifications pass.