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:
_ifor inputs_ofor outputs_fffor flip-flops_enfor 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:
- Value annotations -- each signal can be marked with an inlay hint displaying its current value.
- Active annotations -- each line in a statement block that is active (i.e. located under a sequence of triggered
if/casebranches) can be highlighted to represent contributing drivers. - 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
wrapperortopmodule. - waveform_top_prefix — a hierarchical path prefix that ends at the
waveform_topmodule 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.
- Load waveform -- opens a file manager dialog to select a waveform file in
.fstformat. Currently, only FST is supported. This command also reloads the file in the waveform viewer client. - 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.
- Toggle value annotations -- enables or disables value annotations.
- Toggle active annotations -- enables or disables active annotations.
- Add signal -- adds a selected signal or scope to the waveform viewer.
- 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:
load_waveform-- notifies the client that a waveform file has been loaded.add_variable-- adds a selected variable to the waveform.add_scope-- adds a selected scope (including nested elements such as structs and unpacked arrays) to the waveform.set_cursor-- sets the cursor to a specified timestamp in the waveform viewer.
Supported events:
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
- The
waveforms_loadedevent 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.