Sequential Statements in Subprograms
We've seen examples of how sequential statements are written in a process statement. The process statement is relatively easy to understand if you think of it as a small software program that executes independent of other processes and concurrent statements during simulation.
Functions and procedures (which are collectively called subprograms) are very similar to processes in that they contain sequential statements executed as independent 'programs' during simulation. The parameters you pass into a subprogram are analogous to the sensitivity list of a process; whenever there is an event on any object (signal or variable) being passed as an argument to a subprogram, that subprogram is executed and its outputs (whether they are output parameters, in the case of a procedure, or the return value, in the case of a function) are recalculated.
The following example includes a procedure declared within the architecture. The procedure counts the number of ones and zeroes there are in a std_logic_vector input (of arbitrary width) and returns the count values as output parameters. The procedure is used to build two result strings containing the appropriate number of ones and zeroes, left justified and padded with 'X' values. (For example, an input with the values "1010001001" would result in the values "1111XXXXXX" and "000000XXXX".)
entity proc is
port (Clk: in std_logic;
Rst: in std_logic;
InVector: in std_logic_vector(0 to 9);
OutOnes: out std_logic_vector(0 to 9);
OutZeroes: out std_logic_vector(0 to 9));
end proc;
architecture behavior of proc is
procedure CountBits(InVector: in std_logic_vector;
ones,zeroes: out natural) is
variable cnt1: natural := 0;
variable cnt0: natural := 0;
begin
for I in 0 to InVector'right loop
case InVector(I) is
when '1' => cnt1 := cnt1 + 1;
when '0' => cnt0 := cnt0 + 1;
when others => null;
end case;
end loop;
ones := cnt1;
zeroes := cnt0;
end CountBits;
signal Tmp1, Tmp0: std_logic_vector(0 to 9);
begin
process(Rst, Clk)
begin
if Rst = '1' then
OutOnes <= (others => '0');
OutZeroes <= (others => '0');
elsif rising_edge(Clk) then
OutOnes <= Tmp1;
OutZeroes <= Tmp0;
end if;
end process;
process(InVector)
variable ones, zeroes: natural;
begin
Countbits(InVector,ones,zeroes);
Tmp0 <= (others => 'X');
Tmp1 <= (others => 'X');
for I in 0 to ones - 1 loop
Tmp1(I) <= '1';
end loop;
for I in 0 to zeroes - 1 loop
Tmp0(I) <= '0';
end loop;
end process;
end behavior;
This example shows that a procedure containing sequential statements can be invoked from within a process—or even from within another procedure. The calling process simply suspends until the procedure has completed execution.
Note: This example is theoretically synthesizable, but the fact that the procedure has been written without regard to the width of the inputs will probably make it impossible to process by synthesis tools. If this design were to be synthesized, the variables cnt1 and cnt0 would have to be given range constraints.