Packages:
Now we will understand how a package is created from this, let's see

Package Declaration:
​
In VHDL, creating a package means collecting many related things in one place, such as:
​
-
Constants
-
Types / Subtypes
-
Functions / Procedures
-
Reusable Components (Modules/Entities)
And whatever is necessary for your design, you can use from it.
In simple terms, a package is like a box where you store reusable and essential items, so you don’t have to write them repeatedly in different files.
Why do we use a package in VHDL?
​
-
A package in VHDL is used to reuse common code in multiple design files.
-
Instead of writing the same definitions again and again, we keep them once in a package.
-
Inside a package, we usually put:
-
constants
-
types
-
functions/procedures
-
component declarations (like a blueprint of an entity)
-
Then, in any RTL file, we just write:
use work.my_package.all;
and we can reuse those definitions and components.
So, if we want to use the same design in another RTL file, we declare its component in a package and then instantiate it wherever needed.
How to reuse a VHDL Counter in multiple files
​
In VHDL, you cannot put the entire entity + architecture inside a package.
A package is only for:
-
Constants
-
Types
-
Functions/Procedures
-
Component Declarations (like a "blueprint" of the entity)
So the correct way is:
Step 1: Write your counter separately
​
Put the full counter (entity + architecture) in its own file,
​
e.g. counter.vhd
VHDL
Step 2: Create a package with component declaration
​
Now make a package file,
​
e.g. up_down_pkg.vhd
VHDL
This acts like a header file (like in C/C++).
Step 3: Use the package in another design
​
In your top file, import the package and instantiate the counter:​​
VHDL
Test Bench:
VHDL
Elaborated Diagram:

Synthesis:

Simulation:

Here inside top file up/down counter is being instantiated which is being done by port mapping which I will explain in further lectures, when the design is very large and one component is used in another design then it is port mapped.
​
A VHDL package can contain as many components as you want, such as constants, types, subtypes, functions, procedures, and reusable component declarations.
​
There is no strict limit defined by VHDL, but practical limits depend on your tool/compiler and design complexity.
​
For better readability and reuse, related components should be grouped together, and very large packages can be split into smaller logical packages.
Libraries:
In VHDL, a library is like a storage place where your compiled design units are kept. Every time you write VHDL code – an entity, an architecture, or a package – and you compile it, the compiler stores it inside a library. You can think of it like a bookshelf: the library is the shelf, and the different VHDL units are the books on it.
​
There are some libraries that are always there for you. For example, the ieee library holds all the standard packages that almost every design needs, like std_logic_1164 which defines the logic types, or numeric_std which lets you do arithmetic with vectors. There’s also the std library with the most basic definitions, and the work library which is your default personal shelf – whenever you compile your own code, if you don’t say otherwise, it goes into work.
​
You can also make your own libraries if you want to organize your project better. For instance, you might decide to keep all your RTL code in one library, your testbenches in another, and maybe some utility packages in a third. In most simulators or tools, you first create a new library, then tell the compiler to put certain design files into it. Later, if you want to use something from that library in another file, you write library mylib; and then bring in whatever package or component you need with a use statement.
​
It’s also useful to understand how libraries and packages are related. A package is like a header file in C or C++: it holds constants, functions, and component declarations that you want to share. The library is the container where that package (and everything else) lives once it’s compiled. So you write a package, you compile it into a library, and then you can use it in other files.
​
In short, libraries keep your design units organized and accessible, while packages are the reusable blocks of code you put inside them.
what is the benefit of this, the data design is compiled only in the work library?
Think of it like this:
The work library is the default backpack every VHDL project carries. If you throw all your files (entities, architectures, packages, testbenches) into that one backpack, it works for small projects. But imagine if you’re working on a big project – maybe a CPU design, or a large FPGA system with hundreds of VHDL files. If everything sits together in work, it quickly becomes messy and hard to manage.
​
By creating and using custom libraries, you are basically creating separate folders on your bookshelf:
​
-
One library might hold all your RTL code (the real design).
-
Another library might hold your testbenches (which often have the same entity names, like “top”, and would clash if stored in the same library).
-
Yet another might hold utility packages that you want to share across multiple projects.
Another benefit is reuse. Suppose you wrote a package with lots of math functions or custom types. If you compile it into a library called utils_lib, then in a completely different project you can just library utils_lib; use utils_lib.my_pkg.all; without recompiling that code every time.
​
Professional flows (ASIC, FPGA teams) almost always separate things this way. They’ll keep vendor-provided IP cores in one library, RTL in another, verification code in another, so that the build system and simulation environment stay clean and organized.
​
So yes, for your small student projects, keeping everything in work is totally fine. It’s simpler and faster. But once you step into bigger designs or industry-level work, splitting things into multiple libraries helps with:
​
-
Organization
-
Avoiding name conflicts
-
Reusing packages and code easily
-
Clear separation between design and test
Till now you might have understood what a library is, its uses and work library. Let's understand this
library ieee;
-
This tells VHDL that you want to use a predefined collection of useful code called a library.
-
ieee is a standard library provided for VHDL designs.
use ieee.std_logic_1164.all;
-
From the ieee library, we are using everything (all) from the std_logic_1164 package.
-
This package gives us standard logic types like std_logic and std_logic_vector, which are used to represent signals like 0, 1, unknown (X), high-impedance (Z), etc.
use work.up_down_pkg.all;
-
work is the current project/library where your own code resides.
-
up_down_pkg is a package you or someone created that contains reusable code, like constants, types, or functions.
-
all means you are importing everything inside that package.
-
This is useful if you want to reuse your counter types, constants, or helper functions in multiple VHDL files without rewriting them.