IDE: Quartus 15
I'm new to VHDL programming so there are some nuances I am not used to (translating from C++). Whilst I have found resources for programming the "source" files, I've struggled to find anything for the "header" files.
In short, what is the standard layout / syntax of a VHDL "header" file?
To keep things simple, the use cases I'm interested in are declaring subtype
and function references for use between "source" files.
I found the following code snippet here which has helped a little, but I'm still not sure of what the differences between package
and package body
are. I'm also unsure of where "work" comes from.
"Header":
package DEFS is
CONSTANT MAJOR_VERSION: INTEGER := 0;
CONSTANT MINOR_VERSION: INTEGER := 22;
CONSTANT MAXREG: integer := 52;
TYPE REGS_TYPE is array (0 to MAXREG) of STD_LOGIC_VECTOR(15 downto 0);
FUNCTION opndrn(inp: std_logic) return std_logic;
end package DEFS;
package body DEFS is
FUNCTION opndrn(inp: std_logic) return std_logic IS
begin
CASE INP is
WHEN '0' => return '0';
WHEN OTHERS => return 'Z';
END CASE;
end;
end package body DEFS;
"Source":
LIBRARY work;
USE work.defs.all;
Any and all help is appreciated.
Thankfully, there are no header files in VHDL.
What you have there is a package, which isn't ever "include"d in anything.
Unlike a header file, a package is seperately compiled - into a library, which you can then "use" as you are doing.
Unlike a header file, a package creates its own namespace. USE work.defs.all;
imports that entire namespace, like using namespace defs
in C++. Sometimes it's better practice to write USE work.defs;
which then allows you to selectively use that namespace, and refer to defs.Major_Version
in your source, thus (a) keeping your global namespace uncluttered, and (b) documenting where Major_Version
is defined.
Unlike a header file, a package encourages proper separation of interface and implementation. Your source can ONLY access things exported by the package, i.e. declared in the package not the package body. This allows information hiding, opaque types and generally better abstractions.
For example you can declare Major_Version
in the package but hide its actual value in the body (see "deferred constants")
It's legal for both package and package body (interface and implementation) to be in the same file, but if you want to enforce separation of interface and implementation, the package body would be a separate file.
Then you can modify the package body (implementation) and recompile it : nothing that uses the package needs recompilation (unless you also changed the interface.
Any customer of the package only has to look at the package file, not the package body.
In short, what you are doing looks pretty much OK.
But you can go further in information hiding.
And one thing to beware of is creating one all-purpose God package : far better to separate bus constants, functions etc into a "bus" package, register types (and maybe an enumeration of all their names) in a "registers" package, instructions in an "instructions" package etc.