The Case-When statement will cause the program to take one out of multiple different paths, depending on the value of a signal, variable, or expression. It’s a more elegant alternative to an If-Then-Elsif-Else statement with multiple Elsif’s.

Other programming languages have similar constructs, using keywords such as a switch, case, or select. Among other things, Case-When statements are commonly used for implementing multiplexers in VHDL. Continue reading, or watch the video to find out how!

This blog post is part of the Basic VHDL Tutorials series.

The basic syntax for the Case-When statement is:
case <expression> is
    when <choice> =>
        code for this branch
    when <choice> =>
        code for this branch
    ...
end case;

The <expression> is usually a variable or a signal. The Case statement may contain multiple when choices, but only one choice will be selected.

The <choice> may be a unique value like "11":
when "11" =>

Or it can be a range like 5 to 10:
when 5 to 10 =>

It can contain several values like 1|3|5:
when 1|3|5 =>

And most importantly, the others choice. It is selected whenever no other choice was matched:
when others =>

The others choice is equivalent to the Else branch in the If-Then-Elsif-Else statement.

Exercise

In this video tutorial we will learn how to create a multiplexer using the Case-When statement in VHDL:

The final code we created in this tutorial:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T14_CaseWhenTb is
end entity;

architecture sim of T14_CaseWhenTb is

    signal Sig1 : unsigned(7 downto 0) := x"AA";
    signal Sig2 : unsigned(7 downto 0) := x"BB";
    signal Sig3 : unsigned(7 downto 0) := x"CC";
    signal Sig4 : unsigned(7 downto 0) := x"DD";

    signal Sel : unsigned(1 downto 0) := (others => '0');

    signal Output1 : unsigned(7 downto 0);
    signal Output2 : unsigned(7 downto 0);

begin

    -- Stimuli for the selector signal
    process is
    begin
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= Sel + 1;
        wait for 10 ns;
        Sel <= "UU";
        wait;
    end process;

    -- MUX using if-then-else
    process(Sel, Sig1, Sig2, Sig3, Sig4) is
    begin

        if Sel = "00" then
            Output1 <= Sig1;
        elsif Sel = "01" then
            Output1 <= Sig2;
        elsif Sel = "10" then
            Output1 <= Sig3;
        elsif Sel = "11" then
            Output1 <= Sig4;
        else -- 'U', 'X', '-' etc.
            Output1 <= (others => 'X');
        end if;

    end process;

    -- Equivalent MUX using a case statement
    process(Sel, Sig1, Sig2, Sig3, Sig4) is
    begin

        case Sel is
            when "00" =>
                Output2 <= Sig1;
            when "01" =>
                Output2 <= Sig2;
            when "10" =>
                Output2 <= Sig3;
            when "11" =>
                Output2 <= Sig4;
            when others => -- 'U', 'X', '-', etc.
                Output2 <= (others => 'X');
        end case;

    end process;

end architecture;

The waveform window in ModelSim after we pressed run, and zoomed in on the timeline:

The output to the simulator console when we pressed the run button in ModelSim:

VSIM 2> run
# ** Warning: NUMERIC_STD."=": metavalue detected, returning FALSE
#    Time: 50 ns  Iteration: 1  Instance: /t14_casewhentb
# ** Warning: NUMERIC_STD."=": metavalue detected, returning FALSE
#    Time: 50 ns  Iteration: 1  Instance: /t14_casewhentb
# ** Warning: NUMERIC_STD."=": metavalue detected, returning FALSE
#    Time: 50 ns  Iteration: 1  Instance: /t14_casewhentb
# ** Warning: NUMERIC_STD."=": metavalue detected, returning FALSE
#    Time: 50 ns  Iteration: 1  Instance: /t14_casewhentb

Need the ModelSim project files?

Let me send you a Zip with everything you need to get started in 30 seconds

How does it work?

Tested on Windows and Linux How it works

    Unsubscribe at any time

    Analysis

    First, we created a process using If-Then-Elsif-Else that would forward one of the signals Sig1, Sig2, Sig3, or Sig4, based on the value of the selector signal Sel.

    Then we created a process that did exactly the same, using the Case-When statement. We can see from the waveform that the output signals from the two processes, Output1 and Output2, behave exactly the same.

    In our example, the Sel signal has only four legal values. But if there had been a higher number of possibilities, we can easily see that the Case-When statement can help making code more readable. This is the preferred way of creating such a component by most VHDL designers.

    Understanding of the multiplexer was the bonus point of this exercise. Multiplexers, or MUX’s for short, are central components in digital design. It is simply a switch that selects one of several inputs, and forwards it to the output.

    This is an illustration of how our MUX forwards the selected input signal:
    mux

    We used the others clause to catch all values of Sel which were not ones or zeros. As we learned in the std_logic tutorial, these signals can have a number of values which are not '0' or '1'. It’s good design practice to deal with these values by outputting 'X'. This indicates an unknown value on this signal, and it will be visible in downstream logic as well.

    We can see from the waveform that when the Sel signal turned red, Output1 and Output2 also changed to "XX". This is when others => in action.

    Additionally, the console output in ModelSim shows a warning because of the Sel signal being set to "UU". The “** Warning: NUMERIC_STD.”=”: metavalue detected, returning FALSE” messages appear at 50 ns simulation time, which is exactly when the signals turn red.

    Get exclusive access to exercises and answers!

    Takeaway

    • Case-When can be used instead of multiple If-Then-Elsif statements
    • The when others => can be used to implement a default choice
    • Multiplexers are preferably created using Case-When statements

    Go to the next tutorial »

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    3 thoughts on “How to use a Case-When statement in VHDL

    1. Thanks for your tutorials. Quick question:

      When a ‘when xxx =>’ block is evaluated, can one and only one choice be evaluated for each scheduled event?

      In other words, if something changes in the first ‘when xxx =>’ block that could cause the condition in the second ‘when xxx =>’ block immediately below to be true, does this get ignored until the next event, or will VHDL run through every ‘when xxx =>’ block (like a C switch statement with no ‘break’ between cases)?

      Keep up the good work.

      Posted on October 4, 2018 at 5:27 pm
      1. Hi Joel,

        Interesting question!

        The Case statement is not like a C switch, hence there is no ‘break’ keyword. Only one When-branch will be run each time the program reaches the Case statement.

        What happens in a situation where the condition (the ‘Sel’ signal) is changed from within a When-branch, depends on the process that the Case is inside of.

        If we managed to change the Sel signal inside of the ‘when “10” =>’ for example (even though that would not work because of multiple drivers). Then, the process would immediately run once more because the Sel signal which the process is sensitive to has changed. This time, another When branch would be selected.

        If the above algorithm results in an infinite loop, the simulator may produce a warning, or it may freeze or hang. I have seen both happen.

        The thousand dollar question is of course what kind of logic this would produce if used in an RTL (production) module. The results can be unpredictable. Therefore you should only use such creative code in testbenches 🙂

        Posted on October 5, 2018 at 2:13 pm
        1. Makes sense. Thanks for your time!

          Posted on October 5, 2018 at 2:58 pm