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, seecargo installdocumentation for location order if--root <PREFIX>is ignored.v0.4.0is 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
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
Latest version from Gitlab
In addition, it is possible to download and install the latest binary built after each merge to main:
- Linux (x86)
- Rocky Linux (x86)
- Linux (ARM)
- macOS (ARM) This binary is currently not signed, so most users will not be able to install it as is. We are looking for a solution to this.
- Windows (x86) Note that sometimes Windows Defender has been known to report Surfer and other rust projects as a trojan. If in doubt, please use Virus total to check.
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.
-
reloadReload the current file. Does not work in a web browser.
-
remove_unavailableRemove variables that are not longer present in the reloaded/switched file.
State files
-
load_state <FILE_NAME>Load a previously saved state file.
-
save_stateSave 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_addAdd all variables in the specified scope to the waveform display.
module_addis an alias forscope_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_rootDeselect 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_addAdd a timeline row.
Groups
-
group_marked [NAME]Group the currently selected items into a new group with the optional given name.
-
group_dissolveRemove the focused group, moving its contents to the parent level.
-
group_fold_recursiveCollapse the focused group and all nested groups.
-
group_unfold_recursiveExpand the focused group and all nested groups.
-
group_fold_allCollapse all groups.
-
group_unfold_allExpand 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_colorReset to default color.
-
item_unset_background_colorReset to default background color.
-
item_unfocusRemove focus from currently focused item.
-
item_rename <NAME>Rename the currently focused item.
-
theme_select <THEME_NAME>Switch to the given color theme.
Navigation
-
zoom_fitZoom to display the full simulation.
-
zoom_inZoom in on the waveform.
-
zoom_outZoom out of the waveform.
-
scroll_to_start,goto_startScroll to the beginning of the simulation.
-
scroll_to_end,goto_endScroll to the end of the simulation.
-
goto_time <TIME>Center the view at the given time without moving the cursor.
TIMEcan be a plain integer (raw timescale ticks) or a value with a time unit, e.g.100ns,1.5 ms,2us. -
transition_nextMove cursor to next transition of focused item. Scroll if not visible.
-
transition_previousMove cursor to previous transition of focused item. Scroll if not visible.
-
transaction_nextMove to the next transaction of the focused item.
-
transaction_prevMove to the previous transaction of the focused item.
UI control
-
show_controlsShow keyboard shortcut help window.
-
show_mouse_gesturesShow mouse gesture help window.
-
show_quick_startShow the quick start guide window.
-
show_logsShow log window.
-
toggle_menuToggle visibility of menu. If not visible, there will be a burger menu in the toolbar.
-
toggle_side_panelToggle visibility of the side panel, i.e., where the scopes and variables are shown.
-
toggle_fullscreenToggle fullscreen view.
-
toggle_tick_linesToggle 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:
Linedraws a vertical line,Cycleshades alternating cycles,Nonedisables highlighting. -
preference_set_hierarchy_style <Separate | Tree>Set how the design hierarchy is shown:
Separateshows scopes and variables in separate panes,Treeshows 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_reloadReload the configuration file.
Cursor and markers
-
goto_cursorGo 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.
TIMEcan 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_windowDisplay 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_arrayto source pixel data from a memory array (a scope), orframe_buffer_set_variableto 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 ofBITSbits (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>LASTthe 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_simulationPause a running simulation.
-
unpause_simulationResume a paused simulation.
Viewports
-
viewport_addAdd a new viewport (additional waveform view pane).
-
viewport_removeRemove 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
addresssetting in thewcppart of the config file. -
wcp_server_stop(not WASM)Stop the WCP server.
Other
-
copy_valueCopy the variable name and value at cursor to the clipboard.
-
undoUndo the last action.
-
redoRedo the last undone action.
-
exit(not WASM)Exit Surfer.
Debugging
-
dump_treePrint the current displayed item tree to the log.
-
show_performance(performance_plot feature only)Show the performance plot window. Pass
redrawto 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
| Name | Description |
|---|---|
| Cancel | No operation |
| GoToEnd | Scroll view to last time in simulation |
| GoToStart | Scroll view to first time in simulation |
| ZoomIn | Zoom in to the range defined by the start and end time of the gesture |
| ZoomOut | Zoom out a constant factor |
| ZoomToFit | Zoom 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 runningsurverdoes 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:
- If the computer running the server is directly accessible, it can be accessed using the provided URL.
- 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-addressand 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
| Os | Path |
|---|---|
| Linux | ~/.local/share/surfer/translators |
| Windows | C:\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.
| Os | Path |
|---|---|
| Linux | ~/.config/surfer/decoders/ |
| Windows | C:\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:
| Os | Path |
|---|---|
| Linux | ~/.config/surfer/mappings/ |
| Windows | C:\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:
| Kind | Theme color |
|---|---|
default | variable_default |
dontcare | variable_dontcare |
error | variable_error |
event | variable_event |
highimp | variable_highimp |
normal | variable_default |
undef | variable_undef |
weak | variable_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.
| Os | Path |
|---|---|
| Linux | ~/.config/surfer/config.toml. |
| Windows | C:\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
| Os | Path |
|---|---|
| Linux | ~/.config/surfer/themes/ |
| Windows | C:\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:
- Built-in defaults from
default_config.toml - The per-user
config.tomlin Surfer’s configuration directory - Deprecated
surfer.tomlin the current working directory, if present - Any
.surfer/config.tomlfiles found from the filesystem root down to the current directory - Environment variables with the
SURFERprefix
Top-level settings
| Key | Default | Values | Description |
|---|---|---|---|
default_variable_name_type | "Unique" | Local, Unique, Global | Default signal name display style. |
default_clock_highlight_type | "Line" | Line, Cycle, None | Default clock highlighting mode. |
snap_distance | 6 | non-negative number | Cursor snap distance in pixels. |
theme | "" | theme name | Theme to load. Leave empty to use the built-in default theme. |
undo_stack_size | 50 | integer | Maximum number of undo steps to keep. |
autoreload_files | "Ask" | Always, Never, Ask | What to do when loaded waveform files change on disk. |
autoload_sibling_state_files | "Ask" | Always, Never, Ask | Whether matching state files should be loaded automatically. |
animation_time | 0.1 | non-negative number | Duration of UI animations in seconds. |
animation_enabled | true | boolean | Enable or disable UI animations entirely. |
show_divider_text | false | boolean | Show divider labels inline in the waveform area. |
max_url_length | 65534 | integer | Maximum 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.
| Key | Default | Values | Description |
|---|---|---|---|
format | "No" | No, Locale, SI | Numeric formatting style. Locale uses the current locale. SI groups digits using SI-style spacing. |
show_space | true | boolean | Insert a space between the numeric part and the unit. |
show_unit | true | boolean | Show the time unit suffix. |
[layout]
Controls the initial UI layout and waveform rendering behavior.
| Key | Default | Values | Description |
|---|---|---|---|
show_hierarchy | true | boolean | Show the hierarchy panel. |
show_menu | true | boolean | Show the menu bar. |
show_toolbar | true | boolean | Show the toolbar. |
show_ticks | true | boolean | Show vertical tick lines in the waveform area. |
show_tooltip | true | boolean | Show tooltips for variables. |
show_scope_tooltip | false | boolean | Show tooltips for scopes. |
show_overview | true | boolean | Show the overview panel. |
show_statusbar | true | boolean | Show the status bar. |
show_variable_indices | true | boolean | Show signal indices in the variable list when available. |
show_variable_direction | true | boolean | Show direction icons or indicators for variables. |
show_default_timeline | true | boolean | Add a timeline row by default. |
show_empty_scopes | false | boolean | Show scopes that contain no visible items. |
show_hierarchy_icons | false | boolean | Show scope and variable icons in the hierarchy. |
parameter_display_location | "Scopes" | Variables, Scopes, Tooltips, None | Where parameter values are displayed in the hierarchy UI. |
window_width | 1920 | integer | Initial window width in pixels. |
window_height | 1080 | integer | Initial window height in pixels. |
align_names_right | false | boolean | Right-align names in the item list. |
hierarchy_style | "Separate" | Separate, Tree, Variables | Layout style used for the hierarchy and variable list. |
waveforms_text_size | 11.0 | non-negative number | Text size for waveform values, in points. |
waveforms_line_height | 16.0 | non-negative number | Base line height for waveforms, in points. |
waveforms_gap | 2.5 | non-negative number | Vertical 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 numbers | Available line-height multipliers for taller rows. |
transactions_line_height | 30.0 | non-negative number | Line 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 numbers | Available UI zoom factors. |
default_zoom_factor | 1.0 | non-negative number | Initial UI zoom factor. |
highlight_focused | false | boolean | Highlight the waveform of the focused item. |
move_focus_on_inserted_marker | true | boolean | Move focus to newly inserted markers. |
fill_high_values | true | boolean | Fill the high state in boolean waveforms. |
use_dinotrace_style | false | boolean | Use 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, Both | Which value to show when the cursor is exactly on a transition. |
[gesture]
Controls the radial mouse-gesture overlay shown when using gesture mode.
| Key | Default | Values | Description |
|---|---|---|---|
size | 300 | non-negative number | Size of the gesture help overlay. |
deadzone | 20 | non-negative number | Minimum squared drag distance before a gesture action is triggered. |
background_radius | 1.35 | non-negative number | Background circle radius as a factor of size / 2. |
background_gamma | 0.75 | number between 0 and 1 | Background 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.
| Direction | Default |
|---|---|
north | "Cancel" |
northeast | "ZoomOut" |
east | "ZoomIn" |
southeast | "GoToEnd" |
south | "Cancel" |
southwest | "GoToStart" |
west | "ZoomIn" |
northwest | "ZoomToFit" |
[behavior]
Controls a small set of interaction defaults.
| Key | Default | Values | Description |
|---|---|---|---|
keep_during_reload | true | boolean | Keep variables/items when they are unavailable after a reload. |
arrow_key_bindings | "Edge" | Edge, Scroll | Make left/right arrow keys jump between edges or scroll the viewport. |
primary_button_drag_behavior | "Cursor" | Cursor, Measure | Default behavior for primary-button dragging. Holding Shift temporarily selects the other mode. |
[wcp]
Waveform Control Protocol server settings.
| Key | Default | Values | Description |
|---|---|---|---|
autostart | false | boolean | Start the WCP server automatically on launch. |
address | "127.0.0.1:54321" | host:port string | Bind address for the WCP server. |
[server]
Settings for Surver’s HTTP server.
| Key | Default | Values | Description |
|---|---|---|---|
bind_address | "127.0.0.1" | host or IP string | Address to bind the server to. |
port | 8911 | integer | TCP 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:
| Action | Default binding |
|---|---|
open_file | Command+O |
switch_file | Command+Shift+O |
undo | Command+Z, U |
redo | Command+Shift+Z, Command+Y |
toggle_side_panel | B |
toggle_toolbar | T |
goto_end | E |
goto_start | S |
goto_top | Home |
goto_bottom | End |
save_state_file | Command+S |
group_new | G |
item_focus | F |
select_all | Command+A |
select_toggle | A |
reload_waveform | R |
zoom_in | Plus, Equals |
zoom_out | Minus |
ui_zoom_in | Command+Plus |
ui_zoom_out | Command+Minus |
scroll_up | PageUp |
scroll_down | PageDown |
delete_selected | Delete, X |
marker_add | M |
toggle_menu | Alt+M |
show_command_prompt | Space |
rename_item | F2 |
divider_add | D |
zoom_to_fit | Shift+F |
go_to_time | Command+G |
Notes
- Floating-point values that are documented as non-negative are clamped to
0if a negative value is provided. - Values documented as being between
0and1are 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
| Key | Type | Description |
|---|---|---|
foreground | color | Default foreground text color used across the UI. |
border_color | color | Border color between UI elements. |
alt_text_color | color | Alternate text color. Often when an explicit background color is used, the color with most contrast is chosen between foreground and this. |
canvas_colors | ThemeColorTriple | Colors for the waveform canvas. |
primary_ui_color | ThemeColorPair | Main UI background and foreground colors. |
secondary_ui_color | ThemeColorPair | Secondary UI colors, used for panels, lists, and inputs. |
selected_elements_colors | ThemeColorPair | Colors used for selected items in the UI. |
accent_info | ThemeColorPair | Informational accent colors. |
accent_warn | ThemeColorPair | Warning accent colors. |
accent_error | ThemeColorPair | Error accent colors. |
cursor | SurferLineStyle | Style used to draw the main cursor and marker vertical lines. |
gesture | SurferLineStyle | Style used for mouse gesture lines. |
measure | SurferLineStyle | Style used for measurement lines. |
clock_highlight_line | SurferLineStyle | Line style used when clock highlighting is in Line mode. |
clock_highlight_cycle | color | Fill color used when clock highlighting is in Cycle mode. |
clock_rising_marker | boolean | Draw arrows on rising clock edges. |
variable_default | color | Default waveform color for regular signals. |
variable_highimp | color | Color used for high-impedance (Z) signal segments. |
variable_undef | color | Color used for undefined (X) signal segments. |
variable_dontcare | color | Color used for don’t-care signal segments. |
variable_weak | color | Color used for weak-signal segments. |
variable_parameter | color | Color used for parameter/constant values. |
variable_event | color | Color used for event variables. |
transaction_default | color | Default color for transaction streams. |
relation_arrow | SurferRelationArrow | Style used for transaction relation arrows. |
waveform_opacity | number 0..1 | Background opacity for waveform rows. |
wide_opacity | number 0..1 | Background opacity for wide signals. |
colors | table of named colors | Named colors exposed in UI commands such as item_set_color. |
highlight_background | color | Background highlight color used for focused or emphasized rows/elements. |
linewidth | non-negative number | Standard waveform line width. |
thick_linewidth | non-negative number | Thicker waveform line width for emphasized signals. |
vector_transition_width | non-negative number | Maximum width of vector transition markers. |
alt_frequency | integer | Number of rows using the normal canvas background before alternating to alt_background. Set to 0 to disable alternating backgrounds. |
viewport_separator | SurferLineStyle | Style of the separator between viewports. |
drag_hint_color | color | Color of drag hint guides. |
drag_hint_width | non-negative number | Width of drag hint guides. |
drag_threshold | non-negative number | Threshold before drag hints or drag behavior activate. |
ticks | SurferTicks | Tick line density and style. |
scope_icons | ScopeIcons | Optional icon overrides for scope types in the hierarchy. |
variable_icons | VariableIcons | Optional 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" }
| Field | Type | Description |
|---|---|---|
background | color | Background color. |
foreground | color | Foreground/text color. |
ThemeColorTriple
Used by canvas_colors.
canvas_colors = { background = "0b151d", alt_background = "1b252d", foreground = "d4d4d4" }
| Field | Type | Description |
|---|---|---|
background | color | Primary waveform canvas background. |
alt_background | color | Alternating background used every alt_frequency rows. |
foreground | color | Text color used on the canvas. |
SurferLineStyle
Used by cursor, gesture, measure, clock_highlight_line, and viewport_separator.
cursor = { color = "b63935", width = 2 }
| Field | Type | Description |
|---|---|---|
color | color | Line color. |
width | non-negative number | Line width. |
SurferTicks
Used by ticks.
[ticks]
density = 1.0
style = { color = "222222", width = 2 }
| Field | Type | Description |
|---|---|---|
density | number 0..1 | Tick density. 1 means as many ticks as can fit without overlap. |
style | SurferLineStyle | Tick line style. |
SurferRelationArrow
Used by relation_arrow.
[relation_arrow]
style = { color = "c61521", width = 1.3 }
head_angle = 25
head_length = 8
| Field | Type | Description |
|---|---|---|
style | SurferLineStyle | Arrow line style. |
head_angle | non-negative number | Arrowhead angle in degrees. |
head_length | non-negative number | Arrowhead 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:
moduletaskfunctionbeginforkgeneratestructunionclassinterfacepackageprogramvhdl_architecturevhdl_procedurevhdl_functionvhdl_recordvhdl_processvhdl_blockvhdl_for_generatevhdl_if_generatevhdl_generatevhdl_packageghw_genericvhdl_arrayunknownclockingsv_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:
wirebusstringeventother
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
colorstable is separate from UI palette settings; it exists so commands can refer to stable names likeGreenorOrange. - 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

Dark high contrast

Dark plus

IBM

Light high contrast

Light plus

Okabe Ito

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

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

Solarized

Rosé Pine

Rosé Pine Moon

Rosé Pine Dawn

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:
- Fork and clone the repository
- Setup pre-commit
- Create a branch (other than
main) - Edit code
- Commit code with a sensible commit message
- Push branch
- Create a merge request
- Wait for the change to be merged, including fixing suggestions from reviewers
- 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.
- Install pre-commit:
pip install pre-commit
- 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:
-
Run
cargo test -
Run
./accept_snapshots.bash -
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:
- If set by the user in the application, it will saved in the state file.
- 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.
| Feature | Description | Default |
|---|---|---|
accesskit | Accessibility support. | No* |
f128 | 128-bit floating-point translator. Requires building with gcc as underlying C-compiler. | No |
performance_plot | The show_performance command and the drawing performance plot window. | Yes |
python | Python translators. | No |
wasm_plugins | WASM translator plugins. | Yes |
* Included in pre-built binaries.