In my last webinar I explained what happens when you import a package in SystemVerilog. There were still many questions, so here is a written version.
Please, try these examples on your own system or EDA Playground. Cut and paste the code into SystemVerilog files, compile, and debug. Make mistakes, get messy, and you will learn. If you just listen, or just read this, but never run the code, the concepts will disappear from your mind faster than Comet Neowise.
Another box of sugar
Imagine you are cooking dinner, and need some sugar. What do you do? Reach into the cabinet next to the refrigerator and grab the box. Oops, no box as you used it up last night. So you need to go to the grocery store and buy some more.
A SystemVerilog package is like a grocery store – a place to hold lots of stuff, that you go to when you can’t find something locally.
What is a package?
A package holds definitions that you want to share between modules. You might have a parameter, enumerated type, structure, a type definition (typedef), a class, or even a task or function.
Here is a package that defines a data type and a parameter.
// chip_pkg.sv package chip_pkg; typedef logic [3:0] data_t; parameter LIFE = 9; endpackage
Compile a package
When you compile this with Questa, the code is turned into a binary form in the work library. The compiler can read the binary version much faster than the original code, which is why we import packages rather than including them. The UVM package is 70,000 lines, but the compiled version is imported almost instantaneously.
Import a package
A module accesses the compiled package code by importing it. Here is the chip module that declares some parameters and a variable, and displays a parameter.
// chip.sv module chip; import chip_pkg::*; // Wildcard import parameter INIT_VALUE = 'hFF; // Initial value data_t my_data = INIT_VALUE; // What are data_t and INIT_VALUE? initial $display("my_data = 'h%x / 'b%b", my_data, my_data); parameter LIFE = 42; // Ask Douglas Adams initial $display("The meaning of life is %0d", LIFE); endmodule
The package store
The SystemVerilog compiler looks for names locally. If they are not found, it goes to the “grocery store”, which is the package.
When you compile this module, the wildcard import statement tells the compiler that the package is a place to find definitions. The compiler does not bring in all the names from the package. That would be like bringing home an entire grocery store!
The module defines the parameter INIT_VALUE. For the declaration of “my_data”, the compiler needs to figure out what “data_t” and “INIT_VALUE” mean. The compiler always starts by searching the local scope, which is the chip module. Success: INIT_VALUE is found here. However, there is no data_t. Only then does the compiler look in packages. Success: the compiler finds the definition of data_t in the chip package!
You can prove that packages are searched after the local scope. The next block of code defines a parameter LIFE, and prints it. In the $display() statement, the compiler needs to know what “LIFE” is. Since you just declared it locally, the compiler never looks in chip_pkg, even though there is a parameter with the same name there. The local definition does NOT conflict with the parameter in the package, as chip_pkg::LIFE was never imported.
The bare minimum
SystemVerilog only brings in new definitions from a package when they are not found in the local scope. Why? If every name in the package was brought in immediately, there is a good chance that one of the package names could conflict with one in the local scope, such as the the chip module. Better to bring in the minimum number of names, rather than too many.
The module defined a parameter called LIFE. Run this code in your favorite simulator and find out the meaning of life. Is it 9, an important number if you are a cat? Or is there something deeper?
What would happen if the module defined the type data_t as 8 bits instead of just 4? How can you explicitly get the value of LIFE from chip_pkg? What if a new parameter is defined in both chip_pkg and chop_pkg, and both are imported – what happens? If I tell you the answer, you’ll never remember it. Try it yourself, invest the time, discover the truth.
Enjoy your verification journey!