1
\$\begingroup\$

I'm new to VHDL and currently try to get more complex data types working, so that code becomes more readable... However, it seems that I cannot define a type in VHDL before the entity statement, which is using the type inside it's port statement.

Hence, it seems I need to somehow write my own library for that. I assume this must work, as types as std_logic_vector must be defined somehow too. Or did they hardcode these types into the VDHL compiler... and if so, why do we still need to include the libraries for it?

I want to do something like in the following code example. However, the compiler doesn't let my define the type in Test.vhdl as mentioned above. Anyhow, it seems to be valid to define the component in TOP.vhdl. I also would like to avoid to redefine the component and the data type in TOP.vhdl anyway. Is there a way to do this?

Test.vhdl

 library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;
 use ieee.numeric_std.all;
 type MyRecordType is record -- Compiler complains about this!
 x : std_logic_vector(2 downto 0); -- expects 'entity' or 'architecture'
 y : std_logic_vector(2 downto 0);
 end record;
 entity Test is
 port(
 clk : in std_logic;
 input : in MyRecordType;
 output : out std_logic
 );
 end entity;
 architecture RTL of Test is
 begin
 process (clk) is
 begin
 if rising_edge(clk) then
 if (input.x = input.y) then
 output <= '1';
 else
 output <= '0';
 end if;
 end if;
 end process;
 end;

TOP.vhdl

 library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;
 use ieee.numeric_std.all;
 entity TOP is
 end entity;
 architecture SIM of TOP is
 type MyRecordType is record
 x : std_logic_vector(2 downto 0);
 y : std_logic_vector(2 downto 0);
 end record;
 component Test is
 port(
 clk : in std_logic;
 input : in MyRecordType;
 output : out std_logic
 );
 end component;
 constant period : time := 20 ns;
 signal clk : std_logic;
 signal result : std_logic;
 signal myRecord : MyRecordType;
 begin
 dut : Test port map(clk => clk, input => myRecord, output => result);
 clk <= not clk after period / 2;
 process is
 begin
 myRecord.x <= "000";
 myRecord.y <= "000";
 wait for 20 ns;
 if result = 0 then
 report "TEST 1 - FAILED.";
 else
 report "TEST 1 - PASSED.";
 end if;
 myRecord.x <= "000";
 myRecord.y <= "010";
 wait for 20 ns;
 if result = 1 then
 report "TEST 2 - FAILED.";
 else
 report "TEST 2 - PASSED.";
 end if;
 wait;
 end process;
 end architecture;
asked Jan 20, 2019 at 18:21
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

To use a user defined type in a port declaration, you need to specify the type in a package and use that package in the context before the entity.

Utilities.vhdl

library ieee;
use ieee.std_logic_1164.all;
package utilities is
 type MyRecordType is record
 x : std_logic_vector(2 downto 0);
 y : std_logic_vector(2 downto 0);
 end record;
end package;

Test.vhdl

library ieee;
use ieee.std_logic_1164.all;
library myLib;
use myLib.Utilities.all;
entity Test is
 port (
 clk : in std_logic;
 input : in MyRecordType;
 output : out std_logic
 );
end entity;

Top.vhdl

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library myLib;
use myLib.Utilities.all;
entity TOP is
end entity;
architecture SIM of TOP is
 constant period : time := 20 ns;
 signal clk : std_logic;
 signal result : std_logic;
 signal myRecord : MyRecordType;
begin
 dut : entity myLib.Test
 port map(
 clk => clk,
 input => myRecord,
 output => result
 );
end architecture;

Further hints:

  • Don't use package std_logic_unsigned, use numeric_std instead.
  • Declaring the some type twice create two independent and incompatible types. VHDL is here more strict than C, because type equality is not based on structure, it's based on names. When you define a type twice, the fully qualified name of both types is different, thus you have incompatible types.
  • You can omit component declarations and spare lot's of doubled code, when using direct entity instantiations.
  • If you want to initialize myRecord at the beginning of the simulation, then initialize it when you declare the signal. Using myRecord.x <= "000"; has a delay of one delta cycle!
  • This expression will not work: result = 0, because result is no integer, you need to compare with '0'.
  • You shouldn't wait for 20 ns;. Use wait for period;.
answered Jan 20, 2019 at 21:28
\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the solution and your very helpful additional advices! I've got two additional questions when reading your answer: a.) How is Utilities.vhdl actually declared to belong to "library myLib" instead of "work"? b.) Is the initialization at the declation via := VALUE also synthesized or is it just working within the simulator (like the wait for... statement)? \$\endgroup\$ Commented Jan 20, 2019 at 22:29
  • 1
    \$\begingroup\$ libraries are handled by your tool, there is no additional file or instruction to make them part of a library. Your tool will offer you a mechanism to set a library name for each source file. If you use your tool on command line this will propably be --work=myLib. You shouldn't use a library named work, because work is a special name in VHDL. work refers to the current library, like a this pointer in C#/Java, ... \$\endgroup\$ Commented Jan 20, 2019 at 22:33
  • 1
    \$\begingroup\$ If the signal will be translated to a memory element and you have an FPGA as target platform, then initial values are synthesizable, otherwise they are ignored. Don't initialize signals, that will translate to wires, this might cover bugs, which you're trying to find in simulation with X and U propagation. In your case it's a testbench, so you actually need to initialize it as I have shown, otherwise you have a delty-cycle delay, which might cause big problems (and hard to find problems....) \$\endgroup\$ Commented Jan 20, 2019 at 22:36
  • \$\begingroup\$ Yeah, that makes sense... thank's for also pointing out the potential pitfalls. \$\endgroup\$ Commented Jan 20, 2019 at 22:38

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.