Skip to main content

1. Introduction to VHDL

1.1 What is VHDL

VHDL is an acronym for VHSIC HDL or, more completely, Very High-Speed Integrated Circuit Hardware Description Language. VHDL is a language used to describe hardware, so its writing style cannot be equated with high/low-level programming languages. A VHDL model or program can be translated into an actual digital circuit quickly with the help of software and, of course, according to specific needs; this process is known as synthesis. The resulting circuit can also be tested using VHDL to ensure it works according to the user's requirements. Before proceeding to the main material, readers are reminded to understand the concepts of Basic Digital Circuits (DSD) for ease in describing and designing hardware.

1.2 VHDL Syntax

Because VHDL is a language used to describe hardware, in addition to the correct output, tidy program writing is also needed to make it easier to understand. The following are VHDL writing conventions that need to be observed:

  • Case Sensitivity : VHDL is not case-sensitive, meaning that both uppercase and lowercase letters are recognized as the same object.

  • White Space : VHDL is not sensitive to white space, meaning that creating space using either a tab or a space bar has the same meaning.

  • Comments : Like programming languages in general, VHDL also has comments, which are made by using the -- sign.

  • Parentheses : In VHDL, there are open and close parentheses () which are used for precedence, giving a higher priority to the statement within them.

  • VHDL Statements : Statements in VHDL always end with a ; or semi-colon.

  • If, case, and loop Statements

    • Every if statement is followed by a then component.

    • Every if statement ends with end if;.

    • Else if in VHDL is written as elsif.

    • Every case statement ends with end case;.

    • Every loop statement is terminated with end loop;.

  • Identifiers/Variables : Identifiers or variables in VHDL can use a combination of letters (A-Z and a-z) and numbers (0-9), must not end with an _, and can have an unlimited length. It is important to name variables according to their function so they are easy to understand.

1.3 VHDL Operator

Operators in VHDL are grouped into 7 types: logical, relational, shift, adding, sign, multiplying, and others. The order of this list also describes the precedence of the operators. The following is a complete description of these operators:

  • Logical
Operator Type





Logical and or nand nor xor xnor
  • Relational
Operator Name Explanation
A = B equivalence is A equivalent to B?
A /= B non-equivalence is A not equivalent to B?
A < B less than is A less than B?
A <= B less than or equal is A less than or equal to B?
A > B greater than is A greater than B?
A >= B greater than or equal is A greater than or equal to B?
  • Shift
  Operator Name Example Result
logical sll shift left logical result <= "10010101" sll 2 "01010100"
  srl shift right logical result <= "10010101" srl 3 "00010010"
arithmetic sla shift left arithmetic result <= "10010101" sla 3 "10101111"
  sra shift right arithmetic result <= "10010101" sra 2 "11100101"
rotate rol rotate left result <= "10100011" rol 2 "10001110"
  ror rotate right result <= "10100011" ror 2 "11101000"
  • Arithmetic
  Operator Name Comment
adding + addition  
  - subtraction  
  & concatenation
can operate only on specific types
sign + identity unary operator
  - negation unary operator
multiplying * multiplication  
  / division
often limited to powers of two
  mod modulus
can operate only on specific types
  rem remainder
can operate only on specific types
miscellaneous ** exponentiation
often limited to powers of two
  abs absolute value  

1.4 Design Units

There are two important parts when designing a digital circuit using VHDL: "entity" and "architecture." These two units form a hierarchical design consisting of a black box and the components within it.

  • Entity : The entity is the first part of a VHDL design. It is the highest-level specification of a component or module in the design. In the entity, we define the component's external interface, including its inputs and outputs. The entity is the "black box" that describes what the component does and how it is accessed from the outside. The entity also defines the name of the component and the data types used.

image.png

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- The ENTITY describes the "black box" interface.
-- It defines the input and output ports.
entity Logic_Circuit is
    port (
        A, B, C : in  STD_LOGIC;  -- The three input pins
        Y       : out STD_LOGIC   -- The single output pin
    );
end Logic_Circuit;

 

  • Architecture : The architecture is the second part of a VHDL design. This section describes how the component works internally, including how the signals defined in the entity are processed and connected within that component.

image.png

-- The ARCHITECTURE describes the internal logic.
-- It explains HOW the inputs are used to create the output.
architecture Dataflow of Logic_Circuit is
begin
    -- This single line of code represents the AND gate followed by the OR gate.
    Y <= (A and B) or C;
end Dataflow;

1.5 Data Objects

In VHDL, there are 4 types of Data Objects: signals, variables, constants, and files. The way to declare a data object for all types is more or less the same, as follows:

VHDL data object Declaration form
Signal signal sig_name : sig_type:=initial_value;
Variable variable var_name : var_type:=initial_value;
Constant constant const_name : const_type:=initial_value;

1.5.1 VHDL Signals

A signal in VHDL is the primary way to model a physical wire or connection in a hardware design. Declared within an architecture, its main purpose is to communicate data between different concurrent components, such as processes or logic gates. A signal is assigned a value using the <= operator, and this assignment is not immediate. it is scheduled to occur at a specific future time, which accurately reflects the signal propagation delay found in real-world circuits. This delayed behavior is essential for correctly modeling how different parts of a hardware design interact with each other. Signals is also only Declared in the declarative part of an architecture or package. There are two ways to declare signals :

Port Signal

A port signal is declared in the entity section of a VHDL design and represents an external connection. Its purpose is to define how the module sends and receives data from the outside world. Think of ports as the plugs and sockets on an appliance—they are the only way to interact with what's inside. You must specify a direction (or mode) for each port, such as in, out, inout, or buffer.

-- Port signals are declared inside the ENTITY
entity D_Flip_Flop is
    port (
        d, clk, rst : in  STD_LOGIC;  -- Input ports
        q           : out STD_LOGIC   -- Output port
    );
end D_Flip_Flop;

architecture Behavioral of D_Flip_Flop is
-- ... logic using the ports ...
end Behavioral;
Intermediate Signal

An intermediate signal is declared in the declarative part of the architecture and acts as an internal wire within your design. It is not visible from outside the module. Intermediate signals are essential for connecting different internal processes or concurrent statements, breaking down complex logic into simpler steps, or holding a value that needs to be used in multiple places within the architecture.

entity Complex_Gate is
    port (
        a, b, c, d : in  STD_LOGIC;
        y          : out STD_LOGIC
    );
end Complex_Gate;

-- Intermediate signal is declared inside the ARCHITECTURE
architecture Dataflow of Complex_Gate is
    -- This signal is an internal "wire" to hold a temporary result
    signal and_result_1 : STD_LOGIC;
begin
    -- The intermediate signal connects the output of the first AND gate
    -- to the input of the OR gate.
    and_result_1 <= a and b;
    y <= and_result_1 or (c and d);
end Dataflow;

1.5.2 VHDL Variables

A variable acts as temporary, local storage for calculations and does not represent a physical wire. It can only be declared and used inside a sequential block, such as a process (this will be explained more in module 3 : Behavioral Style) . The key distinction of a variable is its immediate update behavior. when a value is assigned using the := operator, the variable changes instantly and can be used in the very next line of code with its new value. This makes variables ideal for complex, multi-step algorithms where you need to store intermediate results without the delay and hardware overhead associated with a signal. Variables is also only Declared only inside a process, function, or procedure. It cannot be used to connect different processes. 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Entity defines the inputs and outputs
entity Bit_Counter is
    port (
        data_in  : in  STD_LOGIC_VECTOR(7 downto 0); -- 8-bit input bus
        count_out: out INTEGER range 0 to 8          -- The final count
    );
end Bit_Counter;

-- Architecture shows the internal logic
architecture Behavioral of Bit_Counter is
begin
    -- A process is needed to use a variable
    count_process: process(data_in)
        -- 1. The variable is declared here, inside the process.
        -- It is initialized to 0 every time the process runs.
        variable bit_count : INTEGER := 0;
    begin
        -- Loop through each bit of the input signal
        for i in data_in'range loop
            if data_in(i) = '1' then
                -- 2. The variable is updated IMMEDIATELY.
                bit_count := bit_count + 1;
            end if;
        end loop;
        
        -- 3. The final result is assigned to the output signal.
        count_out <= bit_count;
        
    end process count_process;
end Behavioral;

1.5.3 VHDL Constant

A constant in VHDL is a data object that holds a fixed value which cannot be changed after it is declared using the constant NAME : TYPE := VALUE; syntax. Its primary purpose is to improve code readability and maintainability by assigning a descriptive name to a value, like using DATA_WIDTH instead of the number 8. This practice makes a design much easier to update, as changing the constant's value in its single declaration will automatically apply that change everywhere it's used, effectively acting like a labeled, unchangeable setting for your entire project. Constant can be declared in various places like a package, entity, architecture, or process.

-- First, define the constants in a package
package My_Design_Package is
    constant DATA_WIDTH : integer := 8;
    constant CLK_FREQ_HZ: integer := 50_000_000; -- 50 MHz
end package My_Design_Package;

-- Then, use the package in your design
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.My_Design_Package.all; -- Makes our constants visible

entity My_Register_File is
    port (
        clk      : in  std_logic;
        data_in  : in  std_logic_vector(DATA_WIDTH - 1 downto 0); -- Uses the constant
        data_out : out std_logic_vector(DATA_WIDTH - 1 downto 0)  -- Uses the constant
    );
end My_Register_File;

1.5.5 Standard Data Types

In VHDL (VHSIC Hardware Description Language), there are various data types used to define the properties and types of variables, signals, and other objects in a hardware design. Here are some common data types in VHDL:

  • Signed : This data type is used to represent integers with a sign (signed integer). It is suitable for representing negative and positive numbers in hardware design.

-- Declaration
signal setpoint_signed    : SIGNED(7 downto 0);
signal feedback_signed    : SIGNED(7 downto 0);
signal error_value_signed : SIGNED(7 downto 0);

--  Usage Example: Calculate the difference between two signed values
error_value_signed <= setpoint_signed - feedback_signed;
  • Unsigned : This data type is similar to "Signed," but it is only used to represent non-negative integers (unsigned integers).

-- Declaration
signal program_counter : UNSIGNED(15 downto 0);

-- Usage Example: Increment the counter in a clocked process
if rising_edge(clk) then
    program_counter <= program_counter + 1;
end if;
  • STD_LOGIC : This data type is used to represent a single logic signal that can have the values '0', '1', 'Z' (high impedance), 'U' (uninitialized), 'X' (don't care), 'W' (weak), or 'L' (weak low).

-- Declaration
signal clk   : STD_LOGIC;
signal rst   : STD_LOGIC;
signal q_out : STD_LOGIC;

-- Usage Example: Using a reset signal to clear a register
if rst = '1' then
    q_out <= '0';
elsif rising_edge(clk) then
    -- ... other logic ...
end if;
  • STD_LOGIC_VECTOR : This is a data type used to represent a vector of STD_LOGIC signals. You can use this type to represent a bus or a collection of logic signals in a hardware design (multiple bits).

-- Declaration
signal control_register : STD_LOGIC_VECTOR(7 downto 0);

-- Usage Example: Assigning a hexadecimal value to a control register
control_register <= x"A5"; -- Assigns the bit pattern "10100101"
  • Integer : This data type is used to represent whole numbers, positive or negative. It is often used for counting and managing numerical values in a design.

-- Usage within a process
process(clk)
    -- Declaration (variable declared inside a process)
    variable i : INTEGER;
begin
    -- Usage Example: Controlling a loop a specific number of times
    for i in 0 to 15 loop
        -- ... perform an operation ...
    end loop;
end process;
  • Boolean : This data type has two values, "True" or "False." It is used for conditioning and logical expressions.

-- Declaration
signal fifo_is_not_empty : BOOLEAN;
signal read_enable       : STD_LOGIC;

-- Usage Example: Using a boolean flag to control an operation
if fifo_is_not_empty = True then
    read_enable <= '1';
else
    read_enable <= '0';
end if;

1.6 VHDL Architecture Models

In VHDL, there are several approaches to explaining or describing an architecture. Hardware can be described using these styles or models according to its needs and complexity. These approaches are divided into three types:

  • Data-flow style : The data-flow approach describes a circuit by showing the relationship between the inputs and outputs of the components in the VHDL language. Concurrent signal assignment, conditional signal assignment, and selected signal assignment are the statements used in the data-flow style.

  • Behavioral style : The behavioral style approach doesn't describe how the circuit is implemented when synthesized. Instead, the behavioral style models how the circuit's output reacts to its inputs. The main component of the behavioral style is the process statement.

  • Structural style : The structural style approach is essentially a method that supports the interconnection of black boxes or entities. This style enables modular design, allowing you to connect previously separate components into a single circuit or entity. The structural style is commonly used when a circuit becomes increasingly complex, as it simplifies the description process.