Disallowed constructs
From FPGA Wiki
There are a number of constructs that are commonly used within VHDL that are not able to be synthesized. The more common ones are listed below as well as alternative designs to allow for synthesis.
Shared Variables
For some components such as register-files, it is sometimes convenient to use separate processes to read and write data to the underlying data structure. To do this, the variable containing the data structure must be moved out of a process and into the architecture level so both processes can use it. For example:
architecture behavioral of register_file is type register_data is array(0 to 7) of STD_LOGIC_VECTOR (31 downto 0); shared variable regBank: register_data := ( X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000" ); begin write_proc: process(clk) begin -- code end process write_proc; read_proc: process(read_reg1, read_reg2) begin read_reg_out1 <= regBank(register1); read_reg_out2 <= regBank(register2); end process read_proc; end behavioral;
Unfortunately, the shared keyword is not synthesizeable. An easy fix for this is to change the data structure to a signal rather than a variable, and move the code inside read_proc outside, into the architecture:
architecture behavioral of register_file is type register_data is array(0 to 7) of STD_LOGIC_VECTOR (31 downto 0); signal regBank: register_data := ( X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000", X"00000000" ); begin write_proc: process(clk) begin -- code end process write_proc; read_reg_out1 <= regBank(register1); read_reg_out2 <= regBank(register2); end behavioral;
Because the data is now a signal, it will automatically trigger the bindings to be updated causing read_reg_out1 and read_reg_out2 to update asynchronously.
Storing Data vs. Setting Output to Input
The main difference between placing code on an FPGA and running it in a simulator is latency caused by combinatoric logic from latches. In an effort to remove as many un-needed latches as possible, code that stores data asynchronously and then updates the output to the value of the stored data should be changed. For example:
entity obj is port ( in_data : in std_logic_vector(31 downto 0); clk : in std_logic; out_data : out std_logic_vector(31 downto 0) ); end obj; architecture behavioral of obj is signal stored_data : std_logic_vector(31 downto 0) := X"00000000"; begin proc : process begin wait until (clk'event and clk='1'); out_data <= stored_data; end process proc; stored_data <= in_data; end behavioral;
Should be changed to:
entity obj is port ( in_data : in std_logic_vector(31 downto 0); clk : in std_logic; out_data : out std_logic_vector(31 downto 0) ); end obj; architecture behavioral of obj is begin proc : process begin wait until (clk'event and clk='1'); out_data <= in_data; end process proc; end behavioral;
