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

Integration with waveform viewers

Fromco can natively read FST waveform files. By using additional LSP commands, it is possible to load a waveform file, set the cursor to a specified timestamp, and perform other related actions. This chapter provides a detailed description of these features.

Access to waveform data enables the following capabilities:

  1. Value annotations -- each signal can be marked with an inlay hint displaying its current value.
  2. Active annotations -- each line in a statement block that is active (i.e. located under a sequence of triggered if/case branches) can be highlighted to represent contributing drivers.
  3. Waveform navigation -- any signal (or scope of signals) in the source code can be added directly to the waveform viewer using a navigation button.

Configuration

The following entries must be added to .fromco_cfg.json:

  "waveform_top" : "module_name",
  "waveform_top_prefix" : "hierachical.path.prefix_to.i_module_name",
  "wcp_port" : 6666,
  • waveform_top — the name of the module selected as the starting point. It must be unique within the hierarchy. Typically, this is some kind of wrapper or top module.
  • waveform_top_prefix — a hierarchical path prefix that ends at the waveform_top module instance. This is sometimes required when no SystemVerilog source is available for the testbench.
  • wcp_port — specifies the port used by the WCP server. The default value is 6666.

Known limitations

Unfortunately, most WCP clients are implemented on top of the IP stack. As a result, if multiple users share the same machine, port usage must be coordinated to avoid conflicts.

Commands

Commands are accessible via the command palette in VS Code and similar interfaces in other editors.

  1. Load waveform -- opens a file manager dialog to select a waveform file in .fst format. Currently, only FST is supported. This command also reloads the file in the waveform viewer client.
  2. Set timestamp -- sets the cursor to a specified timestamp and synchronizes it with the waveform viewer. This command can be triggered via Ctrl+Click on time patterns in the integrated terminal.
  3. Toggle value annotations -- enables or disables value annotations.
  4. Toggle active annotations -- enables or disables active annotations.
  5. Add signal -- adds a selected signal or scope to the waveform viewer.
  6. Add signal recursively -- adds a selected signal or scope along with all nested scopes.

WCP integration

Fromco provides features (1) and (2) out of the box. However, on their own, these features may be of limited use. For full functionality, Fromco can be integrated with your preferred waveform viewer via the WCP protocol.

The following WCP commands are currently supported:

  1. load_waveform -- notifies the client that a waveform file has been loaded.
  2. add_variable -- adds a selected variable to the waveform.
  3. add_scope -- adds a selected scope (including nested elements such as structs and unpacked arrays) to the waveform.
  4. set_cursor -- sets the cursor to a specified timestamp in the waveform viewer.

Supported events:

  1. waveforms_loaded -- notifies the language server that a waveform file has been loaded by the waveform viewer.

For an improved user experience, it is recommended to add a cursor_set event to the WCP client. This event notifies the language server when the cursor position is changed via the waveform viewer GUI and includes the timestamp value (see the next section).

Integration with Surfer

A simple patch is available for the Surfer Waveform Viewer that adds the required functionality (cursor_set event). Eventually, this patch is expected to be merged upstream, but it is not yet included.

diff --git a/libsurfer/src/lib.rs b/libsurfer/src/lib.rs
index df4f727..9005ecf 100644
--- a/libsurfer/src/lib.rs
+++ b/libsurfer/src/lib.rs
@@ -237,6 +237,7 @@ pub struct WcpClientCapabilities {
     pub goto_declaration: bool,
     pub add_drivers: bool,
     pub add_loads: bool,
+    pub cursor_set: bool,
 }
 impl WcpClientCapabilities {
     fn new() -> Self {
@@ -245,6 +246,7 @@ impl WcpClientCapabilities {
             goto_declaration: false,
             add_drivers: false,
             add_loads: false,
+            cursor_set: false,
         }
     }
 }
@@ -971,7 +973,17 @@ impl SystemState {
             }
             Message::CursorSet(time) => {
                 let waves = self.user.waves.as_mut()?;
-                waves.cursor = Some(time);
+                waves.cursor = Some(time.clone());
+
+                if self.wcp_greeted_signal.load(Ordering::Relaxed)
+                    && self.wcp_client_capabilities.cursor_set
+                {
+                    self.channels.wcp_s2c_sender.as_ref().map(|ch| {
+                        block_on(
+                            ch.send(WcpSCMessage::event(WcpEvent::cursor_set { time })),
+                        )
+                    });
+                }
             }
             Message::ExpandParameterSection => {
                 self.expand_parameter_section = true;
diff --git a/libsurfer/src/wcp/proto.rs b/libsurfer/src/wcp/proto.rs
index 6b5b268..e2ceb32 100644
--- a/libsurfer/src/wcp/proto.rs
+++ b/libsurfer/src/wcp/proto.rs
@@ -69,6 +69,7 @@ pub enum WcpEvent {
     goto_declaration { variable: String },
     add_drivers { variable: String },
     add_loads { variable: String },
+    cursor_set { time: BigInt },
 }
 
 #[derive(Serialize, Deserialize, Debug, PartialEq)]
diff --git a/libsurfer/src/wcp/wcp_handler.rs b/libsurfer/src/wcp/wcp_handler.rs
index 984c303..98070f3 100644
--- a/libsurfer/src/wcp/wcp_handler.rs
+++ b/libsurfer/src/wcp/wcp_handler.rs
@@ -363,6 +363,9 @@ impl SystemState {
                     if commands.iter().any(|s| s == "add_loads") {
                         self.wcp_client_capabilities.add_loads = true;
                     }
+                    if commands.iter().any(|s| s == "cursor_set") {
+                        self.wcp_client_capabilities.cursor_set = true;
+                    }
                     self.wcp_greeted_signal.store(true, Ordering::Relaxed);
                     self.wcp_greeted_signal.store(true, Ordering::Relaxed);
                     self.send_greeting()

Known issues

  1. The waveforms_loaded event provides a relative path based on the directory from which Surfer is started. This may cause issues when opening waveforms on the LSP side. To avoid this problem, use an absolute path to the waveform file when launching Surfer.

Integration with Vaporview

The Fromco VSCode extension is natively integrated with the Vaporview waveform viewer. No additional actions are required.

Waveform Features API

This section may help implement support for other editors.

Several LSP custom methods are implemented and listed below:

handler/loadWaveform

Parameters: { path: <waveform file path : string> }

Response: void

Loads a waveform from the given path.

handler/setTimestamp

Parameters: { timestamp: <timestamp value : string> }

Response: void

Sets the specified timestamp value. Note that value is provided as string.

handler/addSignal

Parameters: { path: <cursor file path: string>, pos: { line: <cursor line number : number>, character: <cursor column number : number> }, recursive: bool }

Response: <hierarchical path added : string>

Adds a signal to the waveform and returns the actual hierarchical path.

handler/toggleValueAnnotations

Parameters: none

Response: void

Toggles the appearance of value annotations.