📦 What is a package
?#
A package
in SystemVerilog is a modular container that holds reusable type definitions, constants, functions, and tasks.
It acts like a namespace, similar to namespace
in C++ or Java, helping to keep code organized, readable, and reusable across modules and testbenches.
🧱 Basic package
Syntax#
package my_pkg;
typedef enum logic [1:0] {IDLE, RUN, STOP} state_t;
int global_counter;
function int add(int a, b);
return a + b;
endfunction
endpackage
🚀 How to Use a package
#
You can use the contents of a package in three ways:
🔹 1. Import Entire Package#
import my_pkg::*;
Makes all symbols (e.g.,
state_t
,add()
) visible in the current scope.
🔹 2. Import Specific Items#
import my_pkg::state_t;
Safer and cleaner — only brings in what you need.
🔹 3. Use Fully Qualified Names#
state_t s;
s = my_pkg::IDLE;
Prevents naming collisions by explicitly referencing the namespace.
🧠 Why Use Packages?#
Benefit | Description |
---|---|
Avoid repetition | Centralizes reusable types, constants, and functions |
Reusable testbenches | Common in UVM for shared testbench utilities |
Large-scale design | Keeps design modular and organized |
Type safety | Each package has its own isolated namespace |
🧪 Example: Shared Types in Design & Testbench#
// my_defs_pkg.sv
package my_defs_pkg;
typedef logic [31:0] word_t;
typedef enum {REQ, RESP} tx_type_t;
endpackage
// dut.sv
import my_defs_pkg::*;
module dut(input word_t a, b, output word_t sum);
assign sum = a + b;
endmodule
// testbench.sv
import my_defs_pkg::*;
initial begin
word_t a = 32'h10;
word_t b = 32'h20;
tx_type_t mode = REQ;
...
end
🛠️ What Can You Put Inside a Package?#
Definition Type | Allowed in package |
---|---|
typedef , enum , struct | ✅ Yes |
parameter , localparam | ✅ Yes |
function , task | ✅ Yes |
interface , module | ❌ No (must be declared outside) |
⚠️ Common Pitfalls#
- A
package
is not a module — it can’t containalways
,initial
, or procedural logic. import
should be placed before usage in the compilation unit.- Same names can exist in different packages — namespace prevents collisions.
🧠 package
vs include
#
Feature | package | include |
---|---|---|
Modular structure | ✅ Yes | ❌ Just text substitution |
Namespace support | ✅ Yes | ❌ None |
Compile-time | ✅ Recognized by compiler | ❌ Preprocessor-based |
Error handling | ✅ Scoped and isolated | ❌ Can introduce hidden bugs |
✅ Summary#
- Use
package
to define reusable constants, types, and functions. - Use
import my_pkg::*;
orimport my_pkg::item;
to control visibility. - Use
my_pkg::symbol
style to avoid naming collisions in large designs. - Widely used in UVM, testbenches, and shared RTL infrastructure.
// Best practice
import my_util_pkg::my_function;
import uvm_pkg::*;
Packages help you write cleaner, safer, and more modular SystemVerilog code.
// === File: my_pkg.sv ===
package my_pkg;
typedef enum logic [1:0] {IDLE, RUN, STOP} state_t;
int global_counter;
function int add(int a, b);
return a + b;
endfunction
endpackage
// === File: dut.sv ===
import my_pkg::*;
module dut(input logic clk,
input logic [3:0] a, b,
output logic [4:0] result,
output my_pkg::state_t state);
assign result = add(a, b);
assign state = RUN;
endmodule
// === File: tb_pkg_demo.sv ===
import my_pkg::*;
module tb_pkg_demo;
logic clk = 0;
logic [3:0] a = 4'd7, b = 4'd9;
logic [4:0] result;
state_t current_state;
// Clock generation
always #5 clk = ~clk;
// DUT instantiation
dut u_dut (
.clk(clk),
.a(a),
.b(b),
.result(result),
.state(current_state)
);
initial begin
#10;
$display("Result = %0d", result);
$display("State = %s", current_state.name());
#10 $finish;
end
endmodule
📘 Scoped Package Import in Modules#
Starting from SystemVerilog 2012, you can import a package directly inside a module, interface, or function definition. This makes the imported symbols visible only within that specific scope, rather than globally across the file.
This helps avoid name collisions and improves modularity in large projects.
✅ Example: Scoped import
Inside a Module#
module tb_pkg_demo import my_pkg::*;
logic [3:0] a = 4'd5, b = 4'd3;
logic [4:0] result;
state_t s;
initial begin
result = add(a, b);
s = RUN;
$display("Result = %0d, State = %s", result, s.name());
end
endmodule
🔎 This imports everything from
my_pkg
only insidetb_pkg_demo
, without affecting other modules or global scope.