Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Surfer is a wave form viewer supporting VCD, FST, and GHW files as well as the memory transaction format FTR.

The GHW support is not as complete as VCD and FST, but please file issues with examples of files not working.

It is built to be highly configurable.

Installation

You can install Surfer either as a binary or from source. It is in general recommended to run the latest version from git.

Installing Surfer from source

To install from source you must have a Rust compiler. To install the Rust compiler go to https://rust-lang.org/tools/install/.

Now, you can do

cargo install --git https://gitlab.com/surfer-project/surfer.git surfer

Replace surfer with surver to install the server only version.

There are a number of compile-time features that can be enabled/disabled.

If you plan to contribute to the development, please see the [development](development information).

Installing a specific version

To install an earlier version, use:

cargo install --locked --root <PREFIX> --git https://gitlab.com/surfer-project/surfer.git --tag v0.4.0 surfer

where

  • <PREFIX> is the install location, see cargo install documentation for location order if --root <PREFIX> is ignored.
  • v0.4.0 is the tag

Note that --locked is important here as it will install with exactly the same dependencies that worked when releasing that version.

You may also want to replace --tag <TAG> with --rev <COMMIT-HASH> to get the version at a specific commit. For example, the version just before we broke something that we have not yet fixed.

Also note that Surfer versions are not yet that important, but more a reason to write an announcement (and to update the distributions in the next section).

Installing Surfer as a binary

Some Linux distributions have Surfer available as a package to be installed through the package manager. The current status is:

surfer

Packaging status

Note that some of the packages, like the one for openSuse, is a completely different program though.

For macOS (also included in the table above), Homebrew has a formulae.

For at least Spack and Homebrew, it is also possible to install the latest git version. Click the table above to get more information.

surfer-waveform

Packaging status

Latest version from Gitlab

In addition, it is possible to download and install the latest binary built after each merge to main:

Starting Surfer

Once Surfer is installed, it can be started by typing surfer or surfer WAVEFORMFILE.vcd to directly load a waveform file. There are also additional arguments that can be seen by typing surfer --help. This should now display the arguments as:

Usage: surfer [OPTIONS] [WAVE_FILE] [COMMAND]

Commands:
  server  starts surfer in headless mode so that a user can connect to it
  help    Print this message or the help of the given subcommand(s)

Arguments:
  [WAVE_FILE]  Waveform file in VCD, FST, or GHW format

Options:
  -c, --command-file <COMMAND_FILE>  Path to a file containing 'commands' to run after a waveform has been loaded.
                                     The commands are the same as those used in the command line interface inside the program.
                                     Commands are separated by lines or ;. Empty lines are ignored. Line comments starting with
                                     `#` are supported
                                     NOTE: This feature is not permanent, it will be removed once a solid scripting system
                                     is implemented.
      --script <SCRIPT>              Alias for --command_file to support VUnit
  -s, --state-file <STATE_FILE>      Load previously saved state file
      --wcp-initiate <WCP_INITIATE>  Port for WCP to connect to
  -h, --help                         Print help
  -V, --version                      Print version

Commands

To execute a command, press space and type the command. There is fuzzy match support, so it is enough to type parts of the command name and it will display options that matches.

It is also possible to create a command file, extension .sucl, and run that. Running a command file can be done from within Surfer using the menu option in the File menu, through the toolbar button, or by typing the command run_command_file. It can also be done using the --command-file argument when starting Surfer.

Not all commands are available unless a file is loaded. Also, some commands are not available in the WASM-build (browser/VS Code extension).

Surver (streaming waveform server)

  • surver_select_file <FILE_NAME>

    Load a file from the connected Surver instance, discarding the current waveform view.

  • surver_switch_file <FILE_NAME>

    Load a file from the connected Surver instance, keeping the current waveform view.

Waveform/transaction loading and reloading

  • load_file <FILE_NAME>

    Load a file. Note that it works to load a waveform file from a command file.

    In WASM-builds (web browser/VS Code plugin) it is not possible to open a file due to file access restrictions. Use load_url.
  • switch_file <FILE_NAME>

    Load file, but keep waveform view.

  • load_url <URL>

    Load a URL.

  • reload

    Reload the current file. Does not work in a web browser.

  • remove_unavailable

    Remove variables that are not longer present in the reloaded/switched file.

State files

  • load_state <FILE_NAME>

    Load a previously saved state file.

  • save_state

    Save the current state to the default state file.

  • save_state_as <FILE_NAME>

    Save the current state to the given file.

Command files

  • run_command_file <FILE_NAME> (not on WASM)

    Run the commands in the given file.

    In WASM-builds (web browser/VS Code plugin) it is not possible to run another command file from a command file due to file access restrictions.
  • run_command_file_from_url <URL>

    Run the commands at the given URL.

Add variable/transaction items

  • scope_add <SCOPE_NAME>, stream_add, module_add

    Add all variables in the specified scope to the waveform display. module_add is an alias for scope_add.

  • scope_add_recursive <SCOPE_NAME>

    Add all variables in the specified scope and from all sub-scopes to the waveform display.

    Adding large hierarchies with a large number of variables can freeze surfer for a significant amount of time.
  • scope_add_as_group <SCOPE_NAME>

    Add all variables in the specified scope to the waveform display in a newly created group of the same name.

  • scope_add_as_group_recursive <SCOPE_NAME>

    Add all variables in the specified scope and all sub-scopes to the waveform display in a newly created groups nested.

    Adding large hierarchies with a large number of variables can freeze surfer for a significant amount of time.
  • variable_add <FULL_VARIABLE_NAME>, generator_add <FULL_GENERATOR_NAME>

    Add a variable/generator using the full path, including scopes/streams.

  • scope_select <SCOPE_NAME>, stream_select <STREAM_NAME>

    Select a scope/stream to be active (shown in the side panel).

  • scope_select_root, stream_select_root

    Deselect the active scope/stream (resets to the root).

  • variable_add_from_scope <VARIABLE_NAME>, generator_add_from_stream <GENERATOR_NAME>

    Add variable/generator from currently selected scope/stream.

Add other items

  • divider_add [NAME]

    Add a divider with the optional given name.

  • timeline_add

    Add a timeline row.

Groups

  • group_marked [NAME]

    Group the currently selected items into a new group with the optional given name.

  • group_dissolve

    Remove the focused group, moving its contents to the parent level.

  • group_fold_recursive

    Collapse the focused group and all nested groups.

  • group_unfold_recursive

    Expand the focused group and all nested groups.

  • group_fold_all

    Collapse all groups.

  • group_unfold_all

    Expand all groups.

Controlling item appearance

  • item_focus <ITEM>

    Set keyboard focus to the given item (referenced by its alphabetical index shown in the display).

  • item_set_color <COLOR_NAME>

    Set the foreground color of the focused item.

  • item_set_background_color <COLOR_NAME>

    Set the background color of the focused item.

  • item_set_format <FORMAT_NAME>

    Set the value display format of the focused item (e.g. hex, binary, decimal, signed).

  • item_unset_color

    Reset to default color.

  • item_unset_background_color

    Reset to default background color.

  • item_unfocus

    Remove focus from currently focused item.

  • item_rename <NAME>

    Rename the currently focused item.

  • theme_select <THEME_NAME>

    Switch to the given color theme.

  • zoom_fit

    Zoom to display the full simulation.

  • zoom_in

    Zoom in on the waveform.

  • zoom_out

    Zoom out of the waveform.

  • scroll_to_start, goto_start

    Scroll to the beginning of the simulation.

  • scroll_to_end, goto_end

    Scroll to the end of the simulation.

  • goto_time <TIME>

    Center the view at the given time without moving the cursor. TIME can be a plain integer (raw timescale ticks) or a value with a time unit, e.g. 100ns, 1.5 ms, 2us.

  • transition_next

    Move cursor to next transition of focused item. Scroll if not visible.

  • transition_previous

    Move cursor to previous transition of focused item. Scroll if not visible.

  • transaction_next

    Move to the next transaction of the focused item.

  • transaction_prev

    Move to the previous transaction of the focused item.

UI control

  • show_controls

    Show keyboard shortcut help window.

  • show_mouse_gestures

    Show mouse gesture help window.

  • show_quick_start

    Show the quick start guide window.

  • show_logs

    Show log window.

  • toggle_menu

    Toggle visibility of menu. If not visible, there will be a burger menu in the toolbar.

  • toggle_side_panel

    Toggle visibility of the side panel, i.e., where the scopes and variables are shown.

  • toggle_fullscreen

    Toggle fullscreen view.

  • toggle_tick_lines

    Toggle display of vertical tick lines on the waveform.

  • variable_set_name_type <Local | Unique | Global>

    Set the name display style for the focused variable.

  • variable_force_name_type <Local | Unique | Global>

    Set the name display style for all variables.

  • preference_set_clock_highlight <Line | Cycle | None>

    Set how clock signals are highlighted: Line draws a vertical line, Cycle shades alternating cycles, None disables highlighting.

  • preference_set_hierarchy_style <Separate | Tree>

    Set how the design hierarchy is shown: Separate shows scopes and variables in separate panes, Tree shows them together as a tree.

  • preference_set_arrow_key_bindings <Edge | Scroll>

    Set whether arrow keys move to the next/previous signal edge (Edge) or scroll the view (Scroll).

  • config_reload

    Reload the configuration file.

Cursor and markers

  • goto_cursor

    Go to the location of the main cursor. If off screen, scroll to it.

  • goto_marker <MARKER_NAME> | #<MARKER_NUMBER>

    Go to the location of the given marker. If off screen, scroll to it.

  • cursor_set <TIME>

    Move cursor to given time and scroll to it if not in view. TIME can be a plain integer (raw timescale ticks) or a value with a time unit, e.g. 100ns, 1.5 ms, 2us.

  • marker_set <MARKER_NAME> | #<MARKER_NUMBER>

    Add/set marker to location of cursor.

  • marker_remove <MARKER_NAME> | #<MARKER_NUMBER>

    Remove marker.

  • show_marker_window

    Display window with markers and differences between markers

Frame buffer

  • frame_buffer_set_array <SCOPE_NAME> / frame_buffer_set_variable <VARIABLE_NAME>

    Set the data source for the frame buffer. Use frame_buffer_set_array to source pixel data from a memory array (a scope), or frame_buffer_set_variable to source it from a single variable.

  • frame_buffer_set_mode <grayscale | rgb | ycbcr> <BITS> [BITS2 BITS3]

    Set the color mode and bit widths used when decoding pixels.

    • grayscale <BITS> — each pixel is a single grey value of BITS bits (1–8).
    • rgb <R_BITS> <G_BITS> <B_BITS> — each pixel is packed as red/green/blue with the given bit widths (each 0–8).
    • ycbcr <Y_BITS> <CB_BITS> <CR_BITS> — each pixel is packed as Y/Cb/Cr (BT.601) with the given bit widths (each 0–8).

    Examples:

    frame_buffer_set_mode grayscale 8
    frame_buffer_set_mode rgb 5 6 5
    frame_buffer_set_mode ycbcr 8 8 8
    
  • frame_buffer_set_width <WIDTH>

    Set the number of pixels per row in the frame buffer display.

  • frame_buffer_set_range <FIRST> <LAST> [FIRST2 LAST2 ...]

    Set the displayed index range for each array level. Pairs of integers are matched to levels in order; extra pairs beyond the number of levels are ignored. Each value is clamped to the valid range of its level, and if FIRST > LAST the values are swapped automatically.

    Example — set level 0 to rows 0–479 and level 1 to columns 0–639:

    frame_buffer_set_range 0 479 0 639
    

Interactive simulation

  • pause_simulation

    Pause a running simulation.

  • unpause_simulation

    Resume a paused simulation.

Viewports

  • viewport_add

    Add a new viewport (additional waveform view pane).

  • viewport_remove

    Remove the most recently added viewport.

Waveform control protocol (WCP)

  • wcp_server_start (not WASM)

    Start the WCP server. Typically, this is using port 54321 at address 127.0.0.1, but this can be changed using the address setting in the wcp part of the config file.

  • wcp_server_stop (not WASM)

    Stop the WCP server.

Other

  • copy_value

    Copy the variable name and value at cursor to the clipboard.

  • undo

    Undo the last action.

  • redo

    Redo the last undone action.

  • exit (not WASM)

    Exit Surfer.

Debugging

  • dump_tree

    Print the current displayed item tree to the log.

  • show_performance (performance_plot feature only)

    Show the performance plot window. Pass redraw to also enable continuous redraw mode.

Cursor and markers

In Surfer, the cursor is the vertical line that can be positioned by clicking the primary mouse button. The cursor will snap to a nearby transition if there is a waveform below.

There are also numbered markers. These are created from the cursor location, either by right-clicking and selecting New (or a number to redefine an existing), or by pressing Ctrl+0-9 (Cmd+0-9 on MacOS).

Although only marker 0 to 9 can be directly accessed using keyboard commands, there is support for up to 255 markers, numbered

It is possible to center on a marker by pressing 0-9.

The number shown in the column usually showing variable values of waveforms is the difference in time to the current cursor location.

Cursor and marker window

By pressing space and typing show_marker_window a rudimentary window showing differences between all defined markers and the cursor (primary) is shown. It is possible to center a marker/cursor by pressing on the name of the marker/cursor.

Mouse gestures

Surfer supports mouse gestured. These are activated using the middle mouse button, or if the middle mouse button is not available, but pressing Ctrl (Cmd on MacOS) and using the primary mouse button.

If the mouse pointer is close to the location where it was pressed, a graphical overlay showing the different gestures is shown.

Configuration

It is possible to modify how the mouse gestures behave.

[gesture]
# Size of the square encapsulating the instructions
size = 300
# Squared minimum move for the instructions to show up
deadzone = 20
# Radius, relative to size, for the background circle
background_radius = 1.35
# Gamma for the background circle
background_gamma = 0.75

# Mapping of different locations
[gesture.mapping]
north = "Cancel"
south = "Cancel"
west = "ZoomIn"
east = "ZoomIn"
northeast = "ZoomOut"
northwest = "ZoomToFit"
southeast = "GoToEnd"
southwest = "GoToStart"

The currently available mouse gestures actions are

NameDescription
CancelNo operation
GoToEndScroll view to last time in simulation
GoToStartScroll view to first time in simulation
ZoomInZoom in to the range defined by the start and end time of the gesture
ZoomOutZoom out a constant factor
ZoomToFitZoom to cover the whole range of the simulation

Note that although any action can be mapped to any direction, it may not make sense to map ZoomIn to anything else that East or West, as the difference in x-direction is what determines the zoom factor.

Measure time

It is possible to measure the time by holding shift and pressing the primary mouse button.

The behavior can be configured using the config primary_button_drag_behavior which can take the value Cursor (press shift to measure) or Measure (no need to press shift). There is also a preference setting for this in the Preference menu.

Remote file access

It is possible to run a remote Surfer server, called Surver, on a different computer and then connect to that computer to avoid downloading/copying large waveform files. Only the requested information will be transferred.

The recommended way is to use an ssh tunnel to secure the connection. It is described how to set this up when you start Surver.

Warning

If an ssh tunnel is not used, this is done using plain http, so absolutely no security is provided for the access or transmission, apart from having to provide the correct token, which is also transmitted using plain http.

Surver

There is a stand-alone binary, Surver, that can be compiled, resulting in a much smaller binary and more likely to succeed on systems where Surfer may be hard to install due to GUI dependencies not being installed etc.

Tip

There is basically no point in running surfer server, as running surver does not have any drawbacks. Most likely, support for running Surfer in server mode will be removed and only Surver can be used.

Using remote mode

There are two ways to start the server, either start the stand-alone server binary Surver:

surver <FILENAME>

or start Surfer in server mode using:

surfer server --filename <FILENAME>

In both situations, instructions how to progress will be printed. There are basically two ways to connect:

  1. If the computer running the server is directly accessible, it can be accessed using the provided URL.
  2. If not, you will need to setup an SSH tunnel by following the instructions.

Now, Surfer can be started using the provided URL/start command, or you can use File -> Open URL and enter the provided URL.

Configuration

Currently, the configuration options are quite rudimentary and can be provided on the command line. To see the available configuration values, either execute:

surver --help

leading to

Server for the Surfer waveform viewer

Usage: surver [OPTIONS] <WAVE_FILES|--file <FILE>>

Arguments:
  [WAVE_FILES]...  Waveform files in VCD, FST, or GHW format

Options:
      --file <FILE>                  File with one wave form file name per line
      --port <PORT>                  Port on which server will listen
      --bind-address <BIND_ADDRESS>  IP address to bind the server to
      --token <TOKEN>                Token used by the client to authenticate to the server
  -h, --help                         Print help
  -V, --version                      Print version

or

surfer server --help

which will print a similar set of options.

Caution

Using --bind-address and accessing the connection directly is not secure. This should only be done in a local network.

Translators

Surfer supports custom translators that are loaded at runtime via web-assembly.

See additional documentation how to install and write translator plugins.

If there is enough interest, we are contemplating hosting user-developed plugins in a central location.

It is also possible to use decoders, which does not require writing your own custom translator. Or the simpler variant mapping translators

Installing Translator Plugins

Plugins come as a single .wasm file which Surfer will search for in .surfer/translators the current working directory, as well as in the global, OS-dependent, configuration directory

OsPath
Linux~/.local/share/surfer/translators
WindowsC:\Users\<Name>\AppData\Roaming\surfer-project\surfer\data\translators\
macOS/Users/<Name>/Library/Application Support/org.surfer-project.surfer/translators/

To install a translator, simply put the .wasm file in one of these locations, and it will be discovered automatically.

Translators execute arbitrary code, so some care should be taken before installing translators. However, they are sandboxed behind a web-assembly runtime that, unless there are security issues, does not allow any access to anything on the system that surfer does not allow.

Currently, the only system access surfer allows for plugins is

  • Reading the path of the current working directory
  • Reading arbitrary files

Writing Translator Plugins

Documentation on writing WASM-based plugins is available at https://docs.surfer-project.org/translator_docs/index.html

Decoders

Decoders allow translating n-bit signals into nice text representations. They are based on the instruction-decoder crate. To add additional decoders to Surfer, create a decoders directory in Surfer’s config directory and add your decoders inside there.

OsPath
Linux~/.config/surfer/decoders/
WindowsC:\Users\<Name>\AppData\Roaming\surfer-project\surfer\config\decoders\
macOS/Users/<Name>/Library/Application Support/org.surfer-project.surfer/decoders/

To add a new decoder, create a subdirectory inside decoders and add the required toml files. A decoder can consist of multiple toml files which will be merged. You can also add project-specific decoders by creating subdirectories in .surfer/decoders.

The decoders show up as additional formats.

For simpler use cases, you may want to consider a mapping translator.

Mapping Translators

A simpler variant of decoders is the mapping translator. This can convert bit-vector values into text using a simple configuration file.

The configuration files are located either in .surfer/mappings/ in the current working directory or in any of the following, OS-dependent, directories:

OsPath
Linux~/.config/surfer/mappings/
WindowsC:\Users\<Name>\AppData\Roaming\surfer-project\surfer\config\mappings\
macOS/Users/<Name>/Library/Application Support/org.surfer-project.surfer/mappings/

The file format is in its simplest form just pairs of vector values and text strings, one per line. For example:

0b0000 Start
0b0001 State 1
0b0010 State 2
0b0011 State 3

will map the binary variable value 0000 into the text Start and the variable value 0001 into the text State2 and so on.

The values can be written either as binary (0b), octal (0o), decimal (no prefix) or hex (0x) and different formats can be used for each row. It is possible to use _ as part of the numbers to obtain clearer formatting.

Hence, the example above can be written as

0b00_00 Start
0x1 State 1
0o2 State 2
3 State 3

It is also possible to write values using 4-state or 9-state logic when using binary radix, so 0bxx01zz is a valid value.

The wordlength is determined by the values, the longest string or binary value, or the number of bits required to represent the largest number. It can also be specified using a line as the first or second line (see below about naming) as

Bits = 4
0 Start
1 State 1
2 State 2
3 State 3

It is also possible to name the translator, which then is used as the Format to select, by having a first line as

Name = My statemachine
Bits = 4
0 Start
1 State 1
2 State 2
3 State 3

If no name is provided, the filename without extension is used as Format name.

Finally, it is possible to supply a variable kind or color for each line. This is supplied within [] directly after the value (no space). The supported kinds and corresponding theme color names are:

KindTheme color
defaultvariable_default
dontcarevariable_dontcare
errorvariable_error
eventvariable_event
highimpvariable_highimp
normalvariable_default
undefvariable_undef
weakvariable_weak

For colors, any named Color32 can be used (case insensitive, so RED, red, and Red will all work). It is also possible to specify an RGB hex color, either with or without a leading # so both aa7035 and #aa7035 are valid options.

If no kind/color is given, the waveform is drawn as a default/normal variable.

Comments starts with # and spans the rest of the line.

A final example including comments, kinds, and colors is:

# The statemachine in block 2
Name = Block 2 statemachine
Bits = 4
# Make the start state magenta
0[magenta] Start
# Often better to use the kinds as they follow the themes
# We also want to highlight State 1
1[error] State 1
# Empty lines are OK

2 State 2
3[#abcdef] State 3

Configuration

Surfer can be customized by modifying configuration files.

Note that it is enough to only add the configuration parameters that are changed to the file. All other will have the default values.

For a list of all possible configuration options, please look at the default configuration. To replace Surfer’s default configuration, add your configuration to a file called config.toml and place it in Surfer configuration directory. The location of the configuration directory depends on your OS.

OsPath
Linux~/.config/surfer/config.toml.
WindowsC:\Users\<Name>\AppData\Roaming\surfer-project\surfer\config\config.toml.
macOS/Users/<Name>/Library/Application Support/org.surfer-project.surfer/config.toml

Surfer also allows having custom configs per directory. To use a configuration in just a single directory, create a .surfer subdirectory and add a file called config.toml inside this subdirectory. If you now start Surfer from within the directory containing .surfer, the configuration is loaded.

The load order of these configurations is default->config.toml->project specific. All these configuration options can be layered, this means that configurations that are loaded later only overwrite the options they provide.

After changing the configuration, run the config_reload command to update the running Sufer instance.

Themes

To add additional themes to Surfer, create a themes directory in Surfer’s config directory and add your themes inside there. That is

OsPath
Linux~/.config/surfer/themes/
WindowsC:\Users\<Name>\AppData\Roaming\surfer-project\surfer\config\themes\
macOS/Users/<Name>/Library/Application Support/org.surfer-project.surfer/themes/

You can also add project-specific themes to .surfer/themes directories. Additionally, configurations can be loaded using the Menubar option View/Theme or using the theme_select command.

For a list of all possible style options, please look at the default theme. For example of existing themes look here.

Customizing Icons

Themes can customize the icons displayed in the hierarchy view for scopes and variables. Icons are specified using Unicode code points from the Remix Icon font. To find the Unicode code point for an icon, search the egui-remixicon source.

Scope Icons

Scope icons appear next to hierarchy items like modules, functions, and packages. Add a [scope_icons] section to your theme file:

[scope_icons]
module = "\ued52"        # FOLDER_2_LINE
function = "\ued9e"      # FUNCTION_LINE
package = "\ued88"       # FOLDER_ZIP_LINE
#...

This is useful for adapting icons to HDL languages other than Verilog/VHDL. For example, if your simulator maps a language-specific construct to one of the existing scope types, you can customize its icon to better represent its meaning in your workflow.

Variable Icons

Variable icons appear next to signals in the hierarchy. Add a [variable_icons] section to your theme file:

[variable_icons]
wire = "\uf035"          # PULSE_LINE
bus = "\uebad"           # CODE_S_SLASH_LINE
string = "\uf201"        # TEXT
event = "\ueea8"         # LIGHTBULB_FLASH_LINE
other = "\uedfc"         # HASHTAG

Icon Colors

Icons can be colored using 6-digit hex RGB values (without #). Add [scope_icons.colors] or [variable_icons.colors] sections:

[scope_icons.colors]
module = "4FC3F7"        # Light Blue
function = "BA68C8"      # Purple
package = "FFD54F"       # Yellow
# ... other scope types: task, begin, fork, generate, struct, union,
# class, interface, program, vhdl_*, ghw_generic, unknown

[variable_icons.colors]
wire = "81C784"          # Green (1-bit)
bus = "64B5F6"           # Blue (multi-bit)
string = "FFB74D"        # Orange
event = "F06292"         # Pink
other = "BA68C8"         # Purple

Light themes include darker colors for better contrast. Only specify colors you want to override.

Config file

This page documents the user configuration file loaded by Surfer on native builds. You only need to specify the settings you want to change; any omitted setting keeps its default value.

The complete default configuration lives in default_config.toml.

Example

theme = "dark+"
default_variable_name_type = "Global"
snap_distance = 10

[default_time_format]
format = "SI"
show_space = true
show_unit = true

[layout]
show_ticks = false
hierarchy_style = "Tree"
waveforms_text_size = 12.0

[behavior]
arrow_key_bindings = "Scroll"
primary_button_drag_behavior = "Measure"

Load order

On native builds, configuration is loaded in this order, with later sources overriding earlier ones:

  1. Built-in defaults from default_config.toml
  2. The per-user config.toml in Surfer’s configuration directory
  3. Deprecated surfer.toml in the current working directory, if present
  4. Any .surfer/config.toml files found from the filesystem root down to the current directory
  5. Environment variables with the SURFER prefix

Top-level settings

KeyDefaultValuesDescription
default_variable_name_type"Unique"Local, Unique, GlobalDefault signal name display style.
default_clock_highlight_type"Line"Line, Cycle, NoneDefault clock highlighting mode.
snap_distance6non-negative numberCursor snap distance in pixels.
theme""theme nameTheme to load. Leave empty to use the built-in default theme.
undo_stack_size50integerMaximum number of undo steps to keep.
autoreload_files"Ask"Always, Never, AskWhat to do when loaded waveform files change on disk.
autoload_sibling_state_files"Ask"Always, Never, AskWhether matching state files should be loaded automatically.
animation_time0.1non-negative numberDuration of UI animations in seconds.
animation_enabledtruebooleanEnable or disable UI animations entirely.
show_divider_textfalsebooleanShow divider labels inline in the waveform area.
max_url_length65534integerMaximum URL length used for remote connections. Useful when a proxy enforces a limit.

The remaining top-level keys are tables documented below: default_time_format, layout, gesture, behavior, wcp, server, and shortcuts.

[default_time_format]

Controls how time values are rendered in the UI.

KeyDefaultValuesDescription
format"No"No, Locale, SINumeric formatting style. Locale uses the current locale. SI groups digits using SI-style spacing.
show_spacetruebooleanInsert a space between the numeric part and the unit.
show_unittruebooleanShow the time unit suffix.

[layout]

Controls the initial UI layout and waveform rendering behavior.

KeyDefaultValuesDescription
show_hierarchytruebooleanShow the hierarchy panel.
show_menutruebooleanShow the menu bar.
show_toolbartruebooleanShow the toolbar.
show_tickstruebooleanShow vertical tick lines in the waveform area.
show_tooltiptruebooleanShow tooltips for variables.
show_scope_tooltipfalsebooleanShow tooltips for scopes.
show_overviewtruebooleanShow the overview panel.
show_statusbartruebooleanShow the status bar.
show_variable_indicestruebooleanShow signal indices in the variable list when available.
show_variable_directiontruebooleanShow direction icons or indicators for variables.
show_default_timelinetruebooleanAdd a timeline row by default.
show_empty_scopesfalsebooleanShow scopes that contain no visible items.
show_hierarchy_iconsfalsebooleanShow scope and variable icons in the hierarchy.
parameter_display_location"Scopes"Variables, Scopes, Tooltips, NoneWhere parameter values are displayed in the hierarchy UI.
window_width1920integerInitial window width in pixels.
window_height1080integerInitial window height in pixels.
align_names_rightfalsebooleanRight-align names in the item list.
hierarchy_style"Separate"Separate, Tree, VariablesLayout style used for the hierarchy and variable list.
waveforms_text_size11.0non-negative numberText size for waveform values, in points.
waveforms_line_height16.0non-negative numberBase line height for waveforms, in points.
waveforms_gap2.5non-negative numberVertical gap above and below waveform traces. Basically, how far the background is drawn.
waveforms_line_height_multiples[1, 2, 4, 8, 16]list of non-negative numbersAvailable line-height multipliers for taller rows.
transactions_line_height30.0non-negative numberLine height for transaction streams.
zoom_factors[0.5, 0.75, 0.9, 1.0, 1.1, 1.25, 1.5, 2.0, 2.5]list of non-negative numbersAvailable UI zoom factors.
default_zoom_factor1.0non-negative numberInitial UI zoom factor.
highlight_focusedfalsebooleanHighlight the waveform of the focused item.
move_focus_on_inserted_markertruebooleanMove focus to newly inserted markers.
fill_high_valuestruebooleanFill the high state in boolean waveforms.
use_dinotrace_stylefalsebooleanUse Dinotrace-style digital waveform drawing. This means no upper line and a bold lower line for all zeros vector values and a bold upper line for all ones vector values.
transition_value"Next"Previous, Next, BothWhich value to show when the cursor is exactly on a transition.

[gesture]

Controls the radial mouse-gesture overlay shown when using gesture mode.

KeyDefaultValuesDescription
size300non-negative numberSize of the gesture help overlay.
deadzone20non-negative numberMinimum squared drag distance before a gesture action is triggered.
background_radius1.35non-negative numberBackground circle radius as a factor of size / 2.
background_gamma0.75number between 0 and 1Background opacity factor. Lower values are more opaque.

[gesture.mapping]

Maps each drag direction to a gesture action.

Supported actions are Cancel, ZoomIn, ZoomOut, ZoomToFit, GoToEnd, and GoToStart.

DirectionDefault
north"Cancel"
northeast"ZoomOut"
east"ZoomIn"
southeast"GoToEnd"
south"Cancel"
southwest"GoToStart"
west"ZoomIn"
northwest"ZoomToFit"

[behavior]

Controls a small set of interaction defaults.

KeyDefaultValuesDescription
keep_during_reloadtruebooleanKeep variables/items when they are unavailable after a reload.
arrow_key_bindings"Edge"Edge, ScrollMake left/right arrow keys jump between edges or scroll the viewport.
primary_button_drag_behavior"Cursor"Cursor, MeasureDefault behavior for primary-button dragging. Holding Shift temporarily selects the other mode.

[wcp]

Waveform Control Protocol server settings.

KeyDefaultValuesDescription
autostartfalsebooleanStart the WCP server automatically on launch.
address"127.0.0.1:54321"host:port stringBind address for the WCP server.

[server]

Settings for Surver’s HTTP server.

KeyDefaultValuesDescription
bind_address"127.0.0.1"host or IP stringAddress to bind the server to.
port8911integerTCP port to listen on.

[shortcuts]

The shortcuts table maps an action name to a list of key chords. Each value is an array of strings such as "Command+O" or "PageDown", where each value in the list is one shortcut, not a sequence. Hence, each action can have multiple alternative shortcuts.

Command corresponds to ⌘ on Mac and Ctrl on all other platforms. For a list of key names, see Key.

The default configuration defines these actions:

ActionDefault binding
open_fileCommand+O
switch_fileCommand+Shift+O
undoCommand+Z, U
redoCommand+Shift+Z, Command+Y
toggle_side_panelB
toggle_toolbarT
goto_endE
goto_startS
goto_topHome
goto_bottomEnd
save_state_fileCommand+S
group_newG
item_focusF
select_allCommand+A
select_toggleA
reload_waveformR
zoom_inPlus, Equals
zoom_outMinus
ui_zoom_inCommand+Plus
ui_zoom_outCommand+Minus
scroll_upPageUp
scroll_downPageDown
delete_selectedDelete, X
marker_addM
toggle_menuAlt+M
show_command_promptSpace
rename_itemF2
divider_addD
zoom_to_fitShift+F
go_to_timeCommand+G

Notes

  • Floating-point values that are documented as non-negative are clamped to 0 if a negative value is provided.
  • Values documented as being between 0 and 1 are clamped to that range.
  • Theme files are documented separately in the configuration section’s themes page.

Theme parameters

This page documents the keys supported in a Surfer theme file.

You only need to include the keys you want to override. Any omitted value falls back to the selected base theme or, for a full theme file, the built-in defaults.

For a complete example, see the default theme.

Value formats

  • Colors use RGB hex without a leading #, for example "d4d4d4".
  • Three-digit hex like "abc" is also accepted and expanded to "aabbcc".
  • Widths, lengths, and similar numeric values are non-negative. Negative values are clamped to 0.
  • Opacity-like values are clamped to the range 0..1.

Example

foreground = "d4d4d4"
border_color = "282b2d"
highlight_background = "37485E"
cursor = { color = "b63935", width = 2 }

canvas_colors = { background = "0b151d", alt_background = "1b252d", foreground = "d4d4d4" }
primary_ui_color = { background = "171717", foreground = "d4d4d4" }
selected_elements_colors = { background = "444444", foreground = "d4d4d4" }

[colors]
Green = "6a9955"
Red = "f44747"

[ticks]
density = 1.0
style = { color = "222222", width = 2 }

Top-level parameters

KeyTypeDescription
foregroundcolorDefault foreground text color used across the UI.
border_colorcolorBorder color between UI elements.
alt_text_colorcolorAlternate text color. Often when an explicit background color is used, the color with most contrast is chosen between foreground and this.
canvas_colorsThemeColorTripleColors for the waveform canvas.
primary_ui_colorThemeColorPairMain UI background and foreground colors.
secondary_ui_colorThemeColorPairSecondary UI colors, used for panels, lists, and inputs.
selected_elements_colorsThemeColorPairColors used for selected items in the UI.
accent_infoThemeColorPairInformational accent colors.
accent_warnThemeColorPairWarning accent colors.
accent_errorThemeColorPairError accent colors.
cursorSurferLineStyleStyle used to draw the main cursor and marker vertical lines.
gestureSurferLineStyleStyle used for mouse gesture lines.
measureSurferLineStyleStyle used for measurement lines.
clock_highlight_lineSurferLineStyleLine style used when clock highlighting is in Line mode.
clock_highlight_cyclecolorFill color used when clock highlighting is in Cycle mode.
clock_rising_markerbooleanDraw arrows on rising clock edges.
variable_defaultcolorDefault waveform color for regular signals.
variable_highimpcolorColor used for high-impedance (Z) signal segments.
variable_undefcolorColor used for undefined (X) signal segments.
variable_dontcarecolorColor used for don’t-care signal segments.
variable_weakcolorColor used for weak-signal segments.
variable_parametercolorColor used for parameter/constant values.
variable_eventcolorColor used for event variables.
transaction_defaultcolorDefault color for transaction streams.
relation_arrowSurferRelationArrowStyle used for transaction relation arrows.
waveform_opacitynumber 0..1Background opacity for waveform rows.
wide_opacitynumber 0..1Background opacity for wide signals.
colorstable of named colorsNamed colors exposed in UI commands such as item_set_color.
highlight_backgroundcolorBackground highlight color used for focused or emphasized rows/elements.
linewidthnon-negative numberStandard waveform line width.
thick_linewidthnon-negative numberThicker waveform line width for emphasized signals.
vector_transition_widthnon-negative numberMaximum width of vector transition markers.
alt_frequencyintegerNumber of rows using the normal canvas background before alternating to alt_background. Set to 0 to disable alternating backgrounds.
viewport_separatorSurferLineStyleStyle of the separator between viewports.
drag_hint_colorcolorColor of drag hint guides.
drag_hint_widthnon-negative numberWidth of drag hint guides.
drag_thresholdnon-negative numberThreshold before drag hints or drag behavior activate.
ticksSurferTicksTick line density and style.
scope_iconsScopeIconsOptional icon overrides for scope types in the hierarchy.
variable_iconsVariableIconsOptional icon overrides for variable types in the hierarchy.

theme_names exists internally in the theme data model but is populated by Surfer itself and should not be set in a theme file.

Named colors

The [colors] table defines the color names available to commands like item_set_color and item_set_background_color.

Example:

[colors]
Green = "6a9955"
Red = "f44747"
Blue = "569cd6"

Each key is an arbitrary user-visible color name and each value is a hex RGB color.

Structured types

ThemeColorPair

Used by primary_ui_color, secondary_ui_color, selected_elements_colors, accent_info, accent_warn, and accent_error.

primary_ui_color = { background = "171717", foreground = "d4d4d4" }
FieldTypeDescription
backgroundcolorBackground color.
foregroundcolorForeground/text color.

ThemeColorTriple

Used by canvas_colors.

canvas_colors = { background = "0b151d", alt_background = "1b252d", foreground = "d4d4d4" }
FieldTypeDescription
backgroundcolorPrimary waveform canvas background.
alt_backgroundcolorAlternating background used every alt_frequency rows.
foregroundcolorText color used on the canvas.

SurferLineStyle

Used by cursor, gesture, measure, clock_highlight_line, and viewport_separator.

cursor = { color = "b63935", width = 2 }
FieldTypeDescription
colorcolorLine color.
widthnon-negative numberLine width.

SurferTicks

Used by ticks.

[ticks]
density = 1.0
style = { color = "222222", width = 2 }
FieldTypeDescription
densitynumber 0..1Tick density. 1 means as many ticks as can fit without overlap.
styleSurferLineStyleTick line style.

SurferRelationArrow

Used by relation_arrow.

[relation_arrow]
style = { color = "c61521", width = 1.3 }
head_angle = 25
head_length = 8
FieldTypeDescription
styleSurferLineStyleArrow line style.
head_anglenon-negative numberArrowhead angle in degrees.
head_lengthnon-negative numberArrowhead length.

Icon customization

Themes can override both the glyph and the color for scope and variable icons shown in the hierarchy view.

Icon values are Unicode strings, typically copied from the Remix Icon set used by Surfer.

ScopeIcons

Use a [scope_icons] table to override glyphs for scope-like hierarchy nodes.

Supported keys are:

  • module
  • task
  • function
  • begin
  • fork
  • generate
  • struct
  • union
  • class
  • interface
  • package
  • program
  • vhdl_architecture
  • vhdl_procedure
  • vhdl_function
  • vhdl_record
  • vhdl_process
  • vhdl_block
  • vhdl_for_generate
  • vhdl_if_generate
  • vhdl_generate
  • vhdl_package
  • ghw_generic
  • vhdl_array
  • unknown
  • clocking
  • sv_array

Example:

[scope_icons]
module = "\ued52"
function = "\ued9e"
package = "\ued88"

scope_icons.colors

The nested [scope_icons.colors] table accepts the same keys as [scope_icons], but each value is a color instead of a glyph.

[scope_icons.colors]
module = "4FC3F7"
function = "BA68C8"
package = "FFD54F"

VariableIcons

Use a [variable_icons] table to override glyphs for variable categories.

Supported keys are:

  • wire
  • bus
  • string
  • event
  • other

Example:

[variable_icons]
wire = "\uf035"
bus = "\uebad"
string = "\uf201"
event = "\ueea8"
other = "\uedfc"

variable_icons.colors

The nested [variable_icons.colors] table accepts the same keys as [variable_icons], but each value is a color.

[variable_icons.colors]
wire = "81C784"
bus = "64B5F6"
string = "FFB74D"
event = "F06292"
other = "BA68C8"

Notes

  • A theme file may define only a subset of keys when it is intended to override an existing theme.
  • The colors table is separate from UI palette settings; it exists so commands can refer to stable names like Green or Orange.
  • Icon color tables are optional. If omitted, Surfer uses built-in defaults for icon colors.

Built-in themes

The following are examples of the built-in themes available in Surfer.

Default

Surfer default theme

Dark high contrast

Surfer dark high contrast theme

Dark plus

Surfer dark plus theme

IBM

Surfer IBM theme

Light high contrast

Surfer light high contrast theme

Light plus

Surfer light plus theme

Okabe Ito

Surfer Okabe Ito theme

Petroff Dark

Based on the article by Petroff https://doi.org/10.48550/arXiv.2107.02270.

Surfer Petroff dark theme

Petroff Light

Based on the article by Petroff https://doi.org/10.48550/arXiv.2107.02270.

Surfer Petroff light theme

Solarized

Surfer solarized theme

Rosé Pine

Surfer Rosé Pine theme

Rosé Pine Moon

Surfer Rosé Pine Moon theme

Rosé Pine Dawn

Surfer Rosé Pine Dawn theme

Development Information

Anyone is welcome to contribute to Surfer. As Surfer is licensed under EUPL 1.2 it is assumed that your contribution will also follow that license.

Once you find something to contribute, either that feature that you are missing or one of the issues, the pattern follows a regular git-like contribution:

  1. Fork and clone the repository
  2. Setup pre-commit
  3. Create a branch (other than main)
  4. Edit code
  5. Commit code with a sensible commit message
  6. Push branch
  7. Create a merge request
  8. Wait for the change to be merged, including fixing suggestions from reviewers
  9. Enjoy the new feature!

Pre-Commit

Surfer uses the pre-commit framework to do some basic checking when committing new code locally. By using this, the risk of CI errors is reduced.

This is a Python package, so the instructions below assumes that you have a working Python in your console.

  1. Install pre-commit:
pip install pre-commit
  1. In the Surfer source-code directory:
pre-commit install

The first time you commit, there will be things installed, so the time taken can be long. However, the next time no installation is required.

Also note that if something fails, like cargo fmt has to reformat the code, you will have to commit again as the pre-commit hook only formatted the code, not committed the formatted code.

Note that the spelling check does not alter the code, but only points out errors. Hence, these must be manually corrected before committing again.

Tests

To run the tests locally, do

cargo test

When possible, it is nice to have a test of the added code. As Surfer is graphical to a large extent, we primarily rely on image tests located in libsurfer/src/tests/snapshots.sh. These tests send a suitable set of messages and then takes a snapshot of the screen content which is the ground truth. Easiest way it to copy a suitable test and change the messages.

After running the coverage test in the CI, either a red or a green vertical line will be present in the code view of the merge request to see which code was executed. Ideally, all new code should be tested, but it is currently not realistic to have that as a strict requirement.

Update Image Tests

If you change something that affects rendering or adds new image tests, you will have to update the test images:

  1. Run cargo test

  2. Run ./accept_snapshots.bash

  3. Add and commit new images

Or if you for whatever reason only want to update some of the images (if you’re incrementally fixing things), copy snapshots/<test>.new.png to snapshots/<test>.png (and remove snapshots/<test>.diff.png).

Note that the test images are compressed using oxipng as part of the pre-commit hook.

Using egui Test Framework

When Surfer started with the graphical testing, egui did not have any testing facilities. Now it does, and it would be much beneficial to use egui_kittest. This would allow not just sending messages but to actually click on things etc, which allows both much higher test coverage and, more importantly, certainty that Surfer works as expected.

If you prefer to write the tests using egui_kittest that is much appreciated and clearly not a problem. More a step in the right direction.

Long Compilation Times

Compiling Surfer takes a long time which can be annoying during development. To make compilation faster, you can change lto to false and opt-level to a 0 or 1 towards the end of Cargo.toml in the root directory. This will speed up compilation at the expense of slightly larger and slower binaries (which is probably OK during development anyway).

Adding Configurations

The preferred pattern for a configuration value that can be set both in the program and in the config file is to add an Option-value in the UserState enum and then query the value first there, and, if not set by the user, take it from the config. This has two benefits:

  1. If set by the user in the application, it will saved in the state file.
  2. If not set by the user, any changes in the config will be reflected when loading a state.

To obtain this, a function similar to the following can be added to libsurfer/state_util.rs

#![allow(unused)]
fn main() {
    #[inline]
    pub fn show_default_timeline(&self) -> bool {
        self.user
            .show_default_timeline
            .unwrap_or_else(|| self.user.config.layout.show_default_timeline())
    }
}

and then this method is used everywhere to access the value. This also requires adding a public method in config.rs, in this case show_default_timeline(), that simply returns the corresponding config value (which should not be public to avoid overwriting etc).

Performance Measurement

If you want to measure performance, surfer has some features to help out. By running the command show_performance, it will show a graph with the total frame time, as well as the time taken to run various parts of the program.

The bulk of rendering is done in signal_canvas::generate_draw_commands. The results of generate_draw_commands are cached by default, and only recomputed when the viewport changes. This makes performance measurement harder, but there is a switch to turn off the cache. You can either click the “Continuous redraw” checkbox in the performance window, or run show_performance redraw to turn off the cache.

Command files

If you are debugging performance issues in a specific situation, you can use command files to automate the setup of surfer. For example, if you want to automatically add waves and turn on performance measurements, you can create `performance.sucl and add command prompt arguments that reproduce the issue to it, then run

surfer <wave file> -c performance.sucl

For example, to check performance with many displayed waves, performance.sucl may look like this:

show_performance redraw
module_add testbench.top.uut
module_add testbench.top.uut

Optimizations

Remember to run in release mode to get accurate performance measurements.

cargo run --bin surfer --release

Flamegraphs

Flamegraphs can be generated using cargo-flamegraph

CARGO_PROFILE_RELEASE_DEBUG=true ca flamegraph -- examples/picorv32.vcd -c performance.sucl

Compile Features

There are a number of compile time features that can be enabled or disabled.

FeatureDescriptionDefault
accesskitAccessibility support.No*
f128128-bit floating-point translator. Requires building with gcc as underlying C-compiler.No
performance_plotThe show_performance command and the drawing performance plot window.Yes
pythonPython translators.No
wasm_pluginsWASM translator plugins.Yes

* Included in pre-built binaries.