In my efforts to make my code more modular and testable, I've been playing with VHDL packages. This came about because I was building a logic block that would do different things depending on the value of its "operation" input. Since there is a well-defined set of supported operations, an enumerated type makes sense, but how can an enumerated type be exported so it may be used by "clients"? Previously I've only declared enumerated types as the type of a state machine, all of which have been confined to a single file.
My solution is straightforward, if not particularly elegant (if you know a better way please tell me!). I made a simple proof-of-concept for it, using just a simple
gate entity which implements a logic function (
OP_OR) which is user-selectable. First declare a package with a definition for the user-defined type for
-- gate_pkg.vhdl library ieee; package gate_pkg is type Operation is ( OP_AND, OP_OR ); end package;
Then define and implement the
-- gate.vhdl library ieee; use ieee.std_logic_1164.all; use work.gate_pkg.all; entity gate is port( op_in : in Operation; a_in : in std_logic; b_in : in std_logic; x_out : out std_logic ); end entity; architecture rtl of gate is begin x_out <= a_in or b_in when op_in = OP_OR else a_in and b_in when op_in = OP_AND; end architecture;
And finally you can import the package and use its types and its logic blocks:
-- toplevel.vhdl library ieee; use ieee.std_logic_1164.all; use work.gate_pkg.all; entity toplevel is port( op_in : in std_logic; a_in : in std_logic; b_in : in std_logic; x_out : out std_logic ); end entity; architecture structural of toplevel is signal op : Operation; begin u1: gate port map( op_in => op, a_in => a_in, b_in => b_in, x_out => x_out ); op <= OP_AND when op_in = '1' else OP_OR; end architecture;
I have checked a fully-working example of this into GitHub. I also updated the GHDL simulation stuff I talked about in this blog post to use a
.ghw file rather than a
.vcd file for the waves. This means you can see the symbolic value of the enumerated type in GTKWave:
If you have a Digilent S3BOARD you can load it with the
.bit file generated by the build. Button 3 sets the operation (
OP_AND), button 2 and 1 set the inputs and LED 0 displays the output.