This is part four of our VHDL tutorial series. Today, we're diving into how to design combinational circuits within the sequential region using the if statement in VHDL.
From previous lessons, you’ll likely remember that every VHDL code is generally composed of two main sections: Entity and Architecture.
More...
The Architecture Section of a VHDL Design
The Architecture section itself is divided into three parts.

The general structure of the Architecture section in VHDL code
The first part is where you declare signals and modules.
The next part, which is the Concurrent section, is where you can describe combinational circuits.
And finally, within the Concurrent section, there’s the Sequential region, where you can describe both combinational and sequential circuits.
The topic of this video focuses on using the Sequential region for describing combinational circuits.
To recap the structure of the Architecture section, as you’ve seen before, a typical Architecture structure used to describe circuits can be represented like this: After the keyword Architecture, you’ll encounter the keyword Begin.
The section between these two keywords is known as the Declarative region, where signals and modules are declared.
From the Begin keyword of the Architecture to the end of the Architecture section, which is marked by the keyword end Architecture, lies the Concurrent section, where you can only design combinational circuits.
The Process Statement in VHDL
Within the concurrent section, we can use the process statement to create a new region called the sequential region. And within the sequential region, we can implement both combinational and sequential circuits.
Just as we had specific assignment statements in the concurrent section to describe various combinational circuits, the sequential region also has assignment statements that allow us to describe both sequential and combinational circuits.
Two common and essential assignment statements in the sequential region are the if-then-else statement and the case statement.
Today, I’ll focus on the if-then-else statement.
Now, let's get a little more familiar with the process statement and some of its key concepts.
The process statement is special, and its concepts differ slightly from other parts of VHDL.
It’s very important that you make an effort to fully understand these concepts—there aren’t too many of them, but they are crucial.
If you don’t grasp them well, the circuits you define using this structure may have issues or bugs, which won’t be easily identifiable through logical analysis.
In this simple code example, I've created a sequential region using a process within the concurrent section of the architecture, just to illustrate some process-related concepts.
Architecture Behavioral of temp is begin -- concurrent. process(A,X) begin A <= B; C <= A; end process; -- concurrent. end Behavioral;
A process begins with the keyword process and ends with the keyword end process.
Sensitivity List and Process Activation
Before the process and after the end process, we are back in the concurrent region. Right after the process keyword, you’ll see a list of signals enclosed in parentheses. This is called the Sensitivity List.
The signals in the sensitivity list determine when the process should be activated and when the statements inside should be evaluated.
This means that the assignment statements within the process—in this example, the following two assignments—are evaluated only when at least one of the signals in the sensitivity list changes its value.
A <= B; C <= A;
To put it in VHDL terms: if an event occurs on one of the signals in the sensitivity list, the process becomes active, and the statements within it are evaluated.
In this example, we’ve included two signals, A and X, in the sensitivity list. Consequently, this process is triggered, and the statements within it are evaluated only when at least one of these two signals experiences an event, meaning a change in value.
Now, let's assume an event has occurred on one of them; its value has changed, and the process is activated. The statements are evaluated line by line.
How Processes Respond to Events
The first statement assigns the value of signal B to A, and the next assigns the value of A to C.
If these two assignment statements were written in the Concurrent section, they would be evaluated as follows: if the value of signal B changes, the first line activates, and the value of B is assigned to A.
Then, since A has changed, the next line activates, and the value of A is assigned to C. After a short delay, B, A, and C would all have the same value.
However, things work differently within a process.
Inside a process, assignments are evaluated sequentially, after the process is activated.
But unlike in typical programming languages, the value of the signal on the left-hand side of an assignment is not immediately updated after each line is evaluated.
Instead, the new values of the signals on the left-hand side of the assignments are updated only when we reach the end of the process.
Therefore, until the process ends, the values of the signals remain the same as they were before the process was activated.
For example, if B is assigned to A and then A is assigned to C in the next line, the value of A used in the second assignment is not the new value of A (which is equal to B), but rather the old value of A from before the process activation.
Let's clarify this with an example.
Imagine that before the process was triggered—meaning before any of the signals in the sensitivity list changed—the values of signals A, B, and C were 1, 2, and 3, respectively.

The values of signals A, B, and C were 1, 2, and 3 before the process was triggered.
Now, let’s say one of the signals A or X (or both) changes, triggering the process.
After activation, we evaluate the statements line by line: first, B is assigned to A, and then A is assigned to C.
What do you think the values of A, B, and C will be after the process ends?
The outcome might be different from what you expect, especially if you're coming from a programming background.
With a programming mindset, you might think that B (which is 2) gets assigned to A, making A equal to 2. Then, since A is now 2, that value gets assigned to C, making C also 2.
So, you might expect all signals to be 2 after the process. However, what actually happens is different.
As you can see, the values of A and B become 2, but C remains 1.

After the process ends, the values of A and B become 2, but C remains 1.
Let's see why.
Signal A is assigned the value of B, which was 2 before the process activated. So, 2 is assigned to A, but as I mentioned, the value of A doesn’t change until the end of the process.
During the process, A retains the value it had before the process activated.
In the second assignment, A is assigned to C. To determine what value is assigned to C, we need to look at the value of A before the process activated, which was 1. Therefore, 1 is assigned to C, not 2.
So, after the process completes, B (which was 2) is assigned to A, so A becomes 2. C is assigned the old value of A (which was 1), making C equal to 1. And B remains unchanged because there was no assignment to B.
If-Then-Else Statement within the Process
Now, to better understand the process construct and to explain the if-then-else statement within the process, let’s revisit the example of a 4-to-1 multiplexer that we used earlier to explain conditional and selected signal assignments in the Concurrent section.

A 4-to1 Multiplexer.

The truth table for a 4-to1 multiplexer.
Designing a 4-to-1 Multiplexer Using the Process Statement
Here’s the code that describes a 4-to-1 multiplexer.
library IEEE; uSe IEEE.STD_LOGIC_1164.ALL; entity MUX4to1_if iS Port ( A : in STD_LOGIC; B : in STD_LOGIC; C : in STD_LOGIC; D : in STD_LOGIC; S : in STD_LOGIC_VECTOR (1 downto 0); F : out STD_LOGIC ); end MUX4to1_if; architecture Behavioral oF MUX4to1_if iS begin -- concurrent. proceSS(A,B,C,D,S) begin -- Sequential. if (S = "00") then F <= A; elsif (S = "01") then F <= B; elsif (S = "10") then F <= C; else F <= D; end if; -- Sequential. end process; -- concurrent. end Behavioral;
As you saw in the previous diagram, our multiplexer has four inputs: A, B, C, and D. For each of these inputs, we’ve defined a single-bit signal or port of type STD_LOGIC.
Our control lines consist of two lines, which we’ve defined as a vector using the STD_LOGIC_VECTOR type.
We also have a single output line, F, which is also defined as a single-bit signal of type STD_LOGIC.
Now, let’s see how we can describe this multiplexer using the process and the if-then-else conditional statements.
The Architecture section is used for describing the multiplexer, where we’ve used a process statement.
We’ve included the multiplexer inputs (A, B, C, D, and S) in the sensitivity list and used the if statement to describe the multiplexer.
How does this work?
We say: if S (the control signal) equals "00", then assign A to F.
Elsif – meaning if the previous condition wasn't met and S equals "01" – then assign B to F.
Otherwise, if S equals "10," assign C to F.
And finally, else – meaning if none of the previous conditions were met – assign D to F. We conclude the if statement with the keyword end if.
There are a few points to note about this code.
First, in the last condition of the if statement, we used else without specifying a condition. Here, the else means “If none of the previous conditions are met.”
In other words, if S is not equal to "00", "01", or "10"—then assign D to F. In this case, it implies S is equal to 11.
The next point is about syntax: when using elsif, notice that else and if are combined into a single keyword. However, there's no 'e' at the end of else.
This is specific to VHDL syntax; so keep this in mind to avoid errors.
Alternative Implementation Strategies for If-Then-Else Constructs
Now, let’s modify this code slightly to explore the process statement further and see if the resulting multiplexer description changes.
I'm going to take the assignment of D to F and move it outside the if statement, placing it at the beginning. I'll also remove the else part.
Do you think this modified code is equivalent to the previous version? Does it still describe a 4-to-1 multiplexer? Or does it describe something different?
library IEEE; uSe IEEE.STD_LOGIC_1164.ALL; entity MUX4to1_if iS Port ( A : in STD_LOGIC; B : in STD_LOGIC; C : in STD_LOGIC; D : in STD_LOGIC; S : in STD_LOGIC_VECTOR (1 downto 0); F : out STD_LOGIC ); end MUX4to1_if; architecture Behavioral oF MUX4to1_if iS begin -- concurrent. process(A,B,C,D,S) begin -- Sequential. F <= D; if (S = "00") then F <= A; elsif (S = "01") then F <= B; elsif (S = "10") then F <= C; end if; -- Sequential. end process; -- concurrent. end Behavioral;
If you look closely at the code and are familiar with the concepts related to the process statement, you’ll realize that this code is exactly the same as the previous one.
Let’s see why.
In this modified code, as soon as the process is triggered, the value of D is assigned to F unconditionally. Then, if S equals 00, A is assigned to F.
Since, as I mentioned earlier, signal values aren’t updated until the process finishes, the last assignment to a signal takes precedence.
In other words, if you assign a value to a signal multiple times within a process, only the final assignment takes effect.
Pro Tip!
If you assign a value to a signal multiple times within a process, only the final assignment takes effect.
Here, we’ve assigned D to F unconditionally. Then, we’ve added conditions: if S is equal to "00", assign A to F; if it’s equal to "01", assign B to F; and if it’s equal to "10", assign C to F.
If none of these conditions are met, the initial assignment of D to F remains valid.
Therefore, this code behaves exactly like the previous one because if S is equal to "11", the first line assigns D to F, and since none of the conditions are met, the last assignment remains D to F, producing the correct result.
However, if one of these conditions is met, the assignment is updated, and a new assignment occurs, resulting in the desired outcome.
This illustrates an important point: if a signal is assigned multiple times within a process, the last assignment is the one that ultimately determines the signal's value at the end of the process.
There are other concepts related to the process statement that we'll discuss in future videos.
I hope you found this video helpful and that you can use what you've learned here in your own code. Don’t forget to leave your thoughts and feedback in the comments below.