Packages in System Verilog

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

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

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

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top