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

Project setup

There are several use cases of fromco executable. It can be used either as LSP server or CLI utility for linting, and documentation extraction.

Lsp setup

Create a configuration file .fromco_cfg.json at project root directory

{
	"top_module"     	: "top",
	"file_list"      	: "filelist.f",
	"exclude_globs"  	: ["glob1", "glob2", "..."],
	"use_file_watcher" 	: true
}

If you have dependencies e.g. UVM, just create a separate filelist for UVM and add it to root file list.

For example uvm_1_2.f:

+define+UVM_MAJOR_VERSION=1
+define+UVM_MINOR_VERSION=2
+incdir+/path_to_uvm/UVM/1.2/
/path_to_uvm/UVM/1.2/uvm_pkg.sv

If your filelist has dependency from environment variable, you can add it to IDE env variables or you can define it via in .env file. They will be visible only for LSP and substituted into described filelists. So, fromco-lsp is just a simple wrapper:

#!/bin/bash
FROMCO_ROOT="$(pwd)"
if [ -f "$FROMCO_ROOT/.env" ]; then
	export $(grep -v '^#' "$FROMCO_ROOT/.env" | xargs)
fi
exec fromco --lsp

IDE setup

The default distribution contains pre-defined configs for number of a common text editors. Feel free to modify and reuse it. See lsp/ directory.

Visual Studio Code

See lsp/vscode_fromco.vsix The default distribution contains fromco*.vsix extension which can be installed via Extensions->Install from VSIX . It provides key LSP protocol functionality (see LSP features), additional functionality (e.g. goto drivers, preprocessor highlights), and Schematic Viewer.

Nvim

See lsp/nvim_fromco.lua

Sublime text

See lsp/sublime_text_fromco.json

CLI setup

Can be used for fast linting and CI integration.

$ fromco -h

Documentation generator setup (CLI)

fromco provides a documentation extraction functionality for any project. It can be easily integrated into CI or other workflows which will enable a documentation vs RTL consistency.

$ fromco -F <filelist path> --dump-json <entity kind> --focus hier_path.[entity1,entity2]

The tool output might be postprocessed and inserted into your documentation build pipeline. Default distribution provides an example script which consumes names intended to be dumped and produces a number of latex or adoc tables. For example:

$ fromco-dump --yaml hooks.yaml --adoc -o hooks.adoc 

You can open an examples/documentation folder and inspect a template of documentation generation pipeline.

Features and usage scenarious

Full list of arguments might be achieved by

$ fromco -h

You can start fromco on single systemverilog file just typing

$ fromco --file <FILE>

Some preprocessor, parse, and name resolution checks will be performed.

Messages will be printed into stdout with coloring. For example:

error:4e4419: Pipeline_scoreboarding/Control_scoreboard.sv:207:1: [-Wname-resolution]
    could not to find declaration of coder
    |
207 | coder #(.INPUT_WIDTH(4)) exec_pos_coder (
    | ^

Each error message contains severity, location, message type, piece of the source code and hash which can be used for waivers.

Filelists

Fromco supports next expressions in verilog file list:

+incdir+directory
+define+SOME_DEFINE
+define+SOME_DEFINE_IS=12
+define+SOME_DEFINE_IS_WHATEVER=whatever
path/to/verilog/source/file
-v path/to/verilog/source/file
-f path/to/another/filelist
-y path/to/directory/with/verilog/sources (all of them will be read: .v .vh .sv .svh)
// Comments
${ENV_VARIBALE}/path // Environment variables are also supported

Other statements will be ignored.

You may start fromco with filelist using -F <filelist path> cli option.

$ fromco -F <filelist path>

KNOWN ISSUES:

  • fromco will crash if file at filelist is not exist (will be fixed later)

Focus option

Focus option is usually used with other options.

$ fromco -F <filelist path> --focus hier.path.[entity1,entity2]

Dump-json

Internal data structures after name resulution may be dumped into json with some pre-computations. This feature uses --focus options for specifying entities to dump.

Some kinds of entities are supported:

  • port
  • portgroup
  • struct
  • enum
  • interface
  • paramgroup

Example:

module demo #
(
    parameter X = 4
)(
    input [X-1:0] a, // Some description of a
                     // Might be multiline

    // Description of b
    output        b  // Inline comment has lower priority
);

endmodule
$ fromco --file demo.sv --focus demo.[a,b] --dump-json portgroup

Such output will be produced (in file fromco-json.out)

{
  "enBody": {
    "pgPorts": [
      {
        "pDirection": "input",
        "pSignal": {
          "sDescription": "Some description of a\nMight be multiline",
          "sName": "a",
          "sRange": "3..0",
          "sType": null,
          "sWidth": "4"
        }
      },
      {
        "pDirection": "output",
        "pSignal": {
          "sDescription": "Description of b",
          "sName": "b",
          "sRange": "",
          "sType": null,
          "sWidth": "1"
        }
      }
    ]
  },
  "enHead": "EkPortGroup"
}

Widths of a signals were calculated to the numbers. You can dump parameters as symbols (localparams will be calculated as numbers):

$ fromco --file demo.sv --focus demo.[a,b] --dump-json portgroup --symbolic

Which gives you

{
  "enBody": {
    "pgPorts": [
      {
        "pDirection": "input",
        "pSignal": {
          "sDescription": "Some description of a\nMight be multiline",
          "sName": "a",
          "sRange": "(X-1)..0",
          "sType": null,
          "sWidth": "(X)"
        }
      },
      {
        "pDirection": "output",
        "pSignal": {
          "sDescription": "Description of b",
          "sName": "b",
          "sRange": "",
          "sType": null,
          "sWidth": "1"
        }
      }
    ]
  },
  "enHead": "EkPortGroup"
}

Localparams declared at imported packages may be converted to symbols using --params-imported option.

This feature may be used for documentation generation. There is a script which accepts a list of entities and produces a long .tex or .adoc file with tables which are ready to be included to your documentation (see scripts/fromco-dump.py). You can play with demo of documentation building pipeline (see examples/dump-json/).

Sizecheck

Fromco is intented to be a tool which helps to write reusable parametrized SystemVerilog code. It supports number of signal width checks with symbolic interpretation of parameter values.

Symbolic width checks

Fromco supports parameter agnostic width check. Each parameter (and localparam from imported package) is interpreted as symbolic value. Width check is generalized and perfomed over symbolic sizes of variables.

parameter  X = 5;
localparam Y = X;
localparam Z = 5;

logic [4:0]   a;
logic [X-1:0] x;
logic [Y-1:0] y;
logic [Z-1:0] z; 

assign a = x; // Warning: 5 vs X
assign y = a; // Warning: Y vs 5
assign z = a; // OK
assign y = x; // OK

Symbolic parameters can be narrowed to exact values using conditional statements.

if (X == Z)
  assign z = x; // OK
else

Parameter values can be bounded using assumptions.

initial X_assumption : assume (X == Z);

assign z = x; // OK

It may compute complex expression over symbolic parameter values, but now it is not 100% accurate (TBD).

Clock gating warning

In ASIC design it is nessesary to provide enable signal for large flip-flops. Fromco will warn NBA without enable signal when width of the flip-flop is parametrized or has large number of bits.

parameter X;
logic         a;
logic [4:0]   b;
logic [X-1:0] x;

always_ff (@posedge clk)
begin
  a <= a_next; // OK
  b <= b_next; // Warning
  x <= x_next; // Warning
end

always_ff (@posedge clk)
if (a) begin
  b <= b_next; // OK
  x <= x_next; // OK
end

Signal naming checks

Might be invoked with:

$ fromco -F <filelist path> --style

Uses common postfixes for signals:

  • _i for inputs
  • _o for outputs
  • _ff for flip-flops
  • _en for enables

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.