A static cast is a SystemVerilog feature that converts an expression from one data type to another, using the single-quote (') operator. This is different from $cast — covered in SystemVerilog Cast Dynamic — which performs its check at run time and can fail gracefully. A static cast's type compatibility is checked once, at compile time, with no run-time validity check at all. The conversion itself, though, still runs at simulation time whenever its operand isn't a constant — casting a variable or signal costs the same as any other expression; it's only the type-checking that's free.

9 min read | Intermediate Level

What You'll Learn

  • What a static cast is, and how it differs from $cast
  • How casting a string to an integer packs its trailing bytes into a fixed-width value
  • The real distinction between real-to-integer truncation and bit-width truncation
  • Why a static cast doesn't perform any run-time validity checking

Syntax


'(value or variable or expression)

The type being cast to comes immediately before the single quote — for example, int'(expr) — and the value or expression being cast must be in parentheses.

Static Cast vs $cast

Static cast (type'(expr))$cast
When checkedCompile timeRun time
On an invalid conversionSilently produces whatever the reinterpreted bits happen to mean — no errorRuntime error (as a task) or returns 0 (as a function)
Performance impactNo run-time cost for the type check; the conversion itself still runs whenever its operand isn't a constantRun-time overhead for both the validity check and the conversion

Casting a String to an Integer

A string can be cast to a compatible data type like int:


module tb;
  
	initial begin  
    $display("data=%0d", int'("Hello World"));
end
endmodule  

Output

Output
xcelium> run
data=1869769828
xmsim: *W,RNQUIE: Simulation is complete.

This number isn't arbitrary. int is 4 bytes wide, and "Hello World" is 11 characters — too many to fit. Only the last 4 characters, "orld", actually get packed into the result, each character's ASCII code becoming one byte: o=0x6F, r=0x72, l=0x6C, d=0x64, giving 0x6F726C64 — which is exactly 1869769828 in decimal.

Quick Check

Q: What would int'("World") produce?

Show Answer

The exact same value, 1869769828. "World" is 5 characters, so only its last 4 — "orld" — get packed, which happens to be identical to the last 4 characters of "Hello World".

Real-to-Integer Truncation

Casting a computed real expression to int drops the fractional part entirely:


  module tb;
  
	initial begin
    $display("data=%0.3f", int'(3.4 + 2 * 1.5));
end
endmodule  

Output

Output
 	xcelium> run
data=6.000
xmsim: *W,RNQUIE: Simulation is complete.

3.4 + 2 * 1.5 evaluates to 6.4, and int'(...) truncates that down to the integer 6, discarding the fractional part rather than rounding it.


module tb;
	int 	data;
  
	initial begin
		data = int'(3.145);
		$display("data=%0.3f", data);
end
endmodule  

Output

Output
 	xcelium> run
data=3.000
xmsim: *W,RNQUIE: Simulation is complete.

int'(3.145) similarly truncates to 3. It's worth being precise about what's happening here: this is real-to-integer truncation — dropping the fractional part of a real number — which is a different mechanism from truncating the bits of a wide integer value, covered next.

Bit-Width Truncation (Narrowing a Vector)

Casting a wider integer value into a narrower type keeps only its least significant bits, discarding everything above that width:


module tb;
  bit [31:0] wide = 32'hDEAD_BEEF;
  bit [15:0] narrow;

  initial begin
    narrow = 16'(wide);
    $display ("narrow = 0x%0h", narrow);
  end
endmodule

This prints narrow = 0xbeef — only the lower 16 bits of 32'hDEAD_BEEF survive the cast; the upper half (DEAD) is simply discarded, with no warning or error of any kind.

This is the property the previous section's int'(3.145) example doesn't actually demonstrate. Truncating a real number's fractional part and truncating a wide integer's most significant bits are two genuinely different mechanisms — both fall under "truncation" loosely, but they don't behave the same way, and it's easy to conflate the two.

Quick Check

Q: Using the same 32'hDEAD_BEEF value, what would 8'(wide) produce?

Show Answer

0xEF — just the single lowest byte. Narrowing to 8 bits keeps only the lowest 8 bits of the original 32-bit value, discarding the rest.

Other Properties

  • Static cast enforces type safety at compile time — it won't allow casting between genuinely incompatible data types (like two unrelated class handles with no relationship to each other).
  • It's applicable to both variables and full expressions, not just simple values.
  • It's generally described as preserving the signedness of the source value, though this depends on the specific source and target types involved — when in doubt, verify the actual result for your specific case rather than assuming.

Where Is Static Cast Used?

Static cast is commonly used when deliberately packing or narrowing a value into a fixed-width field — preparing data for a DPI call with a specific expected width, or extracting a specific byte or field from a wider computed value — situations where the conversion is known to be intentional and correct, so $cast's run-time checking overhead isn't needed.

Common Beginner Mistakes

Mistake #1: Confusing static cast with $cast

A static cast performs zero run-time checking — an invalid or lossy conversion succeeds silently, with no error and no way to detect failure. Why? If there's a real chance a cast might not be meaningful (like recovering a specific class type from a base handle), $cast is the right tool, since it can actually report failure; a static cast simply reinterprets bits and moves on.

Mistake #2: Assuming int'(3.145) demonstrates bit-width truncation

As explained above, this is real-to-integer truncation — dropping a fractional part — not the same mechanism as narrowing a wide integer value down to fewer bits. Why? The two are easy to conflate since both are casually called "truncation," but they behave differently and apply to different situations.

Mistake #3: Mixing a %f format specifier with a non-real value

%f is meant for real-valued arguments, yet several examples in this article pass an already-cast integer to it. Why? While some simulators display a reasonable-looking result anyway, this isn't guaranteed portable behavior across every tool — match your format specifier to your actual argument's type to avoid relying on simulator-specific leniency.

Mistake #4: Assuming a lossy static cast is always harmless

As the bit-width truncation example shows, a static cast that discards real data does so completely silently. Why? There's no warning when a narrowing cast throws away meaningful bits — it's on the code's author to be certain the narrower type is actually wide enough for the values that will realistically flow through it.

Practice Exercise

Challenge: Predict a String-to-Int Cast

Using the same last-4-characters rule demonstrated in this article, predict the result of int'("Verilog").

Hint

"Verilog" is 7 characters — identify the last 4, convert each to its ASCII hex value, and pack them together the same way "Hello World" packed down to "orld".

Solution

1768714087. The last 4 characters of "Verilog" are "ilog": i=0x69, l=0x6C, o=0x6F, g=0x67, packed as 0x696C6F67 — which is 1768714087 in decimal.

Summary

In this tutorial, you learned:

  • A static cast (type'(expr)) converts a value's type at compile time, with no run-time validity checking — unlike $cast
  • Casting a string to an integer type packs only as many trailing characters as fit the target width, each becoming one byte
  • Real-to-integer casting truncates the fractional part; bit-width narrowing truncates the most significant bits of a wide integer value — two genuinely different mechanisms, both loosely called "truncation"
  • A lossy or narrowing static cast succeeds silently, with no warning that data was discarded
  • Static cast is best used when a conversion is already known to be correct and intentional, since it has no way to report failure the way $cast can
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5