3 minute read

Simulation Event Scheduling

Video Tutorial

Watch this comprehensive video explanation of Data Type and Types:

Data Type and Types in SystemVerilog

In SystemVerilog, a signal is defined with both a Data Type and a Type.


Data Type

Data types can be broadly categorized into Nets and Variables.

  • Nets are like physical wires, representing connections between components. They connect a driver (source) to a receiver (destination), transmitting signals between parts of a design.
  • Variables are abstract storage elements, used mainly in simulation. For synthesis, variables might translate into physical registers based on their definition and usage.

Type

Types are distinguished by the number of states they can represent:

  • 2-state types: Can hold values of 0 or 1.
  • 4-state types: Can represent 0, 1, high impedance (Z), or unknown (X).

  • The keyword logic declares a variable or a net as a 4-state type.
  • The keyword bit declares a 2-state type.

Variables can be either 2-state or 4-state types.
Nets are restricted to being only 4-state types.


Nets

Nets function as connections, not storage elements. They represent the current value of their driver, can have multiple drivers, and must be of the logic type.

If a signal is used but not explicitly declared, it is typically inferred as a net.

Type Description
wire An interconnection wire that can have multiple drivers
tri Exactly the same as wire. It can be used to emphasize tri-state values

Net Data Type

Nets: Declaration and assignment examples:

Explicit continuous assignment:

wire logic [31:0] data; // 32-bit packed vector
assign data = a * b;    // Explicit continuous assignment

Implicit continuous assignment:

wire logic [31:0] data = a * b; // Implicit continuous assignment

Both methods are functionally equivalent.

Note:

  • Nets cannot have subfields (e.g., no wire logic [7:0][7:0] data8;)
  • Nets must be packed arrays, not unpacked arrays (e.g., wire logic [7:0] data8[7:0]; is illegal).

Variables

Within procedural blocks (like always blocks), the left-hand side of an assignment must be a variable.

  • 4-state variables: Use var logic for values that can be 0, 1, X, or Z.
  • 2-state variables: Use var bit for values restricted to 0 or 1.

Best practice: Use the logic type for variables in RTL code to allow the simulator to detect indeterminate states (X).
Use bit type mainly for iterators in for loops or testbenches.

Type Description Equivalent n-state Default Sign
integer 32-bit variable var logic[31:0] 4-state signed
bit General purpose variable - 2-state unsigned
byte 8-bit variable var bit[7:0] 2-state signed
shortint 16-bit variable var bit[15:0] 2-state signed
int 32-bit variable var bit[31:0] 2-state signed
longint 64-bit variable var bit[63:0] 2-state signed

Synthesizable Variable Data Types

  • Use 2-state data types (bit) primarily for validation and testbench development. This enhances simulation efficiency.
  • Use 4-state data types (logic) for RTL code to catch indeterminate logic.

Logic Data Type

The logic data type is versatile:

  • By default, logic is interpreted as a variable (var logic).
  • For input or inout ports, logic is interpreted as a net (wire logic).

Variables do not support multiple drivers. For multi-driven signals (e.g., tri-state buses), use wire logic or tri logic.

General guideline: Use the logic data type for signals. Use wire logic or tri logic only for multi-driven signals.


Logic (Variable): Declaration and Assignment

Scalar declaration:

logic a; // 1-bit unsigned variable

Vector declaration:

logic [31:0] data_le; // 32-bit vector, little endian (MSB is bit 31, LSB is bit 0)
logic [0:31] data_be; // 32-bit vector, big endian (MSB is bit 0, LSB is bit 31)

Signed vector:

logic signed [15:0] data_sn; // 16-bit signed variable

Bit and range select:

logic [31:0] bus;
logic [7:0] data8;
assign bus = data_le;           // copy entire data_le into bus
assign a = data_be[5];          // fixed bit select (selects bit at index 5)
assign data8 = data_le[15:8];   // 8-bit part select (bits 15 down to 8)

Important: The range in part-selects should follow the declaration’s endianness.


Variable Bit Select and Range Select

Variable bit select:

assign bus[0] = data_le[a];

Variable range select ([start +: width] or [start -: width]):

// [start +: width] expands to [start : (start + width - 1)]
// [start -: width] expands to [start : (start - width + 1)]
assign data8 = data_le[15-:8]; // equivalent to data_le[15:8]

Parameterized variable range select:

parameter WIDTH = 32;
logic [WIDTH-1:0] data;
logic [7:0] slice;
logic [4:0] start;
assign start = 3;
assign slice = data[start +: WIDTH]; // Accessing a slice based on 'start' and 'WIDTH'