Data Types Interview Questions

Master SystemVerilog data types: logic vs wire, packed vs unpacked arrays, structs, unions, and type casting.

Beginner Level

Fundamentals
What is the difference between reg, logic, and wire? When would you use each?

wire: Used for structural connections. Can have multiple drivers (resolved net). Primarily for connecting module ports and continuous assignments.

reg: Legacy Verilog type. Holds a value in procedural blocks. Despite the name, it does NOT necessarily synthesize to a register—it depends on usage.

logic: SystemVerilog's 4-state replacement for both reg and wire. Key restriction: can only have ONE driver. This improves simulation performance and catches accidental multi-driver bugs at compile time.

Rule: Use logic everywhere unless you specifically need a resolved net with multiple drivers (then use wire).

Explain the difference between a packed array and an unpacked array. Give a one-line example of each.

Packed Array: Dimensions declared BEFORE the variable name. Stored as a contiguous block of bits. Can be used in arithmetic and bit-select operations.

bit [7:0] packed_byte;  // 8 contiguous bits

Unpacked Array: Dimensions declared AFTER the variable name. Each element may be stored separately. Cannot be directly assigned as a single bit-vector.

bit unpacked_byte [7:0];  // 8 separate bits (potentially non-contiguous)

Key Difference: packed_byte + 1 is valid arithmetic. unpacked_byte + 1 is a compile error.

What is an enum? How do you iterate over all values of an enum?

An enum defines a set of named constants, improving code readability and preventing magic numbers.

typedef enum {IDLE, RUN, DONE} state_e;
state_e current_state;
// Iterate over all values:
state_e s = s.first();
do begin
    $display("State: %s", s.name());
    s = s.next();
end while (s != s.first());

Methods: .first(), .last(), .next(), .prev(), .num(), .name().

Intermediate Level

Industry Standard
What is the difference between == and === in SystemVerilog? When would you specifically use ===?

== (Logical Equality): Returns x if either operand contains x or z. Used for standard comparison.

=== (Case Equality): Compares bit-by-bit including x and z values. Returns 1'b1 or 1'b0 only—never x.

Use Case for ===: Checking if a signal is explicitly x or z, e.g., during reset verification:

if (data_out === 4'bxxxx) $display("Output is undefined!");
if (tristate_bus === 8'bzzzz_zzzz) $display("Bus is high-Z!");
You have a typedef struct packed with a 4-bit field and an 8-bit field. What is the total size? Can you treat the entire struct as a single bit vector?

A packed struct stores all fields contiguously. Total size = 4 + 8 = 12 bits.

typedef struct packed {
    logic [3:0] tag;    // 4 bits
    logic [7:0] data;   // 8 bits
} packet_t;             // Total: 12 bits
packet_t pkt;
logic [11:0] raw_bits;
raw_bits = pkt;         // Valid! Direct assignment.
pkt = 12'hABC;          // Valid! Assign as bit-vector.

Gotcha: If the struct were unpacked, this direct cast would NOT be allowed.

(Debug Scenario) A designer uses a string variable to build a log message inside a high-speed loop. The simulation is extremely slow. Why, and what's the fix?

Problem: In SystemVerilog, string is a dynamic type. Every concatenation like msg = {msg, "new text"} allocates new memory and copies the old string—an O(n²) complexity nightmare inside a loop.

Fix:

  • Use $sformatf() for one-shot formatting instead of incremental concatenation.
  • Or, move logging outside the critical loop.
  • Or, use a queue of strings and join them once at the end.
// Slow:
string msg;
for (int i = 0; i < 1000; i++) msg = {msg, $sformatf("iter %0d ", i)};
// Fast:
$display("iter %0d to %0d processed", 0, 999);

Advanced Level

Expert
(Size Calculation) Calculate the total memory for this declaration in bits. Is lines a packed or unpacked structure? Can you pass it to a DPI-C function directly?
typedef struct packed {
    logic valid;         // 1 bit
    logic [3:0] tag;     // 4 bits
    logic [31:0] data;   // 32 bits
} cache_line_t;          // Total: 37 bits per element
cache_line_t lines [4][8]; // 4 x 8 = 32 elements

Total: 32 elements × 37 bits = 1184 bits.

Structure: cache_line_t is packed, but lines [4][8] is an unpacked array of packed structs.

DPI-C: Cannot be passed directly! DPI-C requires packed types or specific open_array handling. You'd need to flatten it or use svOpenArrayHandle.

Explain the $cast() system function. When would a static cast fail but $cast() succeeds at runtime?

$cast() performs a dynamic type check at runtime, primarily used for class handle downcasting.

class Animal; endclass
class Dog extends Animal; endclass
Animal a = new Dog();
Dog d;
// Static cast: d = Dog'(a); // Compile warning/error – no type safety check.
// Dynamic cast:
if ($cast(d, a)) $display("Cast OK! d is now a valid Dog handle.");
else $display("Cast failed. a was not pointing to a Dog.");

Key Use: When you have a base-class handle that might point to a derived-class object, and you need to access derived-class members. $cast() succeeds only if the runtime type is compatible.

What is a union in SystemVerilog? Create a union that interprets the same 32 bits as either a shortreal, an int, or a 4-byte array.

A union allows multiple data types to share the same memory. Useful for type-punning (reinterpreting bits without conversion).

typedef union packed {
    shortreal  f;         // IEEE 754 float
    int        i;         // Signed 32-bit integer
    byte       b [4];     // 4 bytes
} multi_view_t;
multi_view_t data;
data.i = 32'h41200000;          // Binary for 10.0 in IEEE 754
$display("As float: %f", data.f);   // Should print 10.0
$display("Byte 0: 0x%h", data.b[0]);

Caveat: Packed unions require all members to have the same bit width. For unpacked unions, members can be different types but only one is valid at a time.

What is the difference between byte, shortint, int, and longint? Are they signed or unsigned by default?
Type Bits Default Signedness Range
byte 8 Signed -128 to 127
shortint 16 Signed -32768 to 32767
int 32 Signed -2³¹ to 2³¹-1
longint 64 Signed -2⁶³ to 2⁶³-1

Gotcha: All are signed by default. Use byte unsigned to get an unsigned type. This affects arithmetic and comparison operations significantly!