SystemVerilog packages are powerful containers for reusable code such as data types, parameters, functions, classes, and tasks. They help engineers write modular and consistent designs by preventing type mismatches and enabling code sharing across modules, interfaces, and testbenches. In this post, we’ll explore package syntax, importing methods, common pitfalls, and examples that every VLSI learner must know.
Introduction
Think of a package as a toolbox in SystemVerilog:
- It stores commonly used definitions in one place.
- Ensures consistent type usage across your project.
- Helps with namespacing to avoid collisions.
- Improves maintainability and readability of RTL & testbenches.
Declaring a Package
package math_pkg;
parameter int PI = 314; // scaled by 100
function int area_circle(int radius);
return (PI * radius * radius) / 100;
endfunction
endpackage
Here, math_pkg
contains a constant and a function.
Accessing Package Members
Without Import
module top;
int result;
initial begin
result = math_pkg::area_circle(10);
$display("Circle area = %0d", result);
end
endmodule
Using pkg::item
keeps scope clear
With Import
import math_pkg::*;
module top;
int result;
initial begin
result = area_circle(5);
$display("Circle area = %0d", result);
end
endmodule
import
makes members available directly.
Selective Import
If a package has multiple items, you can import only what you need:
package str_pkg;
function string to_upper(string s);
foreach(s[i]) if (s[i] >= "a" && s[i] <= "z")
s[i] = s[i] - 32;
return s;
endfunction
function string reverse(string s);
string r;
for (int i = s.len()-1; i >= 0; i--)
r = {r, s[i]};
return r;
endfunction
endpackage
module test;
import str_pkg::to_upper;
string s;
initial begin
s = to_upper("vlsi");
$display("Converted: %s", s);
end
endmodule
Only to_upper
is imported, avoiding namespace clutter.
Handling Name Conflicts
Two packages might define items with the same name:
package pkgA;
typedef enum {RED, GREEN, BLUE} color;
endpackage
package pkgB;
typedef enum {RED, YELLOW, BLACK} signal;
endpackage
If you import both fully:
module bad_case;
import pkgA::*;
import pkgB::*;
signal s; // ERROR: multiple RED definitions
endmodule
Fix by qualifying names or selective import:
module good_case;
import pkgA::color;
import pkgB::signal, pkgB::YELLOW, pkgB::BLACK;
signal s = YELLOW;
initial $display("Signal = %s", s.name());
endmodule
Nested Packages
package p1;
int x = 100;
endpackage
package p2;
import p1::*;
int y = 200;
endpackage
module test;
import p1::*;
import p2::*;
initial $display("x=%0d, y=%0d", x, y);
endmodule
Note: Importing p2::*
does not automatically import p1::*
.
Enum Import Rules
package mode_pkg;
typedef enum logic [1:0] {IDLE, RUN, STOP} mode_e;
endpackage
Wrong usage:
module bad_enum;
import mode_pkg::mode_e;
mode_e m = RUN; // ERROR
endmodule
Correct usage:
module good_enum;
import mode_pkg::*;
mode_e m = RUN;
endmodule
\
includeeverywhere and faced type mismatch issues. The explanation of using
import` for type consistency solved so many problems. Highly recommended!”