Skip to main content

SystemVerilog Data Types

· loading · loading · ·
Hardware Design Verification SystemVerilog Verilog RTL Design Data Types Synthesis Simulation
Hardware Design Verification
Axolot Logic
Author
Axolot Logic
Digital Design Engineer
Table of Contents
SystemVerilog Design Series - This article is part of a series.
Part 2: This Article

🔄 Legacy Data Types in SystemVerilog
#

SystemVerilog supports all Verilog-2001 data types for backward compatibility, but modern designs are encouraged to use SystemVerilog’s enhanced type system. The table below outlines commonly encountered legacy types and their modern replacements:


📘 Recommended Read: 👉 check out the Verilog Data Types Guide.

📜 Legacy Data Types Table
#

Verilog TypeSystemVerilog EquivalentUsage StatusNotes
reglogic⚠️ DeprecatedUse logic in RTL for better semantics and synthesis support
wirelogic or wire⚠️ Mixed UseUse wire only for multi-driver net connections
integerint⚠️ Limited Use32-bit signed; prefer int in new code
timelongint🧪 Simulation OnlyUsed for simulation time tracking; not synthesizable
realreal, shortreal🧪 Simulation Only64-bit (real) or 32-bit (shortreal) floating point; not synthesizable

graph LR
A[SystemVerilog Data Types] --> B[Base scalar]
A --> C[Component structures]
B --> D[bit, logic, int]
C --> E[struct, union]
C --> F[array, queue]

Types
#

TypeStatesSizeSignedDefault ValueCategoryNotes
bit0, 11-bit (scalar or packed)No02-StateUse in simulations or when X/Z not needed
logic0, 1, X, Z1-bit (scalar or packed)NoX4-StatePreferred over reg; for synthesizable RTL
reg0, 1, X, Z1-bit (scalar or packed)NoX4-StateLegacy type; replaced by logic
byteN/A8-bitYes0IntegerSigned by default
shortintN/A16-bitYes0Integer
intN/A32-bitYes0IntegerMost common integer type
longintN/A64-bitYes0Integer
integerN/A≥32-bit (impl. defined)Yes0IntegerLegacy from Verilog; prefer int or longint
timeN/A64-bitNo0TimingUsed for simulation time tracking
stringN/ADynamic lengthN/A""StringSupports .len(), .putc(), etc.

🔄 reg vs logic
#

// Verilog style
reg [7:0] counter;  // Only allowed inside procedural blocks

// SystemVerilog style
logic [7:0] counter; // Works in both 'assign' and 'always' blocks

logic offers clearer semantics and better compatibility with synthesis and tooling. ❌ reg is legacy and not recommended for new RTL.


🔌 Guidelines for Using wire
#

module example(
  input  wire a,      // Still common for input ports
  output logic b      // Preferred modern output
);
  wire c;
  assign c = a & b;    // Use only for multi-driver connections

  logic d;             // Use for internal signals
endmodule

🎯 Rule: Use wire only when multiple drivers are required. Otherwise, prefer logic for clarity and safety.


📅 Type Migration Guide
#

Usage ContextVerilog TypeRecommended SystemVerilog Type
Combinational Logicreglogic
Counters/Variablesintegerint or bit [31:0]
Floating Point Opsrealshortreal (32-bit)
Hardware Connectionswirelogic (single driver) or wire

🧪 Example: Mixed Legacy and Modern Types
#

module legacy_mix(
  input  wire clk,
  output logic [3:0] data
);
  integer i;             // Legacy signed 32-bit
  bit [31:0] j;          // Modern unsigned 32-bit

  always_ff @(posedge clk) begin
    i = -1;
    j = i;               // Signed to unsigned conversion
  end
endmodule

🧠 Both integer and int are 32-bit signed, but int is preferred in modern designs. bit holds only 0/1 and is ideal for 2-state modeling.


⚠️ Common Pitfalls
#

  1. Signedness Issues with integer:

    integer i = 32'hFFFF_FFFF; // Equals -1 (signed!)
    bit [31:0] b = i;          // Still 32'hFFFF_FFFF, but unsigned
    
  2. real Is Not Synthesizable:

    • Only usable in testbenches
    • Will be ignored or rejected by synthesis tools

🛠️ Initial Value & Multiple Driver Problem with logic
#

  logic [7:0] x;
  initial x = 8'hFF;
  always_ff @(posedge clk)
    x <= x + 1;

❗ In the example above, a logic variable is assigned an initial value (= 8'hFF) within an initial block and then reassigned in an always_ff block. ⚠️ A variable assigned within an always_ff block cannot be assigned in any other procedural block.

✅ To avoid this, choose following:

  logic [7:0] x;
  initial x = 8'hFF;
  always @(posedge clk)
    x <= x + 1;

✅ Best Practices for New Code
#

  • Use logic instead of reg for synthesizable RTL.
  • Use bit, int in testbenches for simpler simulation and better performance.
  • Use wire only when multiple drivers are necessary.
  • Replace integer with int, and real with shortreal where applicable.
  • Be cautious when assigning initial values to logic in FPGA code.
module datatype_testbench;

  // Data type declarations
  bit         b;
  logic       l;
  reg         r;
  wire        w;
  byte        bt;
  shortint    si;
  int         i;
  longint     li;
  integer     old_i;
  time        t;
  real        real_val;
  shortreal   sreal_val;
  string      str;

  assign w = b; // wire must be driven

  initial begin
    // Initial default values
    $display("----- [Initial Default Values] -----");
    $display("bit         = %b", b);
    $display("logic       = %b", l);
    $display("reg         = %b", r);
    $display("wire        = %b", w);
    $display("byte        = %0d", bt);
    $display("shortint    = %0d", si);
    $display("int         = %0d", i);
    $display("longint     = %0d", li);
    $display("integer     = %0d", old_i);
    $display("time        = %0t", t);
    $display("real        = %0f", real_val);
    $display("shortreal   = %0f", sreal_val);
    $display("string      = \"%s\" (length = %0d)", str, str.len());

    #5; // Wait for 5 time units

    // Assign signed values
    b         = -1'b1;
    l         = -1'b1;
    r         = -1'b1;
    bt        = -8'sd100;
    si        = -16'sd30000;
    i         = -32'sd12345678;
    li        = -64'sd1234567890123456;
    old_i     = -42;
    t         = -64'd500;
    real_val  = -3.141592;
    sreal_val = -2.71;
    str       = "SystemVerilog";

    $display("\n----- [Assigned Signed Values] / If signed it should negative -----");
    $display("bit         = %b", b);
    $display("logic       = %b", l);
    $display("reg         = %b", r);
    $display("wire        = %b", w);
    $display("byte        = %0d", bt);
    $display("shortint    = %0d", si);
    $display("int         = %0d", i);
    $display("longint     = %0d", li);
    $display("integer     = %0d", old_i);
    $display("time        = %0t", t);
    $display("real        = %0f", real_val);
    $display("shortreal   = %0f", sreal_val);
    $display("string      = \"%s\" (length = %0d)", str, str.len());

    // Bit widths using $bits()
    $display("\n----- [Bit Widths Using $bits()] -----");
    $display("$bits(bit)         = %0d", $bits(b));
    $display("$bits(logic)       = %0d", $bits(l));
    $display("$bits(reg)         = %0d", $bits(r));
    $display("$bits(byte)        = %0d", $bits(bt));
    $display("$bits(shortint)    = %0d", $bits(si));
    $display("$bits(int)         = %0d", $bits(i));
    $display("$bits(longint)     = %0d", $bits(li));
    $display("$bits(integer)     = %0d", $bits(old_i));
    $display("$bits(time)        = %0d", $bits(t));
    $display("real               = %0d", $bits(real_val));
    $display("shortreal          = %0d", $bits(sreal_val));
    $display("string             = \"%0d\" (uzunluk = %0d)", $bits(str), str.len());
    // Note: $bits() is not applicable to 'real', 'shortreal'
  end

endmodule

📤 Output:
#

# ----- [Initial Default Values] -----
# bit         = 0
# logic       = x
# reg         = x
# wire        = x
# byte        = 0
# shortint    = 0
# int         = 0
# longint     = 0
# integer     = x
# time        = 0
# real        = 0.000000
# shortreal   = 0.000000
# string      = "" (length = 0)
# 
# ----- [Assigned Signed Values] / If signed it should negative -----
# bit         = 1
# logic       = 1
# reg         = 1
# wire        = 0
# byte        = -100
# shortint    = -30000
# int         = -12345678
# longint     = -1234567890123456
# integer     = -42
# time        = -500
# real        = -3.141592
# shortreal   = -2.710000
# string      = "SystemVerilog" (length = 13)
# 
# ----- [Bit Widths Using $bits()] -----
# $bits(bit)         = 1
# $bits(logic)       = 1
# $bits(reg)         = 1
# $bits(byte)        = 8
# $bits(shortint)    = 16
# $bits(int)         = 32
# $bits(longint)     = 64
# $bits(integer)     = 32
# $bits(time)        = 64
# real               = 0
# shortreal          = 0
# string             = "104" (length = 13)

🔍 Why Are Legacy Types Still Around?
#

  • To support legacy IP and older toolchains
  • Useful for auto-conversion tools and wrappers
  • Much of the industry still relies on Verilog-2001 style code

SystemVerilog Design Series - This article is part of a series.
Part 2: This Article

Related

SystemVerilog Logic Data Type
· loading · loading
Hardware Design Verification SystemVerilog Logic RTL Design Verilog Synthesis Net vs Variable
Hardware Design Verification
SystemVerilog Intoduction
· loading · loading
Hardware Design Verification SystemVerilog Verilog RTL Design UVM Hardware Verification IEEE 1800
Hardware Design Verification
SystemVerilog Clocking Block – Timing Control for Testbenches
· loading · loading
Verification Hardware Design SystemVerilog Clocking Block RTL Design Testbench UVM Timing
Verification Hardware Design
SystemVerilog Enum Data Type
· loading · loading
Hardware Design Verification SystemVerilog Enum FSM RTL Design Testbench Debugging
Hardware Design Verification
SystemVerilog Unsized Literals
· loading · loading
Hardware Design SystemVerilog Literals RTL Design Initialization Synthesis Reset Logic
Hardware Design
SystemVerilog Blocking vs Non-Blocking Assignments Explained
· loading · loading
Hardware Design SystemVerilog Blocking Non-Blocking RTL Design Simulation Always Block
Hardware Design