SystemVerilog, standardized as IEEE 1800 by the Institute of Electrical and Electronics Engineers (IEEE), is a hardware description and hardware verification language commonly used to model, design, simulate, test and implement electronic systems in the semiconductor and electronic design industry. SystemVerilog is an extension of Verilog.

History SystemVerilog started with the donation of the Superlog language to Accellera in 2002 by the startup company Co-Design Automation.Rich, D. “The evolution of SystemVerilog” IEEE Design and Test of Computers, July/August 2003 The bulk of the verification functionality is based on the OpenVera language donated by Synopsys. In 2005, SystemVerilog was adopted as IEEE Standard 1800-2005.IEEE approves SystemVerilog, revision of Verilog In 2009, the standard was merged with the base Verilog (IEEE 1364-2005) standard, creating IEEE Standard 1800-2009.

The SystemVerilog standard was subsequently updated in 2012,IEEE 1800-2012, IEEE, 2012 2017,IEEE 1800-2017, IEEE, 2017 and most recently in December 2023.IEEE 1800-2023, IEEE Standard for SystemVerilog--Unified Hardware Design, Specification, and Verification Language, IEEE, 2023

Design features

The feature-set of SystemVerilog can be divided into two distinct roles:

SystemVerilog for register-transfer level (RTL) design is an extension of Verilog-2005; all features of that language are available in SystemVerilog. Therefore, Verilog is a subset of SystemVerilog. SystemVerilog for verification uses extensive object-oriented programming techniques and is more closely related to Java than Verilog. These constructs are generally not synthesizable.

The remainder of this article discusses the features of SystemVerilog not present in Verilog-2005.

Data lifetime There are two types of data lifetime specified in SystemVerilog: static and automatic. Automatic variables are created the moment program execution comes to the scope of the variable. Static variables are created at the start of the program's execution and keep the same value during the entire program's lifespan, unless assigned a new value during execution.

Any variable that is declared inside a task or function without specifying type will be considered automatic. To specify that a variable is static place the "static" keyword in the declaration before the type, e.g., "static int x;". The "automatic" keyword is used in the same way.

New data types Enhanced variable types add new capability to Verilog's "reg" type: logic [31:0] my_var;

Verilog-1995 and -2001 limit reg variables to behavioral statements such as RTL code. SystemVerilog extends the reg type so it can be driven by a single driver such as gate or module. SystemVerilog names this type "logic" to remind users that it has this extra capability and is not a hardware register. The names "logic" and "reg" are interchangeable. A signal with more than one driver (such as a tri-state buffer for general-purpose input/output) needs to be declared a net type such as "wire" so SystemVerilog can resolve the final value.

Multidimensional packed arrays unify and extend Verilog's notion of "registers" and "memories": logic [1:0][2:0] my_pack;

Classical Verilog permitted only one dimension to be declared to the left of the variable name. SystemVerilog permits any number of such "packed" dimensions. A variable of packed array type maps 1:1 onto an integer arithmetic quantity. In the example above, each element of my_pack may be used in expressions as a six-bit integer. The dimensions to the right of the name (32 in this case) are referred to as "unpacked" dimensions. As in Verilog-2001, any number of unpacked dimensions is permitted.

Enumerated data types (enums) allow numeric quantities to be assigned meaningful names. Variables declared to be of enumerated type cannot be assigned to variables of a different enumerated type without casting. This is not true of parameters, which were the preferred implementation technique for enumerated quantities in Verilog-2005:

typedef enum logic [2:0] { RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW } color_t;

color_t my_color = GREEN; initial $display("The color is %s", my_color.name());

As shown above, the designer can specify an underlying arithmetic type (logic [2:0] in this case) which is used to represent the enumeration value. The meta-values X and Z can be used here, possibly to represent illegal states. The built-in function name() returns an ASCII string for the current enumerated value, which is useful in validation and testing.

New integer types: SystemVerilog defines byte, shortint, int and longint as two-state signed integral types having 8, 16, 32, and 64 bits respectively. A bit type is a variable-width two-state type that works much like logic. Two-state types lack the X and Z metavalues of classical Verilog; working with these types may result in faster simulation.

Structures and unions work much like they do in the C language. SystemVerilog enhancements include the packed attribute and the tagged attribute. The tagged attribute allows runtime tracking of which member(s) of a union are currently in use. The packed attribute causes the structure or union to be mapped 1:1 onto a packed array of bits. The contents of struct data types occupy a continuous block of memory with no gaps, similar to bit fields in C and C++:

typedef struct packed { bit [10:0] expo; bit sign; bit [51:0] mant; } FP;

FP zero = 64'b0;As shown in this example, SystemVerilog also supports typedefs, as in C and C++.

Procedural blocks SystemVerilog introduces three new procedural blocks intended to model hardware: always_comb (to model combinational logic), always_ff (for flip-flops), and always_latch (for latches). Whereas Verilog used a single, general-purpose always block to model different types of hardware structures, each of SystemVerilog's new blocks is intended to model a specific type of hardware, by imposing semantic restrictions to ensure that hardware described by the blocks matches the intended usage of the model. An HDL compiler or verification program can take extra steps to ensure that only the intended type of behavior occurs.

An always_comb block models combinational logic. The simulator infers the sensitivity list to be all variables from the contained statements:

always_comb begin tmp = b * b - 5'h4 * a * c; no_root = (tmp < 0); end

An always_latch block models level-sensitive latches. Again, the sensitivity list is inferred from the code:

always_latch if (en) q <= d;

An always_ff block models synchronous logic (especially edge-sensitive sequential logic):

always_ff @(posedge clk) count <= count + 4'd1;

Electronic design automation (EDA) tools can verify the design's intent by checking that the hardware model does not violate any block usage semantics. For example, the new blocks restrict assignment to a variable by allowing only one source, whereas Verilog's always block permitted assignment from multiple procedural sources.

When performing arithmetic operations with static numeric literals in RTL code, it is important to explicitly specify the bit-width of constants to avoid unintended truncation, linting violations or synthesis issues. This is particularly critical in combinational and sequential logic blocks. When operands lack explicit bit specifications, simulators and synthesis tools may infer widths based on context or default to implementation-specific sizes, potentially causing data loss or unexpected behavior during simulation or hardware implementation.

Interfaces For small designs, the Verilog port compactly describes a module's connectivity with the surrounding environment. But major blocks within a large design hierarchy typically possess port counts in the thousands. SystemVerilog introduces the concept of interfaces to both reduce the redundancy of port-name declarations between connected modules, as well as group and abstract related signals into a user-declared bundle. An additional concept is modport, which shows the direction of logic connections.

Example:

interface intf; logic a; logic b; modport in (input a, output b); modport out (input b, output a); endinterface

module top; intf i (); u_a m1 (.i1(i.in)); u_b m2 (.i2(i.out)); endmodule

module u_a (intf.in i1); endmodule

module u_b (intf.out i2); endmodule

Verification features The following verification features are typically not synthesizable, meaning they cannot be implemented in hardware based on HDL code. Instead, they assist in the creation of extensible, flexible test benches.

New data types The string data type represents a variable-length text string. For example: string s1 = "Hello"; string s2 = "world"; string p = ".?!"; string s3 = {s1, ", ", s2, p}; // string concatenation $display("[%d] %s", s3.len(), s3); // simulation will print: " Hello, world!"

In addition to the static array used in design, SystemVerilog offers dynamic arrays, associative arrays and queues:

int cmdline_elements; // # elements for dynamic array int da[]; // dynamic array int ai[int]; // associative array, indexed by int int as[string]; // associative array, indexed by string int qa[$]; // queue, indexed as an array, or by built-in methods

initial begin cmdline_elements = 16; da = new[ cmdline_elements ]; // Allocate array with 16 elements end

A dynamic array works much like an unpacked array, but offers the advantage of being dynamically allocated at runtime (as shown above.) Whereas a packed array's size must be known at compile time (from a constant or expression of constants), the dynamic array size can be initialized from another runtime variable, allowing the array to be sized and resize arbitrarily as needed.

An associative array can be thought of as a binary search tree with a user-specified key type and data type. The key implies an ordering; the elements of an associative array can be read out in lexicographic order. Finally, a queue provides much of the functionality of the C++ STL deque type: elements can be added and removed from either end efficiently. These primitives allow the creation of complex data structures required for scoreboarding a large design.

Classes SystemVerilog provides an object-oriented programming model.

In SystemVerilog, classes support a single-inheritance model, but may implement functionality similar to multiple-inheritance through the use of so-called "interface classes" (identical in concept to the interface feature of Java). Classes can be parameterized by type, providing the basic function of C++ templates. However, template specialization and function templates are not supported.

SystemVerilog's polymorphism features are similar to those of C++: the programmer may specifically write a virtual function to have a derived class gain control of the function. See virtual function for further information.

Encapsulation and data hiding is accomplished using the local and protected keywords, which must be applied to any item that is to be hidden. By default, all class properties are public.

Class instances are dynamically created with the new keyword. A constructor denoted by function new can be defined. SystemVerilog has automatic garbage collection, so there is no language facility to explicitly destroy instances created by the new operator.

Example:

virtual class Memory; virtual function bit [31:0] read(bit [31:0] addr); endfunction virtual function void write(bit [31:0] addr, bit [31:0] data); endfunction endclass

class SRAM #(parameter AWIDTH=10) extends Memory; bit [31:0] mem [1<<AWIDTH];

virtual function bit [31:0] read(bit [31:0] addr); return mem[addr]; endfunction

virtual function void write(bit [31:0] addr, bit [31:0] data); mem[addr] = data; endfunction endclass

Constrained random generation