slang SystemVerilog Language Services

repository·master·Indexed 22 days ago

https://github.com/mikepopoloski/slang

A high-performance SystemVerilog frontend providing lexing, parsing, type checking, and elaboration. It serves as a standalone compiler, a library for tool developers (synthesis, simulation), and a backend for IDE features. The project includes pyslang Python bindings, the slang-hier hierarchy inspection tool, and slang-reflect for generating C++ representations of SystemVerilog structs, enums, and parameters.

Tokens
21.6K
Snippets
82
Records
96
Agent score
78%

What's inside slang

  1. Overview of slang SystemVerilog Language Services

    master

    slang is a high-performance software library and toolset designed for lexing, parsing, type checking, and elaborating SystemVerilog code. It is designed to be both a standalone executable for compilation and static analysis, and a library/frontend for other tools like synthesis engines, simulators, linters, and code editors.

    Key characteristics include:

    • Robustness: Designed to handle broken source text, making it suitable for real-time editor features like syntax highlighting and autocompletion.
    • Round-tripping: The parse tree is designed to round-trip back to the original source, facilitating the creation of refactoring and code generation tools.
    • Performance: Optimized for speed and compliance with the chipsalliance test suite, even on production-scale projects.
  2. Use the Rewriter tool to inspect or modify SystemVerilog files

    master

    The rewriter tool is a utility designed to demonstrate the round-trip capabilities of the slang library. By default, it prints the input file exactly as it is. It is useful for modifying files before they are used in other tools, understanding preprocessor behavior, or testing the library's ability to preserve source structure.

    The tool supports standard slang arguments, such as include directories. If a macro or include cannot be found, the tool will skip it by default.

    rewriter [options] <file-name>
  3. SystemVerilog Attribute Syntax

    master

    In SystemVerilog, attributes are used to provide additional information to tools. They are enclosed in (* ... *) and can contain one or more attribute specifications separated by commas. Each specification consists of an attr_name and an optional assignment to a constant_expression using the = operator.

    attribute_instance ::= `(*` [attr_spec] { `,` [attr_spec] } `*)`  
    attr_spec ::= attr_name [ `=` constant_expression ]
  4. Continuous assignment and net alias statements

    master

    SystemVerilog supports continuous assignments for nets and variable assignments.

    • Continuous Net Assignment: Uses the assign keyword followed by optional drive_strength and delay3. It can assign to a list of nets.
    • Continuous Variable Assignment: Uses the assign keyword with optional delay_control to assign to a list of variables.
    • Net Alias: Uses the alias keyword to create aliases between nets.
    assign [drive_strength] [delay3] list_of_net_assignments;
    assign [delay_control] list_of_variable_assignments;
    alias net_lvalue = net_lvalue = net_lvalue;
  5. SystemVerilog Expression Types and Operators

    master

    SystemVerilog expressions are categorized into several types:

    Primary Expressions

    • Literals: Numbers, time literals (e.g., 10ns), strings, and unbased unsized literals (e.g., '1).
    • Identifiers: Hierarchical identifiers, class handles (this, super), and enum identifiers.
    • Casting: Type casting using the ' operator (e.g., type'(expression)).
    • Streaming Concatenation: { >> slice_size expression }.

    Operators

    • Unary: +, -, !, ~, &, ~&, ||, ~|, ^, ~^, ^~.
    • Binary: Arithmetic (+, -, *, /, %, **), Logical (&&, ||), Relational (<, <=, >, >=), Equality (==, !=, ===, !==, ==?, !=?), Bitwise (&, |, ^, ^~, ~^), and Shift (>>, <<, >>>, <<<).
    • Increment/Decrement: ++, --.
    • Conditional: The ternary operator condition ? expr1 : expr2.

    Numbers

    • Integral Numbers: Decimal, Octal ('o), Binary ('b), and Hexadecimal ('h).
    • Real Numbers: Fixed-point or floating-point numbers with optional exponent (e or E).
    • Time Literals: Numbers followed by a time unit (s, ms, us, ns, ps, fs).
    // Ternary operator
    assign out = (sel) ? a : b;
    
    // Bitwise and Logical
    assign mask = 4'b1010 & 4'b1100;
    
    // Time literal
    #10ns a = 1;
  6. Understand SystemVerilog Source Text Structure

    master

    SystemVerilog source text can optionally begin with timeunits_declaration and is composed of one or more description items. A description can be any of the following top-level declarations:

    • module_declaration (or macromodule)
    • udp_declaration (User Defined Types)
    • interface_declaration
    • program_declaration
    • package_declaration
    • package_item (optionally preceded by an attribute_instance)
    • bind_directive (optionally preceded by an attribute_instance)
    • config_declaration
    source_text ::= [ [timeunits_declaration] ] { [description] }
    description ::= [module_declaration] | [udp_declaration] | [interface_declaration] | [program_declaration] | [package_declaration] | { [attribute_instance] } [package_item] | { [attribute_instance] } [bind_directive] | [config_declaration]
  7. Understand Module, Interface, and Program Declarations

    master

    SystemVerilog uses several primary declaration types, which can follow either Non-ANSI or ANSI styles:

    Module Declarations

    Modules can be declared using module or macromodule keywords. They support:

    • Non-ANSI Header: Uses a list_of_ports.
    • ANSI Header: Uses list_of_port_declarations.
    • Parameterized Modules: Uses a parameter_port_list.
    • Extern Modules: Declared using the extern keyword.

    Interface Declarations

    Interfaces define groups of signals and can be declared as:

    • Non-ANSI Header: Uses a list_of_ports.
    • ANSI Header: Uses list_of_port_declarations.
    • Parameterized Interfaces: Uses a parameter_port_list.
    • Extern Interfaces: Declared using the extern keyword.

    Program Declarations

    Programs are used for testbench code and follow similar header patterns (Non-ANSI, ANSI, Parameterized, or Extern) as modules and interfaces.

  8. SystemVerilog Package and Scope Access

    master

    Accessing items within specific scopes is handled via the package_scope or ps_identifier patterns.

    • Package Scope: Uses the :: operator (e.g., package_name::item).
    • Unit Scope: Uses the $unit:: syntax to access items in the compilation unit.
    • Hierarchical Access: Uses the $ prefix followed by a dot-separated path (e.g., $root.module.signal).
    package_scope ::= package_identifier `::` | `$`unit `::` 
    hierarchical_identifier ::= [ `$`root `.` ] { [identifier] [constant_bit_select] `.` } [identifier]
  9. Assertion statements

    master

    Assertions are used to verify properties of the design.

    • Immediate Assertions: assert (expression) checks a condition immediately. Can be deferred using #0 or final to check at the end of a time step.
    • Concurrent Assertions: Typically used with clocking events to check properties over time.
    • Keywords: assert, assume, and cover are used to define the type of check or coverage goal.
    assert (a == b) $display("Match");
    assert #0 (condition); // Deferred immediate assertion
  10. Parallel and sequential blocks

    master

    SystemVerilog provides mechanisms for controlling the execution order of statements.

    • Sequential Block (begin ... end): Statements are executed one after another in the order they appear.
    • Parallel Block (fork ... join): Statements are executed in parallel. The join keyword determines when the block finishes:
      • join: Waits for all processes in the fork to complete.
      • join_any: Waits for any one of the processes to complete.
      • join_none: Does not wait for any processes; the execution continues immediately.
    begin : my_block
      statement1;
      statement2;
    end
    
    fork
      statement1;
      statement2;
    join_any
  11. How SystemVerilog enums are transpiled to C++

    master

    SystemVerilog enums are transpiled into a C++ struct rather than a raw enum. This allows the tool to provide helper methods for serialization, deserialization, and string conversion.

    Generated Structure Features

    • Inner Enum: An internal enum Type : uint32_t holds the actual values.
    • Serialization: A constructor my_enum(uint32_t data) that uses a switch statement to map raw values to enum members.
    • String Conversion: An overloaded operator<< for std::ostream to print the enum name.
    • Type Conversion: Overloaded operator uint64_t() for casting to numeric types and operator() to access the underlying Type.

    Example

    SystemVerilog:

    package bar;
        typedef enum {ONE = 5, TWO, THREE} my_enum /* public */;
    endpackage

    Generated C++:

    namespace bar {
        struct my_enum {
            enum Type : uint32_t {
                ONE = 5,
                TWO = 6,
                THREE = 7
            };
            static constexpr size_t _size = 32;
            Type type;
            my_enum(uint32_t data) { /* ... switch logic ... */ }
            // ... other operators ...
        };
    }
  12. How SystemVerilog structs are transpiled to C++

    master

    SystemVerilog structs are transpiled into C++ structs that support serialization and deserialization to/from raw bit vectors.

    Key Features

    • Member Types: Non-struct/non-enum members are transpiled as uint32_t, uint64_t, or sc_bv<N> (SystemC bit vector).
    • Bit Manipulation: The struct includes static constants for bit offsets (_s) and widths (_w) for every member, and constructors that use bit-shifting to pack/unpack data.
    • SystemC Support: If a member or the struct itself exceeds 64 bits, SystemC support must be enabled via the tool's configuration.
    • Utility Methods: Includes to_string(), operator<<, and static get_<member>() methods for easy access.

    Example

    SystemVerilog:

    package bar;
        typedef struct packed {
            logic [7:0]   b;
            logic [15:0]  h;
            logic [31:0]  w;
        } bar_struct /* public */;
    endpackage

    Generated C++ Snippet:

    namespace bar {
        struct bar_struct {
            uint32_t w;
            uint32_t h;
            uint32_t b;
            static constexpr size_t w_s = 0;
            static constexpr size_t w_w = 32;
            // ... other offsets/widths ...
            bar_struct(const uint64_t& data) { /* bit-shifting logic */ }
            operator uint64_t() const { /* packing logic */ }
        };
    }