In complex testbenches, some variable declarations end up with a long data-type specification, or need to be used in multiple places throughout the code. A typedef gives a user-defined name to an existing data type, so that name can be reused everywhere afterward — avoiding the need to edit multiple places if the underlying type ever needs to change.
10 min read | Intermediate Level
What You'll Learn
- How
typedefcreates a reusable name for a data type, useful for long or repeated type specifications - Why assigning a value wider than a typedef'd type still truncates, exactly as it would for any variable of that width
- The difference between
typedef(a new name for a type) andalias(multiple names for the same physical net) - Why
aliasonly works on nets, never on variables
Typedef
// Normal declaration may turn out to be quite long
shortint unsigned my_data;
enum {RED, YELLOW, GREEN} e_light;
bit [7:0] my_byte;
// Declare an alias for this long definition
typedef shortint unsigned u_shorti;
typedef enum {RED, YELLOW, GREEN} e_light;
typedef bit [7:0] ubyte;
// Use these new data-types to create variables
u_shorti my_data;
e_light light1;
ubyte my_byte;
Syntax
typedef data_type type_name [range];
Example
module tb;
typedef shortint unsigned u_shorti;
typedef enum {RED, YELLOW, GREEN} e_light;
typedef bit [7:0] ubyte;
initial begin
u_shorti data = 32'hface_cafe;
e_light light = GREEN;
ubyte cnt = 8'hFF;
$display ("light=%s data=0x%0h cnt=%0d", light.name(), data, cnt);
end
endmodule
Output
ncsim> run light=GREEN data=0xcafe cnt=255 ncsim: *W,RNQUIE: Simulation is complete.
data shows 0xcafe, not the full 0xface_cafe that was assigned. u_shorti is typedef'd from shortint unsigned, which is only 16 bits wide — assigning a 32-bit literal to it truncates down to the lower 16 bits, exactly as it would for any ordinary 16-bit variable. A typedef only renames an existing type; it doesn't change any of that type's own behavior, including its width.
Quick Check
Q: Why does data end up as 0xcafe specifically, rather than being truncated to some other value?
Show Answer
Because truncation to a narrower width keeps the lower bits and discards the upper ones. 32'hface_cafe's lower 16 bits are cafe — that's exactly what survives once the value is forced into a 16-bit u_shorti.
Alias
An alias statement declares multiple names for the same physical net — it does not work on variables. Per IEEE 1800 §10.11 ("Net aliasing"): "Variables and hierarchical references cannot be used in alias statements." It's mainly used to model a bi-directional short-circuit connection, and can appear inside modules, interfaces, and generate blocks.
wire [7:0] data;
wire [7:0] mydata;
alias mydata = data; // "mydata" and "data" now name the same physical net
assign data = 8'hFF; // drives the shared net -- mydata reads back 8'hFF too
data and mydata are two names for the exact same physical net, so driving data is indistinguishable from driving mydata — unlike a variable, a wire is driven with a continuous assign (or force), not a plain procedural =.
Quick Check
Q: Could alias be used to give a second name to a logic variable driven procedurally inside an always block?
Show Answer
No. alias only works on nets — variables and hierarchical references are explicitly disallowed, per the IEEE 1800 citation above. A logic variable driven procedurally isn't a valid target for alias at all.
Where Is This Used?
typedef is commonly used in testbenches to give a project's own custom bit-widths — like a 21-bit address or a 4-bit opcode — a meaningful, consistent name used everywhere, so a later width change only requires editing one typedef line rather than hunting down every individual declaration. alias is far more specialized, mostly seen in low-level net modeling, such as bidirectional pad or pin connections, rather than everyday testbench code.
Common Beginner Mistakes
Mistake #1: Forgetting a typedef'd type can still be narrower than expected
As the u_shorti example shows, a typedef doesn't change the underlying type's width or behavior — only its name. Why? Assigning a wider value than the typedef'd type can hold still truncates silently, exactly as it would without the typedef at all.
Mistake #2: Trying to use alias on a variable instead of a net
As the second Quick Check shows, this is explicitly disallowed by the LRM. Why? alias exists specifically to name a physical net, not to create a second reference to a variable's storage — that's a different problem entirely, and not one alias solves.
Mistake #3: Assuming typedef and alias solve the same problem
They don't — typedef names a type, used to declare new variables; alias names an existing net, creating no new storage at all. Why? Confusing the two means reaching for the wrong construct: typedef can't connect two existing signals together, and alias can't be used to declare a new variable.
Mistake #4: Redeclaring the same typedef separately in every file that needs it
If the same custom type needs to be used across multiple files, repeating its typedef in each one risks the definitions silently drifting out of sync. Why? Declaring it once inside a shared package and importing it everywhere keeps every file working from the exact same definition.
Practice Exercise
Challenge: Predict a Truncation
Given typedef bit [11:0] u_addr; (a 12-bit type), what value would a variable of type u_addr hold if assigned 16'hABCD?
Hint
Truncation to a narrower width keeps the lower bits and discards the upper ones — the same pattern demonstrated in this article's own u_shorti example.
Solution
12'hBCD. 16'hABCD's lower 12 bits are BCD — the upper nibble (A) is discarded, since u_addr is only 12 bits wide, exactly the same truncation behavior shown for u_shorti in this article.
Summary
In this tutorial, you learned:
typedefgives a reusable name to an existing data type, useful for long specifications or types used repeatedly throughout a testbench- A typedef'd type keeps every behavior of its underlying type, including its width — assigning a wider value than it can hold still truncates silently
aliasdeclares multiple names for the same physical net, and works only on nets — never on variables or hierarchical referencestypedefandaliassolve different problems: one names a type for declaring new variables, the other names an existing net with no new storage created