top of page

Functions And Procedure

Functions:

In Verilog we have bitwise reduction operators like & or | that can directly reduce a multi-bit signal into a single bit by performing AND or OR across all bits. For example, if a signal is 8 bits wide, using &signal gives one output bit that is the AND of all 8 bits, and |signal gives one output bit that is the OR of all 8 bits. VHDL does not provide these reduction operators directly, so we often write a function to perform the same operation. The function takes the multi-bit input, executes the bitwise ANDing or ORing across the vector, and returns a single bit as the result. In hardware, this function will be synthesized into gates. The advantage of writing such a function is that we can reuse it in many places without having to repeat the same piece of code again and again, just like we do in C programming. So, a function in VHDL is essentially a reusable piece of code that returns one value, which makes designs cleaner and avoids repetition.

Example: 8 bit Parity Detector

VDHL

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

 

entity parity_detector_8 is

  port (

    A         : in  STD_LOGIC_VECTOR(7 downto 0);

    Parity_odd: out STD_LOGIC;  -- '1' when number of ones in A is odd

    Parity_even: out STD_LOGIC  -- '1' when number of ones in A is even

  );

end entity;

 

architecture rtl of parity_detector_8 is

 

  -- Function declared inside architecture (no package)

  function reduce_xor(vec : STD_LOGIC_VECTOR) return STD_LOGIC is

    variable r : STD_LOGIC := '0';

  begin

    for i in vec'range loop

      -- xor accumulative reduction

      r := r xor vec(i);

    end loop;

    return r;  -- returns '1' if odd number of '1's else '0'

  end function;

 

begin

 

  -- Call the function: reduce_xor returns odd parity

  Parity_odd  <= reduce_xor(A);

  Parity_even <= not reduce_xor(A);

 

end architecture;

Elaborated Diagram:

FAP1.png

Synthesis:

FAP2.png

Simulation:

FAP3.png

Here we can see an example of a parity detector, which is a simple form of error detection circuit. Parity checking is widely used in functional safety and is an important method in industry. There are other methods such as CRC, SECDED, and sniffers, but parity is a very general and basic circuit. In this example, we implemented both even and odd parity checks. Since parity checks may be required many times in a design, we wrote the logic as a function. Whenever the function is called, it executes according to its declaration and is synthesized into hardware. This way, the same function can be reused multiple times without rewriting the code.

Where Functions are declared?

There are two ways to declare a function in VHDL. The first way is to put the function inside a package. This makes it reusable, because any other design can use the package and call the function without writing it again.

VHDL

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

 

package reduction_pkg is

  function reduce_and(vec : STD_LOGIC_VECTOR) return STD_LOGIC;

  function reduce_or(vec : STD_LOGIC_VECTOR) return STD_LOGIC;

  function reduce_xor(vec : STD_LOGIC_VECTOR) return STD_LOGIC;

end package;

 

package body reduction_pkg is

 

  function reduce_and(vec : STD_LOGIC_VECTOR) return STD_LOGIC is

    variable result : STD_LOGIC := '1';

  begin

    for i in vec'range loop

      result := result and vec(i);

    end loop;

    return result;

  end function;

 

  function reduce_or(vec : STD_LOGIC_VECTOR) return STD_LOGIC is

    variable result : STD_LOGIC := '0';

  begin

    for i in vec'range loop

      result := result or vec(i);

    end loop;

    return result;

  end function;

 

  function reduce_xor(vec : STD_LOGIC_VECTOR) return STD_LOGIC is

    variable result : STD_LOGIC := '0';

  begin

    for i in vec'range loop

      result := result xor vec(i);

    end loop;

    return result;

  end function;

 

end package body;

Package used in Design main file:

VHDL

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use work.reduction_pkg.all;  -- import package

 

entity reduction_example is

  port (

    A     : in  STD_LOGIC_VECTOR(7 downto 0);

    Y_and : out STD_LOGIC;

    Y_or  : out STD_LOGIC;

    Y_xor : out STD_LOGIC

  );

end entity;

 

architecture rtl of reduction_example is

begin

  -- Function calls

  Y_and <= reduce_and(A);  -- equivalent to Verilog &A

  Y_or  <= reduce_or(A);   -- equivalent to Verilog |A

  Y_xor <= reduce_xor(A);  -- equivalent to Verilog ^A

end architecture;

Elaborated Diagram:

FAP4.png

Synthesis:

FAP5.png

Simulation:

FAP6.png

The second way is to declare the function inside the architecture of an entity. In this case, the function is only available for that entity and cannot be reused elsewhere. We have seen this in the above parity detector example.

​

Note: Function declaration will be at compilation time but synthesize and execution will be at Function calling time.

When functions can do the job, why procedures?

In VHDL, a function and a procedure look similar, but they are not used for the same purpose. A function always gives back one single value, just like solving a math problem and writing one final answer. Inside a function, the keyword return means “this is my final answer,” and that value is passed back to wherever the function was called.

​

A procedure is different. A procedure can produce multiple outputs at the same time, and those outputs are passed through its out or inout parameters. That’s why procedures are chosen when you need more than one result. Unlike a function, a procedure does not send a value back with the return keyword. Instead, the outputs are already given through the parameters.

​

So what does return mean inside a procedure? In this case, return simply means “stop the execution here and exit the procedure.” It does not give back a value. If you write return; in the middle of a procedure, any code written after that line will be skipped, and control will move back outside the procedure.

​

Think of it like this:

  • A function is like an answer sheet where you must write exactly one final result before submitting.
     

  • A procedure is like a teacher explaining to many students at once, giving different answers to each. If the teacher suddenly says “class dismissed” (that’s the return;), the lesson stops right there, but the answers already given to the students remain with them.

VHDL

library ieee;

use ieee.std_logic_1164.all;

 

entity proc_example is

    port(

        data  : in  std_logic_vector(7 downto 0);

        high4 : out std_logic_vector(3 downto 0);

        low4  : out std_logic_vector(3 downto 0)

    );

end entity;

 

architecture rtl of proc_example is

 

    procedure split_nibbles (

        signal x     : in  std_logic_vector(7 downto 0);

        signal upper : out std_logic_vector(3 downto 0);

        signal lower : out std_logic_vector(3 downto 0)

    ) is

    begin

        -- If input is all zero, just exit early

        if x = "00000000" then

            upper <= "0000";

            lower <= "0000";

            return;  -- stop procedure here, skip rest

        end if;

 

        -- Otherwise split into upper and lower 4 bits

        upper <= x(7 downto 4);

        lower <= x(3 downto 0);

    end procedure;

 

begin

    -- Procedure call

    process(data)

    begin

        split_nibbles(data, high4, low4);

    end process;

 

end rtl;

If data = "00000000", the procedure assigns both outputs to "0000" and then return; exits immediately. The rest of the body is skipped.
If data is not zero, the procedure continues and assigns the upper 4 bits and lower 4 bits normally.

Elaborated Diagram:

FAP7.png

Synthesis:

FAP8.png

Simulation:

FAP9.png

Dataflow modeling

Packages and Libraries

© Copyright 2025 VLSI Mentor. All Rights Reserved.©

Connect with us

  • Instagram
  • Facebook
  • Twitter
  • LinkedIn
  • YouTube
bottom of page